/// <summary> /// Opens the archive stream for reading. /// </summary> /// <param name="archiveNumber">The zero-based index of the archive to /// open.</param> /// <param name="archiveName">The name of the archive being opened.</param> /// <param name="compressionEngine">Instance of the compression engine /// doing the operations.</param> /// <returns>A stream from which archive bytes are read, or null to cancel /// extraction of the archive.</returns> /// <remarks> /// This method opens the file from the <see cref="ArchiveFiles"/> list with /// the specified index. If the archive number is outside the bounds of the /// list, this method returns null. /// <para>If the <see cref="EnableOffsetOpen"/> flag is set, this method will /// seek to the start of any existing archive in the file, or to the end of /// the file if the existing file is not an archive.</para> /// </remarks> public virtual Stream OpenArchiveReadStream( int archiveNumber, string archiveName, CompressionEngine compressionEngine) { if (archiveNumber >= this.archiveFiles.Count) { return(null); } string archiveFile = this.archiveFiles[archiveNumber]; Stream stream = File.Open( archiveFile, FileMode.Open, FileAccess.Read, FileShare.Read); if (this.enableOffsetOpen) { if (compressionEngine == null) { throw new ArgumentNullException("compressionEngine"); } long offset = compressionEngine.FindArchiveOffset( new DuplicateStream(stream)); if (offset > 0) { stream = new OffsetStream(stream, offset); } else { stream.Seek(0, SeekOrigin.Begin); } } return(stream); }
/// <summary> /// Opens a stream for writing an archive. /// </summary> /// <param name="archiveNumber">The 0-based index of the archive within /// the chain.</param> /// <param name="archiveName">The name of the archive that was returned /// by <see cref="GetArchiveName"/>.</param> /// <param name="truncate">True if the stream should be truncated when /// opened (if it already exists); false if an existing stream is being /// re-opened for writing additional data.</param> /// <param name="compressionEngine">Instance of the compression engine /// doing the operations.</param> /// <returns>A writable Stream where the compressed archive bytes will be /// written, or null to cancel the archive creation.</returns> /// <remarks> /// This method opens the file from the <see cref="ArchiveFiles"/> list /// with the specified index. If the archive number is outside the bounds /// of the list, this method returns null. /// <para>If the <see cref="EnableOffsetOpen"/> flag is set, this method /// will seek to the start of any existing archive in the file, or to the /// end of the file if the existing file is not an archive.</para> /// </remarks> public virtual Stream OpenArchiveWriteStream( int archiveNumber, string archiveName, bool truncate, CompressionEngine compressionEngine) { if (archiveNumber >= this.archiveFiles.Count) { return(null); } if (string.IsNullOrWhiteSpace(archiveName)) { throw new ArgumentNullException("archiveName"); } // All archives must be in the same directory, // so always use the directory from the first archive. string archiveFile = Path.Combine( Path.GetDirectoryName(this.archiveFiles[0]), archiveName); Stream stream = File.Open( archiveFile, (truncate ? FileMode.OpenOrCreate : FileMode.Open), FileAccess.ReadWrite); if (this.enableOffsetOpen) { if (compressionEngine == null) { throw new ArgumentNullException("compressionEngine"); } long offset = compressionEngine.FindArchiveOffset( new DuplicateStream(stream)); // If this is not an archive file, append the archive to it. if (offset < 0) { offset = stream.Length; } if (offset > 0) { stream = new OffsetStream(stream, offset); } stream.Seek(0, SeekOrigin.Begin); } if (truncate) { // Truncate the stream, in case a larger old archive starts here. stream.SetLength(0); } return(stream); }
/// <summary> /// Checks if the archive contains a valid archive header. /// </summary> /// <returns>True if the file is a valid archive; false otherwise.</returns> public bool IsValid() { using (Stream stream = File.OpenRead(this.FullName)) { using (CompressionEngine compressionEngine = this.CreateCompressionEngine()) { return(compressionEngine.FindArchiveOffset(stream) >= 0); } } }
/// <summary> /// Opens the archive stream for reading. /// </summary> /// <param name="archiveNumber">The zero-based index of the archive to /// open.</param> /// <param name="archiveName">The name of the archive being opened.</param> /// <param name="compressionEngine">Instance of the compression engine /// doing the operations.</param> /// <returns>A stream from which archive bytes are read, or null to cancel /// extraction of the archive.</returns> /// <remarks> /// This method opens the file from the <see cref="ArchiveFiles"/> list with /// the specified index. If the archive number is outside the bounds of the /// list, this method returns null. /// <para>If the <see cref="EnableOffsetOpen"/> flag is set, this method will /// seek to the start of any existing archive in the file, or to the end of /// the file if the existing file is not an archive.</para> /// </remarks> public virtual Stream OpenArchiveReadStream( int archiveNumber, string archiveName, CompressionEngine compressionEngine) { if (archiveNumber >= this.archiveFiles.Count) { return null; } string archiveFile = this.archiveFiles[archiveNumber]; Stream stream = File.Open( archiveFile, FileMode.Open, FileAccess.Read, FileShare.Read); if (this.enableOffsetOpen) { if (compressionEngine == null) { throw new ArgumentNullException("compressionEngine"); } long offset = compressionEngine.FindArchiveOffset( new DuplicateStream(stream)); if (offset > 0) { stream = new OffsetStream(stream, offset); } else { stream.Seek(0, SeekOrigin.Begin); } } return stream; }
/// <summary> /// Opens a stream for writing an archive. /// </summary> /// <param name="archiveNumber">The 0-based index of the archive within /// the chain.</param> /// <param name="archiveName">The name of the archive that was returned /// by <see cref="GetArchiveName"/>.</param> /// <param name="truncate">True if the stream should be truncated when /// opened (if it already exists); false if an existing stream is being /// re-opened for writing additional data.</param> /// <param name="compressionEngine">Instance of the compression engine /// doing the operations.</param> /// <returns>A writable Stream where the compressed archive bytes will be /// written, or null to cancel the archive creation.</returns> /// <remarks> /// This method opens the file from the <see cref="ArchiveFiles"/> list /// with the specified index. If the archive number is outside the bounds /// of the list, this method returns null. /// <para>If the <see cref="EnableOffsetOpen"/> flag is set, this method /// will seek to the start of any existing archive in the file, or to the /// end of the file if the existing file is not an archive.</para> /// </remarks> public virtual Stream OpenArchiveWriteStream( int archiveNumber, string archiveName, bool truncate, CompressionEngine compressionEngine) { if (archiveNumber >= this.archiveFiles.Count) { return null; } if (string.IsNullOrWhiteSpace(archiveName)) { throw new ArgumentNullException("archiveName"); } // All archives must be in the same directory, // so always use the directory from the first archive. string archiveFile = Path.Combine( Path.GetDirectoryName(this.archiveFiles[0]), archiveName); Stream stream = File.Open( archiveFile, (truncate ? FileMode.OpenOrCreate : FileMode.Open), FileAccess.ReadWrite); if (this.enableOffsetOpen) { if (compressionEngine == null) { throw new ArgumentNullException("compressionEngine"); } long offset = compressionEngine.FindArchiveOffset( new DuplicateStream(stream)); // If this is not an archive file, append the archive to it. if (offset < 0) { offset = stream.Length; } if (offset > 0) { stream = new OffsetStream(stream, offset); } stream.Seek(0, SeekOrigin.Begin); } if (truncate) { // Truncate the stream, in case a larger old archive starts here. stream.SetLength(0); } return stream; }