private void UpdateCrcAndSizes(ref ZipFileEntry _zfe) { /* CRC32 algorithm The 'magic number' for the CRC is 0xdebb20e3. The proper CRC pre and post conditioning is used, meaning that the CRC register is pre-conditioned with all ones (a starting value of 0xffffffff) and the value is post-conditioned by taking the one's complement of the CRC residual. If bit 3 of the general purpose flag is set, this field is set to zero in the local header and the correct value is put in the data descriptor and in the central directory. */ long lastPos = this.ZipFileStream.Position; this.ZipFileStream.Position = _zfe.HeaderOffset + 8; this.ZipFileStream.Write(BitConverter.GetBytes((ushort)_zfe.Method), 0, 2); this.ZipFileStream.Position = _zfe.HeaderOffset + 14; this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.Crc32), 0, 4); this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.CompressedSize), 0, 4); this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.FileSize), 0, 4); this.ZipFileStream.Position = lastPos; }
public void DisposeStream(ZipFileEntry _zfe, Stream s) { if (_zfe.Method == Compression.Deflate) s.Dispose(); }
/// <summary> /// Copy the contents of a stored file into a physical file. /// </summary> /// <param name="zipFileEntry">Entry information of file to extract.</param> /// <param name="destinationFileName">Name of file to store uncompressed data.</param> /// <returns><see langword="true"/> if the file is successfully extracted; otherwise, <see langword="false"/>.</returns> /// <remarks>Unique compression methods are Store and Deflate.</remarks> public bool ExtractFile(ZipFileEntry zipFileEntry, string destinationFileName) { // Make sure the parent directory exist string path = System.IO.Path.GetDirectoryName(destinationFileName); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } // Check it is directory. If so, do nothing if (Directory.Exists(destinationFileName)) { return true; } bool result = false; using (Stream output = new FileStream(destinationFileName, FileMode.Create, FileAccess.Write)) { result = this.ExtractFile(zipFileEntry, output); } File.SetCreationTime(destinationFileName, zipFileEntry.ModifyTime); File.SetLastWriteTime(destinationFileName, zipFileEntry.ModifyTime); return result; }
public bool ExtractFile(ZipFileEntry _zfe, Stream _stream) { return ExtractFile(_zfe, _stream, 0); }
/// <summary> /// Copy the contents of a stored file into a physical file /// </summary> /// <param name="zfe">Entry information of file to extract</param> /// <param name="targetFileName">Name of file to store uncompressed data</param> /// <returns>True if success, false if not.</returns> /// <remarks>Unique compression methods are Store and Deflate</remarks> public bool ExtractFile( ZipFileEntry zfe, [NotNull] string targetFileName ) { if( fileName == null ) throw new ArgumentNullException( "targetFileName" ); // Make sure the parent directory exist string path = Path.GetDirectoryName( fileName ); if( path == null ) throw new NotImplementedException(); if( !Directory.Exists( path ) ) { Directory.CreateDirectory( path ); } // Check it is directory. If so, do nothing if( Directory.Exists( fileName ) ) { return true; } Stream output = new FileStream( fileName, FileMode.Create, FileAccess.Write ); bool result = ExtractFile( zfe, output ); if( result ) output.Close(); File.SetCreationTime( fileName, zfe.ModifyTime ); File.SetLastWriteTime( fileName, zfe.ModifyTime ); return result; }
/// <summary> /// Copy the contents of a stored file into an opened stream /// </summary> /// <param name="_zfe">Entry information of file to extract</param> /// <param name="_stream">Stream to store the uncompressed data</param> /// <returns>True if success, false if not.</returns> /// <remarks>Unique compression methods are Store and Deflate</remarks> public bool ExtractFile(ZipFileEntry _zfe, Stream _stream) { if (!_stream.CanWrite) throw new InvalidOperationException("Stream cannot be written"); // check signature byte[] signature = new byte[4]; this.ZipFileStream.Seek(_zfe.HeaderOffset, SeekOrigin.Begin); this.ZipFileStream.Read(signature, 0, 4); if (BitConverter.ToUInt32(signature, 0) != 0x04034b50) return false; // Select input stream for inflating or just reading Stream inStream; if (_zfe.Method == Compression.Store) inStream = this.ZipFileStream; else if (_zfe.Method == Compression.Deflate) inStream = new DeflateStream(this.ZipFileStream, CompressionMode.Decompress, true); else return false; // Buffered copy byte[] buffer = new byte[16384]; this.ZipFileStream.Seek(_zfe.FileOffset, SeekOrigin.Begin); uint bytesPending = _zfe.FileSize; while (bytesPending > 0) { int bytesRead = inStream.Read(buffer, 0, (int)Math.Min(bytesPending, buffer.Length)); _stream.Write(buffer, 0, bytesRead); bytesPending -= (uint)bytesRead; } _stream.Flush(); if (_zfe.Method == Compression.Deflate) inStream.Dispose(); return true; }
/* Central directory's File header: central file header signature 4 bytes (0x02014b50) version made by 2 bytes version needed to extract 2 bytes general purpose bit flag 2 bytes compression method 2 bytes last mod file time 2 bytes last mod file date 2 bytes crc-32 4 bytes compressed size 4 bytes uncompressed size 4 bytes filename length 2 bytes extra field length 2 bytes file comment length 2 bytes disk number start 2 bytes internal file attributes 2 bytes external file attributes 4 bytes relative offset of local header 4 bytes filename (variable size) extra field (variable size) file comment (variable size) */ private void WriteCentralDirRecord(ZipFileEntry _zfe) { Encoding encoder = _zfe.EncodeUTF8 ? Encoding.UTF8 : DefaultEncoding; byte[] encodedFilename = encoder.GetBytes(_zfe.FilenameInZip); byte[] encodedComment = encoder.GetBytes(_zfe.Comment); this.ZipFileStream.Write(new byte[] { 80, 75, 1, 2, 23, 0xB, 20, 0 }, 0, 8); this.ZipFileStream.Write(BitConverter.GetBytes((ushort)(_zfe.EncodeUTF8 ? 0x0800 : 0)), 0, 2); // filename and comment encoding this.ZipFileStream.Write(BitConverter.GetBytes((ushort)_zfe.Method), 0, 2); // zipping method this.ZipFileStream.Write(BitConverter.GetBytes(DateTimeToDosTime(_zfe.ModifyTime)), 0, 4); // zipping date and time this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.Crc32), 0, 4); // file CRC this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.CompressedSize), 0, 4); // compressed file size this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.FileSize), 0, 4); // uncompressed file size this.ZipFileStream.Write(BitConverter.GetBytes((ushort)encodedFilename.Length), 0, 2); // Filename in zip this.ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); // extra length this.ZipFileStream.Write(BitConverter.GetBytes((ushort)encodedComment.Length), 0, 2); this.ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); // disk=0 this.ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); // file type: binary this.ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); // Internal file attributes this.ZipFileStream.Write(BitConverter.GetBytes((ushort)0x8100), 0, 2); // External file attributes (normal/readable) this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.HeaderOffset), 0, 4); // Offset of header this.ZipFileStream.Write(encodedFilename, 0, encodedFilename.Length); this.ZipFileStream.Write(encodedComment, 0, encodedComment.Length); }
/// <summary> /// Read all the file records in the central directory /// </summary> /// <returns>List of all entries in directory</returns> private IEnumerable <ZipFileEntry> ReadCentralDir() { if (CentralDirImage == null) { throw new InvalidOperationException("Central directory currently does not exist"); } for (int pointer = 0; pointer < CentralDirImage.Length;) { uint signature = BitConverter.ToUInt32(CentralDirImage, pointer); if (signature != 0x02014b50) { CentralDirImage = null; yield break; } bool encodeUTF8 = (BitConverter.ToUInt16(CentralDirImage, pointer + 8) & 0x0800) != 0; ushort method = BitConverter.ToUInt16(CentralDirImage, pointer + 10); uint modifyTime = BitConverter.ToUInt32(CentralDirImage, pointer + 12); uint crc32 = BitConverter.ToUInt32(CentralDirImage, pointer + 16); ulong comprSize = BitConverter.ToUInt32(CentralDirImage, pointer + 20); ulong fileSize = BitConverter.ToUInt32(CentralDirImage, pointer + 24); ushort filenameSize = BitConverter.ToUInt16(CentralDirImage, pointer + 28); ushort extraSize = BitConverter.ToUInt16(CentralDirImage, pointer + 30); ushort commentSize = BitConverter.ToUInt16(CentralDirImage, pointer + 32); ulong headerOffset = BitConverter.ToUInt32(CentralDirImage, pointer + 42); uint headerSize = (uint)(46 + filenameSize + extraSize + commentSize); Encoding encoder = encodeUTF8 ? Encoding.UTF8 : DefaultEncoding; if (extraSize >= 4) { int extraPtr = pointer + 46 + filenameSize; // Find ZIP64 extra field record while (extraPtr < pointer + 46 + filenameSize + extraSize) { ushort headerId = BitConverter.ToUInt16(CentralDirImage, extraPtr); ushort length = BitConverter.ToUInt16(CentralDirImage, extraPtr + 2); if (headerId == 1) { extraPtr += 4; if (fileSize == 0xffffffff) { fileSize = BitConverter.ToUInt64(CentralDirImage, extraPtr); extraPtr += 8; } if (comprSize == 0xffffffff) { comprSize = BitConverter.ToUInt64(CentralDirImage, extraPtr); extraPtr += 8; } if (headerOffset == 0xffffffff) { headerOffset = BitConverter.ToUInt64(CentralDirImage, extraPtr); extraPtr += 8; } break; } else { extraPtr += (4 + length); } } } ZipFileEntry zfe = new ZipFileEntry { Method = (Compression)method, FilenameInZip = encoder.GetString(CentralDirImage, pointer + 46, filenameSize), FileSize = fileSize, CompressedSize = comprSize, HeaderOffset = headerOffset, HeaderSize = headerSize, FileOffset = GetFileOffset(headerOffset), Crc32 = crc32, ModifyTime = DosTimeToDateTime(modifyTime) ?? DateTime.Now }; if (commentSize > 0) { zfe.Comment = encoder.GetString(CentralDirImage, pointer + 46 + filenameSize + extraSize, commentSize); } pointer += (46 + filenameSize + extraSize + commentSize); yield return(zfe); } CentralDirImage = null; }
private void LoadHeader(ZipFileEntry entryHeader, Stream stream) { if (FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.Encrypted)) { if (!entryHeader.IsDirectory && entryHeader.CompressedSize == 0 && FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.UsePostDataDescriptor)) { throw new NotSupportedException("SharpCompress cannot currently read non-seekable Zip Streams with encrypted data that has been written in a non-seekable manner."); } if (password == null) { throw new CryptographicException("No password supplied for encrypted zip."); } entryHeader.Password = password; if (entryHeader.CompressionMethod == ZipCompressionMethod.WinzipAes) { #if NO_CRYPTO throw new NotSupportedException("Cannot decrypt Winzip AES with Silverlight or WP7."); #else ExtraData data = entryHeader.Extra.SingleOrDefault(x => x.Type == ExtraDataType.WinZipAes); if (data != null) { var keySize = (WinzipAesKeySize)data.DataBytes[4]; var salt = new byte[WinzipAesEncryptionData.KeyLengthInBytes(keySize) / 2]; var passwordVerifyValue = new byte[2]; stream.Read(salt, 0, salt.Length); stream.Read(passwordVerifyValue, 0, 2); entryHeader.WinzipAesEncryptionData = new WinzipAesEncryptionData(keySize, salt, passwordVerifyValue, password); entryHeader.CompressedSize -= (uint)(salt.Length + 2); } #endif } } if (entryHeader.IsDirectory) { return; } //if (FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.UsePostDataDescriptor)) //{ // entryHeader.PackedStream = new ReadOnlySubStream(stream); //} //else //{ switch (mode) { case StreamingMode.Seekable: { entryHeader.DataStartPosition = stream.Position; stream.Position += entryHeader.CompressedSize; break; } case StreamingMode.Streaming: { entryHeader.PackedStream = stream; break; } default: { throw new InvalidFormatException("Invalid StreamingMode"); } } //} }
ExtractFileAsync(ZipFileEntry _zfe, Stream _stream) { if (!_stream.CanWrite) { throw new InvalidOperationException("Stream cannot be written"); } // check signature byte[] signature = new byte[4]; this.ZipFileStream.Seek(_zfe.HeaderOffset, SeekOrigin.Begin); #if NOASYNC this.ZipFileStream.Read(signature, 0, 4); #else await this.ZipFileStream.ReadAsync(signature, 0, 4); #endif if (BitConverter.ToUInt32(signature, 0) != 0x04034b50) { return(false); } // Select input stream for inflating or just reading Stream inStream; if (_zfe.Method == Compression.Store) { inStream = this.ZipFileStream; } else if (_zfe.Method == Compression.Deflate) { inStream = new DeflateStream(this.ZipFileStream, CompressionMode.Decompress, true); } else { return(false); } // Buffered copy byte[] buffer = new byte[65535]; this.ZipFileStream.Seek(_zfe.FileOffset, SeekOrigin.Begin); long bytesPending = _zfe.FileSize; while (bytesPending > 0) { #if NOASYNC int bytesRead = inStream.Read(buffer, 0, (int)Math.Min(bytesPending, buffer.Length)); _stream.Write(buffer, 0, bytesRead); #else int bytesRead = await inStream.ReadAsync(buffer, 0, (int)Math.Min(bytesPending, buffer.Length)); await _stream.WriteAsync(buffer, 0, bytesRead); #endif bytesPending -= (uint)bytesRead; } _stream.Flush(); if (_zfe.Method == Compression.Deflate) { inStream.Dispose(); } return(true); }
Store(ZipFileEntry _zfe, Stream _source) { byte[] buffer = new byte[16384]; int bytesRead; uint totalRead = 0; Stream outStream; long posStart = this.ZipFileStream.Position; long sourceStart = _source.CanSeek ? _source.Position : 0; if (_zfe.Method == Compression.Store) { outStream = this.ZipFileStream; } else { outStream = new DeflateStream(this.ZipFileStream, CompressionMode.Compress, true); } _zfe.Crc32 = 0 ^ 0xffffffff; do { #if NOASYNC bytesRead = _source.Read(buffer, 0, buffer.Length); if (bytesRead > 0) { outStream.Write(buffer, 0, bytesRead); } #else bytesRead = await _source.ReadAsync(buffer, 0, buffer.Length); if (bytesRead > 0) { await outStream.WriteAsync(buffer, 0, bytesRead); } #endif for (uint i = 0; i < bytesRead; i++) { _zfe.Crc32 = ZipStorer.CrcTable[(_zfe.Crc32 ^ buffer[i]) & 0xFF] ^ (_zfe.Crc32 >> 8); } totalRead += (uint)bytesRead; } while (bytesRead > 0); outStream.Flush(); if (_zfe.Method == Compression.Deflate) { outStream.Dispose(); } _zfe.Crc32 ^= 0xFFFFFFFF; _zfe.FileSize = totalRead; _zfe.CompressedSize = (uint)(this.ZipFileStream.Position - posStart); // Verify for real compression if (_zfe.Method == Compression.Deflate && !this.ForceDeflating && _source.CanSeek && _zfe.CompressedSize > _zfe.FileSize) { // Start operation again with Store algorithm _zfe.Method = Compression.Store; this.ZipFileStream.Position = posStart; this.ZipFileStream.SetLength(posStart); _source.Position = sourceStart; #if NOASYNC return(this.Store(_zfe, _source)); #else return(await this.Store(_zfe, _source)); #endif } return(_zfe.Method); }
/// <summary> /// Read all the file records in the central directory /// </summary> /// <returns>List of all entries in directory</returns> public List <ZipFileEntry> ReadCentralDir() { if (this.CentralDirImage == null) { throw new InvalidOperationException("Central directory currently does not exist"); } List <ZipFileEntry> result = new List <ZipFileEntry>(); for (int pointer = 0; pointer < this.CentralDirImage.Length;) { uint signature = BitConverter.ToUInt32(CentralDirImage, pointer); if (signature != 0x02014b50) { break; } bool encodeUTF8 = (BitConverter.ToUInt16(CentralDirImage, pointer + 8) & 0x0800) != 0; ushort method = BitConverter.ToUInt16(CentralDirImage, pointer + 10); uint modifyTime = BitConverter.ToUInt32(CentralDirImage, pointer + 12); uint crc32 = BitConverter.ToUInt32(CentralDirImage, pointer + 16); long comprSize = BitConverter.ToUInt32(CentralDirImage, pointer + 20); long fileSize = BitConverter.ToUInt32(CentralDirImage, pointer + 24); ushort filenameSize = BitConverter.ToUInt16(CentralDirImage, pointer + 28); ushort extraSize = BitConverter.ToUInt16(CentralDirImage, pointer + 30); ushort commentSize = BitConverter.ToUInt16(CentralDirImage, pointer + 32); uint headerOffset = BitConverter.ToUInt32(CentralDirImage, pointer + 42); uint headerSize = (uint)(46 + filenameSize + extraSize + commentSize); DateTime modifyTimeDT = DosTimeToDateTime(modifyTime) ?? DateTime.Now; Encoding encoder = encodeUTF8 ? Encoding.UTF8 : DefaultEncoding; ZipFileEntry zfe = new ZipFileEntry() { Method = (Compression)method, FilenameInZip = encoder.GetString(CentralDirImage, pointer + 46, filenameSize), FileOffset = GetFileOffset(headerOffset), FileSize = fileSize, CompressedSize = comprSize, HeaderOffset = headerOffset, HeaderSize = headerSize, Crc32 = crc32, ModifyTime = modifyTimeDT, CreationTime = modifyTimeDT, AccessTime = DateTime.Now, }; if (commentSize > 0) { zfe.Comment = encoder.GetString(CentralDirImage, pointer + 46 + filenameSize + extraSize, commentSize); } if (extraSize > 0) { this.ReadExtraInfo(CentralDirImage, pointer + 46 + filenameSize, zfe); } result.Add(zfe); pointer += (46 + filenameSize + extraSize + commentSize); } return(result); }
// Copies all source file into storage file void Store(ref ZipFileEntry zfe, [NotNull] Stream source) { if (source == null) { throw new ArgumentNullException("source"); } while (true) { byte[] buffer = new byte[16384]; int bytesRead; uint totalRead = 0; Stream outStream; long posStart = zipFileStream.Position; long sourceStart = source.Position; if (zfe.Method == Compression.Store) { outStream = zipFileStream; } else { outStream = new DeflateStream(zipFileStream, CompressionMode.Compress, true); } zfe.Crc32 = 0 ^ 0xffffffff; do { bytesRead = source.Read(buffer, 0, buffer.Length); totalRead += (uint)bytesRead; if (bytesRead > 0) { outStream.Write(buffer, 0, bytesRead); for (uint i = 0; i < bytesRead; i++) { zfe.Crc32 = CrcTable[(zfe.Crc32 ^ buffer[i]) & 0xFF] ^ (zfe.Crc32 >> 8); } } } while (bytesRead == buffer.Length); if (totalRead > 0) { outStream.Flush(); // fix for "Internal error Flush" under Mono } if (zfe.Method == Compression.Deflate) { outStream.Dispose(); } zfe.Crc32 ^= 0xffffffff; zfe.FileSize = totalRead; zfe.CompressedSize = (uint)(zipFileStream.Position - posStart); // Verify for real compression if (zfe.Method == Compression.Deflate && !ForceDeflating && source.CanSeek && zfe.CompressedSize > zfe.FileSize) { // Start operation again with Store algorithm zfe.Method = Compression.Store; zipFileStream.Position = posStart; zipFileStream.SetLength(posStart); source.Position = sourceStart; continue; } break; } }
// Copies all source file into storage file private void Store(ref ZipFileEntry _zfe, Stream _source) { byte[] buffer = new byte[16384]; int bytesRead; uint totalRead = 0; Stream outStream; long posStart = ZipFileStream.Position; long sourceStart = _source.Position; if (_zfe.Method == Compression.Store) { outStream = ZipFileStream; } else { outStream = new DeflateStream(ZipFileStream, CompressionMode.Compress, true); } _zfe.Crc32 = 0 ^ 0xffffffff; do { bytesRead = _source.Read(buffer, 0, buffer.Length); totalRead += (uint)bytesRead; if (bytesRead > 0) { outStream.Write(buffer, 0, bytesRead); for (uint i = 0; i < bytesRead; i++) { _zfe.Crc32 = CrcTable[(_zfe.Crc32 ^ buffer[i]) & 0xFF] ^ (_zfe.Crc32 >> 8); } } } while (bytesRead == buffer.Length); outStream.Flush(); if (_zfe.Method == Compression.Deflate) { outStream.Dispose(); } _zfe.Crc32 ^= 0xffffffff; _zfe.FileSize = totalRead; _zfe.CompressedSize = (uint)(ZipFileStream.Position - posStart); // Verify for real compression if (_zfe.Method == Compression.Deflate && !ForceDeflating && _source.CanSeek && _zfe.CompressedSize > _zfe.FileSize) { // Start operation again with Store algorithm _zfe.Method = Compression.Store; ZipFileStream.Position = posStart; ZipFileStream.SetLength(posStart); _source.Position = sourceStart; Store(ref _zfe, _source); } }
private void WriteLocalHeader(ref ZipFileEntry _zfe) { /* Local file header: local file header signature 4 bytes (0x04034b50) version needed to extract 2 bytes general purpose bit flag 2 bytes compression method 2 bytes last mod file time 2 bytes last mod file date 2 bytes crc-32 4 bytes compressed size 4 bytes uncompressed size 4 bytes filename length 2 bytes extra field length 2 bytes filename (variable size) extra field (variable size) */ long pos = this.ZipFileStream.Position; Encoding encoder = _zfe.EncodeUTF8 ? Encoding.UTF8 : DefaultEncoding; byte[] encodedFilename = encoder.GetBytes(_zfe.FilenameInZip); this.ZipFileStream.Write(new byte[] { 80, 75, 3, 4, 20, 0}, 0, 6); this.ZipFileStream.Write(BitConverter.GetBytes((ushort)(_zfe.EncodeUTF8 ? 0x0800 : 0)), 0, 2); this.ZipFileStream.Write(BitConverter.GetBytes((ushort)_zfe.Method), 0, 2); this.ZipFileStream.Write(BitConverter.GetBytes(DateTimeToDosTime(_zfe.ModifyTime)), 0, 4); this.ZipFileStream.Write(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0, 12); this.ZipFileStream.Write(BitConverter.GetBytes((ushort)encodedFilename.Length), 0, 2); this.ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); this.ZipFileStream.Write(encodedFilename, 0, encodedFilename.Length); _zfe.HeaderSize = (uint)(this.ZipFileStream.Position - pos); }
/// <summary> /// Initializes a new instance of the <see cref="ZipStream"/> class. /// </summary> /// <param name="innerStream"> /// The inner stream. /// </param> /// <param name="zipFileEntry"> /// The zip file entry. /// </param> public ZipStream(Stream innerStream, ZipFileEntry zipFileEntry) { this.innerStream = innerStream; this.zipFileEntry = zipFileEntry; }
/// <summary> /// Add full contents of a stream into the Zip storage /// </summary> /// <param name="_method">Compression method</param> /// <param name="_filenameInZip">Filename and path as desired in Zip directory</param> /// <param name="_source">Stream object containing the data to store in Zip</param> /// <param name="_modTime">Modification time of the data to store</param> /// <param name="_comment">Comment for stored file</param> public void AddStream(Compression _method, string _filenameInZip, Stream _source, DateTime _modTime, string _comment) { if (Access == FileAccess.Read) throw new InvalidOperationException("Writing is not alowed"); long offset; if (this.Files.Count == 0) offset = 0; else { ZipFileEntry last = this.Files[this.Files.Count - 1]; offset = last.HeaderOffset + last.HeaderSize; } // Prepare the fileinfo ZipFileEntry zfe = new ZipFileEntry(); zfe.Method = _method; zfe.EncodeUTF8 = this.EncodeUTF8; zfe.FilenameInZip = NormalizedFilename(_filenameInZip); zfe.Comment = (_comment == null ? "" : _comment); // Even though we write the header now, it will have to be rewritten, since we don't know compressed size or crc. zfe.Crc32 = 0; // to be updated later zfe.HeaderOffset = (uint)this.ZipFileStream.Position; // offset within file of the start of this local record zfe.ModifyTime = _modTime; // Write local header WriteLocalHeader(ref zfe); zfe.FileOffset = (uint)this.ZipFileStream.Position; // Write file to zip (store) Store(ref zfe, _source); _source.Close(); this.UpdateCrcAndSizes(ref zfe); Files.Add(zfe); }
private void LoadHeader(ZipFileEntry entryHeader, Stream stream) { if (FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.Encrypted)) { if (!entryHeader.IsDirectory && entryHeader.CompressedSize == 0 && FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.UsePostDataDescriptor)) { throw new NotSupportedException( "TF.Common.SharpCompress cannot currently read non-seekable Zip Streams with encrypted data that has been written in a non-seekable manner."); } if (password == null) { throw new CryptographicException("No password supplied for encrypted zip."); } if (entryHeader.CompressionMethod != ZipCompressionMethod.WinzipAes) { byte[] buffer = new byte[12]; stream.Read(buffer, 0, 12); entryHeader.PkwareTraditionalEncryptionData = PkwareTraditionalEncryptionData.ForRead(password, entryHeader, buffer); entryHeader.CompressedSize -= 12; } else { #if PORTABLE || NETFX_CORE throw new NotSupportedException("Cannot decrypt Winzip AES with Silverlight or WP7."); #else var data = entryHeader.Extra.Where(x => x.Type == ExtraDataType.WinZipAes).SingleOrDefault(); WinzipAesKeySize keySize = (WinzipAesKeySize)data.DataBytes[4]; byte[] salt = new byte[WinzipAesEncryptionData.KeyLengthInBytes(keySize) / 2]; byte[] passwordVerifyValue = new byte[2]; stream.Read(salt, 0, salt.Length); stream.Read(passwordVerifyValue, 0, 2); entryHeader.WinzipAesEncryptionData = new WinzipAesEncryptionData(keySize, salt, passwordVerifyValue, password); entryHeader.CompressedSize -= (uint)(salt.Length + 2); #endif } } if (entryHeader.IsDirectory) { return; } //if (FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.UsePostDataDescriptor)) //{ // entryHeader.PackedStream = new ReadOnlySubStream(stream); //} //else //{ switch (mode) { case StreamingMode.Seekable: { entryHeader.DataStartPosition = stream.Position; stream.Position += entryHeader.CompressedSize; } break; case StreamingMode.Streaming: { entryHeader.PackedStream = stream; } break; default: { throw new InvalidFormatException("Invalid StreamingMode"); } } //} }
// Copies all source file into storage file private void Store(ref ZipFileEntry _zfe, Stream _source) { byte[] buffer = new byte[16384]; int bytesRead; uint totalRead = 0; Stream outStream; long posStart = this.ZipFileStream.Position; long sourceStart = _source.Position; if (_zfe.Method == Compression.Store) outStream = this.ZipFileStream; else outStream = new DeflateStream(this.ZipFileStream, CompressionMode.Compress, true); _zfe.Crc32 = 0 ^ 0xffffffff; do { bytesRead = _source.Read(buffer, 0, buffer.Length); totalRead += (uint)bytesRead; if (bytesRead > 0) { outStream.Write(buffer, 0, bytesRead); for (uint i = 0; i < bytesRead; i++) { _zfe.Crc32 = ZipStorer.CrcTable[(_zfe.Crc32 ^ buffer[i]) & 0xFF] ^ (_zfe.Crc32 >> 8); } } } while (bytesRead == buffer.Length); outStream.Flush(); if (_zfe.Method == Compression.Deflate) outStream.Dispose(); _zfe.Crc32 ^= 0xffffffff; _zfe.FileSize = totalRead; _zfe.CompressedSize = (uint)(this.ZipFileStream.Position - posStart); // Verify for real compression if (_zfe.Method == Compression.Deflate && !this.ForceDeflating && _source.CanSeek && _zfe.CompressedSize > _zfe.FileSize) { // Start operation again with Store algorithm _zfe.Method = Compression.Store; this.ZipFileStream.Position = posStart; this.ZipFileStream.SetLength(posStart); _source.Position = sourceStart; this.Store(ref _zfe, _source); } }
internal ZipFilePart(ZipFileEntry header, Stream stream) { Header = header; header.Part = this; BaseStream = stream; }
/* Central directory's File header: * central file header signature 4 bytes (0x02014b50) * version made by 2 bytes * version needed to extract 2 bytes * general purpose bit flag 2 bytes * compression method 2 bytes * last mod file time 2 bytes * last mod file date 2 bytes * crc-32 4 bytes * compressed size 4 bytes * uncompressed size 4 bytes * filename length 2 bytes * extra field length 2 bytes * file comment length 2 bytes * disk number start 2 bytes * internal file attributes 2 bytes * external file attributes 4 bytes * relative offset of local header 4 bytes * * filename (variable size) * extra field (variable size) * file comment (variable size) */ private void WriteCentralDirRecord(ZipFileEntry _zfe) { Encoding encoder = _zfe.EncodeUTF8 ? Encoding.UTF8 : DefaultEncoding; byte[] encodedFilename = encoder.GetBytes(_zfe.FilenameInZip); byte[] encodedComment = encoder.GetBytes(_zfe.Comment); ZipFileStream.Write(new byte[] { 80, 75, 1, 2, 23, 0xB, 20, 0 }, 0, 8); ZipFileStream.Write(BitConverter.GetBytes((ushort)(_zfe.EncodeUTF8 ? 0x0800 : 0)), 0, 2); // filename and comment encoding ZipFileStream.Write(BitConverter.GetBytes((ushort)_zfe.Method), 0, 2); // zipping method ZipFileStream.Write(BitConverter.GetBytes(DateTimeToDosTime(_zfe.ModifyTime)), 0, 4); // zipping date and time ZipFileStream.Write(BitConverter.GetBytes(_zfe.Crc32), 0, 4); // file CRC ZipFileStream.Write(BitConverter.GetBytes(_zfe.CompressedSize), 0, 4); // compressed file size ZipFileStream.Write(BitConverter.GetBytes(_zfe.FileSize), 0, 4); // uncompressed file size ZipFileStream.Write(BitConverter.GetBytes((ushort)encodedFilename.Length), 0, 2); // Filename in zip ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); // extra length ZipFileStream.Write(BitConverter.GetBytes((ushort)encodedComment.Length), 0, 2); ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); // disk=0 ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); // file type: binary ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); // Internal file attributes ZipFileStream.Write(BitConverter.GetBytes((ushort)0x8100), 0, 2); // External file attributes (normal/readable) ZipFileStream.Write(BitConverter.GetBytes(_zfe.HeaderOffset), 0, 4); // Offset of header ZipFileStream.Write(encodedFilename, 0, encodedFilename.Length); ZipFileStream.Write(encodedComment, 0, encodedComment.Length); }
/* CRC32 algorithm The 'magic number' for the CRC is 0xdebb20e3. The proper CRC pre and post conditioning is used, meaning that the CRC register is pre-conditioned with all ones (a starting value of 0xffffffff) and the value is post-conditioned by taking the one's complement of the CRC residual. If bit 3 of the general purpose flag is set, this field is set to zero in the local header and the correct value is put in the data descriptor and in the central directory. */ private void UpdateCrcAndSizes(ref ZipFileEntry zfe) { long lastPos = this.ZipFileStream.Position; // remember position zfe.Crc32 = 0 ^ 0xffffffff; this.ZipFileStream.Position = zfe.FileOffset; for (uint i = 0; i < zfe.FileSize; i++) { byte b = (byte)this.ZipFileStream.ReadByte(); zfe.Crc32 = ZipStorer.CrcTable[(zfe.Crc32 ^ b) & 0xff] ^ (zfe.Crc32 >> 8); } zfe.Crc32 ^= 0xffffffff; this.ZipFileStream.Position = zfe.HeaderOffset + 14; this.ZipFileStream.Write(BitConverter.GetBytes(zfe.Crc32), 0, 4); // Update CRC this.ZipFileStream.Write(BitConverter.GetBytes(zfe.FileSize), 0, 4); // Compressed size this.ZipFileStream.Write(BitConverter.GetBytes(zfe.FileSize), 0, 4); // Uncompressed size this.ZipFileStream.Position = lastPos; // restore position }
/// <summary> /// Add full contents of a stream into the Zip storage /// </summary> /// <param name="method">Compression method</param> /// <param name="fileNameInZip">File name and path as desired in Zip directory</param> /// <param name="source">Stream object containing the data to store in Zip</param> /// <param name="modTime">Modification time of the data to store</param> /// <param name="fileComment">Comment for stored file</param> public void AddStream( Compression method, [NotNull] string fileNameInZip, [NotNull] Stream source, DateTime modTime, [CanBeNull] string fileComment ) { if( fileNameInZip == null ) throw new ArgumentNullException( "fileNameInZip" ); if( source == null ) throw new ArgumentNullException( "source" ); if( access == FileAccess.Read ) throw new InvalidOperationException( "Writing is not alowed" ); /*long offset; if( Files.Count == 0 ) offset = 0; else { ZipFileEntry last = Files[Files.Count - 1]; offset = last.HeaderOffset + last.HeaderSize; }*/ // Prepare the fileinfo ZipFileEntry zfe = new ZipFileEntry { Method = method, EncodeUTF8 = EncodeUTF8, FileNameInZip = NormalizedFileName( fileNameInZip ), Comment = (fileComment ?? ""), Crc32 = 0, HeaderOffset = (uint)zipFileStream.Position, ModifyTime = modTime }; // Even though we write the header now, it will have to be rewritten, since we don't know compressed size or crc. // Write local header WriteLocalHeader( ref zfe ); zfe.FileOffset = (uint)zipFileStream.Position; // Write file to zip (store) Store( ref zfe, source ); source.Close(); UpdateCrcAndSizes( ref zfe ); files.Add( zfe ); }
/// <summary> /// Add full contents of a stream into the Zip storage /// </summary> /// <param name="method">Compression method</param> /// <param name="filenameInZip">Filename and path as desired in Zip directory</param> /// <param name="source">Stream object containing the data to store in Zip</param> /// <param name="modTime">Modification time of the data to store</param> /// <param name="comment">Comment for stored file</param> public void AddStream(Compression method, string filenameInZip, Stream source, DateTime modTime, string comment) { if (_access == FileAccess.Read) throw new InvalidOperationException("Writing is not alowed"); // Prepare the fileinfo var zfe = new ZipFileEntry { Method = method, EncodeUTF8 = EncodeUTF8, FilenameInZip = NormalizedFilename(filenameInZip), Comment = (comment ?? string.Empty), Crc32 = 0, HeaderOffset = (uint) _zipFileStream.Position, ModifyTime = modTime }; // Even though we write the header now, it will have to be rewritten, since we don't know compressed size or crc. // Write local header WriteLocalHeader(ref zfe); zfe.FileOffset = (uint) _zipFileStream.Position; // Write file to zip (store) Store(ref zfe, source); source.Close(); UpdateCrcAndSizes(ref zfe); _files.Add(zfe); }
// Copies all source file into storage file private void Store( ref ZipFileEntry zfe, Stream source ) { byte[] buffer = new byte[16384]; int bytesRead; uint totalRead = 0; Stream outStream; long posStart = zipFileStream.Position; long sourceStart = source.Position; if( zfe.Method == Compression.Store ) outStream = zipFileStream; else outStream = new DeflateStream( zipFileStream, CompressionMode.Compress, true ); zfe.Crc32 = 0 ^ 0xffffffff; do { bytesRead = source.Read( buffer, 0, buffer.Length ); totalRead += (uint)bytesRead; if( bytesRead > 0 ) { outStream.Write( buffer, 0, bytesRead ); for( uint i = 0; i < bytesRead; i++ ) { zfe.Crc32 = CrcTable[(zfe.Crc32 ^ buffer[i]) & 0xFF] ^ (zfe.Crc32 >> 8); } } } while( bytesRead == buffer.Length ); if( totalRead > 0 ) outStream.Flush(); // fix for "Internal error Flush" under Mono if( zfe.Method == Compression.Deflate ) outStream.Dispose(); zfe.Crc32 ^= 0xffffffff; zfe.FileSize = totalRead; zfe.CompressedSize = (uint)(zipFileStream.Position - posStart); // Verify for real compression if( zfe.Method == Compression.Deflate && !ForceDeflating && source.CanSeek && zfe.CompressedSize > zfe.FileSize ) { // Start operation again with Store algorithm zfe.Method = Compression.Store; zipFileStream.Position = posStart; zipFileStream.SetLength( posStart ); source.Position = sourceStart; Store( ref zfe, source ); } }
/// <summary> /// Copy the contents of a stored file into an opened stream /// </summary> /// <param name="zfe">Entry information of file to extract</param> /// <param name="stream">Stream to store the uncompressed data</param> /// <returns>True if success, false if not.</returns> /// <remarks>Unique compression methods are Store and Deflate</remarks> public bool ExtractFile(ZipFileEntry zfe, Stream stream) { if (!stream.CanWrite) throw new InvalidOperationException("Stream cannot be written"); // check signature var signature = new byte[4]; _zipFileStream.Seek(zfe.HeaderOffset, SeekOrigin.Begin); _zipFileStream.Read(signature, 0, 4); if (BitConverter.ToUInt32(signature, 0) != 0x04034b50) return false; // Select input stream for inflating or just reading Stream inStream; switch (zfe.Method) { case Compression.Store: inStream = _zipFileStream; break; case Compression.Deflate: inStream = new DeflateStream(_zipFileStream, CompressionMode.Decompress, true); break; default: return false; } // Buffered copy var buffer = new byte[16384]; _zipFileStream.Seek(zfe.FileOffset, SeekOrigin.Begin); var bytesPending = zfe.FileSize; while (bytesPending > 0) { var bytesRead = inStream.Read(buffer, 0, (int) Math.Min(bytesPending, buffer.Length)); stream.Write(buffer, 0, bytesRead); bytesPending -= (uint) bytesRead; } stream.Flush(); if (zfe.Method == Compression.Deflate) inStream.Dispose(); return true; }
public Stream GetStream(ZipFileEntry _zfe) { // check signature byte[] signature = new byte[4]; this.ZipFileStream.Seek(_zfe.HeaderOffset, SeekOrigin.Begin); this.ZipFileStream.Read(signature, 0, 4); if (BitConverter.ToUInt32(signature, 0) != 0x04034b50) throw new Exception("Bad signature"); // Select input stream for inflating or just reading Stream inStream = null; if (_zfe.Method == Compression.Store) inStream = this.ZipFileStream; else if (_zfe.Method == Compression.Deflate) inStream = new DeflateStream(this.ZipFileStream, CompressionMode.Decompress, true); else throw new Exception("Unsupoorted comprension"); this.ZipFileStream.Seek(_zfe.FileOffset, SeekOrigin.Begin); return inStream; }
/// <summary> /// Read all the file records in the central directory /// </summary> /// <returns>List of all entries in directory</returns> public List<ZipFileEntry> ReadCentralDir() { if (_centralDirImage == null) throw new InvalidOperationException("Central directory currently does not exist"); var result = new List<ZipFileEntry>(); for (var pointer = 0; pointer < _centralDirImage.Length;) { var signature = BitConverter.ToUInt32(_centralDirImage, pointer); if (signature != 0x02014b50) break; var encodeUTF8 = (BitConverter.ToUInt16(_centralDirImage, pointer + 8) & 0x0800) != 0; var method = BitConverter.ToUInt16(_centralDirImage, pointer + 10); var modifyTime = BitConverter.ToUInt32(_centralDirImage, pointer + 12); var crc32 = BitConverter.ToUInt32(_centralDirImage, pointer + 16); var comprSize = BitConverter.ToUInt32(_centralDirImage, pointer + 20); var fileSize = BitConverter.ToUInt32(_centralDirImage, pointer + 24); var filenameSize = BitConverter.ToUInt16(_centralDirImage, pointer + 28); var extraSize = BitConverter.ToUInt16(_centralDirImage, pointer + 30); var commentSize = BitConverter.ToUInt16(_centralDirImage, pointer + 32); var headerOffset = BitConverter.ToUInt32(_centralDirImage, pointer + 42); var headerSize = (uint) (46 + filenameSize + extraSize + commentSize); var encoder = encodeUTF8 ? Encoding.UTF8 : DefaultEncoding; var zfe = new ZipFileEntry { Method = (Compression) method, FilenameInZip = encoder.GetString(_centralDirImage, pointer + 46, filenameSize), FileOffset = GetFileOffset(headerOffset), FileSize = fileSize, CompressedSize = comprSize, HeaderOffset = headerOffset, HeaderSize = headerSize, Crc32 = crc32, ModifyTime = DosTimeToDateTime(modifyTime) }; if (commentSize > 0) zfe.Comment = encoder.GetString(_centralDirImage, pointer + 46 + filenameSize + extraSize, commentSize); result.Add(zfe); pointer += (46 + filenameSize + extraSize + commentSize); } return result; }
/// <summary> /// /// </summary> /// <param name="_method"></param> /// <param name="_filenameInZip"></param> /// <param name="_source"></param> /// <param name="_modTime"></param> /// <param name="_comment"></param> /// <exception cref="InvalidOperationException"></exception> public void AddStream(Compression _method, string _filenameInZip, Stream _source, DateTime _modTime, string _comment) { if (Access == FileAccess.Read) throw new InvalidOperationException("Writing is not allowed."); long offset; if (this.Files.Count==0) offset = 0; else { ZipFileEntry last = this.Files[this.Files.Count-1]; offset = last.HeaderOffset + last.HeaderSize; } ZipFileEntry zfe = new ZipFileEntry(); zfe.Method = _method; zfe.EncodeUTF8 = this.EncodeUTF8; zfe.FilenameInZip = NormalizedFilename(_filenameInZip); zfe.Comment = (_comment == null ? "" : _comment); zfe.Crc32 = 0; zfe.HeaderOffset = (uint)this.ZipFileStream.Position; zfe.ModifyTime = _modTime; WriteLocalHeader(ref zfe); zfe.FileOffset = (uint)this.ZipFileStream.Position; Store(ref zfe, _source); _source.Close(); this.UpdateCrcAndSizes(ref zfe); Files.Add(zfe); }
// Copies all source file into storage file private void Store(ref ZipFileEntry zfe, Stream source) { var buffer = new byte[16384]; int bytesRead; uint totalRead = 0; var posStart = _zipFileStream.Position; var sourceStart = source.Position; Stream outStream = zfe.Method == Compression.Store ? _zipFileStream : new DeflateStream(_zipFileStream, CompressionMode.Compress, true); zfe.Crc32 = 0 ^ 0xffffffff; do { bytesRead = source.Read(buffer, 0, buffer.Length); totalRead += (uint) bytesRead; if (bytesRead <= 0) continue; outStream.Write(buffer, 0, bytesRead); for (uint i = 0; i < bytesRead; i++) zfe.Crc32 = CrcTable[(zfe.Crc32 ^ buffer[i]) & 0xFF] ^ (zfe.Crc32 >> 8); } while (bytesRead == buffer.Length); outStream.Flush(); if (zfe.Method == Compression.Deflate) outStream.Dispose(); zfe.Crc32 ^= 0xffffffff; zfe.FileSize = totalRead; zfe.CompressedSize = (uint) (_zipFileStream.Position - posStart); // Verify for real compression if (zfe.Method != Compression.Deflate || ForceDeflating || !source.CanSeek || zfe.CompressedSize <= zfe.FileSize) return; // Start operation again with Store algorithm zfe.Method = Compression.Store; _zipFileStream.Position = posStart; _zipFileStream.SetLength(posStart); source.Position = sourceStart; Store(ref zfe, source); }
private void WriteCentralDirRecord(ZipFileEntry _zfe) { /* Central directory's File header: central file header signature 4 bytes (0x02014b50) version made by 2 bytes version needed to extract 2 bytes general purpose bit flag 2 bytes compression method 2 bytes last mod file time 2 bytes last mod file date 2 bytes crc-32 4 bytes compressed size 4 bytes uncompressed size 4 bytes filename length 2 bytes extra field length 2 bytes file comment length 2 bytes disk number start 2 bytes internal file attributes 2 bytes external file attributes 4 bytes relative offset of local header 4 bytes filename (variable size) extra field (variable size) file comment (variable size) */ Encoding encoder = _zfe.EncodeUTF8 ? Encoding.UTF8 : DefaultEncoding; byte[] encodedFilename = encoder.GetBytes(_zfe.FilenameInZip); byte[] encodedComment = encoder.GetBytes(_zfe.Comment); this.ZipFileStream.Write(new byte[] { 80, 75, 1, 2, 23, 0xB, 20, 0 }, 0, 8); this.ZipFileStream.Write(BitConverter.GetBytes((ushort)(_zfe.EncodeUTF8 ? 0x0800 : 0)), 0, 2); this.ZipFileStream.Write(BitConverter.GetBytes((ushort)_zfe.Method), 0, 2); this.ZipFileStream.Write(BitConverter.GetBytes(DateTimeToDosTime(_zfe.ModifyTime)), 0, 4); this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.Crc32), 0, 4); this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.CompressedSize), 0, 4); this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.FileSize), 0, 4); this.ZipFileStream.Write(BitConverter.GetBytes((ushort)encodedFilename.Length), 0, 2); this.ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); this.ZipFileStream.Write(BitConverter.GetBytes((ushort)encodedComment.Length), 0, 2); this.ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); this.ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); this.ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); this.ZipFileStream.Write(BitConverter.GetBytes((ushort)0x8100), 0, 2); this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.HeaderOffset), 0, 4); this.ZipFileStream.Write(encodedFilename, 0, encodedFilename.Length); this.ZipFileStream.Write(encodedComment, 0, encodedComment.Length); }
/* CRC32 algorithm The 'magic number' for the CRC is 0xdebb20e3. The proper CRC pre and post conditioning is used, meaning that the CRC register is pre-conditioned with all ones (a starting value of 0xffffffff) and the value is post-conditioned by taking the one's complement of the CRC residual. If bit 3 of the general purpose flag is set, this field is set to zero in the local header and the correct value is put in the data descriptor and in the central directory. */ private void UpdateCrcAndSizes(ref ZipFileEntry zfe) { var lastPos = _zipFileStream.Position; // remember position _zipFileStream.Position = zfe.HeaderOffset + 8; _zipFileStream.Write(BitConverter.GetBytes((ushort) zfe.Method), 0, 2); // zipping method _zipFileStream.Position = zfe.HeaderOffset + 14; _zipFileStream.Write(BitConverter.GetBytes(zfe.Crc32), 0, 4); // Update CRC _zipFileStream.Write(BitConverter.GetBytes(zfe.CompressedSize), 0, 4); // Compressed size _zipFileStream.Write(BitConverter.GetBytes(zfe.FileSize), 0, 4); // Uncompressed size _zipFileStream.Position = lastPos; // restore position }
/// <summary> /// Copy the contents of a stored file into a physical file /// </summary> /// <param name="_zfe">Entry information of file to extract</param> /// <param name="_filename">Name of file to store uncompressed data</param> /// <returns>True if success, false if not.</returns> /// <remarks>Unique compression methods are Store and Deflate</remarks> public bool ExtractStoredFile(ZipFileEntry _zfe, string _filename) { // check signature byte[] signature = new byte[4]; this.ZipFileStream.Seek(_zfe.HeaderOffset, SeekOrigin.Begin); this.ZipFileStream.Read(signature, 0, 4); if (BitConverter.ToUInt32(signature, 0) != 0x04034b50) return false; // Select input stream for inflating or just reading Stream inStream; if (_zfe.Method == Compression.Store) inStream = this.ZipFileStream; else if (_zfe.Method == Compression.Deflate) inStream = new DeflateStream(this.ZipFileStream, CompressionMode.Decompress, true); else return false; // Make sure the parent directory exist string path = System.IO.Path.GetDirectoryName(_filename); if (!Directory.Exists(path)) Directory.CreateDirectory(path); // Check it is directory. If so, do nothing if (Directory.Exists(_filename)) return true; FileStream output = new FileStream(_filename, FileMode.Create, FileAccess.Write); // Buffered copy byte[] buffer = new byte[16384]; this.ZipFileStream.Seek(_zfe.FileOffset, SeekOrigin.Begin); uint bytesPending = _zfe.FileSize; while (bytesPending > 0) { int bytesRead = inStream.Read(buffer, 0, (int)Math.Min(bytesPending, buffer.Length)); output.Write(buffer, 0, bytesRead); bytesPending -= (uint)bytesRead; } output.Close(); if (_zfe.Method == Compression.Deflate) inStream.Dispose(); return true; }
/// <summary> /// Copy the contents of a stored file into a physical file /// </summary> /// <param name="_zfe">Entry information of file to extract</param> /// <param name="_filename">Name of file to store uncompressed data</param> /// <returns>True if success, false if not.</returns> /// <remarks>Unique compression methods are Store and Deflate</remarks> public bool ExtractFile(ZipFileEntry _zfe, string _filename) { // Make sure the parent directory exist string path = System.IO.Path.GetDirectoryName(_filename); if (!Directory.Exists(path)) Directory.CreateDirectory(path); // Check it is directory. If so, do nothing if (Directory.Exists(_filename)) return true; Stream output = new FileStream(_filename, FileMode.Create, FileAccess.Write); bool result = ExtractFile(_zfe, output); if (result) output.Close(); File.SetCreationTime(_filename, _zfe.ModifyTime); File.SetLastWriteTime(_filename, _zfe.ModifyTime); return result; }
// Copies all source file into storage file private void Store(ref ZipFileEntry zfe, Stream source) { byte[] buffer = new byte[16384]; int bytesRead; uint totalRead = 0; Stream outStream; long posStart = this.ZipFileStream.Position; if (zfe.Method == Compression.Store) outStream = this.ZipFileStream; else outStream = new DeflateStream(this.ZipFileStream, CompressionMode.Compress, true); zfe.Crc32 = 0 ^ 0xffffffff; do { bytesRead = source.Read(buffer, 0, buffer.Length); totalRead += (uint)bytesRead; if (bytesRead > 0) { outStream.Write(buffer, 0, bytesRead); for (uint i = 0; i < bytesRead; i++) { zfe.Crc32 = ZipStorer.CrcTable[(zfe.Crc32 ^ buffer[i]) & 0xFF] ^ (zfe.Crc32 >> 8); } } } while (bytesRead == buffer.Length); outStream.Flush(); if (zfe.Method == Compression.Deflate) outStream.Dispose(); zfe.Crc32 ^= 0xffffffff; zfe.FileSize = totalRead; zfe.CompressedSize = (uint)(this.ZipFileStream.Position - posStart); }
/// <summary> /// Read all the file records in the central directory /// </summary> /// <returns>List of all entries in directory</returns> public List<ZipFileEntry> ReadCentralDir() { if (this.CentralDirImage == null) throw new InvalidOperationException("Central directory currently does not exist"); List<ZipFileEntry> result = new List<ZipFileEntry>(); for (int pointer = 0; pointer < this.CentralDirImage.Length; ) { uint signature = BitConverter.ToUInt32(CentralDirImage, pointer); if (signature != 0x02014b50) break; bool encodeUTF8 = (BitConverter.ToUInt16(CentralDirImage, pointer + 8) & 0x0800) != 0; ushort method = BitConverter.ToUInt16(CentralDirImage, pointer + 10); uint modifyTime = BitConverter.ToUInt32(CentralDirImage, pointer + 12); uint crc32 = BitConverter.ToUInt32(CentralDirImage, pointer + 16); uint comprSize = BitConverter.ToUInt32(CentralDirImage, pointer + 20); uint fileSize = BitConverter.ToUInt32(CentralDirImage, pointer + 24); ushort filenameSize = BitConverter.ToUInt16(CentralDirImage, pointer + 28); ushort extraSize = BitConverter.ToUInt16(CentralDirImage, pointer + 30); ushort commentSize = BitConverter.ToUInt16(CentralDirImage, pointer + 32); uint headerOffset = BitConverter.ToUInt32(CentralDirImage, pointer + 42); uint headerSize = (uint)(46 + filenameSize + extraSize + commentSize); Encoding encoder = encodeUTF8 ? Encoding.UTF8 : DefaultEncoding; ZipFileEntry zfe = new ZipFileEntry(); zfe.Method = (Compression)method; zfe.FilenameInZip = encoder.GetString(CentralDirImage, pointer + 46, filenameSize); zfe.FileOffset = GetFileOffset(headerOffset); zfe.FileSize = fileSize; zfe.CompressedSize = comprSize; zfe.HeaderOffset = headerOffset; zfe.HeaderSize = headerSize; zfe.Crc32 = crc32; zfe.ModifyTime = DosTimeToDateTime(modifyTime); if (commentSize > 0) zfe.Comment = encoder.GetString(CentralDirImage, pointer + 46 + filenameSize + extraSize, commentSize); result.Add(zfe); pointer += (46 + filenameSize + extraSize + commentSize); } return result; }
/* Local file header: local file header signature 4 bytes (0x04034b50) version needed to extract 2 bytes general purpose bit flag 2 bytes compression method 2 bytes last mod file time 2 bytes last mod file date 2 bytes crc-32 4 bytes compressed size 4 bytes uncompressed size 4 bytes filename length 2 bytes extra field length 2 bytes filename (variable size) extra field (variable size) */ private void WriteLocalHeader(ref ZipFileEntry zfe) { long pos = this.ZipFileStream.Position; byte[] encodedFilename = FilenameEncoder.GetBytes(zfe.FilenameInZip); this.ZipFileStream.Write(new byte[] { 80, 75, 3, 4, 20, 0, 0, 0 }, 0, 8); // No extra header this.ZipFileStream.Write(BitConverter.GetBytes((ushort)zfe.Method), 0, 2); // zipping method this.ZipFileStream.Write(BitConverter.GetBytes(DosTime(zfe.ModifyTime)), 0, 4); // zipping date and time this.ZipFileStream.Write(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0, 12); // unused CRC, un/compressed size, updated later this.ZipFileStream.Write(BitConverter.GetBytes((ushort)encodedFilename.Length), 0, 2); // filename length this.ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); // extra length this.ZipFileStream.Write(encodedFilename, 0, encodedFilename.Length); zfe.HeaderSize = (uint)(this.ZipFileStream.Position - pos); }
/* CRC32 algorithm 656 The 'magic number' for the CRC is 0xdebb20e3. 657 The proper CRC pre and post conditioning 658 is used, meaning that the CRC register is 659 pre-conditioned with all ones (a starting value 660 of 0xffffffff) and the value is post-conditioned by 661 taking the one's complement of the CRC residual. 662 If bit 3 of the general purpose flag is set, this 663 field is set to zero in the local header and the correct 664 value is put in the data descriptor and in the central 665 directory. 666 */ private void UpdateCrcAndSizes(ref ZipFileEntry _zfe) { long lastPos = this.ZipFileStream.Position; // remember position this.ZipFileStream.Position = _zfe.HeaderOffset + 8; this.ZipFileStream.Write(BitConverter.GetBytes((ushort)_zfe.Method), 0, 2); // zipping method this.ZipFileStream.Position = _zfe.HeaderOffset + 14; this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.Crc32), 0, 4); // Update CRC this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.CompressedSize), 0, 4); // Compressed size this.ZipFileStream.Write(BitConverter.GetBytes(_zfe.FileSize), 0, 4); // Uncompressed size this.ZipFileStream.Position = lastPos; // restore position }
public bool ExtractFile(ZipFileEntry _zfe, string _filename) { return ExtractFile(_zfe, _filename, 0); }
/* Local file header: local file header signature 4 bytes (0x04034b50) version needed to extract 2 bytes general purpose bit flag 2 bytes compression method 2 bytes last mod file time 2 bytes last mod file date 2 bytes crc-32 4 bytes compressed size 4 bytes uncompressed size 4 bytes filename length 2 bytes extra field length 2 bytes filename (variable size) extra field (variable size) */ private void WriteLocalHeader(ref ZipFileEntry _zfe) { long pos = this.ZipFileStream.Position; Encoding encoder = _zfe.EncodeUTF8 ? Encoding.UTF8 : DefaultEncoding; byte[] encodedFilename = encoder.GetBytes(_zfe.FilenameInZip); this.ZipFileStream.Write(new byte[] { 80, 75, 3, 4, 20, 0 }, 0, 6); // No extra header this.ZipFileStream.Write(BitConverter.GetBytes((ushort)(_zfe.EncodeUTF8 ? 0x0800 : 0)), 0, 2); // filename and comment encoding this.ZipFileStream.Write(BitConverter.GetBytes((ushort)_zfe.Method), 0, 2); // zipping method this.ZipFileStream.Write(BitConverter.GetBytes(DateTimeToDosTime(_zfe.ModifyTime)), 0, 4); // zipping date and time this.ZipFileStream.Write(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0, 12); // unused CRC, un/compressed size, updated later this.ZipFileStream.Write(BitConverter.GetBytes((ushort)encodedFilename.Length), 0, 2); // filename length this.ZipFileStream.Write(BitConverter.GetBytes((ushort)0), 0, 2); // extra length this.ZipFileStream.Write(encodedFilename, 0, encodedFilename.Length); _zfe.HeaderSize = (uint)(this.ZipFileStream.Position - pos); }
internal StreamingZipFilePart(ZipFileEntry header, Stream stream) : base(header, stream) { }