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

时间:2017-02-13 14:24:09

标签: swift zip ssziparchive

我有以下问题:我通过SSZipArchive(在Swift应用程序中)提取了一个zip文件,并且有一些文件名带有“无效”字符。
我认为原因是我在Windows下压缩文件,因此名称现在用ANSI编码。

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

2 个答案:

答案 0 :(得分:0)

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

好吧,它在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://stackoverflow.com/a/9009321/1033581
// hexChars from Peter, Aug 19 '14: https://stackoverflow.com/a/25378464/1033581
// not implemented as too lengthy: a potential mapping improvement from Moose, Nov 3 '15: https://stackoverflow.com/a/33501154/1033581
- (NSString *)hexString
{
    const char *hexChars = "0123456789ABCDEF";
    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

答案 1 :(得分:0)

official spec表示路径应该在代码页中编码,如果设置了通用字段的第11位:

  

D.1 ZIP格式历来只支持原始的IBM PC   字符编码集,通常称为IBM Code Page 437。   这会将文件名字符存储限制为仅限于   原始MS-DOS范围的值并没有正确支持文件   其他字符编码或语言中的名称。解决这个问题   限制,本规范将支持以下更改。

     

D.2如果未设置通用位11,则为文件名和注释   应符合原始的ZIP字符编码。如果一般   目的位11设置,文件名和注释必须支持   使用该字符的Unicode标准版本4.1.0或更高版本   由UTF-8存储规范定义的编码形式。该   Unicode标准由The Unicode Consortium发布   (www.unicode.org)。存储在ZIP文件中的UTF-8编码数据是   预计不包括字节顺序标记(BOM)。

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