Esempio n. 1
0
        private void WriteHeader(System.IO.Stream s, byte[] bytes)
        {
            // write the header info

            int i = 0;

            // signature
            bytes[i++] = (byte)(ZipConstants.ZipEntrySignature & 0x000000FF);
            bytes[i++] = (byte)((ZipConstants.ZipEntrySignature & 0x0000FF00) >> 8);
            bytes[i++] = (byte)((ZipConstants.ZipEntrySignature & 0x00FF0000) >> 16);
            bytes[i++] = (byte)((ZipConstants.ZipEntrySignature & 0xFF000000) >> 24);

            // version needed
            Int16 FixedVersionNeeded = 0x14; // from examining existing zip files

            bytes[i++] = (byte)(FixedVersionNeeded & 0x00FF);
            bytes[i++] = (byte)((FixedVersionNeeded & 0xFF00) >> 8);

            // bitfield
            Int16 BitField = 0x00; // from examining existing zip files

            bytes[i++] = (byte)(BitField & 0x00FF);
            bytes[i++] = (byte)((BitField & 0xFF00) >> 8);

            Int16 CompressionMethod = 0x00; // 0x08 = Deflate, 0x00 == No Compression

            // compression for directories = 0x00 (No Compression)

            if (!IsDirectory)
            {
                CompressionMethod = 0x08;
                // CRC32 (Int32)
                if (_FileData != null)
                {
                    // If we have FileData, that means we've read this entry from an
                    // existing zip archive. We must just copy the existing file data,
                    // CRC, compressed size, and uncompressed size
                    // over to the new (updated) archive.
                }
                else
                {
                    // special case zero-length files
                    System.IO.FileInfo fi = new System.IO.FileInfo(LocalFileName);
                    if (fi.Length == 0)
                    {
                        CompressionMethod = 0x00;
                        _UncompressedSize = 0;
                        _CompressedSize   = 0;
                        _Crc32            = 0;
                    }
                    else
                    {
                        // Read in the data from the file in the filesystem, comress it, and
                        // calculate a CRC on it as we read.

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

                        _UncompressedSize = crc32.TotalBytesRead;
                        _CompressedSize   = (Int32)_UnderlyingMemoryStream.Length;

                        // It is possible that applying this stream compression on a previously compressed
                        // file will actually increase the size of the data.  In that case, we back-off
                        // and just store the uncompressed (really, already compressed) data.
                        // We need to recompute the CRC, and point to the right data.
                        if (_CompressedSize > _UncompressedSize)
                        {
                            using (System.IO.Stream input = System.IO.File.OpenRead(LocalFileName))
                            {
                                _UnderlyingMemoryStream = new System.IO.MemoryStream();
                                UInt32 crc = crc32.GetCrc32AndCopy(input, _UnderlyingMemoryStream);
                                _Crc32 = (Int32)crc;
                            }
                            _UncompressedSize = crc32.TotalBytesRead;
                            _CompressedSize   = (Int32)_UnderlyingMemoryStream.Length;
                            if (_CompressedSize != _UncompressedSize)
                            {
                                throw new Exception("No compression but unequal stream lengths!");
                            }
                            CompressionMethod = 0x00;
                        }
                    }
                }
            }
            // compression method
            bytes[i++] = (byte)(CompressionMethod & 0x00FF);
            bytes[i++] = (byte)((CompressionMethod & 0xFF00) >> 8);

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

            // calculated above
            bytes[i++] = (byte)(_Crc32 & 0x000000FF);
            bytes[i++] = (byte)((_Crc32 & 0x0000FF00) >> 8);
            bytes[i++] = (byte)((_Crc32 & 0x00FF0000) >> 16);
            bytes[i++] = (byte)((_Crc32 & 0xFF000000) >> 24);

            // CompressedSize (Int32)
            bytes[i++] = (byte)(_CompressedSize & 0x000000FF);
            bytes[i++] = (byte)((_CompressedSize & 0x0000FF00) >> 8);
            bytes[i++] = (byte)((_CompressedSize & 0x00FF0000) >> 16);
            bytes[i++] = (byte)((_CompressedSize & 0xFF000000) >> 24);

            // UncompressedSize (Int32)
            if (_Debug)
            {
                System.Console.WriteLine("Uncompressed Size: {0}", _UncompressedSize);
            }
            bytes[i++] = (byte)(_UncompressedSize & 0x000000FF);
            bytes[i++] = (byte)((_UncompressedSize & 0x0000FF00) >> 8);
            bytes[i++] = (byte)((_UncompressedSize & 0x00FF0000) >> 16);
            bytes[i++] = (byte)((_UncompressedSize & 0xFF000000) >> 24);

            // filename length (Int16)
            Int16 filenameLength = (Int16)FileName.Length;

            // see note below about TrimVolumeFromFullyQualifiedPaths.
            if ((TrimVolumeFromFullyQualifiedPaths) && (FileName[1] == ':') && (FileName[2] == '\\'))
            {
                filenameLength -= 3;
            }
            // apply upper bound to the length
            if (filenameLength + i > bytes.Length)
            {
                filenameLength = (Int16)(bytes.Length - (Int16)i);
            }
            bytes[i++] = (byte)(filenameLength & 0x00FF);
            bytes[i++] = (byte)((filenameLength & 0xFF00) >> 8);

            // extra field length (short)
            Int16 ExtraFieldLength = 0x00;

            bytes[i++] = (byte)(ExtraFieldLength & 0x00FF);
            bytes[i++] = (byte)((ExtraFieldLength & 0xFF00) >> 8);

            // Tue, 27 Mar 2007  16:35

            // Creating a zip that contains entries with "fully qualified" pathnames
            // can result in a zip archive that is unreadable by Windows Explorer.
            // Such archives are valid according to other tools but not to explorer.
            // To avoid this, we can trim off the leading volume name and slash (eg
            // c:\) when creating (writing) a zip file.  We do this by default and we
            // leave the old behavior available with the
            // TrimVolumeFromFullyQualifiedPaths flag - set it to false to get the old
            // behavior.  It only affects zip creation.

            // actual filename
            char[] c = ((TrimVolumeFromFullyQualifiedPaths) && (FileName[1] == ':') && (FileName[2] == '\\')) ?
                       FileName.Substring(3).ToCharArray() : // trim off volume letter, colon, and slash
                       FileName.ToCharArray();
            int j = 0;

            if (_Debug)
            {
                System.Console.WriteLine("local header: writing filename, {0} chars", c.Length);
                System.Console.WriteLine("starting offset={0}", i);
            }

            for (j = 0; (j < c.Length) && (i + j < bytes.Length); j++)
            {
                bytes[i + j] = System.BitConverter.GetBytes(c[j])[0];
                if (_Debug)
                {
                    System.Console.Write(" {0:X2}", bytes[i + j]);
                }
            }
            if (_Debug)
            {
                System.Console.WriteLine();
            }

            i += j;

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

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

            if (_Debug)
            {
                System.Console.WriteLine("\nAll header data:");
                for (j = 0; j < i; j++)
                {
                    System.Console.Write(" {0:X2}", bytes[j]);
                }
                System.Console.WriteLine();
            }
            // 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[i];
            if (_Debug)
            {
                System.Console.WriteLine("preserving header of {0} bytes", _header.Length);
            }
            for (j = 0; j < i; j++)
            {
                _header[j] = bytes[j];
            }
        }
