Commit | Line | Data |
---|---|---|
cf76e892 JPM |
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 | } |