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 <NGStreams/NGStreamExceptions.h>
24 #include <NGStreams/NGGZipStream.h>
25 #include <NGExtensions/NSData+gzip.h>
33 #ifndef DEF_MEM_LEVEL /* zutil.h */
34 # if MAX_MEM_LEVEL >= 8
35 # define DEF_MEM_LEVEL 8
37 # define DEF_MEM_LEVEL MAX_MEM_LEVEL
39 # define OS_CODE 0x07 /* TODO: probably need to adjust that ... */
44 @implementation NGGZipStream
46 - (id)initWithSource:(id<NGStream>)_source level:(int)_level {
47 if ((self = [super initWithSource:_source])) {
50 NSAssert1((_level >= NGGZipMinimalCompression &&
51 _level <= NGGZipMaximalCompression)
52 || (_level == Z_DEFAULT_COMPRESSION),
53 @"invalid compression level %i (0-9)", _level);
55 self->outBufLen = 2048;
57 self->outBuf = NSZoneMallocAtomic([self zone], self->outBufLen);
58 self->outp = NSZoneMallocAtomic([self zone], sizeof(z_stream));
60 self->outBuf = NSZoneMalloc([self zone], self->outBufLen);
61 self->outp = NSZoneMalloc([self zone], sizeof(z_stream));
64 zout->zalloc = (alloc_func)NULL;
65 zout->zfree = (free_func)NULL;
66 zout->opaque = (voidpf)NULL;
67 zout->next_out = self->outBuf;
68 zout->avail_out = self->outBufLen;
69 zout->next_in = Z_NULL;
71 self->crc = crc32(0L, Z_NULL, 0);
73 if (deflateInit2(zout, _level, Z_DEFLATED, -MAX_WBITS,
74 DEF_MEM_LEVEL, 0) != Z_OK) {
75 NSLog(@"Could not init deflate ..");
76 self = [self autorelease];
88 if (self->outBuf) NSZoneFree([self zone], self->outBuf);
89 if (self->outp) NSZoneFree([self zone], self->outp);
96 - (void)writeGZipHeader {
100 Z_DEFLATED, 0, // flags
105 [self safeWriteBytes:buf count:10];
108 static inline void putLong(NGGZipStream *self, uLong x) {
110 for (n = 0; n < 4; n++) {
111 unsigned char c = (int)(x & 0xff);
112 [self safeWriteBytes:&c count:1];
116 - (void)writeGZipTrailer {
117 putLong(self, self->crc);
118 putLong(self, ((z_stream *)self->outp)->total_in);
123 - (unsigned)readBytes:(void *)_buf count:(unsigned)_len { // decoder
124 [self notImplemented:_cmd];
128 - (unsigned)writeBytes:(const void *)_buf count:(unsigned)_len { // encoder
129 z_stream *zout = self->outp;
131 if (!self->headerIsWritten) [self writeGZipHeader];
134 zout->next_in = (void*)_buf;
135 zout->avail_in = _len;
137 while (zout->avail_in > 0) {
140 if (zout->avail_out == 0) {
141 [self safeWriteBytes:self->outBuf count:self->outBufLen];
142 zout->next_out = self->outBuf; // reset buffer position
143 zout->avail_out = self->outBufLen;
145 errorCode = deflate(self->outp, Z_NO_FLUSH);
146 if (errorCode != Z_OK) {
147 if (zout->state) deflateEnd(self->outp);
148 [NGStreamException raiseWithStream:self
149 format:@"could not deflate chunk !"];
152 self->crc = crc32(self->crc, _buf, _len);
156 - (BOOL)safeWriteBytes:(const void *)_buf count:(unsigned)_len { // encoder
157 // gzip writes are safe
158 if ([self writeBytes:_buf count:_len] == NGStreamError)
166 [self writeGZipTrailer];
167 if (((z_stream *)self->outp)->state) deflateEnd(self->outp);
172 int errorCode = Z_OK;
173 z_stream *zout = self->outp;
176 zout->next_in = NULL;
177 zout->avail_in = 0; // should be zero already anyway
180 int len = self->outBufLen - zout->avail_out;
183 [self safeWriteBytes:self->outBuf count:len];
184 zout->next_out = self->outBuf;
185 zout->avail_out = self->outBufLen;
189 errorCode = deflate(zout, Z_FINISH);
191 // deflate has finished flushing only when it hasn't used up
192 // all the available space in the output buffer:
193 done = (zout->avail_out != 0 || errorCode == Z_STREAM_END);
195 if (errorCode != Z_OK && errorCode != Z_STREAM_END)
198 if (errorCode != Z_STREAM_END) {
199 if (zout->state) deflateEnd(zout);
200 [NGStreamException raiseWithStream:self format:@"flush failed"];