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 <NGStreams/NGStreamExceptions.h>
23 #include <NGStreams/NGGZipStream.h>
24 #include <NGExtensions/NSData+gzip.h>
32 #ifndef DEF_MEM_LEVEL /* zutil.h */
33 # if MAX_MEM_LEVEL >= 8
34 # define DEF_MEM_LEVEL 8
36 # define DEF_MEM_LEVEL MAX_MEM_LEVEL
38 # define OS_CODE 0x07 /* TODO: probably need to adjust that ... */
43 @implementation NGGZipStream
45 - (id)initWithSource:(id<NGStream>)_source level:(int)_level {
46 if ((self = [super initWithSource:_source])) {
49 NSAssert1((_level >= NGGZipMinimalCompression &&
50 _level <= NGGZipMaximalCompression)
51 || (_level == Z_DEFAULT_COMPRESSION),
52 @"invalid compression level %i (0-9)", _level);
54 self->outBufLen = 2048;
56 self->outBuf = NSZoneMallocAtomic([self zone], self->outBufLen);
57 self->outp = NSZoneMallocAtomic([self zone], sizeof(z_stream));
59 self->outBuf = NSZoneMalloc([self zone], self->outBufLen);
60 self->outp = NSZoneMalloc([self zone], sizeof(z_stream));
63 zout->zalloc = (alloc_func)NULL;
64 zout->zfree = (free_func)NULL;
65 zout->opaque = (voidpf)NULL;
66 zout->next_out = self->outBuf;
67 zout->avail_out = self->outBufLen;
68 zout->next_in = Z_NULL;
70 self->crc = crc32(0L, Z_NULL, 0);
72 if (deflateInit2(zout, _level, Z_DEFLATED, -MAX_WBITS,
73 DEF_MEM_LEVEL, 0) != Z_OK) {
74 NSLog(@"Could not init deflate ..");
75 self = [self autorelease];
87 if (self->outBuf) NSZoneFree([self zone], self->outBuf);
88 if (self->outp) NSZoneFree([self zone], self->outp);
95 - (void)writeGZipHeader {
99 Z_DEFLATED, 0, // flags
104 [self safeWriteBytes:buf count:10];
107 static inline void putLong(NGGZipStream *self, uLong x) {
109 for (n = 0; n < 4; n++) {
110 unsigned char c = (int)(x & 0xff);
111 [self safeWriteBytes:&c count:1];
115 - (void)writeGZipTrailer {
116 putLong(self, self->crc);
117 putLong(self, ((z_stream *)self->outp)->total_in);
122 - (unsigned)readBytes:(void *)_buf count:(unsigned)_len { // decoder
123 [self notImplemented:_cmd];
127 - (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len { // encoder
128 z_stream *zout = self->outp;
130 if (!self->headerIsWritten) [self writeGZipHeader];
133 zout->next_in = (void*)_buf;
134 zout->avail_in = _len;
136 while (zout->avail_in > 0) {
139 if (zout->avail_out == 0) {
140 [self safeWriteBytes:self->outBuf count:self->outBufLen];
141 zout->next_out = self->outBuf; // reset buffer position
142 zout->avail_out = self->outBufLen;
144 errorCode = deflate(self->outp, Z_NO_FLUSH);
145 if (errorCode != Z_OK) {
146 if (zout->state) deflateEnd(self->outp);
147 [NGStreamException raiseWithStream:self
148 format:@"could not deflate chunk !"];
151 self->crc = crc32(self->crc, _buf, _len);
155 - (BOOL)safeWriteBytes:(const void *)_buf count:(unsigned)_len { // encoder
156 // gzip writes are safe
157 if ([self writeBytes:_buf count:_len] == NGStreamError)
165 [self writeGZipTrailer];
166 if (((z_stream *)self->outp)->state) deflateEnd(self->outp);
171 int errorCode = Z_OK;
172 z_stream *zout = self->outp;
175 zout->next_in = NULL;
176 zout->avail_in = 0; // should be zero already anyway
179 int len = self->outBufLen - zout->avail_out;
182 [self safeWriteBytes:self->outBuf count:len];
183 zout->next_out = self->outBuf;
184 zout->avail_out = self->outBufLen;
188 errorCode = deflate(zout, Z_FINISH);
190 // deflate has finished flushing only when it hasn't used up
191 // all the available space in the output buffer:
192 done = (zout->avail_out != 0 || errorCode == Z_STREAM_END);
194 if (errorCode != Z_OK && errorCode != Z_STREAM_END)
197 if (errorCode != Z_STREAM_END) {
198 if (zout->state) deflateEnd(zout);
199 [NGStreamException raiseWithStream:self format:@"flush failed"];