using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace FSO.Files.FAR1
{
///
/// A FAR1 (File Archive v1) archive.
///
public class FAR1Archive
{
private string m_Path;
private BinaryReader m_Reader;
private uint m_ManifestOffset;
private uint m_NumFiles;
private List m_Entries = new List();
private bool V1b = true;
///
/// The offset into the archive of the manifest.
///
public uint ManifestOffset
{
get { return m_ManifestOffset; }
}
///
/// The number of files/entries in the archive.
///
public uint NumFiles
{
get { return m_NumFiles; }
}
///
/// Creates a new FAR1Archive instance from a path.
///
/// The path to the archive.
public FAR1Archive(string Path, bool v1b)
{
m_Path = Path;
m_Reader = new BinaryReader(File.Open(Path, FileMode.Open, FileAccess.Read, FileShare.Read));
//Magic number - An 8-byte string (not null-terminated), consisting of the ASCII characters "FAR!byAZ"
string Header = Encoding.ASCII.GetString(m_Reader.ReadBytes(8));
//Version - A 4-byte unsigned integer specifying the version; 1a and 1b each specify 1.
uint Version = m_Reader.ReadUInt32();
if ((Header != "FAR!byAZ") || (Version != 1))
{
throw (new Exception("Archive wasn't a valid FAR V.1 archive!"));
}
//File table offset - A 4-byte unsigned integer specifying the offset to the file table
//from the beginning of the archive.
m_ManifestOffset = m_Reader.ReadUInt32();
m_Reader.BaseStream.Seek(m_ManifestOffset, SeekOrigin.Begin);
m_NumFiles = m_Reader.ReadUInt32();
for (int i = 0; i < m_NumFiles; i++)
{
FarEntry Entry = new FarEntry();
Entry.DataLength = m_Reader.ReadInt32();
Entry.DataLength2 = m_Reader.ReadInt32();
Entry.DataOffset = m_Reader.ReadInt32();
Entry.FilenameLength = (v1b) ? m_Reader.ReadInt16() : (short)m_Reader.ReadInt32();
Entry.Filename = Encoding.ASCII.GetString(m_Reader.ReadBytes(Entry.FilenameLength));
m_Entries.Add(Entry);
}
}
///
/// Gets an entry based on a KeyValuePair.
///
/// A KeyValuePair (string, byte[]) representing the entry. The byte array can be null.
/// A FarEntry or null if the entry wasn't found.
public byte[] GetEntry(KeyValuePair Entry)
{
foreach (FarEntry Ent in m_Entries)
{
if (Ent.Filename == Entry.Key)
{
m_Reader.BaseStream.Seek(Ent.DataOffset, SeekOrigin.Begin);
return m_Reader.ReadBytes(Ent.DataLength);
}
}
return null;
}
///
/// Gets an entry's data from a FarEntry instance.
///
/// A FarEntry instance.
/// The entry's data.
public byte[] GetEntry(FarEntry Entry)
{
foreach (FarEntry Ent in m_Entries)
{
if (Ent.Filename == Entry.Filename)
{
m_Reader.BaseStream.Seek(Ent.DataOffset, SeekOrigin.Begin);
return m_Reader.ReadBytes(Ent.DataLength);
}
}
return null;
}
///
/// Returns a list of all FarEntry instances in this archive.
///
///
public List GetAllFarEntries()
{
return m_Entries;
}
///
/// Gets all entries in the archive.
///
/// A List of KeyValuePair instances.
public List> GetAllEntries()
{
List> Entries = new List>();
foreach (FarEntry Entry in m_Entries)
{
m_Reader.BaseStream.Seek(Entry.DataOffset, SeekOrigin.Begin);
byte[] Data = m_Reader.ReadBytes(Entry.DataLength);
KeyValuePair KvP = new KeyValuePair(Entry.Filename, Data);
Entries.Add(KvP);
}
return Entries;
}
public void Close()
{
m_Reader.Close();
}
}
}