internal IEnumerable <ZipHeader> ReadSeekableHeader(Stream stream) { var reader = new BinaryReader(stream); SeekBackToHeader(stream, reader, DIRECTORY_END_HEADER_BYTES); var entry = new DirectoryEndHeader(); entry.Read(reader); if (entry.IsZip64) { _zip64 = true; SeekBackToHeader(stream, reader, ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR); var zip64Locator = new Zip64DirectoryEndLocatorHeader(); zip64Locator.Read(reader); stream.Seek(zip64Locator.RelativeOffsetOfTheEndOfDirectoryRecord, SeekOrigin.Begin); uint zip64Signature = reader.ReadUInt32(); if (zip64Signature != ZIP64_END_OF_CENTRAL_DIRECTORY) { throw new ArchiveException("Failed to locate the Zip64 Header"); } var zip64Entry = new Zip64DirectoryEndHeader(); zip64Entry.Read(reader); stream.Seek(zip64Entry.DirectoryStartOffsetRelativeToDisk, SeekOrigin.Begin); } else { stream.Seek(entry.DirectoryStartOffsetRelativeToDisk, SeekOrigin.Begin); } long position = stream.Position; while (true) { stream.Position = position; uint signature = reader.ReadUInt32(); var nextHeader = ReadHeader(signature, reader, _zip64); position = stream.Position; if (nextHeader == null) { yield break; } if (nextHeader is DirectoryEntryHeader entryHeader) { //entry could be zero bytes so we need to know that. entryHeader.HasData = entryHeader.CompressedSize != 0; yield return(entryHeader); } else if (nextHeader is DirectoryEndHeader endHeader) { yield return(endHeader); } } }
protected ZipHeader ReadHeader(uint headerBytes, BinaryReader reader, bool zip64 = false) { switch (headerBytes) { case ENTRY_HEADER_BYTES: { var entryHeader = new LocalEntryHeader(_archiveEncoding); entryHeader.Read(reader); LoadHeader(entryHeader, reader.BaseStream); _lastEntryHeader = entryHeader; return(entryHeader); } case DIRECTORY_START_HEADER_BYTES: { var entry = new DirectoryEntryHeader(_archiveEncoding); entry.Read(reader); return(entry); } case POST_DATA_DESCRIPTOR: { if (FlagUtility.HasFlag(_lastEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor)) { _lastEntryHeader.Crc = reader.ReadUInt32(); _lastEntryHeader.CompressedSize = zip64 ? (long)reader.ReadUInt64() : reader.ReadUInt32(); _lastEntryHeader.UncompressedSize = zip64 ? (long)reader.ReadUInt64() : reader.ReadUInt32(); } else { reader.ReadBytes(zip64 ? 20 : 12); } return(null); } case DIGITAL_SIGNATURE: return(null); case DIRECTORY_END_HEADER_BYTES: { var entry = new DirectoryEndHeader(); entry.Read(reader); return(entry); } case SPLIT_ARCHIVE_HEADER_BYTES: { return(new SplitHeader()); } case ZIP64_END_OF_CENTRAL_DIRECTORY: { var entry = new Zip64DirectoryEndHeader(); entry.Read(reader); return(entry); } case ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR: { var entry = new Zip64DirectoryEndLocatorHeader(); entry.Read(reader); return(entry); } default: return(null); } }