iOS gzip 壓縮和解壓

壓縮:

#import <Foundation/Foundation.h>

@interface LFCGzipUtility : NSObject {

    

}

+(NSData*) gzipData: (NSData*)pUncompressedData;

@end



#import "zlib.h"


#import "LFCGzipUtility.h"


@implementation LFCGzipUtility


+(NSData*) gzipData: (NSData*)pUncompressedData

{

    

    if (!pUncompressedData || [pUncompressedData length] == 0)

    {

        NSLog(@"%s: Error: Can't compress an empty or null NSData object.", __func__);

        return nil;

    }

    

    int deflateStatus;

    float buffer = 1.1;

    do {

        z_stream zlibStreamStruct;

        zlibStreamStruct.zalloc    = Z_NULL; // Set zalloc, zfree, and opaque to Z_NULL so

        zlibStreamStruct.zfree     = Z_NULL; // that when we call deflateInit2 they will be

        zlibStreamStruct.opaque    = Z_NULL; // updated to use default allocation functions.

        zlibStreamStruct.total_out = 0; // Total number of output bytes produced so far

        zlibStreamStruct.next_in   = (Bytef*)[pUncompressedData bytes]; // Pointer to input bytes

        zlibStreamStruct.avail_in  = (uInt)[pUncompressedData length]; // Number of input bytes left to process

        

        

        int initError = deflateInit2(&zlibStreamStruct, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY);

        if (initError != Z_OK)

        {

            NSString *errorMsg = nil;

            switch (initError)

            {

                case Z_STREAM_ERROR:

                    errorMsg = @"Invalid parameter passed in to function.";

                    break;

                case Z_MEM_ERROR:

                    errorMsg = @"Insufficient memory.";

                    break;

                case Z_VERSION_ERROR:

                    errorMsg = @"The version of zlib.h and the version of the library linked do not match.";

                    break;

                default:

                    errorMsg = @"Unknown error code.";

                    break;

            }

            NSLog(@"%s: deflateInit2() Error: \"%@\" Message: \"%s\"", __func__, errorMsg, zlibStreamStruct.msg);

            return nil;

        }

    

        // Create output memory buffer for compressed data. The zlib documentation states that

        // destination buffer size must be at least 0.1% larger than avail_in plus 12 bytes.

        NSMutableData *compressedData = [NSMutableData dataWithLength:[pUncompressedData length] * buffer + 12];

        

        do {

            // Store location where next byte should be put in next_out

            zlibStreamStruct.next_out = [compressedData mutableBytes] + zlibStreamStruct.total_out;

            

            // Calculate the amount of remaining free space in the output buffer

            // by subtracting the number of bytes that have been written so far

            // from the buffer's total capacity

            zlibStreamStruct.avail_out = (uInt)([compressedData length] - zlibStreamStruct.total_out);

            

            deflateStatus = deflate(&zlibStreamStruct, Z_FINISH);

            

        } while ( deflateStatus == Z_OK );

        

        if (deflateStatus == Z_BUF_ERROR && buffer < 32) {

            continue;

        }

        

        // Check for zlib error and convert code to usable error message if appropriate

        if (deflateStatus != Z_STREAM_END) {

            NSString *errorMsg = nil;

            switch (deflateStatus)

            {

                case Z_ERRNO:

                    errorMsg = @"Error occured while reading file.";

                    break;

                case Z_STREAM_ERROR:

                    errorMsg = @"The stream state was inconsistent (e.g., next_in or next_out was NULL).";

                    break;

                case Z_DATA_ERROR:

                    errorMsg = @"The deflate data was invalid or incomplete.";

                    break;

                case Z_MEM_ERROR:

                    errorMsg = @"Memory could not be allocated for processing.";

                    break;

                case Z_BUF_ERROR:

                    errorMsg = @"Ran out of output buffer for writing compressed bytes.";

                    break;

                case Z_VERSION_ERROR:

                    errorMsg = @"The version of zlib.h and the version of the library linked do not match.";

                    break;

                default:

                    errorMsg = @"Unknown error code.";

                    break;

            }

            NSLog(@"%s: zlib error while attempting compression: \"%@\" Message: \"%s\"", __func__, errorMsg, zlibStreamStruct.msg);

            

            // Free data structures that were dynamically created for the stream.

            deflateEnd(&zlibStreamStruct);

            

            return nil;

        }

        

        // Free data structures that were dynamically created for the stream.

        deflateEnd(&zlibStreamStruct);

        [compressedData setLength: zlibStreamStruct.total_out];

        

        return compressedData;

    } while ( false );

    return nil;

}


@end


解壓:

服務端使用gzip壓縮,可以大幅度減小傳輸包的體積,加快客戶端網絡請求速度,爲用戶節省流量。當服務器返回的httpHeader的"Content-Encoding" 屬性的值是gzip時,數據會自動被解壓縮,但有時候在客戶端還沒拿到數據的時候,就已經被某些網關解壓了,這樣gzip就沒有起到作用。因此可以約定其他策略,防止網關解壓,例如在別的頭屬性中標記gzip。

如此,就需要我們自己來解壓gzip數據。


方法如下:

添加framework庫中的libbz2.1.0.dylib;

NSData添加方法:

 引入頭文件  #import "zlib.h"


- (NSData *)gzipUnpack

{

    if ([self length] == 0) return self;

 

    unsigned full_length = [self length];

    unsigned half_length = [self length] / 2;

 

    NSMutableData *decompressed = [NSMutableData dataWithLength: full_length +     half_length];

    BOOL done = NO;

    int status;

 

    z_stream strm;

    strm.next_in = (Bytef *)[self bytes];

    strm.avail_in = [self length];

    strm.total_out = 0;

    strm.zalloc = Z_NULL;

    strm.zfree = Z_NULL;

 

    if (inflateInit2(&strm, (15+32)) != Z_OK) return nil;

    while (!done){

      if (strm.total_out >= [decompressed length])

      [decompressed increaseLengthBy: half_length];

      strm.next_out = [decompressed mutableBytes] + strm.total_out;

      strm.avail_out = [decompressed length] - strm.total_out;

 

      // Inflate another chunk.

      status = inflate (&strm, Z_SYNC_FLUSH);

      if (status == Z_STREAM_END) done = YES;

      else if (status != Z_OK) break;

    }

    if (inflateEnd (&strm) != Z_OK) return nil;

 

    // Set real length.

    if (done){

    [decompressed setLength: strm.total_out];

    return [NSData dataWithData: decompressed];

    }

    return nil;

}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章