SonicAudioTools/Source/SonicAudioLib/CriMw/CriTable.Internal.cs

141 lines
4.2 KiB
C#
Raw Normal View History

2018-01-16 09:29:02 +01:00
using System;
using System.IO;
2017-09-17 12:02:44 +02:00
using System.Runtime.InteropServices;
2016-11-12 17:02:48 +01:00
namespace SonicAudioLib.CriMw
{
2017-09-17 12:02:44 +02:00
[StructLayout(LayoutKind.Sequential)]
2016-11-12 17:02:48 +01:00
struct CriTableHeader
{
public static readonly byte[] SignatureBytes = { 0x40, 0x55, 0x54, 0x46 };
2017-01-30 11:47:50 +01:00
public const byte EncodingTypeShiftJis = 0;
public const byte EncodingTypeUtf8 = 1;
public byte[] Signature;
public uint Length;
public byte UnknownByte;
public byte EncodingType;
public ushort RowsPosition;
public uint StringPoolPosition;
public uint DataPoolPosition;
public uint TableNamePosition;
public string TableName;
public ushort FieldCount;
public ushort RowLength;
public uint RowCount;
2016-11-12 17:02:48 +01:00
}
[Flags]
2017-01-30 11:47:50 +01:00
enum CriFieldFlag : byte
2016-11-12 17:02:48 +01:00
{
Name = 16,
DefaultValue = 32,
RowStorage = 64,
Byte = 0,
SByte = 1,
UInt16 = 2,
Int16 = 3,
UInt32 = 4,
Int32 = 5,
UInt64 = 6,
Int64 = 7,
Single = 8,
2016-11-12 17:02:48 +01:00
Double = 9,
String = 10,
Data = 11,
Guid = 12,
TypeMask = 15,
};
2017-09-17 12:02:44 +02:00
[StructLayout(LayoutKind.Sequential)]
2016-11-12 17:02:48 +01:00
struct CriTableField
{
public CriFieldFlag Flag;
public string Name;
public uint Position;
public uint Length;
2017-09-17 12:02:44 +02:00
public uint Offset;
public object Value;
2016-11-12 17:02:48 +01:00
}
static class CriTableMasker
{
public static void FindKeys(byte[] signature, out uint xor, out uint xorMultiplier)
{
2018-01-16 09:29:02 +01:00
for (int x = 0; x < 0x100; x++)
{
// Find XOR using first byte
2018-01-16 09:29:02 +01:00
if ((signature[0] ^ (byte)x) == CriTableHeader.SignatureBytes[0])
{
// Matched the first byte, try finding the multiplier with the second byte
2018-01-16 09:29:02 +01:00
for (int m = 0; m < 0x100; m++)
{
// Matched the second byte, now make sure the other bytes match as well
if ((signature[1] ^ (byte)(x * m)) == CriTableHeader.SignatureBytes[1])
{
byte _x = (byte)(x * m);
bool allMatches = true;
for (int i = 2; i < 4; i++)
{
2018-01-16 09:29:02 +01:00
_x = (byte)(_x * m);
if ((signature[i] ^ _x) != CriTableHeader.SignatureBytes[i])
{
allMatches = false;
break;
}
}
// All matches, return the xor and multiplier
if (allMatches)
{
2018-01-16 09:29:02 +01:00
xor = (uint)x;
xorMultiplier = (uint)m;
return;
}
}
}
}
}
2018-01-16 09:29:02 +01:00
throw new InvalidDataException("'@UTF' signature could not be found. Your file might be corrupted.");
}
public static void Mask(Stream source, Stream destination, long length, uint xor, uint xorMultiplier)
{
uint currentXor = xor;
long currentPosition = source.Position;
while (source.Position < currentPosition + length)
{
byte maskedByte = (byte)(source.ReadByte() ^ currentXor);
currentXor *= xorMultiplier;
destination.WriteByte(maskedByte);
}
}
public static void Mask(Stream source, long length, uint xor, uint xorMultiplier)
{
if (source.CanRead && source.CanWrite)
{
uint currentXor = xor;
long currentPosition = source.Position;
while (source.Position < currentPosition + length)
{
byte maskedByte = (byte)(source.ReadByte() ^ currentXor);
currentXor *= xorMultiplier;
source.Position--;
source.WriteByte(maskedByte);
}
}
}
}
2016-11-12 17:02:48 +01:00
}