static List <endFiles> collectFonts(string input_folder) { bread.BaseStream.Position = FONT_offset; List <uint> entries = collect_entries(true); List <endFiles> filesToCreate = new List <endFiles>(); for (int i = 0; i < entries.Count - 1; i++) { uint offset = entries[i]; bread.BaseStream.Position = offset; endFiles f1 = new endFiles(); string font_name = getSTRGEntry(bread.ReadUInt32()); string font_family = getSTRGEntry(bread.ReadUInt32()); f1.name = "" + i + "_" + font_name + " (" + font_family + ")"; f1.offset = offset; f1.size = calculateFontSize(offset); filesToCreate.Add(f1); } return(filesToCreate); }
public static void Unpack(string winFile, string destFolder) { string output_win = winFile; input_folder = destFolder; if (input_folder[input_folder.Length - 1] != '\\') { input_folder += '\\'; } uint full_size = (uint)new FileInfo(output_win).Length; bread = new BinaryReader(File.Open(output_win, FileMode.Open)); Directory.CreateDirectory(input_folder + "CHUNK"); uint chunk_offset = 0; while (chunk_offset < full_size) { string chunk_name = new String(bread.ReadChars(4)); uint chunk_size = bread.ReadUInt32(); chunk_offset = (uint)bread.BaseStream.Position; chunk_limit = chunk_offset + chunk_size; System.Console.WriteLine("Chunk " + chunk_name + " offset:" + chunk_offset + " size:" + chunk_size); List <endFiles> filesToCreate = new List <endFiles>(); if (chunk_name == "FORM") { full_size = chunk_limit; chunk_size = 0; } else if (chunk_name == "TPAG") { //StreamWriter tpag = new StreamWriter(input_folder + "TPAG.txt", false, System.Text.Encoding.ASCII); //uint sprite_count = bread.ReadUInt32(); //bread.BaseStream.Position += sprite_count * 4;//Skip offsets //for (uint i = 0; i < sprite_count; i++) //{ // tpag.Write(bread.ReadInt16());//x // tpag.Write(";"); // tpag.Write(bread.ReadInt16());//y // tpag.Write(";"); // tpag.Write(bread.ReadInt16());//w1 // tpag.Write(";"); // tpag.Write(bread.ReadInt16());//h1 // tpag.Write(";"); // tpag.Write(bread.ReadInt16());//? // tpag.Write(";"); // tpag.Write(bread.ReadInt16());//? // tpag.Write(";"); // tpag.Write(bread.ReadInt16());//w2 // tpag.Write(";"); // tpag.Write(bread.ReadInt16());//h2 // tpag.Write(";"); // tpag.Write(bread.ReadInt16());//w3 // tpag.Write(";"); // tpag.Write(bread.ReadInt16());//h3 // tpag.Write(";"); // tpag.Write(bread.ReadInt16());//txtr id // tpag.Write((char)0x0D); // tpag.Write((char)0x0A); //} //bread.BaseStream.Position = chunk_offset; } else if (chunk_name == "STRG") { STRG_offset = (uint)bread.BaseStream.Position; bwrite = new BinaryWriter(File.Open(input_folder + "STRG.txt", FileMode.Create)); uint strings = bread.ReadUInt32(); bread.BaseStream.Position += strings * 4;//Skip offsets for (uint i = 0; i < strings; i++) { uint string_size = bread.ReadUInt32() + 1; for (uint j = 0; j < string_size; j++) { bwrite.Write(bread.ReadByte()); } bwrite.BaseStream.Position--; bwrite.Write((byte)0x0D); bwrite.Write((byte)0x0A); } bwrite.Close(); long bacp = bread.BaseStream.Position; recordFiles(collectFonts(input_folder), "FONT"); bread.BaseStream.Position = bacp; bwrite.Close(); filesToCreate.Clear(); } else if (chunk_name == "TXTR") { List <uint> entries = collect_entries(false); for (int i = 0; i < entries.Count - 1; i++) { uint offset = entries[i]; bread.BaseStream.Position = offset + 4; offset = bread.ReadUInt32(); entries[i] = offset; } filesToCreate = new List <endFiles>(); for (int i = 0; i < entries.Count - 1; i++) { uint offset = entries[i]; uint next_offset = entries[i + 1]; uint size = next_offset - offset; endFiles f1 = new endFiles(); f1.name = "" + i + ".png"; f1.offset = offset; f1.size = size; filesToCreate.Add(f1); } } else if (chunk_name == "AUDO") { List <uint> entries = collect_entries(false); filesToCreate = new List <endFiles>(); for (int i = 0; i < entries.Count - 1; i++) { uint offset = entries[i]; bread.BaseStream.Position = offset; uint size = bread.ReadUInt32(); offset = (uint)bread.BaseStream.Position; endFiles f1 = new endFiles(); f1.name = "" + i + ".wav"; f1.offset = offset; f1.size = size; filesToCreate.Add(f1); } } else if (chunk_name == "FONT") { FONT_offset = (uint)bread.BaseStream.Position; FONT_limit = chunk_limit; } if (chunk_name != "FORM") { if (filesToCreate.Count == 0) { string name = "CHUNK//" + chunk_name + ".chunk"; uint bu = (uint)bread.BaseStream.Position; bread.BaseStream.Position = chunk_offset; bwrite = new BinaryWriter(File.Open(input_folder + name, FileMode.Create)); for (uint i = 0; i < chunk_size; i++) { bwrite.Write(bread.ReadByte()); } bread.BaseStream.Position = bu; bwrite.Close(); } else { recordFiles(filesToCreate, chunk_name); if (chunk_name == "TXTR") { collectFontImages(); } } } chunk_offset += chunk_size; bread.BaseStream.Position = chunk_offset; } var translateFile = File.Open(input_folder + "translate.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite); translateFile.Close(); Directory.CreateDirectory(input_folder + "patch"); var patchFile = File.Open(input_folder + "patch\\patch.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite); bread.Close(); patchFile.Close(); }
static void Main(string[] args) { if (args.Length < 2) { System.Console.WriteLine("Usage: winextract <output .win file> <input folder>"); return; } string output_win = args[0]; input_folder = args[1]; if (input_folder[input_folder.Length - 1] != '\\') { input_folder += '\\'; } for (int i = 0; i < args.Length; i++) { if (args[i] == "-tt") { translatale = true; } if (args[i] == "-showstringsextract") { showstringsextract = true; } if (args[i] == "-correctTXTR") { correctTXTR = true; } if (args[i] == "-unpackAUDO") { unpackAUDO = true; } } translatale = true; strgWithBr = false; uint full_size = (uint)new FileInfo(output_win).Length; bread = new BinaryReader(File.Open(output_win, FileMode.Open)); Directory.CreateDirectory(input_folder + "CHUNK"); Directory.CreateDirectory(input_folder + "FONT"); uint chunk_offset = 0; while (chunk_offset < full_size) { string chunk_name = new String(bread.ReadChars(4)); uint chunk_size = bread.ReadUInt32(); chunk_offset = (uint)bread.BaseStream.Position; chunk_limit = chunk_offset + chunk_size; System.Console.WriteLine("Chunk " + chunk_name + " offset:" + chunk_offset + " size:" + chunk_size); List <endFiles> filesToCreate = new List <endFiles>(); if (chunk_name == "FORM") { full_size = chunk_limit; chunk_size = 0; } else if (chunk_name == "SPRT") { StreamWriter tpag = new StreamWriter(input_folder + "SPRT.txt", false, System.Text.Encoding.ASCII); uint sprite_count = bread.ReadUInt32(); long sprtoffset = bread.BaseStream.Position; uint i = 0; for (; i < sprite_count; sprtoffset += 4, i++) { bread.BaseStream.Position = sprtoffset; long sprt = bread.ReadUInt32(); bread.BaseStream.Position = sprt; string what = getSTRGEntry(bread.ReadUInt32()); bread.BaseStream.Position += 0x48; // 右のページの「Sprite」の項を見ると、「sprite name」の終わりから「number of sub-sprites」まで72なので、0x48 bytesスキップに変更 https://github.com/panzi/cook-serve-hoomans2/blob/master/fileformat.md //TPAG uint spritec = bread.ReadUInt32(); for (int k = 0; k < spritec; k++) { tpag.Write(what + "(" + k + ")");//Sprite name tpag.Write(";"); long backup = bread.BaseStream.Position; sprt = bread.ReadUInt32(); bread.BaseStream.Position = sprt; tpag.Write(bread.ReadInt16()); //x tpag.Write(";"); tpag.Write(bread.ReadInt16()); //y tpag.Write(";"); tpag.Write(bread.ReadInt16()); //w1 tpag.Write(";"); tpag.Write(bread.ReadInt16()); //h1 tpag.Write(";"); bread.BaseStream.Position += 12; tpag.Write(bread.ReadInt16());//txtr id tpag.Write((char)0x0D); tpag.Write((char)0x0A); bread.BaseStream.Position = backup; bread.BaseStream.Position += 4; } } tpag.Close(); bread.BaseStream.Position = chunk_limit; } else if (chunk_name == "STRG") { STRG_offset = (uint)bread.BaseStream.Position; recordStrgList();//Beta! into txt (for Undertale) long bacp = bread.BaseStream.Position; recordFiles(collectFonts(input_folder), "FONT"); bread.BaseStream.Position = bacp; filesToCreate.Clear(); } else if (chunk_name == "TXTR") { List <uint> entries = collect_entries(false, correctTXTR); if (!correctTXTR) { for (int i = 0; i < entries.Count - 1; i++) { ulong offset = entries[i]; bread.BaseStream.Position = (long)(offset + 8); // 右ページによると、FileInfosのサイズが8になっているため https://github.com/panzi/cook-serve-hoomans2/blob/master/fileformat.md offset = bread.ReadUInt64(); // 右ページによると、FileInfosのサイズが8になっているため https://github.com/panzi/cook-serve-hoomans2/blob/master/fileformat.md entries[i] = (uint)offset; } } filesToCreate = new List <endFiles>(); for (int i = 0; i < entries.Count - 1; i++) { uint offset = entries[i]; uint next_offset = entries[i + 1]; uint size = next_offset - offset; endFiles f1 = new endFiles(); f1.name = "" + i + ".png"; f1.offset = offset; f1.size = size; filesToCreate.Add(f1); } } else if (chunk_name == "AUDO" && unpackAUDO == true) { List <uint> entries = collect_entries(false); filesToCreate = new List <endFiles>(); for (int i = 0; i < entries.Count - 1; i++) { uint offset = entries[i]; bread.BaseStream.Position = offset; uint size = bread.ReadUInt32(); offset = (uint)bread.BaseStream.Position; endFiles f1 = new endFiles(); f1.name = "" + i + ".wav"; f1.offset = offset; f1.size = size; filesToCreate.Add(f1); } } else if (chunk_name == "FONT") { FONT_offset = (uint)bread.BaseStream.Position; FONT_limit = chunk_limit; } if (chunk_name != "FORM") { if (filesToCreate.Count == 0) { string name = "CHUNK//" + chunk_name + ".chunk"; uint bu = (uint)bread.BaseStream.Position; bread.BaseStream.Position = chunk_offset; bwrite = new BinaryWriter(File.Open(input_folder + name, FileMode.Create)); for (uint i = 0; i < chunk_size; i++) { bwrite.Write(bread.ReadByte()); } bwrite.Close(); bread.BaseStream.Position = bu; if (chunk_name == "CODE") { var md5 = System.Security.Cryptography.MD5.Create(); var stream = File.OpenRead(input_folder + name); byte[] hashByte = md5.ComputeHash(stream); StringBuilder sBuilder = new StringBuilder(); for (int i = 0; i < hashByte.Length; i++) { sBuilder.Append(hashByte[i].ToString("x2")); } string hashString = sBuilder.ToString(); } } else { recordFiles(filesToCreate, chunk_name); if (chunk_name == "TXTR") { collectFontImages(); } } } chunk_offset += chunk_size; bread.BaseStream.Position = chunk_offset; } if (translatale) { string ext = strgWithBr ? "strg" : "txt"; if (!File.Exists(input_folder + "translate." + ext)) { //File.Copy(input_folder + "original."+ext, input_folder + "translate."+ext); } } else { File.Open(input_folder + "translate.txt", FileMode.OpenOrCreate); } Directory.CreateDirectory(input_folder + "FONT_new"); File.Open(input_folder + "FONT_new\\patch.txt", FileMode.OpenOrCreate); Console.Write("Done! Press any key to exit."); Console.ReadKey(); }
static void Main(string[] args) { if (args.Length < 2) { System.Console.WriteLine("Usage: winextract <output .win file> <input folder>"); return; } string output_win = args[0]; input_folder = args[1]; if (input_folder[input_folder.Length - 1] != '\\') { input_folder += '\\'; } for (int i = 0; i < args.Length; i++) { if (args[i] == "-tt") { translatale = true; } if (args[i] == "-showstringsextract") { showstringsextract = true; } if (args[i] == "-correctTXTR") { correctTXTR = true; } } translatale = true; strgWithBr = false; uint full_size = (uint)new FileInfo(output_win).Length; bread = new BinaryReader(File.Open(output_win, FileMode.Open)); Directory.CreateDirectory(input_folder + "CHUNK"); Directory.CreateDirectory(input_folder + "FONT"); uint chunk_offset = 0; while (chunk_offset < full_size) { string chunk_name = new String(bread.ReadChars(4)); uint chunk_size = bread.ReadUInt32(); chunk_offset = (uint)bread.BaseStream.Position; chunk_limit = chunk_offset + chunk_size; System.Console.WriteLine("Chunk " + chunk_name + " offset:" + chunk_offset + " size:" + chunk_size); List <endFiles> filesToCreate = new List <endFiles>(); if (chunk_name == "FORM") { full_size = chunk_limit; chunk_size = 0; } else if (chunk_name == "TPAG") { //StreamWriter tpag = new StreamWriter(input_folder + "TPAG.txt", false, System.Text.Encoding.ASCII); //uint sprite_count = bread.ReadUInt32(); //bread.BaseStream.Position += sprite_count * 4;//Skip offsets //for (uint i = 0; i < sprite_count; i++) //{ // tpag.Write(bread.ReadInt16());//x // tpag.Write(";"); // tpag.Write(bread.ReadInt16());//y // tpag.Write(";"); // tpag.Write(bread.ReadInt16());//w1 // tpag.Write(";"); // tpag.Write(bread.ReadInt16());//h1 // tpag.Write(";"); // tpag.Write(bread.ReadInt16());//? // tpag.Write(";"); // tpag.Write(bread.ReadInt16());//? // tpag.Write(";"); // tpag.Write(bread.ReadInt16());//w2 // tpag.Write(";"); // tpag.Write(bread.ReadInt16());//h2 // tpag.Write(";"); // tpag.Write(bread.ReadInt16());//w3 // tpag.Write(";"); // tpag.Write(bread.ReadInt16());//h3 // tpag.Write(";"); // tpag.Write(bread.ReadInt16());//txtr id // tpag.Write((char)0x0D); // tpag.Write((char)0x0A); //} //bread.BaseStream.Position = chunk_offset; } else if (chunk_name == "STRG") { STRG_offset = (uint)bread.BaseStream.Position; recordStrgList();//Beta! into txt (for Undertale) long bacp = bread.BaseStream.Position; recordFiles(collectFonts(input_folder), "FONT"); bread.BaseStream.Position = bacp; filesToCreate.Clear(); } else if (chunk_name == "TXTR") { List <uint> entries = collect_entries(false, correctTXTR); if (!correctTXTR) { for (int i = 0; i < entries.Count - 1; i++) { uint offset = entries[i]; bread.BaseStream.Position = offset + 4; offset = bread.ReadUInt32(); entries[i] = offset; } } filesToCreate = new List <endFiles>(); for (int i = 0; i < entries.Count - 1; i++) { uint offset = entries[i]; uint next_offset = entries[i + 1]; uint size = next_offset - offset; endFiles f1 = new endFiles(); f1.name = "" + i + ".png"; f1.offset = offset; f1.size = size; filesToCreate.Add(f1); } } else if (chunk_name == "AUDO") { List <uint> entries = collect_entries(false); filesToCreate = new List <endFiles>(); for (int i = 0; i < entries.Count - 1; i++) { uint offset = entries[i]; bread.BaseStream.Position = offset; uint size = bread.ReadUInt32(); offset = (uint)bread.BaseStream.Position; endFiles f1 = new endFiles(); f1.name = "" + i + ".wav"; f1.offset = offset; f1.size = size; filesToCreate.Add(f1); } } else if (chunk_name == "FONT") { FONT_offset = (uint)bread.BaseStream.Position; FONT_limit = chunk_limit; } if (chunk_name != "FORM") { if (filesToCreate.Count == 0) { string name = "CHUNK//" + chunk_name + ".chunk"; uint bu = (uint)bread.BaseStream.Position; bread.BaseStream.Position = chunk_offset; bwrite = new BinaryWriter(File.Open(input_folder + name, FileMode.Create)); for (uint i = 0; i < chunk_size; i++) { bwrite.Write(bread.ReadByte()); } bwrite.Close(); bread.BaseStream.Position = bu; if (chunk_name == "CODE") { var md5 = System.Security.Cryptography.MD5.Create(); var stream = File.OpenRead(input_folder + name); byte[] hashByte = md5.ComputeHash(stream); StringBuilder sBuilder = new StringBuilder(); for (int i = 0; i < hashByte.Length; i++) { sBuilder.Append(hashByte[i].ToString("x2")); } string hashString = sBuilder.ToString(); if (hashString == "ff44e9b4b88209202af1b73d7b187d5f") { undertaleVer = 101; } else if (hashString == "00fc3b1363cd51f7bfc81e6c082d2d14") { undertaleVer = 106; } else if (hashString == "76de1a6b4b75786b54f7d69177eb1e3e") { undertaleVer = 108; } if (undertaleVer != 0) { System.Console.WriteLine("Undertale v. " + undertaleVer); } else { System.Console.WriteLine("Unknown Undertale ver. Hash " + hashString); } } } else { recordFiles(filesToCreate, chunk_name); if (chunk_name == "TXTR") { collectFontImages(); } } } chunk_offset += chunk_size; bread.BaseStream.Position = chunk_offset; } if (translatale) { string ext = strgWithBr ? "strg" : "txt"; if (!File.Exists(input_folder + "translate." + ext)) { //File.Copy(input_folder + "original."+ext, input_folder + "translate."+ext); } } else { File.Open(input_folder + "translate.txt", FileMode.OpenOrCreate); } Directory.CreateDirectory(input_folder + "FONT_new"); File.Open(input_folder + "FONT_new\\patch.txt", FileMode.OpenOrCreate); //Console.Write("Done! Press any key to exit."); //Console.ReadKey(); }
static void Main(string[] args) { string output_bars = ""; if (args.Length == 1) { output_bars = args[0]; } else { System.Console.WriteLine("Usage: bars_extract <output .bars file>"); return; } FileInfo fi = new FileInfo(output_bars); string input_folder = fi.DirectoryName + "\\" + fi.Name + "_extracted\\"; uint full_size = (uint)fi.Length; bread = new BinaryReader(File.Open(output_bars, FileMode.Open)); Directory.CreateDirectory(input_folder); //first 4 bytes form the word BARS(42 41 52 53) string bars = new string(bread.ReadChars(4)); if (bars != "BARS") { System.Console.WriteLine("Not a valid .bars file"); return; } //starting byte 0x4 is the lenght of the file, 4 bytes long. maximum file size would be 16777215 bytes. uint file_size = readInt32be(bread); //next 4 bytes seem to be always the same(FE FF 01 01). bread.ReadChars(4); List <uint> entries = collect_entries(); //after that starts the data itself. List <endFiles> filesToCreate = new List <endFiles>(); for (int i = 0; i < entries.Count; i++) { string file_name = ""; if (i < entries.Count / 2) { bread.BaseStream.Position = entries[i]; //AMTA bread.ReadChars(4); //24 unknown bytes bread.ReadChars(24); //DATA string chunk_name = new string(bread.ReadChars(4)); uint chunk_size = readInt32be(bread); bread.BaseStream.Position += chunk_size; //MARK chunk_name = new string(bread.ReadChars(4)); chunk_size = readInt32be(bread); bread.BaseStream.Position += chunk_size; //EXT_ chunk_name = new string(bread.ReadChars(4)); chunk_size = readInt32be(bread); bread.BaseStream.Position += chunk_size; //STRG //byte 0xA7 of the header contains the lenght of the file name. chunk_name = new string(bread.ReadChars(4)); chunk_size = readInt32be(bread); byte[] bytes = new byte[chunk_size - 1]; for (uint j = 0; j < chunk_size - 1; j++) { bytes[j] = bread.ReadByte(); } file_name = System.Text.Encoding.UTF8.GetString(bytes) + ".bfwav"; endFiles f1 = new endFiles(); f1.name = file_name; f1.offset = entries[i + entries.Count / 2]; filesToCreate.Add(f1); } else { //if the.bars doesn't have bfwav's inside then that second value is null(FF FF FF FF). if (entries[i] == 0xffffffff) { continue; } bread.BaseStream.Position = entries[i]; bwrite = new BinaryWriter(File.Open(input_folder + filesToCreate[i - entries.Count / 2].name, FileMode.Create)); bread.ReadBytes(4); //FWAV bread.ReadBytes(2); //Byte order (feff) bread.ReadBytes(2); //Header size(0040) bread.ReadBytes(4); //Unknown uint fwav_size = readInt32be(bread); bread.BaseStream.Position -= 16; for (uint ik = 0; ik < fwav_size; ik++) { bwrite.Write(bread.ReadByte()); } } } }