public static PkwareTraditionalEncryptionData ForRead(string password, ZipFileEntry header, byte[] encryptionHeader) { var encryptor = new PkwareTraditionalEncryptionData(password, header.ArchiveEncoding); byte[] plainTextHeader = encryptor.Decrypt(encryptionHeader, encryptionHeader.Length); if (plainTextHeader[11] != (byte)((header.Crc >> 24) & 0xff)) { if (!FlagUtility.HasFlag(header.Flags, HeaderFlags.UsePostDataDescriptor)) { throw new CryptographicException("The password did not match."); } if (plainTextHeader[11] != (byte)((header.LastModifiedTime >> 8) & 0xff)) { throw new CryptographicException("The password did not match."); } } return(encryptor); }
private static IEnumerable <IEnumerable <RarFilePart> > GetMatchedFileParts(IEnumerable <RarVolume> parts) { var groupedParts = new List <RarFilePart>(); foreach (RarFilePart fp in GetFileParts(parts)) { groupedParts.Add(fp); if (!FlagUtility.HasFlag((long)fp.FileHeader.FileFlags, (long)FileFlags.SPLIT_AFTER)) { yield return(groupedParts); groupedParts = new List <RarFilePart>(); } } if (groupedParts.Count > 0) { yield return(groupedParts); } }
protected Stream GetCryptoStream(Stream plainStream) { if ((this.Header.CompressedSize == 0) && (this.Header.PkwareTraditionalEncryptionData != null)) { throw new NotSupportedException("Cannot encrypt file with unknown size at start."); } if ((this.Header.CompressedSize == 0) && FlagUtility.HasFlag <HeaderFlags>(this.Header.Flags, HeaderFlags.UsePostDataDescriptor)) { plainStream = new NonDisposingStream(plainStream); } else { plainStream = new ReadOnlySubStream(plainStream, (long)this.Header.CompressedSize); } if (this.Header.PkwareTraditionalEncryptionData != null) { return(new PkwareTraditionalCryptoStream(plainStream, this.Header.PkwareTraditionalEncryptionData, CryptoMode.Decrypt)); } return(plainStream); }
private static IEnumerable <IEnumerable <RarFilePart> > GetMatchedFileParts(IEnumerable <RarVolume> parts) { List <RarFilePart> iteratorVariable0 = new List <RarFilePart>(); foreach (RarFilePart iteratorVariable1 in GetFileParts(parts)) { iteratorVariable0.Add(iteratorVariable1); if (!FlagUtility.HasFlag((long)((ulong)iteratorVariable1.FileHeader.FileFlags), 2L)) { yield return(iteratorVariable0); iteratorVariable0 = new List <RarFilePart>(); } } if (iteratorVariable0.Count <= 0) { yield break; } yield return(iteratorVariable0); }
internal static IEnumerable <RarVolume> GetParts(FileInfo fileInfo, string password, Options options) { FileInfoRarArchiveVolume part = new FileInfoRarArchiveVolume(fileInfo, password, options); yield return(part); if (!FlagUtility.HasFlag(part.ArchiveHeader.ArchiveHeaderFlags, ArchiveFlags.VOLUME)) { yield break; //if file isn't volume then there is no reason to look } ArchiveHeader ah = part.ArchiveHeader; fileInfo = GetNextFileInfo(ah, part.FileParts.FirstOrDefault() as FileInfoRarFilePart); //we use fileinfo because rar is dumb and looks at file names rather than archive info for another volume while (fileInfo != null && fileInfo.Exists) { part = new FileInfoRarArchiveVolume(fileInfo, password, options); fileInfo = GetNextFileInfo(ah, part.FileParts.FirstOrDefault() as FileInfoRarFilePart); yield return(part); } }
/// <summary> /// Extract to specific directory, retaining filename /// </summary> public static void WriteToDirectory(this IArchiveEntry entry, string destinationDirectory, ExtractOptions options = ExtractOptions.Overwrite) { string destinationFileName; string file = Path.GetFileName(entry.Key); if (FlagUtility.HasFlag(options, ExtractOptions.ExtractFullPath)) { string folder = Path.GetDirectoryName(entry.Key); string destdir = Path.Combine(destinationDirectory, folder); if (!Directory.Exists(destdir)) { Directory.CreateDirectory(destdir); } destinationFileName = Path.Combine(destdir, file); } else { destinationFileName = Path.Combine(destinationDirectory, file); } entry.WriteToFile(destinationFileName, options); }
private void LoadHeader(ZipFileEntry entryHeader, Stream stream) { if (FlagUtility.HasFlag <HeaderFlags>(entryHeader.Flags, HeaderFlags.Encrypted)) { if ((!entryHeader.IsDirectory && (entryHeader.CompressedSize == 0)) && FlagUtility.HasFlag <HeaderFlags>(entryHeader.Flags, HeaderFlags.UsePostDataDescriptor)) { throw new NotSupportedException("SharpCompress cannot currently read non-seekable Zip Streams with encrypted data that has been written in a non-seekable manner."); } if (this.password == null) { throw new CryptographicException("No password supplied for encrypted zip."); } if (entryHeader.CompressionMethod == ZipCompressionMethod.WinzipAes) { throw new NotSupportedException("Cannot decrypt Winzip AES with Silverlight or WP7."); } byte[] buffer = new byte[12]; stream.Read(buffer, 0, 12); entryHeader.PkwareTraditionalEncryptionData = PkwareTraditionalEncryptionData.ForRead(this.password, entryHeader, buffer); entryHeader.CompressedSize -= 12; } if (!entryHeader.IsDirectory) { switch (this.mode) { case StreamingMode.Streaming: entryHeader.PackedStream = stream; return; case StreamingMode.Seekable: entryHeader.DataStartPosition = new long?(stream.Position); stream.Position += entryHeader.CompressedSize; return; } throw new InvalidFormatException("Invalid StreamingMode"); } }
protected Stream GetCryptoStream(Stream plainStream) { if ((Header.CompressedSize == 0) #if !PORTABLE && ((Header.PkwareTraditionalEncryptionData != null) || (Header.WinzipAesEncryptionData != null))) #else && (Header.PkwareTraditionalEncryptionData != null)) #endif { throw new NotSupportedException("Cannot encrypt file with unknown size at start."); } if ((Header.CompressedSize == 0) && FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor)) { plainStream = new NonDisposingStream(plainStream); //make sure AES doesn't close } else { plainStream = new ReadOnlySubStream(plainStream, Header.CompressedSize); //make sure AES doesn't close } if (Header.PkwareTraditionalEncryptionData != null) { return(new PkwareTraditionalCryptoStream(plainStream, Header.PkwareTraditionalEncryptionData, CryptoMode.Decrypt)); } #if !PORTABLE if (Header.WinzipAesEncryptionData != null) { //only read 10 less because the last ten are auth bytes return(new WinzipAesCryptoStream(plainStream, Header.WinzipAesEncryptionData, Header.CompressedSize - 10, CryptoMode.Decrypt)); } #endif return(plainStream); }
protected Stream CreateDecompressionStream(Stream stream) { switch (Header.CompressionMethod) { case ZipCompressionMethod.None: { return(stream); } case ZipCompressionMethod.Deflate: { return(new System.IO.Compression.DeflateStream(stream, System.IO.Compression.CompressionMode.Decompress)); } #if BZIP2 case ZipCompressionMethod.BZip2: { return(new BZip2Stream(stream, CompressionMode.Decompress)); } #endif #if LZMA case ZipCompressionMethod.LZMA: { if (FlagUtility.HasFlag(Header.Flags, HeaderFlags.Encrypted)) { throw new NotSupportedException("LZMA with pkware encryption."); } var reader = new BinaryReader(stream); reader.ReadUInt16(); //LZMA version var props = new byte[reader.ReadUInt16()]; reader.Read(props, 0, props.Length); return(new LzmaStream(props, stream, Header.CompressedSize > 0 ? Header.CompressedSize - 4 - props.Length : -1, FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1) ? -1 : (long)Header.UncompressedSize)); } #endif #if PPMd case ZipCompressionMethod.PPMd: { var props = new byte[2]; stream.Read(props, 0, props.Length); return(new PpmdStream(new PpmdProperties(props), stream, false)); } #endif case ZipCompressionMethod.WinzipAes: { ExtraData data = Header.Extra.Where(x => x.Type == ExtraDataType.WinZipAes).SingleOrDefault(); if (data == null) { throw new InvalidFormatException("No Winzip AES extra data found."); } if (data.Length != 7) { throw new InvalidFormatException("Winzip data length is not 7."); } ushort method = BitConverter.ToUInt16(data.DataBytes, 0); if (method != 0x01 && method != 0x02) { throw new InvalidFormatException("Unexpected vendor version number for WinZip AES metadata"); } ushort vendorId = BitConverter.ToUInt16(data.DataBytes, 2); if (vendorId != 0x4541) { throw new InvalidFormatException("Unexpected vendor ID for WinZip AES metadata"); } Header.CompressionMethod = (ZipCompressionMethod)BitConverter.ToUInt16(data.DataBytes, 5); return(CreateDecompressionStream(stream)); } default: { throw new NotSupportedException("CompressionMethod: " + Header.CompressionMethod); } } }
protected ZipHeader ReadHeader(uint headerBytes, BinaryReader reader) { switch (headerBytes) { case ENTRY_HEADER_BYTES: { var entryHeader = new LocalEntryHeader(); entryHeader.Read(reader); LoadHeader(entryHeader, reader.BaseStream); lastEntryHeader = entryHeader; return(entryHeader); } case DIRECTORY_START_HEADER_BYTES: { var entry = new DirectoryEntryHeader(); entry.Read(reader); return(entry); } case POST_DATA_DESCRIPTOR: { if (FlagUtility.HasFlag(lastEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor)) { lastEntryHeader.Crc = reader.ReadUInt32(); lastEntryHeader.CompressedSize = reader.ReadUInt32(); lastEntryHeader.UncompressedSize = reader.ReadUInt32(); } else { reader.ReadUInt32(); reader.ReadUInt32(); reader.ReadUInt32(); } 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: case ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR: { var entry = new IgnoreHeader(ZipHeaderType.Ignore); entry.Read(reader); return(entry); } default: throw new NotSupportedException("Unknown header: " + headerBytes); } }
private void LoadHeader(ZipFileEntry entryHeader, Stream stream) { if (FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.Encrypted)) { if (!entryHeader.IsDirectory && entryHeader.CompressedSize == 0 && FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.UsePostDataDescriptor)) { throw new NotSupportedException( "SharpCompress cannot currently read non-seekable Zip Streams with encrypted data that has been written in a non-seekable manner."); } if (password == null) { throw new CryptographicException("No password supplied for encrypted zip."); } if (entryHeader.CompressionMethod != ZipCompressionMethod.WinzipAes) { byte[] buffer = new byte[12]; stream.Read(buffer, 0, 12); entryHeader.PkwareTraditionalEncryptionData = PkwareTraditionalEncryptionData.ForRead(password, entryHeader, buffer); entryHeader.CompressedSize -= 12; } else { #if NO_CRYPTO throw new NotSupportedException("Cannot decrypt Winzip AES with Silverlight or WP7."); #else var data = entryHeader.Extra.SingleOrDefault(x => x.Type == ExtraDataType.WinZipAes); WinzipAesKeySize keySize = (WinzipAesKeySize)data.DataBytes[4]; byte[] salt = new byte[WinzipAesEncryptionData.KeyLengthInBytes(keySize) / 2]; byte[] passwordVerifyValue = new byte[2]; stream.Read(salt, 0, salt.Length); stream.Read(passwordVerifyValue, 0, 2); entryHeader.WinzipAesEncryptionData = new WinzipAesEncryptionData(keySize, salt, passwordVerifyValue, password); entryHeader.CompressedSize -= (uint)(salt.Length + 2); #endif } } if (entryHeader.IsDirectory) { return; } //if (FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.UsePostDataDescriptor)) //{ // entryHeader.PackedStream = new ReadOnlySubStream(stream); //} //else //{ switch (mode) { case StreamingMode.Seekable: { entryHeader.DataStartPosition = stream.Position; stream.Position += entryHeader.CompressedSize; } break; case StreamingMode.Streaming: { entryHeader.PackedStream = stream; } break; default: { throw new InvalidFormatException("Invalid StreamingMode"); } } //} }
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); } }
private void LoadHeader(ZipFileEntry entryHeader, Stream stream) { if (FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.Encrypted)) { if (!entryHeader.IsDirectory && entryHeader.CompressedSize == 0 && FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.UsePostDataDescriptor)) { throw new NotSupportedException("SharpCompress cannot currently read non-seekable Zip Streams with encrypted data that has been written in a non-seekable manner."); } if (_password == null) { throw new CryptographicException("No password supplied for encrypted zip."); } entryHeader.Password = _password; if (entryHeader.CompressionMethod == ZipCompressionMethod.WinzipAes) { ExtraData data = entryHeader.Extra.SingleOrDefault(x => x.Type == ExtraDataType.WinZipAes); if (data != null) { var keySize = (WinzipAesKeySize)data.DataBytes[4]; var salt = new byte[WinzipAesEncryptionData.KeyLengthInBytes(keySize) / 2]; var passwordVerifyValue = new byte[2]; stream.Read(salt, 0, salt.Length); stream.Read(passwordVerifyValue, 0, 2); entryHeader.WinzipAesEncryptionData = new WinzipAesEncryptionData(keySize, salt, passwordVerifyValue, _password); entryHeader.CompressedSize -= (uint)(salt.Length + 2); } } } if (entryHeader.IsDirectory) { return; } //if (FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.UsePostDataDescriptor)) //{ // entryHeader.PackedStream = new ReadOnlySubStream(stream); //} //else //{ switch (_mode) { case StreamingMode.Seekable: { entryHeader.DataStartPosition = stream.Position; stream.Position += entryHeader.CompressedSize; break; } case StreamingMode.Streaming: { entryHeader.PackedStream = stream; break; } default: { throw new InvalidFormatException("Invalid StreamingMode"); } } //} }
protected Stream CreateDecompressionStream(Stream stream, ZipCompressionMethod method) { switch (method) { case ZipCompressionMethod.None: { return(stream); } case ZipCompressionMethod.Deflate: { return(new DeflateStream(stream, CompressionMode.Decompress)); } case ZipCompressionMethod.Deflate64: { return(new Deflate64Stream(stream, CompressionMode.Decompress)); } case ZipCompressionMethod.BZip2: { return(new BZip2Stream(stream, CompressionMode.Decompress, false)); } case ZipCompressionMethod.LZMA: { if (FlagUtility.HasFlag(Header.Flags, HeaderFlags.Encrypted)) { throw new NotSupportedException("LZMA with pkware encryption."); } var reader = new BinaryReader(stream); reader.ReadUInt16(); //LZMA version var props = new byte[reader.ReadUInt16()]; reader.Read(props, 0, props.Length); return(new LzmaStream(props, stream, Header.CompressedSize > 0 ? Header.CompressedSize - 4 - props.Length : -1, FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1) ? -1 : (long)Header.UncompressedSize)); } case ZipCompressionMethod.PPMd: { Span <byte> props = stackalloc byte[2]; stream.ReadFully(props); return(new PpmdStream(new PpmdProperties(props), stream, false)); } case ZipCompressionMethod.WinzipAes: { ExtraData data = Header.Extra.SingleOrDefault(x => x.Type == ExtraDataType.WinZipAes); if (data is null) { throw new InvalidFormatException("No Winzip AES extra data found."); } if (data.Length != 7) { throw new InvalidFormatException("Winzip data length is not 7."); } ushort compressedMethod = BinaryPrimitives.ReadUInt16LittleEndian(data.DataBytes); if (compressedMethod != 0x01 && compressedMethod != 0x02) { throw new InvalidFormatException("Unexpected vendor version number for WinZip AES metadata"); } ushort vendorId = BinaryPrimitives.ReadUInt16LittleEndian(data.DataBytes.AsSpan(2)); if (vendorId != 0x4541) { throw new InvalidFormatException("Unexpected vendor ID for WinZip AES metadata"); } return(CreateDecompressionStream(stream, (ZipCompressionMethod)BinaryPrimitives.ReadUInt16LittleEndian(data.DataBytes.AsSpan(5)))); } default: { throw new NotSupportedException("CompressionMethod: " + Header.CompressionMethod); } } }
protected Stream CreateDecompressionStream(Stream stream) { byte[] buffer; switch (this.Header.CompressionMethod) { case ZipCompressionMethod.None: return(stream); case ZipCompressionMethod.Deflate: return(new DeflateStream(stream, CompressionMode.Decompress, CompressionLevel.Default, false)); case ZipCompressionMethod.BZip2: return(new BZip2Stream(stream, CompressionMode.Decompress, false, false)); case ZipCompressionMethod.LZMA: { if (FlagUtility.HasFlag <HeaderFlags>(this.Header.Flags, HeaderFlags.Encrypted)) { throw new NotSupportedException("LZMA with pkware encryption."); } BinaryReader reader = new BinaryReader(stream); reader.ReadUInt16(); buffer = new byte[reader.ReadUInt16()]; reader.Read(buffer, 0, buffer.Length); return(new LzmaStream(buffer, stream, (this.Header.CompressedSize > 0) ? ((this.Header.CompressedSize - 4) - buffer.Length) : -1L, FlagUtility.HasFlag <HeaderFlags>(this.Header.Flags, HeaderFlags.Bit1) ? -1L : ((long)this.Header.UncompressedSize))); } case ZipCompressionMethod.PPMd: buffer = new byte[2]; stream.Read(buffer, 0, buffer.Length); return(new PpmdStream(new PpmdProperties(buffer), stream, false)); case ZipCompressionMethod.WinzipAes: { ExtraData data = Enumerable.SingleOrDefault <ExtraData>(Enumerable.Where <ExtraData>(this.Header.Extra, delegate(ExtraData x) { return(x.Type == ExtraDataType.WinZipAes); })); if (data == null) { throw new InvalidFormatException("No Winzip AES extra data found."); } if (data.Length != 7) { throw new InvalidFormatException("Winzip data length is not 7."); } ushort num = BitConverter.ToUInt16(data.DataBytes, 0); if ((num != 1) && (num != 2)) { throw new InvalidFormatException("Unexpected vendor version number for WinZip AES metadata"); } if (BitConverter.ToUInt16(data.DataBytes, 2) != 0x4541) { throw new InvalidFormatException("Unexpected vendor ID for WinZip AES metadata"); } this.Header.CompressionMethod = (ZipCompressionMethod)BitConverter.ToUInt16(data.DataBytes, 5); return(this.CreateDecompressionStream(stream)); } } throw new NotSupportedException("CompressionMethod: " + this.Header.CompressionMethod); }
internal IEnumerable <ZipHeader> ReadStreamHeader(Stream stream) { RewindableStream rewindableStream; if (stream is RewindableStream rs) { rewindableStream = rs; } else { rewindableStream = new RewindableStream(stream); } while (true) { ZipHeader header; BinaryReader reader = new BinaryReader(rewindableStream); if (_lastEntryHeader != null && (FlagUtility.HasFlag(_lastEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor) || _lastEntryHeader.IsZip64)) { reader = ((StreamingZipFilePart)_lastEntryHeader.Part).FixStreamedFileLocation(ref rewindableStream); long?pos = rewindableStream.CanSeek ? (long?)rewindableStream.Position : null; uint crc = reader.ReadUInt32(); if (crc == POST_DATA_DESCRIPTOR) { crc = reader.ReadUInt32(); } _lastEntryHeader.Crc = crc; _lastEntryHeader.CompressedSize = reader.ReadUInt32(); _lastEntryHeader.UncompressedSize = reader.ReadUInt32(); if (pos.HasValue) { _lastEntryHeader.DataStartPosition = pos - _lastEntryHeader.CompressedSize; } } _lastEntryHeader = null; uint headerBytes = reader.ReadUInt32(); header = ReadHeader(headerBytes, reader); if (header is null) { yield break; } //entry could be zero bytes so we need to know that. if (header.ZipHeaderType == ZipHeaderType.LocalEntry) { var local_header = ((LocalEntryHeader)header); // If we have CompressedSize, there is data to be read if (local_header.CompressedSize > 0) { header.HasData = true; } // Check if zip is streaming ( Length is 0 and is declared in PostDataDescriptor ) else if (local_header.Flags.HasFlag(HeaderFlags.UsePostDataDescriptor)) { bool isRecording = rewindableStream.IsRecording; if (!isRecording) { rewindableStream.StartRecording(); } uint nextHeaderBytes = reader.ReadUInt32(); // Check if next data is PostDataDescriptor, streamed file with 0 length header.HasData = !IsHeader(nextHeaderBytes); rewindableStream.Rewind(!isRecording); } else // We are not streaming and compressed size is 0, we have no data { header.HasData = false; } } yield return(header); } }
internal IEnumerable <ZipHeader> ReadStreamHeader(Stream stream) { RewindableStream rewindableStream; if (stream is RewindableStream) { rewindableStream = stream as RewindableStream; } else { rewindableStream = new RewindableStream(stream); } while (true) { ZipHeader header = null; BinaryReader reader = new BinaryReader(rewindableStream); if (lastEntryHeader != null && (FlagUtility.HasFlag(lastEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor) || lastEntryHeader.IsZip64)) { reader = (lastEntryHeader.Part as StreamingZipFilePart).FixStreamedFileLocation(ref rewindableStream); long?pos = rewindableStream.CanSeek ? (long?)rewindableStream.Position : null; uint crc = reader.ReadUInt32(); if (crc == POST_DATA_DESCRIPTOR) { crc = reader.ReadUInt32(); } lastEntryHeader.Crc = crc; lastEntryHeader.CompressedSize = reader.ReadUInt32(); lastEntryHeader.UncompressedSize = reader.ReadUInt32(); if (pos.HasValue) { lastEntryHeader.DataStartPosition = pos - lastEntryHeader.CompressedSize; } } lastEntryHeader = null; uint headerBytes = reader.ReadUInt32(); header = ReadHeader(headerBytes, reader); //entry could be zero bytes so we need to know that. if (header.ZipHeaderType == ZipHeaderType.LocalEntry) { bool isRecording = rewindableStream.IsRecording; if (!isRecording) { rewindableStream.StartRecording(); } uint nextHeaderBytes = reader.ReadUInt32(); //check for Headers AfterChild Volumes in Mac OS archive uint nextNextHeaderBytes = reader.ReadUInt32(); if (nextNextHeaderBytes > 0) { nextHeaderBytes = nextNextHeaderBytes; } else { reader.BaseStream.Position -= nextNextHeaderBytes; } header.HasData = !IsHeader(nextHeaderBytes); rewindableStream.Rewind(!isRecording); } yield return(header); } }