Roblox-File-Format/BinaryFormat/BinaryFile.cs
CloneTrooper1019 08c5032ca8 Generally working out the library's flow.
I've setup a system for supporting multiple implementations for Roblox's
file format. This will allow me to cover the binary format and xml
format under the same general-purpose object.

Haven't done much with the XML format yet, but I've been making some
adjustments to the binary format implementation so that its more evenly
branched out and doesn't retain more information than it needs to. I've
also fixed some issues with the data-types, and documented the Instance
object.
2019-01-29 03:50:55 -06:00

95 lines
3.3 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Roblox.BinaryFormat.Chunks;
namespace Roblox.BinaryFormat
{
public class RobloxBinaryFile : IRobloxFile
{
// Header Specific
public const string MagicHeader = "<roblox!\x89\xff\x0d\x0a\x1a\x0a";
public ushort Version;
public uint NumTypes;
public uint NumInstances;
public byte[] Reserved;
// IRobloxFile
public List<Instance> BinaryTrunk = new List<Instance>();
public IReadOnlyList<Instance> Trunk => BinaryTrunk.AsReadOnly();
// Runtime Specific
public List<RobloxBinaryChunk> Chunks = new List<RobloxBinaryChunk>();
public override string ToString() => GetType().Name;
public Instance[] Instances;
public META Metadata;
public INST[] Types;
public void Initialize(byte[] contents)
{
using (MemoryStream file = new MemoryStream(contents))
using (RobloxBinaryReader reader = new RobloxBinaryReader(file))
{
// Verify the signature of the file.
byte[] binSignature = reader.ReadBytes(14);
string signature = Encoding.UTF7.GetString(binSignature);
if (signature != MagicHeader)
throw new InvalidDataException("Provided file's signature does not match RobloxBinaryFile.MagicHeader!");
// Read header data.
Version = reader.ReadUInt16();
NumTypes = reader.ReadUInt32();
NumInstances = reader.ReadUInt32();
Reserved = reader.ReadBytes(8);
// Begin reading the file chunks.
bool reading = true;
Types = new INST[NumTypes];
Instances = new Instance[NumInstances];
while (reading)
{
try
{
RobloxBinaryChunk chunk = new RobloxBinaryChunk(reader);
Chunks.Add(chunk);
switch (chunk.ChunkType)
{
case "INST":
INST type = new INST(chunk);
type.Allocate(this);
break;
case "PROP":
PROP.ReadProperties(this, chunk);
break;
case "PRNT":
PRNT prnt = new PRNT(chunk);
prnt.Assemble(this);
break;
case "META":
Metadata = new META(chunk);
break;
case "END\0":
reading = false;
break;
default:
Chunks.Remove(chunk);
break;
}
}
catch (EndOfStreamException)
{
throw new Exception("Unexpected end of file!");
}
}
}
}
}
}