// ZipHelperStream.cs 
 | 
// 
 | 
// Copyright 2006, 2007 John Reilly 
 | 
// 
 | 
// This program is free software; you can redistribute it and/or 
 | 
// modify it under the terms of the GNU General Public License 
 | 
// as published by the Free Software Foundation; either version 2 
 | 
// of the License, or (at your option) any later version. 
 | 
// 
 | 
// This program is distributed in the hope that it will be useful, 
 | 
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
 | 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 | 
// GNU General Public License for more details. 
 | 
// 
 | 
// You should have received a copy of the GNU General Public License 
 | 
// along with this program; if not, write to the Free Software 
 | 
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. 
 | 
// 
 | 
// Linking this library statically or dynamically with other modules is 
 | 
// making a combined work based on this library.  Thus, the terms and 
 | 
// conditions of the GNU General Public License cover the whole 
 | 
// combination. 
 | 
//  
 | 
// As a special exception, the copyright holders of this library give you 
 | 
// permission to link this library with independent modules to produce an 
 | 
// executable, regardless of the license terms of these independent 
 | 
// modules, and to copy and distribute the resulting executable under 
 | 
// terms of your choice, provided that you also meet, for each linked 
 | 
// independent module, the terms and conditions of the license of that 
 | 
// module.  An independent module is a module which is not derived from 
 | 
// or based on this library.  If you modify this library, you may extend 
 | 
// this exception to your version of the library, but you are not 
 | 
// obligated to do so.  If you do not wish to do so, delete this 
 | 
// exception statement from your version. 
 | 
  
 | 
using System; 
 | 
using System.IO; 
 | 
using System.Text; 
 | 
  
 | 
