ios-gzip压缩和解压缩

时间:2022-05-21 19:58:50

转自:http://www.helmsmansoft.com/index.php/archives/1807

使用zlib来实现对数据的压缩

/*

压缩和解压缩函数

数据压缩参考:

http://www.clintharris.net/2009/how-to-gzip-data-in-memory-using-objective-c/

数据解压缩参考:

ASIHttpRequest库的文件:ASIDataDecompressor.m

*/

添加 libbz2.1.0.dylib xcode4.5还需添加libz.dylib

头文件 .h文件

#import <Foundation/Foundation.h>
#import "zlib.h"
 
@interface LFCGzipUtility : NSObject
{
 
}
 
+(NSData*) gzipData:(NSData*)pUncompressedData; //压缩
+(NSData*) ungzipData:(NSData *)compressedData; //解压缩
 
@end

.m文件

#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;
}
 
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 = [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);
[errorMsg release];
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] * 1.01 + 12];
 
int deflateStatus;
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 = [compressedData length] - zlibStreamStruct.total_out;
deflateStatus = deflate(&zlibStreamStruct, Z_FINISH);
 
} while ( deflateStatus == Z_OK );
 
// 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);
[errorMsg release];
 
// 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];
NSLog(@"%s: Compressed file from %d KB to %d KB", __func__, [pUncompressedData length]/1024, [compressedData length]/1024);
 
return compressedData;
}
 
+(NSData *)ungzipData:(NSData *)compressedData
{
if ([compressedData length] == 0)
return compressedData;
 
unsigned full_length = [compressedData length];
unsigned half_length = [compressedData length] / 2;
 
NSMutableData *decompressed = [NSMutableData dataWithLength: full_length + half_length];
BOOL done = NO;
int status;
 
z_stream strm;
strm.next_in = (Bytef *)[compressedData bytes];
strm.avail_in = [compressedData length];
strm.total_out = 0;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
if (inflateInit2(&strm, (15+32)) != Z_OK)
return nil;
 
while (!done) {
// Make sure we have enough room and reset the lengths.
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;
}
 
@end