/// <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; }
/// <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(this.centralDirImage, pointer); if (signature != 0x02014b50) { break; } bool encodeUtf8 = (BitConverter.ToUInt16(this.centralDirImage, pointer + 8) & 0x0800) != 0; ushort method = BitConverter.ToUInt16(this.centralDirImage, pointer + 10); uint modifyTime = BitConverter.ToUInt32(this.centralDirImage, pointer + 12); uint crc32 = BitConverter.ToUInt32(this.centralDirImage, pointer + 16); uint comprSize = BitConverter.ToUInt32(this.centralDirImage, pointer + 20); uint fileSize = BitConverter.ToUInt32(this.centralDirImage, pointer + 24); ushort filenameSize = BitConverter.ToUInt16(this.centralDirImage, pointer + 28); ushort extraSize = BitConverter.ToUInt16(this.centralDirImage, pointer + 30); ushort commentSize = BitConverter.ToUInt16(this.centralDirImage, pointer + 32); uint headerOffset = BitConverter.ToUInt32(this.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(this.centralDirImage, pointer + 46, filenameSize); zfe.FileOffset = this.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(this.centralDirImage, pointer + 46 + filenameSize + extraSize, commentSize); } result.Add(zfe); pointer += (46 + filenameSize + extraSize + commentSize); } return result; }
/// <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 = Path.GetDirectoryName(filename); if (!Directory.Exists(path)) { if (path != null) { Directory.CreateDirectory(path); } } // Check it is directory. If so, do nothing if (Directory.Exists(filename)) { return true; } bool result = false; using (Stream output = new FileStream(filename, FileMode.Create, FileAccess.Write)) { result = this.ExtractFile(zfe, output); } File.SetCreationTime(filename, zfe.ModifyTime); File.SetLastWriteTime(filename, zfe.ModifyTime); return result; }