mirror of
https://github.com/simtactics/mysimulation.git
synced 2025-07-19 04:24:54 -04:00
Added FSO.Files for use with the API server
Don't ask me. FreeSO is the prime example of dependency hell.
This commit is contained in:
parent
4b5e584eeb
commit
8fec258215
104 changed files with 14653 additions and 163 deletions
184
server/tso.files/Formats/DBPF/DBPFFile.cs
Executable file
184
server/tso.files/Formats/DBPF/DBPFFile.cs
Executable file
|
@ -0,0 +1,184 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using FSO.Files.Utils;
|
||||
|
||||
namespace FSO.Files.Formats.DBPF
|
||||
{
|
||||
/// <summary>
|
||||
/// The database-packed file (DBPF) is a format used to store data for pretty much all Maxis games after The Sims,
|
||||
/// including The Sims Online (the first appearance of this format), SimCity 4, The Sims 2, Spore, The Sims 3, and
|
||||
/// SimCity 2013.
|
||||
/// </summary>
|
||||
public class DBPFFile : IDisposable
|
||||
{
|
||||
public int DateCreated;
|
||||
public int DateModified;
|
||||
|
||||
private uint IndexMajorVersion;
|
||||
private uint NumEntries;
|
||||
private IoBuffer m_Reader;
|
||||
|
||||
private List<DBPFEntry> m_EntriesList = new List<DBPFEntry>();
|
||||
private Dictionary<ulong, DBPFEntry> m_EntryByID = new Dictionary<ulong, DBPFEntry>();
|
||||
private Dictionary<DBPFTypeID, List<DBPFEntry>> m_EntriesByType = new Dictionary<DBPFTypeID, List<DBPFEntry>>();
|
||||
|
||||
private IoBuffer Io;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new DBPF instance.
|
||||
/// </summary>
|
||||
public DBPFFile()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a DBPF instance from a path.
|
||||
/// </summary>
|
||||
/// <param name="file">The path to an DBPF archive.</param>
|
||||
public DBPFFile(string file)
|
||||
{
|
||||
var stream = File.OpenRead(file);
|
||||
Read(stream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a DBPF archive from a stream.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to read from.</param>
|
||||
public void Read(Stream stream)
|
||||
{
|
||||
m_EntryByID = new Dictionary<ulong,DBPFEntry>();
|
||||
m_EntriesList = new List<DBPFEntry>();
|
||||
|
||||
var io = IoBuffer.FromStream(stream, ByteOrder.LITTLE_ENDIAN);
|
||||
m_Reader = io;
|
||||
this.Io = io;
|
||||
|
||||
var magic = io.ReadCString(4);
|
||||
if (magic != "DBPF")
|
||||
{
|
||||
throw new Exception("Not a DBPF file");
|
||||
}
|
||||
|
||||
var majorVersion = io.ReadUInt32();
|
||||
var minorVersion = io.ReadUInt32();
|
||||
var version = majorVersion + (((double)minorVersion)/10.0);
|
||||
|
||||
/** Unknown, set to 0 **/
|
||||
io.Skip(12);
|
||||
|
||||
if (version == 1.0)
|
||||
{
|
||||
this.DateCreated = io.ReadInt32();
|
||||
this.DateModified = io.ReadInt32();
|
||||
}
|
||||
|
||||
if (version < 2.0)
|
||||
{
|
||||
IndexMajorVersion = io.ReadUInt32();
|
||||
}
|
||||
|
||||
NumEntries = io.ReadUInt32();
|
||||
uint indexOffset = 0;
|
||||
if (version < 2.0)
|
||||
{
|
||||
indexOffset = io.ReadUInt32();
|
||||
}
|
||||
var indexSize = io.ReadUInt32();
|
||||
|
||||
if (version < 2.0)
|
||||
{
|
||||
var trashEntryCount = io.ReadUInt32();
|
||||
var trashIndexOffset = io.ReadUInt32();
|
||||
var trashIndexSize = io.ReadUInt32();
|
||||
var indexMinor = io.ReadUInt32();
|
||||
}
|
||||
else if (version == 2.0)
|
||||
{
|
||||
var indexMinor = io.ReadUInt32();
|
||||
indexOffset = io.ReadUInt32();
|
||||
io.Skip(4);
|
||||
}
|
||||
|
||||
/** Padding **/
|
||||
io.Skip(32);
|
||||
|
||||
io.Seek(SeekOrigin.Begin, indexOffset);
|
||||
for (int i = 0; i < NumEntries; i++)
|
||||
{
|
||||
var entry = new DBPFEntry();
|
||||
entry.TypeID = (DBPFTypeID)io.ReadUInt32();
|
||||
entry.GroupID = (DBPFGroupID)io.ReadUInt32();
|
||||
entry.InstanceID = io.ReadUInt32();
|
||||
entry.FileOffset = io.ReadUInt32();
|
||||
entry.FileSize = io.ReadUInt32();
|
||||
|
||||
m_EntriesList.Add(entry);
|
||||
ulong id = (((ulong)entry.InstanceID) << 32) + (ulong)entry.TypeID;
|
||||
if (!m_EntryByID.ContainsKey(id))
|
||||
m_EntryByID.Add(id, entry);
|
||||
|
||||
if (!m_EntriesByType.ContainsKey(entry.TypeID))
|
||||
m_EntriesByType.Add(entry.TypeID, new List<DBPFEntry>());
|
||||
|
||||
m_EntriesByType[entry.TypeID].Add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a DBPFEntry's data from this DBPF instance.
|
||||
/// </summary>
|
||||
/// <param name="entry">Entry to retrieve data for.</param>
|
||||
/// <returns>Data for entry.</returns>
|
||||
public byte[] GetEntry(DBPFEntry entry)
|
||||
{
|
||||
m_Reader.Seek(SeekOrigin.Begin, entry.FileOffset);
|
||||
|
||||
return m_Reader.ReadBytes((int)entry.FileSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an entry from its ID (TypeID + FileID).
|
||||
/// </summary>
|
||||
/// <param name="ID">The ID of the entry.</param>
|
||||
/// <returns>The entry's data.</returns>
|
||||
public byte[] GetItemByID(ulong ID)
|
||||
{
|
||||
if (m_EntryByID.ContainsKey(ID))
|
||||
return GetEntry(m_EntryByID[ID]);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all entries of a specific type.
|
||||
/// </summary>
|
||||
/// <param name="Type">The Type of the entry.</param>
|
||||
/// <returns>The entry data, paired with its instance id.</returns>
|
||||
public List<KeyValuePair<uint, byte[]>> GetItemsByType(DBPFTypeID Type)
|
||||
{
|
||||
|
||||
var result = new List<KeyValuePair<uint, byte[]>>();
|
||||
|
||||
var entries = m_EntriesByType[Type];
|
||||
for (int i = 0; i < entries.Count; i++)
|
||||
{
|
||||
result.Add(new KeyValuePair<uint, byte[]>(entries[i].InstanceID, GetEntry(entries[i])));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
/// <summary>
|
||||
/// Disposes this DBPF instance.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Io.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue