private void readCentralDir() throws IOException {
  long scanOffset=raf.length() - ENDHDR;
  if (scanOffset < 0) {
    throw new ZipException("File too short to be a zip file: " + raf.length());
  }
  raf.seek(0);
  final int headerMagic=Integer.reverseBytes(raf.readInt());
  if (headerMagic != LOCSIG) {
    throw new ZipException("Not a zip archive");
  }
  long stopOffset=scanOffset - 65536;
  if (stopOffset < 0) {
    stopOffset=0;
  }
  while (true) {
    raf.seek(scanOffset);
    if (Integer.reverseBytes(raf.readInt()) == ENDSIG) {
      break;
    }
    scanOffset--;
    if (scanOffset < stopOffset) {
      throw new ZipException("End Of Central Directory signature not found");
    }
  }
  byte[] eocd=new byte[ENDHDR - 4];
  raf.readFully(eocd);
  BufferIterator it=HeapBufferIterator.iterator(eocd,0,eocd.length,ByteOrder.LITTLE_ENDIAN);
  int diskNumber=it.readShort() & 0xffff;
  int diskWithCentralDir=it.readShort() & 0xffff;
  int numEntries=it.readShort() & 0xffff;
  int totalNumEntries=it.readShort() & 0xffff;
  it.skip(4);
  long centralDirOffset=((long)it.readInt()) & 0xffffffffL;
  int commentLength=it.readShort() & 0xffff;
  if (numEntries != totalNumEntries || diskNumber != 0 || diskWithCentralDir != 0) {
    throw new ZipException("Spanned archives not supported");
  }
  if (commentLength > 0) {
    byte[] commentBytes=new byte[commentLength];
    raf.readFully(commentBytes);
    comment=new String(commentBytes,0,commentBytes.length,StandardCharsets.UTF_8);
  }
  RAFStream rafStream=new RAFStream(raf,centralDirOffset);
  BufferedInputStream bufferedStream=new BufferedInputStream(rafStream,4096);
  byte[] hdrBuf=new byte[CENHDR];
  for (int i=0; i < numEntries; ++i) {
    TinkerZipEntry newEntry=new TinkerZipEntry(hdrBuf,bufferedStream,StandardCharsets.UTF_8,(false));
    if (newEntry.localHeaderRelOffset >= centralDirOffset) {
      throw new ZipException("Local file header offset is after central directory");
    }
    String entryName=newEntry.getName();
    if (entries.put(entryName,newEntry) != null) {
      throw new ZipException("Duplicate entry name: " + entryName);
    }
  }
}

private void readCentralDir ( ) throws IOException { long scanOffset = raf . length ( ) - ENDHDR ; if ( scanOffset < 0 ) { throw new ZipException ( "File too short to be a zip file: " + raf . length ( ) ) ; } raf . seek ( 0 ) ; final int headerMagic = Integer . reverseBytes ( raf . readInt ( ) ) ; if ( headerMagic != LOCSIG ) { throw new ZipException ( "Not a zip archive" ) ; } long stopOffset = scanOffset - 65536 ; if ( stopOffset < 0 ) { stopOffset = 0 ; } while ( true ) { raf . seek ( scanOffset ) ; if ( Integer . reverseBytes ( raf . readInt ( ) ) == ENDSIG ) { break ; } scanOffset -- ; if ( scanOffset < stopOffset ) { throw new ZipException ( "End Of Central Directory signature not found" ) ; } } byte [ ] eocd = new byte [ ENDHDR - 4 ] ; raf . readFully ( eocd ) ; BufferIterator it = HeapBufferIterator . iterator ( eocd , 0 , eocd . length , ByteOrder . LITTLE_ENDIAN ) ; int diskNumber = it . readShort ( ) & 0xffff ; int diskWithCentralDir = it . readShort ( ) & 0xffff ; int numEntries = it . readShort ( ) & 0xffff ; int totalNumEntries = it . readShort ( ) & 0xffff ; it . skip ( 4 ) ; long centralDirOffset = ( ( long ) it . readInt ( ) ) & 0xffffffffL ; int commentLength = it . readShort ( ) & 0xffff ; if ( numEntries != totalNumEntries || diskNumber != 0 || diskWithCentralDir != 0 ) { throw new ZipException ( "Spanned archives not supported" ) ; } if ( commentLength > 0 ) { byte [ ] commentBytes = new byte [ commentLength ] ; raf . readFully ( commentBytes ) ; comment = new String ( commentBytes , 0 , commentBytes . length , StandardCharsets . UTF_8 ) ; } RAFStream rafStream = new RAFStream ( raf , centralDirOffset ) ; BufferedInputStream bufferedStream = new BufferedInputStream ( rafStream , 4096 ) ; byte [ ] hdrBuf = new byte [ CENHDR ] ; for ( int i = 0 ; i < numEntries ; ++ i ) { TinkerZipEntry newEntry = new TinkerZipEntry ( hdrBuf , bufferedStream , StandardCharsets . UTF_8 , ( false ) ) ; if ( newEntry . localHeaderRelOffset >= centralDirOffset ) { throw new ZipException ( "Local file header offset is after central directory" ) ; } String entryName = newEntry . getName ( ) ; if ( entries . put ( entryName , newEntry ) != null ) { throw new ZipException ( "Duplicate entry name: " + entryName ) ; } } }
find the central directory and read the contents . < p > the central directory can be followed by a variable - length comment field , so we have to scan through it backwards . the comment is at most 64k , plus we have 18 bytes for the end - of - central - dir stuff itself , plus apparently sometimes people throw random junk on the end just for the fun of it . < p > this is all a little wobbly . if the wrong value ends up in the eocd area , we ' re hosed . this appears to be the way that everybody handles it though , so we ' re in good company if this fails .
