public static bool parseBCH(string path) { // goto 0x80 (skip the PT container header and go straight to the BCH data // srcdata[:]=srcdata[0x80:len(srcdata)] byte[] input = File.ReadAllBytes(path); if (input.Length == 0) { return(false); } if (BitConverter.ToUInt32(input, 0) != 0x484342) // BCH { return(false); } // BCH should now be in our data array. BCH bch = analyze(path, input); if (bch.TextureCount > 0) { Directory.CreateDirectory(bch.FilePath + "\\" + bch.FileName + "_\\"); } for (int i = 0; i < bch.TextureCount; i++) { string texname = bch.TexNames[i]; Bitmap img = parseEntry(bch.Textures[i], bch.data); //pass in texture desc, data using (MemoryStream ms = new MemoryStream()) { //error will throw from here img.Save(ms, ImageFormat.Png); byte[] data = ms.ToArray(); File.WriteAllBytes(bch.FilePath + "\\" + bch.FileName + "_\\" + texname + ".png", data); } } return(true); }
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); }
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; }