@@ -86,26 +86,40 @@ public void read(@Nonnull ZipArchive zip, @Nonnull MemorySegment data) throws IO
86
86
end .read (data , endOfCentralDirectoryOffset );
87
87
zip .addPart (end );
88
88
89
- // Read central directories (going from the back to the front) up until the preceding ZIP file (if any)
90
- // but not surpassing the declared cen directory offset in the end of central directory header.
89
+ // Find the first CEN header.
91
90
long len = data .byteSize ();
92
- long centralDirectoryOffset = len - ZipPatterns .CENTRAL_DIRECTORY_FILE_HEADER .length ;
93
- long maxRelativeOffset = 0 ;
94
91
long centralDirectoryOffsetScanEnd = Math .max (Math .max (precedingEndOfCentralDirectory , 0 ), end .getCentralDirectoryOffset ());
95
- while (centralDirectoryOffset > centralDirectoryOffsetScanEnd ) {
96
- centralDirectoryOffset = MemorySegmentUtil .lastIndexOfQuad (data , centralDirectoryOffset - 1L , ZipPatterns .CENTRAL_DIRECTORY_FILE_HEADER_QUAD );
97
- if (centralDirectoryOffset >= 0L ) {
98
- CentralDirectoryFileHeader directory = newCentralDirectoryFileHeader ();
99
- try {
100
- directory .read (data , centralDirectoryOffset );
101
- } catch (ZipParseException ex ) {
102
- // We cannot recover from the CEN reading encountering failures.
103
- throw new IOException (ex );
104
- }
105
- zip .addPart (directory );
106
- if (directory .getRelativeOffsetOfLocalHeader () > maxRelativeOffset )
107
- maxRelativeOffset = directory .getRelativeOffsetOfLocalHeader ();
92
+ long earliestCentralDirectoryOffset = len - ZipPatterns .CENTRAL_DIRECTORY_FILE_HEADER .length ;
93
+ long maxRelativeOffset = 0 ;
94
+ while (true ) {
95
+ // Look backwards for the next CEN magic quad.
96
+ long offset = MemorySegmentUtil .lastIndexOfQuad (data , earliestCentralDirectoryOffset - 1L , ZipPatterns .CENTRAL_DIRECTORY_FILE_HEADER_QUAD );
97
+
98
+ // If the offset is before the END defined CEN offset, then we should stop scanning.
99
+ // This offset is the first CEN for the given END.
100
+ if (offset < centralDirectoryOffsetScanEnd )
101
+ break ;
102
+
103
+ // Record as the new earliest CEN offset, and loop again.
104
+ earliestCentralDirectoryOffset = offset ;
105
+ }
106
+
107
+ // Read central directories going forward from the first CEN header.
108
+ // We do this "find the first, then read forward" so that we can skip over data that may
109
+ // coincidentally hold the CEN magic, but not actually denote the beginning of a central directory entry.
110
+ long centralDirectoryOffset = earliestCentralDirectoryOffset ;
111
+ while (centralDirectoryOffset >= 0L ) {
112
+ CentralDirectoryFileHeader directory = newCentralDirectoryFileHeader ();
113
+ try {
114
+ directory .read (data , centralDirectoryOffset );
115
+ } catch (ZipParseException ex ) {
116
+ // We cannot recover from the CEN reading encountering failures.
117
+ throw new IOException (ex );
108
118
}
119
+ zip .addPart (directory );
120
+ if (directory .getRelativeOffsetOfLocalHeader () > maxRelativeOffset )
121
+ maxRelativeOffset = directory .getRelativeOffsetOfLocalHeader ();
122
+ centralDirectoryOffset = MemorySegmentUtil .indexOfQuad (data , centralDirectoryOffset + CentralDirectoryFileHeader .MIN_FIXED_SIZE , ZipPatterns .CENTRAL_DIRECTORY_FILE_HEADER_QUAD );
109
123
}
110
124
111
125
// Determine base offset for computing file header locations with.
0 commit comments