// $Id: zip.cpp,v 1.3 1999/01/25 20:00:32 shields Exp $ copyright notice #include "config.h" #include <assert.h> #include <iostream.h> #include <string.h> #include "control.h" #include "zip.h" #include "symbol.h" //************************************************************************************************ // // The ZipFile methods follow // //************************************************************************************************ #ifdef UNIX_FILE_SYSTEM int (*ZipFile::uncompress_file[10]) (FILE *, char *, long) = { UncompressFile0, UncompressFile1, UncompressFile2, UncompressFile3, UncompressFile4, UncompressFile5, UncompressFile6, UncompressFile7, UncompressFile8, UncompressFile9 }; inline u1 ZipFile::GetU1() { return getc(zipfile); } inline void ZipFile::Skip(u4 length) { for (u4 i = 0; i < length; i++) getc(zipfile); } #elif defined(WIN32_FILE_SYSTEM) int (*ZipFile::uncompress_file[10]) (char *, char *, long) = { UncompressFile0, UncompressFile1, UncompressFile2, UncompressFile3, UncompressFile4, UncompressFile5, UncompressFile6, UncompressFile7, UncompressFile8, UncompressFile9 }; inline u1 ZipFile::GetU1() { return *file_buffer++; } inline void ZipFile::Skip(u4 length) { file_buffer += length; } #endif inline u2 ZipFile::GetU2() { u4 val = GetU1(); val |= (((u4) GetU1()) << 8); return val; } inline u4 ZipFile::GetU4() { u4 val = GetU1(); val |= (((u4) GetU1()) << 8); val |= (((u4) GetU1()) << 16); val |= (((u4) GetU1()) << 24); return val; } ZipFile::ZipFile(FileSymbol *file_symbol) : buffer(NULL) { Zip *zip = file_symbol -> Zipfile(); #ifdef UNIX_FILE_SYSTEM zipfile = zip -> zipfile; int rc = fseek(zipfile, file_symbol -> offset, SEEK_SET); assert(rc == 0); #elif defined(WIN32_FILE_SYSTEM) file_buffer = &zip -> zipbuffer[file_symbol -> offset]; #endif Skip(8); // u4 magic = GetU4(); // u2 version_needed_to_extract = GetU2(); // u2 general_purpose_bits = GetU2(); u2 compression_method = GetU2(); Skip(16); // u2 time = GetU2(); // u2 date = GetU2(); // u4 crc32 = GetU4(); // u4 compressed_size = GetU4(); // u4 uncompressed_size = GetU4(); u2 filename_length = GetU2(); u2 extra_field_length = GetU2(); Skip(filename_length + extra_field_length); #ifdef UNIX_FILE_SYSTEM this -> buffer = new char[file_symbol -> uncompressed_size]; if (! uncompress_file[compression_method < 9 ? compression_method : 9](zipfile, this -> buffer, file_symbol -> uncompressed_size)) { delete [] this -> buffer; this -> buffer = NULL; } #elif defined(WIN32_FILE_SYSTEM) if (compression_method > 0) { this -> buffer = new char[file_symbol -> uncompressed_size]; if (! uncompress_file[compression_method < 9 ? compression_method : 9](file_buffer, this -> buffer, file_symbol -> uncompressed_size)) { delete [] this -> buffer; this -> buffer = NULL; this -> file_buffer = NULL; } } #endif return; } ZipFile::~ZipFile() { delete [] buffer; } //************************************************************************************************ // // The Zip methods follow: // //************************************************************************************************ inline u1 Zip::GetU1() { return *buffer_ptr++; } inline u2 Zip::GetU2() { u4 val = GetU1(); val |= (((u4) GetU1()) << 8); return val; } inline u4 Zip::GetU4() { u4 val = GetU1(); val |= (((u4) GetU1()) << 8); val |= (((u4) GetU1()) << 16); val |= (((u4) GetU1()) << 24); return val; } inline void Zip::Skip(u4 length) { buffer_ptr += length; } inline DirectorySymbol *Zip::ProcessSubdirectoryEntries(DirectorySymbol *directory_symbol, char *name, int name_length) { wchar_t *directory_name = new wchar_t[name_length]; for (int start = 0, end; start < name_length; start = end + 1) { end = start; for (int i = 0; end < name_length && name[end] != U_SLASH; i++, end++) directory_name[i] = name[end]; NameSymbol *name_symbol = control.FindOrInsertName(directory_name, end - start); DirectorySymbol *subdirectory_symbol = directory_symbol -> FindDirectorySymbol(name_symbol); if (! subdirectory_symbol) subdirectory_symbol = directory_symbol -> InsertDirectorySymbol(name_symbol); directory_symbol = subdirectory_symbol; } delete [] directory_name; return directory_symbol; } inline NameSymbol *Zip::ProcessFilename(char *name, int name_length) { wchar_t *input_filename = new wchar_t[name_length]; for (int i = 0; i < name_length; i++) input_filename[i] = name[i]; NameSymbol *name_symbol = control.FindOrInsertName(input_filename, name_length); delete [] input_filename; return name_symbol; } inline void Zip::ProcessDirectoryEntry(DirectorySymbol *directory_symbol) { Skip(8); // u2 version_made_by = GetU2(); // u2 version_needed_to_extract = GetU2(); // u2 general_purpose_bits = GetU2(); // u2 compression_method = GetU2(); u2 last_mod_file_time = GetU2(); u2 last_mod_file_date = GetU2(); Skip(4); // u4 crc32 = GetU4(); Skip(4); // u4 compressed_size = GetU4(); u4 uncompressed_size = GetU4(); u2 file_name_length = GetU2(); u2 extra_field_length = GetU2(); u2 file_comment_length = GetU2(); Skip(8); // u2 disk_number_start = GetU2(); // u2 internal_file_attributes = GetU2(); // u4 external_file_attributes = GetU4(); u4 relative_offset_of_local_header = GetU4(); u4 date_time = ((u4) last_mod_file_date) << 16 | last_mod_file_time; char *name = buffer_ptr; Skip(file_name_length + extra_field_length + file_comment_length); // // Note that we need to process all subdirectory entries that appear in the zip file, and not // just the ones that contain java and class files. Recall that in java the dot notation is // used in specifying a package. Therefore, in processing a qualified-name that represents // a package, we need to recognize each name as a subpackage. E.g., when processing // "java.lang", we need to recognize "java" as a package before looking for "lang"... // if (name[file_name_length - 1] == U_SLASH) ProcessSubdirectoryEntries(directory_symbol, name, file_name_length - 1); // -1 to remove last '/' else { bool java_file = (file_name_length >= FileSymbol::java_suffix_length && FileSymbol::IsJavaSuffix(&name[file_name_length - FileSymbol::java_suffix_length])), class_file = (file_name_length >= FileSymbol::class_suffix_length && FileSymbol::IsClassSuffix(&name[file_name_length - FileSymbol::class_suffix_length])); if (java_file || class_file) { int name_length = file_name_length - (java_file ? FileSymbol::java_suffix_length : FileSymbol::class_suffix_length); int i; for (i = name_length - 1; i >= 0 && name[i] != U_SLASH; i--) ; if (i > 0) // directory specified? directory_symbol = ProcessSubdirectoryEntries(directory_symbol, name, i); NameSymbol *name_symbol = ProcessFilename(&name[i + 1], name_length - (i + 1)); // // Search for a file of that name in the directory. If one is not found, then insert ... // Otherwise, either a class file of that name was previously processed and now we found // a java file with the same name or vice-versa... In that case keep (or replace with ) the // the file with the most recent date stamp. // FileSymbol *file_symbol = directory_symbol -> FindFileSymbol(name_symbol); if (! file_symbol) { file_symbol = directory_symbol -> InsertFileSymbol(name_symbol); file_symbol -> directory_symbol = directory_symbol; if (java_file) file_symbol -> SetJava(); else file_symbol -> SetClassOnly(); file_symbol -> uncompressed_size = uncompressed_size; file_symbol -> offset = relative_offset_of_local_header; file_symbol -> date_time = date_time; } else if (file_symbol -> date_time < date_time) { if (java_file) file_symbol -> SetJava(); else file_symbol -> SetClass(); file_symbol -> uncompressed_size = uncompressed_size; file_symbol -> offset = relative_offset_of_local_header; file_symbol -> date_time = date_time; } } } return; } Zip::Zip(Control &control_, char *zipfile_name) : control(control_), zipbuffer(NULL), magic(0) { #ifdef UNIX_FILE_SYSTEM zipfile = ::SystemFopen(zipfile_name, "rb"); if (zipfile) { int rc = fseek(zipfile, -22, SEEK_END); if (rc == 0); { zipbuffer = new char[22]; buffer_ptr = zipbuffer; fread(buffer_ptr, sizeof(char), 22, zipfile); magic = GetU4(); } } #elif defined(WIN32_FILE_SYSTEM) zipfile = CreateFile(zipfile_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); if (zipfile != INVALID_HANDLE_VALUE) { mapfile = CreateFileMapping(zipfile, NULL, PAGE_READONLY, 0, 0, NULL); zipbuffer = (mapfile == INVALID_HANDLE_VALUE ? NULL : (char *) MapViewOfFile(mapfile, FILE_MAP_READ, 0, 0, 0)); if (zipbuffer) { buffer_ptr = &zipbuffer[GetFileSize(zipfile, NULL) - 22]; magic = GetU4(); } } #endif return; } Zip::~Zip() { #ifdef UNIX_FILE_SYSTEM delete [] zipbuffer; if (zipfile) fclose(zipfile); #elif defined(WIN32_FILE_SYSTEM) if (zipfile != INVALID_HANDLE_VALUE) { if (mapfile != INVALID_HANDLE_VALUE) { if (zipbuffer) UnmapViewOfFile(zipbuffer); CloseHandle(mapfile); } CloseHandle(zipfile); } #endif } void Zip::ReadDirectory(DirectorySymbol *directory_symbol) { if (IsValid()) { Skip(8); // u2 number_of_this_disk = GetU2(); // u2 number_of_the_disk_with_the_star = GetU2(); // u2 start_of_the_central_directory = GetU2(); // u2 total_number_of_entries_in_the_ = GetU2(); u4 central_directory_size = GetU4(); #ifdef UNIX_FILE_SYSTEM int rc = fseek(zipfile, -((int) central_directory_size + 22), SEEK_END); assert(rc == 0); delete [] zipbuffer; zipbuffer = new char[central_directory_size + 22]; buffer_ptr = zipbuffer; fread(buffer_ptr, sizeof(char), central_directory_size + 22, zipfile); #elif defined(WIN32_FILE_SYSTEM) buffer_ptr -= (central_directory_size + 16); #endif for (magic = GetU4(); magic == 0x02014b50; magic = GetU4()) ProcessDirectoryEntry(directory_symbol); assert(IsValid()); // magic == 0x06054b50 } return; }