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(<ime))\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