static fontInfo recordNewFont(fontInfo font) { font.font_offset = (uint)bwrite.BaseStream.Position; bwrite.Write(font.filename_offset); bwrite.Write(font.fontname_offset); bwrite.Write(Convert.ToUInt32(font.data.Element("font").Element("size").Value)); bwrite.Write(font.data.Element("font").Element("bold").Value == "0" ? (uint)0 : (uint)1); bwrite.Write(font.data.Element("font").Element("italic").Value == "0" ? (uint)0 : (uint)1); string[] range0 = font.data.Element("font").Element("ranges").Element("range0").Value.Split(','); bwrite.Write(Convert.ToUInt16(range0[0])); bwrite.Write((ushort)1); //? bwrite.Write(Convert.ToUInt16(range0[1])); bwrite.Write((ushort)0); //? font.image_offset = (uint)bwrite.BaseStream.Position; bwrite.Write((uint)0); //sprite bwrite.Write((uint)0x3F800000); //? bwrite.Write((uint)0x3F800000); //? IEnumerable <XElement> glyphs = font.data.Element("font").Element("glyphs").Elements("glyph"); uint glyphCount = 0; foreach (XElement glyph in glyphs) { glyphCount++; } font.glyph_count = glyphCount; uint[] Offsets = new uint[glyphCount]; bwrite.Write(glyphCount); for (int g = 0; g < glyphCount; g++) { Offsets[g] = (uint)bwrite.BaseStream.Position; bwrite.Write((uint)0); } int f0 = 0; foreach (XElement glyph in glyphs) { uint file_off = (uint)bwrite.BaseStream.Position; bwrite.BaseStream.Position = Offsets[f0]; bwrite.Write(file_off); bwrite.BaseStream.Position = file_off; bwrite.Write(Convert.ToUInt16(glyph.Attribute("character").Value)); bwrite.Write(Convert.ToUInt16(glyph.Attribute("x").Value)); bwrite.Write(Convert.ToUInt16(glyph.Attribute("y").Value)); bwrite.Write(Convert.ToUInt16(glyph.Attribute("w").Value)); bwrite.Write(Convert.ToUInt16(glyph.Attribute("h").Value)); bwrite.Write(Convert.ToUInt16(glyph.Attribute("shift").Value)); bwrite.Write(Convert.ToInt16(glyph.Attribute("offset").Value));//sic! bwrite.Write((ushort)0); f0++; } return(font); }
static void Main(string[] args) { if (args.Length < 2) { System.Console.WriteLine("Usage: winpack <output folder> <input .win file>"); return; } string output_folder = args[0]; if (output_folder[output_folder.Length - 1] != '\\') { output_folder += '\\'; } string input_win = args[1]; for (int i = 0; i < args.Length; i++) { if (args[i] == "-tt") { translatale = true; } if (args[i] == "-correctTXTR") { correctTXTR = true; } } translatale = true; strgWithBr = false; bool useTXTR = Directory.Exists(output_folder + "TXTR"); form_size = 0; string patch_path0 = output_folder + "FONT_new\\"; if (File.Exists(patch_path0 + "patch.txt")) { string[] patchLines = File.ReadAllLines(patch_path0 + "patch.txt", System.Text.Encoding.UTF8); for (int l = 0; l < patchLines.Length; l++) { if (patchLines[l].IndexOf("//") == 0) { continue; } string[] par = patchLines[l].Split(';'); fontInfo newFont = new fontInfo(); newFont.id = Convert.ToInt32(par[0]); newFont.filename = par[1].Substring(0, par[1].Length - ".gmx".Length); newFont.data = XDocument.Load(patch_path0 + par[1]); newFonts.Add(newFont); } } TXTR_count = useTXTR ? (ushort)Directory.GetFiles(output_folder + "TXTR").Length : (ushort)0; bwrite = new BinaryWriter(File.Open(input_win, FileMode.Create)); bwrite.Write(System.Text.Encoding.ASCII.GetBytes("FORM")); bwrite.Write(form_size); for (int i = 0; i < chunks.Length; i++) { string chunk_name = chunks[i]; if (!File.Exists(output_folder + "CHUNK\\" + chunk_name + ".chunk")) { if (!(chunk_name == "AUDO" || (chunk_name == "TXTR" && useTXTR))) { continue; } } uint chunk_size = 0; bwrite.Write(System.Text.Encoding.ASCII.GetBytes(chunk_name)); uint chunk_offset = (uint)bwrite.BaseStream.Position; bwrite.Write(chunk_size); form_size += 8; if (chunk_name == "STRG") { string ext = strgWithBr ? "strg" : "txt"; List <string> strg = createStrgList(output_folder + "original." + ext); //string[] strg = File.ReadAllLines(output_folder + "original.strg", System.Text.Encoding.UTF8); uint lines = (uint)strg.Count; if (strg[(int)(lines - 1)].Length == 0) { lines--; } bwrite.Write(lines); chunk_size += 4; uint[] Offsets = new uint[lines]; //Lines offsets for (int f = 0; f < lines; f++) { Offsets[f] = (uint)bwrite.BaseStream.Position; bwrite.Write((uint)0); chunk_size += 4; } //Lines (line size + line + 0) for (int f = 0; f < lines; f++) { uint line_off = (uint)bwrite.BaseStream.Position; bwrite.BaseStream.Position = Offsets[f]; bwrite.Write(line_off); bwrite.BaseStream.Position = line_off; string oneLine = strg[f]; uint lineLen = (uint)oneLine.Length; bwrite.Write(lineLen); chunk_size += 4; for (int j = 0; j < lineLen; j++) { bwrite.Write(oneLine[j]); } chunk_size += (uint)System.Text.Encoding.UTF8.GetByteCount(oneLine); bwrite.Write((byte)0); chunk_size += 1; } //Edited lines if (File.Exists(output_folder + "translate." + ext)) { List <string> patch = createStrgList(output_folder + "translate." + ext); //string[] patch = File.ReadAllLines(output_folder + "translate.strg", System.Text.Encoding.UTF8); lines = (uint)patch.Count; if (lines != strg.Count) { System.Console.WriteLine("Warning: original." + ext + " has " + strg.Count + " lines, translate." + ext + " has " + lines + " lines"); } if (lines > 0 && patch[(int)(lines - 1)].Length == 0) { lines--; } if (translatale) { for (int f = 0; f < lines; f++) { string oneLine = patch[f]; if (strg[f] == oneLine) { continue; } uint lineN = (uint)(f + 1); uint line_offset = chunk_offset + (lineN + 1) * 4; uint line_off = (uint)bwrite.BaseStream.Position; bwrite.BaseStream.Position = line_offset; bwrite.Write(line_off); bwrite.BaseStream.Position = line_off; uint lineLen = (uint)oneLine.Length; bwrite.Write(lineLen); chunk_size += 4; for (int j = 0; j < lineLen; j++) { bwrite.Write(oneLine[j]); } chunk_size += (uint)System.Text.Encoding.UTF8.GetByteCount(oneLine); bwrite.Write((byte)0); chunk_size += 1; } } else { bool patchNumber = true; for (int f = 0; f < lines; f++) { string oneLine = patch[f]; if (oneLine.IndexOf("//") == 0) { continue; } if (patchNumber) { uint lineN = System.Convert.ToUInt32(oneLine); uint line_offset = chunk_offset + (lineN + 1) * 4; uint line_off = (uint)bwrite.BaseStream.Position; bwrite.BaseStream.Position = line_offset; bwrite.Write(line_off); bwrite.BaseStream.Position = line_off; } else { uint lineLen = (uint)oneLine.Length; bwrite.Write(lineLen); chunk_size += 4; for (int j = 0; j < lineLen; j++) { bwrite.Write(oneLine[j]); } chunk_size += (uint)System.Text.Encoding.UTF8.GetByteCount(oneLine); bwrite.Write((byte)0); chunk_size += 1; } patchNumber = !patchNumber; } } } else { System.Console.WriteLine("translate.txt not found. Strings will not be modified."); } //Font strings for (int f0 = 0; f0 < newFonts.Count; f0++) { fontInfo fi = newFonts[f0]; string font_name = fi.filename; uint lineLen = (uint)font_name.Length; bwrite.Write(lineLen); chunk_size += 4; fi.filename_offset = (uint)bwrite.BaseStream.Position; for (int j = 0; j < lineLen; j++) { bwrite.Write(font_name[j]); } chunk_size += (uint)System.Text.Encoding.UTF8.GetByteCount(font_name); bwrite.Write((byte)0); chunk_size += 1; font_name = fi.data.Element("font").Element("name").Value; lineLen = (uint)font_name.Length; bwrite.Write(lineLen); chunk_size += 4; fi.fontname_offset = (uint)bwrite.BaseStream.Position; for (int j = 0; j < lineLen; j++) { bwrite.Write(font_name[j]); } chunk_size += (uint)System.Text.Encoding.UTF8.GetByteCount(font_name); bwrite.Write((byte)0); chunk_size += 1; newFonts[f0] = fi; } //Fonts for (ushort f0 = 0; f0 < newFonts.Count; f0++) { fontInfo fi = newFonts[f0]; string font_name = fi.filename; uint lineLen = (uint)font_name.Length; bwrite.Write(lineLen); chunk_size += 4; fi.filename_offset = (uint)bwrite.BaseStream.Position; for (int j = 0; j < lineLen; j++) { bwrite.Write(font_name[j]); } chunk_size += (uint)System.Text.Encoding.UTF8.GetByteCount(font_name); bwrite.Write((byte)0); chunk_size += 1; font_name = fi.data.Element("font").Element("name").Value; lineLen = (uint)font_name.Length; bwrite.Write(lineLen); chunk_size += 4; fi.fontname_offset = (uint)bwrite.BaseStream.Position; for (int j = 0; j < lineLen; j++) { bwrite.Write(font_name[j]); } chunk_size += (uint)System.Text.Encoding.UTF8.GetByteCount(font_name); bwrite.Write((byte)0); chunk_size += 1; newFonts[f0] = fi; } //Fonts for (ushort f0 = 0; f0 < newFonts.Count; f0++) { fontInfo fi = newFonts[f0]; uint bacp = (uint)bwrite.BaseStream.Position; bwrite.BaseStream.Position = FONT_offset + 4 * (fi.id + 1);//!!! bwrite.Write(bacp); bwrite.BaseStream.Position = bacp; fi = recordNewFont(fi); chunk_size += calculateFontSize(fi.glyph_count); newFonts[f0] = fi; } //Sprites for (ushort f0 = 0; f0 < newFonts.Count; f0++) { fontInfo fi = newFonts[f0]; long bacp = bwrite.BaseStream.Position; bwrite.BaseStream.Position = fi.image_offset;//!!! bwrite.Write((uint)bacp); bwrite.BaseStream.Position = bacp; ushort w = 0; ushort h = 0; string imagePath = output_folder + "FONT_new\\" + fi.data.Element("font").Element("image").Value; using (FileStream stream = new FileStream(imagePath, FileMode.Open, FileAccess.Read)) { Image texture = Image.FromStream(stream); w = (ushort)texture.Width; h = (ushort)texture.Height; } ushort x = 0; ushort y = 0; ushort s = (ushort)(TXTR_count + f0 + 1);//??? editSprite((uint)bwrite.BaseStream.Position, x, y, w, h, s); bwrite.BaseStream.Position += 22; chunk_size += 22; } bwrite.Write((uint)0); chunk_size += 4; //Unknown purpose zeros //for (int f=0; f<79; f++) //{ // bwrite.Write((byte)0); chunk_size += 1; //} } else if (chunk_name == "TXTR") { uint files = TXTR_count; bwrite.Write((uint)(files + newFonts.Count)); chunk_size += 4; uint[] Offsets = new uint[files + newFonts.Count]; //Headers offset for (int f = 0; f < files; f++) { Offsets[f] = (uint)bwrite.BaseStream.Position; bwrite.Write((uint)0); chunk_size += 4; } for (int f = 0; f < newFonts.Count; f++) { Offsets[f + files] = (uint)bwrite.BaseStream.Position; bwrite.Write((uint)0); chunk_size += 4; } //Headers for (int f = 0; f < files; f++) { uint header_off = (uint)bwrite.BaseStream.Position; bwrite.BaseStream.Position = Offsets[f]; bwrite.Write(header_off); bwrite.BaseStream.Position = header_off; if (correctTXTR) { bwrite.Write(0x00000000); bwrite.Write(0xFFFFFFFF); } else { bwrite.Write((uint)1); } Offsets[f] = (uint)bwrite.BaseStream.Position; bwrite.Write((uint)0); chunk_size += 8; if (correctTXTR) { chunk_size += 4; } } for (int f = 0; f < newFonts.Count; f++) { uint header_off = (uint)bwrite.BaseStream.Position; bwrite.BaseStream.Position = Offsets[f + files]; bwrite.Write(header_off); bwrite.BaseStream.Position = header_off; if (correctTXTR) { bwrite.Write(0x00000000); bwrite.Write(0xFFFFFFFF); } else { bwrite.Write((uint)1); } Offsets[f + files] = (uint)bwrite.BaseStream.Position; bwrite.Write((uint)0); chunk_size += 8; if (correctTXTR) { chunk_size += 4; } } //Неизвестно, зачем здесь нули, но игра запускается и без них //Если требуется сравнить оригинальный win со сгенерированным, расскоментируйте строки //for (int f=0; f<13; f++) //{ // bwrite.Write((uint)0); chunk_size += 4; //} //Files for (int f0 = 0; f0 < files; f0++) { uint file_off = (uint)bwrite.BaseStream.Position; bwrite.BaseStream.Position = Offsets[f0]; bwrite.Write(file_off); bwrite.BaseStream.Position = file_off; uint file_size = (uint)new FileInfo(output_folder + chunk_name + "\\" + f0 + ".png").Length; bread = new BinaryReader(File.Open(output_folder + chunk_name + "\\" + f0 + ".png", FileMode.Open)); for (uint j = 0; j < file_size; j++) { bwrite.Write(bread.ReadByte()); } chunk_size += file_size; } for (int f0 = 0; f0 < newFonts.Count; f0++) { uint file_off = (uint)bwrite.BaseStream.Position; bwrite.BaseStream.Position = Offsets[f0 + files]; bwrite.Write(file_off); bwrite.BaseStream.Position = file_off; string imagePath = output_folder + "FONT_new\\" + newFonts[f0].data.Element("font").Element("image").Value; uint file_size = (uint)new FileInfo(imagePath).Length; bread = new BinaryReader(File.Open(imagePath, FileMode.Open)); for (uint j = 0; j < file_size; j++) { bwrite.Write(bread.ReadByte()); } chunk_size += file_size; } } else if (chunk_name == "AUDO") { uint files = (uint)Directory.GetFiles(output_folder + chunk_name).Length; bwrite.Write(files); chunk_size += 4; uint[] Offsets = new uint[files]; //Headers offset for (int f = 0; f < files; f++) { Offsets[f] = (uint)bwrite.BaseStream.Position; bwrite.Write((uint)0); chunk_size += 4; } for (uint f0 = 0; f0 < files; f0++) { uint file_off = (uint)bwrite.BaseStream.Position; bwrite.BaseStream.Position = Offsets[f0]; bwrite.Write(file_off); bwrite.BaseStream.Position = file_off; uint file_size = (uint)new FileInfo(output_folder + chunk_name + "\\" + f0 + ".wav").Length; bwrite.Write(file_size); chunk_size += 4; bread = new BinaryReader(File.Open(output_folder + chunk_name + "\\" + f0 + ".wav", FileMode.Open)); for (uint j = 0; j < file_size; j++) { bwrite.Write(bread.ReadByte()); } chunk_size += file_size; if (f0 == files - 1) { continue; } for (int j = 0; j < file_size % 4; j++) { bwrite.Write((byte)0); chunk_size++; } } } else { string filer = output_folder + "CHUNK\\" + chunk_name + ".chunk"; if (chunk_name == "FONT") { FONT_offset = (uint)bwrite.BaseStream.Position; } chunk_size = (uint)new FileInfo(filer).Length; bread = new BinaryReader(File.Open(filer, FileMode.Open)); for (uint j = 0; j < chunk_size; j++) { bwrite.Write(bread.ReadByte()); } } uint chunk_end = (uint)bwrite.BaseStream.Position; bwrite.BaseStream.Position = chunk_offset; bwrite.Write(chunk_size); bwrite.BaseStream.Position = chunk_end; form_size += chunk_size; System.Console.WriteLine("Chunk " + chunk_name + " offset:" + (chunk_offset - 4) + " size:" + (chunk_size + 8)); } bwrite.BaseStream.Position = 4; bwrite.Write(form_size); //bwrite.BaseStream.Position = 0x725D8C;//Debug mode //bwrite.Write((byte)1); }