void csArchive::ReadZipEntries (FILE *infile) { size_t cur_offs, new_offs; char buff[1024]; ZIP_central_directory_file_header cdfh; ZIP_local_file_header lfh; cur_offs = 0; while ((fread (buff, 1, sizeof (hdr_local), infile) >= sizeof (hdr_local)) && (memcmp (buff, hdr_local, sizeof (hdr_local)) == 0) && (ReadLFH (lfh, infile))) { new_offs = cur_offs + sizeof (hdr_local) + ZIP_LOCAL_FILE_HEADER_SIZE + lfh.filename_length + lfh.extra_field_length + lfh.csize; if ((lfh.filename_length > sizeof (buff)) || (fread (buff, 1, lfh.filename_length, infile) < lfh.filename_length)) return; /* Broken zipfile? */ buff[lfh.filename_length] = 0; if ((buff[lfh.filename_length - 1] != '/') && (buff[lfh.filename_length - 1] != PATH_SEPARATOR)) { /* Partialy convert lfh to cdfh */ memset (&cdfh, 0, sizeof (cdfh)); cdfh.version_needed_to_extract[0] = lfh.version_needed_to_extract[0]; cdfh.version_needed_to_extract[1] = lfh.version_needed_to_extract[1]; cdfh.general_purpose_bit_flag = lfh.general_purpose_bit_flag; cdfh.compression_method = lfh.compression_method; cdfh.last_mod_file_time = lfh.last_mod_file_time; cdfh.last_mod_file_date = lfh.last_mod_file_date; cdfh.crc32 = lfh.crc32; cdfh.csize = lfh.csize; cdfh.ucsize = lfh.ucsize; cdfh.relative_offset_local_header = cur_offs; ArchiveEntry *curentry = InsertEntry (buff, cdfh); if (!curentry->ReadExtraField (infile, lfh.extra_field_length)) return; /* Broken zipfile */ } /* endif */ if (fseek (infile, cur_offs = new_offs, SEEK_SET)) return; /* Broken zipfile */ } /* endwhile */ }
void csArchive::ReadZipDirectory (FILE *infile) { ZIP_end_central_dir_record ecdr; ZIP_central_directory_file_header cdfh; char buff[1024]; /* Read ZIPfile from end in 1K chunks */ size_t cur_offs, min_offs, central_directory_offset; size_t step = ZIP_END_CENTRAL_DIR_RECORD_SIZE + sizeof (hdr_endcentral); if (!infile) return; /* File not open */ if (fseek (infile, 0, SEEK_END)) return; /* Seek error */ if ((long) (cur_offs = ftell (infile)) == -1) return; /* Can't get file position */ if (cur_offs >= (65535 + ZIP_END_CENTRAL_DIR_RECORD_SIZE + sizeof (hdr_endcentral))) min_offs = cur_offs - (65535 + ZIP_END_CENTRAL_DIR_RECORD_SIZE + sizeof (hdr_endcentral)); else min_offs = 0; /* Try to find ZIPfile central directory structure */ /* For this we have to search from end of file the signature "PK" */ /* after which follows a two-byte END_CENTRAL_SIG */ while (cur_offs > min_offs) { UInt search_pos; if (cur_offs >= sizeof (buff) - step) cur_offs -= sizeof (buff) - step; else cur_offs = 0; fseek (infile, cur_offs, SEEK_SET); search_pos = fread (buff, 1, sizeof (buff), infile); if (search_pos >= step) { register char *search_ptr; for (search_ptr = &buff[search_pos - step]; search_ptr > buff; search_ptr--) if ((*search_ptr == 'P') && (memcmp (search_ptr, hdr_endcentral, sizeof (hdr_endcentral)) == 0)) { /* Central directory structure found */ central_directory_offset = cur_offs + (ULong) search_ptr - (ULong)buff; LoadECDR (ecdr, &search_ptr[sizeof (hdr_endcentral)]); if (fseek (infile, central_directory_offset + sizeof (hdr_endcentral) + ZIP_END_CENTRAL_DIR_RECORD_SIZE, SEEK_SET) || !ReadArchiveComment (infile, ecdr.zipfile_comment_length) || fseek (infile, ecdr.offset_start_central_directory, SEEK_SET)) goto rebuild_cdr; /* Broken central directory */ /* Now read central directory structure */ for (;;) { if ((fread (buff, 1, sizeof (hdr_central), infile) < sizeof (hdr_central)) || (memcmp (buff, hdr_central, sizeof (hdr_central)) != 0)) { if (dir.Length ()) return; /* Finished reading central directory */ else goto rebuild_cdr; /* Broken central directory */ } if ((!ReadCDFH (cdfh, infile)) || (cdfh.filename_length > sizeof (buff)) || (fread (buff, 1, cdfh.filename_length, infile) < cdfh.filename_length)) return; /* Broken zipfile? */ buff[cdfh.filename_length] = 0; if ((buff[cdfh.filename_length - 1] == PATH_SEPARATOR) || (buff[cdfh.filename_length - 1] == PATH_SEPARATOR_2)) { if (fseek (infile, cdfh.extra_field_length + cdfh.file_comment_length, SEEK_CUR)) return; /* Broken zipfile? */ continue; } /* endif */ ArchiveEntry *curentry = InsertEntry (buff, cdfh); if (!curentry->ReadExtraField (infile, cdfh.extra_field_length) || !curentry->ReadFileComment (infile, cdfh.file_comment_length)) return; /* Broken zipfile? */ } /* endfor */ } /* endif */ } /* endif */ } /* endwhile */ rebuild_cdr: /* If we are here, we did not succeeded to read central directory */ /* If so, we have to rebuild it by reading each ZIPfile member separately */ if (fseek (infile, 0, SEEK_SET)) return; ReadZipEntries (infile); }