+ }
+
+ private static final int CFH_LEN =
+ /* version made by */2
+ /* version needed to extract */+ 2
+ /* general purpose bit flag */+ 2
+ /* compression method */+ 2
+ /* last mod file time */+ 2
+ /* last mod file date */+ 2
+ /* crc-32 */+ 4
+ /* compressed size */+ 4
+ /* uncompressed size */+ 4
+ /* filename length */+ 2
+ /* extra field length */+ 2
+ /* file comment length */+ 2
+ /* disk number start */+ 2
+ /* internal file attributes */+ 2
+ /* external file attributes */+ 4
+ /* relative offset of local header */+ 4;
+
+ /**
+ * Reads the central directory of the given archive and populates the internal
+ * tables with ZipEntry instances.
+ *
+ * <p>
+ * The ZipEntrys will know all data that can be obtained from the central
+ * directory alone, but not the data that requires the local file header or
+ * additional data to be read.
+ * </p>
+ */
+ private void populateFromCentralDirectory() throws IOException {
+ positionAtCentralDirectory();
+
+ byte[] cfh = new byte[CFH_LEN];
+
+ byte[] signatureBytes = new byte[4];
+ archive.readFully(signatureBytes);
+ long sig = ZipLong.getValue(signatureBytes);
+ final long cfhSig = ZipLong.getValue(ZipOutputStream.CFH_SIG);
+ while (sig == cfhSig) {
+ archive.readFully(cfh);
+ int off = 0;
+ ZipEntry ze = new ZipEntry();
+
+ int versionMadeBy = ZipShort.getValue(cfh, off);
+ off += 2;
+ ze.setPlatform((versionMadeBy >> 8) & 0x0F);
+
+ off += 4; // skip version info and general purpose byte
+
+ ze.setMethod(ZipShort.getValue(cfh, off));
+ off += 2;
+
+ // FIXME this is actually not very cpu cycles friendly as we are
+ // converting from
+ // dos to java while the underlying Sun implementation will convert
+ // from java to dos time for internal storage...
+ long time = dosToJavaTime(ZipLong.getValue(cfh, off));
+ ze.setTime(time);
+ off += 4;
+
+ ze.setCrc(ZipLong.getValue(cfh, off));
+ off += 4;
+
+ ze.setCompressedSize(ZipLong.getValue(cfh, off));
+ off += 4;
+
+ ze.setSize(ZipLong.getValue(cfh, off));
+ off += 4;
+
+ int fileNameLen = ZipShort.getValue(cfh, off);
+ off += 2;
+
+ int extraLen = ZipShort.getValue(cfh, off);
+ off += 2;
+
+ int commentLen = ZipShort.getValue(cfh, off);
+ off += 2;
+
+ off += 2; // disk number
+
+ ze.setInternalAttributes(ZipShort.getValue(cfh, off));
+ off += 2;
+
+ ze.setExternalAttributes(ZipLong.getValue(cfh, off));
+ off += 4;
+
+ byte[] fileName = new byte[fileNameLen];
+ archive.readFully(fileName);
+ ze.setName(getString(fileName));
+
+ // LFH offset,
+ OffsetEntry offset = new OffsetEntry();
+ offset.headerOffset = ZipLong.getValue(cfh, off);
+ // data offset will be filled later
+ entries.put(ze, offset);
+
+ nameMap.put(ze.getName(), ze);
+
+ archive.skipBytes(extraLen);
+
+ byte[] comment = new byte[commentLen];
+ archive.readFully(comment);
+ ze.setComment(getString(comment));
+
+ archive.readFully(signatureBytes);
+ sig = ZipLong.getValue(signatureBytes);