1
0
mirror of synced 2024-12-11 07:16:05 +01:00
Switch-Toolbox/File_Format_Library/FileFormats/BCSV/BCSVParse.cs
2020-10-02 17:11:24 +10:00

167 lines
5.1 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Toolbox.Library;
using Toolbox.Library.IO;
using Toolbox.Library.Security.Cryptography;
namespace FirstPlugin
{
public class BCSVParse
{
public class Field
{
public uint Hash { get; set; }
public uint Offset { get; set; }
public object Value;
}
public class DataEntry
{
public Dictionary<string, object> Fields;
}
static Dictionary<uint, string> hashes = new Dictionary<uint, string>();
public static Dictionary<uint, string> Hashes
{
get
{
if (hashes.Count == 0)
CalculateHashes();
return hashes;
}
}
public List<DataEntry> Entries = new List<DataEntry>();
public void Read(FileReader reader)
{
uint numEntries = reader.ReadUInt32();
uint entrySize = reader.ReadUInt32();
ushort numFields = reader.ReadUInt16();
byte flag1 = reader.ReadByte();
byte flag2 = reader.ReadByte();
if (flag1 == 1)
{
uint magic = reader.ReadUInt32();
uint unk = reader.ReadUInt32(); //Always 100000
reader.ReadUInt32();//0
reader.ReadUInt32();//0
}
Field[] fields = new Field[numFields];
for (int i = 0; i < numFields; i++) {
fields[i] = new Field()
{
Hash = reader.ReadUInt32(),
Offset = reader.ReadUInt32(),
};
}
for (int i = 0; i < numEntries; i++)
{
DataEntry entry = new DataEntry();
Entries.Add(entry);
entry.Fields = new Dictionary<string, object>();
long pos = reader.Position;
for (int f = 0; f < fields.Length; f++)
{
DataType type = DataType.String;
uint size = entrySize - fields[f].Offset;
if (f < fields.Length - 1) {
size = fields[f + 1].Offset - fields[f].Offset;
}
if (size == 1)
type = DataType.Byte;
if (size == 2)
type = DataType.Int16;
if (size == 4)
type = DataType.Int32;
reader.SeekBegin(pos + fields[f].Offset);
object value = 0;
string name = fields[f].Hash.ToString("x");
switch (type)
{
case DataType.Byte:
value = reader.ReadByte();
break;
case DataType.Float:
value = reader.ReadSingle();
break;
case DataType.Int16:
value = reader.ReadInt16();
break;
case DataType.Int32:
value = reader.ReadInt32();
if (IsFloatValue((int)value))
{
reader.Seek(-4);
value = reader.ReadSingle();
}
break;
case DataType.String:
value = reader.ReadZeroTerminatedString(Encoding.UTF8);
break;
}
if (Hashes.ContainsKey(fields[f].Hash))
name = Hashes[fields[f].Hash];
entry.Fields.Add(name, value);
}
reader.SeekBegin(pos + entrySize);
}
}
private bool IsFloatValue(int value) {
return value.ToString().Length > 6;
}
public enum DataType
{
Byte,
Int16,
Int32,
Int64,
Float,
String,
}
public void Write(FileWriter writer)
{
writer.Write(Entries.FirstOrDefault().Fields.Count);
}
private static void CalculateHashes()
{
string dir = Path.Combine(Runtime.ExecutableDir, "Hashes");
if (!Directory.Exists(dir))
return;
foreach (var file in Directory.GetFiles(dir))
{
if (Utils.GetExtension(file) != ".txt")
continue;
foreach (string hashStr in File.ReadAllLines(file))
{
CheckHash(hashStr);
}
}
}
private static void CheckHash(string hashStr)
{
uint hash = Crc32.Compute(hashStr);
if (!hashes.ContainsKey(hash))
hashes.Add(hash, hashStr);
}
}
}