private void WriteHeader(System.IO.Stream s, byte[] bytes) { // write the header info int i = 0; // signature bytes[i++] = (byte)(ZipEntrySignature & 0x000000FF); bytes[i++] = (byte)((ZipEntrySignature & 0x0000FF00) >> 8); bytes[i++] = (byte)((ZipEntrySignature & 0x00FF0000) >> 16); bytes[i++] = (byte)((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); // compression method Int16 CompressionMethod = 0x08; // 0x08 = Deflate 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); // 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 & 0x000000FF); bytes[i++] = (byte)((crc & 0x0000FF00) >> 8); bytes[i++] = (byte)((crc & 0x00FF0000) >> 16); bytes[i++] = (byte)((crc & 0xFF000000) >> 24); // CompressedSize (Int32) Int32 isz = (Int32)_UnderlyingMemoryStream.Length; UInt32 sz = (UInt32)isz; bytes[i++] = (byte)(sz & 0x000000FF); bytes[i++] = (byte)((sz & 0x0000FF00) >> 8); bytes[i++] = (byte)((sz & 0x00FF0000) >> 16); bytes[i++] = (byte)((sz & 0xFF000000) >> 24); // UncompressedSize (Int32) if (_Debug) { System.Console.WriteLine("Uncompressed Size: {0}", crc32.TotalBytesRead); } bytes[i++] = (byte)(crc32.TotalBytesRead & 0x000000FF); bytes[i++] = (byte)((crc32.TotalBytesRead & 0x0000FF00) >> 8); bytes[i++] = (byte)((crc32.TotalBytesRead & 0x00FF0000) >> 16); bytes[i++] = (byte)((crc32.TotalBytesRead & 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]; } }
private void WriteHeader(System.IO.Stream s, byte[] bytes) { // write the header info int i = 0; // signature bytes[i++] = (byte)(ZipEntrySignature & 0x000000FF); bytes[i++] = (byte)((ZipEntrySignature & 0x0000FF00) >> 8); bytes[i++] = (byte)((ZipEntrySignature & 0x00FF0000) >> 16); bytes[i++] = (byte)((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); // compression method Int16 CompressionMethod = 0x08; // 0x08 = Deflate 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); // 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 & 0x000000FF); bytes[i++] = (byte)((crc & 0x0000FF00) >> 8); bytes[i++] = (byte)((crc & 0x00FF0000) >> 16); bytes[i++] = (byte)((crc & 0xFF000000) >> 24); // CompressedSize (Int32) Int32 isz = (Int32)_UnderlyingMemoryStream.Length; UInt32 sz = (UInt32)isz; bytes[i++] = (byte)(sz & 0x000000FF); bytes[i++] = (byte)((sz & 0x0000FF00) >> 8); bytes[i++] = (byte)((sz & 0x00FF0000) >> 16); bytes[i++] = (byte)((sz & 0xFF000000) >> 24); // UncompressedSize (Int32) if (_Debug) System.Console.WriteLine("Uncompressed Size: {0}", crc32.TotalBytesRead); bytes[i++] = (byte)(crc32.TotalBytesRead & 0x000000FF); bytes[i++] = (byte)((crc32.TotalBytesRead & 0x0000FF00) >> 8); bytes[i++] = (byte)((crc32.TotalBytesRead & 0x00FF0000) >> 16); bytes[i++] = (byte)((crc32.TotalBytesRead & 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]; }