错误的字符集文件名后解压

问题描述:

我有以下问题:我通过提取一个SSZipArchive zip文件(在斯威夫特的应用程序),并有与“无效”字的某些文件名。
我认为原因是我压缩了Windows下的文件,所以名称现在用ANSI编码。错误的字符集文件名后解压

有没有办法在解压缩过程中所有的“损坏”文件夹和文件名转换?
或更高版本?如果我必须迭代文件夹树并重命名文件,这将是没有问题的。
但我不知道如何找出哪些名称是在ANSI中设置的,我也不知道如何更正字符集。

+0

请提供样本zip并在github跟踪器上报告 –

可能在最新的SSZipArchive(目前2.1.1)中修复。我已经以类似于下面的代码的方式实现了对非Unicode文件名的支持,所以如果您愿意,您可以重复使用它来自己处理文件名。

OK,这是在Objective-C,但由于SSZipArchive具有自身修复已经,您应该不再需要它。否则,要么创建一个桥接头来包含Objective-C代码到你的swift应用中,要么将它转换成Swift(应该很容易)。

@implementation NSString (SSZipArchive) 

+ (NSString *)filenameStringWithCString:(const char *)filename size:(uint16_t)size_filename 
{ 
    // unicode conversion attempt 
    NSString *strPath = @(filename); 
    if (strPath) { 
     return strPath; 
    } 

    // if filename is non-unicode, detect and transform Encoding 
    NSData *data = [NSData dataWithBytes:(const void *)filename length:sizeof(unsigned char) * size_filename]; 
    // supported encodings are in [NSString availableStringEncodings] 
    [NSString stringEncodingForData:data encodingOptions:nil convertedString:&strPath usedLossyConversion:nil]; 
    if (strPath) { 
     return strPath; 
    } 

    // if filename encoding is non-detected, we default to something based on data 
    // note: hexString is more readable than base64RFC4648 for debugging unknown encodings 
    strPath = [data hexString]; 
    return strPath; 
} 
@end 

@implementation NSData (SSZipArchive) 

// initWithBytesNoCopy from NSProgrammer, Jan 25 '12: https://*.com/a/9009321/1033581 
// hexChars from Peter, Aug 19 '14: https://*.com/a/25378464/1033581 
// not implemented as too lengthy: a potential mapping improvement from Moose, Nov 3 '15: https://*.com/a/33501154/1033581 
- (NSString *)hexString 
{ 
    const char *hexChars = "ABCDEF"; 
    NSUInteger length = self.length; 
    const unsigned char *bytes = self.bytes; 
    char *chars = malloc(length * 2); 
    // TODO: check for NULL 
    char *s = chars; 
    NSUInteger i = length; 
    while (i--) { 
     *s++ = hexChars[*bytes >> 4]; 
     *s++ = hexChars[*bytes & 0xF]; 
     bytes++; 
    } 
    NSString *str = [[NSString alloc] initWithBytesNoCopy:chars 
                length:length * 2 
               encoding:NSASCIIStringEncoding 
              freeWhenDone:YES]; 
    return str; 
} 
@end 

official spec说,路径应在代码页437 MS-DOS拉丁美或UTF-8(如果通用字段的第11位被置位)被任一编码:

d 0.1 ZIP格式历来支持只有原来的IBM PC 字符编码集,通常被称为IBM代码页437 此限制存储的文件名字符,只有那些值的 原始MS-DOS的范围内,并且不以其他字符编码或语言正确支持文件 。为解决此限制,本规范将支持以下更改。

D.2如果通用11位没有设置,文件名和注释 应符合原ZIP字符编码。如果一般 目的位11被设置为,文件名和注释必须支持的 Unicode标准,版本4.1.0或使用由UTF-8存储规范中定义的字符 编码形式越大。 Unicode标准由Unicode联盟 (www.unicode.org)发布。存储在ZIP文件中的UTF-8编码数据为 ,预期不包含字节顺序标记(BOM)。

我最近发布了名为ZIPFoundation ZIP文件格式的斯威夫特开源实现。它符合标准,应该能够检测Windows路径名并正确解码它们。