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