Esempio n. 2
0
 private void WriteHeader(Stream s, byte[] bytes)
 {
     int num = 0;
     bytes[num++] = 80;
     bytes[num++] = 0x4b;
     bytes[num++] = 3;
     bytes[num++] = 4;
     short num2 = 20;
     bytes[num++] = (byte) (num2 & 0xff);
     bytes[num++] = (byte) ((num2 & 0xff00) >> 8);
     short num3 = 0;
     bytes[num++] = (byte) (num3 & 0xff);
     bytes[num++] = (byte) ((num3 & 0xff00) >> 8);
     short num4 = 0;
     if (!this.IsDirectory)
     {
         num4 = 8;
         if (this._FileData == null)
         {
             FileInfo info = new FileInfo(this.LocalFileName);
             if (info.Length == 0L)
             {
                 num4 = 0;
                 this._UncompressedSize = 0;
                 this._CompressedSize = 0;
                 this._Crc32 = 0;
             }
             else
             {
                 Stream stream;
                 uint num5;
                 CRC32 crc = new CRC32();
                 using (stream = File.OpenRead(this.LocalFileName))
                 {
                     num5 = crc.GetCrc32AndCopy(stream, this.CompressedStream);
                     this._Crc32 = (int) num5;
                 }
                 this.CompressedStream.Close();
                 this._CompressedStream = null;
                 this._UncompressedSize = crc.TotalBytesRead;
                 this._CompressedSize = (int) this._UnderlyingMemoryStream.Length;
                 if (this._CompressedSize > this._UncompressedSize)
                 {
                     using (stream = File.OpenRead(this.LocalFileName))
                     {
                         this._UnderlyingMemoryStream = new MemoryStream();
                         num5 = crc.GetCrc32AndCopy(stream, this._UnderlyingMemoryStream);
                         this._Crc32 = (int) num5;
                     }
                     this._UncompressedSize = crc.TotalBytesRead;
                     this._CompressedSize = (int) this._UnderlyingMemoryStream.Length;
                     if (this._CompressedSize != this._UncompressedSize)
                     {
                         throw new Exception("No compression but unequal stream lengths!");
                     }
                     num4 = 0;
                 }
             }
         }
     }
     bytes[num++] = (byte) (num4 & 0xff);
     bytes[num++] = (byte) ((num4 & 0xff00) >> 8);
     bytes[num++] = (byte) (this._LastModDateTime & 0xff);
     bytes[num++] = (byte) ((this._LastModDateTime & 0xff00) >> 8);
     bytes[num++] = (byte) ((this._LastModDateTime & 0xff0000) >> 0x10);
     bytes[num++] = (byte) ((this._LastModDateTime & 0xff000000L) >> 0x18);
     bytes[num++] = (byte) (this._Crc32 & 0xff);
     bytes[num++] = (byte) ((this._Crc32 & 0xff00) >> 8);
     bytes[num++] = (byte) ((this._Crc32 & 0xff0000) >> 0x10);
     bytes[num++] = (byte) ((this._Crc32 & 0xff000000L) >> 0x18);
     bytes[num++] = (byte) (this._CompressedSize & 0xff);
     bytes[num++] = (byte) ((this._CompressedSize & 0xff00) >> 8);
     bytes[num++] = (byte) ((this._CompressedSize & 0xff0000) >> 0x10);
     bytes[num++] = (byte) ((this._CompressedSize & 0xff000000L) >> 0x18);
     if (this._Debug)
     {
         Console.WriteLine("Uncompressed Size: {0}", this._UncompressedSize);
     }
     bytes[num++] = (byte) (this._UncompressedSize & 0xff);
     bytes[num++] = (byte) ((this._UncompressedSize & 0xff00) >> 8);
     bytes[num++] = (byte) ((this._UncompressedSize & 0xff0000) >> 0x10);
     bytes[num++] = (byte) ((this._UncompressedSize & 0xff000000L) >> 0x18);
     short length = (short) this.FileName.Length;
     if ((this.TrimVolumeFromFullyQualifiedPaths && (this.FileName[1] == ':')) && (this.FileName[2] == '\\'))
     {
         length = (short) (length - 3);
     }
     if ((length + num) > bytes.Length)
     {
         length = (short) (bytes.Length - ((short) num));
     }
     bytes[num++] = (byte) (length & 0xff);
     bytes[num++] = (byte) ((length & 0xff00) >> 8);
     short num7 = 0;
     bytes[num++] = (byte) (num7 & 0xff);
     bytes[num++] = (byte) ((num7 & 0xff00) >> 8);
     char[] chArray = ((this.TrimVolumeFromFullyQualifiedPaths && (this.FileName[1] == ':')) && (this.FileName[2] == '\\')) ? this.FileName.Substring(3).Replace(@"\", "/").ToCharArray() : this.FileName.Replace(@"\", "/").ToCharArray();
     int index = 0;
     if (this._Debug)
     {
         Console.WriteLine("local header: writing filename, {0} chars", chArray.Length);
         Console.WriteLine("starting offset={0}", num);
     }
     index = 0;
     while ((index < chArray.Length) && ((num + index) < bytes.Length))
     {
         bytes[num + index] = BitConverter.GetBytes(chArray[index])[0];
         if (this._Debug)
         {
             Console.Write(" {0:X2}", bytes[num + index]);
         }
         index++;
     }
     if (this._Debug)
     {
         Console.WriteLine();
     }
     num += index;
     this._RelativeOffsetOfHeader = (int) s.Length;
     if (this._Debug)
     {
         Console.WriteLine("\nAll header data:");
         for (index = 0; index < num; index++)
         {
             Console.Write(" {0:X2}", bytes[index]);
         }
         Console.WriteLine();
     }
     s.Write(bytes, 0, num);
     this._header = new byte[num];
     if (this._Debug)
     {
         Console.WriteLine("preserving header of {0} bytes", this._header.Length);
     }
     for (index = 0; index < num; index++)
     {
         this._header[index] = bytes[index];
     }
 }
Esempio n. 3
0
        private void WriteHeader(Stream s, byte[] bytes)
        {
            int num = 0;

            bytes[num++] = 80;
            bytes[num++] = 0x4b;
            bytes[num++] = 3;
            bytes[num++] = 4;
            short num2 = 20;

            bytes[num++] = (byte)(num2 & 0xff);
            bytes[num++] = (byte)((num2 & 0xff00) >> 8);
            short num3 = 0;

            bytes[num++] = (byte)(num3 & 0xff);
            bytes[num++] = (byte)((num3 & 0xff00) >> 8);
            short num4 = 0;

            if (!this.IsDirectory)
            {
                num4 = 8;
                if (this._FileData == null)
                {
                    FileInfo info = new FileInfo(this.LocalFileName);
                    if (info.Length == 0L)
                    {
                        num4 = 0;
                        this._UncompressedSize = 0;
                        this._CompressedSize   = 0;
                        this._Crc32            = 0;
                    }
                    else
                    {
                        Stream stream;
                        uint   num5;
                        CRC32  crc = new CRC32();
                        using (stream = File.OpenRead(this.LocalFileName))
                        {
                            num5        = crc.GetCrc32AndCopy(stream, this.CompressedStream);
                            this._Crc32 = (int)num5;
                        }
                        this.CompressedStream.Close();
                        this._CompressedStream = null;
                        this._UncompressedSize = crc.TotalBytesRead;
                        this._CompressedSize   = (int)this._UnderlyingMemoryStream.Length;
                        if (this._CompressedSize > this._UncompressedSize)
                        {
                            using (stream = File.OpenRead(this.LocalFileName))
                            {
                                this._UnderlyingMemoryStream = new MemoryStream();
                                num5        = crc.GetCrc32AndCopy(stream, this._UnderlyingMemoryStream);
                                this._Crc32 = (int)num5;
                            }
                            this._UncompressedSize = crc.TotalBytesRead;
                            this._CompressedSize   = (int)this._UnderlyingMemoryStream.Length;
                            if (this._CompressedSize != this._UncompressedSize)
                            {
                                throw new Exception("No compression but unequal stream lengths!");
                            }
                            num4 = 0;
                        }
                    }
                }
            }
            bytes[num++] = (byte)(num4 & 0xff);
            bytes[num++] = (byte)((num4 & 0xff00) >> 8);
            bytes[num++] = (byte)(this._LastModDateTime & 0xff);
            bytes[num++] = (byte)((this._LastModDateTime & 0xff00) >> 8);
            bytes[num++] = (byte)((this._LastModDateTime & 0xff0000) >> 0x10);
            bytes[num++] = (byte)((this._LastModDateTime & 0xff000000L) >> 0x18);
            bytes[num++] = (byte)(this._Crc32 & 0xff);
            bytes[num++] = (byte)((this._Crc32 & 0xff00) >> 8);
            bytes[num++] = (byte)((this._Crc32 & 0xff0000) >> 0x10);
            bytes[num++] = (byte)((this._Crc32 & 0xff000000L) >> 0x18);
            bytes[num++] = (byte)(this._CompressedSize & 0xff);
            bytes[num++] = (byte)((this._CompressedSize & 0xff00) >> 8);
            bytes[num++] = (byte)((this._CompressedSize & 0xff0000) >> 0x10);
            bytes[num++] = (byte)((this._CompressedSize & 0xff000000L) >> 0x18);
            if (this._Debug)
            {
                Console.WriteLine("Uncompressed Size: {0}", this._UncompressedSize);
            }
            bytes[num++] = (byte)(this._UncompressedSize & 0xff);
            bytes[num++] = (byte)((this._UncompressedSize & 0xff00) >> 8);
            bytes[num++] = (byte)((this._UncompressedSize & 0xff0000) >> 0x10);
            bytes[num++] = (byte)((this._UncompressedSize & 0xff000000L) >> 0x18);
            short length = (short)this.FileName.Length;

            if ((this.TrimVolumeFromFullyQualifiedPaths && (this.FileName[1] == ':')) && (this.FileName[2] == '\\'))
            {
                length = (short)(length - 3);
            }
            if ((length + num) > bytes.Length)
            {
                length = (short)(bytes.Length - ((short)num));
            }
            bytes[num++] = (byte)(length & 0xff);
            bytes[num++] = (byte)((length & 0xff00) >> 8);
            short num7 = 0;

            bytes[num++] = (byte)(num7 & 0xff);
            bytes[num++] = (byte)((num7 & 0xff00) >> 8);
            char[] chArray = ((this.TrimVolumeFromFullyQualifiedPaths && (this.FileName[1] == ':')) && (this.FileName[2] == '\\')) ? this.FileName.Substring(3).Replace(@"\", "/").ToCharArray() : this.FileName.Replace(@"\", "/").ToCharArray();
            int    index   = 0;

            if (this._Debug)
            {
                Console.WriteLine("local header: writing filename, {0} chars", chArray.Length);
                Console.WriteLine("starting offset={0}", num);
            }
            index = 0;
            while ((index < chArray.Length) && ((num + index) < bytes.Length))
            {
                bytes[num + index] = BitConverter.GetBytes(chArray[index])[0];
                if (this._Debug)
                {
                    Console.Write(" {0:X2}", bytes[num + index]);
                }
                index++;
            }
            if (this._Debug)
            {
                Console.WriteLine();
            }
            num += index;
            this._RelativeOffsetOfHeader = (int)s.Length;
            if (this._Debug)
            {
                Console.WriteLine("\nAll header data:");
                for (index = 0; index < num; index++)
                {
                    Console.Write(" {0:X2}", bytes[index]);
                }
                Console.WriteLine();
            }
            s.Write(bytes, 0, num);
            this._header = new byte[num];
            if (this._Debug)
            {
                Console.WriteLine("preserving header of {0} bytes", this._header.Length);
            }
            for (index = 0; index < num; index++)
            {
                this._header[index] = bytes[index];
            }
        }
Esempio n. 4
0
        private void WriteHeader(System.IO.Stream s, byte[] bytes)
        {
            // write the header info

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

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

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

            Int16 CompressionMethod = 0x00; // 0x08 = Deflate, 0x00 == No Compression

            // compression for directories = 0x00 (No Compression)

            if (!IsDirectory)
            {
                CompressionMethod = 0x08;
                // CRC32 (Int32)
                if (_FileData != null)
                {
                    // If we have FileData, that means we've read this entry from an
                    // existing zip archive. We must just copy the existing file data,
                    // CRC, compressed size, and uncompressed size
                    // over to the new (updated) archive.
                }
                else
                {
                    // special case zero-length files
                    System.IO.FileInfo fi = new System.IO.FileInfo(LocalFileName);
                    if (fi.Length == 0)
                    {
                        CompressionMethod = 0x00;
                        _UncompressedSize = 0;
                        _CompressedSize = 0;
                        _Crc32 = 0;
                    }
                    else
                    {
                        // Read in the data from the file in the filesystem, comress it, and
                        // calculate a CRC on it as we read.

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

                        _UncompressedSize = crc32.TotalBytesRead;
                        _CompressedSize = (Int32)_UnderlyingMemoryStream.Length;

                        // It is possible that applying this stream compression on a previously compressed
                        // file will actually increase the size of the data.  In that case, we back-off
                        // and just store the uncompressed (really, already compressed) data.
                        // We need to recompute the CRC, and point to the right data.
                        if (_CompressedSize > _UncompressedSize)
                        {
                            using (System.IO.Stream input = System.IO.File.OpenRead(LocalFileName))
                            {
                                _UnderlyingMemoryStream = new System.IO.MemoryStream();
                                UInt32 crc = crc32.GetCrc32AndCopy(input, _UnderlyingMemoryStream);
                                _Crc32 = (Int32)crc;
                            }
                            _UncompressedSize = crc32.TotalBytesRead;
                            _CompressedSize = (Int32)_UnderlyingMemoryStream.Length;
                            if (_CompressedSize != _UncompressedSize) throw new Exception("No compression but unequal stream lengths!");
                            CompressionMethod = 0x00;
                        }
                    }
                }
            }
            // compression method
            bytes[i++] = (byte)(CompressionMethod & 0x00FF);
            bytes[i++] = (byte)((CompressionMethod & 0xFF00) >> 8);

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

            // calculated above
            bytes[i++] = (byte)(_Crc32 & 0x000000FF);
            bytes[i++] = (byte)((_Crc32 & 0x0000FF00) >> 8);
            bytes[i++] = (byte)((_Crc32 & 0x00FF0000) >> 16);
            bytes[i++] = (byte)((_Crc32 & 0xFF000000) >> 24);

            // CompressedSize (Int32)
            bytes[i++] = (byte)(_CompressedSize & 0x000000FF);
            bytes[i++] = (byte)((_CompressedSize & 0x0000FF00) >> 8);
            bytes[i++] = (byte)((_CompressedSize & 0x00FF0000) >> 16);
            bytes[i++] = (byte)((_CompressedSize & 0xFF000000) >> 24);

            // UncompressedSize (Int32)
            if (_Debug) System.Console.WriteLine("Uncompressed Size: {0}", _UncompressedSize);
            bytes[i++] = (byte)(_UncompressedSize & 0x000000FF);
            bytes[i++] = (byte)((_UncompressedSize & 0x0000FF00) >> 8);
            bytes[i++] = (byte)((_UncompressedSize & 0x00FF0000) >> 16);
            bytes[i++] = (byte)((_UncompressedSize & 0xFF000000) >> 24);

            // filename length (Int16)
            Int16 filenameLength = (Int16)FileName.Length;
            // see note below about TrimVolumeFromFullyQualifiedPaths.
            if ((TrimVolumeFromFullyQualifiedPaths) && (FileName[1] == ':') && (FileName[2] == '\\')) filenameLength -= 3;
            // apply upper bound to the length
            if (filenameLength + i > bytes.Length) filenameLength = (Int16)(bytes.Length - (Int16)i);
            bytes[i++] = (byte)(filenameLength & 0x00FF);
            bytes[i++] = (byte)((filenameLength & 0xFF00) >> 8);

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

            // Tue, 27 Mar 2007  16:35

            // Creating a zip that contains entries with "fully qualified" pathnames
            // can result in a zip archive that is unreadable by Windows Explorer.
            // Such archives are valid according to other tools but not to explorer.
            // To avoid this, we can trim off the leading volume name and slash (eg
            // c:\) when creating (writing) a zip file.  We do this by default and we
            // leave the old behavior available with the
            // TrimVolumeFromFullyQualifiedPaths flag - set it to false to get the old
            // behavior.  It only affects zip creation.

            // actual filename
            char[] c = ((TrimVolumeFromFullyQualifiedPaths) && (FileName[1] == ':') && (FileName[2] == '\\')) ?
              FileName.Substring(3).ToCharArray() :  // trim off volume letter, colon, and slash
              FileName.ToCharArray();
            int j = 0;

            if (_Debug)
            {
                System.Console.WriteLine("local header: writing filename, {0} chars", c.Length);
                System.Console.WriteLine("starting offset={0}", i);
            }

            for (j = 0; (j < c.Length) && (i + j < bytes.Length); j++)
            {
                bytes[i + j] = System.BitConverter.GetBytes(c[j])[0];
                if (_Debug) System.Console.Write(" {0:X2}", bytes[i + j]);
            }
            if (_Debug) System.Console.WriteLine();

            i += j;

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

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

            if (_Debug)
            {
                System.Console.WriteLine("\nAll header data:");
                for (j = 0; j < i; j++)
                    System.Console.Write(" {0:X2}", bytes[j]);
                System.Console.WriteLine();
            }
            // 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[i];
            if (_Debug) System.Console.WriteLine("preserving header of {0} bytes", _header.Length);
            for (j = 0; j < i; j++)
                _header[j] = bytes[j];
        }