2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #include "NSData+gzip.h"
30 #ifndef DEF_MEM_LEVEL /* zutil.h */
31 # if MAX_MEM_LEVEL >= 8
32 # define DEF_MEM_LEVEL 8
34 # define DEF_MEM_LEVEL MAX_MEM_LEVEL
36 # define OS_CODE 0x07 /* TODO: probably need to adjust that ... */
41 @implementation NSData(gzip)
44 return [self gzipWithLevel:Z_DEFAULT_COMPRESSION];
47 static inline void putLong(uLong x, NSMutableData *data, IMP addBytes) {
49 for (n = 0; n < 4; n++) {
50 unsigned char c = (int)(x & 0xff);
51 addBytes(data, @selector(appendBytes:length:), &c, 1);
56 - (NSData *)gzipWithLevel:(int)_level {
57 NSMutableData *data = nil;
59 unsigned len = [self length];
60 void *src = (void *)[self bytes];
66 NSAssert1((_level >= NGGZipMinimalCompression &&
67 _level <= NGGZipMaximalCompression)
68 || (_level == Z_DEFAULT_COMPRESSION),
69 @"invalid compression level %i (0-9)", _level);
71 data = [NSMutableData dataWithCapacity:
72 (len / 10 < 128) ? len : len / 10];
73 addBytes = [data methodForSelector:@selector(appendBytes:length:)];
75 out.zalloc = (alloc_func)NULL;
76 out.zfree = (free_func)NULL;
77 out.opaque = (voidpf)NULL;
78 out.next_out = (Byte*)&outBuf;
79 out.avail_out = sizeof(outBuf);
83 crc = crc32(0L, Z_NULL, 0);
85 errorCode = deflateInit2(&out, _level, Z_DEFLATED, -MAX_WBITS,
87 0); // windowBits is passed <0 to suppress zlib header
88 if (errorCode != Z_OK) {
89 NSLog(@"ERROR: could not init deflate !");
96 Z_DEFLATED, 0, // flags
100 addBytes(data, @selector(appendBytes:length:), &buf, 10);
107 while (out.avail_in > 0) {
108 if (out.avail_out == 0) {
109 out.next_out = (void *)&outBuf; // reset buffer position
110 addBytes(data, @selector(appendBytes:length:), &outBuf, sizeof(outBuf));
111 out.avail_out = sizeof(outBuf);
113 errorCode = deflate(&out, Z_NO_FLUSH);
114 if (errorCode != Z_OK) {
115 NSLog(@"ERROR: could not deflate chunk !");
116 if (out.state) deflateEnd(&out);
120 crc = crc32(crc, src, len);
127 out.avail_in = 0; // should be zero already anyway
130 len = sizeof(outBuf) - out.avail_out;
133 addBytes(data, @selector(appendBytes:length:), &outBuf, len);
134 out.next_out = (void *)&outBuf;
135 out.avail_out = sizeof(outBuf);
139 errorCode = deflate(&out, Z_FINISH);
141 // deflate has finished flushing only when it hasn't used up
142 // all the available space in the output buffer:
143 done = (out.avail_out != 0 || errorCode == Z_STREAM_END);
145 if (errorCode != Z_OK && errorCode != Z_STREAM_END)
148 if (errorCode != Z_STREAM_END) {
149 NSLog(@"ERROR: flush failed.");
150 if (out.state) deflateEnd(&out);
154 { // write trailer (checksum and filesize)
155 putLong(crc, data, addBytes);
156 putLong(out.total_in, data, addBytes);
158 if (out.state) deflateEnd(&out);
165 void __link_NSData_gzip(void) {
166 __link_NSData_gzip();