]>
Commit | Line | Data |
---|---|---|
377029eb | 1 | /* Handle a .class file embedded in a .zip archive. |
2 | This extracts a member from a .zip file, but does not handle | |
3 | uncompression (since that is not needed for classes.zip). | |
f1717362 | 4 | Copyright (C) 1996-2016 Free Software Foundation, Inc. |
377029eb | 5 | |
7d82ed5e | 6 | This file is part of GCC. |
377029eb | 7 | |
7d82ed5e | 8 | GCC is free software; you can redistribute it and/or modify |
377029eb | 9 | it under the terms of the GNU General Public License as published by |
e4b52719 | 10 | the Free Software Foundation; either version 3, or (at your option) |
377029eb | 11 | any later version. |
12 | ||
7d82ed5e | 13 | GCC is distributed in the hope that it will be useful, |
377029eb | 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
e4b52719 | 19 | along with GCC; see the file COPYING3. If not see |
20 | <http://www.gnu.org/licenses/>. | |
377029eb | 21 | |
22 | Java and all Java-based marks are trademarks or registered trademarks | |
23 | of Sun Microsystems, Inc. in the United States and other countries. | |
24 | The Free Software Foundation is independent of Sun Microsystems, Inc. */ | |
25 | ||
26 | /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */ | |
27 | ||
65c439eb | 28 | #include "config.h" |
29 | #include "system.h" | |
805e22b2 | 30 | #include "coretypes.h" |
377029eb | 31 | #include "zipfile.h" |
32 | ||
377029eb | 33 | /* This stuff is partly based on the 28 August 1994 public release of the |
34 | Info-ZIP group's portable UnZip zipfile-extraction program (and related | |
35 | utilities). */ | |
36 | ||
377029eb | 37 | /*************/ |
38 | /* Defines */ | |
39 | /*************/ | |
40 | ||
41 | #define UNZIP | |
42 | #define UNZIP_VERSION 20 /* compatible with PKUNZIP 2.0 */ | |
43 | #define VMS_UNZIP_VERSION 42 /* if OS-needed-to-extract is VMS: can do */ | |
44 | ||
45 | ||
46 | #define ZSUFX ".zip" | |
47 | #define CENTRAL_HDR_SIG "\113\001\002" /* the infamous "PK" signature */ | |
48 | #define LOCAL_HDR_SIG "\113\003\004" /* bytes, sans "P" (so unzip */ | |
49 | #define END_CENTRAL_SIG "\113\005\006" /* executable not mistaken for */ | |
50 | #define EXTD_LOCAL_SIG "\113\007\010" /* zipfile itself) */ | |
51 | ||
52 | #define STORED 0 /* compression methods */ | |
53 | #define SHRUNK 1 | |
54 | #define REDUCED1 2 | |
55 | #define REDUCED2 3 | |
56 | #define REDUCED3 4 | |
57 | #define REDUCED4 5 | |
58 | #define IMPLODED 6 | |
59 | #define TOKENIZED 7 | |
60 | #define DEFLATED 8 | |
61 | #define NUM_METHODS 9 /* index of last method + 1 */ | |
62 | /* don't forget to update list_files() appropriately if NUM_METHODS changes */ | |
63 | ||
64 | #define PK_OK 0 /* no error */ | |
65 | #define PK_COOL 0 /* no error */ | |
66 | #define PK_GNARLY 0 /* no error */ | |
67 | #define PK_WARN 1 /* warning error */ | |
68 | #define PK_ERR 2 /* error in zipfile */ | |
69 | #define PK_BADERR 3 /* severe error in zipfile */ | |
70 | #define PK_MEM 4 /* insufficient memory */ | |
71 | #define PK_MEM2 5 /* insufficient memory */ | |
72 | #define PK_MEM3 6 /* insufficient memory */ | |
73 | #define PK_MEM4 7 /* insufficient memory */ | |
74 | #define PK_MEM5 8 /* insufficient memory */ | |
75 | #define PK_NOZIP 9 /* zipfile not found */ | |
76 | #define PK_PARAM 10 /* bad or illegal parameters specified */ | |
77 | #define PK_FIND 11 /* no files found */ | |
78 | #define PK_DISK 50 /* disk full */ | |
79 | #define PK_EOF 51 /* unexpected EOF */ | |
80 | ||
81 | /*--------------------------------------------------------------------------- | |
82 | True sizes of the various headers, as defined by PKWARE--so it is not | |
83 | likely that these will ever change. But if they do, make sure both these | |
84 | defines AND the typedefs below get updated accordingly. | |
85 | ---------------------------------------------------------------------------*/ | |
86 | #define LREC_SIZE 26 /* lengths of local file headers, central */ | |
87 | #define CREC_SIZE 42 /* directory headers, and the end-of- */ | |
88 | #define ECREC_SIZE 18 /* central-dir record, respectively */ | |
89 | ||
90 | ||
91 | #ifndef SEEK_SET | |
92 | # define SEEK_SET 0 | |
93 | # define SEEK_CUR 1 | |
94 | # define SEEK_END 2 | |
95 | #endif | |
96 | ||
97 | /**************/ | |
98 | /* Typedefs */ | |
99 | /**************/ | |
100 | ||
101 | typedef char boolean; | |
102 | typedef unsigned char uch; /* code assumes unsigned bytes; these type- */ | |
103 | typedef unsigned short ush; /* defs replace byte/UWORD/ULONG (which are */ | |
104 | typedef unsigned long ulg; /* predefined on some systems) & match zip */ | |
105 | ||
106 | /*--------------------------------------------------------------------------- | |
107 | Zipfile layout declarations. If these headers ever change, make sure the | |
108 | xxREC_SIZE defines (above) change with them! | |
109 | ---------------------------------------------------------------------------*/ | |
110 | ||
111 | typedef uch local_byte_hdr[ LREC_SIZE ]; | |
112 | # define L_VERSION_NEEDED_TO_EXTRACT_0 0 | |
113 | # define L_VERSION_NEEDED_TO_EXTRACT_1 1 | |
114 | # define L_GENERAL_PURPOSE_BIT_FLAG 2 | |
115 | # define L_COMPRESSION_METHOD 4 | |
116 | # define L_LAST_MOD_FILE_TIME 6 | |
117 | # define L_LAST_MOD_FILE_DATE 8 | |
118 | # define L_CRC32 10 | |
119 | # define L_COMPRESSED_SIZE 14 | |
120 | # define L_UNCOMPRESSED_SIZE 18 | |
121 | # define L_FILENAME_LENGTH 22 | |
122 | # define L_EXTRA_FIELD_LENGTH 24 | |
123 | ||
124 | typedef uch cdir_byte_hdr[ CREC_SIZE ]; | |
125 | # define C_VERSION_MADE_BY_0 0 | |
126 | # define C_VERSION_MADE_BY_1 1 | |
127 | # define C_VERSION_NEEDED_TO_EXTRACT_0 2 | |
128 | # define C_VERSION_NEEDED_TO_EXTRACT_1 3 | |
129 | # define C_GENERAL_PURPOSE_BIT_FLAG 4 | |
130 | # define C_COMPRESSION_METHOD 6 | |
131 | # define C_LAST_MOD_FILE_TIME 8 | |
132 | # define C_LAST_MOD_FILE_DATE 10 | |
133 | # define C_CRC32 12 | |
134 | # define C_COMPRESSED_SIZE 16 | |
135 | # define C_UNCOMPRESSED_SIZE 20 | |
136 | # define C_FILENAME_LENGTH 24 | |
137 | # define C_EXTRA_FIELD_LENGTH 26 | |
138 | # define C_FILE_COMMENT_LENGTH 28 | |
139 | # define C_DISK_NUMBER_START 30 | |
140 | # define C_INTERNAL_FILE_ATTRIBUTES 32 | |
141 | # define C_EXTERNAL_FILE_ATTRIBUTES 34 | |
142 | # define C_RELATIVE_OFFSET_LOCAL_HEADER 38 | |
143 | ||
144 | typedef uch ec_byte_rec[ ECREC_SIZE+4 ]; | |
145 | /* define SIGNATURE 0 space-holder only */ | |
146 | # define NUMBER_THIS_DISK 4 | |
147 | # define NUM_DISK_WITH_START_CENTRAL_DIR 6 | |
148 | # define NUM_ENTRIES_CENTRL_DIR_THS_DISK 8 | |
149 | # define TOTAL_ENTRIES_CENTRAL_DIR 10 | |
150 | # define SIZE_CENTRAL_DIRECTORY 12 | |
151 | # define OFFSET_START_CENTRAL_DIRECTORY 16 | |
152 | # define ZIPFILE_COMMENT_LENGTH 20 | |
153 | ||
154 | ||
155 | typedef struct local_file_header { /* LOCAL */ | |
156 | uch version_needed_to_extract[2]; | |
157 | ush general_purpose_bit_flag; | |
158 | ush compression_method; | |
159 | ush last_mod_file_time; | |
160 | ush last_mod_file_date; | |
161 | ulg crc32; | |
162 | ulg csize; | |
163 | ulg ucsize; | |
164 | ush filename_length; | |
165 | ush extra_field_length; | |
166 | } local_file_hdr; | |
167 | ||
168 | typedef struct central_directory_file_header { /* CENTRAL */ | |
169 | uch version_made_by[2]; | |
170 | uch version_needed_to_extract[2]; | |
171 | ush general_purpose_bit_flag; | |
172 | ush compression_method; | |
173 | ush last_mod_file_time; | |
174 | ush last_mod_file_date; | |
175 | ulg crc32; | |
176 | ulg csize; | |
177 | ulg ucsize; | |
178 | ush filename_length; | |
179 | ush extra_field_length; | |
180 | ush file_comment_length; | |
181 | ush disk_number_start; | |
182 | ush internal_file_attributes; | |
183 | ulg external_file_attributes; | |
184 | ulg relative_offset_local_header; | |
185 | } cdir_file_hdr; | |
186 | ||
187 | typedef struct end_central_dir_record { /* END CENTRAL */ | |
188 | ush number_this_disk; | |
189 | ush num_disk_with_start_central_dir; | |
190 | ush num_entries_centrl_dir_ths_disk; | |
191 | ush total_entries_central_dir; | |
192 | ulg size_central_directory; | |
193 | ulg offset_start_central_directory; | |
194 | ush zipfile_comment_length; | |
195 | } ecdir_rec; | |
196 | ||
197 | ||
198 | /************/ | |
199 | /* Macros */ | |
200 | /************/ | |
201 | ||
202 | #ifndef MAX | |
203 | # define MAX(a,b) ((a) > (b) ? (a) : (b)) | |
204 | #endif | |
205 | #ifndef MIN | |
206 | # define MIN(a,b) ((a) < (b) ? (a) : (b)) | |
207 | #endif | |
208 | ||
209 | ||
68ddcc2a | 210 | /***********************/ |
211 | /* Prototypes */ | |
212 | /***********************/ | |
213 | ||
6852521a | 214 | static ush makeword (const uch *); |
215 | static ulg makelong (const uch *); | |
216 | static long find_zip_file_start (int fd, long offset); | |
68ddcc2a | 217 | |
377029eb | 218 | /***********************/ |
219 | /* Function makeword() */ | |
220 | /***********************/ | |
221 | ||
2883a3ed | 222 | static ush makeword(const uch *b) |
377029eb | 223 | { |
224 | /* | |
225 | * Convert Intel style 'short' integer to non-Intel non-16-bit | |
226 | * host format. This routine also takes care of byte-ordering. | |
227 | */ | |
228 | return (ush)((b[1] << 8) | b[0]); | |
229 | } | |
230 | ||
231 | ||
232 | /***********************/ | |
233 | /* Function makelong() */ | |
234 | /***********************/ | |
235 | ||
83a070d0 | 236 | static ulg |
237 | makelong (const uch *sig) | |
377029eb | 238 | { |
239 | /* | |
240 | * Convert intel style 'long' variable to non-Intel non-16-bit | |
241 | * host format. This routine also takes care of byte-ordering. | |
242 | */ | |
243 | return (((ulg)sig[3]) << 24) | |
244 | + (((ulg)sig[2]) << 16) | |
245 | + (((ulg)sig[1]) << 8) | |
246 | + ((ulg)sig[0]); | |
247 | } | |
248 | ||
0136a00b | 249 | /* Examine file's header in zip file and return the offset of the |
250 | start of the actual data. Return -1 on error. OFFSET is the | |
251 | offset from the beginning of the zip file of the file's header. */ | |
252 | static long | |
2883a3ed | 253 | find_zip_file_start (int fd, long offset) |
0136a00b | 254 | { |
255 | int filename_length, extra_field_length; | |
256 | unsigned char buffer[LREC_SIZE + 4]; | |
257 | ||
258 | if (lseek (fd, offset, SEEK_SET) < 0) | |
259 | return -1; | |
260 | ||
261 | if (read (fd, buffer, LREC_SIZE + 4) != LREC_SIZE + 4) | |
262 | return -1; | |
263 | ||
8e452f9c | 264 | if (buffer[0] != 'P' || strncmp ((const char *) &buffer[1], LOCAL_HDR_SIG, 3)) |
0136a00b | 265 | return -1; |
266 | ||
267 | filename_length = makeword (&buffer[4 + L_FILENAME_LENGTH]); | |
268 | extra_field_length = makeword (&buffer[4 + L_EXTRA_FIELD_LENGTH]); | |
269 | ||
270 | return offset + (4 + LREC_SIZE) + filename_length + extra_field_length; | |
271 | } | |
272 | ||
377029eb | 273 | int |
2883a3ed | 274 | read_zip_archive (ZipFile *zipf) |
377029eb | 275 | { |
276 | int i; | |
277 | int dir_last_pad; | |
278 | char *dir_ptr; | |
279 | char buffer[100]; | |
280 | ||
281 | zipf->size = lseek (zipf->fd, 0L, SEEK_END); | |
282 | ||
283 | if (zipf->size < (ECREC_SIZE+4) || lseek (zipf->fd, (long)(-(ECREC_SIZE+4)), SEEK_CUR) <= 0) | |
284 | return -1; | |
285 | if (read (zipf->fd, buffer, ECREC_SIZE+4) != ECREC_SIZE+4) | |
286 | return -2; | |
d9e80e62 | 287 | if (buffer[0] != 'P' |
288 | || strncmp ((const char *) &buffer[1], END_CENTRAL_SIG, 3)) | |
289 | { | |
290 | /* We could not find the end-central-header signature, probably | |
291 | because a zipfile comment is present. Scan backwards until we | |
292 | find the signature. */ | |
293 | if (lseek (zipf->fd, (long)(-ECREC_SIZE), SEEK_END) <= 0) | |
294 | return -2; | |
295 | while (buffer[0] != 'P' | |
296 | || strncmp ((const char *) &buffer[1], END_CENTRAL_SIG, 3)) | |
297 | { | |
298 | if (lseek (zipf->fd, -5, SEEK_CUR) < 0) | |
299 | return -2; | |
300 | if (read (zipf->fd, buffer, 4) != 4) | |
301 | return -2; | |
302 | } | |
303 | if (read (zipf->fd, buffer + 4, ECREC_SIZE) != ECREC_SIZE) | |
304 | return -2; | |
305 | } | |
8e452f9c | 306 | zipf->count = makeword((const uch *) &buffer[TOTAL_ENTRIES_CENTRAL_DIR]); |
307 | zipf->dir_size = makelong((const uch *) &buffer[SIZE_CENTRAL_DIRECTORY]); | |
377029eb | 308 | /* Allocate 1 more to allow appending '\0' to last filename. */ |
4c36ffe6 | 309 | zipf->central_directory = XNEWVEC (char, zipf->dir_size + 1); |
377029eb | 310 | if (lseek (zipf->fd, -(zipf->dir_size+ECREC_SIZE+4), SEEK_CUR) < 0) |
311 | return -2; | |
312 | if (read (zipf->fd, zipf->central_directory, zipf->dir_size) < 0) | |
313 | return -2; | |
314 | ||
315 | #ifdef TEST | |
316 | printf ("number_this_disk = %d\n", makeword(&buffer[NUMBER_THIS_DISK])); | |
317 | printf ("num_disk_with_start_central_dir = %d\n", makeword(&buffer[NUM_DISK_WITH_START_CENTRAL_DIR])); | |
318 | ||
319 | printf ("num_entries_centrl_dir_ths_disk = %d\n", | |
320 | makeword(&buffer[NUM_ENTRIES_CENTRL_DIR_THS_DISK])); | |
321 | printf ("total_entries_central_dir = %d\n", | |
322 | makeword(&buffer[TOTAL_ENTRIES_CENTRAL_DIR])); | |
323 | printf ("size_central_directory = %d\n", | |
8e452f9c | 324 | makelong((const uch *) &buffer[SIZE_CENTRAL_DIRECTORY])); |
377029eb | 325 | printf ("offset_start_central_directory = %d\n", |
8e452f9c | 326 | makelong((const uch *) &buffer[OFFSET_START_CENTRAL_DIRECTORY])); |
377029eb | 327 | printf ("zipfile_comment_length = %d\n", |
328 | makeword(&buffer[ZIPFILE_COMMENT_LENGTH])); | |
329 | #endif | |
330 | ||
331 | dir_last_pad = 0; | |
332 | dir_ptr = zipf->central_directory; | |
333 | for (i = 0; i < zipf->count; i++) | |
334 | { | |
335 | ZipDirectory *zipd = (ZipDirectory*)(dir_ptr + dir_last_pad); | |
fad14b72 | 336 | int compression_method = (int) dir_ptr[4+C_COMPRESSION_METHOD]; |
8e452f9c | 337 | long size = makelong ((const uch *) &dir_ptr[4+C_COMPRESSED_SIZE]); |
338 | long uncompressed_size = makelong ((const uch *) &dir_ptr[4+C_UNCOMPRESSED_SIZE]); | |
339 | long filename_length = makeword ((const uch *) &dir_ptr[4+C_FILENAME_LENGTH]); | |
340 | long extra_field_length = makeword ((const uch *) &dir_ptr[4+C_EXTRA_FIELD_LENGTH]); | |
341 | long file_offset = makelong ((const uch *) &dir_ptr[4+C_RELATIVE_OFFSET_LOCAL_HEADER]); | |
377029eb | 342 | int unpadded_direntry_length; |
343 | if ((dir_ptr-zipf->central_directory)+filename_length+CREC_SIZE+4>zipf->dir_size) | |
344 | return -1; | |
345 | ||
346 | zipd->filename_length = filename_length; | |
fad14b72 | 347 | zipd->compression_method = compression_method; |
348 | zipd->size = size; | |
349 | zipd->uncompressed_size = uncompressed_size; | |
de9c2bdc | 350 | zipd->zipf = zipf; |
377029eb | 351 | #ifdef __GNUC__ |
352 | #define DIR_ALIGN __alignof__(ZipDirectory) | |
353 | #else | |
354 | #define DIR_ALIGN sizeof(long) | |
355 | #endif | |
ead85e11 | 356 | zipd->filestart = find_zip_file_start (zipf->fd, file_offset); |
377029eb | 357 | zipd->filename_offset = CREC_SIZE+4 - dir_last_pad; |
358 | unpadded_direntry_length | |
359 | = zipd->filename_offset + zipd->filename_length + extra_field_length; | |
360 | zipd->direntry_size = | |
361 | ((unpadded_direntry_length + DIR_ALIGN) / DIR_ALIGN) * DIR_ALIGN; | |
362 | dir_last_pad = zipd->direntry_size - unpadded_direntry_length; | |
363 | dir_ptr = (char*)zipd + unpadded_direntry_length; | |
364 | *dir_ptr = '\0'; | |
365 | } | |
366 | return 0; | |
367 | } | |
368 | ||
369 | #ifdef TEST | |
2883a3ed | 370 | main (void) |
377029eb | 371 | { |
372 | ZipFile zipf[1]; | |
373 | ZipDirectory *zipd; | |
374 | int i; | |
375 | ||
376 | zipf->fd = 0; | |
377 | ||
378 | i = read_zip_archive (zipf); | |
379 | if (i) | |
380 | { | |
381 | fprintf (stderr, "Bad zip file.\n"); | |
382 | exit (i); | |
383 | } | |
384 | ||
385 | zipd = (ZipDirectory*) zipf->central_directory; | |
386 | for (i = 0; i < zipf->count; i++, zipd = ZIPDIR_NEXT (zipd)) | |
387 | { | |
388 | printf ("%d: size:%d, name(#%d)%s, offset:%d\n", | |
389 | i, zipd->size, zipd->filename_length, | |
390 | ZIPDIR_FILENAME (zipd), | |
391 | zipd->filestart); | |
392 | } | |
393 | } | |
394 | #endif |