不知道什么情况,做为一个三方广泛使用的框架库,会出现这种比较低级的问题!
还有中文的文件名解压后显示乱码!
经过深入研究排查,发现目录或文件名编码错误!但是POD库,不可能直接在里面改!只能进行封装修改!
修复后的显示:
修复文件代码:头文件
// // ZipRar7zUnArchive.h // ZipRar7zUnArchive // // Created by Saravanan V on 26/04/13. // Copyright (c) 2013 SARAVANAN. All rights reserved. //#import <Foundation/Foundation.h> #import <SSZipArchive/SSZipArchive.h>#define UNIQUE_KEY( x ) NSString * const x = @#xenum{SARFileTypeZIP,SARFileTypeRAR };static UNIQUE_KEY( rar ); static UNIQUE_KEY( zip );typedef void(^completionBlock)(BOOL result);@interface ZipRar7zUnArchive : NSObject{ }+ (BOOL)isPasswordProtectedAtPath:(NSString *)path;+ (BOOL)unarchiveFrom:(NSString *)filePath toPath:(NSString *)topath password:(NSString *)password; @end
实现逻辑:
// // ZipRar7zUnArchive.m // ZipRar7zUnArchive // // Created by Saravanan V on 26/04/13. // Copyright (c) 2013 SARAVANAN. All rights reserved. //#import "ZipRar7zUnArchive.h"#import <UnrarKit/UnrarKit.h> #import "LzmaSDKObjC.h"#import "SSZipCommon.h" #import "mz_compat.h" #import "mz_zip.h"#include <zlib.h> #include <sys/stat.h>@interface ZipRar7zUnArchive ()<SSZipArchiveDelegate>{ } @property (nonatomic, strong) SSZipArchive *zipArchive;@property (nonatomic, strong) NSString *filePath; @property (nonatomic, strong) NSString *password; @property (nonatomic, strong) NSString *destinationPath; @end@implementation ZipRar7zUnArchive+ (ZipRar7zUnArchive *)instance {static dispatch_once_t onceToken;static ZipRar7zUnArchive *m = nil;dispatch_once(&onceToken, ^{m = [[ZipRar7zUnArchive alloc] init];});return m; }#pragma mark - Init Methods + (BOOL)unarchiveFrom:(NSString *)filePath toPath:(NSString *)topath password:(NSString *)password {ZipRar7zUnArchive *a = [ZipRar7zUnArchive instance];[a setFilePath:filePath];[a setDestinationPath:topath];[a setPassword:password];return [a decompress]; }+ (BOOL)isPasswordProtectedAtPath:(NSString *)path {NSError *archiveError = nil;//URKArchive用来判断是否要输入密码,filePath是要解压的文件路径URKArchive *archive = [[URKArchive alloc] initWithPath:path error:&archiveError];if ([archive isPasswordProtected]) {return YES;}return NO; }#pragma mark - Helper Methods - (NSString *)fileType{NSArray *derivedPathArr = [_filePath componentsSeparatedByString:@"/"];NSString *lastObject = [derivedPathArr lastObject];NSString *fileType = [[lastObject componentsSeparatedByString:@"."] lastObject];return [fileType lowercaseString]; }#pragma mark - Decompressing Methods - (BOOL)decompress{// NSLog(@"_fileType : %@",_fileType);if ( [[self fileType] compare:rar options:NSCaseInsensitiveSearch] == NSOrderedSame ) {return [self rarDecompress];}else if ( [[self fileType] compare:zip options:NSCaseInsensitiveSearch] == NSOrderedSame ) {return [self zipDecompress];}else if ( [[self fileType] compare:@"7z" options:NSCaseInsensitiveSearch] == NSOrderedSame ) {return [self decompress7z];}return NO; }- (BOOL)rarDecompress { // _filePath = [[NSBundle mainBundle] pathForResource:@"example" ofType:@"rar"];NSLog(@"filePath : %@",_filePath);NSLog(@"destinationPath : %@",_destinationPath);NSError *archiveError = nil;URKArchive *archive = [[URKArchive alloc] initWithPath:_filePath error:&archiveError];if (!archive) {NSLog(@"Failed!");return NO;}NSError *error = nil;NSArray *filenames = [archive listFilenames:&error];if (archive.isPasswordProtected) {archive.password = self.password;}if (error) {NSLog(@"Error reading archive: %@", error);return NO;}// for (NSString *filename in filenames) { // NSLog(@"File: %@", filename); // }// Extract a file into memory just to validate if it works/extracts[archive extractDataFromFile:filenames[0] progress:nil error:&error];if (error) {if (error.code == ERAR_MISSING_PASSWORD) {NSLog(@"Password protected archive! Please provide a password for the archived file.");}return NO;}else {return true;} }- (BOOL)zipDecompress{/*BOOL unzipped = [SSZipArchive unzipFileAtPath:_filePath toDestination:_destinationPath delegate:self];*/BOOL unzipped = [SSZipArchive unzipFileAtPath:self.filePath toDestination:self.destinationPath fileName:[self.destinationPath lastPathComponent] preserveAttributes:YES overwrite:YES nestedZipLevel:0 password:nil error:nil delegate:self progressHandler:nil completionHandler:nil];; // NSLog(@"unzipped : %d",unzipped);NSError *error;if (self.password != nil && self.password.length > 0) { // unzipped = [SSZipArchive unzipFileAtPath:_filePath toDestination:_destinationPath overwrite:NO password:self.password error:&error delegate:self]; // unzipped = [SSZipArchive unzipFileAtPath:_filePath toDestination:_destinationPath fileName:@"" preserveAttributes:YES overwrite:NO nestedZipLevel:0 password:self.password error:error delegate:self progressHandler:nil completionHandler:nil];NSLog(@"error: %@", error);}return unzipped; }- (BOOL)decompress7z{NSLog(@"_filePath: %@", _filePath);NSLog(@"_destinationPath: %@", _destinationPath);// LzmaSDKObjCReader *reader = [[LzmaSDKObjCReader alloc] initWithFileURL:[NSURL fileURLWithPath:_filePath]];// 1.2 Or create with predefined archive type if path doesn't containes suitable extensionLzmaSDKObjCReader *reader = [[LzmaSDKObjCReader alloc] initWithFileURL:[NSURL fileURLWithPath:_filePath] andType:LzmaSDKObjCFileType7z];// // Optionaly: assign weak delegate for tracking extract progress. // reader.delegate = self;// If achive encrypted - define password getter handler.// NOTES:// - Encrypted file needs password for extract process.// - Encrypted file with encrypted header needs password for list(iterate) and extract archive items.reader.passwordGetter = ^NSString*(void){ // return @"password to my achive";NSLog(@"self.password: %@", self.password);return self.password;};// Open archive, with or without error. Error can be nil.NSError * error = nil;if (![reader open:&error]) {NSLog(@"Open error: %@", error);}NSLog(@"Open error: %@", reader.lastError);NSMutableArray *filePathsArray = [NSMutableArray array];NSMutableArray * items = [NSMutableArray array]; // Array with selected items.// Iterate all archive items, track what items do you need & hold them in array.[reader iterateWithHandler:^BOOL(LzmaSDKObjCItem * item, NSError * error){ // NSLog(@"\nitem:%@", item);if (item) {[items addObject:item]; // if needs this item - store to array.if (!item.isDirectory) {NSString *filePath = [_destinationPath stringByAppendingPathComponent:item.directoryPath];filePath = [filePath stringByAppendingPathComponent:item.fileName];[filePathsArray addObject:filePath];}}return YES; // YES - continue iterate, NO - stop iteration}];NSLog(@"Iteration error: %@", reader.lastError);// Extract selected items from prev. step.// YES - create subfolders structure for the items.// NO - place item file to the root of path(in this case items with the same names will be overwrited automaticaly).[reader extract:itemstoPath:_destinationPathwithFullPaths:YES];NSLog(@"Extract error: %@", reader.lastError);// Test selected items from prev. step.[reader test:items];NSLog(@"test error: %@", reader.lastError);if (reader.lastError || ![filePathsArray count]) {return NO;}else {return YES;} }#pragma mark - Utility Methods - (NSString *) applicationDocumentsDirectory {NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;return basePath; }@endBOOL _afileIsSymbolicLink(const unz_file_info *fileInfo) {//// Determine whether this is a symbolic link:// - File is stored with 'version made by' value of UNIX (3),// as per https://www.pkware.com/documents/casestudies/APPNOTE.TXT// in the upper byte of the version field.// - BSD4.4 st_mode constants are stored in the high 16 bits of the// external file attributes (defacto standard, verified against libarchive)//// The original constants can be found here:// https://minnie.tuhs.org/cgi-bin/utree.pl?file=4.4BSD/usr/include/sys/stat.h//const uLong ZipUNIXVersion = 3;const uLong BSD_SFMT = 0170000;const uLong BSD_IFLNK = 0120000;BOOL fileIsSymbolicLink = ((fileInfo->version >> 8) == ZipUNIXVersion) && BSD_IFLNK == (BSD_SFMT & (fileInfo->external_fa >> 16));return fileIsSymbolicLink; }@interface SSZipArchive (extra) + (BOOL)unzipFileAtPath:(NSString *)pathtoDestination:(NSString *)destinationfileName:(NSString *)fileNamepreserveAttributes:(BOOL)preserveAttributesoverwrite:(BOOL)overwritenestedZipLevel:(NSInteger)nestedZipLevelpassword:(nullable NSString *)passworderror:(NSError **)errordelegate:(nullable id<SSZipArchiveDelegate>)delegateprogressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandlercompletionHandler:(void (^_Nullable)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler;+ (NSString *)filenameStringWithCString:(const char *)filenameversion_made_by:(uint16_t)version_made_bygeneral_purpose_flag:(uint16_t)flagsize:(uint16_t)size_filename; @end@implementation SSZipArchive (extra)+ (BOOL)unzipFileAtPath:(NSString *)pathtoDestination:(NSString *)destinationfileName:(NSString *)fileNamepreserveAttributes:(BOOL)preserveAttributesoverwrite:(BOOL)overwritenestedZipLevel:(NSInteger)nestedZipLevelpassword:(nullable NSString *)passworderror:(NSError **)errordelegate:(nullable id<SSZipArchiveDelegate>)delegateprogressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandlercompletionHandler:(void (^_Nullable)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler {// Guard against empty stringsif (path.length == 0 || destination.length == 0){NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"received invalid argument(s)"};NSError *err = [NSError errorWithDomain:SSZipArchiveErrorDomain code:SSZipArchiveErrorCodeInvalidArguments userInfo:userInfo];if (error){*error = err;}if (completionHandler){completionHandler(nil, NO, err);}return NO;}// Begin openingzipFile zip = unzOpen(path.fileSystemRepresentation);if (zip == NULL){NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"failed to open zip file"};NSError *err = [NSError errorWithDomain:SSZipArchiveErrorDomain code:SSZipArchiveErrorCodeFailedOpenZipFile userInfo:userInfo];if (error){*error = err;}if (completionHandler){completionHandler(nil, NO, err);}return NO;}NSDictionary * fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil];unsigned long long fileSize = [[fileAttributes objectForKey:NSFileSize] unsignedLongLongValue];unsigned long long currentPosition = 0;unz_global_info globalInfo = {};unzGetGlobalInfo(zip, &globalInfo);// Begin unzippingint ret = 0;ret = unzGoToFirstFile(zip);if (ret != UNZ_OK && ret != MZ_END_OF_LIST){NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"failed to open first file in zip file"};NSError *err = [NSError errorWithDomain:SSZipArchiveErrorDomain code:SSZipArchiveErrorCodeFailedOpenFileInZip userInfo:userInfo];if (error){*error = err;}if (completionHandler){completionHandler(nil, NO, err);}unzClose(zip);return NO;}BOOL success = YES;BOOL canceled = NO;int crc_ret = 0;unsigned char buffer[4096] = {0};NSFileManager *fileManager = [NSFileManager defaultManager];NSMutableArray<NSDictionary *> *directoriesModificationDates = [[NSMutableArray alloc] init];// Message delegateif ([delegate respondsToSelector:@selector(zipArchiveWillUnzipArchiveAtPath:zipInfo:)]) {[delegate zipArchiveWillUnzipArchiveAtPath:path zipInfo:globalInfo];}if ([delegate respondsToSelector:@selector(zipArchiveProgressEvent:total:)]) {[delegate zipArchiveProgressEvent:currentPosition total:fileSize];}NSInteger currentFileNumber = -1;NSError *unzippingError;do {currentFileNumber++;if (ret == MZ_END_OF_LIST) {break;}@autoreleasepool {if (password.length == 0) {ret = unzOpenCurrentFile(zip);} else {ret = unzOpenCurrentFilePassword(zip, [password cStringUsingEncoding:NSUTF8StringEncoding]);}if (ret != UNZ_OK) {unzippingError = [NSError errorWithDomain:@"SSZipArchiveErrorDomain" code:SSZipArchiveErrorCodeFailedOpenFileInZip userInfo:@{NSLocalizedDescriptionKey: @"failed to open file in zip file"}];success = NO;break;}// Reading data and write to fileunz_file_info fileInfo;memset(&fileInfo, 0, sizeof(unz_file_info));ret = unzGetCurrentFileInfo(zip, &fileInfo, NULL, 0, NULL, 0, NULL, 0);if (ret != UNZ_OK) {unzippingError = [NSError errorWithDomain:@"SSZipArchiveErrorDomain" code:SSZipArchiveErrorCodeFileInfoNotLoadable userInfo:@{NSLocalizedDescriptionKey: @"failed to retrieve info for file"}];success = NO;unzCloseCurrentFile(zip);break;}currentPosition += fileInfo.compressed_size;// Message delegateif ([delegate respondsToSelector:@selector(zipArchiveShouldUnzipFileAtIndex:totalFiles:archivePath:fileInfo:)]) {if (![delegate zipArchiveShouldUnzipFileAtIndex:currentFileNumbertotalFiles:(NSInteger)globalInfo.number_entryarchivePath:pathfileInfo:fileInfo]) {success = NO;canceled = YES;break;}}if ([delegate respondsToSelector:@selector(zipArchiveWillUnzipFileAtIndex:totalFiles:archivePath:fileInfo:)]) {[delegate zipArchiveWillUnzipFileAtIndex:currentFileNumber totalFiles:(NSInteger)globalInfo.number_entryarchivePath:path fileInfo:fileInfo];}if ([delegate respondsToSelector:@selector(zipArchiveProgressEvent:total:)]) {[delegate zipArchiveProgressEvent:(NSInteger)currentPosition total:(NSInteger)fileSize];}char *filename = (char *)malloc(fileInfo.size_filename + 1);if (filename == NULL){success = NO;break;}unzGetCurrentFileInfo(zip, &fileInfo, filename, fileInfo.size_filename + 1, NULL, 0, NULL, 0);filename[fileInfo.size_filename] = '\0';BOOL fileIsSymbolicLink = _afileIsSymbolicLink(&fileInfo);const char *cname = [fileName cStringUsingEncoding:NSUTF8StringEncoding];NSString * strPath = [SSZipArchive filenameStringWithCString:filenameversion_made_by:fileInfo.versiongeneral_purpose_flag:fileInfo.flagsize:fileInfo.size_filename];if ([strPath hasPrefix:@"__MACOSX/"]) {// ignoring resource forks: https://superuser.com/questions/104500/what-is-macosx-folderunzCloseCurrentFile(zip);ret = unzGoToNextFile(zip); // free(filename);continue;}// Check if it contains directoryBOOL isDirectory = NO;if (filename[fileInfo.size_filename-1] == '/' || filename[fileInfo.size_filename-1] == '\\') {isDirectory = YES;}free(filename);// Sanitize paths in the file name.strPath = [strPath _sanitizedPath];if (!strPath.length) {// if filename data is unsalvageable, we default to currentFileNumberstrPath = @(currentFileNumber).stringValue;}NSString *fullPath = [destination stringByAppendingPathComponent:strPath];NSError *err = nil;NSDictionary *directoryAttr;if (preserveAttributes) {NSDate *modDate = [[self class] _dateWithMSDOSFormat:(UInt32)fileInfo.mz_dos_date];directoryAttr = @{NSFileCreationDate: modDate, NSFileModificationDate: modDate};[directoriesModificationDates addObject: @{@"path": fullPath, @"modDate": modDate}];}if (isDirectory) {[fileManager createDirectoryAtPath:fullPath withIntermediateDirectories:YES attributes:directoryAttr error:&err];} else {[fileManager createDirectoryAtPath:fullPath.stringByDeletingLastPathComponent withIntermediateDirectories:YES attributes:directoryAttr error:&err];}if (err != nil) {if ([err.domain isEqualToString:NSCocoaErrorDomain] &&err.code == 640) {unzippingError = err;unzCloseCurrentFile(zip);success = NO;break;}NSLog(@"[SSZipArchive] Error: %@", err.localizedDescription);}if ([fileManager fileExistsAtPath:fullPath] && !isDirectory && !overwrite) {//FIXME: couldBe CRC Check?unzCloseCurrentFile(zip);ret = unzGoToNextFile(zip);continue;}if (isDirectory && !fileIsSymbolicLink) {// nothing to read/write for a directory} else if (!fileIsSymbolicLink) {// ensure we are not creating stale file entriesint readBytes = unzReadCurrentFile(zip, buffer, 4096);if (readBytes >= 0) {FILE *fp = fopen(fullPath.fileSystemRepresentation, "wb");while (fp) {if (readBytes > 0) {if (0 == fwrite(buffer, readBytes, 1, fp)) {if (ferror(fp)) {NSString *message = [NSString stringWithFormat:@"Failed to write file (check your free space)"];NSLog(@"[SSZipArchive] %@", message);success = NO;unzippingError = [NSError errorWithDomain:@"SSZipArchiveErrorDomain" code:SSZipArchiveErrorCodeFailedToWriteFile userInfo:@{NSLocalizedDescriptionKey: message}];break;}}} else {break;}readBytes = unzReadCurrentFile(zip, buffer, 4096);if (readBytes < 0) {// Let's assume error Z_DATA_ERROR is caused by an invalid password// Let's assume other errors are caused by Content Not Readablesuccess = NO;}}if (fp) {fclose(fp);if (nestedZipLevel&& [fullPath.pathExtension.lowercaseString isEqualToString:@"zip"]&& [self unzipFileAtPath:fullPathtoDestination:fullPath.stringByDeletingLastPathComponentpreserveAttributes:preserveAttributesoverwrite:overwritenestedZipLevel:nestedZipLevel - 1password:passworderror:nildelegate:nilprogressHandler:nilcompletionHandler:nil]) {[directoriesModificationDates removeLastObject];[[NSFileManager defaultManager] removeItemAtPath:fullPath error:nil];} else if (preserveAttributes) {// Set the original datetime propertyif (fileInfo.mz_dos_date != 0) {NSDate *orgDate = [[self class] _dateWithMSDOSFormat:(UInt32)fileInfo.mz_dos_date];NSDictionary *attr = @{NSFileModificationDate: orgDate};if (attr) {if (![fileManager setAttributes:attr ofItemAtPath:fullPath error:nil]) {// Can't set attributesNSLog(@"[SSZipArchive] Failed to set attributes - whilst setting modification date");}}}// Set the original permissions on the file (+read/write to solve #293)uLong permissions = fileInfo.external_fa >> 16 | 0b110000000;if (permissions != 0) {// Store it into a NSNumberNSNumber *permissionsValue = @(permissions);// Retrieve any existing attributesNSMutableDictionary *attrs = [[NSMutableDictionary alloc] initWithDictionary:[fileManager attributesOfItemAtPath:fullPath error:nil]];// Set the value in the attributes dict[attrs setObject:permissionsValue forKey:NSFilePosixPermissions];// Update attributesif (![fileManager setAttributes:attrs ofItemAtPath:fullPath error:nil]) {// Unable to set the permissions attributeNSLog(@"[SSZipArchive] Failed to set attributes - whilst setting permissions");}}}}else{// if we couldn't open file descriptor we can validate global errno to see the reasonint errnoSave = errno;BOOL isSeriousError = NO;switch (errnoSave) {case EISDIR:// Is a directory// assumed casebreak;case ENOSPC:case EMFILE:// No space left on device// or// Too many open filesisSeriousError = YES;break;default:// ignore case// Just log the error{NSError *errorObject = [NSError errorWithDomain:NSPOSIXErrorDomaincode:errnoSaveuserInfo:nil];NSLog(@"[SSZipArchive] Failed to open file on unzipping.(%@)", errorObject);}break;}if (isSeriousError) {// serious caseunzippingError = [NSError errorWithDomain:NSPOSIXErrorDomaincode:errnoSaveuserInfo:nil];unzCloseCurrentFile(zip);// Log the errorNSLog(@"[SSZipArchive] Failed to open file on unzipping.(%@)", unzippingError);// Break unzippingsuccess = NO;break;}}} else {// Let's assume error Z_DATA_ERROR is caused by an invalid password// Let's assume other errors are caused by Content Not Readablesuccess = NO;break;}}else{// Assemble the path for the symbolic linkNSMutableString *destinationPath = [NSMutableString string];int bytesRead = 0;while ((bytesRead = unzReadCurrentFile(zip, buffer, 4096)) > 0){buffer[bytesRead] = 0;[destinationPath appendString:@((const char *)buffer)];}if (bytesRead < 0) {// Let's assume error Z_DATA_ERROR is caused by an invalid password// Let's assume other errors are caused by Content Not Readablesuccess = NO;break;}// Check if the symlink exists and delete it if we're overwritingif (overwrite){if ([fileManager fileExistsAtPath:fullPath]){NSError *localError = nil;BOOL removeSuccess = [fileManager removeItemAtPath:fullPath error:&localError];if (!removeSuccess){NSString *message = [NSString stringWithFormat:@"Failed to delete existing symbolic link at \"%@\"", localError.localizedDescription];NSLog(@"[SSZipArchive] %@", message);success = NO;unzippingError = [NSError errorWithDomain:SSZipArchiveErrorDomain code:localError.code userInfo:@{NSLocalizedDescriptionKey: message}];}}}// Create the symbolic link (making sure it stays relative if it was relative before)int symlinkError = symlink([destinationPath cStringUsingEncoding:NSUTF8StringEncoding],[fullPath cStringUsingEncoding:NSUTF8StringEncoding]);if (symlinkError != 0){// Bubble the error up to the completion handlerNSString *message = [NSString stringWithFormat:@"Failed to create symbolic link at \"%@\" to \"%@\" - symlink() error code: %d", fullPath, destinationPath, errno];NSLog(@"[SSZipArchive] %@", message);success = NO;unzippingError = [NSError errorWithDomain:NSPOSIXErrorDomain code:symlinkError userInfo:@{NSLocalizedDescriptionKey: message}];}}crc_ret = unzCloseCurrentFile(zip);if (crc_ret == MZ_CRC_ERROR) {// CRC ERRORsuccess = NO;break;}ret = unzGoToNextFile(zip);// Message delegateif ([delegate respondsToSelector:@selector(zipArchiveDidUnzipFileAtIndex:totalFiles:archivePath:fileInfo:)]) {[delegate zipArchiveDidUnzipFileAtIndex:currentFileNumber totalFiles:(NSInteger)globalInfo.number_entryarchivePath:path fileInfo:fileInfo];} else if ([delegate respondsToSelector: @selector(zipArchiveDidUnzipFileAtIndex:totalFiles:archivePath:unzippedFilePath:)]) {[delegate zipArchiveDidUnzipFileAtIndex: currentFileNumber totalFiles: (NSInteger)globalInfo.number_entryarchivePath:path unzippedFilePath: fullPath];}if (progressHandler){progressHandler(strPath, fileInfo, currentFileNumber, globalInfo.number_entry);}}} while (ret == UNZ_OK && success);// CloseunzClose(zip);// The process of decompressing the .zip archive causes the modification times on the folders// to be set to the present time. So, when we are done, they need to be explicitly set.// set the modification date on all of the directories.if (success && preserveAttributes) {NSError * err = nil;for (NSDictionary * d in directoriesModificationDates) {if (![[NSFileManager defaultManager] setAttributes:@{NSFileModificationDate: [d objectForKey:@"modDate"]} ofItemAtPath:[d objectForKey:@"path"] error:&err]) {NSLog(@"[SSZipArchive] Set attributes failed for directory: %@.", [d objectForKey:@"path"]);}if (err) {NSLog(@"[SSZipArchive] Error setting directory file modification date attribute: %@", err.localizedDescription);}}}// Message delegateif (success && [delegate respondsToSelector:@selector(zipArchiveDidUnzipArchiveAtPath:zipInfo:unzippedPath:)]) {[delegate zipArchiveDidUnzipArchiveAtPath:path zipInfo:globalInfo unzippedPath:destination];}// final progress event = 100%if (!canceled && [delegate respondsToSelector:@selector(zipArchiveProgressEvent:total:)]) {[delegate zipArchiveProgressEvent:fileSize total:fileSize];}NSError *retErr = nil;if (crc_ret == MZ_CRC_ERROR){NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"crc check failed for file"};retErr = [NSError errorWithDomain:SSZipArchiveErrorDomain code:SSZipArchiveErrorCodeFileInfoNotLoadable userInfo:userInfo];}if (error) {if (unzippingError) {*error = unzippingError;}else {*error = retErr;}}if (completionHandler){if (unzippingError) {completionHandler(path, success, unzippingError);}else{completionHandler(path, success, retErr);}}return success; }+ (NSString *)filenameStringWithCString:(const char *)filenameversion_made_by:(uint16_t)version_made_bygeneral_purpose_flag:(uint16_t)flagsize:(uint16_t)size_filename {// Respect Language encoding flag only reading filename as UTF-8 when this is set// when file entry created on dos system.//// https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT// Bit 11: Language encoding flag (EFS). If this bit is set,// the filename and comment fields for this file// MUST be encoded using UTF-8. (see APPENDIX D)uint16_t made_by = version_made_by >> 8;BOOL made_on_dos = made_by == 0;BOOL languageEncoding = (flag & (1 << 11)) != 0;if (!languageEncoding && made_on_dos) {// APPNOTE.TXT D.1:// D.2 If general purpose bit 11 is unset, the file name and comment should conform// to the original ZIP character encoding. If general purpose bit 11 is set, the// filename and comment must support The Unicode Standard, Version 4.1.0 or// greater using the character encoding form defined by the UTF-8 storage// specification. The Unicode Standard is published by the The Unicode// Consortium (www.unicode.org). UTF-8 encoded data stored within ZIP files// is expected to not include a byte order mark (BOM).// Code Page 437 corresponds to kCFStringEncodingDOSLatinUSNSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingDOSChineseSimplif);NSString* strPath = [NSString stringWithCString:filename encoding:encoding];if (strPath) {return strPath;}}// attempting unicode encodingNSString * strPath = @(filename);if (strPath) {return strPath;}// if filename is non-unicode, detect and transform EncodingNSData *data = [NSData dataWithBytes:(const void *)filename length:sizeof(unsigned char) * size_filename]; // Testing availability of @available (https://stackoverflow.com/a/46927445/1033581) #if __clang_major__ < 9// Xcode 8-if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber10_9_2) { #else// Xcode 9+if (@available(macOS 10.10, iOS 8.0, watchOS 2.0, tvOS 9.0, *)) { #endif// supported encodings are in [NSString availableStringEncodings][NSString stringEncodingForData:data encodingOptions:nil convertedString:&strPath usedLossyConversion:nil];} else {// fallback to a simple manual detect for macOS 10.9 or olderNSArray<NSNumber *> *encodings = @[@(kCFStringEncodingGB_18030_2000), @(kCFStringEncodingShiftJIS)];for (NSNumber *encoding in encodings) {strPath = [NSString stringWithCString:filename encoding:(NSStringEncoding)CFStringConvertEncodingToNSStringEncoding(encoding.unsignedIntValue)];if (strPath) {break;}}}if (strPath) {return strPath;}// if filename encoding is non-detected, we default to something based on data// _hexString is more readable than _base64RFC4648 for debugging unknown encodingsstrPath = [data _hexString];return strPath; } @end