private static void findPrimaryOutStreamIndex(SevenZipHeader.Folder folder, out UInt64 primaryCoderIndex, out UInt64 primaryOutStreamIndex) { bool foundPrimaryOutStream = false; primaryCoderIndex = 0; primaryOutStreamIndex = 0; for (UInt64 outStreamIndex = 0, coderIndex = 0; coderIndex < (UInt64)folder.CodersInfo.LongLength; coderIndex++) { for (UInt64 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 UInt64 findCoderIndexForOutStreamIndex(SevenZipHeader.Folder folder, UInt64 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]; UInt64[] packedSizes = new UInt64[folder.NumPackedStreams]; for (ulong i = 0, currentPackPos = packPos; i < folder.NumPackedStreams; ++i) { UInt64 packedSize = streamsInfo.PackInfo.Sizes[packIndex + i]; packedStreams[i] = new SubStream(this.stream, (long)currentPackPos, (long)packedSize); packedSizes[i] = packedSize; currentPackPos += packedSize; } // create output streams Stream[] outputStreams = new Stream[folder.NumOutStreamsTotal]; // find primary output stream UInt64 primaryCoderIndex; UInt64 primaryOutStreamIndex; findPrimaryOutStreamIndex(folder, out primaryCoderIndex, out primaryOutStreamIndex); // start recursive stream creation return(createDecoderStreamForCoder(packedStreams, packedSizes, outputStreams, folder, primaryCoderIndex)); }
private Stream createDecoderStreamForCoder(Stream[] packedStreams, UInt64[] packedSizes, Stream[] outputStreams, SevenZipHeader.Folder folder, UInt64 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) { Int64 bindPairIndex = folder.FindBindPairForInStream(inStreamId); if (bindPairIndex == -1) { Int64 index = folder.FindPackedIndexForInStream(inStreamId); if (index == -1) { throw new SevenZipException("Could not find input stream binding."); } inStreams[i] = packedStreams[index]; } else { UInt64 pairedOutIndex = folder.BindPairsInfo[bindPairIndex].OutIndex; if (outputStreams[pairedOutIndex] != default(Stream)) { throw new SevenZipException("Overlapping stream bindings are invalid."); } UInt64 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, null, (long)folder.UnPackSizes[outStreamId])); }
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 = new ReadOnlyCollection <SevenZipArchiveFile>(_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."); } UInt64 size = folder.GetUnPackSize(); UInt32?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 = (UInt64?)streamIndex; fileIndex++; streamIndex++; } } }