Ejemplo n.º 1
0
        private ArchiveMetadata ReadArchive()
        {
            var token = ReadToken();

            if (token == ArchiveMetadataToken.ArchiveProperties)
            {
                ReadArchiveProperties();
                token = ReadToken();
            }

            var streams = ImmutableArray <Stream> .Empty;

            if (token == ArchiveMetadataToken.AdditionalStreams)
            {
                streams = ReadPackedStreams();
                token   = ReadToken();
            }

            ArchiveMetadata metadata;

            if (token == ArchiveMetadataToken.MainStreams)
            {
                metadata = ReadMetadata(streams, true);
                token    = ReadToken();
            }
            else
            {
                throw new NotImplementedException();
            }

            int?emptyStreamCount = null;

            if (token != ArchiveMetadataToken.End)
            {
                if (token != ArchiveMetadataToken.Files)
                {
                    throw new InvalidDataException();
                }

                var fileCount = ReadNumberAsInt32();
                Initialize(fileCount);

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

                    var recordSize = (long)ReadNumber();
                    if (recordSize < 0)
                    {
                        throw new InvalidDataException();
                    }

                    var oldOffset = GetCurrentOffset();

                    #region File Metadata

                    switch (token)
                    {
                    case ArchiveMetadataToken.Name:
                        using (SelectStream(streams))
                        {
                            var reader = new MetadataStringReader(this, fileCount);
                            ReadNames(reader);
                            reader.Complete();
                        }
                        break;

                    case ArchiveMetadataToken.WinAttributes:
                    {
                        var vector = ReadOptionalBitVector(fileCount);
                        using (SelectStream(streams))
                        {
                            var reader = new MetadataAttributeReader(this, fileCount, vector, EnablePosixFileAttributeExtension);
                            ReadAttributes(reader);
                            reader.Complete();
                        }

                        break;
                    }

                    case ArchiveMetadataToken.EmptyStream:
                    {
                        var emptyStreams = ReadRequiredBitVector(fileCount);
                        emptyStreamCount = emptyStreams.CountSetBits();

                        var reader = new MetadataBitReader(this, emptyStreams);
                        ReadEmptyStreamMarkers(reader);
                        reader.Complete();
                        break;
                    }

                    case ArchiveMetadataToken.EmptyFile:
                    {
                        if (emptyStreamCount == null)
                        {
                            throw new InvalidDataException();
                        }

                        var reader = new MetadataBitReader(this, ReadRequiredBitVector(emptyStreamCount.Value));
                        ReadEmptyFileMarkers(reader);
                        reader.Complete();
                        break;
                    }

                    case ArchiveMetadataToken.Anti:
                    {
                        if (emptyStreamCount == null)
                        {
                            throw new InvalidDataException();
                        }

                        var reader = new MetadataBitReader(this, ReadRequiredBitVector(emptyStreamCount.Value));
                        ReadRemovedFileMarkers(reader);
                        reader.Complete();
                        break;
                    }

                    case ArchiveMetadataToken.StartPos:
                    {
                        var vector = ReadOptionalBitVector(fileCount);
                        using (SelectStream(streams))
                        {
                            var reader = new MetadataNumberReader(this, fileCount, vector);
                            ReadOffsets(reader);
                            reader.Complete();
                        }

                        break;
                    }

                    case ArchiveMetadataToken.CTime:
                    {
                        var vector = ReadOptionalBitVector(fileCount);
                        using (SelectStream(streams))
                        {
                            var reader = new MetadataDateReader(this, fileCount, vector);
                            ReadCTime(reader);
                            reader.Complete();
                        }

                        break;
                    }

                    case ArchiveMetadataToken.ATime:
                    {
                        var vector = ReadOptionalBitVector(fileCount);
                        using (SelectStream(streams))
                        {
                            var reader = new MetadataDateReader(this, fileCount, vector);
                            ReadATime(reader);
                            reader.Complete();
                        }

                        break;
                    }

                    case ArchiveMetadataToken.MTime:
                    {
                        var vector = ReadOptionalBitVector(fileCount);
                        using (SelectStream(streams))
                        {
                            var reader = new MetadataDateReader(this, fileCount, vector);
                            ReadMTime(reader);
                            reader.Complete();
                        }

                        break;
                    }

                    case ArchiveMetadataToken.Padding:
                        // TODO: what does the reference implementation do here? just skip it? then we shouldn't throw an exception!
                        for (int i = 0; i < recordSize; i++)
                        {
                            if (ReadByte() != 0)
                            {
                                throw new InvalidDataException();
                            }
                        }

                        break;

                    default:
                        // TODO: skip data
                        break;
                    }

                    #endregion

                    // Up until version 0.3 there was a bug which could emit invalid record sizes, but it didn't really matter.
                    // Starting from version 0.3 there have been extensions to the file format which require correct record sizes.
                    if (!(mMajorVersion == 0 && mMinorVersion < 3))
                    {
                        var newOffset = GetCurrentOffset();
                        if (newOffset - oldOffset != recordSize)
                        {
                            throw new InvalidDataException();
                        }
                    }
                }
            }

            return(metadata);
        }
Ejemplo n.º 2
0
 protected virtual void ReadAttributes(MetadataAttributeReader data)
 {
 }