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