public static BCH analyze(string path, byte[] input)
{
BCH bch = new BCH
{
FileName = Path.GetFileNameWithoutExtension(path),
FilePath = Path.GetDirectoryName(path),
Extension = Path.GetExtension(path)
};
using (MemoryStream ms = new MemoryStream())
{
using (BinaryWriter bw = new BinaryWriter(ms))
{
bw.Write(input);
using (BinaryReader br = new BinaryReader(ms))
{
br.BaseStream.Seek(0, SeekOrigin.Begin);
long bchlength = br.BaseStream.Length;
bch.Magic = br.ReadUInt32(); //0x00 [4]byte "BCH\x00"
br.ReadUInt32(); //0x04 [4]byte 07 07 0D 97
bch.InfoOffset = br.ReadUInt32(); //0x08 InfoTable Offset
bch.SymbolOffset = br.ReadUInt32(); //0x0C SymbTable Offset
bch.DescOffset = br.ReadUInt32(); //0x10 DescTable Offset
bch.DataOffset = br.ReadUInt32(); //0x14 DataTable Offset
uint AfterDataOffset = br.ReadUInt32(); //0x18 UnknTable offset
uint AADP = br.ReadUInt32(); //0x1C InfoTable size
uint SymbSize = br.ReadUInt32(); //0x20 SymbTable Size
uint DescSize = br.ReadUInt32(); //0x24 DescTable Size
bch.DataLength = br.ReadUInt32(); //0x28 DataTable Size
uint dumb = br.ReadUInt32(); //0x2C UnknTable Size
if (bch.InfoOffset == 0x44)
{
SymbSize = DescSize;
bch.DataLength = Math.Max(dumb, Math.Max(AADP, AfterDataOffset) - bch.DataOffset);
}
br.BaseStream.Seek(bch.InfoOffset + 0x24, SeekOrigin.Begin);
bch.TableOffset = br.ReadUInt32() + bch.InfoOffset; //info+0x24
bch.TextureCount = br.ReadUInt32(); //info+0x28
bch.TexNames = new List<String>();
bch.RawNames = new Dictionary<int, string>();
br.BaseStream.Seek((bch.SymbolOffset), SeekOrigin.Begin);
int ofs = 0;
uint ind = 0;
while (ind < SymbSize)
{
string curname = "";
byte b = br.ReadByte();
ind++;
while (b != 0)
{
curname = curname + (char)b;
b = br.ReadByte();
ind++;
}
bch.RawNames.Add(ofs, curname);
ofs += curname.Length + 1;
}
bch.Textures = new List<BCHTexture>();
for (int i = 0; i < bch.TextureCount; i++)
{
BCHTexture CurTexture = new BCHTexture();
br.BaseStream.Seek(bch.TableOffset + i * 0x4, SeekOrigin.Begin);
uint CurTexInfoOffset = br.ReadUInt32();
br.BaseStream.Seek(bch.InfoOffset + CurTexInfoOffset, SeekOrigin.Begin);
CurTexture.DescOffset = br.ReadUInt32() + bch.DescOffset; //0x0 Location within Desc
br.ReadUInt32(); //0x4 unk
br.ReadUInt32(); //0x8 unk
br.ReadUInt32(); //0xC unk
br.ReadUInt32(); //0x10 unk
br.ReadUInt32(); //0x14 unk
br.ReadUInt32(); //0x18 unk;
int key = (int)br.ReadUInt32(); //0x1C Name offset; not useful because we already parsed
if (bch.InfoOffset == 0x44)
{
// key--;
}
string name;
bch.RawNames.TryGetValue(key, out name);
bch.TexNames.Add(name);
br.BaseStream.Seek(CurTexture.DescOffset, SeekOrigin.Begin);
CurTexture.Height = br.ReadUInt16(); //0x0 height
CurTexture.Width = br.ReadUInt16(); //0x2 width
br.ReadUInt32(); //0x4, unk
CurTexture.DataOffset = br.ReadUInt32(); //0x8 DataOffset
br.ReadUInt32(); //0xC unk
CurTexture.Format = br.ReadUInt32(); //0x10 Format
if (bch.InfoOffset == 0x44 || bch.InfoOffset == 0x3C)
{
CurTexture.DataOffset = CurTexture.Format;
br.ReadUInt32();
CurTexture.Format = br.ReadUInt32();
}
bch.Textures.Add(CurTexture); //OKAY DONE
}
for (int i = 0; i < bch.Textures.Count - 1; i++)
{
BCHTexture bchtex = bch.Textures[i];
bchtex.Length = bch.Textures[i + 1].DataOffset - bch.Textures[i].DataOffset;
if (bch.InfoOffset == 0x44)
{
bchtex.Length = (uint)(FormatToBPP((int)bchtex.Format) * bchtex.Width * bchtex.Height);
}
bch.Textures[i] = bchtex;
}
if (bch.TextureCount > 0)
{
BCHTexture bchtex1 = bch.Textures[bch.Textures.Count - 1];
bchtex1.Length = bch.DataLength - bchtex1.DataOffset;
if (bch.InfoOffset == 0x44)
{
bchtex1.Length = (uint)(FormatToBPP((int)bchtex1.Format) * bchtex1.Width * bchtex1.Height);
}
bch.Textures[bch.Textures.Count - 1] = bchtex1;
}
br.BaseStream.Seek(bch.DataOffset, SeekOrigin.Begin);
byte[] data = new byte[bch.DataLength];
br.Read(data, 0, (int)bch.DataLength);
bch.data = data;
}
}
}
return bch;
}