public IList <ArchiveFileInfo> GetFileInfo( IUnpackStreamContext streamContext, Predicate <string> fileFilter) { if (streamContext == null) { throw new ArgumentNullException("streamContext"); } lock (this) { _context = streamContext; _filter = fileFilter; NextCabinetName = string.Empty; _fileList = new List <ArchiveFileInfo>(); var tmpSuppress = SuppressProgressEvents; SuppressProgressEvents = true; try { for (short cabNumber = 0; NextCabinetName != null; cabNumber++) { Erf.Clear(); CabNumbers[NextCabinetName] = cabNumber; NativeMethods.FDI.Copy( _fdiHandle, NextCabinetName, string.Empty, 0, CabListNotify, IntPtr.Zero, IntPtr.Zero); CheckError(true); } var tmpFileList = _fileList; _fileList = null; return(tmpFileList.AsReadOnly()); } finally { SuppressProgressEvents = tmpSuppress; if (CabStream != null) { _context.CloseArchiveReadStream( CurrentArchiveNumber, CurrentArchiveName, CabStream); CabStream = null; } _context = null; } } }
public void Unpack(IUnpackStreamContext streamContext, Predicate <string> fileFilter) { checked { lock (this) { IList <ArchiveFileInfo> fileInfo = GetFileInfo(streamContext, fileFilter); ResetProgressData(); if (fileInfo != null) { totalFiles = fileInfo.Count; for (int i = 0; i < fileInfo.Count; i++) { totalFileBytes += fileInfo[i].Length; if (fileInfo[i].ArchiveNumber >= totalArchives) { int num = fileInfo[i].ArchiveNumber + 1; totalArchives = (short)num; } } } context = streamContext; fileList = null; base.NextCabinetName = string.Empty; folderId = -1; currentFileNumber = -1; try { short num2 = 0; while (base.NextCabinetName != null) { base.Erf.Clear(); base.CabNumbers[base.NextCabinetName] = num2; NativeMethods.FDI.Copy(fdiHandle, base.NextCabinetName, string.Empty, 0, CabExtractNotify, IntPtr.Zero, IntPtr.Zero); CheckError(extracting: true); num2 = (short)(num2 + 1); } } finally { if (base.CabStream != null) { context.CloseArchiveReadStream(currentArchiveNumber, currentArchiveName, base.CabStream); base.CabStream = null; } if (base.FileStream != null) { context.CloseFileWriteStream(currentFileName, base.FileStream, FileAttributes.Normal, DateTime.Now); base.FileStream = null; } context = null; } } } }
internal override int CabCloseStreamEx(int streamHandle, out int err, IntPtr pv) { Stream stream = DuplicateStream.OriginalStream(base.StreamHandles[streamHandle]); if (stream == DuplicateStream.OriginalStream(base.CabStream)) { if (folderId != -3) { OnProgress(ArchiveProgressType.FinishArchive); } context.CloseArchiveReadStream(currentArchiveNumber, currentArchiveName, stream); currentArchiveName = base.NextCabinetName; currentArchiveBytesProcessed = (currentArchiveTotalBytes = 0L); base.CabStream = null; } return(base.CabCloseStreamEx(streamHandle, out err, pv)); }
internal override int CabCloseStreamEx(int streamHandle, out int err, IntPtr pv) { Stream stream = DuplicateStream.OriginalStream(StreamHandles[streamHandle]); if (stream == DuplicateStream.OriginalStream(CabStream)) { if (folderId != -3) // -3 is a special folderId that requires re-opening the same cab { OnProgress(ArchiveProgressType.FinishArchive); } context.CloseArchiveReadStream(currentArchiveNumber, currentArchiveName, stream); currentArchiveName = NextCabinetName; currentArchiveBytesProcessed = currentArchiveTotalBytes = 0; CabStream = null; } return(base.CabCloseStreamEx(streamHandle, out err, pv)); }
public IList <ArchiveFileInfo> GetFileInfo(IUnpackStreamContext streamContext, Predicate <string> fileFilter) { if (streamContext == null) { throw new ArgumentNullException("streamContext"); } lock (this) { context = streamContext; filter = fileFilter; base.NextCabinetName = string.Empty; fileList = new List <ArchiveFileInfo>(); bool suppressProgressEvents = base.SuppressProgressEvents; base.SuppressProgressEvents = true; try { short num = 0; while (base.NextCabinetName != null) { base.Erf.Clear(); base.CabNumbers[base.NextCabinetName] = num; NativeMethods.FDI.Copy(fdiHandle, base.NextCabinetName, string.Empty, 0, CabListNotify, IntPtr.Zero, IntPtr.Zero); CheckError(extracting: true); num = checked ((short)(num + 1)); } List <ArchiveFileInfo> list = fileList; fileList = null; return(list.AsReadOnly()); } finally { base.SuppressProgressEvents = suppressProgressEvents; if (base.CabStream != null) { context.CloseArchiveReadStream(currentArchiveNumber, currentArchiveName, base.CabStream); base.CabStream = null; } context = null; } } }
/// <summary> /// Reads all the file headers from the central directory in the main archive. /// </summary> private IList <ZipFileHeader> GetCentralDirectory(IUnpackStreamContext streamContext) { Stream archiveStream = null; this.currentArchiveNumber = 0; try { List <ZipFileHeader> headers = new List <ZipFileHeader>(); archiveStream = this.OpenArchive(streamContext, 0); ZipEndOfCentralDirectory eocd = this.GetEOCD(streamContext, 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(); if (!header.Read(archiveStream, true)) { throw new ZipException( "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); } } }
/// <summary> /// Extracts files from a zip archive or archive chain. /// </summary> /// <param name="streamContext">A context interface to handle opening /// and closing of archive and file streams.</param> /// <param name="fileFilter">An optional predicate that can determine /// which files to process.</param> /// <exception cref="ArchiveException">The archive provided /// by the stream context is not valid.</exception> /// <remarks> /// The <paramref name="fileFilter"/> predicate takes an internal file /// path and returns true to include the file or false to exclude it. /// </remarks> public override void Unpack( IUnpackStreamContext streamContext, Predicate <string> fileFilter) { if (streamContext == null) { throw new ArgumentNullException("streamContext"); } lock (this) { IList <ZipFileHeader> allHeaders = this.GetCentralDirectory(streamContext); if (allHeaders == null) { throw new ZipException("Zip central directory not found."); } IList <ZipFileHeader> headers = new List <ZipFileHeader>(allHeaders.Count); foreach (ZipFileHeader header in allHeaders) { if (!header.IsDirectory && (fileFilter == null || fileFilter(header.fileName))) { headers.Add(header); } } this.ResetProgressData(); // Count the total number of files and bytes to be compressed. this.totalFiles = headers.Count; foreach (ZipFileHeader header in headers) { long compressedSize; long uncompressedSize; long localHeaderOffset; int archiveNumber; uint crc; header.GetZip64Fields( out compressedSize, out uncompressedSize, out localHeaderOffset, out archiveNumber, out crc); this.totalFileBytes += uncompressedSize; if (archiveNumber >= this.totalArchives) { this.totalArchives = (short)(archiveNumber + 1); } } this.currentArchiveNumber = -1; this.currentFileNumber = -1; Stream archiveStream = null; try { foreach (ZipFileHeader header in headers) { this.currentFileNumber++; this.UnpackOneFile(streamContext, header, ref archiveStream); } } finally { if (archiveStream != null) { streamContext.CloseArchiveReadStream( 0, String.Empty, archiveStream); this.currentArchiveNumber--; this.OnProgress(ArchiveProgressType.FinishArchive); } } } }
/// <summary> /// Decompresses bytes for one file from an archive or archive chain, /// checking the crc at the end. /// </summary> private void UnpackFileBytes( IUnpackStreamContext streamContext, string fileName, long compressedSize, long uncompressedSize, uint crc, Stream fileStream, Func <Stream, Stream> compressionStreamCreator, ref Stream archiveStream) { CrcStream crcStream = new CrcStream(fileStream); ConcatStream concatStream = new ConcatStream( delegate(ConcatStream s) { this.currentArchiveBytesProcessed = s.Source.Position; streamContext.CloseArchiveReadStream( this.currentArchiveNumber, String.Empty, s.Source); this.currentArchiveNumber--; this.OnProgress(ArchiveProgressType.FinishArchive); this.currentArchiveNumber += 2; this.currentArchiveName = null; this.currentArchiveBytesProcessed = 0; this.currentArchiveTotalBytes = 0; s.Source = this.OpenArchive(streamContext, this.currentArchiveNumber); FileStream archiveFileStream = s.Source as FileStream; this.currentArchiveName = (archiveFileStream != null ? Path.GetFileName(archiveFileStream.Name) : null); this.currentArchiveTotalBytes = s.Source.Length; this.currentArchiveNumber--; this.OnProgress(ArchiveProgressType.StartArchive); this.currentArchiveNumber++; }); concatStream.Source = archiveStream; concatStream.SetLength(compressedSize); Stream decompressionStream = compressionStreamCreator(concatStream); try { byte[] buf = new byte[4096]; long bytesRemaining = uncompressedSize; int counter = 0; while (bytesRemaining > 0) { int count = (int)Math.Min(buf.Length, bytesRemaining); count = decompressionStream.Read(buf, 0, count); crcStream.Write(buf, 0, count); bytesRemaining -= count; this.fileBytesProcessed += count; this.currentFileBytesProcessed += count; this.currentArchiveBytesProcessed = concatStream.Source.Position; if (++counter % 16 == 0) // Report every 64K { this.currentArchiveNumber--; this.OnProgress(ArchiveProgressType.PartialFile); this.currentArchiveNumber++; } } } finally { archiveStream = concatStream.Source; } crcStream.Flush(); if (crcStream.Crc != crc) { throw new ZipException("CRC check failed for file: " + fileName); } }
/// <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 { Func <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> /// Extracts files from a zip archive or archive chain. /// </summary> /// <param name="streamContext">A context interface to handle opening /// and closing of archive and file streams.</param> /// <param name="fileFilter">An optional predicate that can determine /// which files to process.</param> /// <exception cref="ArchiveException">The archive provided /// by the stream context is not valid.</exception> /// <remarks> /// The <paramref name="fileFilter"/> predicate takes an internal file /// path and returns true to include the file or false to exclude it. /// </remarks> public override void Unpack( IUnpackStreamContext streamContext, Predicate<string> fileFilter) { if (streamContext == null) { throw new ArgumentNullException("streamContext"); } lock (this) { IList<ZipFileHeader> allHeaders = this.GetCentralDirectory(streamContext); if (allHeaders == null) { throw new ZipException("Zip central directory not found."); } IList<ZipFileHeader> headers = new List<ZipFileHeader>(allHeaders.Count); foreach (ZipFileHeader header in allHeaders) { if (!header.IsDirectory && (fileFilter == null || fileFilter(header.fileName))) { headers.Add(header); } } this.ResetProgressData(); // Count the total number of files and bytes to be compressed. this.totalFiles = headers.Count; foreach (ZipFileHeader header in headers) { long compressedSize; long uncompressedSize; long localHeaderOffset; int archiveNumber; uint crc; header.GetZip64Fields( out compressedSize, out uncompressedSize, out localHeaderOffset, out archiveNumber, out crc); this.totalFileBytes += uncompressedSize; if (archiveNumber >= this.totalArchives) { this.totalArchives = (short) (archiveNumber + 1); } } this.currentArchiveNumber = -1; this.currentFileNumber = -1; Stream archiveStream = null; try { foreach (ZipFileHeader header in headers) { this.currentFileNumber++; this.UnpackOneFile(streamContext, header, ref archiveStream); } } finally { if (archiveStream != null) { streamContext.CloseArchiveReadStream( 0, String.Empty, archiveStream); this.currentArchiveNumber--; this.OnProgress(ArchiveProgressType.FinishArchive); } } } }
/// <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> /// Decompresses bytes for one file from an archive or archive chain, /// checking the crc at the end. /// </summary> private void UnpackFileBytes( IUnpackStreamContext streamContext, string fileName, long compressedSize, long uncompressedSize, uint crc, Stream fileStream, Converter<Stream, Stream> compressionStreamCreator, ref Stream archiveStream) { CrcStream crcStream = new CrcStream(fileStream); ConcatStream concatStream = new ConcatStream( delegate(ConcatStream s) { this.currentArchiveBytesProcessed = s.Source.Position; streamContext.CloseArchiveReadStream( this.currentArchiveNumber, String.Empty, s.Source); this.currentArchiveNumber--; this.OnProgress(ArchiveProgressType.FinishArchive); this.currentArchiveNumber += 2; this.currentArchiveName = null; this.currentArchiveBytesProcessed = 0; this.currentArchiveTotalBytes = 0; s.Source = this.OpenArchive(streamContext, this.currentArchiveNumber); FileStream archiveFileStream = s.Source as FileStream; this.currentArchiveName = (archiveFileStream != null ? Path.GetFileName(archiveFileStream.Name) : null); this.currentArchiveTotalBytes = s.Source.Length; this.currentArchiveNumber--; this.OnProgress(ArchiveProgressType.StartArchive); this.currentArchiveNumber++; }); concatStream.Source = archiveStream; concatStream.SetLength(compressedSize); Stream decompressionStream = compressionStreamCreator(concatStream); try { byte[] buf = new byte[4096]; long bytesRemaining = uncompressedSize; int counter = 0; while (bytesRemaining > 0) { int count = (int) Math.Min(buf.Length, bytesRemaining); count = decompressionStream.Read(buf, 0, count); crcStream.Write(buf, 0, count); bytesRemaining -= count; this.fileBytesProcessed += count; this.currentFileBytesProcessed += count; this.currentArchiveBytesProcessed = concatStream.Source.Position; if (++counter % 16 == 0) // Report every 64K { this.currentArchiveNumber--; this.OnProgress(ArchiveProgressType.PartialFile); this.currentArchiveNumber++; } } } finally { archiveStream = concatStream.Source; } crcStream.Flush(); if (crcStream.Crc != crc) { throw new ZipException("CRC check failed for file: " + fileName); } }
public void Unpack( IUnpackStreamContext streamContext, Predicate <string> fileFilter) { lock (this) { IList <ArchiveFileInfo> files = GetFileInfo(streamContext, fileFilter); ResetProgressData(); if (files != null) { totalFiles = files.Count; for (int i = 0; i < files.Count; i++) { totalFileBytes += files[i].Length; if (files[i].ArchiveNumber >= this.totalArchives) { int totalArchives = files[i].ArchiveNumber + 1; this.totalArchives = (short)totalArchives; } } } context = streamContext; fileList = null; NextCabinetName = String.Empty; folderId = -1; currentFileNumber = -1; try { for (short cabNumber = 0; NextCabinetName != null; cabNumber++) { Erf.Clear(); CabNumbers[NextCabinetName] = cabNumber; NativeMethods.FDI.Copy( fdiHandle, NextCabinetName, String.Empty, 0, CabExtractNotify, IntPtr.Zero, IntPtr.Zero); CheckError(true); } } finally { if (CabStream != null) { context.CloseArchiveReadStream( currentArchiveNumber, currentArchiveName, CabStream); CabStream = null; } if (FileStream != null) { context.CloseFileWriteStream(currentFileName, FileStream, FileAttributes.Normal, DateTime.Now); FileStream = null; } context = null; } } }
/// <summary> /// Reads all the file headers from the central directory in the main archive. /// </summary> private IList<ZipFileHeader> GetCentralDirectory(IUnpackStreamContext streamContext) { Stream archiveStream = null; this.currentArchiveNumber = 0; try { List<ZipFileHeader> headers = new List<ZipFileHeader>(); archiveStream = this.OpenArchive(streamContext, 0); ZipEndOfCentralDirectory eocd = this.GetEOCD(streamContext, 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(); if (!header.Read(archiveStream, true)) { throw new ZipException( "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); } } }