/// <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); } } } }
/// <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); } } } }
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; } }