ZipArchive.mm 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  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. NSLog(@"%@", [NSString stringWithFormat:@"%lu entries in the zip file",globalInfo.number_entry] );
  149. }
  150. }
  151. return _unzFile!=NULL;
  152. }
  153. -(BOOL) UnzipOpenFile:(NSString*) zipFile Password:(NSString*) password
  154. {
  155. _password = password;
  156. return [self UnzipOpenFile:zipFile];
  157. }
  158. -(BOOL) UnzipFileTo:(NSString*) path overWrite:(BOOL) overwrite
  159. {
  160. BOOL success = YES;
  161. int ret = unzGoToFirstFile( _unzFile );
  162. unsigned char buffer[4096] = {0};
  163. NSFileManager* fman = [NSFileManager defaultManager];
  164. if( ret!=UNZ_OK )
  165. {
  166. [self OutputErrorMessage:@"Failed"];
  167. }
  168. do{
  169. if( [_password length]==0 )
  170. ret = unzOpenCurrentFile( _unzFile );
  171. else
  172. ret = unzOpenCurrentFilePassword( _unzFile, [_password cStringUsingEncoding:NSASCIIStringEncoding] );
  173. if( ret!=UNZ_OK )
  174. {
  175. [self OutputErrorMessage:@"Error occurs"];
  176. success = NO;
  177. break;
  178. }
  179. // reading data and write to file
  180. int read ;
  181. unz_file_info fileInfo ={0};
  182. ret = unzGetCurrentFileInfo(_unzFile, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
  183. if( ret!=UNZ_OK )
  184. {
  185. [self OutputErrorMessage:@"Error occurs while getting file info"];
  186. success = NO;
  187. unzCloseCurrentFile( _unzFile );
  188. break;
  189. }
  190. char* filename = (char*) malloc( fileInfo.size_filename +1 );
  191. unzGetCurrentFileInfo(_unzFile, &fileInfo, filename, fileInfo.size_filename + 1, NULL, 0, NULL, 0);
  192. filename[fileInfo.size_filename] = '\0';
  193. // check if it contains directory
  194. NSString * strPath = [NSString stringWithCString:filename];
  195. BOOL isDirectory = NO;
  196. if( filename[fileInfo.size_filename-1]=='/' || filename[fileInfo.size_filename-1]=='\\')
  197. isDirectory = YES;
  198. free( filename );
  199. if( [strPath rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"/\\"]].location!=NSNotFound )
  200. {// contains a path
  201. strPath = [strPath stringByReplacingOccurrencesOfString:@"\\" withString:@"/"];
  202. }
  203. NSString* fullPath = [path stringByAppendingPathComponent:strPath];
  204. if( isDirectory )
  205. [fman createDirectoryAtPath:fullPath withIntermediateDirectories:YES attributes:nil error:nil];
  206. else
  207. [fman createDirectoryAtPath:[fullPath stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil];
  208. if( [fman fileExistsAtPath:fullPath] && !isDirectory && !overwrite )
  209. {
  210. if( ![self OverWrite:fullPath] )
  211. {
  212. unzCloseCurrentFile( _unzFile );
  213. ret = unzGoToNextFile( _unzFile );
  214. continue;
  215. }
  216. }
  217. FILE* fp = fopen( (const char*)[fullPath UTF8String], "wb");
  218. while( fp )
  219. {
  220. read=unzReadCurrentFile(_unzFile, buffer, 4096);
  221. if( read > 0 )
  222. {
  223. fwrite(buffer, read, 1, fp );
  224. }
  225. else if( read<0 )
  226. {
  227. [self OutputErrorMessage:@"Failed to reading zip file"];
  228. break;
  229. }
  230. else
  231. break;
  232. }
  233. if( fp )
  234. {
  235. fclose( fp );
  236. // set the orignal datetime property
  237. NSDate* orgDate = nil;
  238. //{{ thanks to brad.eaton for the solution
  239. NSDateComponents *dc = [[NSDateComponents alloc] init];
  240. dc.second = fileInfo.tmu_date.tm_sec;
  241. dc.minute = fileInfo.tmu_date.tm_min;
  242. dc.hour = fileInfo.tmu_date.tm_hour;
  243. dc.day = fileInfo.tmu_date.tm_mday;
  244. dc.month = fileInfo.tmu_date.tm_mon+1;
  245. dc.year = fileInfo.tmu_date.tm_year;
  246. NSCalendar *gregorian = [[NSCalendar alloc]
  247. initWithCalendarIdentifier:NSGregorianCalendar];
  248. orgDate = [gregorian dateFromComponents:dc] ;
  249. // [dc release];
  250. // [gregorian release];
  251. //}}
  252. NSDictionary* attr = [NSDictionary dictionaryWithObject:orgDate forKey:NSFileModificationDate]; //[[NSFileManager defaultManager] fileAttributesAtPath:fullPath traverseLink:YES];
  253. if( attr )
  254. {
  255. // [attr setValue:orgDate forKey:NSFileCreationDate];
  256. if( ![[NSFileManager defaultManager] setAttributes:attr ofItemAtPath:fullPath error:nil] )
  257. {
  258. // cann't set attributes
  259. NSLog(@"Failed to set attributes");
  260. }
  261. }
  262. }
  263. unzCloseCurrentFile( _unzFile );
  264. ret = unzGoToNextFile( _unzFile );
  265. }while( ret==UNZ_OK && UNZ_OK!=UNZ_END_OF_LIST_OF_FILE );
  266. return success;
  267. }
  268. -(BOOL) UnzipAllFileToDir:(NSString*) path overWrite:(BOOL) overwrite
  269. {
  270. BOOL success = YES;
  271. int ret = unzGoToFirstFile( _unzFile );
  272. unsigned char buffer[4096] = {0};
  273. NSFileManager* fman = [NSFileManager defaultManager];
  274. if( ret!=UNZ_OK )
  275. {
  276. [self OutputErrorMessage:@"Failed"];
  277. }
  278. do{
  279. if( [_password length]==0 )
  280. ret = unzOpenCurrentFile( _unzFile );
  281. else
  282. ret = unzOpenCurrentFilePassword( _unzFile, [_password cStringUsingEncoding:NSASCIIStringEncoding] );
  283. if( ret!=UNZ_OK )
  284. {
  285. [self OutputErrorMessage:@"Error occurs"];
  286. success = NO;
  287. break;
  288. }
  289. // reading data and write to file
  290. int read ;
  291. unz_file_info fileInfo ={0};
  292. ret = unzGetCurrentFileInfo(_unzFile, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
  293. if( ret!=UNZ_OK )
  294. {
  295. [self OutputErrorMessage:@"Error occurs while getting file info"];
  296. success = NO;
  297. unzCloseCurrentFile( _unzFile );
  298. break;
  299. }
  300. char* filename = (char*) malloc( fileInfo.size_filename +1 );
  301. unzGetCurrentFileInfo(_unzFile, &fileInfo, filename, fileInfo.size_filename + 1, NULL, 0, NULL, 0);
  302. filename[fileInfo.size_filename] = '\0';
  303. NSString* fullPath=nil;
  304. // check if it contains directory
  305. // NSString * strPath = [NSString stringWithCString:filename];
  306. BOOL isDirectory = NO;
  307. if( filename[fileInfo.size_filename-1]=='/' || filename[fileInfo.size_filename-1]=='\\')
  308. {
  309. isDirectory = YES;
  310. fullPath= path;
  311. }
  312. else
  313. {
  314. NSString* fname = [fman displayNameAtPath:[NSString stringWithCString:filename]];
  315. fullPath= [path stringByAppendingPathComponent:fname];
  316. }
  317. free( filename );
  318. // if( [strPath rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"/\\"]].location!=NSNotFound )
  319. // {// contains a path
  320. // strPath = [strPath stringByReplacingOccurrencesOfString:@"\\" withString:@"/"];
  321. // }
  322. if( isDirectory )
  323. [fman createDirectoryAtPath:fullPath withIntermediateDirectories:YES attributes:nil error:nil];
  324. else
  325. [fman createDirectoryAtPath:[fullPath stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil];
  326. if( [fman fileExistsAtPath:fullPath] && !isDirectory && !overwrite )
  327. {
  328. if( ![self OverWrite:fullPath] )
  329. {
  330. unzCloseCurrentFile( _unzFile );
  331. ret = unzGoToNextFile( _unzFile );
  332. continue;
  333. }
  334. }
  335. FILE* fp = fopen( (const char*)[fullPath UTF8String], "wb");
  336. while( fp )
  337. {
  338. read=unzReadCurrentFile(_unzFile, buffer, 4096);
  339. if( read > 0 )
  340. {
  341. fwrite(buffer, read, 1, fp );
  342. }
  343. else if( read<0 )
  344. {
  345. [self OutputErrorMessage:@"Failed to reading zip file"];
  346. break;
  347. }
  348. else
  349. break;
  350. }
  351. if( fp )
  352. {
  353. fclose( fp );
  354. // set the orignal datetime property
  355. NSDate* orgDate = nil;
  356. //{{ thanks to brad.eaton for the solution
  357. NSDateComponents *dc = [[NSDateComponents alloc] init];
  358. dc.second = fileInfo.tmu_date.tm_sec;
  359. dc.minute = fileInfo.tmu_date.tm_min;
  360. dc.hour = fileInfo.tmu_date.tm_hour;
  361. dc.day = fileInfo.tmu_date.tm_mday;
  362. dc.month = fileInfo.tmu_date.tm_mon+1;
  363. dc.year = fileInfo.tmu_date.tm_year;
  364. NSCalendar *gregorian = [[NSCalendar alloc]
  365. initWithCalendarIdentifier:NSGregorianCalendar];
  366. orgDate = [gregorian dateFromComponents:dc] ;
  367. // [dc release];
  368. // [gregorian release];
  369. //}}
  370. NSDictionary* attr = [NSDictionary dictionaryWithObject:orgDate forKey:NSFileModificationDate]; //[[NSFileManager defaultManager] fileAttributesAtPath:fullPath traverseLink:YES];
  371. if( attr )
  372. {
  373. // [attr setValue:orgDate forKey:NSFileCreationDate];
  374. if( ![[NSFileManager defaultManager] setAttributes:attr ofItemAtPath:fullPath error:nil] )
  375. {
  376. // cann't set attributes
  377. NSLog(@"Failed to set attributes");
  378. }
  379. }
  380. }
  381. unzCloseCurrentFile( _unzFile );
  382. ret = unzGoToNextFile( _unzFile );
  383. }while( ret==UNZ_OK && UNZ_OK!=UNZ_END_OF_LIST_OF_FILE );
  384. return success;
  385. }
  386. -(BOOL) UnzipCloseFile
  387. {
  388. _password = nil;
  389. if( _unzFile )
  390. return unzClose( _unzFile )==UNZ_OK;
  391. return YES;
  392. }
  393. #pragma mark wrapper for delegate
  394. -(void) OutputErrorMessage:(NSString*) msg
  395. {
  396. if( _delegate && [_delegate respondsToSelector:@selector(ErrorMessage)] )
  397. [_delegate ErrorMessage:msg];
  398. }
  399. -(BOOL) OverWrite:(NSString*) file
  400. {
  401. if( _delegate && [_delegate respondsToSelector:@selector(OverWriteOperation)] )
  402. return [_delegate OverWriteOperation:file];
  403. return YES;
  404. }
  405. #pragma mark get NSDate object for 1980-01-01
  406. -(NSDate*) Date1980
  407. {
  408. NSDateComponents *comps = [[NSDateComponents alloc] init];
  409. [comps setDay:1];
  410. [comps setMonth:1];
  411. [comps setYear:1980];
  412. NSCalendar *gregorian = [[NSCalendar alloc]
  413. initWithCalendarIdentifier:NSGregorianCalendar];
  414. NSDate *date = [gregorian dateFromComponents:comps];
  415. // [comps release];
  416. // [gregorian release];
  417. return date;
  418. }
  419. @end