@@ -86,26 +86,40 @@ public void read(@Nonnull ZipArchive zip, @Nonnull MemorySegment data) throws IO
8686 end .read (data , endOfCentralDirectoryOffset );
8787 zip .addPart (end );
8888
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.
9190 long len = data .byteSize ();
92- long centralDirectoryOffset = len - ZipPatterns .CENTRAL_DIRECTORY_FILE_HEADER .length ;
93- long maxRelativeOffset = 0 ;
9491 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 );
108118 }
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 );
109123 }
110124
111125 // Determine base offset for computing file header locations with.
0 commit comments