Code

clean up tabs and DOS-ishness
[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"
17 #include <cstring>
18 #include <string>
20 namespace Inkscape
21 {
22 namespace IO
23 {
25 //#########################################################################
26 //# G Z I P    I N P U T    S T R E A M
27 //#########################################################################
29 #define OUT_SIZE 4000
31 /**
32  *
33  */ 
34 GzipInputStream::GzipInputStream(InputStream &sourceStream)
35                     : BasicInputStream(sourceStream),
36                       loaded(false),
37                       totalIn(0),
38                       totalOut(0),
39                       outputBuf(NULL),
40                       crc(0),
41                       srcCrc(0),
42                       srcSiz(0),
43                       srcConsumed(0),
44                       srcLen(0),
45                       outputBufPos(0),
46                       outputBufLen(0)
47 {
48     memset( &d_stream, 0, sizeof(d_stream) );
49 }
51 /**
52  *
53  */ 
54 GzipInputStream::~GzipInputStream()
55 {
56     close();
57     if ( srcBuf ) {
58       free(srcBuf);
59       srcBuf = 0;
60     }
61     if ( outputBuf ) {
62         free(outputBuf);
63         outputBuf = 0;
64     }
65 }
67 /**
68  * Returns the number of bytes that can be read (or skipped over) from
69  * this input stream without blocking by the next caller of a method for
70  * this input stream.
71  */ 
72 int GzipInputStream::available()
73 {
74     if (closed || !outputBuf)
75         return 0;
76     return outputBufLen - outputBufPos;
77 }
79     
80 /**
81  *  Closes this input stream and releases any system resources
82  *  associated with the stream.
83  */ 
84 void GzipInputStream::close()
85 {
86     if (closed)
87         return;
89     int zerr = inflateEnd(&d_stream);
90     if (zerr != Z_OK) {
91         printf("inflateEnd: Some kind of problem: %d\n", zerr);
92     }
94     if ( srcBuf ) {
95       free(srcBuf);
96       srcBuf = 0;
97     }
98     if ( outputBuf ) {
99         free(outputBuf);
100         outputBuf = 0;
101     }
102     closed = true;
104     
105 /**
106  * Reads the next byte of data from the input stream.  -1 if EOF
107  */ 
108 int GzipInputStream::get()
110     int ch = -1;
111     if (closed) {
112         // leave return value -1
113     }
114     else if (!loaded && !load()) {
115         closed=true;
116     } else {
117         loaded = true;
119         int zerr = Z_OK;
120         if ( outputBufPos >= outputBufLen ) {
121             // time to read more, if we can
122             zerr = fetchMore();
123         }
125         if ( outputBufPos < outputBufLen ) {
126             ch = (int)outputBuf[outputBufPos++];
127         }
128     }
130     return ch;
133 #define FTEXT 0x01
134 #define FHCRC 0x02
135 #define FEXTRA 0x04
136 #define FNAME 0x08
137 #define FCOMMENT 0x10
139 bool GzipInputStream::load()
141     crc = crc32(0L, Z_NULL, 0);
142     
143     std::vector<Byte> inputBuf;
144     while (true)
145         {
146         int ch = source.get();
147         if (ch<0)
148             break;
149         inputBuf.push_back((Byte)(ch & 0xff));
150         }
151     long inputBufLen = inputBuf.size();
152     
153     if (inputBufLen < 19) //header + tail + 1
154         {
155         return false;
156         }
158     srcLen = inputBuf.size();
159     srcBuf = (Bytef *)malloc(srcLen * sizeof(Byte));
160     if (!srcBuf) {
161         return false;
162     }
164     outputBuf = (unsigned char *)malloc(OUT_SIZE);
165     if ( !outputBuf ) {
166         free(srcBuf);
167         srcBuf = 0;
168         return false;
169     }
170     outputBufLen = 0; // Not filled in yet
172     std::vector<unsigned char>::iterator iter;
173     Bytef *p = srcBuf;
174     for (iter=inputBuf.begin() ; iter != inputBuf.end() ; iter++)
175         *p++ = *iter;
177     int headerLen = 10;
179     //Magic
180     int val = (int)srcBuf[0];
181     //printf("val:%x\n", val);
182     val = (int)srcBuf[1];
183     //printf("val:%x\n", val);
185     //Method
186     val = (int)srcBuf[2];
187     //printf("val:%x\n", val);
189     //flags
190     int flags = (int)srcBuf[3];
192     //time
193     val = (int)srcBuf[4];
194     val = (int)srcBuf[5];
195     val = (int)srcBuf[6];
196     val = (int)srcBuf[7];
198     //xflags
199     val = (int)srcBuf[8];
200     //OS
201     val = (int)srcBuf[9];
203     int cur = 10;
204 //     if ( flags & FEXTRA ) {
205 //         headerLen += 2;
206 //         int xlen = 
207 //         TODO deal with optional header parts
208 //     }
209     if ( flags & FNAME ) {
210         while ( srcBuf[cur] )
211         {
212             cur++;
213             headerLen++;
214         }
215         headerLen++;
216     }
219     srcCrc = ((0x0ff & srcBuf[srcLen - 5]) << 24)
220            | ((0x0ff & srcBuf[srcLen - 6]) << 16)
221            | ((0x0ff & srcBuf[srcLen - 7]) <<  8)
222            | ((0x0ff & srcBuf[srcLen - 8]) <<  0);
223     //printf("srcCrc:%lx\n", srcCrc);
224     
225     srcSiz = ((0x0ff & srcBuf[srcLen - 1]) << 24)
226            | ((0x0ff & srcBuf[srcLen - 2]) << 16)
227            | ((0x0ff & srcBuf[srcLen - 3]) <<  8)
228            | ((0x0ff & srcBuf[srcLen - 4]) <<  0);
229     //printf("srcSiz:%lx/%ld\n", srcSiz, srcSiz);
230     
231     if ( srcSiz <= 0 ) {
232         return false;
233     }
235     //outputBufLen = srcSiz + srcSiz/100 + 14;
236     
237     unsigned char *data = srcBuf + headerLen;
238     unsigned long dataLen = srcLen - (headerLen + 8);
239     //printf("%x %x\n", data[0], data[dataLen-1]);
240     
241     d_stream.zalloc    = (alloc_func)0;
242     d_stream.zfree     = (free_func)0;
243     d_stream.opaque    = (voidpf)0;
244     d_stream.next_in   = data;
245     d_stream.avail_in  = dataLen;
246     d_stream.next_out  = outputBuf;
247     d_stream.avail_out = OUT_SIZE;
248     
249     int zerr = inflateInit2(&d_stream, -MAX_WBITS);
250     if ( zerr == Z_OK )
251     {
252         zerr = fetchMore();
253     } else {
254         printf("inflateInit2: Some kind of problem: %d\n", zerr);
255     }
257         
258     return (zerr == Z_OK) || (zerr == Z_STREAM_END);
262 int GzipInputStream::fetchMore()
264     int zerr = Z_OK;
266     // TODO assumes we aren't called till the buffer is empty
267     d_stream.next_out  = outputBuf;
268     d_stream.avail_out = OUT_SIZE;
269     outputBufLen = 0;
270     outputBufPos = 0;
272     zerr = inflate( &d_stream, Z_SYNC_FLUSH );
273     if ( zerr == Z_OK || zerr == Z_STREAM_END ) {
274         outputBufLen = OUT_SIZE - d_stream.avail_out;
275         if ( outputBufLen ) {
276             crc = crc32(crc, (const Bytef *)outputBuf, outputBufLen);
277         }
278         //printf("crc:%lx\n", crc);
279 //     } else if ( zerr != Z_STREAM_END ) {
280 //         // TODO check to be sure this won't happen for partial end reads
281 //         printf("inflate: Some kind of problem: %d\n", zerr);
282     }
284     return zerr;
287 //#########################################################################
288 //# G Z I P   O U T P U T    S T R E A M
289 //#########################################################################
291 /**
292  *
293  */ 
294 GzipOutputStream::GzipOutputStream(OutputStream &destinationStream)
295                      : BasicOutputStream(destinationStream)
298     totalIn         = 0;
299     totalOut        = 0;
300     crc             = crc32(0L, Z_NULL, 0);
302     //Gzip header
303     destination.put(0x1f);
304     destination.put(0x8b);
306     //Say it is compressed
307     destination.put(Z_DEFLATED);
309     //flags
310     destination.put(0);
312     //time
313     destination.put(0);
314     destination.put(0);
315     destination.put(0);
316     destination.put(0);
318     //xflags
319     destination.put(0);
321     //OS code - from zutil.h
322     //destination.put(OS_CODE);
323     //apparently, we should not explicitly include zutil.h
324     destination.put(0);
328 /**
329  *
330  */ 
331 GzipOutputStream::~GzipOutputStream()
333     close();
336 /**
337  * Closes this output stream and releases any system resources
338  * associated with this stream.
339  */ 
340 void GzipOutputStream::close()
342     if (closed)
343         return;
345     flush();
347     //# Send the CRC
348     uLong outlong = crc;
349     for (int n = 0; n < 4; n++)
350         {
351         destination.put((int)(outlong & 0xff));
352         outlong >>= 8;
353         }
354     //# send the file length
355     outlong = totalIn & 0xffffffffL;
356     for (int n = 0; n < 4; n++)
357         {
358         destination.put((int)(outlong & 0xff));
359         outlong >>= 8;
360         }
362     destination.close();
363     closed = true;
365     
366 /**
367  *  Flushes this output stream and forces any buffered output
368  *  bytes to be written out.
369  */ 
370 void GzipOutputStream::flush()
372     if (closed || inputBuf.size()<1)
373         return;
374     
375     uLong srclen = inputBuf.size();
376     Bytef *srcbuf = (Bytef *)malloc(srclen * sizeof(Byte));
377     if (!srcbuf)
378         {
379         return;
380         }
381         
382     uLong destlen = srclen;
383     Bytef *destbuf = (Bytef *)malloc((destlen + (srclen/100) + 13) * sizeof(Byte));
384     if (!destbuf)
385         {
386         free(srcbuf);
387         return;
388         }
389         
390     std::vector<unsigned char>::iterator iter;
391     Bytef *p = srcbuf;
392     for (iter=inputBuf.begin() ; iter != inputBuf.end() ; iter++)
393         *p++ = *iter;
394         
395     crc = crc32(crc, (const Bytef *)srcbuf, srclen);
396     
397     int zerr = compress(destbuf, (uLongf *)&destlen, srcbuf, srclen);
398     if (zerr != Z_OK)
399         {
400         printf("Some kind of problem\n");
401         }
403     totalOut += destlen;
404     //skip the redundant zlib header and checksum
405     for (uLong i=2; i<destlen-4 ; i++)
406         {
407         destination.put((int)destbuf[i]);
408         }
409         
410     destination.flush();
412     inputBuf.clear();
413     free(srcbuf);
414     free(destbuf);
415     
416     //printf("done\n");
417     
422 /**
423  * Writes the specified byte to this output stream.
424  */ 
425 void GzipOutputStream::put(int ch)
427     if (closed)
428         {
429         //probably throw an exception here
430         return;
431         }
434     //Add char to buffer
435     inputBuf.push_back(ch);
436     totalIn++;
442 } // namespace IO
443 } // namespace Inkscape
446 //#########################################################################
447 //# E N D    O F    F I L E
448 //#########################################################################
450 /*
451   Local Variables:
452   mode:c++
453   c-file-style:"stroustrup"
454   c-file-offsets:((innamespace . 0)(inline-open . 0))
455   indent-tabs-mode:nil
456   fill-column:99
457   End:
458 */
459 // vim: expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :