This class reads and writes zip files

image_pdfimage_print
   
 

// Zip.cs
//
// This class reads and writes zip files, according to the format
// described by pkware, at:
// http://international.us.server12.fileserver.kutayzorlu.com/files/download/2017/01/appnote_uuid-f6697e18-9683-4981-88cb-985b2f5dd1e6_crc-0.txt
//
// This implementation is based on the
// System.IO.Compression.DeflateStream base class in the .NET Framework
// v2.0 base class library.
//
// There are other Zip class libraries available.  For example, it is
// possible to read and write zip files within .NET via the J# runtime.
// But some people don't like to install the extra DLL.  Also, there is
// a 3rd party LGPL-based (or is it GPL?) library called SharpZipLib,
// which works, in both .NET 1.1 and .NET 2.0.  But some people don't
// like the GPL. Finally, there are commercial tools (From ComponentOne,
// XCeed, etc).  But some people don't want to incur the cost.
//
// This alternative implementation is not GPL licensed, is free of cost,
// and does not require J#.
//
// It does require .NET 2.0 (for the DeflateStream class).  
//
// Notes:
// This is at best a cripppled and naive implementation. 
//
// Bugs:
// 1. does not do 0..9 compression levels (not supported by DeflateStream)
// 2. does not do encryption
// 3. no support for reading or writing multi-disk zip archives
// 4. no support for file comments or archive comments
// 5. does not stream as it compresses; all compressed data is kept in memory.
// 6. no support for double-byte chars in filenames
// 7. no support for asynchronous operation
// 
// But it does read and write basic zip files, and it gets reasonable compression. 
//
// NB: PKWare's zip specification states: 
//
// ----------------------
//   PKWARE is committed to the interoperability and advancement of the
//   .ZIP format.  PKWARE offers a free license for certain technological
//   aspects described above under certain restrictions and conditions.
//   However, the use or implementation in a product of certain technological
//   aspects set forth in the current APPNOTE, including those with regard to
//   strong encryption or patching, requires a license from PKWARE.  Please 
//   contact PKWARE with regard to acquiring a license.
// ----------------------
//    
// Fri, 31 Mar 2006  14:43
//

using System;
using System.IO;
using System.IO.Compression;

namespace ionic.utils.zip
{
    /// <summary>
    /// Calculates a 32bit Cyclic Redundancy Checksum (CRC) using the
    /// same polynomial used by Zip.
    /// </summary>
    public class CRC32
    {
        private UInt32[] crc32Table;
        private const int BUFFER_SIZE = 8192;

        private Int32 _TotalBytesRead = 0;
        public Int32 TotalBytesRead
        {
            get
            {
                return _TotalBytesRead;
            }
        }

        /// <summary>
        /// Returns the CRC32 for the specified stream.
        /// </summary>
        /// <param name="input">The stream over which to calculate the CRC32</param>
        /// <returns>the CRC32 calculation</returns>
        public UInt32 GetCrc32(System.IO.Stream input)
        {
            return GetCrc32AndCopy(input, null);
        }

        /// <summary>
        /// Returns the CRC32 for the specified stream, and writes the input into the output stream.
        /// </summary>
        /// <param name="input">The stream over which to calculate the CRC32</param>
        /// <param name="output">The stream into which to deflate the input</param>
        /// <returns>the CRC32 calculation</returns>
        public UInt32 GetCrc32AndCopy(System.IO.Stream input, System.IO.Stream output)
        {
            unchecked
            {
                UInt32 crc32Result;
                crc32Result = 0xFFFFFFFF;
                byte[] buffer = new byte[BUFFER_SIZE];
                int readSize = BUFFER_SIZE;

                _TotalBytesRead = 0;
                int count = input.Read(buffer, 0, readSize);
                if (output != null) output.Write(buffer, 0, count);
                _TotalBytesRead += count;
                while (count > 0)
                {
                    for (int i = 0; i < count; i++)
                    {
                        crc32Result = ((crc32Result) >> 8) ^ crc32Table[(buffer[i]) ^ ((crc32Result) &amp; 0x000000FF)];
                    }
                    count = input.Read(buffer, 0, readSize);
                    if (output != null) output.Write(buffer, 0, count);
                    _TotalBytesRead += count;

                }

                return ~crc32Result;
            }
        }


        /// <summary>
        /// Construct an instance of the CRC32 class, pre-initialising the table
        /// for speed of lookup.
        /// </summary>
        public CRC32()
        {
            unchecked
            {
                // This is the official polynomial used by CRC32 in PKZip.
                // Often the polynomial is shown reversed as 0x04C11DB7.
                UInt32 dwPolynomial = 0xEDB88320;
                UInt32 i, j;

                crc32Table = new UInt32[256];

                UInt32 dwCrc;
                for (i = 0; i < 256; i++)
                {
                    dwCrc = i;
                    for (j = 8; j > 0; j--)
                    {
                        if ((dwCrc &amp; 1) == 1)
                        {
                            dwCrc = (dwCrc >> 1) ^ dwPolynomial;
                        }
                        else
                        {
                            dwCrc >>= 1;
                        }
                    }
                    crc32Table[i] = dwCrc;
                }
            }
        }
    }

    class Utils
    {
        protected internal static string StringFromBuffer(byte[] buf, int start, int maxlength)
        {
            int i;
            char[] c = new char[maxlength];
            for (i = 0; (i < maxlength) &amp;&amp; (i < buf.Length) &amp;&amp; (buf&#91;i&#93; != 0); i++)
            {
                c&#91;i&#93; = (char)buf&#91;i&#93;; // System.BitConverter.ToChar(buf, start+i*2);
            }
            string s = new System.String(c, 0, i);
            return s;
        }

        protected internal static int ReadSignature(System.IO.Stream s)
        {
            int n = 0;
            byte&#91;&#93; sig = new byte&#91;4&#93;;
            n = s.Read(sig, 0, sig.Length);
            int signature = (((sig&#91;3&#93; * 256 + sig&#91;2&#93;) * 256) + sig&#91;1&#93;) * 256 + sig&#91;0&#93;;
            return signature;
        }

        protected internal static DateTime PackedToDateTime(Int32 packedDateTime)
        {
            Int16 packedTime = (Int16)(packedDateTime &amp; 0x0000ffff);
            Int16 packedDate = (Int16)((packedDateTime &amp; 0xffff0000) >> 16);

            int year = 1980 + ((packedDate &amp; 0xFE00) >> 9);
            int month = (packedDate &amp; 0x01E0) >> 5;
            int day = packedDate &amp; 0x001F;


            int hour = (packedTime &amp; 0xF800) >> 11;
            int minute = (packedTime &amp; 0x07E0) >> 5;
            int second = packedTime &amp; 0x001F;

            DateTime d = System.DateTime.Now;
            try { d = new System.DateTime(year, month, day, hour, minute, second, 0); }
            catch
            {
                Console.Write("
Invalid date/time?:
year: {0} ", year);
                Console.Write("month: {0} ", month);
                Console.WriteLine("day: {0} ", day);
                Console.WriteLine("HH:MM:SS= {0}:{1}:{2}", hour, minute, second);
            }

            return d;
        }


        protected internal static Int32 DateTimeToPacked(DateTime time)
        {
            UInt16 packedDate = (UInt16)((time.Day &amp; 0x0000001F) | ((time.Month << 5) &amp; 0x000001E0) | (((time.Year - 1980) << 9) &amp; 0x0000FE00));
            UInt16 packedTime = (UInt16)((time.Second &amp; 0x0000001F) | ((time.Minute << 5) &amp; 0x000007E0) | ((time.Hour << 11) &amp; 0x0000F800));
            return (Int32)(((UInt32)(packedDate << 16)) | packedTime);
        }
    }





    public class ZipDirEntry
    {

        internal const int ZipDirEntrySignature = 0x02014b50;

        private bool _Debug = false;

        private ZipDirEntry() { }

        private DateTime _LastModified;
        public DateTime LastModified
        {
            get { return _LastModified; }
        }

        private string _FileName;
        public string FileName
        {
            get { return _FileName; }
        }

        private string _Comment;
        public string Comment
        {
            get { return _Comment; }
        }

        private Int16 _VersionMadeBy;
        public Int16 VersionMadeBy
        {
            get { return _VersionMadeBy; }
        }

        private Int16 _VersionNeeded;
        public Int16 VersionNeeded
        {
            get { return _VersionNeeded; }
        }

        private Int16 _CompressionMethod;
        public Int16 CompressionMethod
        {
            get { return _CompressionMethod; }
        }

        private Int32 _CompressedSize;
        public Int32 CompressedSize
        {
            get { return _CompressedSize; }
        }

        private Int32 _UncompressedSize;
        public Int32 UncompressedSize
        {
            get { return _UncompressedSize; }
        }


        private Int16 _BitField;
        private Int32 _LastModDateTime;

        private Int32 _Crc32;
        private byte&#91;&#93; _Extra;

        internal ZipDirEntry(ZipEntry ze) { }


        public static ZipDirEntry Read(System.IO.Stream s)
        {
            return Read(s, false);
        }


        public static ZipDirEntry Read(System.IO.Stream s, bool TurnOnDebug)
        {
            int signature = Utils.ReadSignature(s);
            // return null if this is not a local file header signature
            if (SignatureIsNotValid(signature))
            {
                s.Seek(-4, System.IO.SeekOrigin.Current);
                return null;
            }

            byte&#91;&#93; block = new byte&#91;42&#93;;
            int n = s.Read(block, 0, block.Length);
            if (n != block.Length) return null;

            int i = 0;
            ZipDirEntry zde = new ZipDirEntry();

            zde._Debug = TurnOnDebug;
            zde._VersionMadeBy = (short)(block&#91;i++&#93; + block&#91;i++&#93; * 256);
            zde._VersionNeeded = (short)(block&#91;i++&#93; + block&#91;i++&#93; * 256);
            zde._BitField = (short)(block&#91;i++&#93; + block&#91;i++&#93; * 256);
            zde._CompressionMethod = (short)(block&#91;i++&#93; + block&#91;i++&#93; * 256);
            zde._LastModDateTime = block&#91;i++&#93; + block&#91;i++&#93; * 256 + block&#91;i++&#93; * 256 * 256 + block&#91;i++&#93; * 256 * 256 * 256;
            zde._Crc32 = block&#91;i++&#93; + block&#91;i++&#93; * 256 + block&#91;i++&#93; * 256 * 256 + block&#91;i++&#93; * 256 * 256 * 256;
            zde._CompressedSize = block&#91;i++&#93; + block&#91;i++&#93; * 256 + block&#91;i++&#93; * 256 * 256 + block&#91;i++&#93; * 256 * 256 * 256;
            zde._UncompressedSize = block&#91;i++&#93; + block&#91;i++&#93; * 256 + block&#91;i++&#93; * 256 * 256 + block&#91;i++&#93; * 256 * 256 * 256;

            zde._LastModified = Utils.PackedToDateTime(zde._LastModDateTime);

            Int16 filenameLength = (short)(block&#91;i++&#93; + block&#91;i++&#93; * 256);
            Int16 extraFieldLength = (short)(block&#91;i++&#93; + block&#91;i++&#93; * 256);
            Int16 commentLength = (short)(block&#91;i++&#93; + block&#91;i++&#93; * 256);
            Int16 diskNumber = (short)(block&#91;i++&#93; + block&#91;i++&#93; * 256);
            Int16 internalFileAttrs = (short)(block&#91;i++&#93; + block&#91;i++&#93; * 256);
            Int32 externalFileAttrs = block&#91;i++&#93; + block&#91;i++&#93; * 256 + block&#91;i++&#93; * 256 * 256 + block&#91;i++&#93; * 256 * 256 * 256;
            Int32 Offset = block&#91;i++&#93; + block&#91;i++&#93; * 256 + block&#91;i++&#93; * 256 * 256 + block&#91;i++&#93; * 256 * 256 * 256;

            block = new byte&#91;filenameLength&#93;;
            n = s.Read(block, 0, block.Length);
            zde._FileName = Utils.StringFromBuffer(block, 0, block.Length);

            zde._Extra = new byte&#91;extraFieldLength&#93;;
            n = s.Read(zde._Extra, 0, zde._Extra.Length);

            block = new byte&#91;commentLength&#93;;
            n = s.Read(block, 0, block.Length);
            zde._Comment = Utils.StringFromBuffer(block, 0, block.Length);

            return zde;
        }

        private static bool SignatureIsNotValid(int signature)
        {
            return (signature != ZipDirEntrySignature);
        }

    }

    public class ZipEntry
    {
        private const int ZipEntrySignature = 0x04034b50;

        private DateTime _LastModified;
        public DateTime LastModified
        {
            get { return _LastModified; }
        }

        private string _FileName;
        public string FileName
        {
            get { return _FileName; }
        }

        private Int16 _VersionNeeded;
        public Int16 VersionNeeded
        {
            get { return _VersionNeeded; }
        }

        private Int16 _BitField;
        public Int16 BitField
        {
            get { return _BitField; }
        }

        private Int16 _CompressionMethod;
        public Int16 CompressionMethod
        {
            get { return _CompressionMethod; }
        }

        private Int32 _CompressedSize;
        public Int32 CompressedSize
        {
            get { return _CompressedSize; }
        }

        private Int32 _UncompressedSize;
        public Int32 UncompressedSize
        {
            get { return _UncompressedSize; }
        }

        private Int32 _LastModDateTime;
        private Int32 _Crc32;
        private byte&#91;&#93; _Extra;

        private byte&#91;&#93; __filedata;
        private byte&#91;&#93; _FileData
        {
            get
            {
                if (__filedata == null)
                {
                }
                return __filedata;
            }
        }

        private System.IO.MemoryStream _UnderlyingMemoryStream;
        private System.IO.Compression.DeflateStream _CompressedStream;
        private System.IO.Compression.DeflateStream CompressedStream
        {
            get
            {
                if (_CompressedStream == null)
                {
                    _UnderlyingMemoryStream = new System.IO.MemoryStream();
                    bool LeaveUnderlyingStreamOpen = true;
                    _CompressedStream = new System.IO.Compression.DeflateStream(_UnderlyingMemoryStream,
                                      System.IO.Compression.CompressionMode.Compress,
                                      LeaveUnderlyingStreamOpen);
                }
                return _CompressedStream;
            }
        }

        private byte&#91;&#93; _header;
        internal byte&#91;&#93; Header
        {
            get
            {
                return _header;
            }
        }

        private int _RelativeOffsetOfHeader;


        private static bool ReadHeader(System.IO.Stream s, ZipEntry ze)
        {
            int signature = Utils.ReadSignature(s);

            // return null if this is not a local file header signature
            if (SignatureIsNotValid(signature))
            {
                s.Seek(-4, System.IO.SeekOrigin.Current);
                return false;
            }

            byte&#91;&#93; block = new byte&#91;26&#93;;
            int n = s.Read(block, 0, block.Length);
            if (n != block.Length) return false;

            int i = 0;
            ze._VersionNeeded = (short)(block&#91;i++&#93; + block&#91;i++&#93; * 256);
            ze._BitField = (short)(block&#91;i++&#93; + block&#91;i++&#93; * 256);
            ze._CompressionMethod = (short)(block&#91;i++&#93; + block&#91;i++&#93; * 256);
            ze._LastModDateTime = block&#91;i++&#93; + block&#91;i++&#93; * 256 + block&#91;i++&#93; * 256 * 256 + block&#91;i++&#93; * 256 * 256 * 256;
            ze._Crc32 = block&#91;i++&#93; + block&#91;i++&#93; * 256 + block&#91;i++&#93; * 256 * 256 + block&#91;i++&#93; * 256 * 256 * 256;
            ze._CompressedSize = block&#91;i++&#93; + block&#91;i++&#93; * 256 + block&#91;i++&#93; * 256 * 256 + block&#91;i++&#93; * 256 * 256 * 256;
            ze._UncompressedSize = block&#91;i++&#93; + block&#91;i++&#93; * 256 + block&#91;i++&#93; * 256 * 256 + block&#91;i++&#93; * 256 * 256 * 256;

            Int16 filenameLength = (short)(block&#91;i++&#93; + block&#91;i++&#93; * 256);
            Int16 extraFieldLength = (short)(block&#91;i++&#93; + block&#91;i++&#93; * 256);

            ze._LastModified = Utils.PackedToDateTime(ze._LastModDateTime);

            block = new byte&#91;filenameLength&#93;;
            n = s.Read(block, 0, block.Length);
            ze._FileName = Utils.StringFromBuffer(block, 0, block.Length);

            ze._Extra = new byte&#91;extraFieldLength&#93;;
            n = s.Read(ze._Extra, 0, ze._Extra.Length);

            return true;
        }


        private static bool SignatureIsNotValid(int signature)
        {
            return (signature != ZipEntrySignature);
        }

        public static ZipEntry Read(System.IO.Stream s)
        {
            ZipEntry entry = new ZipEntry();
            if (!ReadHeader(s, entry)) return null;

            entry.__filedata = new byte&#91;entry.CompressedSize&#93;;
            int n = s.Read(entry._FileData, 0, entry._FileData.Length);
            if (n != entry._FileData.Length)
            {
                throw new Exception("badly formatted zip file.");
            }

            return entry;
        }

        internal static ZipEntry Create(String filename)
        {
            ZipEntry entry = new ZipEntry();
            entry._FileName = filename;

            entry._LastModified = System.IO.File.GetLastWriteTime(filename);
            if (entry._LastModified.IsDaylightSavingTime())
            {
                System.DateTime AdjustedTime = entry._LastModified - new System.TimeSpan(1, 0, 0);
                entry._LastModDateTime = Utils.DateTimeToPacked(AdjustedTime);
            }
            else
                entry._LastModDateTime = Utils.DateTimeToPacked(entry._LastModified);

            // we don&#039;t actually slurp in the file until the caller invokes Write on this entry.

            return entry;
        }

        public void Extract()
        {
            Extract(".");
        }

        public bool Extract(Stream output)
        {
            try
            {
                using (MemoryStream memstream = new MemoryStream(_FileData))
                {
                    using (DeflateStream input = new DeflateStream(memstream, CompressionMode.Decompress))
                    {
                        byte&#91;&#93; bytes = new byte&#91;4096&#93;;
                        int n;

                        n = 1;
                        while (n != 0)
                        {
                            n = input.Read(bytes, 0, bytes.Length);

                            if (n > 0)
                                output.Write(bytes, 0, n);
                        }

                        return true;
                    }
                }
            }
            catch (Exception)
            {
                output.Write(_FileData, 0, _FileData.Length);
                return false;
            }
        }

        public void Extract(string basedir)
        {
            string TargetFile = System.IO.Path.Combine(basedir, FileName);

            using (System.IO.MemoryStream memstream = new System.IO.MemoryStream(_FileData))
            {

                using (System.IO.Compression.DeflateStream input =
                      new System.IO.Compression.DeflateStream(memstream, System.IO.Compression.CompressionMode.Decompress))
                {

                    // ensure the target path exists
                    if (!System.IO.Directory.Exists(System.IO.Path.GetDirectoryName(TargetFile)))
                    {
                        System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(TargetFile));
                    }

                    using (System.IO.FileStream output = new System.IO.FileStream(TargetFile, System.IO.FileMode.CreateNew))
                    {
                        //BinaryWriter w = new BinaryWriter(fs);

                        byte[] bytes = new byte[4096];
                        int n;

                        n = 1; // anything non-zero
                        while (n != 0)
                        {
                            n = input.Read(bytes, 0, bytes.Length);

                            if (n > 0)
                                output.Write(bytes, 0, n);
                        }
                    }

                    if (LastModified.IsDaylightSavingTime())
                        System.IO.File.SetLastWriteTime(TargetFile, LastModified.AddHours(1));
                    else
                        System.IO.File.SetLastWriteTime(TargetFile, LastModified);

                }
            }
        }


        internal void WriteCentralDirectoryEntry(System.IO.Stream s)
        {
            byte[] bytes = new byte[4096];
            int i = 0;
            // signature
            bytes[i++] = (byte)(ZipDirEntry.ZipDirEntrySignature &amp; 0x000000FF);
            bytes[i++] = (byte)((ZipDirEntry.ZipDirEntrySignature &amp; 0x0000FF00) >> 8);
            bytes[i++] = (byte)((ZipDirEntry.ZipDirEntrySignature &amp; 0x00FF0000) >> 16);
            bytes[i++] = (byte)((ZipDirEntry.ZipDirEntrySignature &amp; 0xFF000000) >> 24);

            // Version Made By
            bytes[i++] = Header[4];
            bytes[i++] = Header[5];

            // Version Needed, Bitfield, compression method, lastmod,
            // crc, sizes, filename length and extra field length -
            // are all the same as the local file header. So just copy them
            int j = 0;
            for (j = 0; j < 26; j++)
                bytes&#91;i + j&#93; = Header&#91;4 + j&#93;;

            i += j;  // positioned at next available byte

            // File Comment Length
            bytes&#91;i++&#93; = 0;
            bytes&#91;i++&#93; = 0;

            // Disk number start
            bytes&#91;i++&#93; = 0;
            bytes&#91;i++&#93; = 0;

            // internal file attrs
            // TODO: figure out what is required here. 
            bytes&#91;i++&#93; = 1;
            bytes&#91;i++&#93; = 0;

            // external file attrs
            // TODO: figure out what is required here. 
            bytes&#91;i++&#93; = 0x20;
            bytes&#91;i++&#93; = 0;
            bytes&#91;i++&#93; = 0xb6;
            bytes&#91;i++&#93; = 0x81;

            // relative offset of local header (I think this can be zero)
            bytes&#91;i++&#93; = (byte)(_RelativeOffsetOfHeader &amp; 0x000000FF);
            bytes&#91;i++&#93; = (byte)((_RelativeOffsetOfHeader &amp; 0x0000FF00) >> 8);
            bytes[i++] = (byte)((_RelativeOffsetOfHeader &amp; 0x00FF0000) >> 16);
            bytes[i++] = (byte)((_RelativeOffsetOfHeader &amp; 0xFF000000) >> 24);

            // actual filename (starts at offset 34 in header) 
            for (j = 0; j < Header.Length - 30; j++)
                bytes&#91;i + j&#93; = Header&#91;30 + j&#93;;

            i += j;

            s.Write(bytes, 0, i);
        }


        private void WriteHeader(System.IO.Stream s, byte&#91;&#93; bytes)
        {
            // write the header info

            int i = 0;
            // signature
            bytes&#91;i++&#93; = (byte)(ZipEntrySignature &amp; 0x000000FF);
            bytes&#91;i++&#93; = (byte)((ZipEntrySignature &amp; 0x0000FF00) >> 8);
            bytes[i++] = (byte)((ZipEntrySignature &amp; 0x00FF0000) >> 16);
            bytes[i++] = (byte)((ZipEntrySignature &amp; 0xFF000000) >> 24);

            // version needed
            Int16 FixedVersionNeeded = 0x14; // from examining existing zip files
            bytes[i++] = (byte)(FixedVersionNeeded &amp; 0x00FF);
            bytes[i++] = (byte)((FixedVersionNeeded &amp; 0xFF00) >> 8);

            // bitfield
            Int16 BitField = 0x00; // from examining existing zip files
            bytes[i++] = (byte)(BitField &amp; 0x00FF);
            bytes[i++] = (byte)((BitField &amp; 0xFF00) >> 8);

            // compression method
            Int16 CompressionMethod = 0x08; // 0x08 = Deflate
            bytes[i++] = (byte)(CompressionMethod &amp; 0x00FF);
            bytes[i++] = (byte)((CompressionMethod &amp; 0xFF00) >> 8);

            // LastMod
            bytes[i++] = (byte)(_LastModDateTime &amp; 0x000000FF);
            bytes[i++] = (byte)((_LastModDateTime &amp; 0x0000FF00) >> 8);
            bytes[i++] = (byte)((_LastModDateTime &amp; 0x00FF0000) >> 16);
            bytes[i++] = (byte)((_LastModDateTime &amp; 0xFF000000) >> 24);

            // CRC32 (Int32)
            CRC32 crc32 = new CRC32();
            UInt32 crc = 0;
            using (System.IO.Stream input = System.IO.File.OpenRead(FileName))
            {
                crc = crc32.GetCrc32AndCopy(input, CompressedStream);
            }
            CompressedStream.Close();  // to get the footer bytes written to the underlying stream

            bytes[i++] = (byte)(crc &amp; 0x000000FF);
            bytes[i++] = (byte)((crc &amp; 0x0000FF00) >> 8);
            bytes[i++] = (byte)((crc &amp; 0x00FF0000) >> 16);
            bytes[i++] = (byte)((crc &amp; 0xFF000000) >> 24);

            // CompressedSize (Int32)
            Int32 isz = (Int32)_UnderlyingMemoryStream.Length;
            UInt32 sz = (UInt32)isz;
            bytes[i++] = (byte)(sz &amp; 0x000000FF);
            bytes[i++] = (byte)((sz &amp; 0x0000FF00) >> 8);
            bytes[i++] = (byte)((sz &amp; 0x00FF0000) >> 16);
            bytes[i++] = (byte)((sz &amp; 0xFF000000) >> 24);

            // UncompressedSize (Int32)
            bytes[i++] = (byte)(crc32.TotalBytesRead &amp; 0x000000FF);
            bytes[i++] = (byte)((crc32.TotalBytesRead &amp; 0x0000FF00) >> 8);
            bytes[i++] = (byte)((crc32.TotalBytesRead &amp; 0x00FF0000) >> 16);
            bytes[i++] = (byte)((crc32.TotalBytesRead &amp; 0xFF000000) >> 24);

            // filename length (Int16)
            Int16 length = (Int16)FileName.Length;
            bytes[i++] = (byte)(length &amp; 0x00FF);
            bytes[i++] = (byte)((length &amp; 0xFF00) >> 8);

            // extra field length (short)
            Int16 ExtraFieldLength = 0x00;
            bytes[i++] = (byte)(ExtraFieldLength &amp; 0x00FF);
            bytes[i++] = (byte)((ExtraFieldLength &amp; 0xFF00) >> 8);

            // actual filename
            char[] c = FileName.ToCharArray();
            int j = 0;

            for (j = 0; (j < c.Length) &amp;&amp; (i + j < bytes.Length); j++)
                bytes&#91;i + j&#93; = System.BitConverter.GetBytes(c&#91;j&#93;)&#91;0&#93;;

            i += j;

            // extra field (we always write null in this implementation)
            // ;;

            // remember the file offset of this header
            _RelativeOffsetOfHeader = (int)s.Length;

            // finally, write the header to the stream
            s.Write(bytes, 0, i);

            // preserve this header data for use with the central directory structure.
            _header = new byte&#91;i&#93;;

            for (j = 0; j < i; j++)
                _header&#91;j&#93; = bytes&#91;j&#93;;
        }


        internal void Write(System.IO.Stream s)
        {
            byte&#91;&#93; bytes = new byte&#91;4096&#93;;
            int n;

            // write the header:
            WriteHeader(s, bytes);

            // write the actual file data: 
            _UnderlyingMemoryStream.Position = 0;

            while ((n = _UnderlyingMemoryStream.Read(bytes, 0, bytes.Length)) != 0)
                s.Write(bytes, 0, n);

            //_CompressedStream.Close();
            //_CompressedStream= null;
            _UnderlyingMemoryStream.Close();
            _UnderlyingMemoryStream = null;
        }
    }

    public class ZipFile : System.Collections.Generic.IEnumerable<ZipEntry>, IDisposable
    {
        private string _name;
        public string Name
        {
            get { return _name; }
        }

        private System.IO.Stream ReadStream
        {
            get
            {
                return _readstream;
            }
        }

        private System.IO.FileStream WriteStream
        {
            get
            {
                if (_writestream == null)
                {
                    _writestream = new System.IO.FileStream(_name, System.IO.FileMode.CreateNew);
                }
                return _writestream;
            }
        }

        private ZipFile() { }


        #region For Writing Zip Files

        public ZipFile(string NewZipFileName)
        {
            // create a new zipfile
            _name = NewZipFileName;
            if (System.IO.File.Exists(_name))
                throw new System.Exception("That file already exists.");
            _entries = new System.Collections.Generic.List<ZipEntry>();
        }


        public void AddFile(string FileName)
        {
            ZipEntry ze = ZipEntry.Create(FileName);
            _entries.Add(ze);
        }

        public void AddDirectory(string DirectoryName)
        {
            String[] filenames = System.IO.Directory.GetFiles(DirectoryName);
            foreach (String filename in filenames)
                AddFile(filename);

            String[] dirnames = System.IO.Directory.GetDirectories(DirectoryName);
            foreach (String dir in dirnames)
                AddDirectory(dir);
        }


        public void Save()
        {
            // an entry for each file
            foreach (ZipEntry e in _entries)
            {
                e.Write(WriteStream);
            }

            WriteCentralDirectoryStructure();
            WriteStream.Close();
            _writestream = null;
        }


        private void WriteCentralDirectoryStructure()
        {
            // the central directory structure
            long Start = WriteStream.Length;
            foreach (ZipEntry e in _entries)
            {
                e.WriteCentralDirectoryEntry(WriteStream);
            }
            long Finish = WriteStream.Length;

            // now, the footer
            WriteCentralDirectoryFooter(Start, Finish);
        }


        private void WriteCentralDirectoryFooter(long StartOfCentralDirectory, long EndOfCentralDirectory)
        {
            byte[] bytes = new byte[1024];
            int i = 0;
            // signature
            UInt32 EndOfCentralDirectorySignature = 0x06054b50;
            bytes[i++] = (byte)(EndOfCentralDirectorySignature &amp; 0x000000FF);
            bytes[i++] = (byte)((EndOfCentralDirectorySignature &amp; 0x0000FF00) >> 8);
            bytes[i++] = (byte)((EndOfCentralDirectorySignature &amp; 0x00FF0000) >> 16);
            bytes[i++] = (byte)((EndOfCentralDirectorySignature &amp; 0xFF000000) >> 24);

            // number of this disk
            bytes[i++] = 0;
            bytes[i++] = 0;

            // number of the disk with the start of the central directory
            bytes[i++] = 0;
            bytes[i++] = 0;

            // total number of entries in the central dir on this disk
            bytes[i++] = (byte)(_entries.Count &amp; 0x00FF);
            bytes[i++] = (byte)((_entries.Count &amp; 0xFF00) >> 8);

            // total number of entries in the central directory
            bytes[i++] = (byte)(_entries.Count &amp; 0x00FF);
            bytes[i++] = (byte)((_entries.Count &amp; 0xFF00) >> 8);

            // size of the central directory
            Int32 SizeOfCentralDirectory = (Int32)(EndOfCentralDirectory - StartOfCentralDirectory);
            bytes[i++] = (byte)(SizeOfCentralDirectory &amp; 0x000000FF);
            bytes[i++] = (byte)((SizeOfCentralDirectory &amp; 0x0000FF00) >> 8);
            bytes[i++] = (byte)((SizeOfCentralDirectory &amp; 0x00FF0000) >> 16);
            bytes[i++] = (byte)((SizeOfCentralDirectory &amp; 0xFF000000) >> 24);

            // offset of the start of the central directory 
            Int32 StartOffset = (Int32)StartOfCentralDirectory;  // cast down from Long
            bytes[i++] = (byte)(StartOffset &amp; 0x000000FF);
            bytes[i++] = (byte)((StartOffset &amp; 0x0000FF00) >> 8);
            bytes[i++] = (byte)((StartOffset &amp; 0x00FF0000) >> 16);
            bytes[i++] = (byte)((StartOffset &amp; 0xFF000000) >> 24);

            // zip comment length
            bytes[i++] = 0;
            bytes[i++] = 0;

            WriteStream.Write(bytes, 0, i);
        }

        #endregion

        #region For Reading Zip Files

        /// <summary>
        /// This will throw if the zipfile does not exist. 
        /// </summary>
        public static ZipFile Read(Stream zipstream)
        {
            ZipFile zf = new ZipFile();
            zf._readstream = zipstream;
            zf._entries = new System.Collections.Generic.List<ZipEntry>();
            ZipEntry e;
            while ((e = ZipEntry.Read(zf.ReadStream)) != null)
            {
                zf._entries.Add(e);
            }

            // read the zipfile&#039;s central directory structure here.
            zf._direntries = new System.Collections.Generic.List<ZipDirEntry>();

            ZipDirEntry de;
            while ((de = ZipDirEntry.Read(zf.ReadStream)) != null) { }

            zf._direntries.Add(de);

            return zf;
        }

        public System.Collections.Generic.IEnumerator<ZipEntry> GetEnumerator()
        {
            foreach (ZipEntry e in _entries)
                yield return e;
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }


        public void ExtractAll(string path)
        {
            foreach (ZipEntry e in _entries)
            {
                e.Extract(path);
            }
        }


        public void Extract(string filename)
        {
            this[filename].Extract();
        }


        public ZipEntry this[String filename]
        {
            get
            {
                foreach (ZipEntry e in _entries)
                {
                    if (e.FileName == filename) return e;
                }
                return null;
            }
        }

        #endregion




        // the destructor
        ~ZipFile()
        {
            // call Dispose with false.  Since we&#039;re in the
            // destructor call, the managed resources will be
            // disposed of anyways.
            Dispose(false);
        }

        public void Dispose()
        {
            // dispose of the managed and unmanaged resources
            Dispose(true);

            // tell the GC that the Finalize process no longer needs
            // to be run for this object.
            GC.SuppressFinalize(this);
        }


        protected virtual void Dispose(bool disposeManagedResources)
        {
            if (!this._disposed)
            {
                if (disposeManagedResources)
                {
                    // dispose managed resources
                    if (_readstream != null)
                    {
                        _readstream.Dispose();
                        _readstream = null;
                    }
                    if (_writestream != null)
                    {
                        _writestream.Dispose();
                        _writestream = null;
                    }
                }
                this._disposed = true;
            }
        }


        private System.IO.Stream _readstream;
        private System.IO.FileStream _writestream;
        private bool _disposed = false;
        private System.Collections.Generic.List<ZipEntry> _entries = null;
        private System.Collections.Generic.List<ZipDirEntry> _direntries = null;
    }
}

   
     


This entry was posted in File Stream. Bookmark the permalink.