/** * Create a new {@link CentralDirectoryEndRecord} instance from the specified * {@link RandomAccessData}, searching backwards from the end until a valid block is * located. * @param data the source data * @throws IOException in case of I/O errors */ CentralDirectoryEndRecord(RandomAccessData data) throws IOException { this.block = createBlockFromEndOfData(data, READ_BLOCK_SIZE); this.size = MINIMUM_SIZE; this.offset = this.block.length - this.size; while (!isValid()) { this.size++; if (this.size > this.block.length) { if (this.size >= MAXIMUM_SIZE || this.size > data.getSize()) { throw new IOException("Unable to find ZIP central directory " + "records after reading " + this.size + " bytes"); } this.block = createBlockFromEndOfData(data, this.size + READ_BLOCK_SIZE); } this.offset = this.block.length - this.size; } }
@Override public void visitStart(CentralDirectoryEndRecord endRecord, RandomAccessData centralDirectoryData) { int maxSize = endRecord.getNumberOfRecords(); this.centralDirectoryData = centralDirectoryData; this.hashCodes = new int[maxSize]; this.centralDirectoryOffsets = new int[maxSize]; this.positions = new int[maxSize]; }
/** * Parse the source data, triggering {@link CentralDirectoryVisitor visitors}. * @param data the source data * @param skipPrefixBytes if prefix bytes should be skipped * @return the actual archive data without any prefix bytes * @throws IOException on error */ public RandomAccessData parse(RandomAccessData data, boolean skipPrefixBytes) throws IOException { CentralDirectoryEndRecord endRecord = new CentralDirectoryEndRecord(data); if (skipPrefixBytes) { data = getArchiveData(endRecord, data); } RandomAccessData centralDirectoryData = endRecord.getCentralDirectory(data); visitStart(endRecord, centralDirectoryData); parseEntries(endRecord, centralDirectoryData); visitEnd(); return data; }
private RandomAccessData getArchiveData(CentralDirectoryEndRecord endRecord, RandomAccessData data) { long offset = endRecord.getStartOfArchive(data); if (offset == 0) { return data; } return data.getSubsection(offset, data.getSize() - offset); }
private void parseEntries(CentralDirectoryEndRecord endRecord, RandomAccessData centralDirectoryData) throws IOException { byte[] bytes = centralDirectoryData.read(0, centralDirectoryData.getSize()); CentralDirectoryFileHeader fileHeader = new CentralDirectoryFileHeader(); int dataOffset = 0; for (int i = 0; i < endRecord.getNumberOfRecords(); i++) { fileHeader.load(bytes, dataOffset, null, 0, null); visitFileHeader(dataOffset, fileHeader); dataOffset += CENTRAL_DIRECTORY_HEADER_BASE_SIZE + fileHeader.getName().length() + fileHeader.getComment().length() + fileHeader.getExtra().length; } }