Example #1
0
        private void ReadSectionDetails(ArchiveSectionMetadataBuilder[] sections)
        {
            #region Counts

            bool hasStreamCounts = false;

            ArchiveMetadataToken token;
            for (;;)
            {
                token = ReadToken();
                if (token == ArchiveMetadataToken.End || token == ArchiveMetadataToken.CRC || token == ArchiveMetadataToken.Size)
                {
                    break;
                }

                if (token == ArchiveMetadataToken.NumUnpackStream)
                {
                    hasStreamCounts = true;

                    foreach (var section in sections)
                    {
                        section.SubStreamCount = ReadNumberAsInt32();
                    }
                }
                else
                {
                    SkipDataBlock();
                }
            }

            if (!hasStreamCounts)
            {
                foreach (var section in sections)
                {
                    section.SubStreamCount = 1;
                }
            }

            #endregion

            #region Sizes

            foreach (var section in sections)
            {
                // v3.13 was broken and wrote empty sections
                // v4.07 added compat code to skip empty sections
                if (section.SubStreamCount.Value == 0)
                {
                    continue;
                }

                var remaining   = section.OutputLength;
                var subsections = new DecodedStreamMetadata[section.SubStreamCount.Value];

                for (int i = 0; i < subsections.Length - 1; i++)
                {
                    if (token == ArchiveMetadataToken.Size)
                    {
                        var size = ReadNumberAsInt64();
                        if (size == 0 || size >= remaining)
                        {
                            throw new InvalidDataException();
                        }

                        subsections[i] = new DecodedStreamMetadata(size, null);
                        remaining     -= size;
                    }
                }

                if (remaining == 0)
                {
                    throw new InvalidDataException();
                }

                subsections[subsections.Length - 1] = new DecodedStreamMetadata(remaining, null);
                section.Subsections = subsections;
            }

            if (token == ArchiveMetadataToken.Size)
            {
                token = ReadToken();
            }

            #endregion

            #region Checksums

            int requiredChecksumCount = 0;
            int totalChecksumCount    = 0;

            ImmutableArray <Checksum?> .Builder checksums = null;

            foreach (var section in sections)
            {
                // If there is only one stream and we have a section checksum 7z doesn't store the checksum again.
                if (!(section.SubStreamCount == 1 && section.OutputChecksum.HasValue))
                {
                    requiredChecksumCount += section.SubStreamCount.Value;
                }

                totalChecksumCount += section.SubStreamCount.Value;
            }

            for (;;)
            {
                if (token == ArchiveMetadataToken.End)
                {
                    if (checksums == null)
                    {
                        checksums = ImmutableArray.CreateBuilder <Checksum?>(totalChecksumCount);
                        for (int i = 0; i < totalChecksumCount; i++)
                        {
                            checksums.Add(null);
                        }
                    }

                    break;
                }
                else if (token == ArchiveMetadataToken.CRC)
                {
                    checksums = ImmutableArray.CreateBuilder <Checksum?>(totalChecksumCount);

                    var vector = ReadOptionalBitVector(requiredChecksumCount);
                    int requiredChecksumIndex = 0;

                    foreach (var section in sections)
                    {
                        if (section.SubStreamCount == 1 && section.OutputChecksum.HasValue)
                        {
                            checksums.Add(section.OutputChecksum.Value);
                        }
                        else
                        {
                            for (int i = 0; i < section.SubStreamCount; i++)
                            {
                                if (vector[requiredChecksumIndex++])
                                {
                                    checksums.Add(new Checksum(ReadInt32()));
                                }
                                else
                                {
                                    checksums.Add(null);
                                }
                            }
                        }
                    }

                    System.Diagnostics.Debug.Assert(requiredChecksumIndex == requiredChecksumCount);
                    System.Diagnostics.Debug.Assert(checksums.Count == totalChecksumCount);
                }
                else
                {
                    SkipDataBlock();
                }

                token = ReadToken();
            }

            #endregion
        }
        private void ReadSectionDetails(ArchiveSectionMetadataBuilder[] sections)
        {
            #region Counts

            bool hasStreamCounts = false;

            ArchiveMetadataToken token;
            for (;;)
            {
                token = ReadToken();
                if (token == ArchiveMetadataToken.End || token == ArchiveMetadataToken.CRC || token == ArchiveMetadataToken.Size)
                    break;

                if (token == ArchiveMetadataToken.NumUnpackStream)
                {
                    hasStreamCounts = true;

                    foreach (var section in sections)
                        section.SubStreamCount = ReadNumberAsInt32();
                }
                else
                {
                    SkipDataBlock();
                }
            }

            if (!hasStreamCounts)
                foreach (var section in sections)
                    section.SubStreamCount = 1;

            #endregion

            #region Sizes

            foreach (var section in sections)
            {
                // v3.13 was broken and wrote empty sections
                // v4.07 added compat code to skip empty sections
                if (section.SubStreamCount.Value == 0)
                    continue;

                var remaining = section.OutputLength;
                var subsections = new DecodedStreamMetadata[section.SubStreamCount.Value];

                for (int i = 0; i < subsections.Length - 1; i++)
                {
                    if (token == ArchiveMetadataToken.Size)
                    {
                        var size = ReadNumberAsInt64();
                        if (size == 0 || size >= remaining)
                            throw new InvalidDataException();

                        subsections[i] = new DecodedStreamMetadata(size, null);
                        remaining -= size;
                    }
                }

                if (remaining == 0)
                    throw new InvalidDataException();

                subsections[subsections.Length - 1] = new DecodedStreamMetadata(remaining, null);
                section.Subsections = subsections;
            }

            if (token == ArchiveMetadataToken.Size)
                token = ReadToken();

            #endregion

            #region Checksums

            int requiredChecksumCount = 0;
            int totalChecksumCount = 0;

            ImmutableArray<Checksum?>.Builder checksums = null;

            foreach (var section in sections)
            {
                // If there is only one stream and we have a section checksum 7z doesn't store the checksum again.
                if (!(section.SubStreamCount == 1 && section.OutputChecksum.HasValue))
                    requiredChecksumCount += section.SubStreamCount.Value;

                totalChecksumCount += section.SubStreamCount.Value;
            }

            for (;;)
            {
                if (token == ArchiveMetadataToken.End)
                {
                    if (checksums == null)
                    {
                        checksums = ImmutableArray.CreateBuilder<Checksum?>(totalChecksumCount);
                        for (int i = 0; i < totalChecksumCount; i++)
                            checksums.Add(null);
                    }

                    break;
                }
                else if (token == ArchiveMetadataToken.CRC)
                {
                    checksums = ImmutableArray.CreateBuilder<Checksum?>(totalChecksumCount);

                    var vector = ReadOptionalBitVector(requiredChecksumCount);
                    int requiredChecksumIndex = 0;

                    foreach (var section in sections)
                    {
                        if (section.SubStreamCount == 1 && section.OutputChecksum.HasValue)
                        {
                            checksums.Add(section.OutputChecksum.Value);
                        }
                        else
                        {
                            for (int i = 0; i < section.SubStreamCount; i++)
                            {
                                if (vector[requiredChecksumIndex++])
                                    checksums.Add(new Checksum(ReadInt32()));
                                else
                                    checksums.Add(null);
                            }
                        }
                    }

                    System.Diagnostics.Debug.Assert(requiredChecksumIndex == requiredChecksumCount);
                    System.Diagnostics.Debug.Assert(checksums.Count == totalChecksumCount);
                }
                else
                {
                    SkipDataBlock();
                }

                token = ReadToken();
            }

            #endregion
        }