2 Copyright (C) 2000-2003 SKYRIX Software AG
4 This file is part of OGo
6 OGo 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 OGo 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 OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 #include "NSData+gzip.h"
31 #ifndef DEF_MEM_LEVEL /* zutil.h */
32 # if MAX_MEM_LEVEL >= 8
33 # define DEF_MEM_LEVEL 8
35 # define DEF_MEM_LEVEL MAX_MEM_LEVEL
37 # define OS_CODE 0x07 /* TODO: probably need to adjust that ... */
42 @implementation NSData(gzip)
45 return [self gzipWithLevel:Z_DEFAULT_COMPRESSION];
48 static inline void putLong(uLong x, NSMutableData *data, IMP addBytes) {
50 for (n = 0; n < 4; n++) {
51 unsigned char c = (int)(x & 0xff);
52 addBytes(data, @selector(appendBytes:length:), &c, 1);
57 - (NSData *)gzipWithLevel:(int)_level {
58 NSMutableData *data = nil;
60 unsigned len = [self length];
61 void *src = (void *)[self bytes];
67 NSAssert1((_level >= NGGZipMinimalCompression &&
68 _level <= NGGZipMaximalCompression)
69 || (_level == Z_DEFAULT_COMPRESSION),
70 @"invalid compression level %i (0-9)", _level);
72 data = [NSMutableData dataWithCapacity:
73 (len / 10 < 128) ? len : len / 10];
74 addBytes = [data methodForSelector:@selector(appendBytes:length:)];
76 out.zalloc = (alloc_func)NULL;
77 out.zfree = (free_func)NULL;
78 out.opaque = (voidpf)NULL;
79 out.next_out = (Byte*)&outBuf;
80 out.avail_out = sizeof(outBuf);
84 crc = crc32(0L, Z_NULL, 0);
86 errorCode = deflateInit2(&out, _level, Z_DEFLATED, -MAX_WBITS,
88 0); // windowBits is passed <0 to suppress zlib header
89 if (errorCode != Z_OK) {
90 NSLog(@"ERROR: could not init deflate !");
97 Z_DEFLATED, 0, // flags
101 addBytes(data, @selector(appendBytes:length:), &buf, 10);
108 while (out.avail_in > 0) {
109 if (out.avail_out == 0) {
110 out.next_out = (void *)&outBuf; // reset buffer position
111 addBytes(data, @selector(appendBytes:length:), &outBuf, sizeof(outBuf));
112 out.avail_out = sizeof(outBuf);
114 errorCode = deflate(&out, Z_NO_FLUSH);
115 if (errorCode != Z_OK) {
116 NSLog(@"ERROR: could not deflate chunk !");
117 if (out.state) deflateEnd(&out);
121 crc = crc32(crc, src, len);
128 out.avail_in = 0; // should be zero already anyway
131 len = sizeof(outBuf) - out.avail_out;
134 addBytes(data, @selector(appendBytes:length:), &outBuf, len);
135 out.next_out = (void *)&outBuf;
136 out.avail_out = sizeof(outBuf);
140 errorCode = deflate(&out, Z_FINISH);
142 // deflate has finished flushing only when it hasn't used up
143 // all the available space in the output buffer:
144 done = (out.avail_out != 0 || errorCode == Z_STREAM_END);
146 if (errorCode != Z_OK && errorCode != Z_STREAM_END)
149 if (errorCode != Z_STREAM_END) {
150 NSLog(@"ERROR: flush failed.");
151 if (out.state) deflateEnd(&out);
155 { // write trailer (checksum and filesize)
156 putLong(crc, data, addBytes);
157 putLong(out.total_in, data, addBytes);
159 if (out.state) deflateEnd(&out);
166 void __link_NSData_gzip(void) {
167 __link_NSData_gzip();