public IExtractor ExtractFile(UInt64 index, string outputDirectory) { if (index >= (ulong)_Files.LongLength) { throw new ArgumentOutOfRangeException($"Index `{index}` is out of range."); } SevenZipArchiveFile file = _Files[index]; if (!preProcessFile(outputDirectory, file)) { string fullPath = Path.Combine(outputDirectory, PreserveDirectoryStructure ? file.Name : Path.GetFileName(file.Name)); // progress provider SevenZipProgressProvider szpp = null; if (ProgressDelegate != null) { szpp = new SevenZipProgressProvider(_Files, new[] { index }, ProgressDelegate); } // extraction Trace.TraceInformation($"Filename: `{file.Name}`, file size: `{file.Size} bytes`."); var sx = new SevenZipStreamsExtractor(stream, header.RawHeader.MainStreamsInfo, Password); using (Stream fileStream = File.Create(fullPath)) sx.Extract((UInt64)file.UnPackIndex, fileStream, szpp); if (file.Time != null) { File.SetLastWriteTimeUtc(fullPath, (DateTime)file.Time); } } return(this); }
public IExtractor ExtractFile(UInt64 index, Stream outputStream) { if (index >= (ulong)_Files.LongLength) { throw new ArgumentOutOfRangeException($"Index `{index}` is out of range."); } if (outputStream == null || !outputStream.CanWrite) { throw new ArgumentException($"Stream `{nameof(outputStream)}` is invalid or cannot be written to."); } SevenZipArchiveFile file = _Files[index]; if (file.IsEmpty) { Trace.TraceWarning($"Filename: {file.Name} is a directory, empty file or anti file, nothing to output to stream."); } else { // progress provider SevenZipProgressProvider szpp = null; if (ProgressDelegate != null) { szpp = new SevenZipProgressProvider(_Files, new[] { index }, ProgressDelegate); } // extraction Trace.TraceInformation($"Filename: `{file.Name}`, file size: `{file.Size} bytes`."); Trace.TraceInformation("Extracting..."); var sx = new SevenZipStreamsExtractor(stream, header.RawHeader.MainStreamsInfo, Password); sx.Extract((UInt64)file.UnPackIndex, outputStream, szpp); } return(this); }
public ICompressor Finalize() { if (this.stream == null || this.header == null) { throw new SevenZipException("Compressor object has already been finalized."); } Trace.TraceInformation($"Compressing files."); Trace.Indent(); try { buildFilesInfo(); // index files var streamToFileIndex = new Dictionary <ulong, ulong>(); ulong streamIndex = 0; for (long i = 0; i < _Files.LongCount(); ++i) { if (!_Files[(int)i].IsEmpty) { _Files[(int)i].UnPackIndex = streamIndex; streamToFileIndex[streamIndex++] = (ulong)i; } } // progress object SevenZipProgressProvider szpp = null; if (ProgressDelegate != null) { szpp = new SevenZipProgressProvider(_Files, new ulong[0], ProgressDelegate); } // compress files this.header.RawHeader.MainStreamsInfo = new SevenZipHeader.StreamsInfo(); if (Solid && streamIndex > 1) { compressFilesSolid(streamIndex, streamToFileIndex, szpp); } else { compressFilesNonSolid(streamIndex, streamToFileIndex, szpp); } // write headers writeHeaders(); } finally { Trace.Unindent(); Trace.TraceInformation("Done compressing files."); } this.stream = null; this.header = null; return(this); }
private void compressFilesNonSolid(ulong numStreams, Dictionary <ulong, ulong> streamToFileIndex, SevenZipProgressProvider progressProvider) { var sc = new SevenZipStreamsCompressor(stream); sc.Method = Compression.Registry.Method.LZMA; // actual compression (into a single packed stream per file) SevenZipStreamsCompressor.PackedStream[] css = new SevenZipStreamsCompressor.PackedStream[numStreams]; ulong numPackStreams = 0; for (ulong i = 0; i < numStreams; ++i) { SevenZipArchiveFile file = _Files[(int)streamToFileIndex[i]]; Trace.TraceInformation($"Compressing `{file.Name}`, Size: `{file.Size} bytes`..."); using (Stream source = file.Source.Get(FileAccess.Read)) css[i] = sc.Compress(source, progressProvider); numPackStreams += css[i].NumStreams; } // build headers var streamsInfo = this.header.RawHeader.MainStreamsInfo; streamsInfo.PackInfo = new SevenZipHeader.PackInfo() { NumPackStreams = numPackStreams, PackPos = 0, Sizes = new UInt64[numPackStreams], Digests = new SevenZipHeader.Digests(numPackStreams) }; streamsInfo.UnPackInfo = new SevenZipHeader.UnPackInfo() { NumFolders = numStreams, Folders = new SevenZipHeader.Folder[numStreams] }; streamsInfo.SubStreamsInfo = new SevenZipHeader.SubStreamsInfo(streamsInfo.UnPackInfo) { NumUnPackStreamsInFolders = Enumerable.Repeat((UInt64)1, (int)numStreams).ToArray(), NumUnPackStreamsTotal = numStreams, UnPackSizes = new List <UInt64>((int)numStreams), Digests = new SevenZipHeader.Digests(numStreams) }; for (ulong i = 0, k = 0; i < numStreams; ++i) { for (ulong j = 0; j < css[i].NumStreams; ++j, ++k) { streamsInfo.PackInfo.Sizes[k] = css[i].Sizes[j]; streamsInfo.PackInfo.Digests.CRCs[k] = css[i].CRCs[j]; } streamsInfo.SubStreamsInfo.UnPackSizes.Add((UInt64)css[i].Folder.GetUnPackSize()); streamsInfo.SubStreamsInfo.Digests.CRCs[i] = css[i].Folder.UnPackCRC; css[i].Folder.UnPackCRC = null; streamsInfo.UnPackInfo.Folders[i] = css[i].Folder; } }
private void compressFilesSolid(ulong numStreams, Dictionary <ulong, ulong> streamToFileIndex, SevenZipProgressProvider progressProvider) { var sc = new SevenZipStreamsCompressor(stream); sc.Method = Compression.Registry.Method.LZMA; Trace.TraceInformation($"Compressing `{numStreams} files` into a solid block..."); // actual compression using a sequence file stream and stream compressor var inputStream = new MultiFileStream( FileAccess.Read, streamToFileIndex.Select(sfi => _Files[(int)sfi.Value].Source).ToArray()); SevenZipStreamsCompressor.PackedStream cs = sc.Compress(inputStream, progressProvider); // build headers var streamsInfo = this.header.RawHeader.MainStreamsInfo; streamsInfo.PackInfo = new SevenZipHeader.PackInfo() { NumPackStreams = cs.NumStreams, PackPos = 0, Sizes = cs.Sizes, Digests = new SevenZipHeader.Digests(cs.NumStreams) { CRCs = cs.CRCs } }; streamsInfo.UnPackInfo = new SevenZipHeader.UnPackInfo() { NumFolders = 1, Folders = new SevenZipHeader.Folder[1] { cs.Folder } }; streamsInfo.UnPackInfo.Folders[0].UnPackCRC = null; streamsInfo.SubStreamsInfo = new SevenZipHeader.SubStreamsInfo(streamsInfo.UnPackInfo) { NumUnPackStreamsInFolders = new UInt64[1] { numStreams }, NumUnPackStreamsTotal = numStreams, UnPackSizes = new List <UInt64>((int)numStreams), Digests = new SevenZipHeader.Digests(numStreams) }; for (ulong i = 0; i < numStreams; ++i) { streamsInfo.SubStreamsInfo.UnPackSizes.Add((UInt64)inputStream.Sizes[i]); streamsInfo.SubStreamsInfo.Digests.CRCs[i] = inputStream.CRCs[i]; } }
internal PackedStream Compress(Stream inputStream, SevenZipProgressProvider progressProvider) { // Compression method if (!Method.HasValue || !SevenZipMethods.Lookup.ContainsKey(Method.Value)) { throw new SevenZipException("Undefined compression method."); } var MethodID = SevenZipMethods.Lookup[Method.Value]; // create compressed stream information structure var ps = new PackedStream() { NumStreams = 1, Sizes = new UInt64[1] { 0 }, CRCs = new UInt32?[1] { null }, Folder = new SevenZipHeader.Folder() { NumCoders = 1, CodersInfo = new SevenZipHeader.CoderInfo[1] { new SevenZipHeader.CoderInfo() { Attributes = (Byte)MethodID.Raw.Length, CodecId = MethodID.Raw.ToArray(), NumInStreams = 1, NumOutStreams = 1 } }, NumInStreamsTotal = 1, NumOutStreamsTotal = 1, PackedIndices = new UInt64[1] { 0 }, UnPackSizes = new UInt64[1] { 0 }, UnPackCRC = 0 } }; // remember current offsets long outStreamStartOffset = this.stream.Position; long inStreamStartOffset = inputStream.Position; // encode while calculating CRCs using (var inCRCStream = new CRCStream(inputStream)) using (var outCRCStream = new CRCStream(stream)) { LZMA.CLzmaEnc encoder = LZMA.LzmaEnc_Create(LZMA.ISzAlloc.SmallAlloc); LZMA.CLzmaEncProps encoderProps = LZMA.CLzmaEncProps.LzmaEncProps_Init(); LZMA.CSeqOutStream outputHelper; LZMA.CSeqInStream inputHelper; LZMA.SRes res = LZMA.SZ_OK; // prepare encoder settings res = encoder.LzmaEnc_SetProps(encoderProps); if (res != LZMA.SZ_OK) { throw new SevenZipException("Error setting LZMA encoder properties."); } byte[] properties = new byte[LZMA.LZMA_PROPS_SIZE]; long binarySettingsSize = LZMA.LZMA_PROPS_SIZE; res = encoder.LzmaEnc_WriteProperties(properties, ref binarySettingsSize); if (res != LZMA.SZ_OK) { throw new SevenZipException("Error writing LZMA encoder properties."); } if (binarySettingsSize != LZMA.LZMA_PROPS_SIZE) { throw new NotSupportedException(); } // read/write helpers outputHelper = new LZMA.CSeqOutStream( (P <byte> buf, long sz) => { outCRCStream.Write(buf.mBuffer, buf.mOffset, checked ((int)sz)); }); inputHelper = new LZMA.CSeqInStream( (P <byte> buf, long sz) => { return(inCRCStream.Read(buf.mBuffer, buf.mOffset, checked ((int)sz))); }); // encode res = encoder.LzmaEnc_Encode(outputHelper, inputHelper, progressProvider, LZMA.ISzAlloc.SmallAlloc, LZMA.ISzAlloc.BigAlloc); if (res != LZMA.SZ_OK) { throw new InvalidOperationException(); } // cleanup encoder.LzmaEnc_Destroy(LZMA.ISzAlloc.SmallAlloc, LZMA.ISzAlloc.BigAlloc); // keep settings in header ps.Folder.CodersInfo[0].Attributes |= (Byte)SevenZipHeader.CoderInfo.AttrHasAttributes; ps.Folder.CodersInfo[0].Properties = properties.ToArray(); ps.Folder.CodersInfo[0].PropertiesSize = (UInt64)ps.Folder.CodersInfo[0].Properties.Length; // store sizes and checksums ps.Folder.UnPackSizes[0] = (UInt64)(inputStream.Position - inStreamStartOffset); ps.Folder.UnPackCRC = inCRCStream.Result; ps.Sizes[0] = (UInt64)(this.stream.Position - outStreamStartOffset); ps.CRCs[0] = outCRCStream.Result; // handle progress offsets (in case compressor is called multiple times, with non-solid archives for instance) if (progressProvider != null) { progressProvider.IncreaseOffsetBy((long)ps.Folder.UnPackSizes[0], (long)ps.Sizes[0]); progressProvider.SetProgress(0, 0); } } return(ps); }
public IExtractor ExtractFiles(UInt64[] indices, Func <ArchiveFile, Stream> onStreamRequest, Action <ArchiveFile, Stream> onStreamClose = null) { if (indices.Any(index => index >= (ulong)_Files.LongLength)) { throw new ArgumentOutOfRangeException("An index given in `indices[]` array is out of range."); } // preprocess files and keep track of streams to decompress var streamToFileIndex = new Dictionary <ulong, ulong>(); var streamIndices = new List <ulong>(); ulong streamIndex = 0; for (ulong i = 0; i < (ulong)_Files.LongLength; ++i) { if (!indices.Any() || Array.IndexOf(indices, i) != -1) { if (_Files[i].IsEmpty) { using (Stream s = onStreamRequest(_Files[i])) if (s != null) { onStreamClose?.Invoke(_Files[i], s); } } else if (indices.Any()) { streamIndices.Add(streamIndex); } } if (!_Files[i].IsEmpty) { streamToFileIndex[streamIndex++] = i; } } // no file to decompress if (!streamToFileIndex.Any()) { Trace.TraceWarning("ExtractFiles: No decoding required."); return(this); } // progress provider SevenZipProgressProvider szpp = null; if (ProgressDelegate != null) { szpp = new SevenZipProgressProvider(_Files, indices, ProgressDelegate); } // extraction Trace.TraceInformation("Extracting..."); var sx = new SevenZipStreamsExtractor(stream, header.RawHeader.MainStreamsInfo, Password); sx.ExtractMultiple( streamIndices.ToArray(), (ulong index) => onStreamRequest(_Files[streamToFileIndex[index]]), (ulong index, Stream stream) => onStreamClose?.Invoke(_Files[streamToFileIndex[index]], stream), szpp); return(this); }
public IExtractor ExtractFiles(UInt64[] indices, string outputDirectory) { if (indices.Any(index => index >= (ulong)_Files.LongLength)) { throw new ArgumentOutOfRangeException("An index given in `indices[]` array is out of range."); } // preprocess files and keep track of streams to decompress var streamToFileIndex = new Dictionary <ulong, ulong>(); var streamIndices = new List <ulong>(); ulong streamIndex = 0; for (ulong i = 0; i < (ulong)_Files.LongLength; ++i) { if (!indices.Any() || Array.IndexOf(indices, i) != -1) { if (!preProcessFile(outputDirectory, _Files[i])) { streamIndices.Add(streamIndex); } } if (!_Files[i].IsEmpty) { streamToFileIndex[streamIndex++] = i; } } // no file to decompress if (!streamIndices.Any()) { Trace.TraceWarning("ExtractFiles: No decoding required."); return(this); } // progress provider SevenZipProgressProvider szpp = null; if (ProgressDelegate != null) { szpp = new SevenZipProgressProvider(_Files, indices, ProgressDelegate); } // extraction Trace.TraceInformation("Extracting..."); var sx = new SevenZipStreamsExtractor(stream, header.RawHeader.MainStreamsInfo, Password); sx.ExtractMultiple( streamIndices.ToArray(), (ulong index) => { SevenZipArchiveFile file = _Files[streamToFileIndex[index]]; string fullPath = Path.Combine(outputDirectory, PreserveDirectoryStructure ? file.Name : Path.GetFileName(file.Name)); Trace.TraceInformation($"File index {index}, filename: {file.Name}, file size: {file.Size}"); return(new FileStream(fullPath, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize)); }, (ulong index, Stream stream) => { stream.Close(); SevenZipArchiveFile file = _Files[streamToFileIndex[index]]; string fullPath = Path.Combine(outputDirectory, PreserveDirectoryStructure ? file.Name : Path.GetFileName(file.Name)); if (file.Time != null) { File.SetLastWriteTimeUtc(fullPath, (DateTime)file.Time); } }, szpp); return(this); }
internal void ExtractMultiple(ulong[] outStreamIndices, Func <ulong, Stream> onStreamRequest, Action <ulong, Stream> onStreamClose, SevenZipProgressProvider progressProvider) { // simplify if (outStreamIndices.Any() && streamsInfo.SubStreamsInfo != null && ((ulong)outStreamIndices.LongLength == streamsInfo.SubStreamsInfo.NumUnPackStreamsTotal)) { outStreamIndices = new ulong[0]; } // sequentially scan through folders and unpacked streams ulong index = 0; ulong packIndex = 0; for (ulong i = 0; i < streamsInfo.UnPackInfo.NumFolders; ++i) { bool processed = false; // only one unpack stream in folder if (streamsInfo.SubStreamsInfo == null || !streamsInfo.SubStreamsInfo.NumUnPackStreamsInFolders.Any()) { if (!outStreamIndices.Any() || outStreamIndices.Contains(index)) { extractMultipleFromFolder(index, null, i, packIndex, onStreamRequest, onStreamClose, progressProvider); processed = true; } ++index; } else // or multiple streams { ulong numStreams = streamsInfo.SubStreamsInfo.NumUnPackStreamsInFolders[i]; ulong osiOffset = index; bool[] matches = new bool[numStreams]; for (ulong j = 0; j < numStreams; ++j, ++index) { matches[j] = (!outStreamIndices.Any() || outStreamIndices.Contains(index)); } if (matches.Any(m => m == true)) { extractMultipleFromFolder(osiOffset, matches, i, packIndex, onStreamRequest, onStreamClose, progressProvider); processed = true; } } packIndex += streamsInfo.UnPackInfo.Folders[i].NumPackedStreams; // add unpack size to offset to progress provider if folder was skipped entirely if (!processed && progressProvider != null) { progressProvider.IncreaseOffsetBy((long)streamsInfo.UnPackInfo.Folders[i].GetUnPackSize(), 0); progressProvider.SetProgress(0, 0); } } }
internal void ExtractAll(Func <ulong, Stream> onStreamRequest, Action <ulong, Stream> onStreamClose, SevenZipProgressProvider progressProvider) { ExtractMultiple(new ulong[0], onStreamRequest, onStreamClose, progressProvider); }
internal void Extract(ulong outStreamIndex, Stream outStream, SevenZipProgressProvider progressProvider) { ExtractMultiple(new ulong[] { outStreamIndex }, (ulong i) => outStream, null, progressProvider); }
private void extractMultipleFromFolder(ulong outputStreamIndexOffset, bool[] matches, ulong folderIndex, ulong packIndex, Func <ulong, Stream> onStreamRequest, Action <ulong, Stream> onStreamClose, SevenZipProgressProvider progressProvider) { using (var decoder = createDecoderStream(folderIndex, packIndex)) { ulong unPackSize = streamsInfo.UnPackInfo.Folders[folderIndex].GetUnPackSize(); ulong neededUnPackSize = 0; // define output stream Stream outStream = null; if (matches == null) { // single stream outStream = onStreamRequest(outputStreamIndexOffset); neededUnPackSize = unPackSize; } else { // find actual number of needed streams ulong numStreams = streamsInfo.SubStreamsInfo.NumUnPackStreamsInFolders[folderIndex]; ulong lastStream = checked ((ulong)Array.LastIndexOf(matches, true)); numStreams = lastStream + 1; // create complex multistream MultiStream multi = new MultiStream(numStreams, (ulong innerIndex) => { Stream innerStream = null; if (matches[innerIndex]) { innerStream = onStreamRequest(outputStreamIndexOffset + innerIndex); if (innerStream == null) { matches[innerIndex] = false; } } return(innerStream ?? new NullStream((long)streamsInfo.SubStreamsInfo.UnPackSizes[(int)(outputStreamIndexOffset + innerIndex)])); }, (ulong innerIndex, Stream stream) => { if (onStreamClose != null && matches[innerIndex]) { onStreamClose(outputStreamIndexOffset + innerIndex, stream); } }); // set sizes in multistream and define needed data size for (ulong i = 0; i < numStreams; i++) { ulong ss = streamsInfo.SubStreamsInfo.UnPackSizes[(int)(outputStreamIndexOffset + i)]; multi.Sizes[i] = (long)ss; neededUnPackSize += ss; } // set new stream as output stream outStream = multi; } // actual extraction is done here (some decoder streams require knowing output size in advance, like PPMd) Util.TransferTo(decoder, outStream, (long)neededUnPackSize, progressProvider); if (progressProvider != null) { progressProvider.IncreaseOffsetBy((long)unPackSize, 0); progressProvider.SetProgress(0, 0); } // call stream close delegate if only one stream and delegate present if (matches == null) { onStreamClose?.Invoke(outputStreamIndexOffset, outStream); } } }