namespace ICSharpCode.SharpZipLib.Zip 
 | 
{ 
 | 
  
 | 
    /// <summary> 
 | 
    /// Holds data pertinent to a data descriptor. 
 | 
    /// </summary> 
 | 
    public class DescriptorData 
 | 
    { 
 | 
        /// <summary> 
 | 
        /// Get /set the compressed size of data. 
 | 
        /// </summary> 
 | 
        public long CompressedSize 
 | 
        { 
 | 
            get { return compressedSize; } 
 | 
            set { compressedSize = value; } 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Get / set the uncompressed size of data 
 | 
        /// </summary> 
 | 
        public long Size 
 | 
        { 
 | 
            get { return size; } 
 | 
            set { size = value; } 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Get /set the crc value. 
 | 
        /// </summary> 
 | 
        public long Crc 
 | 
        { 
 | 
            get { return crc; } 
 | 
            set { crc = (value & 0xffffffff); } 
 | 
        } 
 | 
  
 | 
        #region Instance Fields 
 | 
        long size; 
 | 
        long compressedSize; 
 | 
        long crc; 
 | 
        #endregion 
 | 
    } 
 | 
  
 | 
    class EntryPatchData 
 | 
    { 
 | 
        public long SizePatchOffset 
 | 
        { 
 | 
            get { return sizePatchOffset_; } 
 | 
            set { sizePatchOffset_ = value; } 
 | 
        } 
 | 
  
 | 
        public long CrcPatchOffset 
 | 
        { 
 | 
            get { return crcPatchOffset_; } 
 | 
            set { crcPatchOffset_ = value; } 
 | 
        } 
 | 
         
 | 
        #region Instance Fields 
 | 
        long sizePatchOffset_; 
 | 
        long crcPatchOffset_; 
 | 
        #endregion 
 | 
    } 
 | 
     
 | 
    /// <summary> 
 | 
    /// This class assists with writing/reading from Zip files. 
 | 
    /// </summary> 
 | 
    internal class ZipHelperStream : Stream 
 | 
    { 
 | 
        #region Constructors 
 | 
        /// <summary> 
 | 
        /// Initialise an instance of this class. 
 | 
        /// </summary> 
 | 
        /// <param name="name">The name of the file to open.</param> 
 | 
        public ZipHelperStream(string name) 
 | 
        { 
 | 
            stream_ = new FileStream(name, FileMode.Open, FileAccess.ReadWrite); 
 | 
            isOwner_ = true; 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Initialise a new instance of <see cref="ZipHelperStream"/>. 
 | 
        /// </summary> 
 | 
        /// <param name="stream">The stream to use.</param> 
 | 
        public ZipHelperStream(Stream stream) 
 | 
        { 
 | 
            stream_ = stream; 
 | 
        } 
 | 
        #endregion 
 | 
  
 | 
        /// <summary> 
 | 
        /// Get / set a value indicating wether the the underlying stream is owned or not. 
 | 
        /// </summary> 
 | 
        /// <remarks>If the stream is owned it is closed when this instance is closed.</remarks> 
 | 
        public bool IsStreamOwner 
 | 
        { 
 | 
            get { return isOwner_; } 
 | 
            set { isOwner_ = value; } 
 | 
        } 
 | 
  
 | 
        #region Base Stream Methods 
 | 
        public override bool CanRead 
 | 
        { 
 | 
            get { return stream_.CanRead; } 
 | 
        } 
 | 
  
 | 
        public override bool CanSeek 
 | 
        { 
 | 
            get { return stream_.CanSeek; } 
 | 
        } 
 | 
  
 | 
#if !NET_1_0 && !NET_1_1 && !NETCF_1_0 
 | 
        public override bool CanTimeout 
 | 
        { 
 | 
            get { return stream_.CanTimeout; } 
 | 
        } 
 | 
#endif 
 | 
  
 | 
        public override long Length 
 | 
        { 
 | 
            get { return stream_.Length; } 
 | 
        } 
 | 
  
 | 
        public override long Position 
 | 
        { 
 | 
            get { return stream_.Position; } 
 | 
            set { stream_.Position = value;    } 
 | 
        } 
 | 
  
 | 
        public override bool CanWrite 
 | 
        { 
 | 
            get { return stream_.CanWrite; } 
 | 
        } 
 | 
  
 | 
        public override void Flush() 
 | 
        { 
 | 
            stream_.Flush(); 
 | 
        } 
 | 
  
 | 
        public override long Seek(long offset, SeekOrigin origin) 
 | 
        { 
 | 
            return stream_.Seek(offset, origin); 
 | 
        } 
 | 
  
 | 
        public override void SetLength(long value) 
 | 
        { 
 | 
            stream_.SetLength(value); 
 | 
        } 
 | 
  
 | 
        public override int Read(byte[] buffer, int offset, int count) 
 | 
        { 
 | 
            return stream_.Read(buffer, offset, count); 
 | 
        } 
 | 
  
 | 
        public override void Write(byte[] buffer, int offset, int count) 
 | 
        { 
 | 
            stream_.Write(buffer, offset, count); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Close the stream. 
 | 
        /// </summary> 
 | 
        /// <remarks> 
 | 
        /// The underlying stream is closed only if <see cref="IsStreamOwner"/> is true. 
 | 
        /// </remarks> 
 | 
        override public void Close() 
 | 
        { 
 | 
            Stream toClose = stream_; 
 | 
            stream_ = null; 
 | 
            if (isOwner_ && (toClose != null)) 
 | 
            { 
 | 
                isOwner_ = false; 
 | 
                toClose.Close(); 
 | 
            } 
 | 
        } 
 | 
        #endregion 
 | 
         
 | 
        // Write the local file header 
 | 
        // TODO: ZipHelperStream.WriteLocalHeader is not yet used and needs checking for ZipFile and ZipOuptutStream usage 
 | 
        void WriteLocalHeader(ZipEntry entry, EntryPatchData patchData)  
 | 
        { 
 | 
            CompressionMethod method = entry.CompressionMethod; 
 | 
            bool headerInfoAvailable = true; // How to get this? 
 | 
            bool patchEntryHeader = false; 
 | 
  
 | 
            WriteLEInt(ZipConstants.LocalHeaderSignature); 
 | 
             
 | 
            WriteLEShort(entry.Version); 
 | 
            WriteLEShort(entry.Flags); 
 | 
            WriteLEShort((byte)method); 
 | 
            WriteLEInt((int)entry.DosTime); 
 | 
  
 | 
            if (headerInfoAvailable == true) { 
 | 
                WriteLEInt((int)entry.Crc); 
 | 
                if ( entry.LocalHeaderRequiresZip64 ) { 
 | 
                    WriteLEInt(-1); 
 | 
                    WriteLEInt(-1); 
 | 
                } 
 | 
                else { 
 | 
                    WriteLEInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CryptoHeaderSize : (int)entry.CompressedSize); 
 | 
                    WriteLEInt((int)entry.Size); 
 | 
                } 
 | 
            } else { 
 | 
                if (patchData != null) { 
 | 
                    patchData.CrcPatchOffset = stream_.Position; 
 | 
                } 
 | 
                WriteLEInt(0);    // Crc 
 | 
                 
 | 
                if ( patchData != null ) { 
 | 
                    patchData.SizePatchOffset = stream_.Position; 
 | 
                } 
 | 
  
 | 
                // For local header both sizes appear in Zip64 Extended Information 
 | 
                if ( entry.LocalHeaderRequiresZip64 && patchEntryHeader ) { 
 | 
                    WriteLEInt(-1); 
 | 
                    WriteLEInt(-1); 
 | 
                } 
 | 
                else { 
 | 
                    WriteLEInt(0);    // Compressed size 
 | 
                    WriteLEInt(0);    // Uncompressed size 
 | 
                } 
 | 
            } 
 | 
  
 | 
            byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name); 
 | 
             
 | 
            if (name.Length > 0xFFFF) { 
 | 
                throw new ZipException("Entry name too long."); 
 | 
            } 
 | 
  
 | 
            ZipExtraData ed = new ZipExtraData(entry.ExtraData); 
 | 
  
 | 
            if (entry.LocalHeaderRequiresZip64 && (headerInfoAvailable || patchEntryHeader)) { 
 | 
                ed.StartNewEntry(); 
 | 
                if (headerInfoAvailable) { 
 | 
                    ed.AddLeLong(entry.Size); 
 | 
                    ed.AddLeLong(entry.CompressedSize); 
 | 
                } 
 | 
                else { 
 | 
                    ed.AddLeLong(-1); 
 | 
                    ed.AddLeLong(-1); 
 | 
                } 
 | 
                ed.AddNewEntry(1); 
 | 
  
 | 
                if ( !ed.Find(1) ) { 
 | 
                    throw new ZipException("Internal error cant find extra data"); 
 | 
                } 
 | 
                 
 | 
                if ( patchData != null ) { 
 | 
                    patchData.SizePatchOffset = ed.CurrentReadIndex; 
 | 
                } 
 | 
            } 
 | 
            else { 
 | 
                ed.Delete(1); 
 | 
            } 
 | 
             
 | 
            byte[] extra = ed.GetEntryData(); 
 | 
  
 | 
            WriteLEShort(name.Length); 
 | 
            WriteLEShort(extra.Length); 
 | 
  
 | 
            if ( name.Length > 0 ) { 
 | 
                stream_.Write(name, 0, name.Length); 
 | 
            } 
 | 
             
 | 
            if ( entry.LocalHeaderRequiresZip64 && patchEntryHeader ) { 
 | 
                patchData.SizePatchOffset += stream_.Position; 
 | 
            } 
 | 
  
 | 
            if ( extra.Length > 0 ) { 
 | 
                stream_.Write(extra, 0, extra.Length); 
 | 
            } 
 | 
        } 
 | 
     
 | 
        /// <summary> 
 | 
        /// Locates a block with the desired <paramref name="signature"/>. 
 | 
        /// </summary> 
 | 
        /// <param name="signature">The signature to find.</param> 
 | 
        /// <param name="endLocation">Location, marking the end of block.</param> 
 | 
        /// <param name="minimumBlockSize">Minimum size of the block.</param> 
 | 
        /// <param name="maximumVariableData">The maximum variable data.</param> 
 | 
        /// <returns>Eeturns the offset of the first byte after the signature; -1 if not found</returns> 
 | 
        public long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData) 
 | 
        { 
 | 
            long pos = endLocation - minimumBlockSize; 
 | 
            if ( pos < 0 ) { 
 | 
                return -1; 
 | 
            } 
 | 
  
 | 
            long giveUpMarker = Math.Max(pos - maximumVariableData, 0); 
 | 
  
 | 
            // TODO: This loop could be optimised for speed. 
 | 
            do { 
 | 
                if ( pos < giveUpMarker ) { 
 | 
                    return -1; 
 | 
                } 
 | 
                Seek(pos--, SeekOrigin.Begin); 
 | 
            } while ( ReadLEInt() != signature ); 
 | 
  
 | 
            return Position; 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Write Zip64 end of central directory records (File header and locator). 
 | 
        /// </summary> 
 | 
        /// <param name="noOfEntries">The number of entries in the central directory.</param> 
 | 
        /// <param name="sizeEntries">The size of entries in the central directory.</param> 
 | 
        /// <param name="centralDirOffset">The offset of the dentral directory.</param> 
 | 
        public void WriteZip64EndOfCentralDirectory(long noOfEntries, long sizeEntries, long centralDirOffset) 
 | 
        { 
 | 
            long centralSignatureOffset = stream_.Position; 
 | 
            WriteLEInt(ZipConstants.Zip64CentralFileHeaderSignature); 
 | 
            WriteLELong(44);    // Size of this record (total size of remaining fields in header or full size - 12) 
 | 
            WriteLEShort(ZipConstants.VersionMadeBy);   // Version made by 
 | 
            WriteLEShort(ZipConstants.VersionZip64);   // Version to extract 
 | 
            WriteLEInt(0);      // Number of this disk 
 | 
            WriteLEInt(0);      // number of the disk with the start of the central directory 
 | 
            WriteLELong(noOfEntries);       // No of entries on this disk 
 | 
            WriteLELong(noOfEntries);       // Total No of entries in central directory 
 | 
            WriteLELong(sizeEntries);       // Size of the central directory 
 | 
            WriteLELong(centralDirOffset);  // offset of start of central directory 
 | 
            // zip64 extensible data sector not catered for here (variable size) 
 | 
  
 | 
            // Write the Zip64 end of central directory locator 
 | 
            WriteLEInt(ZipConstants.Zip64CentralDirLocatorSignature); 
 | 
  
 | 
            // no of the disk with the start of the zip64 end of central directory 
 | 
            WriteLEInt(0); 
 | 
  
 | 
            // relative offset of the zip64 end of central directory record 
 | 
            WriteLELong(centralSignatureOffset); 
 | 
  
 | 
            // total number of disks 
 | 
            WriteLEInt(1); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Write the required records to end the central directory. 
 | 
        /// </summary> 
 | 
        /// <param name="noOfEntries">The number of entries in the directory.</param> 
 | 
        /// <param name="sizeEntries">The size of the entries in the directory.</param> 
 | 
        /// <param name="startOfCentralDirectory">The start of the central directory.</param> 
 | 
        /// <param name="comment">The archive comment.  (This can be null).</param> 
 | 
        public void WriteEndOfCentralDirectory(long noOfEntries, long sizeEntries, 
 | 
            long startOfCentralDirectory, byte[] comment) 
 | 
        { 
 | 
  
 | 
            if ( (noOfEntries >= 0xffff) || 
 | 
                (startOfCentralDirectory >= 0xffffffff) || 
 | 
                (sizeEntries >= 0xffffffff) ) { 
 | 
                WriteZip64EndOfCentralDirectory(noOfEntries, sizeEntries, startOfCentralDirectory); 
 | 
            } 
 | 
  
 | 
            WriteLEInt(ZipConstants.EndOfCentralDirectorySignature); 
 | 
  
 | 
            // TODO: ZipFile Multi disk handling not done 
 | 
            WriteLEShort(0);                    // number of this disk 
 | 
            WriteLEShort(0);                    // no of disk with start of central dir 
 | 
  
 | 
             
 | 
            // Number of entries 
 | 
            if ( noOfEntries >= 0xffff ) { 
 | 
                WriteLEUshort(0xffff);  // Zip64 marker 
 | 
                WriteLEUshort(0xffff); 
 | 
            } 
 | 
            else { 
 | 
                WriteLEShort(( short )noOfEntries);          // entries in central dir for this disk 
 | 
                WriteLEShort(( short )noOfEntries);          // total entries in central directory 
 | 
            } 
 | 
  
 | 
            // Size of the central directory 
 | 
            if ( sizeEntries >= 0xffffffff ) { 
 | 
                WriteLEUint(0xffffffff);    // Zip64 marker 
 | 
            } 
 | 
            else { 
 | 
                WriteLEInt(( int )sizeEntries);             
 | 
            } 
 | 
  
 | 
  
 | 
            // offset of start of central directory 
 | 
            if ( startOfCentralDirectory >= 0xffffffff ) { 
 | 
                WriteLEUint(0xffffffff);    // Zip64 marker 
 | 
            } 
 | 
            else { 
 | 
                WriteLEInt(( int )startOfCentralDirectory); 
 | 
            } 
 | 
  
 | 
            int commentLength = (comment != null) ? comment.Length : 0; 
 | 
  
 | 
            if ( commentLength > 0xffff ) { 
 | 
                throw new ZipException(string.Format("Comment length({0}) is too long can only be 64K", commentLength)); 
 | 
            } 
 | 
  
 | 
            WriteLEShort(commentLength); 
 | 
  
 | 
            if ( commentLength > 0 ) { 
 | 
                Write(comment, 0, comment.Length); 
 | 
            } 
 | 
        } 
 | 
  
 | 
        #region LE value reading/writing 
 | 
        /// <summary> 
 | 
        /// Read an unsigned short in little endian byte order. 
 | 
        /// </summary> 
 | 
        /// <returns>Returns the value read.</returns> 
 | 
        /// <exception cref="IOException"> 
 | 
        /// An i/o error occurs. 
 | 
        /// </exception> 
 | 
        /// <exception cref="EndOfStreamException"> 
 | 
        /// The file ends prematurely 
 | 
        /// </exception> 
 | 
        public int ReadLEShort() 
 | 
        { 
 | 
            int byteValue1 = stream_.ReadByte(); 
 | 
  
 | 
            if (byteValue1 < 0) { 
 | 
                throw new EndOfStreamException(); 
 | 
            } 
 | 
  
 | 
            int byteValue2 = stream_.ReadByte(); 
 | 
            if (byteValue2 < 0) { 
 | 
                throw new EndOfStreamException(); 
 | 
            } 
 | 
  
 | 
            return byteValue1 | (byteValue2 << 8); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Read an int in little endian byte order. 
 | 
        /// </summary> 
 | 
        /// <returns>Returns the value read.</returns> 
 | 
        /// <exception cref="IOException"> 
 | 
        /// An i/o error occurs. 
 | 
        /// </exception> 
 | 
        /// <exception cref="System.IO.EndOfStreamException"> 
 | 
        /// The file ends prematurely 
 | 
        /// </exception> 
 | 
        public int ReadLEInt() 
 | 
        { 
 | 
            return ReadLEShort() | (ReadLEShort() << 16); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Read a long in little endian byte order. 
 | 
        /// </summary> 
 | 
        /// <returns>The value read.</returns> 
 | 
        public long ReadLELong() 
 | 
        { 
 | 
            return (uint)ReadLEInt() | ((long)ReadLEInt() << 32); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Write an unsigned short in little endian byte order. 
 | 
        /// </summary> 
 | 
        /// <param name="value">The value to write.</param> 
 | 
        public void WriteLEShort(int value) 
 | 
        { 
 | 
            stream_.WriteByte(( byte )(value & 0xff)); 
 | 
            stream_.WriteByte(( byte )((value >> 8) & 0xff)); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Write a ushort in little endian byte order. 
 | 
        /// </summary> 
 | 
        /// <param name="value">The value to write.</param> 
 | 
        public void WriteLEUshort(ushort value) 
 | 
        { 
 | 
            stream_.WriteByte(( byte )(value & 0xff)); 
 | 
            stream_.WriteByte(( byte )(value >> 8)); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Write an int in little endian byte order. 
 | 
        /// </summary> 
 | 
        /// <param name="value">The value to write.</param> 
 | 
        public void WriteLEInt(int value) 
 | 
        { 
 | 
            WriteLEShort(value); 
 | 
            WriteLEShort(value >> 16); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Write a uint in little endian byte order. 
 | 
        /// </summary> 
 | 
        /// <param name="value">The value to write.</param> 
 | 
        public void WriteLEUint(uint value) 
 | 
        { 
 | 
            WriteLEUshort(( ushort )(value & 0xffff)); 
 | 
            WriteLEUshort(( ushort )(value >> 16)); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Write a long in little endian byte order. 
 | 
        /// </summary> 
 | 
        /// <param name="value">The value to write.</param> 
 | 
        public void WriteLELong(long value) 
 | 
        { 
 | 
            WriteLEInt(( int )value); 
 | 
            WriteLEInt(( int )(value >> 32)); 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Write a ulong in little endian byte order. 
 | 
        /// </summary> 
 | 
        /// <param name="value">The value to write.</param> 
 | 
        public void WriteLEUlong(ulong value) 
 | 
        { 
 | 
            WriteLEUint(( uint )(value & 0xffffffff)); 
 | 
            WriteLEUint(( uint )(value >> 32)); 
 | 
        } 
 | 
  
 | 
        #endregion 
 | 
  
 | 
        /// <summary> 
 | 
        /// Write a data descriptor. 
 | 
        /// </summary> 
 | 
        /// <param name="entry">The entry to write a descriptor for.</param> 
 | 
        /// <returns>Returns the number of descriptor bytes written.</returns> 
 | 
        public int WriteDataDescriptor(ZipEntry entry) 
 | 
        { 
 | 
            if (entry == null) { 
 | 
                throw new ArgumentNullException("entry"); 
 | 
            } 
 | 
  
 | 
            int result=0; 
 | 
  
 | 
            // Add data descriptor if flagged as required 
 | 
            if ((entry.Flags & (int)GeneralBitFlags.Descriptor) != 0) 
 | 
            { 
 | 
                // The signature is not PKZIP originally but is now described as optional 
 | 
                // in the PKZIP Appnote documenting trhe format. 
 | 
                WriteLEInt(ZipConstants.DataDescriptorSignature); 
 | 
                WriteLEInt(unchecked((int)(entry.Crc))); 
 | 
  
 | 
                result+=8; 
 | 
  
 | 
                if (entry.LocalHeaderRequiresZip64) 
 | 
                { 
 | 
                    WriteLELong(entry.CompressedSize); 
 | 
                    WriteLELong(entry.Size); 
 | 
                    result+=16; 
 | 
                } 
 | 
                else 
 | 
                { 
 | 
                    WriteLEInt((int)entry.CompressedSize); 
 | 
                    WriteLEInt((int)entry.Size); 
 | 
                    result+=8; 
 | 
                } 
 | 
            } 
 | 
  
 | 
            return result; 
 | 
        } 
 | 
  
 | 
        /// <summary> 
 | 
        /// Read data descriptor at the end of compressed data. 
 | 
        /// </summary> 
 | 
        /// <param name="zip64">if set to <c>true</c> [zip64].</param> 
 | 
        /// <param name="data">The data to fill in.</param> 
 | 
        /// <returns>Returns the number of bytes read in the descriptor.</returns> 
 | 
        public void ReadDataDescriptor(bool zip64, DescriptorData data) 
 | 
        { 
 | 
            int intValue = ReadLEInt(); 
 | 
  
 | 
            // In theory this may not be a descriptor according to PKZIP appnote. 
 | 
            // In practise its always there. 
 | 
            if (intValue != ZipConstants.DataDescriptorSignature) { 
 | 
                throw new ZipException("Data descriptor signature not found"); 
 | 
            } 
 | 
  
 | 
            data.Crc = ReadLEInt(); 
 | 
             
 | 
            if (zip64) { 
 | 
                data.CompressedSize = ReadLELong(); 
 | 
                data.Size = ReadLELong(); 
 | 
            } 
 | 
            else { 
 | 
                data.CompressedSize = ReadLEInt(); 
 | 
                data.Size = ReadLEInt(); 
 | 
            } 
 | 
        } 
 | 
  
 | 
        #region Instance Fields 
 | 
        bool isOwner_; 
 | 
        Stream stream_; 
 | 
        #endregion 
 | 
    } 
 | 
} 
 |