static void CreateTexbinFile(string pathname, bool generateRectSection = true, bool compressedData = true) { var filelist = Directory.GetFiles(pathname).Where(x => !x.ToLower().EndsWith(".xml")).ToArray(); var filelist_unique = filelist.Select(Path.GetFileNameWithoutExtension).Distinct().Where(x => !x.ToLower().EndsWith(".xml")).ToList(); filelist_unique = filelist_unique.Select(x => x.ToUpper()).ToList(); if (filelist_unique.Count != filelist.Length) { Console.WriteLine("Folder has more files than expected. Are there multiple files with the same name (not including extension)?"); Environment.Exit(1); } var formatMetadata = new FormatMetadata(); if (File.Exists(Path.Combine(pathname, "_metadata-format.xml"))) { formatMetadata = DeserializeFormatMetadata(Path.Combine(pathname, "_metadata-format.xml")); } else { foreach (var filename in filelist_unique) { var data = new FormatInfo { Filename = filename, FormatType = 0, }; formatMetadata.FormatInfo.Add(data); } } var nameSection = CreateNameSection(filelist_unique); var dataSection = new List <byte>(); var fileinfoSection = new List <byte>(); var imageRectInfo = new Dictionary <string, Tuple <ushort, ushort> >(); for (int i = 0; i < filelist_unique.Count; i++) { var data = File.ReadAllBytes(filelist[i]); Console.WriteLine("Adding {0}...", filelist[i]); if (!data.Take(4).SequenceEqual(new byte[] { 0x54, 0x58, 0x44, 0x54 }) && !data.Take(4).SequenceEqual(new byte[] { 0x54, 0x44, 0x58, 0x54 })) { data = gitadora_textool.Program.CreateImageCore(data, true); } var formatTypeList = formatMetadata.FormatInfo.Where(x => String.CompareOrdinal(Path.GetFileNameWithoutExtension(filelist_unique[i]), x.Filename) == 0).ToList(); data[0x2c] = formatTypeList.Count > 0 ? formatTypeList[0].FormatType : data[0x2c]; fileinfoSection.AddRange(BitConverter.GetBytes(0)); fileinfoSection.AddRange(BitConverter.GetBytes(data.Length + 0x08)); fileinfoSection.AddRange(BitConverter.GetBytes(0x40 + nameSection.Count + (filelist_unique.Count * 0x0c) + dataSection.Count)); if (compressedData) { dataSection.AddRange(Compress(data)); } else { dataSection.AddRange(BitConverter.GetBytes(data.Length).Reverse()); dataSection.AddRange(BitConverter.GetBytes(0)); dataSection.AddRange(data); } imageRectInfo[filelist_unique[i]] = new Tuple <ushort, ushort>((ushort)((data[0x11] << 8) | data[0x10]), (ushort)((data[0x13] << 8) | data[0x12])); } if ((dataSection.Count % 4) != 0) { var padding = 4 - (dataSection.Count % 4); while (padding > 0) { dataSection.Add(0); padding--; } } var rectSection = new List <byte>(); if (generateRectSection) { var rectInfo = new TexInfo(); if (File.Exists(Path.Combine(pathname, "_metadata.xml"))) { rectInfo = Deserialize(Path.Combine(pathname, "_metadata.xml")); } else { foreach (var filename in filelist_unique) { var data = new RectInfo { ExternalFilename = filename, Filename = filename, X = 0, Y = 0, W = imageRectInfo[filename].Item1, H = imageRectInfo[filename].Item2 }; rectInfo.RectInfo.Add(data); } } var rectNameFilelist = rectInfo.RectInfo.Select(x => x.Filename) .Select(Path.GetFileNameWithoutExtension).Distinct() .Where(x => !x.ToLower().EndsWith(".xml")).ToList(); var rectinfoSection = new List <byte>(); var rectNameSection = CreateNameSection(rectNameFilelist); foreach (var data in rectInfo.RectInfo) { rectinfoSection.AddRange(BitConverter.GetBytes(filelist_unique.IndexOf(Path.GetFileNameWithoutExtension(data.ExternalFilename)))); rectinfoSection.AddRange(BitConverter.GetBytes(data.X)); rectinfoSection.AddRange(BitConverter.GetBytes(data.W)); rectinfoSection.AddRange(BitConverter.GetBytes(data.Y)); rectinfoSection.AddRange(BitConverter.GetBytes(data.H)); } rectSection.AddRange( new byte[] { 0x54, 0x43, 0x45, 0x52, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00 }); rectSection.AddRange(BitConverter.GetBytes(0x1c + rectNameSection.Count + rectinfoSection.Count)); rectSection.AddRange(BitConverter.GetBytes(rectNameFilelist.Count)); rectSection.AddRange(BitConverter.GetBytes(0x1c)); rectSection.AddRange(BitConverter.GetBytes(0x1c + rectNameSection.Count)); rectSection.AddRange(rectNameSection); rectSection.AddRange(rectinfoSection); } var outputData = new List <byte>(); outputData.AddRange(new byte[] { 0x50, 0x58, 0x45, 0x54, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00 }); outputData.AddRange(BitConverter.GetBytes(0x40 + nameSection.Count + fileinfoSection.Count + dataSection.Count + rectSection.Count)); // Archive size outputData.AddRange(BitConverter.GetBytes(1)); outputData.AddRange(BitConverter.GetBytes(filelist_unique.Count)); outputData.AddRange(BitConverter.GetBytes(0)); outputData.AddRange(BitConverter.GetBytes(0x40 + nameSection.Count + fileinfoSection.Count)); outputData.AddRange(BitConverter.GetBytes(rectSection.Count > 0 ? 0x40 + nameSection.Count + fileinfoSection.Count + dataSection.Count : 0)); outputData.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); outputData.AddRange(BitConverter.GetBytes(0x40)); // PMAN section offset outputData.AddRange(BitConverter.GetBytes(0)); outputData.AddRange(BitConverter.GetBytes(0x40 + nameSection.Count)); outputData.AddRange(nameSection); outputData.AddRange(fileinfoSection); outputData.AddRange(dataSection); outputData.AddRange(rectSection); var basePath = Path.GetFileName(pathname); if (String.IsNullOrWhiteSpace(basePath)) { basePath = pathname.Replace(".\\", "").Replace("\\", ""); } var outputFilename = Path.Combine(Path.GetDirectoryName(pathname), String.Format("{0}.bin", basePath)); File.WriteAllBytes(outputFilename, outputData.ToArray()); }
static void ParseTexbinFile(string filename, bool splitImages = true) { var outputPath = Path.Combine(Path.GetDirectoryName(filename), Path.GetFileNameWithoutExtension(filename)); Directory.CreateDirectory(outputPath); using (BinaryReader reader = new BinaryReader(File.Open(filename, FileMode.Open))) { var texpMagic = Encoding.ASCII.GetString(reader.ReadBytes(4)); if (texpMagic != "PXET") { Console.WriteLine("Not a valid texbin file"); Environment.Exit(1); } var unk1 = reader.ReadInt32(); var unk2 = reader.ReadInt32(); var archiveSize = reader.ReadInt32(); var unk3 = reader.ReadInt32(); var fileCount = reader.ReadInt64(); var dataOffset = reader.ReadInt32(); var rectOffset = reader.ReadInt32(); var unk4 = reader.ReadBytes(0x10); var nameOffset = reader.ReadInt32(); var unk5 = reader.ReadInt32(); var dataEntryOffset = reader.ReadInt32(); if (fileCount == 0) { Console.WriteLine("This file doesn't contain any image data."); return; } var entries = ReadNameSection(reader, nameOffset); ReadDataEntrySection(reader, dataEntryOffset, fileCount, entries); var texInfo = new TexInfo(); if (rectOffset != 0) { var rectInfo = ReadRectEntrySection(reader, rectOffset); foreach (var rect in rectInfo) { var e = new RectInfo { ExternalFilename = entries[rect.ImageId].Filename, Filename = rect.Entry.Filename, X = rect.X, Y = rect.Y, W = rect.W, H = rect.H }; texInfo.RectInfo.Add(e); } // Add code to optionally not split texture files and save a metadata file instead if (!splitImages) { Serialize <TexInfo>(texInfo, Path.Combine(outputPath, "_metadata.xml")); } } var formatMetadata = new FormatMetadata(); foreach (var entry in entries) { reader.BaseStream.Seek(entry.DataOffset, SeekOrigin.Begin); var data = Decompress(reader); if (Encoding.ASCII.GetString(data, 0, 4) == "TXDT" || Encoding.ASCII.GetString(data, 0, 4) == "TDXT") { var rectInfoList = texInfo.RectInfo.Where(x => String.CompareOrdinal(Path.GetFileNameWithoutExtension(entry.Filename), x.ExternalFilename) == 0).ToList(); if (!splitImages) { rectInfoList.Clear(); } if (rectInfoList.Count == 0) { var rectInfo = new RectInfo { ExternalFilename = entry.Filename, Filename = entry.Filename, X = 0, Y = 0, W = 0, H = 0 }; rectInfoList.Add(rectInfo); } if (!splitImages) { formatMetadata.FormatInfo.Add(new FormatInfo { Filename = entry.Filename, FormatType = data[0x2c] }); } foreach (var rectInfo in rectInfoList) { try { using (var stream = new MemoryStream(data)) { using (var dataReader = new BinaryReader(stream)) { byte[] extractedData; if (!splitImages || rectInfoList.Count == 0 || rectInfo.W == 0 || rectInfo.H == 0) { extractedData = gitadora_textool.Program.ExtractImageCore(dataReader, null); } else { extractedData = gitadora_textool.Program.ExtractImageCore(dataReader, rectInfo); } var ext = ".png"; if (extractedData[0] == 'D' && extractedData[1] == 'D' && extractedData[2] == 'S' && extractedData[3] == ' ') { ext = ".dds"; } var outputFilename = Path.Combine(outputPath, rectInfo.Filename); outputFilename += ext; Console.WriteLine("Saving {0}...", outputFilename); File.WriteAllBytes(outputFilename, extractedData); // File.WriteAllBytes(outputFilename.Replace(ext, ".bin"), data); if (splitImages) { formatMetadata.FormatInfo.Add(new FormatInfo { Filename = rectInfo.Filename, FormatType = data[0x2c] }); } } } } catch (Exception e) { Console.WriteLine("Couldn't convert image: {0}", e.Message); File.WriteAllBytes(Path.Combine(outputPath, entry.Filename), data); } } } } Serialize <FormatMetadata>(formatMetadata, Path.Combine(outputPath, "_metadata-format.xml")); } }