private ArchiveSectionMetadataBuilder ReadSection(int rawInputStreamIndex) { var section = new ArchiveSectionMetadataBuilder(); int totalInputCount = 0; int totalOutputCount = 0; var decoderCount = ReadNumberAsInt32(); if (decoderCount == 0) { throw new InvalidDataException(); } section.Decoders = new DecoderMetadataBuilder[decoderCount]; for (int i = 0; i < decoderCount; i++) { var decoder = ReadDecoder(); totalInputCount += decoder.InputCount; totalOutputCount += decoder.OutputCount; section.Decoders[i] = decoder; } // One output is the final output, the others need to be wired up. var usedOutputMask = new bool[totalOutputCount]; for (int i = 1; i < totalOutputCount; i++) { int inputIndex = ReadNumberAsInt32(); int inputDecoderIndex = 0; for (;;) { if (inputDecoderIndex == decoderCount) { throw new InvalidDataException(); } if (inputIndex < section.Decoders[inputDecoderIndex].InputCount) { break; } inputIndex -= section.Decoders[inputDecoderIndex].OutputCount; inputDecoderIndex += 1; } int outputIndex = ReadNumberAsInt32(); // Detect duplicate output connections through the output mask. if (outputIndex >= totalOutputCount || usedOutputMask[outputIndex]) { throw new InvalidDataException(); } usedOutputMask[outputIndex] = true; // Separate the output index into decoder index and stream index int outputDecoderIndex = 0; for (;;) { if (outputDecoderIndex == decoderCount) { throw new InvalidDataException(); } var outputCount = section.Decoders[outputDecoderIndex].OutputCount; if (outputIndex < outputCount) { break; } outputIndex -= outputCount; outputDecoderIndex += 1; } // Detect duplicate input connections by checking for the placeholder. if (section.Decoders[inputDecoderIndex].InputInfo[inputIndex].StreamIndex != Int32.MaxValue) { throw new InvalidDataException(); } section.Decoders[inputDecoderIndex].InputInfo[inputIndex] = new DecoderInputMetadata(outputDecoderIndex, outputIndex); } bool foundFinalOutput = false; for (int finalOutputIndex = 0, i = 0; i < decoderCount; i++) { var decoder = section.Decoders[i]; for (int j = 0; j < decoder.OutputCount; j++) { if (!usedOutputMask[finalOutputIndex++]) { if (foundFinalOutput) { throw new InvalidDataException(); } foundFinalOutput = true; section.OutputStream = new DecoderInputMetadata(i, j); } } } if (!foundFinalOutput) { throw new InvalidDataException(); } // Outputs must be wired up to unique inputs. Inputs which are not wired to outputs must be wired to raw streams. // Note that negative overflow is not possible and positive overflow is ok in this calculation, // it will fail the range check and trigger the exception, which is the intended behavior. var requiredRawStreams = 1 + totalInputCount - totalOutputCount; if (requiredRawStreams <= 0) { throw new InvalidDataException(); } section.RequiredRawInputStreamCount = requiredRawStreams; if (requiredRawStreams == 1) { bool connected = false; foreach (var decoder in section.Decoders) { for (int i = 0; i < decoder.InputCount; i++) { if (decoder.InputInfo[i].StreamIndex == Int32.MaxValue) { if (connected) { throw new InvalidDataException(); } connected = true; decoder.InputInfo[i] = new DecoderInputMetadata(null, 0); } } } if (!connected) { throw new InvalidDataException(); } } else { for (int i = 0; i < requiredRawStreams; i++) { int inputIndex = ReadNumberAsInt32(); int inputDecoderIndex = 0; for (;;) { if (inputDecoderIndex == decoderCount) { throw new InvalidDataException(); } var decoder = section.Decoders[inputDecoderIndex]; if (inputIndex < decoder.InputCount) { break; } inputIndex -= decoder.OutputCount; inputDecoderIndex += 1; } var decoderInput = section.Decoders[inputDecoderIndex].InputInfo; if (decoderInput[inputIndex].StreamIndex != Int32.MaxValue) { throw new InvalidDataException(); } decoderInput[inputIndex] = new DecoderInputMetadata(null, rawInputStreamIndex + i); } } return(section); }
private ArchiveSectionMetadataBuilder[] ReadSectionHeader(ImmutableArray <Stream> streams) { SkipToToken(ArchiveMetadataToken.Folder); var sectionCount = ReadNumberAsInt32(); var sections = new ArchiveSectionMetadataBuilder[sectionCount]; int rawStreamCount = 0; using (SelectStream(streams)) { for (int i = 0; i < sectionCount; i++) { var section = ReadSection(rawStreamCount); rawStreamCount += section.RequiredRawInputStreamCount; sections[i] = section; } } SkipToToken(ArchiveMetadataToken.CodersUnpackSize); foreach (var section in sections) { for (int decoderIndex = 0; decoderIndex < section.Decoders.Length; decoderIndex++) { var decoder = section.Decoders[decoderIndex]; var outputCount = decoder.OutputCount; var outputBuilder = ImmutableArray.CreateBuilder <DecoderOutputMetadata>(outputCount); for (int outputIndex = 0; outputIndex < outputCount; outputIndex++) { var length = ReadNumberAsInt64(); outputBuilder.Add(new DecoderOutputMetadata(length)); var stream = new DecoderInputMetadata(decoderIndex, outputIndex); if (section.OutputStream == stream) { section.OutputLength = length; } } decoder.OutputInfo = outputBuilder; } } for (;;) { var token = ReadToken(); if (token == ArchiveMetadataToken.End) { break; } if (token == ArchiveMetadataToken.CRC) { var vector = ReadOptionalBitVector(sectionCount); for (int i = 0; i < sectionCount; i++) { if (vector[i]) { sections[i].OutputChecksum = new Checksum(ReadInt32()); } else { sections[i].OutputChecksum = null; } } } else { SkipDataBlock(); } } return(sections); }