/// <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; } }
public void AddFile(Stream stream, string packageUri, string mimeType, CompressionLevel level) { string partName = this.DeterminePartName(packageUri); ContentType contentType = this.DetermineContentType(partName, mimeType); ZipFileHeader localFileHeader = new ZipFileHeader(false); localFileHeader.localHeaderOffset = (uint)this.BaseStream.Position; localFileHeader.zip64 = stream.Length > 0xFFFFFFFF; localFileHeader.versionMadeBy = 0; localFileHeader.versionNeeded = localFileHeader.zip64 ? (ushort)45 : (ushort)20; localFileHeader.fileName = partName; localFileHeader.compressionMethod = (level == CompressionLevel.NoCompression) ? ZipCompressionMethod.Store : ZipCompressionMethod.Deflate; localFileHeader.flags = this.BaseStream.CanSeek ? ZipFileFlags.None : ZipFileFlags.DataDescriptor; localFileHeader.Write(this.BaseStream); BlockMapFile blockMapFile = new BlockMapFile(partName) { Size = stream.Length, ZipLocalFileHeaderSize = localFileHeader.GetSize() }; this.blockMapFiles.Add(blockMapFile); ZipCrc crc = new ZipCrc(); BlockDeflateStream deflate = (level == CompressionLevel.NoCompression) ? null : new BlockDeflateStream(this.BaseStream, (BlockDeflateCompressionLevel)level); long outputStart = this.BaseStream.Position; int read = 0; byte[] buffer = new byte[64 * 1024]; while (0 < (read = stream.Read(buffer, 0, buffer.Length))) { crc.UpdateCrc(buffer, 0, read); string hash; using (SHA256 sha256 = SHA256.Create()) { byte[] hashedBytes = sha256.ComputeHash(buffer, 0, read); hash = Convert.ToBase64String(hashedBytes); } long compressedBlockSize = 0; if (deflate != null) { compressedBlockSize = deflate.Deflate(buffer, 0, read); } else { this.BaseStream.Write(buffer, 0, read); compressedBlockSize = -1; } BlockMapFileBlock block = new BlockMapFileBlock() { Hash = hash, CompressedSize = compressedBlockSize }; blockMapFile.Blocks.Add(block); } if (deflate != null) { deflate.Flush(); } else { this.BaseStream.Flush(); } // Update the local file header with data discovered while processing file data. localFileHeader.crc32 = crc.Crc; localFileHeader.compressedSize = (uint)(this.BaseStream.Position - outputStart); // (uint)compressedSize; localFileHeader.uncompressedSize = (uint)stream.Length; // If we're using the data descriptor (because we can't see), append the updated information to the file data. if ((localFileHeader.flags & ZipFileFlags.DataDescriptor) == ZipFileFlags.DataDescriptor) { localFileHeader.WriteDataDescriptor(this.BaseStream); } else // go back to re-write the updated local file header in place, then seek back to our current location. { long position = this.BaseStream.Position; this.BaseStream.Seek(localFileHeader.localHeaderOffset, SeekOrigin.Begin); localFileHeader.Write(this.BaseStream); this.BaseStream.Seek(position, SeekOrigin.Begin); } // If we have a 64-bit local header then the central directory must be // ZIP64 as well. if (localFileHeader.zip64) { this.eocd.zip64 = true; this.eocd.versionMadeBy = 45; this.eocd.versionNeeded = 45; } ZipFileHeader centralFileHeader = new ZipFileHeader(localFileHeader); this.eocd.CentralDirectory.Add(centralFileHeader); }
public ZipEndOfCentralDirectory(Stream stream) { BinaryReader reader = new BinaryReader(stream); // Start searching for the Zip End of Central Directory signature from the end // of the file backwards (towards the beginning of the file). This allows us to // find Zip archives with extra data appended to the archive (for whatever reason // someone might want to do that). long offset = stream.Length - ZipEndOfCentralDirectory.EOCD_RECORD_FIXEDSIZE; for (; offset >= 0; --offset) { stream.Seek(offset, SeekOrigin.Begin); uint sig = reader.ReadUInt32(); if (sig == ZipEndOfCentralDirectory.EOCDSIG) { break; } } if (offset < 0) { throw new InvalidDataException("Failed to find end of central directory record."); } stream.Seek(offset, SeekOrigin.Begin); this.Read(stream); // If the offset to the central directory is DWORD_MAX then this must be a 64-bit // archive. if (this.dirOffset == (long)UInt32.MaxValue) { string saveComment = this.comment; stream.Seek(offset - Zip64EndOfCentralDirectoryLocator.EOCDL64_SIZE, SeekOrigin.Begin); Zip64EndOfCentralDirectoryLocator eocdl = new Zip64EndOfCentralDirectoryLocator(stream); if (eocdl.dirStartDiskNumber == eocdl.totalDisks - 1) { // ZIP64 eocd is entirely in current stream. stream.Seek(eocdl.dirOffset, SeekOrigin.Begin); this.Read64(stream); } else { // TODO: handle EOCD64 spanning archives! throw new NotImplementedException("Zip implementation does not handle end of central directory record that spans archives."); } this.comment = saveComment; } // Read the central directory for the archive. stream.Seek(this.dirOffset, SeekOrigin.Begin); while (this.headers.Count < this.totalEntries) { ZipFileHeader header = new ZipFileHeader(true); if (!header.Read(stream)) { throw new InvalidDataException("Missing or invalid central directory file header"); } this.headers.Add(header); if (this.headers.Count < this.totalEntries && stream.Position == stream.Length) { //streamContext.CloseArchiveReadStream(this.currentArchiveNumber, String.Empty, archiveStream); //this.currentArchiveNumber++; //archiveStream = streamContext.OpenArchiveReadStream(this.currentArchiveNumber, String.Empty, this); //if (archiveStream == null) //{ // this.currentArchiveNumber = 0; // archiveStream = streamContext.OpenArchiveReadStream(this.currentArchiveNumber, String.Empty, this); //} } } }
public IList <ZipFileHeader> GetCentralDirectory(Stream streamContext) { Stream archiveStream = null; //this.currentArchiveNumber = 0; try { List <ZipFileHeader> headers = new List <ZipFileHeader>(); archiveStream = streamContext; //archiveStream = this.OpenArchive(streamContext, 0); ZipEndOfCentralDirectory eocd = this.GetEOCD(archiveStream); if (eocd == null) { return(null); } else if (eocd.totalEntries == 0) { return(headers); } headers.Capacity = (int)eocd.totalEntries; if (eocd.dirOffset > archiveStream.Length - ZipFileHeader.CFH_FIXEDSIZE) { //streamContext.CloseArchiveReadStream(this.currentArchiveNumber, String.Empty, archiveStream); archiveStream = null; } else { archiveStream.Seek(eocd.dirOffset, SeekOrigin.Begin); uint sig = new BinaryReader(archiveStream).ReadUInt32(); if (sig != ZipFileHeader.CFHSIG) { //streamContext.CloseArchiveReadStream(this.currentArchiveNumber, String.Empty, archiveStream); archiveStream = null; } } if (archiveStream == null) { //this.currentArchiveNumber = (short)(eocd.dirStartDiskNumber + 1); //archiveStream = streamContext.OpenArchiveReadStream(this.currentArchiveNumber, String.Empty, this); if (archiveStream == null) { return(null); } } archiveStream.Seek(eocd.dirOffset, SeekOrigin.Begin); while (headers.Count < eocd.totalEntries) { ZipFileHeader header = new ZipFileHeader(true); if (!header.Read(archiveStream)) { throw new InvalidDataException("Missing or invalid central directory file header"); } headers.Add(header); if (headers.Count < eocd.totalEntries && archiveStream.Position == archiveStream.Length) { //streamContext.CloseArchiveReadStream(this.currentArchiveNumber, String.Empty, archiveStream); //this.currentArchiveNumber++; //archiveStream = streamContext.OpenArchiveReadStream(this.currentArchiveNumber, String.Empty, this); //if (archiveStream == null) //{ // this.currentArchiveNumber = 0; // archiveStream = streamContext.OpenArchiveReadStream(this.currentArchiveNumber, String.Empty, this); //} } } return(headers); } finally { //if (archiveStream != null) //{ // streamContext.CloseArchiveReadStream(this.currentArchiveNumber, String.Empty, archiveStream); //} } }