Code

moving trunk for module inkscape
[inkscape.git] / src / io / gzipstream.cpp
1 /**
2  * Zlib-enabled input and output streams
3  *
4  * This is a thin wrapper of libz calls, in order
5  * to provide a simple interface to our developers
6  * for gzip input and output.
7  *
8  * Authors:
9  *   Bob Jamison <rjamison@titan.com>
10  *
11  * Copyright (C) 2004 Inkscape.org
12  *
13  * Released under GNU GPL, read the file 'COPYING' for more information
14  */
16 #include "gzipstream.h"
19 namespace Inkscape
20 {
21 namespace IO
22 {
24 //#########################################################################
25 //# G Z I P    I N P U T    S T R E A M
26 //#########################################################################
28 #define OUT_SIZE 4000
30 /**
31  *
32  */ 
33 GzipInputStream::GzipInputStream(InputStream &sourceStream)
34                     : BasicInputStream(sourceStream),
35                       loaded(false),
36                       totalIn(0),
37                       totalOut(0),
38                       outputBuf(NULL),
39                       crc(0),
40                       srcCrc(0),
41                       srcSiz(0),
42                       srcConsumed(0),
43                       srcLen(0),
44                       outputBufPos(0),
45                       outputBufLen(0)
46 {
47     memset( &d_stream, 0, sizeof(d_stream) );
48 }
50 /**
51  *
52  */ 
53 GzipInputStream::~GzipInputStream()
54 {
55     close();
56     if ( srcBuf ) {
57       free(srcBuf);
58       srcBuf = 0;
59     }
60     if ( outputBuf ) {
61         free(outputBuf);
62         outputBuf = 0;
63     }
64 }
66 /**
67  * Returns the number of bytes that can be read (or skipped over) from
68  * this input stream without blocking by the next caller of a method for
69  * this input stream.
70  */ 
71 int GzipInputStream::available()
72 {
73     if (closed || !outputBuf)
74         return 0;
75     return outputBufLen - outputBufPos;
76 }
78     
79 /**
80  *  Closes this input stream and releases any system resources
81  *  associated with the stream.
82  */ 
83 void GzipInputStream::close()
84 {
85     if (closed)
86         return;
88     int zerr = inflateEnd(&d_stream);
89     if (zerr != Z_OK) {
90         printf("inflateEnd: Some kind of problem: %d\n", zerr);
91     }
93     if ( srcBuf ) {
94       free(srcBuf);
95       srcBuf = 0;
96     }
97     if ( outputBuf ) {
98         free(outputBuf);
99         outputBuf = 0;
100     }
101     closed = true;
103     
104 /**
105  * Reads the next byte of data from the input stream.  -1 if EOF
106  */ 
107 int GzipInputStream::get()
109     int ch = -1;
110     if (closed) {
111         // leave return value -1
112     }
113     else if (!loaded && !load()) {
114         closed=true;
115     } else {
116         loaded = true;
118         int zerr = Z_OK;
119         if ( outputBufPos >= outputBufLen ) {
120             // time to read more, if we can
121             zerr = fetchMore();
122         }
124         if ( outputBufPos < outputBufLen ) {
125             ch = (int)outputBuf[outputBufPos++];
126         }
127     }
129     return ch;
132 #define FTEXT 0x01
133 #define FHCRC 0x02
134 #define FEXTRA 0x04
135 #define FNAME 0x08
136 #define FCOMMENT 0x10
138 bool GzipInputStream::load()
140     crc = crc32(0L, Z_NULL, 0);
141     
142     std::vector<Byte> inputBuf;
143     while (true)
144         {
145         int ch = source.get();
146         if (ch<0)
147             break;
148         inputBuf.push_back((Byte)(ch & 0xff));
149         }
150     long inputBufLen = inputBuf.size();
151     
152     if (inputBufLen < 19) //header + tail + 1
153         {
154         return false;
155         }
157     srcLen = inputBuf.size();
158     srcBuf = (Bytef *)malloc(srcLen * sizeof(Byte));
159     if (!srcBuf) {
160         return false;
161     }
163     outputBuf = (unsigned char *)malloc(OUT_SIZE);
164     if ( !outputBuf ) {
165         free(srcBuf);
166         srcBuf = 0;
167         return false;
168     }
169     outputBufLen = 0; // Not filled in yet
171     std::vector<unsigned char>::iterator iter;
172     Bytef *p = srcBuf;
173     for (iter=inputBuf.begin() ; iter != inputBuf.end() ; iter++)
174         *p++ = *iter;
176     int headerLen = 10;
178     //Magic
179     int val = (int)srcBuf[0];
180     //printf("val:%x\n", val);
181     val = (int)srcBuf[1];
182     //printf("val:%x\n", val);
184     //Method
185     val = (int)srcBuf[2];
186     //printf("val:%x\n", val);
188     //flags
189     int flags = (int)srcBuf[3];
191     //time
192     val = (int)srcBuf[4];
193     val = (int)srcBuf[5];
194     val = (int)srcBuf[6];
195     val = (int)srcBuf[7];
197     //xflags
198     val = (int)srcBuf[8];
199     //OS
200     val = (int)srcBuf[9];
202     int cur = 10;
203 //     if ( flags & FEXTRA ) {
204 //         headerLen += 2;
205 //         int xlen = 
206 //         TODO deal with optional header parts
207 //     }
208     if ( flags & FNAME ) {
209         while ( srcBuf[cur] )
210         {
211             cur++;
212             headerLen++;
213         }
214         headerLen++;
215     }
218     srcCrc = ((0x0ff & srcBuf[srcLen - 5]) << 24)
219            | ((0x0ff & srcBuf[srcLen - 6]) << 16)
220            | ((0x0ff & srcBuf[srcLen - 7]) <<  8)
221            | ((0x0ff & srcBuf[srcLen - 8]) <<  0);
222     //printf("srcCrc:%lx\n", srcCrc);
223     
224     srcSiz = ((0x0ff & srcBuf[srcLen - 1]) << 24)
225            | ((0x0ff & srcBuf[srcLen - 2]) << 16)
226            | ((0x0ff & srcBuf[srcLen - 3]) <<  8)
227            | ((0x0ff & srcBuf[srcLen - 4]) <<  0);
228     //printf("srcSiz:%lx/%ld\n", srcSiz, srcSiz);
229     
230     if ( srcSiz <= 0 ) {
231         return false;
232     }
234     //outputBufLen = srcSiz + srcSiz/100 + 14;
235     
236     unsigned char *data = srcBuf + headerLen;
237     unsigned long dataLen = srcLen - (headerLen + 8);
238     //printf("%x %x\n", data[0], data[dataLen-1]);
239     
240     d_stream.zalloc    = (alloc_func)0;
241     d_stream.zfree     = (free_func)0;
242     d_stream.opaque    = (voidpf)0;
243     d_stream.next_in   = data;
244     d_stream.avail_in  = dataLen;
245     d_stream.next_out  = outputBuf;
246     d_stream.avail_out = OUT_SIZE;
247     
248     int zerr = inflateInit2(&d_stream, -MAX_WBITS);
249     if ( zerr == Z_OK )
250     {
251         zerr = fetchMore();
252     } else {
253         printf("inflateInit2: Some kind of problem: %d\n", zerr);
254     }
256         
257     return (zerr == Z_OK) || (zerr == Z_STREAM_END);
261 int GzipInputStream::fetchMore()
263     int zerr = Z_OK;
265     // TODO assumes we aren't called till the buffer is empty
266     d_stream.next_out  = outputBuf;
267     d_stream.avail_out = OUT_SIZE;
268     outputBufLen = 0;
269     outputBufPos = 0;
271     zerr = inflate( &d_stream, Z_SYNC_FLUSH );
272     if ( zerr == Z_OK || zerr == Z_STREAM_END ) {
273         outputBufLen = OUT_SIZE - d_stream.avail_out;
274         if ( outputBufLen ) {
275             crc = crc32(crc, (const Bytef *)outputBuf, outputBufLen);
276         }
277         //printf("crc:%lx\n", crc);
278 //     } else if ( zerr != Z_STREAM_END ) {
279 //         // TODO check to be sure this won't happen for partial end reads
280 //         printf("inflate: Some kind of problem: %d\n", zerr);
281     }
283     return zerr;
286 //#########################################################################
287 //# G Z I P   O U T P U T    S T R E A M
288 //#########################################################################
290 /**
291  *
292  */ 
293 GzipOutputStream::GzipOutputStream(OutputStream &destinationStream)
294                      : BasicOutputStream(destinationStream)
297     totalIn         = 0;
298     totalOut        = 0;
299     crc             = crc32(0L, Z_NULL, 0);
301     //Gzip header
302     destination.put(0x1f);
303     destination.put(0x8b);
305     //Say it is compressed
306     destination.put(Z_DEFLATED);
308     //flags
309     destination.put(0);
311     //time
312     destination.put(0);
313     destination.put(0);
314     destination.put(0);
315     destination.put(0);
317     //xflags
318     destination.put(0);
320     //OS code - from zutil.h
321     //destination.put(OS_CODE);
322     //apparently, we should not explicitly include zutil.h
323     destination.put(0);
327 /**
328  *
329  */ 
330 GzipOutputStream::~GzipOutputStream()
332     close();
335 /**
336  * Closes this output stream and releases any system resources
337  * associated with this stream.
338  */ 
339 void GzipOutputStream::close()
341     if (closed)
342         return;
344     flush();
346     //# Send the CRC
347     uLong outlong = crc;
348     for (int n = 0; n < 4; n++)
349         {
350         destination.put((int)(outlong & 0xff));
351         outlong >>= 8;
352         }
353     //# send the file length
354     outlong = totalIn & 0xffffffffL;
355     for (int n = 0; n < 4; n++)
356         {
357         destination.put((int)(outlong & 0xff));
358         outlong >>= 8;
359         }
361     destination.close();
362     closed = true;
364     
365 /**
366  *  Flushes this output stream and forces any buffered output
367  *  bytes to be written out.
368  */ 
369 void GzipOutputStream::flush()
371     if (closed || inputBuf.size()<1)
372         return;
373     
374     uLong srclen = inputBuf.size();
375     Bytef *srcbuf = (Bytef *)malloc(srclen * sizeof(Byte));
376     if (!srcbuf)
377         {
378         return;
379         }
380         
381     uLong destlen = srclen;
382     Bytef *destbuf = (Bytef *)malloc((destlen + (srclen/100) + 13) * sizeof(Byte));
383     if (!destbuf)
384         {
385         free(srcbuf);
386         return;
387         }
388         
389     std::vector<unsigned char>::iterator iter;
390     Bytef *p = srcbuf;
391     for (iter=inputBuf.begin() ; iter != inputBuf.end() ; iter++)
392         *p++ = *iter;
393         
394     crc = crc32(crc, (const Bytef *)srcbuf, srclen);
395     
396     int zerr = compress(destbuf, (uLongf *)&destlen, srcbuf, srclen);
397     if (zerr != Z_OK)
398         {
399         printf("Some kind of problem\n");
400         }
402     totalOut += destlen;
403     //skip the redundant zlib header and checksum
404     for (uLong i=2; i<destlen-4 ; i++)
405         {
406         destination.put((int)destbuf[i]);
407         }
408         
409     destination.flush();
411     inputBuf.clear();
412     free(srcbuf);
413     free(destbuf);
414     
415     //printf("done\n");
416     
421 /**
422  * Writes the specified byte to this output stream.
423  */ 
424 void GzipOutputStream::put(int ch)
426     if (closed)
427         {
428         //probably throw an exception here
429         return;
430         }
433     //Add char to buffer
434     inputBuf.push_back(ch);
435     totalIn++;
441 } // namespace IO
442 } // namespace Inkscape
445 //#########################################################################
446 //# E N D    O F    F I L E
447 //#########################################################################
449 /*
450   Local Variables:
451   mode:c++
452   c-file-style:"stroustrup"
453   c-file-offsets:((innamespace . 0)(inline-open . 0))
454   indent-tabs-mode:nil
455   fill-column:99
456   End:
457 */
458 // vim: expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :