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