Ejemplo n.º 1
0
        /// <summary>
        /// Allows to copy complete sections from existing archives into this archive.
        /// </summary>
        public async Task TransferSectionAsync(Stream stream, ArchiveMetadata metadata, int section)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }

            if (metadata == null)
            {
                throw new ArgumentNullException(nameof(metadata));
            }

            if (section < 0 || section >= metadata.DecoderSections.Length)
            {
                throw new ArgumentOutOfRangeException(nameof(section));
            }

            var decoderSection = metadata.DecoderSections[section];
            var count          = decoderSection.Streams.Length;

            if (count == 0)
            {
                throw new InvalidOperationException();
            }

            // TODO: wait for pending writes
            // TODO: translate and append decoder section

            foreach (var decoder in decoderSection.Decoders)
            {
                foreach (var input in decoder.InputStreams)
                {
                    if (!input.DecoderIndex.HasValue)
                    {
                        var fileSection = metadata.FileSections[input.StreamIndex];
                        var offset      = mAppendPosition;
                        var length      = fileSection.Length;
                        mAppendPosition = checked (offset + length);
                        mFileSections.Add(new ArchiveFileSection(offset, length, fileSection.Checksum));
                        using (var fileSectionStream = new ConstrainedReadStream(mArchiveStream, fileSection.Offset, fileSection.Length))
                            await fileSectionStream.CopyToAsync(mArchiveStream).ConfigureAwait(false);
                    }
                }
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Allows to copy complete sections from existing archives into this archive.
        /// </summary>
        public async Task TransferSectionAsync(Stream stream, ArchiveMetadata metadata, int section)
        {
            if (stream == null)
                throw new ArgumentNullException(nameof(stream));

            if (metadata == null)
                throw new ArgumentNullException(nameof(metadata));

            if (section < 0 || section >= metadata.DecoderSections.Length)
                throw new ArgumentOutOfRangeException(nameof(section));

            var decoderSection = metadata.DecoderSections[section];
            var count = decoderSection.Streams.Length;
            if (count == 0)
                throw new InvalidOperationException();

            // TODO: wait for pending writes
            // TODO: translate and append decoder section

            foreach (var decoder in decoderSection.Decoders)
            {
                foreach (var input in decoder.InputStreams)
                {
                    if (!input.DecoderIndex.HasValue)
                    {
                        var fileSection = metadata.FileSections[input.StreamIndex];
                        var offset = mAppendPosition;
                        var length = fileSection.Length;
                        mAppendPosition = checked(offset + length);
                        mFileSections.Add(new ArchiveFileSection(offset, length, fileSection.Checksum));
                        using (var fileSectionStream = new ConstrainedReadStream(mArchiveStream, fileSection.Offset, fileSection.Length))
                            await fileSectionStream.CopyToAsync(mArchiveStream).ConfigureAwait(false);
                    }
                }
            }
        }
Ejemplo n.º 3
0
        protected ArchiveMetadata ReadMetadataCore(Stream stream, PasswordStorage password)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }

            if (!stream.CanRead || !stream.CanSeek)
            {
                throw new InvalidOperationException("Stream must support reading and seeking.");
            }

            if (mStream != null)
            {
                throw new InvalidOperationException("Recursive invocation.");
            }

            try
            {
                mPassword        = password;
                mStream          = stream;
                mStream.Position = 0;
                mStreamLength    = stream.Length;

                var exception = ReadFileHeader(mStream, mStreamLength, out mMajorVersion, out mMinorVersion, out mMetadataOffset, out mMetadataLength, out mMetadataChecksum);
                if (exception != null)
                {
                    throw exception;
                }

                if (mMetadataLength == 0)
                {
                    return(new ArchiveMetadata());
                }

                // TODO: validate metadata stream checksum

                using (var metadataStream = new ConstrainedReadStream(mStream, ArchiveMetadataFormat.kHeaderLength + mMetadataOffset, mMetadataLength))
                    using (var scope = new StreamScope(this))
                    {
                        scope.SetSource(metadataStream);

                        if (!PrepareMetadata(scope))
                        {
                            return(new ArchiveMetadata());
                        }

                        return(ReadArchive());
                    }
            }
            finally
            {
                // Drop references to password and stream so they aren't retained.
                mPassword = null;
                mStream   = null;

                // It is also important to reset optional values to their defaults. Otherwise if
                // the next archive we are reading doesn't contain some of the optional values
                // we could mistake the values from the previous archive as current values.
                //mFileCount = 0;
            }
        }
        protected ArchiveMetadata ReadMetadataCore(Stream stream, PasswordStorage password)
        {
            if (stream == null)
                throw new ArgumentNullException(nameof(stream));

            if (!stream.CanRead || !stream.CanSeek)
                throw new InvalidOperationException("Stream must support reading and seeking.");

            if (mStream != null)
                throw new InvalidOperationException("Recursive invocation.");

            try
            {
                mPassword = password;
                mStream = stream;
                mStream.Position = 0;
                mStreamLength = stream.Length;

                var exception = ReadFileHeader(mStream, mStreamLength, out mMajorVersion, out mMinorVersion, out mMetadataOffset, out mMetadataLength, out mMetadataChecksum);
                if (exception != null)
                    throw exception;

                if (mMetadataLength == 0)
                    return new ArchiveMetadata();

                // TODO: validate metadata stream checksum

                using (var metadataStream = new ConstrainedReadStream(mStream, ArchiveMetadataFormat.kHeaderLength + mMetadataOffset, mMetadataLength))
                using (var scope = new StreamScope(this))
                {
                    scope.SetSource(metadataStream);

                    if (!PrepareMetadata(scope))
                        return new ArchiveMetadata();

                    return ReadArchive();
                }
            }
            finally
            {
                // Drop references to password and stream so they aren't retained.
                mPassword = null;
                mStream = null;

                // It is also important to reset optional values to their defaults. Otherwise if
                // the next archive we are reading doesn't contain some of the optional values
                // we could mistake the values from the previous archive as current values.
                //mFileCount = 0;
            }
        }