]> Shamusworld >> Repos - virtualjaguar/blob - src/unzip.cpp
Fix for bad branch handling in OP.
[virtualjaguar] / src / unzip.cpp
1 //
2 // ZIP file support
3 // This is here to simplify interfacing to zlib, as zlib does NO zip file handling
4 //
5 // by James Hammons
6 // (C) 2012 Underground Software
7 //
8 // JLH = James Hammons <jlhamm@acm.org>
9 //
10 // Who  When        What
11 // ---  ----------  -------------------------------------------------------------
12 // JLH  01/16/2010  Created this log ;-)
13 // JLH  02/28/2010  Removed unnecessary cruft
14 // JLH  05/31/2012  Rewrote everything and removed all MAME code
15 //
16
17 #include "unzip.h"
18
19 #include <stdlib.h>
20 #include <string.h>
21 #include <zlib.h>
22 #include "log.h"
23
24
25 uint32_t GetLong(FILE * fp)
26 {
27         uint32_t n = ((uint32_t)fgetc(fp));
28         n |= ((uint32_t)fgetc(fp)) << 8;
29         n |= ((uint32_t)fgetc(fp)) << 16;
30         n |= ((uint32_t)fgetc(fp)) << 24;
31
32         return n;
33 }
34
35
36 uint16_t GetWord(FILE * fp)
37 {
38         uint16_t n = ((uint16_t)fgetc(fp));
39         n |= ((uint16_t)fgetc(fp)) << 8;
40
41         return n;
42 }
43
44
45 bool GetZIPHeader(FILE * fp, ZipFileEntry & ze)
46 {
47         ze.signature = GetLong(fp);
48         ze.version = GetWord(fp);
49         ze.flags = GetWord(fp);
50         ze.method = GetWord(fp);
51         ze.modifiedTime = GetWord(fp);
52         ze.modifiedDate = GetWord(fp);
53         ze.crc32 = GetLong(fp);
54         ze.compressedSize = GetLong(fp);
55         ze.uncompressedSize = GetLong(fp);
56         ze.filenameLength = GetWord(fp);
57         ze.extraLength = GetWord(fp);
58
59         // This handling is really ungraceful; but if someone is going to feed us
60         // shit, then why eat it? :-)
61         if (ze.filenameLength < 512)
62         {
63                 fread(ze.filename, 1, ze.filenameLength, fp);
64                 ze.filename[ze.filenameLength] = 0;
65         }
66         else
67         {
68                 fseek(fp, ze.filenameLength, SEEK_CUR);
69                 ze.filename[0] = 0;
70         }
71
72         // Skip the "extra" header
73         fseek(fp, ze.extraLength, SEEK_CUR);
74
75         return (ze.signature == 0x04034B50 ? true : false);
76 }
77
78
79 //
80 // Uncompress a file from a ZIP file filestream
81 // NOTE: The passed in buffer *must* be fully allocated before calling this!
82 //
83 #define CHUNKSIZE 16384
84 int UncompressFileFromZIP(FILE * fp, ZipFileEntry ze, uint8_t * buffer)
85 {
86         z_stream zip;
87         unsigned char inBuffer[CHUNKSIZE];
88         uint32_t remaining = ze.compressedSize;
89
90         // Set up z_stream for inflating
91         zip.zalloc = Z_NULL;
92         zip.zfree = Z_NULL;
93         zip.opaque = Z_NULL;
94         zip.avail_in = 0;
95         zip.next_in = Z_NULL;
96
97         int ret = inflateInit2(&zip, -MAX_WBITS);       // -MAX_WBITS tells it there's no header
98
99         // Bail if can't initialize the z_stream...
100         if (ret != Z_OK)
101                 return ret;
102
103         zip.avail_out = ze.uncompressedSize;
104         zip.next_out = buffer;
105
106         // Decompress until deflate stream ends or we hit end of file
107         do
108         {
109                 zip.avail_in = fread(inBuffer, 1, (remaining < CHUNKSIZE ? remaining : CHUNKSIZE), fp);
110                 zip.next_in = inBuffer;
111                 remaining -= CHUNKSIZE;
112
113                 if (ferror(fp))
114                 {
115                         inflateEnd(&zip);
116                         return Z_ERRNO;
117                 }
118
119                 if (zip.avail_in == 0)
120                         break;
121
122                 ret = inflate(&zip, Z_NO_FLUSH);
123
124                 if ((ret == Z_NEED_DICT) || (ret == Z_DATA_ERROR) || (ret == Z_MEM_ERROR))
125                 {
126                         inflateEnd(&zip);
127                         return ret;
128                 }
129
130         }
131         while (ret != Z_STREAM_END);
132
133         inflateEnd(&zip);
134
135         return (ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR);
136 }