public ZipFileHeader(ZipFileInfo fileInfo, bool zip64) : this() { this.flags = ZipFileFlags.None; this.compressionMethod = fileInfo.CompressionMethod; this.fileName = Path.Combine(fileInfo.Path, fileInfo.Name); CompressionEngine.DateTimeToDosDateAndTime( fileInfo.LastWriteTime, out this.lastModDate, out this.lastModTime); this.zip64 = zip64; if (this.zip64) { this.compressedSize = UInt32.MaxValue; this.uncompressedSize = UInt32.MaxValue; this.diskStart = UInt16.MaxValue; this.versionMadeBy = 45; this.versionNeeded = 45; ZipExtraFileField field = new ZipExtraFileField(); field.fieldType = ZipExtraFileFieldType.ZIP64; field.SetZip64Data( fileInfo.CompressedLength, fileInfo.Length, 0, fileInfo.ArchiveNumber); this.extraFields = new ZipExtraFileField[] { field }; } else { this.compressedSize = (uint) fileInfo.CompressedLength; this.uncompressedSize = (uint) fileInfo.Length; this.diskStart = (ushort) fileInfo.ArchiveNumber; } }
internal uint Write(Stream outputStream, ZipCompressionMethod compression) { byte[] bytes = Encoding.UTF8.GetBytes(this.FileName); byte[] buffer = Encoding.UTF8.GetBytes(this.Comment); outputStream.Write(new byte[] { 80, 0x4b, 1, 2, 0x3f, 0, 10, 0 }, 0, 8); HeaderFlags flags = HeaderFlags.UTF8; if (!outputStream.CanSeek) { flags = (HeaderFlags)((ushort)(flags | HeaderFlags.UsePostDataDescriptor)); if (compression == ZipCompressionMethod.LZMA) { flags = (HeaderFlags)((ushort)(flags | HeaderFlags.Bit1)); } } outputStream.Write(BitConverter.GetBytes((ushort)flags), 0, 2); outputStream.Write(BitConverter.GetBytes((ushort)compression), 0, 2); outputStream.Write(BitConverter.GetBytes(Utility.DateTimeToDosTime(this.ModificationTime)), 0, 4); outputStream.Write(BitConverter.GetBytes(this.Crc), 0, 4); outputStream.Write(BitConverter.GetBytes(this.Compressed), 0, 4); outputStream.Write(BitConverter.GetBytes(this.Decompressed), 0, 4); outputStream.Write(BitConverter.GetBytes((ushort)bytes.Length), 0, 2); outputStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); outputStream.Write(BitConverter.GetBytes((ushort)buffer.Length), 0, 2); outputStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); outputStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); outputStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); outputStream.Write(BitConverter.GetBytes((ushort)0x8100), 0, 2); outputStream.Write(BitConverter.GetBytes(this.HeaderOffset), 0, 4); outputStream.Write(bytes, 0, bytes.Length); outputStream.Write(buffer, 0, buffer.Length); return((uint)((0x2e + bytes.Length) + buffer.Length)); }
public ZipCentralDirectoryEntry(ZipCompressionMethod compression, string fileName, ulong headerOffset, Encoding forceEncoding) { this.compression = compression; this.fileName = fileName; HeaderOffset = headerOffset; this.forceEncoding = forceEncoding; }
public ZipFileHeader(ZipFileInfo fileInfo, bool zip64) : this() { this.flags = ZipFileFlags.None; this.compressionMethod = fileInfo.CompressionMethod; this.fileName = Path.Combine(fileInfo.Path, fileInfo.Name); CompressionEngine.DateTimeToDosDateAndTime( fileInfo.LastWriteTime, out this.lastModDate, out this.lastModTime); this.zip64 = zip64; if (this.zip64) { this.compressedSize = UInt32.MaxValue; this.uncompressedSize = UInt32.MaxValue; this.diskStart = UInt16.MaxValue; this.versionMadeBy = 45; this.versionNeeded = 45; ZipExtraFileField field = new ZipExtraFileField(); field.fieldType = ZipExtraFileFieldType.ZIP64; field.SetZip64Data( fileInfo.CompressedLength, fileInfo.Length, 0, fileInfo.ArchiveNumber); this.extraFields = new ZipExtraFileField[] { field }; } else { this.compressedSize = (uint)fileInfo.CompressedLength; this.uncompressedSize = (uint)fileInfo.Length; this.diskStart = (ushort)fileInfo.ArchiveNumber; } }
public ZipCompressionInfo(CompressionInfo compressionInfo) { switch (compressionInfo.Type) { case CompressionType.None: { this.Compression = ZipCompressionMethod.None; } break; case CompressionType.Deflate: { this.DeflateCompressionLevel = compressionInfo.DeflateCompressionLevel; this.Compression = ZipCompressionMethod.Deflate; } break; case CompressionType.BZip2: { this.Compression = ZipCompressionMethod.BZip2; } break; case CompressionType.LZMA: { this.Compression = ZipCompressionMethod.LZMA; } break; case CompressionType.PPMd: { this.Compression = ZipCompressionMethod.PPMd; } break; default: throw new InvalidFormatException("Invalid compression method: " + compressionInfo.Type); } }
virtual protected void ReadHeader(Stream source) { var reader = new BinaryReader(source); int fileNameLength; int extraFieldLength; var enc = encoding437; Version = reader.ReadInt16(); Flags = reader.ReadInt16(); Compression = (ZipCompressionMethod)reader.ReadInt16(); LastModifiedTime = reader.ReadInt16(); LastModifiedDate = reader.ReadInt16(); Crc32 = reader.ReadInt32(); CompressedSize = reader.ReadInt32(); UncompressedSize = reader.ReadInt32(); fileNameLength = reader.ReadInt16(); extraFieldLength = reader.ReadInt16(); ExtraData = new List <ZipExtraField>(); if (UseUTF8) { enc = encodingUTF8; } if (fileNameLength > 0) { Filename = enc.GetString(reader.ReadBytes(fileNameLength)); } else { Filename = ""; } while (extraFieldLength > 0) { // load extra data int id = reader.ReadInt16(); int fieldLength = reader.ReadInt16(); ZipExtraField zef = new ZipExtraField(id, reader.ReadBytes(fieldLength)); extraFieldLength -= fieldLength + 4; ExtraData.Add(zef); } foreach (var data in ExtraData) { using (MemoryStream dataMem = new MemoryStream(data.Data)) { BinaryReader dataReader = new BinaryReader(dataMem); switch (data.Id) { case 1: // ZIP64 UncompressedSize = dataReader.ReadInt64(); CompressedSize = dataReader.ReadInt64(); break; } } } Offset = source.Position; }
internal ZipWritingStream(ZipWriter writer, Stream originalStream, ZipCentralDirectoryEntry entry, ZipCompressionMethod zipCompressionMethod, CompressionLevel compressionLevel) { this.writer = writer; this.originalStream = originalStream; this.writer = writer; this.entry = entry; this.zipCompressionMethod = zipCompressionMethod; this.compressionLevel = compressionLevel; writeStream = GetWriteStream(originalStream); }
/// <summary> /// Creates a new ZipFileInfo object with all parameters specified, /// used internally when reading the metadata out of a zip archive. /// </summary> /// <param name="filePath">The internal path and name of the file in the zip archive.</param> /// <param name="zipNumber">The zip archive number where the file starts.</param> /// <param name="attributes">The stored attributes of the file.</param> /// <param name="lastWriteTime">The stored last write time of the file.</param> /// <param name="length">The uncompressed size of the file.</param> /// <param name="compressedLength">The compressed size of the file.</param> /// <param name="compressionMethod">Compression algorithm used for this file.</param> internal ZipFileInfo( string filePath, int zipNumber, FileAttributes attributes, DateTime lastWriteTime, long length, long compressedLength, ZipCompressionMethod compressionMethod) : base(filePath, zipNumber, attributes, lastWriteTime, length) { this.compressedLength = compressedLength; this.compressionMethod = compressionMethod; }
/// <summary> /// Registers a delegate that can create a warpper stream for /// compressing or uncompressing the data of a source stream. /// </summary> /// <param name="compressionMethod">Compression method being registered.</param> /// <param name="compressionMode">Indicates registration for ether /// compress or decompress mode.</param> /// <param name="creator">Delegate being registered.</param> /// <remarks> /// For compression, the delegate accepts a stream that writes to the archive /// and returns a wrapper stream that compresses bytes as they are written. /// For decompression, the delegate accepts a stream that reads from the archive /// and returns a wrapper stream that decompresses bytes as they are read. /// This wrapper stream model follows the design used by /// System.IO.Compression.DeflateStream, and indeed that class is used /// to implement the Deflate compression method by default. /// <para>To unregister a delegate, call this method again and pass /// null for the delegate parameter.</para> /// </remarks> /// <example> /// When the ZipEngine class is initialized, the Deflate compression method /// is automatically registered like this: /// <code> /// ZipEngine.RegisterCompressionStreamCreator( /// ZipCompressionMethod.Deflate, /// CompressionMode.Compress, /// delegate(Stream stream) { /// return new DeflateStream(stream, CompressionMode.Compress, true); /// }); /// ZipEngine.RegisterCompressionStreamCreator( /// ZipCompressionMethod.Deflate, /// CompressionMode.Decompress, /// delegate(Stream stream) { /// return new DeflateStream(stream, CompressionMode.Decompress, true); /// }); /// </code></example> public static void RegisterCompressionStreamCreator( ZipCompressionMethod compressionMethod, CompressionMode compressionMode, Converter <Stream, Stream> creator) { ZipEngine.InitCompressionStreamCreators(); if (compressionMode == CompressionMode.Compress) { ZipEngine.compressionStreamCreators[compressionMethod] = creator; } else { ZipEngine.decompressionStreamCreators[compressionMethod] = creator; } }
/// <summary> /// Sets up this DeflateManagedStream to be used for Inflation/Decompression /// </summary> private void InitializeInflater(Stream stream, ZipCompressionMethod method = ZipCompressionMethod.Deflate) { Debug.Assert(stream != null); Debug.Assert(method == ZipCompressionMethod.Deflate || method == ZipCompressionMethod.Deflate64); if (!stream.CanRead) { throw new ArgumentException("Deflate64: input stream is not readable", nameof(stream)); } _inflater = new InflaterManaged(method == ZipCompressionMethod.Deflate64); _stream = stream; _mode = CompressionMode.Decompress; _buffer = new byte[DEFAULT_BUFFER_SIZE]; }
/// <summary> /// Sets up this DeflateManagedStream to be used for Inflation/Decompression /// </summary> internal void InitializeInflater(Stream stream, bool leaveOpen, ZipCompressionMethod method = ZipCompressionMethod.Deflate) { Debug.Assert(stream != null); Debug.Assert(method == ZipCompressionMethod.Deflate || method == ZipCompressionMethod.Deflate64); if (!stream.CanRead) { throw new ArgumentException("Deflate64: input stream is not readable", nameof(stream)); } _inflater = new InflaterManaged(method == ZipCompressionMethod.Deflate64); _stream = stream; _mode = CompressionMode.Decompress; _leaveOpen = leaveOpen; _buffer = new byte[DefaultBufferSize]; }
private readonly PpmdProperties ppmdProperties; // Caching properties to speed up PPMd. #endif public ZipWriter(Stream destination, CompressionInfo compressionInfo, string zipComment, Encoding encoding = null) : base(ArchiveType.Zip) { this.zipComment = zipComment ?? string.Empty; this.encoding = encoding ?? ArchiveEncoding.Default; switch (compressionInfo.Type) { case CompressionType.None: { compression = ZipCompressionMethod.None; } break; case CompressionType.Deflate: { compression = ZipCompressionMethod.Deflate; deflateCompressionLevel = compressionInfo.DeflateCompressionLevel; } break; case CompressionType.BZip2: { compression = ZipCompressionMethod.BZip2; } break; #if LZMA case CompressionType.LZMA: { compression = ZipCompressionMethod.LZMA; } break; #endif #if PPMd case CompressionType.PPMd: { ppmdProperties = new PpmdProperties(); compression = ZipCompressionMethod.PPMd; } break; #endif default: throw new InvalidFormatException("Invalid compression method: " + compressionInfo.Type); } InitalizeStream(destination, false); }
// TODO: This method looks like ZipWriter.WriteHeader. Ideally the logic // has to be extracted into a common method and be called from both places // or better refactoring has to be done to keep the header info in a separate // class and use it in the reader and writer. public uint Write(Stream outputStream, ZipCompressionMethod compression) { byte[] encodedFilename = Encoding.UTF8.GetBytes(FileName); byte[] encodedComment = Encoding.UTF8.GetBytes(Comment); //constant sig, then version made by, compabitility, then version to extract outputStream.Write(new byte[] { 80, 75, 1, 2, 0x14, 0, 0x0A, 0 }, 0, 8); HeaderFlags flags = HeaderFlags.UTF8; if (IsEncrypted) { flags |= HeaderFlags.Encrypted; } if (!outputStream.CanSeek) { flags |= HeaderFlags.UsePostDataDescriptor; if (compression == ZipCompressionMethod.LZMA) { flags |= HeaderFlags.Bit1; // eos marker } } outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)flags), 0, 2); outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)compression), 0, 2); // zipping method outputStream.Write(DataConverter.LittleEndian.GetBytes(ModificationTime.DateTimeToDosTime()), 0, 4); // zipping date and time outputStream.Write(DataConverter.LittleEndian.GetBytes(Crc), 0, 4); // file CRC outputStream.Write(DataConverter.LittleEndian.GetBytes(Compressed), 0, 4); // compressed file size outputStream.Write(DataConverter.LittleEndian.GetBytes(Decompressed), 0, 4); // uncompressed file size outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)encodedFilename.Length), 0, 2); // Filename in zip outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)0), 0, 2); // extra length outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)encodedComment.Length), 0, 2); outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)0), 0, 2); // disk=0 outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)0), 0, 2); // file type: binary outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)0), 0, 2); // Internal file attributes outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)0x8100), 0, 2); // External file attributes (normal/readable) outputStream.Write(DataConverter.LittleEndian.GetBytes(HeaderOffset), 0, 4); // Offset of header outputStream.Write(encodedFilename, 0, encodedFilename.Length); outputStream.Write(encodedComment, 0, encodedComment.Length); return((uint)(8 + 2 + 2 + 4 + 4 + 4 + 4 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 4 + encodedFilename.Length + encodedComment.Length)); }
/// <summary> /// Creates a central file header from the information in a local file header. /// </summary> /// <param name="localFileHeader">Local file header to </param> public ZipFileHeader(ZipFileHeader localFileHeader) { if (localFileHeader.central) { throw new ArgumentException(); } this.central = true; this.compressionMethod = localFileHeader.compressionMethod; this.fileName = localFileHeader.fileName; this.fileComment = localFileHeader.fileComment; this.flags = localFileHeader.flags; this.externalFileAttrs = localFileHeader.externalFileAttrs; this.internalFileAttrs = localFileHeader.internalFileAttrs; this.lastModDate = localFileHeader.lastModDate; this.lastModTime = localFileHeader.lastModTime; this.crc32 = localFileHeader.crc32; if (this.zip64) { this.versionMadeBy = 45; this.versionNeeded = 45; this.compressedSize = UInt32.MaxValue; this.uncompressedSize = UInt32.MaxValue; this.diskStart = UInt16.MaxValue; ZipExtraFileField field = new ZipExtraFileField(); field.fieldType = ZipExtraFileFieldType.ZIP64; field.SetZip64Data(localFileHeader.compressedSize, localFileHeader.uncompressedSize, localFileHeader.localHeaderOffset, localFileHeader.diskStart); this.extraFields = new ZipExtraFileField[] { field }; } else { this.versionMadeBy = 20; this.versionNeeded = 20; this.localHeaderOffset = localFileHeader.localHeaderOffset; this.compressedSize = localFileHeader.compressedSize; this.uncompressedSize = localFileHeader.uncompressedSize; } }
internal uint Write(Stream outputStream, ZipCompressionMethod compression) { byte[] encodedFilename = Encoding.UTF8.GetBytes(FileName); byte[] encodedComment = Encoding.UTF8.GetBytes(Comment); //constant sig, then version made by, compabitility, then version to extract outputStream.Write(new byte[] {80, 75, 1, 2, 0x14, 0, 0x0A, 0}, 0, 8); HeaderFlags flags = HeaderFlags.UTF8; if (!outputStream.CanSeek) { flags |= HeaderFlags.UsePostDataDescriptor; if (compression == ZipCompressionMethod.LZMA) { flags |= HeaderFlags.Bit1; // eos marker } } outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort) flags), 0, 2); outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort) compression), 0, 2); // zipping method outputStream.Write(DataConverter.LittleEndian.GetBytes(ModificationTime.DateTimeToDosTime()), 0, 4); // zipping date and time outputStream.Write(DataConverter.LittleEndian.GetBytes(Crc), 0, 4); // file CRC outputStream.Write(DataConverter.LittleEndian.GetBytes(Compressed), 0, 4); // compressed file size outputStream.Write(DataConverter.LittleEndian.GetBytes(Decompressed), 0, 4); // uncompressed file size outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort) encodedFilename.Length), 0, 2); // Filename in zip outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort) 0), 0, 2); // extra length outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort) encodedComment.Length), 0, 2); outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort) 0), 0, 2); // disk=0 outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort) 0), 0, 2); // file type: binary outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort) 0), 0, 2); // Internal file attributes outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort) 0x8100), 0, 2); // External file attributes (normal/readable) outputStream.Write(DataConverter.LittleEndian.GetBytes(HeaderOffset), 0, 4); // Offset of header outputStream.Write(encodedFilename, 0, encodedFilename.Length); outputStream.Write(encodedComment, 0, encodedComment.Length); return (uint) (8 + 2 + 2 + 4 + 4 + 4 + 4 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 4 + encodedFilename.Length + encodedComment.Length); }
public bool Read(Stream stream, bool central) { long startPos = stream.Position; if (stream.Length - startPos < (central ? CFH_FIXEDSIZE : LFH_FIXEDSIZE)) { return false; } BinaryReader reader = new BinaryReader(stream); uint sig = reader.ReadUInt32(); if (sig == SPANSIG || sig == SPANSIG2) { // Spanned zip files may optionally begin with a special marker. // Just ignore it and move on. sig = reader.ReadUInt32(); } if (sig != (central ? CFHSIG : LFHSIG)) { return false; } this.versionMadeBy = (central ? reader.ReadUInt16() : (ushort) 0); this.versionNeeded = reader.ReadUInt16(); this.flags = (ZipFileFlags) reader.ReadUInt16(); this.compressionMethod = (ZipCompressionMethod) reader.ReadUInt16(); this.lastModTime = reader.ReadInt16(); this.lastModDate = reader.ReadInt16(); this.crc32 = reader.ReadUInt32(); this.compressedSize = reader.ReadUInt32(); this.uncompressedSize = reader.ReadUInt32(); this.zip64 = this.uncompressedSize == UInt32.MaxValue; int fileNameLength = reader.ReadUInt16(); int extraFieldLength = reader.ReadUInt16(); int fileCommentLength; if (central) { fileCommentLength = reader.ReadUInt16(); this.diskStart = reader.ReadUInt16(); this.internalFileAttrs = reader.ReadUInt16(); this.externalFileAttrs = reader.ReadUInt32(); this.localHeaderOffset = reader.ReadUInt32(); } else { fileCommentLength = 0; this.diskStart = 0; this.internalFileAttrs = 0; this.externalFileAttrs = 0; this.localHeaderOffset = 0; } if (stream.Length - stream.Position < fileNameLength + extraFieldLength + fileCommentLength) { return false; } Encoding headerEncoding = ((this.flags | ZipFileFlags.UTF8) != 0 ? Encoding.UTF8 : Encoding.GetEncoding(CultureInfo.CurrentCulture.TextInfo.OEMCodePage)); byte[] fileNameBytes = reader.ReadBytes(fileNameLength); this.fileName = headerEncoding.GetString(fileNameBytes).Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); List<ZipExtraFileField> fields = new List<ZipExtraFileField>(); while (extraFieldLength > 0) { ZipExtraFileField field = new ZipExtraFileField(); if (!field.Read(stream, ref extraFieldLength)) { return false; } fields.Add(field); if (field.fieldType == ZipExtraFileFieldType.ZIP64) { this.zip64 = true; } } this.extraFields = fields.ToArray(); byte[] fileCommentBytes = reader.ReadBytes(fileCommentLength); this.fileComment = headerEncoding.GetString(fileCommentBytes); return true; }
internal uint Write(Stream outputStream, ZipCompressionMethod compression) { byte[] encodedFilename = Encoding.UTF8.GetBytes(FileName); byte[] encodedComment = Encoding.UTF8.GetBytes(Comment); var zip64_stream = Compressed >= uint.MaxValue || Decompressed >= uint.MaxValue; var zip64 = zip64_stream || HeaderOffset >= uint.MaxValue || Zip64HeaderOffset != 0; var compressedvalue = zip64 ? uint.MaxValue : (uint)Compressed; var decompressedvalue = zip64 ? uint.MaxValue : (uint)Decompressed; var headeroffsetvalue = zip64 ? uint.MaxValue : (uint)HeaderOffset; var extralength = zip64 ? (2 + 2 + 8 + 8 + 8 + 4) : 0; var version = (byte)(zip64 ? 45 : 10); HeaderFlags flags = HeaderFlags.UTF8; if (!outputStream.CanSeek) { // Cannot use data descriptors with zip64: // https://blogs.oracle.com/xuemingshen/entry/is_zipinput_outputstream_handling_of // We check that streams are not written too large in the ZipWritingStream, // so this extra guard is not required, but kept to simplify changing the code // once the zip64 post-data issue is resolved if (!zip64_stream) { flags |= HeaderFlags.UsePostDataDescriptor; } if (compression == ZipCompressionMethod.LZMA) { flags |= HeaderFlags.Bit1; // eos marker } } //constant sig, then version made by, compabitility, then version to extract outputStream.Write(new byte[] { 80, 75, 1, 2, 0x14, 0, version, 0 }, 0, 8); outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)flags), 0, 2); outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)compression), 0, 2); // zipping method outputStream.Write(DataConverter.LittleEndian.GetBytes(ModificationTime.DateTimeToDosTime()), 0, 4); // zipping date and time outputStream.Write(DataConverter.LittleEndian.GetBytes(Crc), 0, 4); // file CRC outputStream.Write(DataConverter.LittleEndian.GetBytes(compressedvalue), 0, 4); // compressed file size outputStream.Write(DataConverter.LittleEndian.GetBytes(decompressedvalue), 0, 4); // uncompressed file size outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)encodedFilename.Length), 0, 2); // Filename in zip outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)extralength), 0, 2); // extra length outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)encodedComment.Length), 0, 2); outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)0), 0, 2); // disk=0 outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)0), 0, 2); // file type: binary outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)0), 0, 2); // Internal file attributes outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)0x8100), 0, 2); // External file attributes (normal/readable) outputStream.Write(DataConverter.LittleEndian.GetBytes(headeroffsetvalue), 0, 4); // Offset of header outputStream.Write(encodedFilename, 0, encodedFilename.Length); if (zip64) { outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)0x0001), 0, 2); outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)(extralength - 4)), 0, 2); outputStream.Write(DataConverter.LittleEndian.GetBytes(Decompressed), 0, 8); outputStream.Write(DataConverter.LittleEndian.GetBytes(Compressed), 0, 8); outputStream.Write(DataConverter.LittleEndian.GetBytes(HeaderOffset), 0, 8); outputStream.Write(DataConverter.LittleEndian.GetBytes(0), 0, 4); // VolumeNumber = 0 } outputStream.Write(encodedComment, 0, encodedComment.Length); return((uint)(8 + 2 + 2 + 4 + 4 + 4 + 4 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 4 + encodedFilename.Length + extralength + encodedComment.Length)); }
public bool Read(Stream stream, bool central) { long startPos = stream.Position; if (stream.Length - startPos < (central ? CFH_FIXEDSIZE : LFH_FIXEDSIZE)) { return(false); } BinaryReader reader = new BinaryReader(stream); uint sig = reader.ReadUInt32(); if (sig == SPANSIG || sig == SPANSIG2) { // Spanned zip files may optionally begin with a special marker. // Just ignore it and move on. sig = reader.ReadUInt32(); } if (sig != (central ? CFHSIG : LFHSIG)) { return(false); } this.versionMadeBy = (central ? reader.ReadUInt16() : (ushort)0); this.versionNeeded = reader.ReadUInt16(); this.flags = (ZipFileFlags)reader.ReadUInt16(); this.compressionMethod = (ZipCompressionMethod)reader.ReadUInt16(); this.lastModTime = reader.ReadInt16(); this.lastModDate = reader.ReadInt16(); this.crc32 = reader.ReadUInt32(); this.compressedSize = reader.ReadUInt32(); this.uncompressedSize = reader.ReadUInt32(); this.zip64 = this.uncompressedSize == UInt32.MaxValue; int fileNameLength = reader.ReadUInt16(); int extraFieldLength = reader.ReadUInt16(); int fileCommentLength; if (central) { fileCommentLength = reader.ReadUInt16(); this.diskStart = reader.ReadUInt16(); this.internalFileAttrs = reader.ReadUInt16(); this.externalFileAttrs = reader.ReadUInt32(); this.localHeaderOffset = reader.ReadUInt32(); } else { fileCommentLength = 0; this.diskStart = 0; this.internalFileAttrs = 0; this.externalFileAttrs = 0; this.localHeaderOffset = 0; } if (stream.Length - stream.Position < fileNameLength + extraFieldLength + fileCommentLength) { return(false); } #if CORECLR Encoding headerEncoding = Encoding.UTF8; #else Encoding headerEncoding = ((this.flags | ZipFileFlags.UTF8) != 0 ? Encoding.UTF8 : Encoding.GetEncoding(CultureInfo.CurrentCulture.TextInfo.OEMCodePage)); #endif byte[] fileNameBytes = reader.ReadBytes(fileNameLength); this.fileName = headerEncoding.GetString(fileNameBytes).Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); List <ZipExtraFileField> fields = new List <ZipExtraFileField>(); while (extraFieldLength > 0) { ZipExtraFileField field = new ZipExtraFileField(); if (!field.Read(stream, ref extraFieldLength)) { return(false); } fields.Add(field); if (field.fieldType == ZipExtraFileFieldType.ZIP64) { this.zip64 = true; } } this.extraFields = fields.ToArray(); byte[] fileCommentBytes = reader.ReadBytes(fileCommentLength); this.fileComment = headerEncoding.GetString(fileCommentBytes); return(true); }
/// <summary> /// Adds one file to a zip archive in the process of being created. /// </summary> private ZipFileHeader PackOneFile( IPackStreamContext streamContext, string file, long maxArchiveSize, bool forceZip64, ref Stream archiveStream) { Stream fileStream = null; int headerArchiveNumber = 0; try { // TODO: call GetOption to get compression method for the specific file ZipCompressionMethod compressionMethod = ZipCompressionMethod.Deflate; if (this.CompressionLevel == CompressionLevel.None) { compressionMethod = ZipCompressionMethod.Store; } Func <Stream, Stream> compressionStreamCreator; if (!ZipEngine.compressionStreamCreators.TryGetValue( compressionMethod, out compressionStreamCreator)) { return(null); } FileAttributes attributes; DateTime lastWriteTime; fileStream = streamContext.OpenFileReadStream( file, out attributes, out lastWriteTime); if (fileStream == null) { return(null); } this.currentFileName = file; this.currentFileNumber++; this.currentFileTotalBytes = fileStream.Length; this.currentFileBytesProcessed = 0; this.OnProgress(ArchiveProgressType.StartFile); ZipFileInfo fileInfo = new ZipFileInfo( file, this.currentArchiveNumber, attributes, lastWriteTime, fileStream.Length, 0, compressionMethod); bool zip64 = forceZip64 || fileStream.Length >= (long)UInt32.MaxValue; ZipFileHeader fileHeader = new ZipFileHeader(fileInfo, zip64); this.CheckArchiveWriteStream( streamContext, maxArchiveSize, fileHeader.GetSize(false), ref archiveStream); long headerPosition = archiveStream.Position; fileHeader.Write(archiveStream, false); headerArchiveNumber = this.currentArchiveNumber; uint crc; long bytesWritten = this.PackFileBytes( streamContext, fileStream, maxArchiveSize, compressionStreamCreator, ref archiveStream, out crc); fileHeader.Update( bytesWritten, fileStream.Length, crc, headerPosition, headerArchiveNumber); streamContext.CloseFileReadStream(file, fileStream); fileStream = null; // Go back and rewrite the updated file header. if (this.currentArchiveNumber == headerArchiveNumber) { long fileEndPosition = archiveStream.Position; archiveStream.Seek(headerPosition, SeekOrigin.Begin); fileHeader.Write(archiveStream, false); archiveStream.Seek(fileEndPosition, SeekOrigin.Begin); } else { // The file spanned archives, so temporarily reopen // the archive where it started. string headerArchiveName = streamContext.GetArchiveName( headerArchiveNumber + 1); Stream headerStream = null; try { headerStream = streamContext.OpenArchiveWriteStream( headerArchiveNumber, headerArchiveName, false, this); headerStream.Seek(headerPosition, SeekOrigin.Begin); fileHeader.Write(headerStream, false); } finally { if (headerStream != null) { streamContext.CloseArchiveWriteStream( headerArchiveNumber, headerArchiveName, headerStream); } } } this.OnProgress(ArchiveProgressType.FinishFile); return(fileHeader); } finally { if (fileStream != null) { streamContext.CloseFileReadStream( this.currentFileName, fileStream); } } }
protected Stream CreateDecompressionStream(Stream stream, ZipCompressionMethod method) { switch (method) { case ZipCompressionMethod.None: { return(stream); } case ZipCompressionMethod.Deflate: { return(new DeflateStream(stream, CompressionMode.Decompress)); } case ZipCompressionMethod.BZip2: { return(new BZip2Stream(stream, CompressionMode.Decompress)); } case ZipCompressionMethod.LZMA: { if (FlagUtility.HasFlag(Header.Flags, HeaderFlags.Encrypted)) { throw new NotSupportedException("LZMA with pkware encryption."); } var reader = new BinaryReader(stream); reader.ReadUInt16(); //LZMA version var props = new byte[reader.ReadUInt16()]; reader.Read(props, 0, props.Length); return(new LzmaStream(props, stream, Header.CompressedSize > 0 ? Header.CompressedSize - 4 - props.Length : -1, FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1) ? -1 : (long)Header.UncompressedSize)); } case ZipCompressionMethod.PPMd: { var props = new byte[2]; stream.ReadFully(props); return(new PpmdStream(new PpmdProperties(props), stream, false)); } case ZipCompressionMethod.WinzipAes: { ExtraData data = Header.Extra.Where(x => x.Type == ExtraDataType.WinZipAes).SingleOrDefault(); if (data == null) { throw new InvalidFormatException("No Winzip AES extra data found."); } if (data.Length != 7) { throw new InvalidFormatException("Winzip data length is not 7."); } ushort compressedMethod = DataConverter.LittleEndian.GetUInt16(data.DataBytes, 0); if (compressedMethod != 0x01 && compressedMethod != 0x02) { throw new InvalidFormatException("Unexpected vendor version number for WinZip AES metadata"); } ushort vendorId = DataConverter.LittleEndian.GetUInt16(data.DataBytes, 2); if (vendorId != 0x4541) { throw new InvalidFormatException("Unexpected vendor ID for WinZip AES metadata"); } return(CreateDecompressionStream(stream, (ZipCompressionMethod)DataConverter.LittleEndian.GetUInt16(data.DataBytes, 5))); } default: { throw new NotSupportedException("CompressionMethod: " + Header.CompressionMethod); } } }
/// <summary> /// Registers a delegate that can create a warpper stream for /// compressing or uncompressing the data of a source stream. /// </summary> /// <param name="compressionMethod">Compression method being registered.</param> /// <param name="compressionMode">Indicates registration for ether /// compress or decompress mode.</param> /// <param name="creator">Delegate being registered.</param> /// <remarks> /// For compression, the delegate accepts a stream that writes to the archive /// and returns a wrapper stream that compresses bytes as they are written. /// For decompression, the delegate accepts a stream that reads from the archive /// and returns a wrapper stream that decompresses bytes as they are read. /// This wrapper stream model follows the design used by /// System.IO.Compression.DeflateStream, and indeed that class is used /// to implement the Deflate compression method by default. /// <para>To unregister a delegate, call this method again and pass /// null for the delegate parameter.</para> /// </remarks> /// <example> /// When the ZipEngine class is initialized, the Deflate compression method /// is automatically registered like this: /// <code> /// ZipEngine.RegisterCompressionStreamCreator( /// ZipCompressionMethod.Deflate, /// CompressionMode.Compress, /// delegate(Stream stream) { /// return new DeflateStream(stream, CompressionMode.Compress, true); /// }); /// ZipEngine.RegisterCompressionStreamCreator( /// ZipCompressionMethod.Deflate, /// CompressionMode.Decompress, /// delegate(Stream stream) { /// return new DeflateStream(stream, CompressionMode.Decompress, true); /// }); /// </code></example> public static void RegisterCompressionStreamCreator( ZipCompressionMethod compressionMethod, CompressionMode compressionMode, Converter<Stream, Stream> creator) { ZipEngine.InitCompressionStreamCreators(); if (compressionMode == CompressionMode.Compress) { ZipEngine.compressionStreamCreators[compressionMethod] = creator; } else { ZipEngine.decompressionStreamCreators[compressionMethod] = creator; } }
internal uint Write(Stream outputStream, ZipCompressionMethod compression) { byte[] bytes = Encoding.UTF8.GetBytes(this.FileName); byte[] buffer = Encoding.UTF8.GetBytes(this.Comment); outputStream.Write(new byte[] { 80, 0x4b, 1, 2, 0x3f, 0, 10, 0 }, 0, 8); HeaderFlags flags = HeaderFlags.UTF8; if (!outputStream.CanSeek) { flags = (HeaderFlags) ((ushort) (flags | HeaderFlags.UsePostDataDescriptor)); if (compression == ZipCompressionMethod.LZMA) { flags = (HeaderFlags) ((ushort) (flags | HeaderFlags.Bit1)); } } outputStream.Write(BitConverter.GetBytes((ushort) flags), 0, 2); outputStream.Write(BitConverter.GetBytes((ushort) compression), 0, 2); outputStream.Write(BitConverter.GetBytes(Utility.DateTimeToDosTime(this.ModificationTime)), 0, 4); outputStream.Write(BitConverter.GetBytes(this.Crc), 0, 4); outputStream.Write(BitConverter.GetBytes(this.Compressed), 0, 4); outputStream.Write(BitConverter.GetBytes(this.Decompressed), 0, 4); outputStream.Write(BitConverter.GetBytes((ushort) bytes.Length), 0, 2); outputStream.Write(BitConverter.GetBytes((ushort) 0), 0, 2); outputStream.Write(BitConverter.GetBytes((ushort) buffer.Length), 0, 2); outputStream.Write(BitConverter.GetBytes((ushort) 0), 0, 2); outputStream.Write(BitConverter.GetBytes((ushort) 0), 0, 2); outputStream.Write(BitConverter.GetBytes((ushort) 0), 0, 2); outputStream.Write(BitConverter.GetBytes((ushort) 0x8100), 0, 2); outputStream.Write(BitConverter.GetBytes(this.HeaderOffset), 0, 4); outputStream.Write(bytes, 0, bytes.Length); outputStream.Write(buffer, 0, buffer.Length); return (uint) ((0x2e + bytes.Length) + buffer.Length); }