Code

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