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