Files
korenkonder_PD_Tool/KKdBaseLib/F2/POF.cs
T
2021-04-29 07:41:23 +03:00

144 lines
4.4 KiB
C#

namespace KKdBaseLib.F2
{
public struct POF : INull
{
public KKdList<long> Offsets;
public bool IsNull => Offsets. IsNull;
public bool NotNull => Offsets.NotNull;
public int Length => length(false).A(0x10);
public int LengthX => length( true).A(0x10);
public unsafe void Read(byte[] data, bool shiftX)
{
Offsets = KKdList<long>.New;
fixed (byte* ptr = data)
{
long offset = 0;
int i = 0, j = 0, v = 0;
byte bitShift = (byte)(shiftX ? 3 : 2);
int length = *(int*)ptr - 4;
byte* l = ptr + 4;
Offsets.Capacity = length;
while (length > i)
{
if (ReadPOFValue(ref l, out v)) break;
j++;
offset += v;
Offsets.Add(offset << bitShift);
}
Offsets.Capacity = j;
}
}
public unsafe byte[] Write(bool shiftX)
{
Offsets.Sort();
long j, k, o;
byte bitShift, v;
bitShift = (byte)(shiftX ? 3 : 2);
v = (byte)((1 << bitShift) - 1);
j = 0;
byte[] data = new byte[length(shiftX)];
fixed (byte* ptr = data)
{
*(int*)ptr = length(shiftX);
byte* l = ptr + 4;
for (int i = 0; i < Offsets.Count; i++)
{
o = Offsets[i];
if ((o & v) != 0)
{
WritePOFValue(ref l, 0x7FFFFFFF);
break;
}
k = o - j;
if (i > 0 & k == 0)
continue;
j = o;
o = k;
WritePOFValue(ref l, o >> bitShift);
}
}
return data;
}
[System.ThreadStatic] private static Value value;
private unsafe static bool ReadPOFValue(ref byte* ptr, out int v)
{
v = *ptr & 0x3F;
value = (Value)((*ptr & 0xC0) >> 6);
ptr++;
if (value == Value.Int32 ) v = (((((v << 8) | *ptr++) << 8) | *ptr++) << 8) | *ptr++;
else if (value == Value.Int16 ) v = (v << 8) | *ptr++;
else if (value == Value.Invalid) { v = 0; return true; }
return false;
}
private unsafe static bool WritePOFValue(ref byte* ptr, long val)
{
if (val < 0x00000040)
*ptr++ = (byte)(((byte)Value.Int8 << 6) | ( val & 0x3F));
else if (val < 0x00004000)
{
*ptr++ = (byte)(((byte)Value.Int16 << 6) | ((val >> 8) & 0x3F));
*ptr++ = (byte)(val & 0xFF);
}
else if (val < 0x40000000)
{
*ptr++ = (byte)(((byte)Value.Int32 << 6) | ((val >> 24) & 0x3F));
*ptr++ = (byte)((val >> 16) & 0xFF);
*ptr++ = (byte)((val >> 8) & 0xFF);
*ptr++ = (byte)( val & 0xFF);
}
else
{
*ptr++ = (byte)Value.Invalid << 6;
return true;
}
return false;
}
private int length(bool shiftX = false)
{
if (Offsets.IsNull)
return 0;
int length = 4;
long offset = 0;
byte bitShift = (byte)(shiftX ? 3 : 2);
int max1 = 0x00000040;
int max2 = 0x00004000;
int max3 = 0x40000000;
for (int i = 0; i < Offsets.Count; i++)
{
offset = Offsets[i];
if (i > 0) { offset -= Offsets[i - 1]; if (offset == 0) continue; }
offset >>= bitShift;
if (offset < max1) length += 1;
else if (offset < max2) length += 2;
else if (offset < max3) length += 4;
else length += 1;
}
return length;
}
public enum Value : byte
{
Invalid = 0b00,
Int8 = 0b01,
Int16 = 0b10,
Int32 = 0b11,
}
public override string ToString() =>
$"{(NotNull ? $"Offsets Count: {Offsets.Count}" : "No POF")}";
}
}