ZForge.Zip.ZipEntry.WriteHeader C# (CSharp) Method

WriteHeader() private method

private WriteHeader ( System s, byte bytes ) : void
s System
bytes byte
return void
        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 = 0x08; // 0x08 = Deflate, 0x00 == No Compression

            // 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
            {
                // 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 length = (Int16)FileName.Length;
            // see note below about TrimVolumeFromFullyQualifiedPaths.
            if ((TrimVolumeFromFullyQualifiedPaths) && (FileName[1] == ':') && (FileName[2] == '\\')) length -= 3;
            bytes[i++] = (byte)(length & 0x00FF);
            bytes[i++] = (byte)((length & 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];
        }