-
Notifications
You must be signed in to change notification settings - Fork 10
/
LFCGzipUtility.m
executable file
·139 lines (119 loc) · 4.93 KB
/
LFCGzipUtility.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#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;
zlibStreamStruct.zfree = Z_NULL;
zlibStreamStruct.opaque = Z_NULL;
zlibStreamStruct.total_out = 0;
zlibStreamStruct.next_in = (Bytef*)[pUncompressedData bytes];
zlibStreamStruct.avail_in = [pUncompressedData length];
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] * 1.01 + 12];
int deflateStatus;
do {
zlibStreamStruct.next_out = [compressedData mutableBytes] + zlibStreamStruct.total_out;
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);
deflateEnd(&zlibStreamStruct);
return nil;
}
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) {
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;
}
if (done) {
[decompressed setLength:strm.total_out];
return [NSData dataWithData: decompressed];
}
return nil;
}
@end