CFStringCreateWithBytes 提升异常容错性

2018-11-09  本文已影响0人  yellowzhou

在 iOS 开发中,经常会遇到编码问题,通过系统API转码时由于没有容错性,导致因为个别异常编码问题,让全部转码失败。

CFStringRef CFStringCreateWithBytes(CFAllocatorRef alloc, const UInt8 *bytes, CFIndex numBytes, CFStringEncoding encoding, Boolean isExternalRepresentation);

检验GB18030 异常编码

unsigned int checkGB18030(const unsigned char *bytes, unsigned int length, unsigned char *buffer)
{
    unsigned int bufferIndex = 0;
    unsigned int byteIndex = 0;
    bool invalidByte = false;
    while (byteIndex < length) {
        Byte byte = bytes[byteIndex];
        if (byte >= 0 && byte <= (Byte)0x7f) {
            //单字节(英文、数字)
            buffer[bufferIndex++] = byte;
        } else if (byte >= (Byte)0x81 && byte <= (Byte)0xfe){
            //可能是双字节,可能是四字节
            if (byteIndex + 1 >= length) {
                //这是最后一个字节了,但是这个字节表明后面应该还有1或3个字节,那么这个字节一定是错误字节
                break;
            }
            
            Byte byte2 = bytes[++byteIndex];
            if (byte2 >= (Byte)0x40 && byte <= (Byte)0xfe && byte != (Byte)0x7f) {
                //是双字节,并且可能合法
                unsigned char tuple[] = {byte, byte2};
                CFStringRef cfstr = CFStringCreateWithBytes(kCFAllocatorDefault, tuple, 2, kCFStringEncodingGB_18030_2000, false);
                if (cfstr) {
                    CFRelease(cfstr);
                    buffer[bufferIndex++] = byte;
                    buffer[bufferIndex++] = byte2;
                } else {
                    //这个双字节字符不合法,但byte2可能是下一字符的第一字节
                    invalidByte = true;
                }
            } else if (byte2 >= (Byte)0x30 && byte2 <= (Byte)0x39) {
                //可能是四字节
                if (byteIndex + 2 >= length) {
                    break;
                }
                
                Byte byte3 = bytes[++byteIndex];
                if (byte3 >= (Byte)0x81 && byte3 <= (Byte)0xfe) {
                    // 第三位合法,判断第四位
                    
                    Byte byte4 = bytes[++byteIndex];
                    if (byte4 >= (Byte)0x30 && byte4 <= (Byte)0x39) {
                        //第四位可能合法
                        unsigned char tuple[] = {byte, byte2, byte3, byte4};
                        CFStringRef cfstr = CFStringCreateWithBytes(kCFAllocatorDefault, tuple, 4, kCFStringEncodingGB_18030_2000, false);
                        if (cfstr) {
                            CFRelease(cfstr);
                            buffer[bufferIndex++] = byte;
                            buffer[bufferIndex++] = byte2;
                            buffer[bufferIndex++] = byte3;
                            buffer[bufferIndex++] = byte4;
                        } else {
                            //这个四字节字符不合法,但是byte2可能是下一个合法字符的第一字节,回退3位
                            //并且将byte1,byte2用?替代
                            invalidByte = true;
                        }
                    } else {
                        //第四字节不合法
                        invalidByte = true;
                    }
                } else {
                    // 第三字节不合法
                    invalidByte = true;
                }
            } else {
                // 第二字节不是合法的第二位,但可能是下一个合法的第一位,所以回退一个byte
                invalidByte = true;
            }
            
            if (invalidByte) {
                invalidByte = false;
                buffer[bufferIndex++] = '?';
            }
        }
        byteIndex++;
        
    }
    return bufferIndex;
}

具体测试代码

void test()
{
    char *base64 = "CTxkaXY+us69KioKCQkJCQk8c3Bhbj4x";
    char buffer[1024] = {0};
    
    NSData *data64 = [NSData dataWithBytes:base64 length:strlen(base64)];
    NSData *decodeData = [GTMBase64 decodeData:data64];
    const unsigned char *bytes = (void *)[decodeData bytes];
    NSUInteger lenght = [decodeData length];
    printf("base64: %s",bytes);
    CFStringRef cfstr = CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8 *)bytes, lenght, kCFStringEncodingGB_18030_2000, false);
    if (cfstr) {
        NSString *text = (__bridge NSString *)cfstr;
        NSLog(@"%@",text);
        CFRelease(cfstr);
    } else {
        lenght = checkGB18030(bytes, (unsigned int)lenght, (unsigned char *)buffer);
        cfstr = CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8 *)buffer, lenght, kCFStringEncodingGB_18030_2000, false);
        if (cfstr) {
            NSString *text = (__bridge NSString *)cfstr;
            NSLog(@"%@",text);
            CFRelease(cfstr);
        } else {
            NSLog(@"解析错误!!!!");
        }
    }
}

测试结果

test.png
上一篇 下一篇

猜你喜欢

热点阅读