ZipArchive.mm 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. //
  2. // ZipArchive.mm
  3. //
  4. //
  5. // Created by aish on 08-9-11.
  6. // acsolu@gmail.com
  7. // Copyright 2008 Inc. All rights reserved.
  8. //
  9. //消除三方库警告
  10. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  11. #pragma clang diagnostic ignored "-Wshorten-64-to-32"
  12. #pragma clang diagnostic ignored "-Wundeclared-selector"
  13. //#pragma clang diagnostic ignored "-Wdeprecated-declarations"
  14. //#pragma clang diagnostic ignored "-Wdeprecated-declarations"
  15. #import "ZipArchive.h"
  16. #import "zlib.h"
  17. #import "zconf.h"
  18. @interface ZipArchive (Private)
  19. -(void) OutputErrorMessage:(NSString*) msg;
  20. -(BOOL) OverWrite:(NSString*) file;
  21. -(NSDate*) Date1980;
  22. @end
  23. @implementation ZipArchive
  24. @synthesize delegate = _delegate;
  25. -(id) init
  26. {
  27. if( self=[super init] )
  28. {
  29. _zipFile = NULL ;
  30. }
  31. return self;
  32. }
  33. -(void) dealloc
  34. {
  35. [self CloseZipFile2];
  36. // [super dealloc];
  37. }
  38. -(BOOL) CreateZipFile2:(NSString*) zipFile
  39. {
  40. _zipFile = zipOpen( (const char*)[zipFile UTF8String], 0 );
  41. if( !_zipFile )
  42. return NO;
  43. return YES;
  44. }
  45. -(BOOL) CreateZipFile2:(NSString*) zipFile Password:(NSString*) password
  46. {
  47. _password = password;
  48. return [self CreateZipFile2:zipFile];
  49. }
  50. -(BOOL) addFileToZip:(NSString*) file newname:(NSString*) newname;
  51. {
  52. if( !_zipFile )
  53. return NO;
  54. // tm_zip filetime;
  55. time_t current;
  56. time( &current );
  57. zip_fileinfo zipInfo = {0};
  58. // zipInfo.dosDate = (unsigned long) current;
  59. NSDictionary* attr = [[NSFileManager defaultManager] fileAttributesAtPath:file traverseLink:YES];
  60. if( attr )
  61. {
  62. NSDate* fileDate = (NSDate*)[attr objectForKey:NSFileModificationDate];
  63. if( fileDate )
  64. {
  65. // some application does use dosDate, but tmz_date instead
  66. // zipInfo.dosDate = [fileDate timeIntervalSinceDate:[self Date1980] ];
  67. NSCalendar* currCalendar = [NSCalendar currentCalendar];
  68. uint flags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit |
  69. NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit ;
  70. NSDateComponents* dc = [currCalendar components:flags fromDate:fileDate];
  71. zipInfo.tmz_date.tm_sec = [dc second];
  72. zipInfo.tmz_date.tm_min = [dc minute];
  73. zipInfo.tmz_date.tm_hour = [dc hour];
  74. zipInfo.tmz_date.tm_mday = [dc day];
  75. zipInfo.tmz_date.tm_mon = [dc month] - 1;
  76. zipInfo.tmz_date.tm_year = [dc year];
  77. }
  78. }
  79. int ret ;
  80. NSData* data = nil;
  81. if( [_password length] == 0 )
  82. {
  83. ret = zipOpenNewFileInZip( _zipFile,
  84. (const char*) [newname UTF8String],
  85. &zipInfo,
  86. NULL,0,
  87. NULL,0,
  88. NULL,//comment
  89. Z_DEFLATED,
  90. Z_DEFAULT_COMPRESSION );
  91. }
  92. else
  93. {
  94. data = [ NSData dataWithContentsOfFile:file];
  95. uLong crcValue = crc32( 0L,NULL, 0L );
  96. crcValue = crc32( crcValue, (const Bytef*)[data bytes], [data length] );
  97. ret = zipOpenNewFileInZip3( _zipFile,
  98. (const char*) [newname UTF8String],
  99. &zipInfo,
  100. NULL,0,
  101. NULL,0,
  102. NULL,//comment
  103. Z_DEFLATED,
  104. Z_DEFAULT_COMPRESSION,
  105. 0,
  106. 15,
  107. 8,
  108. Z_DEFAULT_STRATEGY,
  109. [_password cStringUsingEncoding:NSASCIIStringEncoding],
  110. crcValue );
  111. }
  112. if( ret!=Z_OK )
  113. {
  114. return NO;
  115. }
  116. if( data==nil )
  117. {
  118. data = [ NSData dataWithContentsOfFile:file];
  119. }
  120. unsigned int dataLen = [data length];
  121. ret = zipWriteInFileInZip( _zipFile, (const void*)[data bytes], dataLen);
  122. if( ret!=Z_OK )
  123. {
  124. return NO;
  125. }
  126. ret = zipCloseFileInZip( _zipFile );
  127. if( ret!=Z_OK )
  128. return NO;
  129. return YES;
  130. }
  131. -(BOOL) CloseZipFile2
  132. {
  133. _password = nil;
  134. if( _zipFile==NULL )
  135. return NO;
  136. BOOL ret = zipClose( _zipFile,NULL )==Z_OK?YES:NO;
  137. _zipFile = NULL;
  138. return ret;
  139. }
  140. -(BOOL) UnzipOpenFile:(NSString*) zipFile
  141. {
  142. _unzFile = unzOpen( (const char*)[zipFile UTF8String] );
  143. if( _unzFile )
  144. {
  145. unz_global_info globalInfo = {0};
  146. if( unzGetGlobalInfo(_unzFile, &globalInfo )==UNZ_OK )
  147. {
  148. #ifdef DEBUG
  149. NSLog(@"%@", [NSString stringWithFormat:@"%lu entries in the zip file",globalInfo.number_entry] );
  150. #endif
  151. }
  152. }
  153. return _unzFile!=NULL;
  154. }
  155. -(BOOL) UnzipOpenFile:(NSString*) zipFile Password:(NSString*) password
  156. {
  157. _password = password;
  158. return [self UnzipOpenFile:zipFile];
  159. }
  160. -(BOOL) UnzipFileTo:(NSString*) path overWrite:(BOOL) overwrite
  161. {
  162. BOOL success = YES;
  163. int ret = unzGoToFirstFile( _unzFile );
  164. unsigned char buffer[4096] = {0};
  165. NSFileManager* fman = [NSFileManager defaultManager];
  166. if( ret!=UNZ_OK )
  167. {
  168. [self OutputErrorMessage:@"Failed"];
  169. }
  170. do{
  171. if( [_password length]==0 )
  172. ret = unzOpenCurrentFile( _unzFile );
  173. else
  174. ret = unzOpenCurrentFilePassword( _unzFile, [_password cStringUsingEncoding:NSASCIIStringEncoding] );
  175. if( ret!=UNZ_OK )
  176. {
  177. [self OutputErrorMessage:@"Error occurs"];
  178. success = NO;
  179. break;
  180. }
  181. // reading data and write to file
  182. int read ;
  183. unz_file_info fileInfo ={0};
  184. ret = unzGetCurrentFileInfo(_unzFile, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
  185. if( ret!=UNZ_OK )
  186. {
  187. [self OutputErrorMessage:@"Error occurs while getting file info"];
  188. success = NO;
  189. unzCloseCurrentFile( _unzFile );
  190. break;
  191. }
  192. char* filename = (char*) malloc( fileInfo.size_filename +1 );
  193. unzGetCurrentFileInfo(_unzFile, &fileInfo, filename, fileInfo.size_filename + 1, NULL, 0, NULL, 0);
  194. filename[fileInfo.size_filename] = '\0';
  195. // check if it contains directory
  196. NSString * strPath = [NSString stringWithCString:filename];
  197. BOOL isDirectory = NO;
  198. if( filename[fileInfo.size_filename-1]=='/' || filename[fileInfo.size_filename-1]=='\\')
  199. isDirectory = YES;
  200. free( filename );
  201. if( [strPath rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"/\\"]].location!=NSNotFound )
  202. {// contains a path
  203. strPath = [strPath stringByReplacingOccurrencesOfString:@"\\" withString:@"/"];
  204. }
  205. NSString* fullPath = [path stringByAppendingPathComponent:strPath];
  206. if( isDirectory )
  207. [fman createDirectoryAtPath:fullPath withIntermediateDirectories:YES attributes:nil error:nil];
  208. else
  209. [fman createDirectoryAtPath:[fullPath stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil];
  210. if( [fman fileExistsAtPath:fullPath] && !isDirectory && !overwrite )
  211. {
  212. if( ![self OverWrite:fullPath] )
  213. {
  214. unzCloseCurrentFile( _unzFile );
  215. ret = unzGoToNextFile( _unzFile );
  216. continue;
  217. }
  218. }
  219. FILE* fp = fopen( (const char*)[fullPath UTF8String], "wb");
  220. while( fp )
  221. {
  222. read=unzReadCurrentFile(_unzFile, buffer, 4096);
  223. if( read > 0 )
  224. {
  225. fwrite(buffer, read, 1, fp );
  226. }
  227. else if( read<0 )
  228. {
  229. [self OutputErrorMessage:@"Failed to reading zip file"];
  230. break;
  231. }
  232. else
  233. break;
  234. }
  235. if( fp )
  236. {
  237. fclose( fp );
  238. // set the orignal datetime property
  239. NSDate* orgDate = nil;
  240. //{{ thanks to brad.eaton for the solution
  241. NSDateComponents *dc = [[NSDateComponents alloc] init];
  242. dc.second = fileInfo.tmu_date.tm_sec;
  243. dc.minute = fileInfo.tmu_date.tm_min;
  244. dc.hour = fileInfo.tmu_date.tm_hour;
  245. dc.day = fileInfo.tmu_date.tm_mday;
  246. dc.month = fileInfo.tmu_date.tm_mon+1;
  247. dc.year = fileInfo.tmu_date.tm_year;
  248. NSCalendar *gregorian = [[NSCalendar alloc]
  249. initWithCalendarIdentifier:NSGregorianCalendar];
  250. orgDate = [gregorian dateFromComponents:dc] ;
  251. // [dc release];
  252. // [gregorian release];
  253. //}}
  254. NSDictionary* attr = [NSDictionary dictionaryWithObject:orgDate forKey:NSFileModificationDate]; //[[NSFileManager defaultManager] fileAttributesAtPath:fullPath traverseLink:YES];
  255. if( attr )
  256. {
  257. // [attr setValue:orgDate forKey:NSFileCreationDate];
  258. if( ![[NSFileManager defaultManager] setAttributes:attr ofItemAtPath:fullPath error:nil] )
  259. {
  260. // cann't set attributes
  261. #ifdef DEBUG
  262. NSLog(@"Failed to set attributes");
  263. #endif
  264. }
  265. }
  266. }
  267. unzCloseCurrentFile( _unzFile );
  268. ret = unzGoToNextFile( _unzFile );
  269. }while( ret==UNZ_OK && UNZ_OK!=UNZ_END_OF_LIST_OF_FILE );
  270. return success;
  271. }
  272. -(BOOL) UnzipAllFileToDir:(NSString*) path overWrite:(BOOL) overwrite
  273. {
  274. BOOL success = YES;
  275. int ret = unzGoToFirstFile( _unzFile );
  276. unsigned char buffer[4096] = {0};
  277. NSFileManager* fman = [NSFileManager defaultManager];
  278. if( ret!=UNZ_OK )
  279. {
  280. [self OutputErrorMessage:@"Failed"];
  281. }
  282. do{
  283. if( [_password length]==0 )
  284. ret = unzOpenCurrentFile( _unzFile );
  285. else
  286. ret = unzOpenCurrentFilePassword( _unzFile, [_password cStringUsingEncoding:NSASCIIStringEncoding] );
  287. if( ret!=UNZ_OK )
  288. {
  289. [self OutputErrorMessage:@"Error occurs"];
  290. success = NO;
  291. break;
  292. }
  293. // reading data and write to file
  294. int read ;
  295. unz_file_info fileInfo ={0};
  296. ret = unzGetCurrentFileInfo(_unzFile, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
  297. if( ret!=UNZ_OK )
  298. {
  299. [self OutputErrorMessage:@"Error occurs while getting file info"];
  300. success = NO;
  301. unzCloseCurrentFile( _unzFile );
  302. break;
  303. }
  304. char* filename = (char*) malloc( fileInfo.size_filename +1 );
  305. unzGetCurrentFileInfo(_unzFile, &fileInfo, filename, fileInfo.size_filename + 1, NULL, 0, NULL, 0);
  306. filename[fileInfo.size_filename] = '\0';
  307. NSString* fullPath=nil;
  308. // check if it contains directory
  309. // NSString * strPath = [NSString stringWithCString:filename];
  310. BOOL isDirectory = NO;
  311. if( filename[fileInfo.size_filename-1]=='/' || filename[fileInfo.size_filename-1]=='\\')
  312. {
  313. isDirectory = YES;
  314. fullPath= path;
  315. }
  316. else
  317. {
  318. NSString* fname = [fman displayNameAtPath:[NSString stringWithCString:filename]];
  319. fullPath= [path stringByAppendingPathComponent:fname];
  320. }
  321. free( filename );
  322. // if( [strPath rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"/\\"]].location!=NSNotFound )
  323. // {// contains a path
  324. // strPath = [strPath stringByReplacingOccurrencesOfString:@"\\" withString:@"/"];
  325. // }
  326. if( isDirectory )
  327. [fman createDirectoryAtPath:fullPath withIntermediateDirectories:YES attributes:nil error:nil];
  328. else
  329. [fman createDirectoryAtPath:[fullPath stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil];
  330. if( [fman fileExistsAtPath:fullPath] && !isDirectory && !overwrite )
  331. {
  332. if( ![self OverWrite:fullPath] )
  333. {
  334. unzCloseCurrentFile( _unzFile );
  335. ret = unzGoToNextFile( _unzFile );
  336. continue;
  337. }
  338. }
  339. FILE* fp = fopen( (const char*)[fullPath UTF8String], "wb");
  340. while( fp )
  341. {
  342. read=unzReadCurrentFile(_unzFile, buffer, 4096);
  343. if( read > 0 )
  344. {
  345. fwrite(buffer, read, 1, fp );
  346. }
  347. else if( read<0 )
  348. {
  349. [self OutputErrorMessage:@"Failed to reading zip file"];
  350. break;
  351. }
  352. else
  353. break;
  354. }
  355. if( fp )
  356. {
  357. fclose( fp );
  358. // set the orignal datetime property
  359. NSDate* orgDate = nil;
  360. //{{ thanks to brad.eaton for the solution
  361. NSDateComponents *dc = [[NSDateComponents alloc] init];
  362. dc.second = fileInfo.tmu_date.tm_sec;
  363. dc.minute = fileInfo.tmu_date.tm_min;
  364. dc.hour = fileInfo.tmu_date.tm_hour;
  365. dc.day = fileInfo.tmu_date.tm_mday;
  366. dc.month = fileInfo.tmu_date.tm_mon+1;
  367. dc.year = fileInfo.tmu_date.tm_year;
  368. NSCalendar *gregorian = [[NSCalendar alloc]
  369. initWithCalendarIdentifier:NSGregorianCalendar];
  370. orgDate = [gregorian dateFromComponents:dc] ;
  371. // [dc release];
  372. // [gregorian release];
  373. //}}
  374. NSDictionary* attr = [NSDictionary dictionaryWithObject:orgDate forKey:NSFileModificationDate]; //[[NSFileManager defaultManager] fileAttributesAtPath:fullPath traverseLink:YES];
  375. if( attr )
  376. {
  377. // [attr setValue:orgDate forKey:NSFileCreationDate];
  378. if( ![[NSFileManager defaultManager] setAttributes:attr ofItemAtPath:fullPath error:nil] )
  379. {
  380. // cann't set attributes
  381. #ifdef DEBUG
  382. NSLog(@"Failed to set attributes");
  383. #endif
  384. }
  385. }
  386. }
  387. unzCloseCurrentFile( _unzFile );
  388. ret = unzGoToNextFile( _unzFile );
  389. }while( ret==UNZ_OK && UNZ_OK!=UNZ_END_OF_LIST_OF_FILE );
  390. return success;
  391. }
  392. -(BOOL) UnzipCloseFile
  393. {
  394. _password = nil;
  395. if( _unzFile )
  396. return unzClose( _unzFile )==UNZ_OK;
  397. return YES;
  398. }
  399. #pragma mark wrapper for delegate
  400. -(void) OutputErrorMessage:(NSString*) msg
  401. {
  402. if( _delegate && [_delegate respondsToSelector:@selector(ErrorMessage)] )
  403. [_delegate ErrorMessage:msg];
  404. }
  405. -(BOOL) OverWrite:(NSString*) file
  406. {
  407. if( _delegate && [_delegate respondsToSelector:@selector(OverWriteOperation)] )
  408. return [_delegate OverWriteOperation:file];
  409. return YES;
  410. }
  411. #pragma mark get NSDate object for 1980-01-01
  412. -(NSDate*) Date1980
  413. {
  414. NSDateComponents *comps = [[NSDateComponents alloc] init];
  415. [comps setDay:1];
  416. [comps setMonth:1];
  417. [comps setYear:1980];
  418. NSCalendar *gregorian = [[NSCalendar alloc]
  419. initWithCalendarIdentifier:NSGregorianCalendar];
  420. NSDate *date = [gregorian dateFromComponents:comps];
  421. // [comps release];
  422. // [gregorian release];
  423. return date;
  424. }
  425. @end