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);
        }
Example #2
0
        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);
            }
        }
Example #3
0
 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);
 }
Example #4
0
        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);
        }
Example #5
0
        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);
        }
Example #7
0
        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");
            }
        }
Example #8
0
        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);
        }
Example #9
0
        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");
            }
            }
            //}
        }
Example #12
0
        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);
            }
        }
Example #13
0
        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");
            }
            }

            //}
        }
Example #14
0
        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);
            }
            }
        }
Example #15
0
        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);
        }
Example #16
0
        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);
            }
        }