using System; using System.IO; using System.Text; namespace Packaging.Targets.IO { /// /// Represents an ar archive, the format used by Debian installer packages. /// /// public class ArFile : ArchiveFile { /// /// The magic used to identify ar files. /// private const string Magic = "!\n"; /// /// Tracks whether the magic has been read or not. /// private bool magicRead; /// /// The header of the current entry. /// private ArHeader entryHeader; /// /// Initializes a new instance of the class. /// /// /// A which represents the CPIO data. /// /// /// to leave the underlying open when this /// is disposed of; otherwise, . /// public ArFile(Stream stream, bool leaveOpen) : base(stream, leaveOpen) { } /// public override bool Read() { this.EnsureMagicRead(); if (this.EntryStream != null) { this.EntryStream.Dispose(); } this.Align(2); if (this.Stream.Position == this.Stream.Length) { return false; } this.entryHeader = this.Stream.ReadStruct(); this.FileHeader = this.entryHeader; this.FileName = this.entryHeader.FileName; if (this.entryHeader.EndChar != "`\n") { throw new InvalidDataException("The magic for the file entry is invalid"); } this.EntryStream = new SubStream(this.Stream, this.Stream.Position, this.entryHeader.FileSize, leaveParentOpen: true); return true; } /// /// Reads the magic if it has not been read previously. /// protected void EnsureMagicRead() { if (!this.magicRead) { byte[] buffer = new byte[Magic.Length]; this.Stream.Read(buffer, 0, buffer.Length); var magic = Encoding.ASCII.GetString(buffer); if (!string.Equals(magic, Magic, StringComparison.Ordinal)) { throw new InvalidDataException("The .ar file did not start with the expected magic"); } this.magicRead = true; } } } }