1  /*****************************************************************************/
2 /* Software Testing Automation Framework (STAF)                              */
3 /* (C) Copyright IBM Corp. 2004                                              */
4 /*                                                                           */
5 /* This software is licensed under the Eclipse Public License (EPL) V1.0.    */
6 /*****************************************************************************/
7 #include "STAF.h"
8 #include "STAFString.h"
9 #include "STAFTrace.h"
10 
11 #include <vector>
12 #include <map>
13 
14 #include "zlib.h"
15 
16 #include "STAFZip.h"
17 #include "STAFZipUtil.h"
18 #include "STAFZipFileAttribute.h"
19 #include "STAFZipCentralDirExtension.h"
20 #include "STAFZipLocalFileHeader.h"
21 #include "STAFZipFileHeader.h"
22 
23 
24 // constructor
STAFZipLocalFileHeader()25 STAFZipLocalFileHeader::STAFZipLocalFileHeader()
26 {
27     signature = 0x04034b50;
28 
29     // 2 bytes, zip 2.0
30     versionNeededToExtract = 20;
31 
32     // 2 bytes, general purpose bit flag bit 2, 1 set to be 1 0 for
33     // maximum compression
34     generalPurposeBitFlag = 2;
35 
36     // 2 bytes, method 8 - deflating
37     compressionMethod = Z_DEFLATED;
38 
39     // 2 bytes time, 2 bytes date
40     lastModifiedTimeDate = 0;
41 
42     // 4 bytes
43     crc = 0;
44 
45     // 4 bytes, not initialized yet
46     compressedSize = 0;
47 
48     // 4 bytes, not initialized yet
49     uncompressedSize = 0;
50 
51     // 2 bytes
52     fileNameLength = 0;
53 
54     // 2 bytes
55     extraFieldLength = 0;
56 
57     fileName = NULL;
58 
59     extraField = NULL;
60 
61     fullFileName = NULL;
62 
63     size = 30;
64 
65     offset = 0;
66 
67 }
68 
69 
70 // constructor based on pathname and prefix length
STAFZipLocalFileHeader(const char * pathname,int prefixlen)71 STAFZipLocalFileHeader::STAFZipLocalFileHeader(const char *pathname,
72                                                int prefixlen)
73 {
74     STAFZipUtil util = STAFZipUtil();
75 
76     signature = 0x04034b50;
77 
78 
79     fileName = NULL;
80 
81     fullFileName = NULL;
82 
83     // 2 bytes
84     fileNameLength = 0;
85 
86     // 2 bytes time, 2 bytes date
87     lastModifiedTimeDate = 0;
88 
89 
90     fullFileName = (char*)calloc(strlen(pathname) + 1, 1);
91 
92     if (fullFileName != NULL)
93     {
94         strcpy(fullFileName, pathname);
95 
96         fileName = util.calculateFileNameInZip(fullFileName, prefixlen);
97 
98         fileNameLength = strlen(fileName);
99 
100         lastModifiedTimeDate = util.fileTime(fullFileName);
101     }
102     else
103     {
104         STAFTrace::trace(kSTAFTraceServiceResult,
105              STAFString("STAFZipLocalFileHeader::STAFZipLocalFileHeader1_CP1")
106                      + "Error allocating memory for full file name.\n");
107     }
108 
109     // 2 bytes, zip 2.0
110     versionNeededToExtract = 20;
111 
112     // 2 bytes, general purpose bit flag bit 2, 1 set to be 1 0 for
113     // maximum compression
114     generalPurposeBitFlag = 2;
115 
116     // 2 bytes, method 8 - deflating
117     compressionMethod = Z_DEFLATED;
118 
119     // 4 bytes
120     crc = 0;
121 
122     // 4 bytes, not initialized yet
123     compressedSize = 0;
124 
125     // 4 bytes, not initialized yet
126     uncompressedSize = 0;
127 
128     // 2 bytes
129     extraFieldLength = 0;
130 
131     extraField = NULL;
132 
133 
134     size = 30 + fileNameLength;
135 
136     offset = 0;
137 
138 }
139 
140 
141 // flush local file header to zip archive and deflating data by
142 // using of zlib utility
flush(FILE * zf,STAFString * result)143 STAFRC_t STAFZipLocalFileHeader::flush(FILE *zf, STAFString *result)
144 {
145     STAFZipUtil util = STAFZipUtil();
146 
147     STAFRC_t rc;
148     int err;
149 
150     // save the current file offset
151     offset = util.tell(zf);
152 
153     // write the local header
154 
155     STAFTrace::trace(kSTAFTraceServiceResult,
156                      STAFString("STAFZipLocalFileHeader::flush_CP1")
157                      + " offset ["
158                      + offset
159                      + "] signature ["
160                      + signature
161                      + "]");
162 
163     // local header magic
164     rc = util.putValue(zf, (uLong)signature, 4);
165 
166     // version needed to extract
167     if (rc == kSTAFOk)
168     {
169         STAFTrace::trace(kSTAFTraceServiceResult,
170                      STAFString("STAFZipLocalFileHeader::flush_CP2")
171                      + " versionNeededToExtract ["
172                      + versionNeededToExtract
173                      + "]");
174 
175         rc = util.putValue(zf, (uLong)versionNeededToExtract, 2);
176     }
177 
178     // general purpose bit flag, 2 for Maximum (-exx/-ex) compression option was
179     // used for method 8 and 9 - deflating
180     if (rc == kSTAFOk)
181     {
182         STAFTrace::trace(kSTAFTraceServiceResult,
183                      STAFString("STAFZipLocalFileHeader::flush_CP3")
184                      + " generalPurposeBitFlag ["
185                      + generalPurposeBitFlag
186                      + "]");
187 
188         rc = util.putValue(zf, (uLong)generalPurposeBitFlag, 2);
189     }
190 
191     // compression method
192     if (rc == kSTAFOk)
193     {
194         STAFTrace::trace(kSTAFTraceServiceResult,
195                      STAFString("STAFZipLocalFileHeader::flush_CP4")
196                      + " compressionMethod ["
197                      + compressionMethod
198                      + "]");
199 
200         rc = util.putValue(zf, (uLong)compressionMethod, 2);
201     }
202 
203     // file time in DOS format
204     if (rc == kSTAFOk)
205     {
206         STAFTrace::trace(kSTAFTraceServiceResult,
207                      STAFString("STAFZipLocalFileHeader::flush_CP5")
208                      + " lastModifiedTimeDate ["
209                      + lastModifiedTimeDate
210                      + "]");
211 
212         rc = util.putValue(zf, (uLong)lastModifiedTimeDate, 4);
213     }
214 
215     // CRC 32, unknown
216     if (rc == kSTAFOk)
217     {
218         STAFTrace::trace(kSTAFTraceServiceResult,
219                      STAFString("STAFZipLocalFileHeader::flush_CP6")
220                      + " crc ["
221                      + crc
222                      + "]");
223 
224         rc = util.putValue(zf, (uLong)crc, 4);
225     }
226 
227     // compressed size, unknown
228     if (rc == kSTAFOk)
229     {
230         STAFTrace::trace(kSTAFTraceServiceResult,
231                      STAFString("STAFZipLocalFileHeader::flush_CP7")
232                      + " compressedSize ["
233                      + compressedSize
234                      + "]");
235 
236         rc = util.putValue(zf, (uLong)compressedSize, 4);
237     }
238 
239     // uncompressed size, unknown
240     if (rc == kSTAFOk)
241     {
242         STAFTrace::trace(kSTAFTraceServiceResult,
243                      STAFString("STAFZipLocalFileHeader::flush_CP7")
244                      + " uncompressedSize ["
245                      + uncompressedSize
246                      + "]");
247 
248         rc = util.putValue(zf, (uLong)uncompressedSize, 4);
249     }
250 
251     // file name size
252     if (rc == kSTAFOk)
253     {
254         STAFTrace::trace(kSTAFTraceServiceResult,
255                      STAFString("STAFZipLocalFileHeader::flush_CP8")
256                      + " fileNameLength ["
257                      + fileNameLength
258                      + "]");
259 
260         rc = util.putValue(zf, (uLong)fileNameLength, 2);
261     }
262 
263     // extra field size
264     if (rc == kSTAFOk)
265     {
266         STAFTrace::trace(kSTAFTraceServiceResult,
267                      STAFString("STAFZipLocalFileHeader::flush_CP9")
268                      + " extraFieldLength ["
269                      + extraFieldLength
270                      + "]");
271 
272         rc = util.putValue(zf, (uLong)extraFieldLength, 2);
273     }
274 
275     // file name
276     if (rc == kSTAFOk && fileNameLength > 0)
277     {
278         STAFTrace::trace(kSTAFTraceServiceResult,
279                      STAFString("STAFZipLocalFileHeader::flush_CP10")
280                      + " fileName ["
281                      + fileName
282                      + "]");
283 
284         if (fwrite(fileName, (uInt)fileNameLength, 1, zf)!=1)
285         {
286             *result = STAFString("STAFZipLocalFileHeader::flush: ")
287                           + "Error writting file name ["
288                           + fileName
289                           + "].\n";
290 
291             rc = kZIPGeneralZipError;
292         }
293     }
294 
295     // extra field
296     if (rc == kSTAFOk && extraFieldLength > 0)
297     {
298         STAFTrace::trace(kSTAFTraceServiceResult,
299                      STAFString("STAFZipLocalFileHeader::flush_CP12")
300                      + " extraField offset ["
301                      + util.tell(zf)
302                      + "]");
303 
304         if (fwrite(extraField, (uInt)extraFieldLength, 1, zf)!=1)
305         {
306             *result = STAFString("STAFZipLocalFileHeader::flush: ")
307                           + "Error writting extra field ["
308                           + fileName
309                           + "].\n";
310 
311             rc = kZIPGeneralZipError;
312         }
313     }
314 
315 
316     if (rc != kSTAFOk)
317     {
318 
319         if ((*result).length() == 0)
320         {
321             *result = STAFString("STAFZipLocalFileHeader::flush: ")
322                           + "Error writing data.\n";
323         }
324 
325         return rc;
326     }
327 
328 
329     // start deflating the file
330     if (*(fileName + fileNameLength - 1) != '/'
331         && *(fileName + fileNameLength - 1) != '\\')
332     {
333 
334         void *outbuf = NULL;
335         void *inbuf = NULL;
336 
337 
338         // allocate output buffer
339         outbuf = (void*)malloc(Z_BUFSIZE);
340         if(outbuf == NULL)
341         {
342             *result = STAFString("STAFZipLocalFileHeader::flush: ")
343                           + "Error allocating memory for zip output buffer ["
344                           + Z_BUFSIZE
345                           + "].\n";
346 
347             return kZIPNotEnoughMemory;
348         }
349 
350 
351         // initialize zLib stream structure for deflate
352         z_stream stream;
353 
354 
355         stream.total_in = 0;
356 
357         stream.total_out = 0;
358 
359         stream.zalloc = (alloc_func)0;
360 
361         stream.zfree = (free_func)0;
362 
363         stream.opaque = (voidpf)0;
364 
365         uInt level = 9;
366 
367         err = deflateInit2(&stream, level,
368                Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
369 
370 
371         if (err != Z_OK)
372         {
373             free(outbuf);
374 
375             *result = STAFString("STAFZipLocalFileHeader::flush: ")
376                           + "Error in zlib deflate init ["
377                           + err
378                           + "].\n";
379 
380             return kZIPGeneralZipError;
381         }
382 
383 
384         // allocate input buffer
385         inbuf = (void*)malloc(Z_BUFSIZE);
386         if(inbuf == NULL)
387         {
388             *result = STAFString("STAFZipLocalFileHeader::flush: ")
389                           + "Error allocating memory for zip input buffer ["
390                           + Z_BUFSIZE
391                           + "].\n";
392 
393             return kZIPNotEnoughMemory;
394         }
395 
396 
397 
398         FILE *fin;
399 
400         // open the to be zipped file
401         fin = fopen(fullFileName, "rb");
402         if (fin == NULL)
403         {
404             *result = STAFString("STAFZipLocalFileHeader::flush: ")
405                           + "Error in open file ["
406                           + fullFileName
407                           + "].\n";
408 
409             free(inbuf);
410             free(outbuf);
411 
412             return kSTAFFileOpenError;
413         }
414 
415 
416         uInt compressed_bytes;
417 
418         stream.avail_in = (uInt)0;
419 
420 
421         // loop to read data from original file
422         while (err == Z_OK)
423         {
424 
425             // prepare zip buffer
426 
427             stream.next_out = (Bytef*)outbuf;
428 
429             stream.avail_out = (uInt)Z_BUFSIZE;
430 
431 
432             // set compressed bytes to 0
433             compressed_bytes = 0;
434 
435 
436             STAFTrace::trace(kSTAFTraceServiceResult,
437                      STAFString("STAFZipLocalFileHeader::flush_CP19")
438                      + " stream.avail_out ["
439                      + stream.avail_out
440                      + "] stream.avail_in ["
441                      + stream.avail_in
442                      + "]");
443 
444             // loop to zip data
445             while (stream.avail_out > 0 && err == Z_OK)
446             {
447 
448                 if (stream.avail_in == 0)
449                 {
450 
451                     // read Z_BUFSIZE of bytes from file
452                     stream.avail_in = fread(inbuf, 1, Z_BUFSIZE, fin);
453 
454                     STAFTrace::trace(kSTAFTraceServiceResult,
455                              STAFString("STAFZipLocalFileHeader::flush_CP20")
456                              + " stream.avail_in ["
457                              + stream.avail_in
458                              + "]");
459 
460                     // if size read < Z_BUFSIZE and not end of file, return err
461                     if (stream.avail_in < Z_BUFSIZE)
462                     {
463                         if (feof(fin) == 0)
464                         {
465                             *result =
466                                 STAFString("STAFZipLocalFileHeader::flush: ")
467                                 + "Error in reading file ["
468                                 + fullFileName
469                                 + "].\n";
470 
471                             rc = kSTAFFileReadError;
472 
473                             break;
474                         }
475                     }
476 
477 
478                     // if size read > 0
479                     if (stream.avail_in > 0)
480                     {
481                         // set next in
482                         stream.next_in = (Bytef*)inbuf;
483 
484                         // calculate crc
485                         crc = crc32(crc, stream.next_in, stream.avail_in);
486                     }
487 
488                 } // read in raw data from file
489 
490 
491                 // save the total out before delfating
492                 uLong uTotalOutBefore = stream.total_out;
493 
494                 STAFTrace::trace(kSTAFTraceServiceResult,
495                              STAFString("STAFZipLocalFileHeader::flush_CP22")
496                              + " stream.total_out ["
497                              + stream.total_out
498                              + "] stream.avail_in ["
499                              + stream.avail_in
500                              + "]");
501 
502 
503                 if (stream.avail_in == 0)
504                 {
505                     // do delate with Z_FINISH
506                     err = deflate(&stream,  Z_FINISH);
507                 }
508                 else
509                 {
510                     // do delate with Z_NO_FLUSH
511                     err = deflate(&stream,  Z_NO_FLUSH);
512                 }
513 
514 
515                 // calculate compressed size
516                 compressed_bytes += (uInt)(stream.total_out - uTotalOutBefore);
517 
518                 STAFTrace::trace(kSTAFTraceServiceResult,
519                              STAFString("STAFZipLocalFileHeader::flush_CP23")
520                              + " stream.total_out ["
521                              + stream.total_out
522                              + "] uTotalOutBefore ["
523                              + uTotalOutBefore
524                              + "] compressed_bytes ["
525                              + compressed_bytes
526                              + "]");
527 
528             } // loop to zip data
529 
530 
531             // if error, break
532             if (rc != kSTAFOk || (err != Z_STREAM_END && err != Z_OK))
533             {
534                 if ((*result).length() == 0)
535                 {
536                     *result = STAFString("STAFZipLocalFileHeader::flush: ")
537                           + "Error in deflating ["
538                           + err
539                           + "].\n";
540                 }
541 
542                 rc = kZIPGeneralZipError;
543 
544                 break;
545             }
546 
547 
548             // write the unzipped buffer to file
549 
550             STAFTrace::trace(kSTAFTraceServiceResult,
551                              STAFString("STAFZipLocalFileHeader::flush_CP25")
552                              + " compressed_bytes ["
553                              + compressed_bytes
554                              + "]");
555 
556             if (compressed_bytes > 0)
557             {
558                 if (fwrite(outbuf, compressed_bytes, 1, zf)!=1)
559                 {
560                     *result = STAFString("STAFZipLocalFileHeader::flush: ")
561                           + "Error writting compressed bytes ["
562                           + compressed_bytes
563                           + "].\n";
564 
565                     rc = kSTAFFileWriteError;
566 
567                     break;
568                 }
569 
570             }
571 
572 
573         } // loop to read data from original file
574 
575 
576         fclose(fin);
577 
578         STAFTrace::trace(kSTAFTraceServiceResult,
579                          STAFString("STAFZipLocalFileHeader::flush_CP27")
580                          + " err ["
581                          + err
582                          + "] rc ["
583                          + rc
584                          + "]");
585 
586         // end the deflate
587         if (err == Z_STREAM_END && rc == kSTAFOk)
588         {
589             err = deflateEnd(&stream);
590         }
591 
592 
593         free(inbuf);
594 
595         free(outbuf);
596 
597 
598         if (err != Z_OK)
599         {
600             if ((*result).length() == 0)
601             {
602                 *result = STAFString("STAFZipLocalFileHeader::flush: ")
603                           + "Error finishing deflating ["
604                           + err
605                           + "].\n";
606             }
607 
608             rc = kZIPGeneralZipError;
609         }
610 
611 
612         if (rc != kSTAFOk)
613         {
614             return rc;
615         }
616 
617 
618         compressedSize = stream.total_out;
619 
620         uncompressedSize = stream.total_in;
621 
622 
623 
624         // save current end of local file header position
625         STAFInt64_t curpos = util.tell(zf);
626 
627         STAFTrace::trace(kSTAFTraceServiceResult,
628                          STAFString("STAFZipLocalFileHeader::flush_CP30")
629                          + " curpos ["
630                          + curpos
631                          + "]");
632 
633         // update crc, compressed size, uncompressed size
634         if (util.seek(zf, offset + 14, SEEK_SET) != 0)
635         {
636             *result = STAFString("STAFZipLocalFileHeader::flush: ")
637                           + "Error seek crc, compressed uncompressed size ["
638                           + (offset + 14)
639                           + "].\n";
640 
641             rc = kZIPGeneralZipError;
642         }
643 
644 
645         // save crc32
646         if (rc == kSTAFOk)
647         {
648             STAFTrace::trace(kSTAFTraceServiceResult,
649                          STAFString("STAFZipLocalFileHeader::flush_CP32")
650                          + " crc ["
651                          + crc
652                          + "]");
653 
654             rc = util.putValue(zf, (uLong)crc, 4);
655         }
656 
657         // save compressed size
658         if (rc == kSTAFOk)
659         {
660             STAFTrace::trace(kSTAFTraceServiceResult,
661                          STAFString("STAFZipLocalFileHeader::flush_CP33")
662                          + " compressedSize ["
663                          + compressedSize
664                          + "]");
665 
666             rc = util.putValue(zf, (uLong)compressedSize, 4);
667         }
668 
669 
670         // save uncompressed size
671         if (rc == kSTAFOk)
672         {
673             STAFTrace::trace(kSTAFTraceServiceResult,
674                          STAFString("STAFZipLocalFileHeader::flush_CP34")
675                          + " uncompressedSize ["
676                          + uncompressedSize
677                          + "]");
678 
679             rc = util.putValue(zf, (uLong)uncompressedSize, 4);
680         }
681 
682 
683         // restore the previous end of local file header position
684         if (util.seek(zf, curpos, SEEK_SET) != 0 && rc == kSTAFOk)
685         {
686             *result = STAFString("STAFZipLocalFileHeader::flush: ")
687                           + "Error restore end of local header pos ["
688                           + curpos
689                           + "].\n";
690 
691             rc = kZIPGeneralZipError;
692         }
693 
694 
695     } // zip the file
696 
697     size = util.tell(zf) - offset;
698 
699     STAFTrace::trace(kSTAFTraceServiceResult,
700                      STAFString("STAFZipLocalFileHeader::flush_CP36")
701                      + " size ["
702                      + size
703                      + "]");
704 
705     return rc;
706 }
707 
708 
709 // extract one file from zip archive by using zlib utility
doExtract(FILE * zf,uLong startPos,FILE * outfile,STAFString * result)710 STAFRC_t STAFZipLocalFileHeader::doExtract(FILE *zf, uLong startPos,
711                                            FILE *outfile,
712                                            STAFString *result)
713 {
714     STAFZipUtil util = STAFZipUtil();
715     z_stream stream;
716     stream.total_out = 0;
717 
718     int err = Z_OK;
719     STAFRC_t rc = kSTAFOk;
720 
721     STAFTrace::trace(kSTAFTraceServiceResult,
722                      STAFString("STAFZipLocalFileHeader::doExtract_CP1")
723                      + " rc ["
724                      + rc
725                      + "]");
726 
727     if (compressionMethod != 0)
728     {
729         stream.zalloc = (alloc_func)0;
730         stream.zfree = (free_func)0;
731         stream.opaque = (voidpf)0;
732 
733         err = inflateInit2(&stream, -MAX_WBITS);
734         /* windowBits is passed < 0 to tell that there is no zlib header.
735          * Note that in this case inflate *requires* an extra "dummy" byte
736          * after the compressed stream in order to complete decompression and
737          * return Z_STREAM_END.
738          * In unzip, i don't wait absolutely Z_STREAM_END because I known the
739          * size of both compressed and uncompressed data
740          */
741 
742         if (err != Z_OK)
743         {
744             *result = STAFString("STAFZipLocalFileHeader::doExtract: ")
745                           + "Error init zlib inflate ["
746                           + err
747                           + "].\n";
748 
749             return kZIPGeneralZipError;
750         }
751     }
752 
753     // allocate input buffer
754 
755     void *inbuf = (void*)malloc(Z_BUFSIZE);
756 
757     if(inbuf == NULL)
758     {
759         *result = STAFString("STAFZipLocalFileHeader::doExtract: ")
760                           + "Error allocating memory for input buffer ["
761                           + Z_BUFSIZE
762                           + "].\n";
763         return kZIPNotEnoughMemory;
764     }
765 
766     // allocate output buffer
767 
768     void *outbuf = (void*)malloc(Z_BUFSIZE);
769 
770     if(outbuf == NULL)
771     {
772         *result = STAFString("STAFZipLocalFileHeader::doExtract: ")
773                           + "Error allocating memory for output buffer ["
774                           + Z_BUFSIZE
775                           + "].\n";
776         return kZIPNotEnoughMemory;
777     }
778 
779     uLong pos = offset + size - compressedSize;
780     uLong rest_uncompressed, rest_compressed;
781 
782     rest_uncompressed = uncompressedSize;
783     rest_compressed = compressedSize;
784 
785     uInt uncompressed_bytes;
786     uLong newcrc32 = 0;
787 
788     stream.avail_in = (uInt)0;
789 
790     STAFTrace::trace(kSTAFTraceServiceResult,
791                      STAFString("STAFZipLocalFileHeader::doExtract_CP4.5")
792                      + " pos ["
793                      + pos
794                      + "] stream.avail_in ["
795                      + stream.avail_in
796                      + "] rest_uncompressed ["
797                      + rest_uncompressed
798                      + "] rest_compressed ["
799                      + rest_compressed
800                      + "]");
801 
802     // loop to read compressed data from zip file
803 
804     while (rest_uncompressed > 0)
805     {
806         // unzip buffer
807 
808         stream.next_out = (Bytef*)outbuf;
809         stream.avail_out = (uInt)Z_BUFSIZE;
810 
811         STAFTrace::trace(kSTAFTraceServiceResult,
812                      STAFString("STAFZipLocalFileHeader::doExtract_CP5")
813                      + " stream.avail_out ["
814                      + stream.avail_out
815                      + "] rest_uncompressed ["
816                      + rest_uncompressed
817                      + "]");
818 
819         if (stream.avail_out > rest_uncompressed)
820         {
821             stream.avail_out = (uInt)rest_uncompressed;
822         }
823 
824         uncompressed_bytes = 0;
825 
826         STAFTrace::trace(kSTAFTraceServiceResult,
827                      STAFString("STAFZipLocalFileHeader::doExtract_CP6")
828                      + " stream.avail_out ["
829                      + stream.avail_out
830                      + "]");
831 
832         // loop to unzip compressed data
833 
834         while (stream.avail_out > 0)
835         {
836             STAFTrace::trace(kSTAFTraceServiceResult,
837                      STAFString("STAFZipLocalFileHeader::doExtract_CP7")
838                      + " stream.avail_in ["
839                      + stream.avail_in
840                      + "] rest_compressed ["
841                      + rest_compressed
842                      + "]");
843 
844             if (stream.avail_in == 0 && rest_compressed != 0)
845             {
846                 // set available in
847 
848                 stream.avail_in = Z_BUFSIZE;
849 
850                 STAFTrace::trace(kSTAFTraceServiceResult,
851                          STAFString("STAFZipLocalFileHeader::doExtract_CP8")
852                          + " stream.avail_in ["
853                          + stream.avail_in
854                          + "] rest_compressed ["
855                          + rest_compressed
856                          + "]");
857 
858                 if (stream.avail_in > rest_compressed)
859                 {
860                     stream.avail_in = (uInt)rest_compressed;
861                 }
862 
863                 // set file position to the next compressed data
864 
865                 if (util.seek(zf, pos + startPos, SEEK_SET) != 0)
866                 {
867                     *result = STAFString("STAFZipLocalFileHeader::doExtract: ")
868                           + "Error set pos to next compressed data ["
869                           + pos + " + " + startPos + "].\n";
870                     rc =  kZIPGeneralZipError;
871 
872                     break;
873                 }
874 
875                 // read stream.avail_in bytes of data from file to inbuf
876 
877                 if (fread(inbuf, stream.avail_in, 1, zf) != 1)
878                 {
879                     *result = STAFString("STAFZipLocalFileHeader::doExtract: ")
880                           + "Error reading file bytes ["
881                           + stream.avail_in
882                           + "].\n";
883                     rc = kSTAFFileReadError;
884 
885                     break;
886                 }
887 
888                 // prepare file position to next compressed data
889 
890                 pos += stream.avail_in;
891 
892                 // reduce rest_compressed data size
893 
894                 rest_compressed -= stream.avail_in;
895 
896                 STAFTrace::trace(kSTAFTraceServiceResult,
897                          STAFString("STAFZipLocalFileHeader::doExtract_CP11")
898                          + " stream.avail_in ["
899                          + stream.avail_in
900                          + "] rest_compressed ["
901                          + rest_compressed
902                          + "] pos ["
903                          + pos
904                          + "]");
905 
906                 // set zip stream to point to inbuf
907 
908                 stream.next_in = (Bytef*)inbuf;
909             }
910 
911             STAFTrace::trace(kSTAFTraceServiceResult,
912                          STAFString("STAFZipLocalFileHeader::doExtract_CP12")
913                          + " compressionMethod ["
914                          + compressionMethod
915                          + "]");
916 
917             // if no compression
918             if (compressionMethod == 0)
919             {
920                 uLong processed_bytes;
921 
922                 STAFTrace::trace(kSTAFTraceServiceResult,
923                          STAFString("STAFZipLocalFileHeader::doExtract_CP13")
924                          + " stream.avail_in ["
925                          + stream.avail_in
926                          + "] stream.avail_out ["
927                          + stream.avail_out
928                          + "]");
929 
930                 if (stream.avail_out < stream.avail_in)
931                 {
932                     processed_bytes = stream.avail_out;
933                 }
934                 else
935                 {
936                     processed_bytes = stream.avail_in;
937                 }
938 
939                 STAFTrace::trace(kSTAFTraceServiceResult,
940                          STAFString("STAFZipLocalFileHeader::doExtract_CP14")
941                          + " processed_bytes ["
942                          + processed_bytes
943                          + "]");
944 
945                 for (int i = 0; i < processed_bytes; i++)
946                 {
947                     *(stream.next_out + i) = *(stream.next_in + i);
948                 }
949 
950                 newcrc32 = crc32(newcrc32, stream.next_out, processed_bytes);
951 
952                 stream.avail_in -= processed_bytes;
953                 stream.avail_out -= processed_bytes;
954 
955                 stream.next_out += processed_bytes;
956                 stream.next_in += processed_bytes;
957 
958                 stream.total_out += processed_bytes;
959 
960                 uncompressed_bytes += processed_bytes;
961 
962                 STAFTrace::trace(kSTAFTraceServiceResult,
963                          STAFString("STAFZipLocalFileHeader::doExtract_CP15")
964                          + " stream.avail_in ["
965                          + stream.avail_in
966                          + " stream.avail_out ["
967                          + stream.avail_out
968                          + " stream.total_out ["
969                          + stream.total_out
970                          + " uncompressed_bytes ["
971                          + uncompressed_bytes
972                          + " newcrc32 ["
973                          + newcrc32
974                          + "]");
975             }
976             else
977             {
978                 // start deflating the file
979 
980                 uLong total_out_before, processed_bytes;
981                 total_out_before = stream.total_out;
982 
983                 const Bytef *bufBefore;
984                 bufBefore = stream.next_out;
985 
986                 STAFTrace::trace(kSTAFTraceServiceResult,
987                          STAFString("STAFZipLocalFileHeader::doExtract_CP16")
988                          + " total_out_before ["
989                          + total_out_before
990                          + "]");
991 
992                 // unzip
993 
994                 err = inflate(&stream, Z_SYNC_FLUSH);
995 
996                 processed_bytes = stream.total_out - total_out_before;
997 
998                 // calculate crc
999 
1000                 newcrc32 = crc32(newcrc32, bufBefore, (uInt)(processed_bytes));
1001 
1002                 // calculate uncompressed bytes
1003 
1004                 uncompressed_bytes += (uInt)processed_bytes;
1005 
1006                 STAFTrace::trace(kSTAFTraceServiceResult,
1007                          STAFString("STAFZipLocalFileHeader::doExtract_CP17")
1008                          + " err ["
1009                          + err
1010                          + "] stream.total_out ["
1011                          + stream.total_out
1012                          + "] processed_bytes ["
1013                          + processed_bytes
1014                          + "] newcrc32 ["
1015                          + newcrc32
1016                          + "] uncompressed_bytes ["
1017                          + uncompressed_bytes
1018                          + "]");
1019 
1020                 if (err != Z_OK)
1021                 {
1022                     *result = STAFString("STAFZipLocalFileHeader::doExtract: ")
1023                           + "Error inflate file, err ["
1024                           + err
1025                           + "].\n";
1026 
1027                     break;
1028                 }
1029             } // compressionMethod == 0?
1030         } // while stream.avail_out > 0
1031 
1032         if (rc != kSTAFOk || (err != Z_OK && err != Z_STREAM_END))
1033         {
1034             if ((*result).length() == 0)
1035             {
1036                 *result = STAFString("STAFZipLocalFileHeader::doExtract: ")
1037                           + "Error deflating file, err ["
1038                           + err
1039                           + "].\n";
1040             }
1041 
1042             rc = kZIPGeneralZipError;
1043 
1044             break;
1045         }
1046 
1047         STAFTrace::trace(kSTAFTraceServiceResult,
1048                          STAFString("STAFZipLocalFileHeader::doExtract_CP20")
1049                          + " uncompressed_bytes ["
1050                          + uncompressed_bytes
1051                          + "]");
1052 
1053         // write the unzipped buffer to file
1054 
1055         if (uncompressed_bytes > 0)
1056         {
1057             if (fwrite(outbuf, uncompressed_bytes, 1, outfile) != 1)
1058             {
1059                 *result = STAFString("STAFZipLocalFileHeader::doExtract: ")
1060                           + "Error writing file bytes ["
1061                           + uncompressed_bytes
1062                           + "].\n";
1063 
1064                 rc = kSTAFFileWriteError;
1065 
1066                 break;
1067             }
1068 
1069             rest_uncompressed -= uncompressed_bytes;
1070 
1071             STAFTrace::trace(kSTAFTraceServiceResult,
1072                          STAFString("STAFZipLocalFileHeader::doExtract_CP22")
1073                          + " rest_uncompressed ["
1074                          + rest_uncompressed
1075                          + "]");
1076         }
1077     } // loop to read compressed data from zip file
1078 
1079     if (compressionMethod != 0)
1080     {
1081         STAFTrace::trace(kSTAFTraceServiceResult,
1082                          STAFString("STAFZipLocalFileHeader::doExtract_CP23")
1083                          + " compressionMethod ["
1084                          + compressionMethod
1085                          + "]");
1086 
1087         // inflate end
1088 
1089         inflateEnd(&stream);
1090     }
1091 
1092     // compare crc
1093 
1094     if (rc == kSTAFOk)
1095     {
1096         if (newcrc32 != crc)
1097         {
1098            *result = STAFString("STAFZipLocalFileHeader::doExtract: ")
1099                           + "Bad CRC new crc ["
1100                           + newcrc32
1101                           + "] old crc ["
1102                           + crc
1103                           + "].\n";
1104             rc = kZIPBadCRC;
1105         }
1106     }
1107 
1108     free(inbuf);
1109     free(outbuf);
1110 
1111     return rc;
1112 }
1113 
1114 
1115 // destructor
1116 
~STAFZipLocalFileHeader()1117 STAFZipLocalFileHeader::~STAFZipLocalFileHeader()
1118 {
1119     if (fullFileName != NULL)
1120     {
1121         free(fullFileName);
1122     }
1123 
1124     if (extraField != NULL)
1125     {
1126         free(extraField);
1127     }
1128 }
1129 
1130 
1131 // extract zip archive to output dir
1132 
extract(FILE * zf,uLong startPos,const char * outputdir,STAFString * result)1133 STAFRC_t STAFZipLocalFileHeader::extract(FILE *zf, uLong startPos,
1134                                          const char *outputdir,
1135                                          STAFString *result)
1136 {
1137     STAFRC_t rc;
1138     STAFZipUtil util = STAFZipUtil();
1139 
1140     STAFTrace::trace(kSTAFTraceServiceResult,
1141                      STAFString("STAFZipLocalFileHeader::extract_CP1")
1142                      + " outputdir ["
1143                      + outputdir
1144                      + "]");
1145 
1146     fullFileName = (char*)calloc(strlen(outputdir) + fileNameLength + 1, 1);
1147 
1148     if (fullFileName == NULL)
1149     {
1150         *result = STAFString("STAFZipLocalFileHeader::extract: ")
1151                           + "Error allocating memory for fullFileName ["
1152                           + (strlen(outputdir) + fileNameLength + 1)
1153                           + "].\n";
1154         return kZIPNotEnoughMemory;
1155     }
1156 
1157     strcpy(fullFileName, outputdir);
1158     strcat(fullFileName, fileName);
1159 
1160     fileName = fullFileName + strlen(outputdir);
1161 
1162     STAFTrace::trace(kSTAFTraceServiceResult,
1163                      STAFString("STAFZipLocalFileHeader::extract_CP3")
1164                      + " fileName ["
1165                      + fileName
1166                      + "] fullFileName ["
1167                      + fullFileName
1168                      + "]");
1169 
1170     if (*(fileName + strlen(fileName) - 1) == '\\'
1171         || *(fileName + strlen(fileName) - 1) == '/')
1172     {
1173         STAFTrace::trace(kSTAFTraceServiceResult,
1174                      STAFString("STAFZipLocalFileHeader::extract_CP4"));
1175 
1176         // create dir
1177 
1178         if ((rc = util.makeDir(fullFileName)) != kSTAFOk)
1179         {
1180             *result = STAFString("STAFZipLocalFileHeader::extract: ")
1181                           + "Error making dir ["
1182                           + fullFileName
1183                           + "].\n";
1184         }
1185 
1186         return rc;
1187     }
1188 
1189     FILE *outfile;
1190 
1191     // make sure the target directories exist before extracting files
1192 
1193     if ((outfile = fopen(fullFileName, "wb")) == NULL)
1194     {
1195         // finding fileName without path
1196 
1197         char *p, *filename_withoutpath;
1198         p = filename_withoutpath = fullFileName;
1199 
1200         while ((*p) != '\0')
1201         {
1202             if (((*p) == '/') || ((*p) == '\\'))
1203             {
1204                 filename_withoutpath = p + 1;
1205             }
1206 
1207             p++;
1208         }
1209 
1210         STAFTrace::trace(kSTAFTraceServiceResult,
1211                      STAFString("STAFZipLocalFileHeader::extract_CP5")
1212                      + " filename_withoutpath ["
1213                      + filename_withoutpath
1214                      + "]");
1215 
1216         // store the char before the file name without path
1217 
1218         char c = *(filename_withoutpath - 1);
1219 
1220         // to form a string which contains only the directory
1221 
1222         *(filename_withoutpath - 1) = '\0';
1223 
1224         STAFTrace::trace(kSTAFTraceServiceResult,
1225                      STAFString("STAFZipLocalFileHeader::extract_CP6")
1226                      + " fullFileName ["
1227                      + fullFileName
1228                      + "]");
1229 
1230         // make the directory
1231 
1232         if ((rc = util.makeDir(fullFileName)) != kSTAFOk)
1233         {
1234             *result = STAFString("STAFZipLocalFileHeader::extract: ")
1235                           + "Error making directory: ["
1236                           + fullFileName
1237                           + "].\n";
1238             return rc;
1239         }
1240 
1241         *(filename_withoutpath - 1) = c;
1242 
1243         if ((outfile = fopen(fullFileName, "wb")) == NULL)
1244         {
1245             *result = STAFString("STAFZipLocalFileHeader::extract: ")
1246                           + "Error creating file ["
1247                           + fullFileName
1248                           + "].\n";
1249 
1250             return kZIPGeneralZipError;
1251         }
1252     }
1253 
1254     rc = doExtract(zf, startPos, outfile, result);
1255 
1256     STAFTrace::trace(kSTAFTraceServiceResult,
1257                      STAFString("STAFZipLocalFileHeader::extract_CP8")
1258                      + " rc ["
1259                      + rc
1260                      + "]");
1261 
1262     fclose(outfile);
1263 
1264     if (rc == kSTAFOk)
1265     {
1266         tm filedate;
1267 
1268         util.fileTime(lastModifiedTimeDate, &filedate);
1269         util.changeFileDate(fullFileName, lastModifiedTimeDate, filedate);
1270     }
1271 
1272     return rc;
1273 }
1274 
1275 
1276 
1277 
1278 
1279