private static void findPrimaryOutStreamIndex(SevenZipHeader.Folder folder, out ulong primaryCoderIndex, out ulong primaryOutStreamIndex) { bool foundPrimaryOutStream = false; primaryCoderIndex = 0; primaryOutStreamIndex = 0; for (ulong outStreamIndex = 0, coderIndex = 0; coderIndex < (ulong)folder.CodersInfo.LongLength; coderIndex++) { for (ulong coderOutStreamIndex = 0; coderOutStreamIndex < folder.CodersInfo[coderIndex].NumOutStreams; coderOutStreamIndex++, outStreamIndex++) { if (folder.FindBindPairForOutStream(outStreamIndex) < 0) { if (foundPrimaryOutStream) { throw new SevenZipException("Multiple output streams are not supported."); } foundPrimaryOutStream = true; primaryCoderIndex = coderIndex; primaryOutStreamIndex = outStreamIndex; } } } if (!foundPrimaryOutStream) { throw new SevenZipException("No primary output stream in folder."); } }
private static ulong findCoderIndexForOutStreamIndex(SevenZipHeader.Folder folder, ulong outStreamIndex) { for (ulong coderIndex = 0, index = 0; coderIndex < folder.NumCoders; ++coderIndex) { for (ulong i = 0; i < folder.CodersInfo[coderIndex].NumOutStreams; ++i, ++index) { if (outStreamIndex == index) { return(coderIndex); } } } throw new SevenZipException($"Could not find coder index for out stream index `{outStreamIndex}`."); }
private Stream createDecoderStream(ulong folderIndex, ulong packIndex) { // find initial position of packed streams ulong packPos = streamsInfo.PackInfo.PackPos + (ulong)Marshal.SizeOf(typeof(SevenZipArchive.SignatureHeader)); for (ulong i = 0; i < packIndex; ++i) { packPos += streamsInfo.PackInfo.Sizes[i]; } // catch current folder info SevenZipHeader.Folder folder = streamsInfo.UnPackInfo.Folders[folderIndex]; // create packed substreams Stream[] packedStreams = new Stream[folder.NumPackedStreams]; ulong[] packedSizes = new ulong[folder.NumPackedStreams]; for (ulong i = 0, currentPackPos = packPos; i < folder.NumPackedStreams; ++i) { ulong packedSize = streamsInfo.PackInfo.Sizes[packIndex + i]; packedStreams[i] = new SubStream(stream, (long)currentPackPos, (long)packedSize); packedSizes[i] = packedSize; currentPackPos += packedSize; } // create output streams Stream[] outputStreams = new Stream[folder.NumOutStreamsTotal]; // find primary output stream ulong primaryCoderIndex; ulong primaryOutStreamIndex; findPrimaryOutStreamIndex(folder, out primaryCoderIndex, out primaryOutStreamIndex); // start recursive stream creation return(createDecoderStreamForCoder(packedStreams, packedSizes, outputStreams, folder, primaryCoderIndex)); }
private Stream createDecoderStreamForCoder(Stream[] packedStreams, ulong[] packedSizes, Stream[] outputStreams, SevenZipHeader.Folder folder, ulong coderIndex) { // find starting in and out id for coder ulong inStreamId = 0; ulong outStreamId = 0; for (ulong i = 0; i < coderIndex; ++i) { inStreamId += folder.CodersInfo[i].NumInStreams; outStreamId += folder.CodersInfo[i].NumOutStreams; } // create input streams Stream[] inStreams = new Stream[folder.CodersInfo[coderIndex].NumInStreams]; for (int i = 0; i < inStreams.Length; ++i, ++inStreamId) { long bindPairIndex = folder.FindBindPairForInStream(inStreamId); if (bindPairIndex == -1) { long index = folder.FindPackedIndexForInStream(inStreamId); if (index == -1) { throw new SevenZipException("Could not find input stream binding."); } inStreams[i] = packedStreams[index]; } else { ulong pairedOutIndex = folder.BindPairsInfo[bindPairIndex].OutIndex; if (outputStreams[pairedOutIndex] != default(Stream)) { throw new SevenZipException("Overlapping stream bindings are invalid."); } ulong subCoderIndex = findCoderIndexForOutStreamIndex(folder, pairedOutIndex); inStreams[i] = createDecoderStreamForCoder(packedStreams, packedSizes, outputStreams, folder, subCoderIndex); if (outputStreams[pairedOutIndex] != default(Stream)) { throw new SevenZipException("Overlapping stream bindings are invalid."); } outputStreams[pairedOutIndex] = inStreams[i]; } } var methodID = new SevenZipMethods.MethodID(folder.CodersInfo[coderIndex].CodecId); if (!SevenZipMethods.Supported.ContainsKey(methodID)) { string codecName = SevenZipMethods.List.Where(id => id.Key == methodID).Select(id => id.Value).FirstOrDefault(); throw new SevenZipException("Compression method `" + (codecName ?? "unknown") + "` not supported."); } return(Compression.Registry.GetDecoderStream( SevenZipMethods.Supported[methodID], inStreams, folder.CodersInfo[coderIndex].Properties, this, (long)folder.UnPackSizes[outStreamId])); }
private void buildFilesIndex() { // build empty index var filesInfo = header.RawHeader.FilesInfo; _Files = new SevenZipArchiveFile[filesInfo.NumFiles]; for (ulong i = 0; i < filesInfo.NumFiles; ++i) { _Files[i] = new SevenZipArchiveFile(); } Files = _Files; // set properties that are contained in FileProperties structures foreach (var properties in filesInfo.Properties) { switch (properties.PropertyID) { case SevenZipHeader.PropertyID.kEmptyStream: for (long i = 0; i < _Files.LongLength; ++i) { bool val = (properties as SevenZipHeader.PropertyEmptyStream).IsEmptyStream[i]; _Files[i].IsEmpty = val; _Files[i].IsDirectory = val; } break; case SevenZipHeader.PropertyID.kEmptyFile: for (long i = 0, j = 0; i < _Files.LongLength; ++i) { if (_Files[i].IsEmpty) { bool val = (properties as SevenZipHeader.PropertyEmptyFile).IsEmptyFile[j++]; _Files[i].IsDirectory = !val; } } break; case SevenZipHeader.PropertyID.kAnti: for (long i = 0, j = 0; i < _Files.LongLength; ++i) { if (_Files[i].IsEmpty) { _Files[i].IsDeleted = (properties as SevenZipHeader.PropertyAnti).IsAnti[j++]; } } break; case SevenZipHeader.PropertyID.kMTime: for (long i = 0; i < _Files.LongLength; ++i) { _Files[i].Time = (properties as SevenZipHeader.PropertyTime).Times[i]; } break; case SevenZipHeader.PropertyID.kName: for (long i = 0; i < _Files.LongLength; ++i) { _Files[i].Name = (properties as SevenZipHeader.PropertyName).Names[i]; } break; case SevenZipHeader.PropertyID.kWinAttributes: for (long i = 0; i < _Files.LongLength; ++i) { _Files[i].Attributes = (properties as SevenZipHeader.PropertyAttributes).Attributes[i]; } break; } } // set output sizes from the overly complex 7zip headers var streamsInfo = header.RawHeader.MainStreamsInfo; var ui = streamsInfo.UnPackInfo; var ssi = streamsInfo.SubStreamsInfo; if (ui == null) { //Trace.TraceWarning("7zip: Missing header information to calculate output file sizes."); return; } int upsIndex = 0; int upcIndex = 0; long fileIndex = 0; long streamIndex = 0; for (long i = 0; i < (long)streamsInfo.UnPackInfo.NumFolders; ++i) { SevenZipHeader.Folder folder = ui.Folders[i]; long ups = 1; if (ssi != null && ssi.NumUnPackStreamsInFolders.Any()) { ups = (long)ssi.NumUnPackStreamsInFolders[i]; } if (ups == 0) { throw new SevenZipException("Unexpected, no UnPackStream in Folder."); } ulong size = folder.GetUnPackSize(); uint? crc = folder.UnPackCRC; for (long j = 0; j < ups; ++j) { if (ssi != null && ssi.UnPackSizes.Any()) { if (upsIndex > ssi.UnPackSizes.Count()) { throw new SevenZipException("Unexpected, missing UnPackSize entry(ies)."); } size = ssi.UnPackSizes[upsIndex++]; } else { if (ups > 1) { throw new SevenZipException("Missing SubStreamsInfo header chunk."); } } if (crc == null || ups > 1) { if (ssi != null && ssi.Digests != null && (int)ssi.Digests.NumStreams() > upcIndex) { crc = ssi.Digests.CRCs[upcIndex]; } upcIndex++; } while (_Files[fileIndex].IsEmpty) { if (++fileIndex >= _Files.LongLength) { throw new SevenZipException("Missing Files entries for defined sizes."); } } _Files[fileIndex].Size = size; _Files[fileIndex].CRC = crc; _Files[fileIndex].UnPackIndex = (ulong?)streamIndex; fileIndex++; streamIndex++; } } }