|
3 | 3 | using ICSharpCode.SharpZipLib.Zip.Compression; |
4 | 4 | using ICSharpCode.SharpZipLib.Zip.Compression.Streams; |
5 | 5 | using System; |
| 6 | +using System.Diagnostics; |
6 | 7 | using System.IO; |
7 | 8 |
|
8 | 9 | namespace ICSharpCode.SharpZipLib.Zip |
@@ -181,31 +182,12 @@ public ZipEntry GetNextEntry() |
181 | 182 | CloseEntry(); |
182 | 183 | } |
183 | 184 |
|
184 | | - int header = inputBuffer.ReadLeInt(); |
185 | | - |
186 | | - if (header == ZipConstants.CentralHeaderSignature || |
187 | | - header == ZipConstants.EndOfCentralDirectorySignature || |
188 | | - header == ZipConstants.CentralHeaderDigitalSignature || |
189 | | - header == ZipConstants.ArchiveExtraDataSignature || |
190 | | - header == ZipConstants.Zip64CentralFileHeaderSignature) |
| 185 | + if (!SkipUntilNextEntry()) |
191 | 186 | { |
192 | | - // No more individual entries exist |
193 | 187 | Dispose(); |
194 | 188 | return null; |
195 | 189 | } |
196 | 190 |
|
197 | | - // -jr- 07-Dec-2003 Ignore spanning temporary signatures if found |
198 | | - // Spanning signature is same as descriptor signature and is untested as yet. |
199 | | - if ((header == ZipConstants.SpanningTempSignature) || (header == ZipConstants.SpanningSignature)) |
200 | | - { |
201 | | - header = inputBuffer.ReadLeInt(); |
202 | | - } |
203 | | - |
204 | | - if (header != ZipConstants.LocalHeaderSignature) |
205 | | - { |
206 | | - throw new ZipException("Wrong Local header signature: 0x" + String.Format("{0:X}", header)); |
207 | | - } |
208 | | - |
209 | 191 | var versionRequiredToExtract = (short)inputBuffer.ReadLeShort(); |
210 | 192 |
|
211 | 193 | flags = inputBuffer.ReadLeShort(); |
@@ -303,6 +285,54 @@ public ZipEntry GetNextEntry() |
303 | 285 | return entry; |
304 | 286 | } |
305 | 287 |
|
| 288 | + /// <summary> |
| 289 | + /// Reads bytes from the input stream until either a local file header signature, or another signature |
| 290 | + /// indicating that no more entries should be present, is found. |
| 291 | + /// </summary> |
| 292 | + /// <exception cref="ZipException">Thrown if the end of the input stream is reached without any signatures found</exception> |
| 293 | + /// <returns>Returns whether the found signature is for a local entry header</returns> |
| 294 | + private bool SkipUntilNextEntry() |
| 295 | + { |
| 296 | + // First let's skip all null bytes since it's the sane padding to add when updating an entry with smaller size |
| 297 | + var paddingSkipped = 0; |
| 298 | + while(inputBuffer.ReadLeByte() == 0) { |
| 299 | + paddingSkipped++; |
| 300 | + } |
| 301 | + |
| 302 | + // Last byte read was not actually consumed, restore the offset |
| 303 | + inputBuffer.Available += 1; |
| 304 | + if(paddingSkipped > 0) { |
| 305 | + Debug.WriteLine("Skipped {0} null byte(s) before reading signature", paddingSkipped); |
| 306 | + } |
| 307 | + |
| 308 | + var offset = 0; |
| 309 | + // Read initial header quad directly after the last entry |
| 310 | + var header = (uint)inputBuffer.ReadLeInt(); |
| 311 | + do |
| 312 | + { |
| 313 | + switch (header) |
| 314 | + { |
| 315 | + case ZipConstants.CentralHeaderSignature: |
| 316 | + case ZipConstants.EndOfCentralDirectorySignature: |
| 317 | + case ZipConstants.CentralHeaderDigitalSignature: |
| 318 | + case ZipConstants.ArchiveExtraDataSignature: |
| 319 | + case ZipConstants.Zip64CentralFileHeaderSignature: |
| 320 | + Debug.WriteLine("Non-entry signature found at offset {0,2}: 0x{1:x8}", offset, header); |
| 321 | + // No more individual entries exist |
| 322 | + return false; |
| 323 | + |
| 324 | + case ZipConstants.LocalHeaderSignature: |
| 325 | + Debug.WriteLine("Entry local header signature found at offset {0,2}: 0x{1:x8}", offset, header); |
| 326 | + return true; |
| 327 | + default: |
| 328 | + // Current header quad did not match any signature, shift in another byte |
| 329 | + header = (uint) (inputBuffer.ReadLeByte() << 24) | (header >> 8); |
| 330 | + offset++; |
| 331 | + break; |
| 332 | + } |
| 333 | + } while (true); // Loop until we either get an EOF exception or we find the next signature |
| 334 | + } |
| 335 | + |
306 | 336 | /// <summary> |
307 | 337 | /// Read data descriptor at the end of compressed data. |
308 | 338 | /// </summary> |
@@ -400,6 +430,7 @@ public void CloseEntry() |
400 | 430 |
|
401 | 431 | if ((inputBuffer.Available > csize) && (csize >= 0)) |
402 | 432 | { |
| 433 | + // Buffer can contain entire entry data. Internally offsetting position inside buffer |
403 | 434 | inputBuffer.Available = (int)((long)inputBuffer.Available - csize); |
404 | 435 | } |
405 | 436 | else |
|
0 commit comments