@@ -36,62 +36,75 @@ public void read(ZipArchive zip, ByteData data) throws IOException {
3636 long endOfCentralDirectoryOffset = ByteDataUtil .lastIndexOf (data , ZipPatterns .END_OF_CENTRAL_DIRECTORY );
3737 if (endOfCentralDirectoryOffset < 0L )
3838 throw new IOException ("No Central-Directory-File-Header found!" );
39+ // Read end header
40+ EndOfCentralDirectory end = new EndOfCentralDirectory ();
41+ end .read (data , endOfCentralDirectoryOffset );
42+ zip .getParts ().add (end );
43+ // Read central directories
44+ long len = data .length ();
45+ long centralDirectoryOffset = len - ZipPatterns .CENTRAL_DIRECTORY_FILE_HEADER .length ;
46+ while (centralDirectoryOffset > 0L ) {
47+ centralDirectoryOffset = ByteDataUtil .lastIndexOf (data , centralDirectoryOffset - 1L , ZipPatterns .CENTRAL_DIRECTORY_FILE_HEADER );
48+ if (centralDirectoryOffset >= 0L ) {
49+ CentralDirectoryFileHeader directory = new CentralDirectoryFileHeader ();
50+ directory .read (data , centralDirectoryOffset );
51+ zip .getParts ().add (directory );
52+ }
53+ }
3954 // Determine base offset for computing file header locations with.
4055 // - If there is a preceding block of another zip, start with that.
41- long jvmBaseOffset ;
56+ long jvmBaseFileOffset ;
4257 long precedingEndOfCentralDirectory = ByteDataUtil .lastIndexOf (data , endOfCentralDirectoryOffset - 1 , ZipPatterns .END_OF_CENTRAL_DIRECTORY );
4358 if (precedingEndOfCentralDirectory == endOfCentralDirectoryOffset ) {
4459 // The prior end part match is target end part, so we can't use it as a base offset.
45- jvmBaseOffset = 0L ;
60+ jvmBaseFileOffset = 0L ;
4661 } else if (precedingEndOfCentralDirectory == -1L ) {
4762 // There was no match for a prior end part. We will seek forwards until finding a *VALID* PK starting header.
48- jvmBaseOffset = ByteDataUtil .indexOf (data , ZipPatterns .PK );
49- while (jvmBaseOffset >= 0L ) {
63+ jvmBaseFileOffset = ByteDataUtil .indexOf (data , ZipPatterns .PK );
64+ while (jvmBaseFileOffset >= 0L ) {
5065 // Check that the PK discovered represents a valid zip part
5166 try {
52- if (ByteDataUtil .startsWith (data , jvmBaseOffset , ZipPatterns .LOCAL_FILE_HEADER ))
53- new LocalFileHeader ().read (data , jvmBaseOffset );
54- else if (ByteDataUtil .startsWith (data , jvmBaseOffset , ZipPatterns .CENTRAL_DIRECTORY_FILE_HEADER ))
55- new CentralDirectoryFileHeader ().read (data , jvmBaseOffset );
67+ if (ByteDataUtil .startsWith (data , jvmBaseFileOffset , ZipPatterns .LOCAL_FILE_HEADER ))
68+ new LocalFileHeader ().read (data , jvmBaseFileOffset );
69+ else if (ByteDataUtil .startsWith (data , jvmBaseFileOffset , ZipPatterns .CENTRAL_DIRECTORY_FILE_HEADER ))
70+ new CentralDirectoryFileHeader ().read (data , jvmBaseFileOffset );
71+ else
72+ throw new IllegalStateException ("No match for LocalFileHeader/CentralDirectoryFileHeader" );
5673 // Valid, we're good to go
5774 break ;
5875 } catch (Exception ex ) {
5976 // Invalid, seek forward
60- jvmBaseOffset = ByteDataUtil .indexOf (data , jvmBaseOffset + 1L , ZipPatterns .PK );
77+ jvmBaseFileOffset = ByteDataUtil .indexOf (data , jvmBaseFileOffset + 1L , ZipPatterns .PK );
6178 }
6279 }
6380 } else {
81+ // TODO: Double check 'precedingEndOfCentralDirectory' points to a EndOfCentralDirectory that isn't bogus
82+ // like some shit defined as a fake comment in another ZipPart
83+
6484 // There was a prior end part, so we will seek past it's length and use that as the base offset.
65- // 22 is the minimum possible size of an end part. It can be longer with comments applied, but there are almost never comments.
66- jvmBaseOffset = precedingEndOfCentralDirectory + 22L ;
67- }
68- // Read end header
69- EndOfCentralDirectory end = new EndOfCentralDirectory ();
70- end .read (data , endOfCentralDirectoryOffset );
71- zip .getParts ().add (end );
72- // Read central directories
73- long len = data .length ();
74- long centralDirectoryOffset = len - ZipPatterns .CENTRAL_DIRECTORY_FILE_HEADER .length ;
75- while (centralDirectoryOffset > 0L ) {
76- centralDirectoryOffset = ByteDataUtil .lastIndexOf (data , centralDirectoryOffset - 1L , ZipPatterns .CENTRAL_DIRECTORY_FILE_HEADER );
77- if (centralDirectoryOffset >= 0L ) {
78- CentralDirectoryFileHeader directory = new CentralDirectoryFileHeader ();
79- directory .read (data , centralDirectoryOffset );
80- zip .getParts ().add (directory );
85+ try {
86+ // Make sure it isn't bogus before we use it as a reference point
87+ EndOfCentralDirectory tempEnd = new EndOfCentralDirectory ();
88+ tempEnd .read (data , precedingEndOfCentralDirectory );
89+ jvmBaseFileOffset = precedingEndOfCentralDirectory + tempEnd .length ();
90+ } catch (Exception ex ) {
91+ // It's bogus and the sig-match was a coincidence. Zero out the offset.
92+ jvmBaseFileOffset = 0 ;
8193 }
8294 }
8395 // Read local files
8496 // - Set to prevent duplicate file header entries for the same offset
8597 Set <Long > offsets = new HashSet <>();
8698 TreeSet <Long > lfhOffsets = new TreeSet <>();
8799 for (CentralDirectoryFileHeader directory : zip .getCentralDirectories ()) {
88- long offset = jvmBaseOffset + directory .getRelativeOffsetOfLocalHeader ();
100+ long offset = jvmBaseFileOffset + directory .getRelativeOffsetOfLocalHeader ();
89101 if (ByteDataUtil .startsWith (data , offset , ZipPatterns .LOCAL_FILE_HEADER )) {
90102 lfhOffsets .add (offset );
91103 }
92104 }
93105 for (CentralDirectoryFileHeader directory : zip .getCentralDirectories ()) {
94- long offset = jvmBaseOffset + directory .getRelativeOffsetOfLocalHeader ();
106+ long relative = directory .getRelativeOffsetOfLocalHeader ();
107+ long offset = jvmBaseFileOffset + relative ;
95108 if (!offsets .contains (offset ) && ByteDataUtil .startsWith (data , offset , ZipPatterns .LOCAL_FILE_HEADER )) {
96109 try {
97110 JvmLocalFileHeader file = new JvmLocalFileHeader (lfhOffsets );
0 commit comments