Fixing zlib inflate and deflate NSData category methods

This commit is contained in:
Mattt Thompson 2011-09-16 23:23:14 -05:00
parent 9ee84844c4
commit 04dad96904

View file

@ -29,65 +29,6 @@ NSString * const AFZlibErrorDomain = @"com.alamofire.networking.zlib.error";
static char Base64EncodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static inline NSUInteger NSDataEstimatedCompressedLength(NSData *data) {
return [data length] / 2;
}
typedef enum {
GzipDeflate = -1,
GzipInflate = 1,
} GzipOperation;
@interface NSData (_AFNetworking)
+ (NSData *)dataByTransformingData:(NSData *)data
usingGZipOperation:(GzipOperation)operation
error:(NSError **)error;
@end
@implementation NSData (_AFNetworking)
+ (NSData *)dataByTransformingData:(NSData *)data
usingGZipOperation:(GzipOperation)operation
error:(NSError **)error
{
z_stream zStream;
NSUInteger estimatedLength = NSDataEstimatedCompressedLength(data);
NSMutableData *mutableData = [NSMutableData dataWithLength:estimatedLength];
int status;
zStream.next_in = (Bytef *)[data bytes];
zStream.avail_in = (unsigned int)[data length];
zStream.avail_out = 0;
NSInteger bytesProcessedAlready = zStream.total_out;
while (zStream.avail_out == 0) {
if (zStream.total_out - bytesProcessedAlready >= [mutableData length]) {
[mutableData increaseLengthBy:estimatedLength / 2];
}
zStream.next_out = [mutableData mutableBytes] + zStream.total_out-bytesProcessedAlready;
zStream.avail_out = (unsigned int)([mutableData length] - (zStream.total_out-bytesProcessedAlready));
status = deflate(&zStream, Z_FINISH);
if (status == Z_STREAM_END) {
break;
} else if (status != Z_OK) {
if (error) {
*error = [NSError errorWithDomain:AFZlibErrorDomain code:status userInfo:nil];
}
return nil;
}
}
[mutableData setLength:zStream.total_out - bytesProcessedAlready];
return mutableData;
}
@end
#pragma mark -
@implementation NSData (AFNetworking)
@ -120,11 +61,81 @@ typedef enum {
}
- (NSData *)dataByGZipCompressingWithError:(NSError **)error {
return [NSData dataByTransformingData:self usingGZipOperation:GzipDeflate error:error];
if ([self length] == 0) {
return self;
}
z_stream zStream;
zStream.zalloc = Z_NULL;
zStream.zfree = Z_NULL;
zStream.opaque = Z_NULL;
zStream.next_in = (Bytef *)[self bytes];
zStream.avail_in = [self length];
zStream.total_out = 0;
if (deflateInit(&zStream, Z_DEFAULT_COMPRESSION) != Z_OK) {
return nil;
}
NSUInteger compressionChunkSize = 16384; // 16Kb
NSMutableData *compressedData = [NSMutableData dataWithLength:compressionChunkSize];
do {
if (zStream.total_out >= [compressedData length]) {
[compressedData increaseLengthBy:compressionChunkSize];
}
zStream.next_out = [compressedData mutableBytes] + zStream.total_out;
zStream.avail_out = [compressedData length] - zStream.total_out;
deflate(&zStream, Z_FINISH);
} while (zStream.avail_out == 0);
deflateEnd(&zStream);
[compressedData setLength:zStream.total_out];
return [NSData dataWithData:compressedData];
}
- (NSData *)dataByGZipDecompressingDataWithError:(NSError **)error {
return [NSData dataByTransformingData:self usingGZipOperation:GzipInflate error:error];
z_stream zStream;
zStream.zalloc = Z_NULL;
zStream.zfree = Z_NULL;
zStream.next_in = (Bytef *)[self bytes];
zStream.avail_in = [self length];
zStream.avail_out = 0;
zStream.total_out = 0;
NSUInteger estimatedLength = [self length] / 2;
NSMutableData *decompressedData = [NSMutableData dataWithLength:estimatedLength];
do {
if (zStream.total_out >= [decompressedData length]) {
[decompressedData increaseLengthBy:estimatedLength / 2];
}
zStream.next_out = [decompressedData mutableBytes] + zStream.total_out;
zStream.avail_out = [decompressedData length] - zStream.total_out;
int status = inflate(&zStream, Z_FINISH);
if (status == Z_STREAM_END) {
break;
} else if (status != Z_OK) {
if (error) {
*error = [NSError errorWithDomain:AFZlibErrorDomain code:status userInfo:nil];
}
return nil;
}
} while (zStream.avail_out == 0);
[decompressedData setLength:zStream.total_out];
return [NSData dataWithData:decompressedData];
}
@end