@@ -90,7 +90,7 @@ public void read(@Nonnull ZipArchive zip, @Nonnull MemorySegment data) throws IO
90
90
long len = data .byteSize ();
91
91
long centralDirectoryOffsetScanEnd = Math .max (Math .max (precedingEndOfCentralDirectory , 0 ), end .getCentralDirectoryOffset ());
92
92
long earliestCentralDirectoryOffset = len - ZipPatterns .CENTRAL_DIRECTORY_FILE_HEADER .length ;
93
- long maxRelativeOffset = 0 ;
93
+ long maxRelativeLFHOffset = 0 ;
94
94
while (true ) {
95
95
// Look backwards for the next CEN magic quad.
96
96
long offset = MemorySegmentUtil .lastIndexOfQuad (data , earliestCentralDirectoryOffset - 1L , ZipPatterns .CENTRAL_DIRECTORY_FILE_HEADER_QUAD );
@@ -107,6 +107,7 @@ public void read(@Nonnull ZipArchive zip, @Nonnull MemorySegment data) throws IO
107
107
// Read central directories going forward from the first CEN header.
108
108
// We do this "find the first, then read forward" so that we can skip over data that may
109
109
// coincidentally hold the CEN magic, but not actually denote the beginning of a central directory entry.
110
+ CentralDirectoryFileHeader latestOffsetCen = null ;
110
111
long centralDirectoryOffset = earliestCentralDirectoryOffset ;
111
112
while (centralDirectoryOffset >= 0L ) {
112
113
CentralDirectoryFileHeader directory = newCentralDirectoryFileHeader ();
@@ -116,9 +117,17 @@ public void read(@Nonnull ZipArchive zip, @Nonnull MemorySegment data) throws IO
116
117
// We cannot recover from the CEN reading encountering failures.
117
118
throw new IOException (ex );
118
119
}
120
+
121
+ // Add to zip
119
122
zip .addPart (directory );
120
- if (directory .getRelativeOffsetOfLocalHeader () > maxRelativeOffset )
121
- maxRelativeOffset = directory .getRelativeOffsetOfLocalHeader ();
123
+
124
+ // Track which CEN has the latest offset in the ZIP file
125
+ if (directory .getRelativeOffsetOfLocalHeader () > maxRelativeLFHOffset ) {
126
+ maxRelativeLFHOffset = directory .getRelativeOffsetOfLocalHeader ();
127
+ latestOffsetCen = directory ;
128
+ }
129
+
130
+ // Step forward
122
131
centralDirectoryOffset = MemorySegmentUtil .indexOfQuad (data , centralDirectoryOffset + CentralDirectoryFileHeader .MIN_FIXED_SIZE , ZipPatterns .CENTRAL_DIRECTORY_FILE_HEADER_QUAD );
123
132
}
124
133
@@ -130,14 +139,26 @@ public void read(@Nonnull ZipArchive zip, @Nonnull MemorySegment data) throws IO
130
139
if (precedingEndOfCentralDirectory != -1 ) {
131
140
// There was a prior end part, so we will seek past it's length and use that as the base offset.
132
141
try {
142
+ // We roughly compute the "size" of section of data occupied by LocalFileHeader contents.
143
+ // The latest relative file offset, plus its header+data size then this should be the section size
144
+ // even if we don't know if there is a preceding end header or not to base off of.
145
+ if (latestOffsetCen != null ) {
146
+ long localFileHeaderSectionLength = LocalFileHeader .MIN_FIXED_SIZE + maxRelativeLFHOffset + latestOffsetCen .getCompressedSize ();
147
+ long startOfRelativeLocalFileHeaders = earliestCentralDirectoryOffset - localFileHeaderSectionLength ;
148
+ if (precedingEndOfCentralDirectory > startOfRelativeLocalFileHeaders ) {
149
+ // This occurs between the start of LocalFileHeader data and our current end and should be ignored.
150
+ throw new IllegalStateException ();
151
+ }
152
+ }
153
+
133
154
// Make sure it isn't bogus before we use it as a reference point
134
155
EndOfCentralDirectory tempEnd = new EndOfCentralDirectory ();
135
156
tempEnd .read (data , precedingEndOfCentralDirectory );
136
157
137
158
// If we use this as a point of reference there must be enough data remaining
138
159
// to read the largest offset specified by our central directories.
139
160
long hypotheticalJvmBaseOffset = precedingEndOfCentralDirectory + tempEnd .length ();
140
- if (len <= hypotheticalJvmBaseOffset + maxRelativeOffset )
161
+ if (len <= hypotheticalJvmBaseOffset + maxRelativeLFHOffset )
141
162
throw new IllegalStateException ();
142
163
143
164
// TODO: Double check 'precedingEndOfCentralDirectory' points to a EndOfCentralDirectory that isn't bogus
0 commit comments