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