public ZipFileHeader(ZipFileInfo fileInfo, bool zip64) : this() { flags = ZipFileFlags.None; compressionMethod = fileInfo.CompressionMethod; fileName = Path.Combine(fileInfo.Path, fileInfo.Name); CompressionEngine.DateTimeToDosDateAndTime( fileInfo.LastWriteTime, out lastModDate, out lastModTime); this.zip64 = zip64; if (this.zip64) { compressedSize = UInt32.MaxValue; uncompressedSize = UInt32.MaxValue; diskStart = UInt16.MaxValue; versionMadeBy = 45; versionNeeded = 45; ZipExtraFileField field = new ZipExtraFileField(); field.fieldType = ZipExtraFileFieldType.ZIP64; field.SetZip64Data( fileInfo.CompressedLength, fileInfo.Length, 0, fileInfo.ArchiveNumber); extraFields = new[] { field }; } else { compressedSize = (uint)fileInfo.CompressedLength; uncompressedSize = (uint)fileInfo.Length; diskStart = (ushort)fileInfo.ArchiveNumber; } }
/// <summary> /// Unpacks a single file from an archive or archive chain. /// </summary> private void UnpackOneFile( IUnpackStreamContext streamContext, ZipFileHeader header, ref Stream archiveStream) { ZipFileInfo fileInfo = null; Stream fileStream = null; try { Converter <Stream, Stream> compressionStreamCreator; if (!ZipEngine.decompressionStreamCreators.TryGetValue( header.compressionMethod, out compressionStreamCreator)) { // Silently skip files of an unsupported compression method. return; } long compressedSize; long uncompressedSize; long localHeaderOffset; int archiveNumber; uint crc; header.GetZip64Fields( out compressedSize, out uncompressedSize, out localHeaderOffset, out archiveNumber, out crc); if (this.currentArchiveNumber != archiveNumber + 1) { if (archiveStream != null) { streamContext.CloseArchiveReadStream( this.currentArchiveNumber, String.Empty, archiveStream); archiveStream = null; this.OnProgress(ArchiveProgressType.FinishArchive); this.currentArchiveName = null; } this.currentArchiveNumber = (short)(archiveNumber + 1); this.currentArchiveBytesProcessed = 0; this.currentArchiveTotalBytes = 0; archiveStream = this.OpenArchive( streamContext, this.currentArchiveNumber); FileStream archiveFileStream = archiveStream as FileStream; this.currentArchiveName = (archiveFileStream != null ? Path.GetFileName(archiveFileStream.Name) : null); this.currentArchiveTotalBytes = archiveStream.Length; this.currentArchiveNumber--; this.OnProgress(ArchiveProgressType.StartArchive); this.currentArchiveNumber++; } archiveStream.Seek(localHeaderOffset, SeekOrigin.Begin); ZipFileHeader localHeader = new ZipFileHeader(); if (!localHeader.Read(archiveStream, false) || !ZipEngine.AreFilePathsEqual(localHeader.fileName, header.fileName)) { string msg = "Could not read file: " + header.fileName; throw new ZipException(msg); } fileInfo = header.ToZipFileInfo(); fileStream = streamContext.OpenFileWriteStream( fileInfo.FullName, fileInfo.Length, fileInfo.LastWriteTime); if (fileStream != null) { this.currentFileName = header.fileName; this.currentFileBytesProcessed = 0; this.currentFileTotalBytes = fileInfo.Length; this.currentArchiveNumber--; this.OnProgress(ArchiveProgressType.StartFile); this.currentArchiveNumber++; this.UnpackFileBytes( streamContext, fileInfo.FullName, fileInfo.CompressedLength, fileInfo.Length, header.crc32, fileStream, compressionStreamCreator, ref archiveStream); } } finally { if (fileStream != null) { streamContext.CloseFileWriteStream( fileInfo.FullName, fileStream, fileInfo.Attributes, fileInfo.LastWriteTime); this.currentArchiveNumber--; this.OnProgress(ArchiveProgressType.FinishFile); this.currentArchiveNumber++; } } }
/// <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 == WixToolset.Dtf.Compression.CompressionLevel.None) { compressionMethod = ZipCompressionMethod.Store; } Converter <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); } } }