Code

Modify includes to not conflict with inkscape
[inkscape.git] / src / dom / util / ziptool.cpp
1 /**\r
2  * This is intended to be a standalone, reduced capability\r
3  * implementation of Gzip and Zip functionality.  Its\r
4  * targeted use case is for archiving and retrieving single files\r
5  * which use these encoding types.  Being memory based and\r
6  * non-optimized, it is not useful in cases where very large\r
7  * archives are needed or where high performance is desired.\r
8  * However, it should hopefully work very well for smaller,\r
9  * one-at-a-time tasks.  What you get in return is the ability\r
10  * to drop these files into your project and remove the dependencies\r
11  * on ZLib and Info-Zip.  Enjoy.\r
12  *\r
13  * Authors:\r
14  *   Bob Jamison\r
15  *\r
16  * Copyright (C) 2006 Bob Jamison\r
17  *\r
18  *  This library is free software; you can redistribute it and/or\r
19  *  modify it under the terms of the GNU Lesser General Public\r
20  *  License as published by the Free Software Foundation; either\r
21  *  version 2.1 of the License, or (at your option) any later version.\r
22  *\r
23  *  This library is distributed in the hope that it will be useful,\r
24  *  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
25  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
26  *  Lesser General Public License for more details.\r
27  *\r
28  *  You should have received a copy of the GNU Lesser General Public\r
29  *  License along with this library; if not, write to the Free Software\r
30  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
31  */\r
32 \r
33 \r
34 #include <stdio.h>\r
35 #include <stdarg.h>\r
36 #include <time.h>\r
37 \r
38 #include <string>\r
39 \r
40 #include "ziptool.h"\r
41 \r
42 \r
43 \r
44 \r
45 \r
46 \r
47 //########################################################################\r
48 //#  A D L E R  3 2\r
49 //########################################################################\r
50 \r
51 /**\r
52  * Constructor\r
53  */\r
54 Adler32::Adler32()\r
55 {\r
56     reset();\r
57 }\r
58 \r
59 /**\r
60  * Destructor\r
61  */\r
62 Adler32::~Adler32()\r
63 {\r
64 }\r
65 \r
66 /**\r
67  * Reset Adler-32 checksum to initial value.\r
68  */\r
69 void Adler32::reset()\r
70 {\r
71     value = 1;\r
72 }\r
73 \r
74 // ADLER32_BASE is the largest prime number smaller than 65536\r
75 #define ADLER32_BASE 65521\r
76 \r
77 void Adler32::update(unsigned char b)\r
78 {\r
79     unsigned long s1 = value & 0xffff;\r
80     unsigned long s2 = (value >> 16) & 0xffff;\r
81     s1 += b & 0xff;\r
82     s2 += s1;\r
83     value = ((s2 % ADLER32_BASE) << 16) | (s1 % ADLER32_BASE);\r
84 }\r
85 \r
86 void Adler32::update(char *str)\r
87 {\r
88     if (str)\r
89         while (*str)\r
90             update((unsigned char)*str++);\r
91 }\r
92 \r
93 \r
94 /**\r
95  * Returns current checksum value.\r
96  */\r
97 unsigned long Adler32::getValue()\r
98 {\r
99     return value & 0xffffffffL;\r
100 }\r
101 \r
102 \r
103 \r
104 //########################################################################\r
105 //#  C R C  3 2\r
106 //########################################################################\r
107 \r
108 /**\r
109  * Constructor\r
110  */\r
111 Crc32::Crc32()\r
112 {\r
113     reset();\r
114 }\r
115 \r
116 /**\r
117  * Destructor\r
118  */\r
119 Crc32::~Crc32()\r
120 {\r
121 }\r
122 \r
123 static bool crc_table_ready = false;\r
124 static unsigned long crc_table[256];\r
125 \r
126 /**\r
127  * make the table for a fast CRC.\r
128  */\r
129 void makeCrcTable()\r
130 {\r
131     if (crc_table_ready)\r
132         return;\r
133     for (int n = 0; n < 256; n++)\r
134         {\r
135         unsigned long c = n;\r
136         for (int k = 8;  --k >= 0; )\r
137             {\r
138             if ((c & 1) != 0)\r
139                 c = 0xedb88320 ^ (c >> 1);\r
140             else\r
141                 c >>= 1;\r
142             }\r
143         crc_table[n] = c;\r
144         }\r
145     crc_table_ready = true;\r
146 }\r
147 \r
148 \r
149 /**\r
150  * Reset CRC-32 checksum to initial value.\r
151  */\r
152 void Crc32::reset()\r
153 {\r
154     value = 0;\r
155     makeCrcTable();\r
156 }\r
157 \r
158 void Crc32::update(unsigned char b)\r
159 {\r
160     unsigned long c = ~value;\r
161     c = crc_table[(c ^ b) & 0xff] ^ (c >> 8);\r
162     value = ~c;\r
163 }\r
164 \r
165 \r
166 void Crc32::update(char *str)\r
167 {\r
168     if (str)\r
169         while (*str)\r
170             update((unsigned char)*str++);\r
171 }\r
172 \r
173 void Crc32::update(const std::vector<unsigned char> &buf)\r
174 {\r
175     std::vector<unsigned char>::const_iterator iter;\r
176     for (iter=buf.begin() ; iter!=buf.end() ; iter++)\r
177         {\r
178         unsigned char ch = *iter;\r
179         update(ch);\r
180         }\r
181 }\r
182 \r
183 \r
184 /**\r
185  * Returns current checksum value.\r
186  */\r
187 unsigned long Crc32::getValue()\r
188 {\r
189     return value & 0xffffffffL;\r
190 }\r
191 \r
192 //########################################################################\r
193 //#  I N F L A T E R\r
194 //########################################################################\r
195 \r
196 \r
197 /**\r
198  *\r
199  */\r
200 typedef struct\r
201 {\r
202     int *count;  // number of symbols of each length\r
203     int *symbol; // canonically ordered symbols\r
204 } Huffman;\r
205 \r
206 /**\r
207  *\r
208  */\r
209 class Inflater\r
210 {\r
211 public:\r
212 \r
213     Inflater();\r
214 \r
215     virtual ~Inflater();\r
216 \r
217     static const int MAXBITS   =  15; // max bits in a code\r
218     static const int MAXLCODES = 286; // max number of literal/length codes\r
219     static const int MAXDCODES =  30; // max number of distance codes\r
220     static const int MAXCODES  = 316; // max codes lengths to read\r
221     static const int FIXLCODES = 288; // number of fixed literal/length codes\r
222 \r
223     /**\r
224      *\r
225      */\r
226     bool inflate(std::vector<unsigned char> &destination,\r
227                  std::vector<unsigned char> &source);\r
228 \r
229 private:\r
230 \r
231     /**\r
232      *\r
233      */\r
234     void error(char *fmt, ...);\r
235 \r
236     /**\r
237      *\r
238      */\r
239     void trace(char *fmt, ...);\r
240 \r
241     /**\r
242      *\r
243      */\r
244     void dump();\r
245 \r
246     /**\r
247      *\r
248      */\r
249     int buildHuffman(Huffman *h, int *length, int n);\r
250 \r
251     /**\r
252      *\r
253      */\r
254     bool getBits(int need, int *oval);\r
255 \r
256     /**\r
257      *\r
258      */\r
259     int doDecode(Huffman *h);\r
260 \r
261     /**\r
262      *\r
263      */\r
264     bool doCodes(Huffman *lencode, Huffman *distcode);\r
265 \r
266     /**\r
267      *\r
268      */\r
269     bool doStored();\r
270 \r
271     /**\r
272      *\r
273      */\r
274     bool doFixed();\r
275 \r
276     /**\r
277      *\r
278      */\r
279     bool doDynamic();\r
280 \r
281 \r
282     std::vector<unsigned char>dest;\r
283 \r
284     std::vector<unsigned char>src;\r
285     unsigned long srcPos;  //current read position\r
286     int bitBuf;\r
287     int bitCnt;\r
288 \r
289 };\r
290 \r
291 \r
292 /**\r
293  *\r
294  */\r
295 Inflater::Inflater()\r
296 {\r
297 }\r
298 \r
299 /**\r
300  *\r
301  */\r
302 Inflater::~Inflater()\r
303 {\r
304 }\r
305 \r
306 /**\r
307  *\r
308  */\r
309 void Inflater::error(char *fmt, ...)\r
310 {\r
311     va_list args;\r
312     va_start(args, fmt);\r
313     fprintf(stdout, "Inflater error:");\r
314     vfprintf(stdout, fmt, args);\r
315     fprintf(stdout, "\n");\r
316     va_end(args);\r
317 }\r
318 \r
319 /**\r
320  *\r
321  */\r
322 void Inflater::trace(char *fmt, ...)\r
323 {\r
324     va_list args;\r
325     va_start(args, fmt);\r
326     fprintf(stdout, "Inflater:");\r
327     vfprintf(stdout, fmt, args);\r
328     fprintf(stdout, "\n");\r
329     va_end(args);\r
330 }\r
331 \r
332 \r
333 /**\r
334  *\r
335  */\r
336 void Inflater::dump()\r
337 {\r
338     for (unsigned int i=0 ; i<dest.size() ; i++)\r
339         {\r
340         fputc(dest[i], stdout);\r
341         }\r
342 }\r
343 \r
344 /**\r
345  *\r
346  */\r
347 int Inflater::buildHuffman(Huffman *h, int *length, int n)\r
348 {\r
349     // count number of codes of each length\r
350     for (int len = 0; len <= MAXBITS; len++)\r
351         h->count[len] = 0;\r
352     for (int symbol = 0; symbol < n; symbol++)\r
353         (h->count[length[symbol]])++;   // assumes lengths are within bounds\r
354     if (h->count[0] == n)               // no codes!\r
355         {\r
356         error("huffman tree will result in failed decode");\r
357         return -1;\r
358         }\r
359 \r
360     // check for an over-subscribed or incomplete set of lengths\r
361     int left = 1;                // number of possible codes left of current length\r
362     for (int len = 1; len <= MAXBITS; len++)\r
363         {\r
364         left <<= 1;                     // one more bit, double codes left\r
365         left -= h->count[len];          // deduct count from possible codes\r
366         if (left < 0)\r
367             {\r
368             error("huffman over subscribed");\r
369             return -1;\r
370             }\r
371         }\r
372 \r
373     // generate offsets into symbol table for each length for sorting\r
374     int offs[MAXBITS+1]; //offsets in symbol table for each length\r
375     offs[1] = 0;\r
376     for (int len = 1; len < MAXBITS; len++)\r
377         offs[len + 1] = offs[len] + h->count[len];\r
378 \r
379     /*\r
380      * put symbols in table sorted by length, by symbol order within each\r
381      * length\r
382      */\r
383     for (int symbol = 0; symbol < n; symbol++)\r
384         if (length[symbol] != 0)\r
385             h->symbol[offs[length[symbol]]++] = symbol;\r
386 \r
387     // return zero for complete set, positive for incomplete set\r
388     return left;\r
389 }\r
390 \r
391 \r
392 /**\r
393  *\r
394  */\r
395 bool Inflater::getBits(int requiredBits, int *oval)\r
396 {\r
397     long val = bitBuf;\r
398 \r
399     //add more bytes if needed\r
400     while (bitCnt < requiredBits)\r
401         {\r
402         if (srcPos >= src.size())\r
403             {\r
404             error("premature end of input");\r
405             return false;\r
406             }\r
407         val |= ((long)(src[srcPos++])) << bitCnt;\r
408         bitCnt += 8;\r
409         }\r
410 \r
411     //update the buffer and return the data\r
412     bitBuf =  (int)(val >> requiredBits);\r
413     bitCnt -= requiredBits;\r
414     *oval = (int)(val & ((1L << requiredBits) - 1));\r
415 \r
416     return true;\r
417 }\r
418 \r
419 \r
420 /**\r
421  *\r
422  */\r
423 int Inflater::doDecode(Huffman *h)\r
424 {\r
425     int bitTmp  = bitBuf;\r
426     int left    = bitCnt;\r
427     int code    = 0;\r
428     int first   = 0;\r
429     int index   = 0;\r
430     int len     = 1;\r
431     int *next = h->count + 1;\r
432     while (true)\r
433         {\r
434         while (left--)\r
435             {\r
436             code   |=  bitTmp & 1;\r
437             bitTmp >>= 1;\r
438             int count  =   *next++;\r
439             if (code < first + count)\r
440                 { /* if length len, return symbol */\r
441                 bitBuf = bitTmp;\r
442                 bitCnt = (bitCnt - len) & 7;\r
443                 return h->symbol[index + (code - first)];\r
444                 }\r
445             index +=  count;\r
446             first +=  count;\r
447             first <<= 1;\r
448             code  <<= 1;\r
449             len++;\r
450             }\r
451         left = (MAXBITS+1) - len;\r
452         if (left == 0)\r
453             break;\r
454         if (srcPos >= src.size())\r
455             {\r
456             error("premature end of input");\r
457             dump();\r
458             return -1;\r
459             }\r
460         bitTmp = src[srcPos++];\r
461         if (left > 8)\r
462             left = 8;\r
463         }\r
464 \r
465     error("no end of block found");\r
466     return -1;\r
467 }\r
468 \r
469 /**\r
470  *\r
471  */\r
472 bool Inflater::doCodes(Huffman *lencode, Huffman *distcode)\r
473 {\r
474     static const int lens[29] = { // Size base for length codes 257..285\r
475         3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,\r
476         35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258};\r
477     static const int lext[29] = { // Extra bits for length codes 257..285\r
478         0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,\r
479         3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0};\r
480     static const int dists[30] = { // Offset base for distance codes 0..29\r
481         1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,\r
482         257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,\r
483         8193, 12289, 16385, 24577};\r
484     static const int dext[30] = { // Extra bits for distance codes 0..29\r
485         0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,\r
486         7, 7, 8, 8, 9, 9, 10, 10, 11, 11,\r
487         12, 12, 13, 13};\r
488 \r
489     //decode literals and length/distance pairs\r
490     while (true)\r
491         {\r
492         int symbol = doDecode(lencode);\r
493         if (symbol == 256)\r
494             break;\r
495         if (symbol < 0)\r
496             {\r
497             return false;\r
498             }\r
499         if (symbol < 256) //literal\r
500             {\r
501             dest.push_back(symbol);\r
502             }\r
503         else if (symbol > 256)//length\r
504             {\r
505             symbol -= 257;\r
506             if (symbol >= 29)\r
507                 {\r
508                 error("invalid fixed code");\r
509                 return false;\r
510                 }\r
511             int ret;\r
512             if (!getBits(lext[symbol], &ret))\r
513                 return false;\r
514             int len = lens[symbol] + ret;\r
515 \r
516             symbol = doDecode(distcode);//distance\r
517             if (symbol < 0)\r
518                 {\r
519                 return false;\r
520                 }\r
521 \r
522             if (!getBits(dext[symbol], &ret))\r
523                 return false;\r
524             unsigned int dist = dists[symbol] + ret;\r
525             if (dist > dest.size())\r
526                 {\r
527                 error("distance too far back %d/%d", dist, dest.size());\r
528                 dump();\r
529                 //printf("pos:%d\n", srcPos);\r
530                 return false;\r
531                 }\r
532 \r
533             // copy length bytes from distance bytes back\r
534             //dest.push_back('{');\r
535             while (len--)\r
536                 {\r
537                 dest.push_back(dest[dest.size() - dist]);\r
538                 }\r
539             //dest.push_back('}');\r
540 \r
541             }\r
542         }\r
543 \r
544     return true;\r
545 }\r
546 \r
547 /**\r
548  */\r
549 bool Inflater::doStored()\r
550 {\r
551     //trace("### stored ###");\r
552 \r
553     // clear bits from current byte\r
554     bitBuf = 0;\r
555     bitCnt = 0;\r
556 \r
557     // length\r
558     if (srcPos + 4 > src.size())\r
559         {\r
560         error("not enough input");\r
561         return false;\r
562         }\r
563 \r
564     int len = src[srcPos++];\r
565     len |= src[srcPos++] << 8;\r
566     //trace("### len:%d", len);\r
567     // check complement\r
568     if (src[srcPos++] != (~len & 0xff) ||\r
569         src[srcPos++] != ((~len >> 8) & 0xff))\r
570         {\r
571         error("twos complement for storage size do not match");\r
572         return false;\r
573         }\r
574 \r
575     // copy data\r
576     if (srcPos + len > src.size())\r
577         {\r
578         error("Not enough input for stored block");\r
579         return false;\r
580         }\r
581     while (len--)\r
582         dest.push_back(src[srcPos++]);\r
583 \r
584     return true;\r
585 }\r
586 \r
587 /**\r
588  */\r
589 bool Inflater::doFixed()\r
590 {\r
591     //trace("### fixed ###");\r
592 \r
593     static bool firstTime = true;\r
594     static int lencnt[MAXBITS+1], lensym[FIXLCODES];\r
595     static int distcnt[MAXBITS+1], distsym[MAXDCODES];\r
596     static Huffman lencode = {lencnt, lensym};\r
597     static Huffman distcode = {distcnt, distsym};\r
598 \r
599     if (firstTime)\r
600         {\r
601         firstTime = false;\r
602 \r
603         int lengths[FIXLCODES];\r
604 \r
605         // literal/length table\r
606         int symbol = 0;\r
607         for ( ; symbol < 144; symbol++)\r
608             lengths[symbol] = 8;\r
609         for ( ; symbol < 256; symbol++)\r
610             lengths[symbol] = 9;\r
611         for ( ; symbol < 280; symbol++)\r
612             lengths[symbol] = 7;\r
613         for ( ; symbol < FIXLCODES; symbol++)\r
614             lengths[symbol] = 8;\r
615         buildHuffman(&lencode, lengths, FIXLCODES);\r
616 \r
617         // distance table\r
618         for (int symbol = 0; symbol < MAXDCODES; symbol++)\r
619             lengths[symbol] = 5;\r
620         buildHuffman(&distcode, lengths, MAXDCODES);\r
621         }\r
622 \r
623     // decode data until end-of-block code\r
624     bool ret = doCodes(&lencode, &distcode);\r
625     return ret;\r
626 }\r
627 \r
628 /**\r
629  */\r
630 bool Inflater::doDynamic()\r
631 {\r
632     //trace("### dynamic ###");\r
633     int lengths[MAXCODES];                      // descriptor code lengths\r
634     int lencnt[MAXBITS+1], lensym[MAXLCODES];   // lencode memory\r
635     int distcnt[MAXBITS+1], distsym[MAXDCODES]; // distcode memory\r
636     Huffman lencode  = {lencnt, lensym};          // length code\r
637     Huffman distcode = {distcnt, distsym};        // distance code\r
638     static const int order[19] =                // permutation of code length codes\r
639         {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};\r
640 \r
641     // get number of lengths in each table, check lengths\r
642     int ret;\r
643     if (!getBits(5, &ret))\r
644         return false;\r
645     int nlen  = ret + 257;\r
646     if (!getBits(5, &ret))\r
647         return false;\r
648     int ndist = ret + 1;\r
649     if (!getBits(4, &ret))\r
650         return false;\r
651     int ncode = ret + 4;\r
652     if (nlen > MAXLCODES || ndist > MAXDCODES)\r
653         {\r
654         error("Bad codes");\r
655         return false;\r
656         }\r
657 \r
658     // get code length code lengths\r
659     int index = 0;\r
660     for ( ; index < ncode; index++)\r
661         {\r
662         if (!getBits(3, &ret))\r
663             return false;\r
664         lengths[order[index]] = ret;\r
665         }\r
666     for ( ; index < 19; index++)\r
667         lengths[order[index]] = 0;\r
668 \r
669     // build huffman table for code lengths codes\r
670     if (buildHuffman(&lencode, lengths, 19) != 0)\r
671         return false;\r
672 \r
673     // read length/literal and distance code length tables\r
674     index = 0;\r
675     while (index < nlen + ndist)\r
676         {\r
677         int symbol = doDecode(&lencode);\r
678         if (symbol < 16)                // length in 0..15\r
679             lengths[index++] = symbol;\r
680         else\r
681             {                          // repeat instruction\r
682             int len = 0;               // assume repeating zeros\r
683             if (symbol == 16)\r
684                 {         // repeat last length 3..6 times\r
685                 if (index == 0)\r
686                     {\r
687                     error("no last length");\r
688                     return false;\r
689                     }\r
690                 len = lengths[index - 1];// last length\r
691                 if (!getBits(2, &ret))\r
692                     return false;\r
693                 symbol = 3 + ret;\r
694                 }\r
695             else if (symbol == 17)      // repeat zero 3..10 times\r
696                 {\r
697                 if (!getBits(3, &ret))\r
698                     return false;\r
699                 symbol = 3 + ret;\r
700                 }\r
701             else                        // == 18, repeat zero 11..138 times\r
702                 {\r
703                 if (!getBits(7, &ret))\r
704                     return false;\r
705                 symbol = 11 + ret;\r
706                 }\r
707             if (index + symbol > nlen + ndist)\r
708                 {\r
709                 error("too many lengths");\r
710                 return false;\r
711                 }\r
712             while (symbol--)            // repeat last or zero symbol times\r
713                 lengths[index++] = len;\r
714             }\r
715         }\r
716 \r
717     // build huffman table for literal/length codes\r
718     int err = buildHuffman(&lencode, lengths, nlen);\r
719     if (err < 0 || (err > 0 && nlen - lencode.count[0] != 1))\r
720         {\r
721         error("incomplete length codes");\r
722         //return false;\r
723         }\r
724     // build huffman table for distance codes\r
725     err = buildHuffman(&distcode, lengths + nlen, ndist);\r
726     if (err < 0 || (err > 0 && nlen - lencode.count[0] != 1))\r
727         {\r
728         error("incomplete dist codes");\r
729         return false;\r
730         }\r
731 \r
732     // decode data until end-of-block code\r
733     bool retn = doCodes(&lencode, &distcode);\r
734     return retn;\r
735 }\r
736 \r
737 /**\r
738  */\r
739 bool Inflater::inflate(std::vector<unsigned char> &destination,\r
740                        std::vector<unsigned char> &source)\r
741 {\r
742     dest.clear();\r
743     src = source;\r
744     srcPos = 0;\r
745     bitBuf = 0;\r
746     bitCnt = 0;\r
747 \r
748     while (true)\r
749         {\r
750         int last; // one if last block\r
751         if (!getBits(1, &last))\r
752             return false;\r
753         int type; // block type 0..3\r
754         if (!getBits(2, &type))\r
755             return false;\r
756         switch (type)\r
757             {\r
758             case 0:\r
759                 if (!doStored())\r
760                     return false;\r
761                 break;\r
762             case 1:\r
763                 if (!doFixed())\r
764                     return false;\r
765                 break;\r
766             case 2:\r
767                 if (!doDynamic())\r
768                     return false;\r
769                 break;\r
770             default:\r
771                 error("Unknown block type %d", type);\r
772                 return false;\r
773             }\r
774         if (last)\r
775             break;\r
776         }\r
777 \r
778     destination = dest;\r
779 \r
780     return true;\r
781 }\r
782 \r
783 \r
784 \r
785 \r
786 \r
787 \r
788 //########################################################################\r
789 //#  D E F L A T E R\r
790 //########################################################################\r
791 \r
792 \r
793 \r
794 class Deflater\r
795 {\r
796 public:\r
797 \r
798     /**\r
799      *\r
800      */\r
801     Deflater();\r
802 \r
803     /**\r
804      *\r
805      */\r
806     virtual ~Deflater();\r
807 \r
808     /**\r
809      *\r
810      */\r
811     virtual void reset();\r
812 \r
813     /**\r
814      *\r
815      */\r
816     virtual bool update(int ch);\r
817 \r
818     /**\r
819      *\r
820      */\r
821     virtual bool finish();\r
822 \r
823     /**\r
824      *\r
825      */\r
826     virtual std::vector<unsigned char> &getCompressed();\r
827 \r
828     /**\r
829      *\r
830      */\r
831     bool deflate(std::vector<unsigned char> &dest,\r
832                  const std::vector<unsigned char> &src);\r
833 \r
834     void encodeDistStatic(unsigned int len, unsigned int dist);\r
835 \r
836 private:\r
837 \r
838     //debug messages\r
839     void error(char *fmt, ...);\r
840     void trace(char *fmt, ...);\r
841 \r
842     bool compressWindow();\r
843 \r
844     bool compress();\r
845 \r
846     std::vector<unsigned char> uncompressed;\r
847 \r
848     std::vector<unsigned char> window;\r
849 \r
850     unsigned int windowPos;\r
851 \r
852     std::vector<unsigned char> compressed;\r
853 \r
854     //#### Output\r
855     unsigned int outputBitBuf;\r
856     unsigned int outputNrBits;\r
857 \r
858     void put(int ch);\r
859 \r
860     void putWord(int ch);\r
861 \r
862     void putFlush();\r
863 \r
864     void putBits(unsigned int ch, unsigned int bitsWanted);\r
865 \r
866     void putBitsR(unsigned int ch, unsigned int bitsWanted);\r
867 \r
868     //#### Huffman Encode\r
869     void encodeLiteralStatic(unsigned int ch);\r
870 };\r
871 \r
872 \r
873 //########################################################################\r
874 //# A P I\r
875 //########################################################################\r
876 \r
877 \r
878 /**\r
879  *\r
880  */\r
881 Deflater::Deflater()\r
882 {\r
883     reset();\r
884 }\r
885 \r
886 /**\r
887  *\r
888  */\r
889 Deflater::~Deflater()\r
890 {\r
891 \r
892 }\r
893 \r
894 /**\r
895  *\r
896  */\r
897 void Deflater::reset()\r
898 {\r
899     outputBitBuf = 0;\r
900     outputNrBits = 0;\r
901     window.clear();\r
902     compressed.clear();\r
903     uncompressed.clear();\r
904 }\r
905 \r
906 /**\r
907  *\r
908  */\r
909 bool Deflater::update(int ch)\r
910 {\r
911     uncompressed.push_back((unsigned char)(ch & 0xff));\r
912     return true;\r
913 }\r
914 \r
915 /**\r
916  *\r
917  */\r
918 bool Deflater::finish()\r
919 {\r
920     return compress();\r
921 }\r
922 \r
923 /**\r
924  *\r
925  */\r
926 std::vector<unsigned char> &Deflater::getCompressed()\r
927 {\r
928     return compressed;\r
929 }\r
930 \r
931 \r
932 /**\r
933  *\r
934  */\r
935 bool Deflater::deflate(std::vector<unsigned char> &dest,\r
936                        const std::vector<unsigned char> &src)\r
937 {\r
938     reset();\r
939     uncompressed = src;\r
940     if (!compress())\r
941         return false;\r
942     dest = compressed;\r
943     return true;\r
944 }\r
945 \r
946 \r
947 \r
948 \r
949 \r
950 \r
951 \r
952 //########################################################################\r
953 //# W O R K I N G    C O D E\r
954 //########################################################################\r
955 \r
956 \r
957 //#############################\r
958 //#  M E S S A G E S\r
959 //#############################\r
960 \r
961 /**\r
962  *  Print error messages\r
963  */\r
964 void Deflater::error(char *fmt, ...)\r
965 {\r
966     va_list args;\r
967     va_start(args, fmt);\r
968     fprintf(stdout, "Deflater error:");\r
969     vfprintf(stdout, fmt, args);\r
970     fprintf(stdout, "\n");\r
971     va_end(args);\r
972 }\r
973 \r
974 /**\r
975  *  Print trace messages\r
976  */\r
977 void Deflater::trace(char *fmt, ...)\r
978 {\r
979     va_list args;\r
980     va_start(args, fmt);\r
981     fprintf(stdout, "Deflater:");\r
982     vfprintf(stdout, fmt, args);\r
983     fprintf(stdout, "\n");\r
984     va_end(args);\r
985 }\r
986 \r
987 \r
988 \r
989 \r
990 //#############################\r
991 //#  O U T P U T\r
992 //#############################\r
993 \r
994 /**\r
995  *\r
996  */\r
997 void Deflater::put(int ch)\r
998 {\r
999     compressed.push_back(ch);\r
1000     outputBitBuf = 0;\r
1001     outputNrBits = 0;\r
1002 }\r
1003 \r
1004 /**\r
1005  *\r
1006  */\r
1007 void Deflater::putWord(int ch)\r
1008 {\r
1009     int lo = (ch   ) & 0xff;\r
1010     int hi = (ch>>8) & 0xff;\r
1011     put(lo);\r
1012     put(hi);\r
1013 }\r
1014 \r
1015 /**\r
1016  *\r
1017  */\r
1018 void Deflater::putFlush()\r
1019 {\r
1020     if (outputNrBits > 0)\r
1021         {\r
1022         put(outputBitBuf & 0xff);\r
1023         }\r
1024     outputBitBuf = 0;\r
1025     outputNrBits = 0;\r
1026 }\r
1027 \r
1028 /**\r
1029  *\r
1030  */\r
1031 void Deflater::putBits(unsigned int ch, unsigned int bitsWanted)\r
1032 {\r
1033     //trace("n:%4u, %d\n", ch, bitsWanted);\r
1034 \r
1035     while (bitsWanted--)\r
1036         {\r
1037         //add bits to position 7.  shift right\r
1038         outputBitBuf = (outputBitBuf>>1) + (ch<<7 & 0x80);\r
1039         ch >>= 1;\r
1040         outputNrBits++;\r
1041         if (outputNrBits >= 8)\r
1042             {\r
1043             unsigned char b = outputBitBuf & 0xff;\r
1044             //printf("b:%02x\n", b);\r
1045             put(b);\r
1046             }\r
1047         }\r
1048 }\r
1049 \r
1050 static unsigned int bitReverse(unsigned int code, unsigned int nrBits)\r
1051 {\r
1052     unsigned int outb = 0;\r
1053     while (nrBits--)\r
1054         {\r
1055         outb = (outb << 1) | (code & 0x01);\r
1056         code >>= 1;\r
1057         }\r
1058     return outb;\r
1059 }\r
1060 \r
1061 \r
1062 /**\r
1063  *\r
1064  */\r
1065 void Deflater::putBitsR(unsigned int ch, unsigned int bitsWanted)\r
1066 {\r
1067     //trace("r:%4u, %d", ch, bitsWanted);\r
1068 \r
1069     unsigned int rcode = bitReverse(ch, bitsWanted);\r
1070 \r
1071     putBits(rcode, bitsWanted);\r
1072 \r
1073 }\r
1074 \r
1075 \r
1076 //#############################\r
1077 //#  E N C O D E\r
1078 //#############################\r
1079 \r
1080 \r
1081 \r
1082 void Deflater::encodeLiteralStatic(unsigned int ch)\r
1083 {\r
1084     //trace("c: %d", ch);\r
1085 \r
1086     if (ch < 144)\r
1087         {\r
1088         putBitsR(ch + 0x0030 , 8); // 00110000\r
1089         }\r
1090     else if (ch < 256)\r
1091         {\r
1092         putBitsR(ch - 144 + 0x0190 , 9); // 110010000\r
1093         }\r
1094     else if (ch < 280)\r
1095         {\r
1096         putBitsR(ch - 256 + 0x0000 , 7); // 0000000\r
1097         }\r
1098     else if (ch < 288)\r
1099         {\r
1100         putBitsR(ch - 280 + 0x00c0 , 8); // 11000000\r
1101         }\r
1102     else //out of range\r
1103         {\r
1104         error("Literal out of range: %d", ch);\r
1105         }\r
1106 \r
1107 }\r
1108 \r
1109 \r
1110 typedef struct\r
1111 {\r
1112     unsigned int base;\r
1113     unsigned int range;\r
1114     unsigned int bits;\r
1115 } LenBase;\r
1116 \r
1117 LenBase lenBases[] =\r
1118 {\r
1119     {   3,  1, 0 },\r
1120     {   4,  1, 0 },\r
1121     {   5,  1, 0 },\r
1122     {   6,  1, 0 },\r
1123     {   7,  1, 0 },\r
1124     {   8,  1, 0 },\r
1125     {   9,  1, 0 },\r
1126     {  10,  1, 0 },\r
1127     {  11,  2, 1 },\r
1128     {  13,  2, 1 },\r
1129     {  15,  2, 1 },\r
1130     {  17,  2, 1 },\r
1131     {  19,  4, 2 },\r
1132     {  23,  4, 2 },\r
1133     {  27,  4, 2 },\r
1134     {  31,  4, 2 },\r
1135     {  35,  8, 3 },\r
1136     {  43,  8, 3 },\r
1137     {  51,  8, 3 },\r
1138     {  59,  8, 3 },\r
1139     {  67, 16, 4 },\r
1140     {  83, 16, 4 },\r
1141     {  99, 16, 4 },\r
1142     { 115, 16, 4 },\r
1143     { 131, 32, 5 },\r
1144     { 163, 32, 5 },\r
1145     { 195, 32, 5 },\r
1146     { 227, 32, 5 },\r
1147     { 258,  1, 0 }\r
1148 };\r
1149 \r
1150 typedef struct\r
1151 {\r
1152     unsigned int base;\r
1153     unsigned int range;\r
1154     unsigned int bits;\r
1155 } DistBase;\r
1156 \r
1157 DistBase distBases[] =\r
1158 {\r
1159     {     1,    1,  0 },\r
1160     {     2,    1,  0 },\r
1161     {     3,    1,  0 },\r
1162     {     4,    1,  0 },\r
1163     {     5,    2,  1 },\r
1164     {     7,    2,  1 },\r
1165     {     9,    4,  2 },\r
1166     {    13,    4,  2 },\r
1167     {    17,    8,  3 },\r
1168     {    25,    8,  3 },\r
1169     {    33,   16,  4 },\r
1170     {    49,   16,  4 },\r
1171     {    65,   32,  5 },\r
1172     {    97,   32,  5 },\r
1173     {   129,   64,  6 },\r
1174     {   193,   64,  6 },\r
1175     {   257,  128,  7 },\r
1176     {   385,  128,  7 },\r
1177     {   513,  256,  8 },\r
1178     {   769,  256,  8 },\r
1179     {  1025,  512,  9 },\r
1180     {  1537,  512,  9 },\r
1181     {  2049, 1024, 10 },\r
1182     {  3073, 1024, 10 },\r
1183     {  4097, 2048, 11 },\r
1184     {  6145, 2048, 11 },\r
1185     {  8193, 4096, 12 },\r
1186     { 12289, 4096, 12 },\r
1187     { 16385, 8192, 13 },\r
1188     { 24577, 8192, 13 }\r
1189 };\r
1190 \r
1191 void Deflater::encodeDistStatic(unsigned int len, unsigned int dist)\r
1192 {\r
1193 \r
1194     //## Output length\r
1195 \r
1196     if (len < 3 || len > 258)\r
1197         {\r
1198         error("Length out of range:%d", len);\r
1199         return;\r
1200         }\r
1201 \r
1202     bool found = false;\r
1203     for (int i=0 ; i<30 ; i++)\r
1204         {\r
1205         unsigned int base  = lenBases[i].base;\r
1206         unsigned int range = lenBases[i].range;\r
1207         if (base + range > len)\r
1208             {\r
1209             unsigned int lenCode = 257 + i;\r
1210             unsigned int length  = len - base;\r
1211             //trace("--- %d %d %d %d", len, base, range, length);\r
1212             encodeLiteralStatic(lenCode);\r
1213             putBits(length, lenBases[i].bits);\r
1214             found = true;\r
1215             break;\r
1216             }\r
1217         }\r
1218     if (!found)\r
1219         {\r
1220         error("Length not found in table:%d", len);\r
1221         return;\r
1222         }\r
1223 \r
1224     //## Output distance\r
1225 \r
1226     if (dist < 4 || dist > 32768)\r
1227         {\r
1228         error("Distance out of range:%d", dist);\r
1229         return;\r
1230         }\r
1231 \r
1232     found = false;\r
1233     for (int i=0 ; i<30 ; i++)\r
1234         {\r
1235         unsigned int base  = distBases[i].base;\r
1236         unsigned int range = distBases[i].range;\r
1237         if (base + range > dist)\r
1238             {\r
1239             unsigned int distCode = i;\r
1240             unsigned int distance = dist - base;\r
1241             //error("--- %d %d %d %d", dist, base, range, distance);\r
1242             putBitsR(distCode, 5);\r
1243             putBits(distance, distBases[i].bits);\r
1244             found = true;\r
1245             break;\r
1246             }\r
1247         }\r
1248     if (!found)\r
1249         {\r
1250         error("Distance not found in table:%d", dist);\r
1251         return;\r
1252         }\r
1253 }\r
1254 \r
1255 \r
1256 //#############################\r
1257 //#  C O M P R E S S\r
1258 //#############################\r
1259 \r
1260 \r
1261 /**\r
1262  *\r
1263  */\r
1264 bool Deflater::compressWindow()\r
1265 {\r
1266     //### Compress as much of the window as possible\r
1267     while (windowPos < window.size())\r
1268         {\r
1269         //### Find best match, if any\r
1270         unsigned int bestMatchLen  = 0;\r
1271         unsigned int bestMatchDist = 0;\r
1272         if (windowPos >= 4)\r
1273             {\r
1274             for (unsigned int lookBack=0 ; lookBack<windowPos-4 ; lookBack++)\r
1275                 {\r
1276                 unsigned int lookAhead;\r
1277                 unsigned int lookAheadMax = window.size() - windowPos;\r
1278                 if (lookBack + lookAheadMax >= windowPos)\r
1279                     lookAheadMax = windowPos - lookBack;\r
1280                 if (lookAheadMax > 258)\r
1281                     lookAheadMax = 258;\r
1282                 for (lookAhead = 0 ; lookAhead<lookAheadMax ; lookAhead++)\r
1283                     {\r
1284                     unsigned int pos1 = lookBack  + lookAhead;\r
1285                     unsigned int pos2 = windowPos + lookAhead;\r
1286                     if (window[pos1] != window[pos2])\r
1287                         break;\r
1288                     }\r
1289                 if (lookAhead > bestMatchLen)\r
1290                     {\r
1291                     bestMatchLen  = lookAhead;\r
1292                     bestMatchDist = windowPos - lookBack;\r
1293                     }\r
1294                 }\r
1295             }\r
1296         if (bestMatchLen > 3)\r
1297             {\r
1298             //Distance encode\r
1299             //trace("### distance");\r
1300             /*\r
1301             printf("### 1 '");\r
1302             for (int i=0 ; i < bestMatchLen ; i++)\r
1303                 fputc(window[windowPos+i], stdout);\r
1304             printf("'\n### 2 '");\r
1305             for (int i=0 ; i < bestMatchLen ; i++)\r
1306                 fputc(window[windowPos-bestMatchDist+i], stdout);\r
1307             printf("'\n");\r
1308             */\r
1309             encodeDistStatic(bestMatchLen, bestMatchDist);\r
1310             windowPos += bestMatchLen;\r
1311             }\r
1312         else\r
1313             {\r
1314             //Literal encode\r
1315             //trace("### literal");\r
1316             encodeLiteralStatic(window[windowPos]);\r
1317             windowPos++;\r
1318             }\r
1319         }\r
1320     encodeLiteralStatic(256);\r
1321     return true;\r
1322 }\r
1323 \r
1324 \r
1325 /**\r
1326  *\r
1327  */\r
1328 bool Deflater::compress()\r
1329 {\r
1330     //trace("compress");\r
1331     unsigned long total = 0L;\r
1332     windowPos = 0;\r
1333     std::vector<unsigned char>::iterator iter;\r
1334     for (iter = uncompressed.begin(); iter != uncompressed.end() ; )\r
1335         {\r
1336         total += windowPos;\r
1337         //trace("total:%ld", total);\r
1338         window.erase(window.begin() , window.begin()+windowPos);\r
1339         while (window.size() < 32768 && iter != uncompressed.end())\r
1340             {\r
1341             window.push_back(*iter);\r
1342             iter++;\r
1343             }\r
1344         windowPos = 0;\r
1345         putBits(0x01, 1); //1  -- last block\r
1346         putBits(0x01, 2); //01 -- static trees\r
1347         if (!compressWindow())\r
1348             return false;\r
1349         }\r
1350     putFlush();\r
1351     return true;\r
1352 }\r
1353 \r
1354 \r
1355 \r
1356 \r
1357 \r
1358 //########################################################################\r
1359 //#  G Z I P    F I L E\r
1360 //########################################################################\r
1361 \r
1362 /**\r
1363  * Constructor\r
1364  */\r
1365 GzipFile::GzipFile()\r
1366 {\r
1367 }\r
1368 \r
1369 /**\r
1370  * Destructor\r
1371  */\r
1372 GzipFile::~GzipFile()\r
1373 {\r
1374 }\r
1375 \r
1376 /**\r
1377  *  Print error messages\r
1378  */\r
1379 void GzipFile::error(char *fmt, ...)\r
1380 {\r
1381     va_list args;\r
1382     va_start(args, fmt);\r
1383     fprintf(stdout, "GzipFile error:");\r
1384     vfprintf(stdout, fmt, args);\r
1385     fprintf(stdout, "\n");\r
1386     va_end(args);\r
1387 }\r
1388 \r
1389 /**\r
1390  *  Print trace messages\r
1391  */\r
1392 void GzipFile::trace(char *fmt, ...)\r
1393 {\r
1394     va_list args;\r
1395     va_start(args, fmt);\r
1396     fprintf(stdout, "GzipFile:");\r
1397     vfprintf(stdout, fmt, args);\r
1398     fprintf(stdout, "\n");\r
1399     va_end(args);\r
1400 }\r
1401 \r
1402 /**\r
1403  *\r
1404  */\r
1405 void GzipFile::put(unsigned char ch)\r
1406 {\r
1407     data.push_back(ch);\r
1408 }\r
1409 \r
1410 /**\r
1411  *\r
1412  */\r
1413 void GzipFile::setData(const std::vector<unsigned char> &str)\r
1414 {\r
1415     data = str;\r
1416 }\r
1417 \r
1418 /**\r
1419  *\r
1420  */\r
1421 void GzipFile::clearData()\r
1422 {\r
1423     data.clear();\r
1424 }\r
1425 \r
1426 /**\r
1427  *\r
1428  */\r
1429 std::vector<unsigned char> &GzipFile::getData()\r
1430 {\r
1431     return data;\r
1432 }\r
1433 \r
1434 /**\r
1435  *\r
1436  */\r
1437 std::string &GzipFile::getFileName()\r
1438 {\r
1439     return fileName;\r
1440 }\r
1441 \r
1442 /**\r
1443  *\r
1444  */\r
1445 void GzipFile::setFileName(const std::string &val)\r
1446 {\r
1447     fileName = val;\r
1448 }\r
1449 \r
1450 \r
1451 \r
1452 //#####################################\r
1453 //# U T I L I T Y\r
1454 //#####################################\r
1455 \r
1456 /**\r
1457  *  Loads a new file into an existing GzipFile\r
1458  */\r
1459 bool GzipFile::loadFile(const std::string &fName)\r
1460 {\r
1461     FILE *f = fopen(fName.c_str() , "rb");\r
1462     if (!f)\r
1463         {\r
1464         error("Cannot open file %s", fName.c_str());\r
1465         return false;\r
1466         }\r
1467     while (true)\r
1468         {\r
1469         int ch = fgetc(f);\r
1470         if (ch < 0)\r
1471             break;\r
1472         data.push_back(ch);\r
1473         }\r
1474     fclose(f);\r
1475     setFileName(fName);\r
1476     return true;\r
1477 }\r
1478 \r
1479 \r
1480 \r
1481 //#####################################\r
1482 //# W R I T E\r
1483 //#####################################\r
1484 \r
1485 /**\r
1486  *\r
1487  */\r
1488 bool GzipFile::putByte(unsigned char ch)\r
1489 {\r
1490     fileBuf.push_back(ch);\r
1491     return true;\r
1492 }\r
1493 \r
1494 \r
1495 \r
1496 /**\r
1497  *\r
1498  */\r
1499 bool GzipFile::putLong(unsigned long val)\r
1500 {\r
1501     fileBuf.push_back( (unsigned char)((val    ) & 0xff));\r
1502     fileBuf.push_back( (unsigned char)((val>> 8) & 0xff));\r
1503     fileBuf.push_back( (unsigned char)((val>>16) & 0xff));\r
1504     fileBuf.push_back( (unsigned char)((val>>24) & 0xff));\r
1505     return true;\r
1506 }\r
1507 \r
1508 \r
1509 \r
1510 /**\r
1511  *\r
1512  */\r
1513 bool GzipFile::write()\r
1514 {\r
1515     fileBuf.clear();\r
1516 \r
1517     putByte(0x1f); //magic\r
1518     putByte(0x8b); //magic\r
1519     putByte(   8); //compression method\r
1520     putByte(0x08); //flags.  say we have a crc and file name\r
1521 \r
1522     unsigned long ltime = (unsigned long) time(NULL);\r
1523     putLong(ltime);\r
1524 \r
1525     //xfl\r
1526     putByte(0);\r
1527     //OS\r
1528     putByte(0);\r
1529 \r
1530     //file name\r
1531     for (int i=0 ; i<fileName.size() ; i++)\r
1532         putByte(fileName[i]);\r
1533     putByte(0);\r
1534 \r
1535 \r
1536     //compress\r
1537     std::vector<unsigned char> compBuf;\r
1538     Deflater deflater;\r
1539     if (!deflater.deflate(compBuf, data))\r
1540         {\r
1541         return false;\r
1542         }\r
1543 \r
1544     std::vector<unsigned char>::iterator iter;\r
1545     for (iter=compBuf.begin() ; iter!=compBuf.end() ; iter++)\r
1546         {\r
1547         unsigned char ch = *iter;\r
1548         putByte(ch);\r
1549         }\r
1550 \r
1551     Crc32 crcEngine;\r
1552     crcEngine.update(data);\r
1553     unsigned long crc = crcEngine.getValue();\r
1554     putLong(crc);\r
1555 \r
1556     putLong(data.size());\r
1557 \r
1558     return true;\r
1559 }\r
1560 \r
1561 \r
1562 /**\r
1563  *\r
1564  */\r
1565 bool GzipFile::writeBuffer(std::vector<unsigned char> &outBuf)\r
1566 {\r
1567     if (!write())\r
1568         return false;\r
1569     outBuf.clear();\r
1570     outBuf = fileBuf;\r
1571     return true;\r
1572 }\r
1573 \r
1574 \r
1575 /**\r
1576  *\r
1577  */\r
1578 bool GzipFile::writeFile(const std::string &fileName)\r
1579 {\r
1580     if (!write())\r
1581         return false;\r
1582     FILE *f = fopen(fileName.c_str(), "wb");\r
1583     if (!f)\r
1584         return false;\r
1585     std::vector<unsigned char>::iterator iter;\r
1586     for (iter=fileBuf.begin() ; iter!=fileBuf.end() ; iter++)\r
1587         {\r
1588         unsigned char ch = *iter;\r
1589         fputc(ch, f);\r
1590         }\r
1591     fclose(f);\r
1592     return true;\r
1593 }\r
1594 \r
1595 \r
1596 //#####################################\r
1597 //# R E A D\r
1598 //#####################################\r
1599 \r
1600 bool GzipFile::getByte(unsigned char *ch)\r
1601 {\r
1602     if (fileBufPos >= fileBuf.size())\r
1603         {\r
1604         error("unexpected end of data");\r
1605         return false;\r
1606         }\r
1607     *ch = fileBuf[fileBufPos++];\r
1608     return true;\r
1609 }\r
1610 \r
1611 /**\r
1612  *\r
1613  */\r
1614 bool GzipFile::getLong(unsigned long *val)\r
1615 {\r
1616     if (fileBuf.size() - fileBufPos < 4)\r
1617         return false;\r
1618     int ch1 = fileBuf[fileBufPos++];\r
1619     int ch2 = fileBuf[fileBufPos++];\r
1620     int ch3 = fileBuf[fileBufPos++];\r
1621     int ch4 = fileBuf[fileBufPos++];\r
1622     *val = ((ch4<<24) & 0xff000000L) |\r
1623            ((ch3<<16) & 0x00ff0000L) |\r
1624            ((ch2<< 8) & 0x0000ff00L) |\r
1625            ((ch1    ) & 0x000000ffL);\r
1626     return true;\r
1627 }\r
1628 \r
1629 bool GzipFile::read()\r
1630 {\r
1631     fileBufPos = 0;\r
1632 \r
1633     unsigned char ch;\r
1634 \r
1635     //magic cookie\r
1636     if (!getByte(&ch))\r
1637         return false;\r
1638     if (ch != 0x1f)\r
1639         {\r
1640         error("bad gzip header");\r
1641         return false;\r
1642         }\r
1643     if (!getByte(&ch))\r
1644         return false;\r
1645     if (ch != 0x8b)\r
1646         {\r
1647         error("bad gzip header");\r
1648         return false;\r
1649         }\r
1650 \r
1651     //## compression method\r
1652     if (!getByte(&ch))\r
1653         return false;\r
1654     int cm = ch & 0xff;\r
1655 \r
1656     //## flags\r
1657     if (!getByte(&ch))\r
1658         return false;\r
1659     bool ftext    = ch & 0x01;\r
1660     bool fhcrc    = ch & 0x02;\r
1661     bool fextra   = ch & 0x04;\r
1662     bool fname    = ch & 0x08;\r
1663     bool fcomment = ch & 0x10;\r
1664 \r
1665     //trace("cm:%d ftext:%d fhcrc:%d fextra:%d fname:%d fcomment:%d",\r
1666     //         cm, ftext, fhcrc, fextra, fname, fcomment);\r
1667 \r
1668     //## file time\r
1669     unsigned long ltime;\r
1670     if (!getLong(&ltime))\r
1671         return false;\r
1672     time_t mtime = (time_t)ltime;\r
1673 \r
1674     //## XFL\r
1675     if (!getByte(&ch))\r
1676         return false;\r
1677     int xfl = ch;\r
1678 \r
1679     //## OS\r
1680     if (!getByte(&ch))\r
1681         return false;\r
1682     int os = ch;\r
1683 \r
1684     //std::string timestr = ctime(&mtime);\r
1685     //trace("xfl:%d os:%d mtime:%s", xfl, os, timestr.c_str());\r
1686 \r
1687     if (fextra)\r
1688         {\r
1689         if (!getByte(&ch))\r
1690             return false;\r
1691         long xlen = ch;\r
1692         if (!getByte(&ch))\r
1693             return false;\r
1694         xlen = (xlen << 8) + ch;\r
1695         for (long l=0 ; l<xlen ; l++)\r
1696             {\r
1697             if (!getByte(&ch))\r
1698                 return false;\r
1699             }\r
1700         }\r
1701 \r
1702     if (fname)\r
1703         {\r
1704         fileName = "";\r
1705         while (true)\r
1706             {\r
1707             if (!getByte(&ch))\r
1708                 return false;\r
1709             if (ch==0)\r
1710                 break;\r
1711             fileName.push_back(ch);\r
1712             }\r
1713         }\r
1714 \r
1715     if (fcomment)\r
1716         {\r
1717         while (true)\r
1718             {\r
1719             if (!getByte(&ch))\r
1720                 return false;\r
1721             if (ch==0)\r
1722                 break;\r
1723             }\r
1724         }\r
1725 \r
1726     if (fhcrc)\r
1727         {\r
1728         if (!getByte(&ch))\r
1729             return false;\r
1730         if (!getByte(&ch))\r
1731             return false;\r
1732         }\r
1733 \r
1734     //read remainder of stream\r
1735     //compressed data runs up until 8 bytes before end of buffer\r
1736     std::vector<unsigned char> compBuf;\r
1737     while (fileBufPos < fileBuf.size() - 8)\r
1738         {\r
1739         if (!getByte(&ch))\r
1740             return false;\r
1741         compBuf.push_back(ch);\r
1742         }\r
1743     //uncompress\r
1744     data.clear();\r
1745     Inflater inflater;\r
1746     if (!inflater.inflate(data, compBuf))\r
1747         {\r
1748         return false;\r
1749         }\r
1750 \r
1751     //Get the CRC and compare\r
1752     Crc32 crcEngine;\r
1753     crcEngine.update(data);\r
1754     unsigned long calcCrc = crcEngine.getValue();\r
1755     unsigned long givenCrc;\r
1756     if (!getLong(&givenCrc))\r
1757         return false;\r
1758     if (givenCrc != calcCrc)\r
1759         {\r
1760         error("Specified crc, %ud, not what received: %ud",\r
1761                 givenCrc, calcCrc);\r
1762         return false;\r
1763         }\r
1764 \r
1765     //Get the file size and compare\r
1766     unsigned long givenFileSize;\r
1767     if (!getLong(&givenFileSize))\r
1768         return false;\r
1769     if (givenFileSize != data.size())\r
1770         {\r
1771         error("Specified data size, %ld, not what received: %ld",\r
1772                 givenFileSize, data.size());\r
1773         return false;\r
1774         }\r
1775 \r
1776     return true;\r
1777 }\r
1778 \r
1779 \r
1780 \r
1781 /**\r
1782  *\r
1783  */\r
1784 bool GzipFile::readBuffer(const std::vector<unsigned char> &inbuf)\r
1785 {\r
1786     fileBuf = inbuf;\r
1787     if (!read())\r
1788         return false;\r
1789     return true;\r
1790 }\r
1791 \r
1792 \r
1793 /**\r
1794  *\r
1795  */\r
1796 bool GzipFile::readFile(const std::string &fileName)\r
1797 {\r
1798     fileBuf.clear();\r
1799     FILE *f = fopen(fileName.c_str(), "rb");\r
1800     if (!f)\r
1801         return false;\r
1802     while (true)\r
1803         {\r
1804         int ch = fgetc(f);\r
1805         if (ch < 0)\r
1806             break;\r
1807         fileBuf.push_back(ch);\r
1808         }\r
1809     fclose(f);\r
1810     if (!read())\r
1811         return false;\r
1812     return true;\r
1813 }\r
1814 \r
1815 \r
1816 \r
1817 \r
1818 \r
1819 \r
1820 \r
1821 \r
1822 //########################################################################\r
1823 //#  Z I P    F I L E\r
1824 //########################################################################\r
1825 \r
1826 /**\r
1827  * Constructor\r
1828  */\r
1829 ZipEntry::ZipEntry()\r
1830 {\r
1831     crc               = 0L;\r
1832     compressionMethod = 8;\r
1833 }\r
1834 \r
1835 /**\r
1836  *\r
1837  */\r
1838 ZipEntry::ZipEntry(const std::string &fileNameArg,\r
1839                    const std::string &commentArg)\r
1840 {\r
1841     crc               = 0L;\r
1842     compressionMethod = 8;\r
1843     fileName          = fileNameArg;\r
1844     comment           = commentArg;\r
1845 }\r
1846 \r
1847 /**\r
1848  * Destructor\r
1849  */\r
1850 ZipEntry::~ZipEntry()\r
1851 {\r
1852 }\r
1853 \r
1854 \r
1855 /**\r
1856  *\r
1857  */\r
1858 std::string ZipEntry::getFileName()\r
1859 {\r
1860     return fileName;\r
1861 }\r
1862 \r
1863 /**\r
1864  *\r
1865  */\r
1866 void ZipEntry::setFileName(const std::string &val)\r
1867 {\r
1868     fileName = val;\r
1869 }\r
1870 \r
1871 /**\r
1872  *\r
1873  */\r
1874 std::string ZipEntry::getComment()\r
1875 {\r
1876     return comment;\r
1877 }\r
1878 \r
1879 /**\r
1880  *\r
1881  */\r
1882 void ZipEntry::setComment(const std::string &val)\r
1883 {\r
1884     comment = val;\r
1885 }\r
1886 \r
1887 /**\r
1888  *\r
1889  */\r
1890 unsigned long ZipEntry::getCompressedSize()\r
1891 {\r
1892     return (unsigned long)compressedData.size();\r
1893 }\r
1894 \r
1895 /**\r
1896  *\r
1897  */\r
1898 int ZipEntry::getCompressionMethod()\r
1899 {\r
1900     return compressionMethod;\r
1901 }\r
1902 \r
1903 /**\r
1904  *\r
1905  */\r
1906 void ZipEntry::setCompressionMethod(int val)\r
1907 {\r
1908     compressionMethod = val;\r
1909 }\r
1910 \r
1911 /**\r
1912  *\r
1913  */\r
1914 std::vector<unsigned char> &ZipEntry::getCompressedData()\r
1915 {\r
1916     return compressedData;\r
1917 }\r
1918 \r
1919 /**\r
1920  *\r
1921  */\r
1922 void ZipEntry::setCompressedData(const std::vector<unsigned char> &val)\r
1923 {\r
1924     compressedData = val;\r
1925 }\r
1926 \r
1927 /**\r
1928  *\r
1929  */\r
1930 unsigned long ZipEntry::getUncompressedSize()\r
1931 {\r
1932     return (unsigned long)uncompressedData.size();\r
1933 }\r
1934 \r
1935 /**\r
1936  *\r
1937  */\r
1938 std::vector<unsigned char> &ZipEntry::getUncompressedData()\r
1939 {\r
1940     return uncompressedData;\r
1941 }\r
1942 \r
1943 /**\r
1944  *\r
1945  */\r
1946 void ZipEntry::setUncompressedData(const std::vector<unsigned char> &val)\r
1947 {\r
1948     uncompressedData = val;\r
1949 }\r
1950 \r
1951 /**\r
1952  *\r
1953  */\r
1954 void ZipEntry::write(unsigned char ch)\r
1955 {\r
1956     uncompressedData.push_back(ch);\r
1957 }\r
1958 \r
1959 /**\r
1960  *\r
1961  */\r
1962 void ZipEntry::finish()\r
1963 {\r
1964     Crc32 c32;\r
1965     std::vector<unsigned char>::iterator iter;\r
1966     for (iter = uncompressedData.begin() ;\r
1967            iter!= uncompressedData.end() ; iter++)\r
1968         {\r
1969         unsigned char ch = *iter;\r
1970         c32.update(ch);\r
1971         }\r
1972     crc = c32.getValue();\r
1973     switch (compressionMethod)\r
1974         {\r
1975         case 0: //none\r
1976             {\r
1977             for (iter = uncompressedData.begin() ;\r
1978                iter!= uncompressedData.end() ; iter++)\r
1979                 {\r
1980                 unsigned char ch = *iter;\r
1981                 compressedData.push_back(ch);\r
1982                 }\r
1983             break;\r
1984             }\r
1985         case 8: //deflate\r
1986             {\r
1987             Deflater deflater;\r
1988             if (!deflater.deflate(compressedData, uncompressedData))\r
1989                 {\r
1990                 //some error\r
1991                 }\r
1992             break;\r
1993             }\r
1994         default:\r
1995             {\r
1996             printf("error: unknown compression method %d\n",\r
1997                     compressionMethod);\r
1998             }\r
1999         }\r
2000     printf("### done\n");\r
2001 }\r
2002 \r
2003 \r
2004 \r
2005 /**\r
2006  *\r
2007  */\r
2008 unsigned long ZipEntry::getCrc()\r
2009 {\r
2010     return crc;\r
2011 }\r
2012 \r
2013 /**\r
2014  *\r
2015  */\r
2016 bool ZipEntry::readFile(const std::string &fileNameArg,\r
2017                         const std::string &commentArg)\r
2018 {\r
2019     crc = 0L;\r
2020     uncompressedData.clear();\r
2021     fileName = fileNameArg;\r
2022     comment  = commentArg;\r
2023     FILE *f = fopen(fileName.c_str(), "rb");\r
2024     if (!f)\r
2025         {\r
2026         return false;\r
2027         }\r
2028     while (true)\r
2029         {\r
2030         int ch = fgetc(f);\r
2031         if (ch < 0)\r
2032             break;\r
2033         uncompressedData.push_back((unsigned char)ch);\r
2034         }\r
2035     fclose(f);\r
2036     finish();\r
2037     return true;\r
2038 }\r
2039 \r
2040 \r
2041 /**\r
2042  *\r
2043  */\r
2044 void ZipEntry::setPosition(unsigned long val)\r
2045 {\r
2046     position = val;\r
2047 }\r
2048 \r
2049 /**\r
2050  *\r
2051  */\r
2052 unsigned long ZipEntry::getPosition()\r
2053 {\r
2054     return position;\r
2055 }\r
2056 \r
2057 \r
2058 \r
2059 \r
2060 \r
2061 \r
2062 \r
2063 /**\r
2064  * Constructor\r
2065  */\r
2066 ZipFile::ZipFile()\r
2067 {\r
2068 \r
2069 }\r
2070 \r
2071 /**\r
2072  * Destructor\r
2073  */\r
2074 ZipFile::~ZipFile()\r
2075 {\r
2076     std::vector<ZipEntry *>::iterator iter;\r
2077     for (iter=entries.begin() ; iter!=entries.end() ; iter++)\r
2078         {\r
2079         ZipEntry *entry = *iter;\r
2080         delete entry;\r
2081         }\r
2082     entries.clear();\r
2083 }\r
2084 \r
2085 /**\r
2086  *\r
2087  */\r
2088 void ZipFile::setComment(const std::string &val)\r
2089 {\r
2090     comment = val;\r
2091 }\r
2092 \r
2093 /**\r
2094  *\r
2095  */\r
2096 std::string ZipFile::getComment()\r
2097 {\r
2098     return comment;\r
2099 }\r
2100 \r
2101 \r
2102 /**\r
2103  *\r
2104  */\r
2105 std::vector<ZipEntry *> &ZipFile::getEntries()\r
2106 {\r
2107     return entries;\r
2108 }\r
2109 \r
2110 \r
2111 \r
2112 //#####################################\r
2113 //# M E S S A G E S\r
2114 //#####################################\r
2115 \r
2116 void ZipFile::error(char *fmt, ...)\r
2117 {\r
2118     va_list args;\r
2119     va_start(args, fmt);\r
2120     fprintf(stdout, "ZipFile error:");\r
2121     vfprintf(stdout, fmt, args);\r
2122     fprintf(stdout, "\n");\r
2123     va_end(args);\r
2124 }\r
2125 \r
2126 void ZipFile::trace(char *fmt, ...)\r
2127 {\r
2128     va_list args;\r
2129     va_start(args, fmt);\r
2130     fprintf(stdout, "ZipFile:");\r
2131     vfprintf(stdout, fmt, args);\r
2132     fprintf(stdout, "\n");\r
2133     va_end(args);\r
2134 }\r
2135 \r
2136 //#####################################\r
2137 //# U T I L I T Y\r
2138 //#####################################\r
2139 \r
2140 /**\r
2141  *\r
2142  */\r
2143 bool ZipFile::addFile(const std::string &fileName,\r
2144                       const std::string &comment)\r
2145 {\r
2146     ZipEntry *ze = new ZipEntry();\r
2147     if (!ze->readFile(fileName, comment))\r
2148         {\r
2149         return false;\r
2150         }\r
2151     entries.push_back(ze);\r
2152     return true;\r
2153 }\r
2154 \r
2155 \r
2156 //#####################################\r
2157 //# W R I T E\r
2158 //#####################################\r
2159 \r
2160 /**\r
2161  *\r
2162  */\r
2163 bool ZipFile::putLong(unsigned long val)\r
2164 {\r
2165     fileBuf.push_back( ((int)(val    )) & 0xff);\r
2166     fileBuf.push_back( ((int)(val>> 8)) & 0xff);\r
2167     fileBuf.push_back( ((int)(val>>16)) & 0xff);\r
2168     fileBuf.push_back( ((int)(val>>24)) & 0xff);\r
2169     return true;\r
2170 }\r
2171 \r
2172 \r
2173 /**\r
2174  *\r
2175  */\r
2176 bool ZipFile::putInt(unsigned int val)\r
2177 {\r
2178     fileBuf.push_back( (val    ) & 0xff);\r
2179     fileBuf.push_back( (val>> 8) & 0xff);\r
2180     return true;\r
2181 }\r
2182 \r
2183 /**\r
2184  *\r
2185  */\r
2186 bool ZipFile::putByte(unsigned char val)\r
2187 {\r
2188     fileBuf.push_back(val);\r
2189     return true;\r
2190 }\r
2191 \r
2192 /**\r
2193  *\r
2194  */\r
2195 bool ZipFile::writeFileData()\r
2196 {\r
2197     std::vector<ZipEntry *>::iterator iter;\r
2198     for (iter = entries.begin() ; iter != entries.end() ; iter++)\r
2199         {\r
2200         ZipEntry *entry = *iter;\r
2201         entry->setPosition(fileBuf.size());\r
2202         //##### HEADER\r
2203         std::string fname = entry->getFileName();\r
2204         putLong(0x04034b50L);\r
2205         putInt(20); //versionNeeded\r
2206         putInt(0); //gpBitFlag\r
2207         //putInt(0); //compression method\r
2208         putInt(entry->getCompressionMethod()); //compression method\r
2209         putInt(0); //mod time\r
2210         putInt(0); //mod date\r
2211         putLong(entry->getCrc()); //crc32\r
2212         putLong(entry->getCompressedSize());\r
2213         putLong(entry->getUncompressedSize());\r
2214         putInt(fname.size());//fileName length\r
2215         putInt(8);//extra field length\r
2216         //file name\r
2217         for (unsigned int i=0 ; i<fname.size() ; i++)\r
2218             putByte((unsigned char)fname[i]);\r
2219         //extra field\r
2220         putInt(0x7855);\r
2221         putInt(4);\r
2222         putInt(100);\r
2223         putInt(100);\r
2224 \r
2225         //##### DATA\r
2226         std::vector<unsigned char> &buf = entry->getCompressedData();\r
2227         std::vector<unsigned char>::iterator iter;\r
2228         for (iter = buf.begin() ; iter != buf.end() ; iter++)\r
2229             {\r
2230             unsigned char ch = (unsigned char) *iter;\r
2231             putByte(ch);\r
2232             }\r
2233         }\r
2234     return true;\r
2235 }\r
2236 \r
2237 /**\r
2238  *\r
2239  */\r
2240 bool ZipFile::writeCentralDirectory()\r
2241 {\r
2242     unsigned long cdPosition = fileBuf.size();\r
2243     std::vector<ZipEntry *>::iterator iter;\r
2244     for (iter = entries.begin() ; iter != entries.end() ; iter++)\r
2245         {\r
2246         ZipEntry *entry = *iter;\r
2247         std::string fname   = entry->getFileName();\r
2248         std::string ecomment = entry->getComment();\r
2249         putLong(0x02014b50L);  //magic cookie\r
2250         putInt(2386); //versionMadeBy\r
2251         putInt(20); //versionNeeded\r
2252         putInt(0); //gpBitFlag\r
2253         putInt(entry->getCompressionMethod()); //compression method\r
2254         putInt(0); //mod time\r
2255         putInt(0); //mod date\r
2256         putLong(entry->getCrc()); //crc32\r
2257         putLong(entry->getCompressedSize());\r
2258         putLong(entry->getUncompressedSize());\r
2259         putInt(fname.size());//fileName length\r
2260         putInt(4);//extra field length\r
2261         putInt(ecomment.size());//comment length\r
2262         putInt(0); //disk number start\r
2263         putInt(0); //internal attributes\r
2264         putLong(0); //external attributes\r
2265         putLong(entry->getPosition());\r
2266 \r
2267         //file name\r
2268         for (unsigned int i=0 ; i<fname.size() ; i++)\r
2269             putByte((unsigned char)fname[i]);\r
2270         //extra field\r
2271         putInt(0x7855);\r
2272         putInt(0);\r
2273         //comment\r
2274         for (unsigned int i=0 ; i<ecomment.size() ; i++)\r
2275             putByte((unsigned char)ecomment[i]);\r
2276         }\r
2277     unsigned long cdSize = fileBuf.size() - cdPosition;\r
2278 \r
2279     putLong(0x06054b50L);\r
2280     putInt(0);//number of this disk\r
2281     putInt(0);//nr of disk with central dir\r
2282     putInt(entries.size()); //number of entries on this disk\r
2283     putInt(entries.size()); //number of entries total\r
2284     putLong(cdSize);  //size of central dir\r
2285     putLong(cdPosition); //position of central dir\r
2286     putInt(comment.size());//comment size\r
2287     for (unsigned int i=0 ; i<comment.size() ; i++)\r
2288         putByte(comment[i]);\r
2289     return true;\r
2290 }\r
2291 \r
2292 \r
2293 \r
2294 /**\r
2295  *\r
2296  */\r
2297 bool ZipFile::write()\r
2298 {\r
2299     fileBuf.clear();\r
2300     if (!writeFileData())\r
2301         return false;\r
2302     if (!writeCentralDirectory())\r
2303         return false;\r
2304     return true;\r
2305 }\r
2306 \r
2307 \r
2308 /**\r
2309  *\r
2310  */\r
2311 bool ZipFile::writeBuffer(std::vector<unsigned char> &outBuf)\r
2312 {\r
2313     if (!write())\r
2314         return false;\r
2315     outBuf.clear();\r
2316     outBuf = fileBuf;\r
2317     return true;\r
2318 }\r
2319 \r
2320 \r
2321 /**\r
2322  *\r
2323  */\r
2324 bool ZipFile::writeFile(const std::string &fileName)\r
2325 {\r
2326     if (!write())\r
2327         return false;\r
2328     FILE *f = fopen(fileName.c_str(), "wb");\r
2329     if (!f)\r
2330         return false;\r
2331     std::vector<unsigned char>::iterator iter;\r
2332     for (iter=fileBuf.begin() ; iter!=fileBuf.end() ; iter++)\r
2333         {\r
2334         unsigned char ch = *iter;\r
2335         fputc(ch, f);\r
2336         }\r
2337     fclose(f);\r
2338     return true;\r
2339 }\r
2340 \r
2341 //#####################################\r
2342 //# R E A D\r
2343 //#####################################\r
2344 \r
2345 /**\r
2346  *\r
2347  */\r
2348 bool ZipFile::getLong(unsigned long *val)\r
2349 {\r
2350     if (fileBuf.size() - fileBufPos < 4)\r
2351         return false;\r
2352     int ch1 = fileBuf[fileBufPos++];\r
2353     int ch2 = fileBuf[fileBufPos++];\r
2354     int ch3 = fileBuf[fileBufPos++];\r
2355     int ch4 = fileBuf[fileBufPos++];\r
2356     *val = ((ch4<<24) & 0xff000000L) |\r
2357            ((ch3<<16) & 0x00ff0000L) |\r
2358            ((ch2<< 8) & 0x0000ff00L) |\r
2359            ((ch1    ) & 0x000000ffL);\r
2360     return true;\r
2361 }\r
2362 \r
2363 /**\r
2364  *\r
2365  */\r
2366 bool ZipFile::getInt(unsigned int *val)\r
2367 {\r
2368     if (fileBuf.size() - fileBufPos < 2)\r
2369         return false;\r
2370     int ch1 = fileBuf[fileBufPos++];\r
2371     int ch2 = fileBuf[fileBufPos++];\r
2372     *val = ((ch2<< 8) & 0xff00) |\r
2373            ((ch1    ) & 0x00ff);\r
2374     return true;\r
2375 }\r
2376 \r
2377 \r
2378 /**\r
2379  *\r
2380  */\r
2381 bool ZipFile::getByte(unsigned char *val)\r
2382 {\r
2383     if (fileBuf.size() <= fileBufPos)\r
2384         return false;\r
2385     *val = fileBuf[fileBufPos++];\r
2386     return true;\r
2387 }\r
2388 \r
2389 \r
2390 /**\r
2391  *\r
2392  */\r
2393 bool ZipFile::readFileData()\r
2394 {\r
2395     //printf("#################################################\n");\r
2396     //printf("###D A T A\n");\r
2397     //printf("#################################################\n");\r
2398     while (true)\r
2399         {\r
2400         unsigned long magicCookie;\r
2401         if (!getLong(&magicCookie))\r
2402             {\r
2403             error("magic cookie not found");\r
2404             break;\r
2405             }\r
2406         trace("###Cookie:%lx", magicCookie);\r
2407         if (magicCookie == 0x02014b50L) //central directory\r
2408             break;\r
2409         if (magicCookie != 0x04034b50L)\r
2410             {\r
2411             error("file header not found");\r
2412             return false;\r
2413             }\r
2414         unsigned int versionNeeded;\r
2415         if (!getInt(&versionNeeded))\r
2416             {\r
2417             error("bad version needed found");\r
2418             return false;\r
2419             }\r
2420         unsigned int gpBitFlag;\r
2421         if (!getInt(&gpBitFlag))\r
2422             {\r
2423             error("bad bit flag found");\r
2424             return false;\r
2425             }\r
2426         unsigned int compressionMethod;\r
2427         if (!getInt(&compressionMethod))\r
2428             {\r
2429             error("bad compressionMethod found");\r
2430             return false;\r
2431             }\r
2432         unsigned int modTime;\r
2433         if (!getInt(&modTime))\r
2434             {\r
2435             error("bad modTime found");\r
2436             return false;\r
2437             }\r
2438         unsigned int modDate;\r
2439         if (!getInt(&modDate))\r
2440             {\r
2441             error("bad modDate found");\r
2442             return false;\r
2443             }\r
2444         unsigned long crc32;\r
2445         if (!getLong(&crc32))\r
2446             {\r
2447             error("bad crc32 found");\r
2448             return false;\r
2449             }\r
2450         unsigned long compressedSize;\r
2451         if (!getLong(&compressedSize))\r
2452             {\r
2453             error("bad compressedSize found");\r
2454             return false;\r
2455             }\r
2456         unsigned long uncompressedSize;\r
2457         if (!getLong(&uncompressedSize))\r
2458             {\r
2459             error("bad uncompressedSize found");\r
2460             return false;\r
2461             }\r
2462         unsigned int fileNameLength;\r
2463         if (!getInt(&fileNameLength))\r
2464             {\r
2465             error("bad fileNameLength found");\r
2466             return false;\r
2467             }\r
2468         unsigned int extraFieldLength;\r
2469         if (!getInt(&extraFieldLength))\r
2470             {\r
2471             error("bad extraFieldLength found");\r
2472             return false;\r
2473             }\r
2474         std::string fileName;\r
2475         for (unsigned int i=0 ; i<fileNameLength ; i++)\r
2476             {\r
2477             unsigned char ch;\r
2478             if (!getByte(&ch))\r
2479                 break;\r
2480             fileName.push_back(ch);\r
2481             }\r
2482         std::string extraField;\r
2483         for (unsigned int i=0 ; i<extraFieldLength ; i++)\r
2484             {\r
2485             unsigned char ch;\r
2486             if (!getByte(&ch))\r
2487                 break;\r
2488             extraField.push_back(ch);\r
2489             }\r
2490         trace("#########################  DATA");\r
2491         trace("FileName           :%d:%s" , fileName.size(), fileName.c_str());\r
2492         trace("Extra field        :%d:%s" , extraField.size(), extraField.c_str());\r
2493         trace("Version needed     :%d" , versionNeeded);\r
2494         trace("Bitflag            :%d" , gpBitFlag);\r
2495         trace("Compression Method :%d" , compressionMethod);\r
2496         trace("Mod time           :%d" , modTime);\r
2497         trace("Mod date           :%d" , modDate);\r
2498         trace("CRC                :%lx", crc32);\r
2499         trace("Compressed size    :%ld", compressedSize);\r
2500         trace("Uncompressed size  :%ld", uncompressedSize);\r
2501 \r
2502         //#### Uncompress the data\r
2503         std::vector<unsigned char> compBuf;\r
2504         if (gpBitFlag & 0x8)//bit 3 was set.  means we dont know compressed size\r
2505             {\r
2506             unsigned char c1, c2, c3, c4;\r
2507             c1 = c2 = c3 = c4 = 0;\r
2508             while (true)\r
2509                 {\r
2510                 unsigned char ch;\r
2511                 if (!getByte(&ch))\r
2512                     {\r
2513                     error("premature end of data");\r
2514                     break;\r
2515                     }\r
2516                 compBuf.push_back(ch);\r
2517                 c1 = c2; c2 = c3; c3 = c4; c4 = ch;\r
2518                 if (c1 == 0x50 && c2 == 0x4b && c3 == 0x07 && c4 == 0x08)\r
2519                     {\r
2520                     trace("found end of compressed data");\r
2521                     //remove the cookie\r
2522                     compBuf.erase(compBuf.end() -4, compBuf.end());\r
2523                     break;\r
2524                     }\r
2525                 }\r
2526             }\r
2527         else\r
2528             {\r
2529             for (unsigned long bnr = 0 ; bnr < compressedSize ; bnr++)\r
2530                 {\r
2531                 unsigned char ch;\r
2532                 if (!getByte(&ch))\r
2533                     {\r
2534                     error("premature end of data");\r
2535                     break;\r
2536                     }\r
2537                 compBuf.push_back(ch);\r
2538                 }\r
2539             }\r
2540 \r
2541         printf("### data: ");\r
2542         for (int i=0 ; i<10 ; i++)\r
2543             printf("%02x ", compBuf[i] & 0xff);\r
2544         printf("\n");\r
2545 \r
2546         if (gpBitFlag & 0x8)//only if bit 3 set\r
2547             {\r
2548             /* this cookie was read in the loop above\r
2549             unsigned long dataDescriptorSignature ;\r
2550             if (!getLong(&dataDescriptorSignature))\r
2551                 break;\r
2552             if (dataDescriptorSignature != 0x08074b50L)\r
2553                 {\r
2554                 error("bad dataDescriptorSignature found");\r
2555                 return false;\r
2556                 }\r
2557             */\r
2558             unsigned long crc32;\r
2559             if (!getLong(&crc32))\r
2560                 {\r
2561                 error("bad crc32 found");\r
2562                 return false;\r
2563                 }\r
2564             unsigned long compressedSize;\r
2565             if (!getLong(&compressedSize))\r
2566                 {\r
2567                 error("bad compressedSize found");\r
2568                 return false;\r
2569                 }\r
2570             unsigned long uncompressedSize;\r
2571             if (!getLong(&uncompressedSize))\r
2572                 {\r
2573                 error("bad uncompressedSize found");\r
2574                 return false;\r
2575                 }\r
2576             }//bit 3 was set\r
2577         //break;\r
2578 \r
2579         std::vector<unsigned char> uncompBuf;\r
2580         switch (compressionMethod)\r
2581             {\r
2582             case 8: //deflate\r
2583                 {\r
2584                 Inflater inflater;\r
2585                 if (!inflater.inflate(uncompBuf, compBuf))\r
2586                     {\r
2587                     return false;\r
2588                     }\r
2589                 break;\r
2590                 }\r
2591             default:\r
2592                 {\r
2593                 error("Unimplemented compression method %d", compressionMethod);\r
2594                 return false;\r
2595                 }\r
2596             }\r
2597 \r
2598         ZipEntry *ze = new ZipEntry(fileName, comment);\r
2599         ze->setCompressionMethod(compressionMethod);\r
2600         ze->setCompressedData(compBuf);\r
2601         ze->setUncompressedData(uncompBuf);\r
2602         entries.push_back(ze);\r
2603 \r
2604 \r
2605         }\r
2606     return true;\r
2607 }\r
2608 \r
2609 \r
2610 /**\r
2611  *\r
2612  */\r
2613 bool ZipFile::readCentralDirectory()\r
2614 {\r
2615     //printf("#################################################\n");\r
2616     //printf("###D I R E C T O R Y\n");\r
2617     //printf("#################################################\n");\r
2618     while (true)\r
2619         {\r
2620         //We start with a central directory cookie already\r
2621         //Check at the bottom of the loop.\r
2622         unsigned int version;\r
2623         if (!getInt(&version))\r
2624             {\r
2625             error("bad version found");\r
2626             return false;\r
2627             }\r
2628         unsigned int versionNeeded;\r
2629         if (!getInt(&versionNeeded))\r
2630             {\r
2631             error("bad version found");\r
2632             return false;\r
2633             }\r
2634         unsigned int gpBitFlag;\r
2635         if (!getInt(&gpBitFlag))\r
2636             {\r
2637             error("bad bit flag found");\r
2638             return false;\r
2639             }\r
2640         unsigned int compressionMethod;\r
2641         if (!getInt(&compressionMethod))\r
2642             {\r
2643             error("bad compressionMethod found");\r
2644             return false;\r
2645             }\r
2646         unsigned int modTime;\r
2647         if (!getInt(&modTime))\r
2648             {\r
2649             error("bad modTime found");\r
2650             return false;\r
2651             }\r
2652         unsigned int modDate;\r
2653         if (!getInt(&modDate))\r
2654             {\r
2655             error("bad modDate found");\r
2656             return false;\r
2657             }\r
2658         unsigned long crc32;\r
2659         if (!getLong(&crc32))\r
2660             {\r
2661             error("bad crc32 found");\r
2662             return false;\r
2663             }\r
2664         unsigned long compressedSize;\r
2665         if (!getLong(&compressedSize))\r
2666             {\r
2667             error("bad compressedSize found");\r
2668             return false;\r
2669             }\r
2670         unsigned long uncompressedSize;\r
2671         if (!getLong(&uncompressedSize))\r
2672             {\r
2673             error("bad uncompressedSize found");\r
2674             return false;\r
2675             }\r
2676         unsigned int fileNameLength;\r
2677         if (!getInt(&fileNameLength))\r
2678             {\r
2679             error("bad fileNameLength found");\r
2680             return false;\r
2681             }\r
2682         unsigned int extraFieldLength;\r
2683         if (!getInt(&extraFieldLength))\r
2684             {\r
2685             error("bad extraFieldLength found");\r
2686             return false;\r
2687             }\r
2688         unsigned int fileCommentLength;\r
2689         if (!getInt(&fileCommentLength))\r
2690             {\r
2691             error("bad fileCommentLength found");\r
2692             return false;\r
2693             }\r
2694         unsigned int diskNumberStart;\r
2695         if (!getInt(&diskNumberStart))\r
2696             {\r
2697             error("bad diskNumberStart found");\r
2698             return false;\r
2699             }\r
2700         unsigned int internalFileAttributes;\r
2701         if (!getInt(&internalFileAttributes))\r
2702             {\r
2703             error("bad internalFileAttributes found");\r
2704             return false;\r
2705             }\r
2706         unsigned long externalFileAttributes;\r
2707         if (!getLong(&externalFileAttributes))\r
2708             {\r
2709             error("bad externalFileAttributes found");\r
2710             return false;\r
2711             }\r
2712         unsigned long localHeaderOffset;\r
2713         if (!getLong(&localHeaderOffset))\r
2714             {\r
2715             error("bad localHeaderOffset found");\r
2716             return false;\r
2717             }\r
2718         std::string fileName;\r
2719         for (unsigned int i=0 ; i<fileNameLength ; i++)\r
2720             {\r
2721             unsigned char ch;\r
2722             if (!getByte(&ch))\r
2723                 break;\r
2724             fileName.push_back(ch);\r
2725             }\r
2726         std::string extraField;\r
2727         for (unsigned int i=0 ; i<extraFieldLength ; i++)\r
2728             {\r
2729             unsigned char ch;\r
2730             if (!getByte(&ch))\r
2731                 break;\r
2732             extraField.push_back(ch);\r
2733             }\r
2734         std::string fileComment;\r
2735         for (unsigned int i=0 ; i<fileCommentLength ; i++)\r
2736             {\r
2737             unsigned char ch;\r
2738             if (!getByte(&ch))\r
2739                 break;\r
2740             fileComment.push_back(ch);\r
2741             }\r
2742         trace("######################### ENTRY");\r
2743         trace("FileName           :%s" , fileName.c_str());\r
2744         trace("Extra field        :%s" , extraField.c_str());\r
2745         trace("File comment       :%s" , fileComment.c_str());\r
2746         trace("Version            :%d" , version);\r
2747         trace("Version needed     :%d" , versionNeeded);\r
2748         trace("Bitflag            :%d" , gpBitFlag);\r
2749         trace("Compression Method :%d" , compressionMethod);\r
2750         trace("Mod time           :%d" , modTime);\r
2751         trace("Mod date           :%d" , modDate);\r
2752         trace("CRC                :%lx", crc32);\r
2753         trace("Compressed size    :%ld", compressedSize);\r
2754         trace("Uncompressed size  :%ld", uncompressedSize);\r
2755         trace("Disk nr start      :%ld", diskNumberStart);\r
2756         trace("Header offset      :%ld", localHeaderOffset);\r
2757 \r
2758 \r
2759         unsigned long magicCookie;\r
2760         if (!getLong(&magicCookie))\r
2761             {\r
2762             error("magic cookie not found");\r
2763             return false;\r
2764             }\r
2765         trace("###Cookie:%lx", magicCookie);\r
2766         if (magicCookie  == 0x06054b50L) //end of central directory\r
2767             break;\r
2768         else if (magicCookie == 0x05054b50L) //signature\r
2769             {\r
2770             //## Digital Signature\r
2771             unsigned int signatureSize;\r
2772             if (!getInt(&signatureSize))\r
2773                 {\r
2774                 error("bad signatureSize found");\r
2775                 return false;\r
2776                 }\r
2777             std::string digitalSignature;\r
2778             for (unsigned int i=0 ; i<signatureSize ; i++)\r
2779                 {\r
2780                 unsigned char ch;\r
2781                 if (!getByte(&ch))\r
2782                     break;\r
2783                 digitalSignature.push_back(ch);\r
2784                 }\r
2785             trace("######## SIGNATURE :'%s'" , digitalSignature.c_str());\r
2786             }\r
2787         else if (magicCookie != 0x02014b50L) //central directory\r
2788             {\r
2789             error("directory file header not found");\r
2790             return false;\r
2791             }\r
2792         }\r
2793 \r
2794     unsigned int diskNr;\r
2795     if (!getInt(&diskNr))\r
2796         {\r
2797         error("bad diskNr found");\r
2798         return false;\r
2799         }\r
2800     unsigned int diskWithCd;\r
2801     if (!getInt(&diskWithCd))\r
2802         {\r
2803         error("bad diskWithCd found");\r
2804         return false;\r
2805         }\r
2806     unsigned int nrEntriesDisk;\r
2807     if (!getInt(&nrEntriesDisk))\r
2808         {\r
2809         error("bad nrEntriesDisk found");\r
2810         return false;\r
2811         }\r
2812     unsigned int nrEntriesTotal;\r
2813     if (!getInt(&nrEntriesTotal))\r
2814         {\r
2815         error("bad nrEntriesTotal found");\r
2816         return false;\r
2817         }\r
2818     unsigned long cdSize;\r
2819     if (!getLong(&cdSize))\r
2820         {\r
2821         error("bad cdSize found");\r
2822         return false;\r
2823         }\r
2824     unsigned long cdPos;\r
2825     if (!getLong(&cdPos))\r
2826         {\r
2827         error("bad cdPos found");\r
2828         return false;\r
2829         }\r
2830     unsigned int commentSize;\r
2831     if (!getInt(&commentSize))\r
2832         {\r
2833         error("bad commentSize found");\r
2834         return false;\r
2835         }\r
2836     comment = "";\r
2837     for (unsigned int i=0 ; i<commentSize ; i++)\r
2838         {\r
2839         unsigned char ch;\r
2840         if (!getByte(&ch))\r
2841             break;\r
2842         comment.push_back(ch);\r
2843         }\r
2844     trace("######## Zip Comment :'%s'" , comment.c_str());\r
2845 \r
2846     return true;\r
2847 }\r
2848 \r
2849 \r
2850 /**\r
2851  *\r
2852  */\r
2853 bool ZipFile::read()\r
2854 {\r
2855     fileBufPos = 0;\r
2856     if (!readFileData())\r
2857         {\r
2858         return false;\r
2859         }\r
2860     if (!readCentralDirectory())\r
2861         {\r
2862         return false;\r
2863         }\r
2864     return true;\r
2865 }\r
2866 \r
2867 /**\r
2868  *\r
2869  */\r
2870 bool ZipFile::readBuffer(const std::vector<unsigned char> &inbuf)\r
2871 {\r
2872     fileBuf = inbuf;\r
2873     if (!read())\r
2874         return false;\r
2875     return true;\r
2876 }\r
2877 \r
2878 \r
2879 /**\r
2880  *\r
2881  */\r
2882 bool ZipFile::readFile(const std::string &fileName)\r
2883 {\r
2884     fileBuf.clear();\r
2885     FILE *f = fopen(fileName.c_str(), "rb");\r
2886     if (!f)\r
2887         return false;\r
2888     while (true)\r
2889         {\r
2890         int ch = fgetc(f);\r
2891         if (ch < 0)\r
2892             break;\r
2893         fileBuf.push_back(ch);\r
2894         }\r
2895     fclose(f);\r
2896     if (!read())\r
2897         return false;\r
2898     return true;\r
2899 }\r
2900 \r
2901 \r
2902 \r
2903 \r
2904 \r
2905 \r
2906 \r
2907 \r
2908 \r
2909 //########################################################################\r
2910 //#  E N D    O F    F I L E\r
2911 //########################################################################\r
2912 \r
2913 \r