142 lines
5.4 KiB
C#
142 lines
5.4 KiB
C#
using LibXom.Blocks;
|
|
using LibXom.Exceptions;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace LibXom.Data
|
|
{
|
|
public class XomFile
|
|
{
|
|
private int version;
|
|
private int unk0;
|
|
private List<XomString> xomStrings = new List<XomString>();
|
|
private List<XomType> xomTypes = new List<XomType>();
|
|
|
|
public XomString[] XomStrings
|
|
{
|
|
get
|
|
{
|
|
return xomStrings.ToArray();
|
|
}
|
|
}
|
|
|
|
public XomType[] XomTypes
|
|
{
|
|
get
|
|
{
|
|
return xomTypes.ToArray();
|
|
}
|
|
}
|
|
|
|
public XomContainer[] XomContainers
|
|
{
|
|
get
|
|
{
|
|
List<XomContainer> xomContainers = new List<XomContainer>();
|
|
foreach(XomType type in xomTypes)
|
|
foreach(XomContainer container in type.Containers)
|
|
xomContainers.Add(container);
|
|
return xomContainers.ToArray();
|
|
}
|
|
}
|
|
public XomString GetStringById(int stringId)
|
|
{
|
|
return XomStrings[stringId];
|
|
}
|
|
public XomContainer GetContainerById(int containerId)
|
|
{
|
|
return XomContainers[containerId];
|
|
}
|
|
public XomType GetTypeByName(string typeName)
|
|
{
|
|
foreach(XomType type in XomTypes)
|
|
if (type.Name.Equals(typeName, StringComparison.InvariantCulture)) return type;
|
|
|
|
throw new XomTypeNotFoundException("Type \"" + typeName + "\" was not found in XOM.");
|
|
}
|
|
internal int calculateIdForXomFileComponent(string searchUuid, XomFileComponent[] components)
|
|
{
|
|
for (int i = 0; i < components.Length; i++)
|
|
if (components[i].uuid.Equals(searchUuid, StringComparison.CurrentCultureIgnoreCase)) return i;
|
|
|
|
throw new XomFileComponentNotFoundException("A XOM Components ID could not be found in the Component List.");
|
|
}
|
|
internal XomFile(XomBlock[] xomBlocks)
|
|
{
|
|
MoikBlock? moikBlock = XomBlockHandler.GetBlockByName(xomBlocks, "MOIK") as MoikBlock;
|
|
SchmBlock? schemeBlock = XomBlockHandler.GetBlockByName(xomBlocks, "SCHM") as SchmBlock;
|
|
StrsBlock? stringBlock = XomBlockHandler.GetBlockByName(xomBlocks, "STRS") as StrsBlock;
|
|
|
|
// Get Types
|
|
XomBlock[] typeBlocks = XomBlockHandler.GetBlocksByName(xomBlocks, "TYPE");
|
|
|
|
// Get Containers
|
|
XomBlock[] containerBlocks = XomBlockHandler.GetBlocksByName(xomBlocks, "CTNR");
|
|
|
|
|
|
if (moikBlock is not MoikBlock) throw new XomBlockNotFoundException("XOM contained no MOIK block!, Is it corrupted?");
|
|
if (schemeBlock is not SchmBlock) throw new XomBlockNotFoundException("XOM contained no SCHM block!, Is it corrupted?");
|
|
if (stringBlock is not StrsBlock) throw new XomBlockNotFoundException("XOM contained no STRS block!, Is it corrupted?");
|
|
|
|
version = moikBlock.Version;
|
|
unk0 = schemeBlock.Unk0;
|
|
|
|
|
|
/// Read Strings
|
|
|
|
// Create a list of all strings and the offset they would appear in the strs block.
|
|
Dictionary<int, string> stringOffsets = new Dictionary<int, string>();
|
|
int loc = 0;
|
|
foreach (string str in stringBlock.StringList)
|
|
{
|
|
stringOffsets.Add(loc, str);
|
|
loc += str.Length + 1; // str length, + \0 for terminator.
|
|
}
|
|
|
|
// Now create the list of XomStrings ...
|
|
for (int i = 0; i < stringBlock.NumStrs; i++)
|
|
{
|
|
int offset = stringBlock.OffsetList[i];
|
|
string value = stringOffsets[offset];
|
|
// Were storing the offset here so that i can figure out how to best order the values again
|
|
// when reconstructing the value (eg make it as close to the actual game)
|
|
// ideally this wouldnt be needed.
|
|
// TODO: Figure out how strings are ordered, so i can ditch the offset variable.
|
|
xomStrings.Add(new XomString(this, offset, value));
|
|
|
|
}
|
|
|
|
/// Read Types
|
|
// keep a global count of how many container blocks have been processed
|
|
int cnt = 0;
|
|
foreach (TypeBlock type in typeBlocks)
|
|
{
|
|
string typeName = type.TypeName;
|
|
byte[] md5 = type.Md5;
|
|
int numContainers = type.NumCtnr;
|
|
// Create a list of containers, inside this type.
|
|
List<XomContainer> xomContainers = new List<XomContainer>();
|
|
// Read numContainers many containers from the container blocks list,
|
|
// and then create XomContainer from it.
|
|
for (int i = 0; i < numContainers; i++)
|
|
{
|
|
// Get the container block from the global count ..
|
|
CtnrBlock? containerBlock = containerBlocks[cnt] as CtnrBlock;
|
|
if (containerBlock is not CtnrBlock) continue;
|
|
|
|
// Add the new container to the list
|
|
xomContainers.Add(new XomContainer(this, typeName, containerBlock.Data));
|
|
|
|
cnt++; // Increment the global container block count.
|
|
}
|
|
|
|
this.xomTypes.Add(new XomType(this, md5, typeName, xomContainers.ToArray()));
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|