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