using System; using System.IO; namespace Packaging.Targets.IO { /// /// Base class for archive files, such as CPIO files or ar files. /// public abstract class ArchiveFile : IDisposable { /// /// The around which this wraps. /// private readonly Stream stream; /// /// Indicates whether should be disposed of when this is disposed of. /// private readonly bool leaveOpen; /// /// Tracks whether this has been disposed of or not. /// private bool disposed; /// /// Initializes a new instance of the class. /// /// /// A which represents the archive data. /// /// /// to leave the underlying open when this /// is disposed of; otherwise, . /// public ArchiveFile(Stream stream, bool leaveOpen) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } this.stream = stream; this.leaveOpen = leaveOpen; } /// /// Gets or sets a which represents the current entry. /// public SubStream EntryStream { get; protected set; } /// /// Gets or sets the name of the current entry. /// public string FileName { get; protected set; } /// /// Gets or sets the header for the current file. /// public IArchiveHeader FileHeader { get; protected set; } /// /// Gets the which underpins this . /// protected Stream Stream { get { this.EnsureNotDisposed(); return this.stream; } } public static int PaddingSize(int multiple, int value) { if (value % multiple == 0) { return 0; } else { return multiple - value % multiple; } } /// /// Returns a which represents the content of the current entry in the . /// /// /// A which represents the content of the current entry in the . /// public Stream Open() { return this.EntryStream; } /// public void Dispose() { if (!this.leaveOpen) { this.Stream.Dispose(); } this.disposed = true; } /// /// Reads the next entry in the archive. /// /// /// if an entry is present, if no more entries /// could be found in the archive. /// public abstract bool Read(); /// /// Skips the current entry, without reading the entry data. /// public void Skip() { byte[] buffer = new byte[60 * 1024]; while (this.EntryStream.Read(buffer, 0, buffer.Length) > 0) { // Keep reading until we're at the end of the stream. } } /// /// Throws a if has been previously called. /// protected void EnsureNotDisposed() { if (this.disposed) { throw new ObjectDisposedException(this.GetType().Name); } } /// /// Aligns the current position. /// /// /// The value to which to align. /// protected void Align(int alignmentBase) { var currentIndex = (int)(this.EntryStream != null ? (this.EntryStream.Offset + this.EntryStream.Length) : this.Stream.Position); if (this.Stream.CanSeek) { this.Stream.Seek(currentIndex + PaddingSize(alignmentBase, currentIndex), SeekOrigin.Begin); } else { byte[] buffer = new byte[PaddingSize(alignmentBase, currentIndex)]; this.Stream.Read(buffer, 0, buffer.Length); } } } }