diff --git a/toolnfs/NFSLocaleTool.sln b/toolnfs/NFSLocaleTool.sln new file mode 100644 index 0000000..b642f87 --- /dev/null +++ b/toolnfs/NFSLocaleTool.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33213.308 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NFSLocaleTool", "NFSLocaleTool\NFSLocaleTool.csproj", "{721F5EEC-8CF1-4FA1-99A6-88506B5B42C5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {721F5EEC-8CF1-4FA1-99A6-88506B5B42C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {721F5EEC-8CF1-4FA1-99A6-88506B5B42C5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {721F5EEC-8CF1-4FA1-99A6-88506B5B42C5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {721F5EEC-8CF1-4FA1-99A6-88506B5B42C5}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {F1CC37B3-9FBC-4792-A463-66C82EA2C007} + EndGlobalSection +EndGlobal diff --git a/toolnfs/NFSLocaleTool/App.config b/toolnfs/NFSLocaleTool/App.config new file mode 100644 index 0000000..3916e0e --- /dev/null +++ b/toolnfs/NFSLocaleTool/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/toolnfs/NFSLocaleTool/NFSLocale.cs b/toolnfs/NFSLocaleTool/NFSLocale.cs new file mode 100644 index 0000000..1cb623d --- /dev/null +++ b/toolnfs/NFSLocaleTool/NFSLocale.cs @@ -0,0 +1,312 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace NFSLocaleTool +{ + internal class NFSLocale + { + //all offsets without 8 bytes + public uint Signature = 0x039000; + public UInt16[] ArrayToHistogram { get; set; } + public string[] DefArrayFile { get; set; } + public int DefLengthFile { get; set; } + public byte[] DefArrayFromStrings { get; set; } + public UInt16[] ArrayOriginList { get; set; } + public UInt16[] ArrayCharsList { get; set; } + public int FileSize { get; set; } + public int EntriesNum { get; set; } + public int TableOffset { get; set; } + public int DataOffset { get; set; } + public int DataOffSize { get; set; } + public string Type { get; set; } + List Entries { get; set; } + List ToEndFile { get; set; } + public void ExtractText(string outputFile) + { + List text = new List(); + foreach (Entry entry in Entries) + { + text.Add($"{entry.String.Replace("\n", "¬")}"); + } + File.WriteAllLines(outputFile, text.ToArray()); + } + + public void WriteFromText(string textFile, string hgfile, string outputChunk, string idsFile) + { + HistogramReadChars(hgfile); + DefaultListChars(); + + string[] text = File.ReadAllLines(textFile); + string[] ids_ = File.ReadAllLines(idsFile); + if(text.Length != ids_.Length) + { + Console.WriteLine($"Несоответствие кол-ва строк в файле {Path.GetFileName(textFile)} к ID в файле {Path.GetFileName(idsFile)}"); + Console.WriteLine($"{text.Length}/{ids_.Length}"); + return; + } + uint[] ids = new uint[text.Length]; + uint[] offsets = new uint[text.Length]; + for(int i = 0; i < ids_.Length; i++) + { + ids[i] = UInt32.Parse(ids_[i], System.Globalization.NumberStyles.HexNumber); + } + using(BinaryWriter writer = new BinaryWriter(File.Create(outputChunk))) + { + writer.Write(Signature); + writer.Write(0); //skip filesize + writer.Write(text.Length); //listSize + writer.Write(140); //table offset dataOffset + int textStart = (text.Length * 8) + 0x8C;//calculate text offset stringsOffset 8-9 + writer.Write(textStart); + writer.Write(Encoding.UTF8.GetBytes("Default")); + + writer.BaseStream.Position = textStart + 8; // start text + for(int i = 0; i < text.Length; i++) + { + offsets[i] = (uint)((writer.BaseStream.Position - textStart) - 8); + writer.Write(NFSEncoder(text[i].Replace("\"\"", "\""))); + writer.Write(new byte()); //null term + } + writer.BaseStream.Position = 0x94; + for (int i = 0; i < text.Length; i++) + { + writer.Write(ids[i]); + writer.Write(offsets[i]); + } + + writer.BaseStream.Position = 4; + writer.Write((uint)(writer.BaseStream.Length - 8)); + } + } + + public void CreateListChars(string outputfile) + { + byte[] defList = Resource1.charslist; + UInt16[] defListUI = new UInt16[(defList.Length)/2]; + using (BinaryWriter writer = new BinaryWriter(File.Create(outputfile))) + { + for (int i = 0; i < defList.Length; i+=2) + { + ushort _a = (ushort)((defList[i]) | (defList[i + 1]) << 8); + defListUI[i/2] = _a; + writer.Write(defListUI[i/2]); + } + } + } + + public void HistogramWrite(string hgfile, string file, string outputfile) + { + HistogramReadChars(file); + DefaultListChars(); + + int countDefList = File.ReadAllLines(hgfile).Length; + + ArrayCharsList = new UInt16[DataOffSize/2]; + using (BinaryReader charsReader = new BinaryReader(File.OpenRead(hgfile))) + { + int countArrayCharsList = 0; + UInt16 tempInt; + for (int i = 1; i < (countDefList/3); i++) + { + tempInt = charsReader.ReadUInt16(); + if ((tempInt != 10) & (tempInt != 13)) + { + ArrayCharsList[countArrayCharsList] = tempInt; + countArrayCharsList++; + } + } + } + + //256 dataoffsize + UInt16[] arrayRemoveSimilar = new UInt16[DataOffSize/2]; + int countRemove = 0; + for (var i = 0; i < ArrayCharsList.Length; i++) + { + if (ArrayOriginList.Contains(ArrayCharsList[i])) + { + continue; + } + else + { + arrayRemoveSimilar[countRemove] = ArrayCharsList[i]; + countRemove++; + } + } + + ArrayToHistogram = new UInt16[DataOffSize/2]; + int countToHistogram = 0; + countRemove = 0; + UInt16 zero = 0; + for (var i = 0; i < ArrayOriginList.Length; i++) + { + if (ArrayOriginList[i] == zero) + { + if (countRemove < arrayRemoveSimilar.Length) + { + ArrayToHistogram[countToHistogram] = arrayRemoveSimilar[countRemove]; + countToHistogram++; + countRemove++; + } + } + else + { + ArrayToHistogram[countToHistogram] = ArrayOriginList[i]; + countToHistogram++; + } + } + + using (BinaryWriter hwriter = new BinaryWriter(File.Create(outputfile))) + { + hwriter.Write(Signature + 1); + hwriter.Write(DataOffset); + hwriter.Write(DataOffSize); + hwriter.BaseStream.Position = 0x10c; + foreach (UInt16 val in ArrayToHistogram) + { + hwriter.Write(val); + } + var hisEndId = from p in ToEndFile select p.Id; + foreach (UInt16 val in hisEndId) + { + hwriter.Write(val); + } + } + } + + + public void DefaultListChars() + { + string defList = NFSLocaleTool.Resource1.default_list_chunk_number; + DefArrayFile = defList.Split('\n'); + DefLengthFile = DefArrayFile.Length; + + DefArrayFromStrings = new byte[DefLengthFile]; + for (int i = 0; i < DefLengthFile; i++) + { + DefArrayFromStrings[i] = byte.Parse(DefArrayFile[i], System.Globalization.NumberStyles.HexNumber); + } + } + + + public void HistogramReadChars(string file) + { + using (BinaryReader hCharReader = new BinaryReader(File.OpenRead(file))) + { + if (hCharReader.ReadUInt32() != Signature + 1) + throw new Exception("Unknown file"); + DataOffset = hCharReader.ReadInt32(); //270600 + DataOffSize = hCharReader.ReadInt32(); //256 + + hCharReader.BaseStream.Position = 0x10c; + + UInt16 tempOriginListReader; + ArrayOriginList = new UInt16[DataOffSize/2]; + for (int i = 0; i < (DataOffSize/2); i++) + { + tempOriginListReader = hCharReader.ReadUInt16(); + ArrayOriginList[i] = tempOriginListReader; + } + + ToEndFile = new List(); + for (int i = 0; i < (DataOffset - (DataOffSize + 260)) / 2; i++) + { + ToEndFile.Add(new Entry() + { + Id = hCharReader.ReadUInt16() + }); + } + + } + } + + + public void Read(string file, string hgfile) + { + HistogramReadChars(hgfile); + DefaultListChars(); + + using (BinaryReader reader = new BinaryReader(File.OpenRead(file))) + { + if (reader.ReadUInt32() != Signature) + throw new Exception("Unknown file"); + FileSize = reader.ReadInt32(); + EntriesNum = reader.ReadInt32(); + TableOffset = reader.ReadInt32(); + DataOffset = reader.ReadInt32(); + Type = Utils.ReadString(reader, Encoding.UTF8); + + Entries = new List(); + reader.BaseStream.Position = TableOffset + 8; + for(int i = 0; i < EntriesNum; i++) + { + Entries.Add(new Entry() + { + Id = reader.ReadUInt32(), + Offset = reader.ReadInt32() + DataOffset + 8 + }); + } + for(int i = 0; i < EntriesNum; i++) + { + Entry entry = Entries[i]; + reader.BaseStream.Position = entry.Offset; + entry.String = NFSDecoder(Utils.ReadNullTerminatedArray(reader)); + Entries[i] = entry; + } + + File.WriteAllLines(file + ".ids", Entries.Select(i => i.Id.ToString("X8"))); + } + } + + private byte[] NFSEncoder(string text) + { + List result = new List(); + + for(int i = 0; i < text.Length; i++) + { + int index = Array.IndexOf(ArrayOriginList, text[i]); + if (index != -1) + { + result.Add(DefArrayFromStrings[index]); + } + else + { + result.Add((byte)text[i]); + } + + } + return result.ToArray(); + } + + private string NFSDecoder(byte[] data) + { + string result = ""; + + for (int i = 0; i < data.Length; i++) + { + int index = Array.IndexOf(DefArrayFromStrings, data[i]); + if (index != -1) + { + result += (char)ArrayOriginList[index]; + } + else + { + result += (char)data[i]; + } + } + return result; + } + } + + internal class Entry + { + public uint Id { get; set; } + public int Offset { get; set; } + public byte[] StringArray { get; set; } + public string String { get; set; } + } +} diff --git a/toolnfs/NFSLocaleTool/NFSLocale.cs.bak b/toolnfs/NFSLocaleTool/NFSLocale.cs.bak new file mode 100644 index 0000000..4815a0f --- /dev/null +++ b/toolnfs/NFSLocaleTool/NFSLocale.cs.bak @@ -0,0 +1,354 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace NFSLocaleTool +{ + internal class NFSLocale + { + //all offsets without 8 bytes + public uint Signature = 0x039000; + public int FileSize { get; set; } + public int EntriesNum { get; set; } + public int TableOffset { get; set; } + public int DataOffset { get; set; } + public string Type { get; set; } + List Entries { get; set; } + + public void ExtractText(string outputFile) + { + List text = new List(); + foreach (Entry entry in Entries) + { + text.Add($"{entry.String.Replace("\n", "¬")}"); + } + File.WriteAllLines(outputFile, text.ToArray()); + } + + public void WriteFromText(string textFile, string outputChunk, string idsFile) + { + string[] text = File.ReadAllLines(textFile); + string[] ids_ = File.ReadAllLines(idsFile); + if(text.Length != ids_.Length) + { + Console.WriteLine($"Несоответствие кол-ва строк в файле {Path.GetFileName(textFile)} к ID в файле {Path.GetFileName(idsFile)}"); + Console.WriteLine($"{text.Length}/{ids_.Length}"); + return; + } + uint[] ids = new uint[text.Length]; + uint[] offsets = new uint[text.Length]; + for(int i = 0; i < ids_.Length; i++) + { + ids[i] = UInt32.Parse(ids_[i], System.Globalization.NumberStyles.HexNumber); + } + using(BinaryWriter writer = new BinaryWriter(File.Create(outputChunk))) + { + writer.Write(Signature); + writer.Write(0); //skip filesize + writer.Write(text.Length); //listSize + writer.Write(140); //table offset dataOffset + int textStart = (text.Length * 8) + 0x8C;//calculate text offset stringsOffset 8-9 + writer.Write(textStart); + writer.Write(Encoding.UTF8.GetBytes("Default")); + + writer.BaseStream.Position = textStart + 8; // start text + for(int i = 0; i < text.Length; i++) + { + offsets[i] = (uint)((writer.BaseStream.Position - textStart) - 8); + writer.Write(NFSEncoder(text[i].Replace("\"\"", "\""))); + writer.Write(new byte()); //null term + } + writer.BaseStream.Position = 0x94; + for (int i = 0; i < text.Length; i++) + { + writer.Write(ids[i]); + writer.Write(offsets[i]); + } + + writer.BaseStream.Position = 4; + writer.Write((uint)(writer.BaseStream.Length - 8)); + } + } + public void Read(string file) + { + using(BinaryReader reader = new BinaryReader(File.OpenRead(file))) + { + if (reader.ReadUInt32() != Signature) + throw new Exception("Unknown file"); + FileSize = reader.ReadInt32(); + EntriesNum = reader.ReadInt32(); + TableOffset = reader.ReadInt32(); + DataOffset = reader.ReadInt32(); + Type = Utils.ReadString(reader, Encoding.UTF8); + + Entries = new List(); + reader.BaseStream.Position = TableOffset + 8; + for(int i = 0; i < EntriesNum; i++) + { + Entries.Add(new Entry() + { + Id = reader.ReadUInt32(), + Offset = reader.ReadInt32() + DataOffset + 8 + }); + } + for(int i = 0; i < EntriesNum; i++) + { + Entry entry = Entries[i]; + reader.BaseStream.Position = entry.Offset; + entry.String = NFSDecoder(Utils.ReadNullTerminatedArray(reader)); + Entries[i] = entry; + } + + File.WriteAllLines(file + ".ids", Entries.Select(i => i.Id.ToString("X8"))); + } + } + + private byte[] NFSEncoder(string text) + { + List result = new List(); + for(int i = 0; i < text.Length; i++) + { + switch (text[i]) + { + case 'А': result.Add(0xc0); break; + case 'Б': result.Add(0xc2); break; + case 'В': result.Add(0x90); break; + case 'Г': result.Add(0x91); break; + case 'Д': result.Add(0xc3); break; + case 'Е': result.Add(0xc4); break; + case 'Ё': result.Add(0x9c); break; + case 'Ж': result.Add(0xc5); break; + case 'З': result.Add(0xc6); break; + case 'И': result.Add(0xc7); break; + case 'Й': result.Add(0x9e); break; + case 'К': result.Add(0xc9); break; + case 'Л': result.Add(0xca); break; + case 'М': result.Add(0xcb); break; + case 'Н': result.Add(0x92); break; + case 'О': result.Add(0xcc); break; + case 'П': result.Add(0xce); break; + case 'Р': result.Add(0xcf); break; + case 'С': result.Add(0xd0); break; + case 'Т': result.Add(0xd1); break; + case 'У': result.Add(0xd2); break; + case 'Ф': result.Add(0xd3); break; + case 'Х': result.Add(0xd4); break; + case 'Ц': result.Add(0xd5); break; + case 'Ч': result.Add(0xd6); break; + case 'Ш': result.Add(0xd7); break; + case 'Щ': result.Add(0xd8); break; + case 'Ъ': result.Add(0xd9); break; + case 'Ы': result.Add(0xda); break; + case 'Ь': result.Add(0xdb); break; + case 'Э': result.Add(0xdd); break; + case 'Ю': result.Add(0xde); break; + case 'Я': result.Add(0xdf); break; + case 'а': result.Add(0x93); break; + case 'б': result.Add(0xe2); break; + case 'в': result.Add(0x8a); break; + case 'г': result.Add(0xe3); break; + case 'д': result.Add(0x94); break; + case 'е': result.Add(0x8b); break; + case 'ё': result.Add(0x9b); break; + case 'ж': result.Add(0xe4); break; + case 'з': result.Add(0xe5); break; + case 'и': result.Add(0x8c); break; + case 'й': result.Add(0xe6); break; + case 'к': result.Add(0xeb); break; + case 'л': result.Add(0x95); break; + case 'м': result.Add(0xec); break; + case 'н': result.Add(0x96); break; + case 'о': result.Add(0x89); break; + case 'п': result.Add(0x97); break; + case 'р': result.Add(0x8d); break; + case 'с': result.Add(0x98); break; + case 'т': result.Add(0xee); break; + case 'у': result.Add(0xf0); break; + case 'ф': result.Add(0xf2); break; + case 'х': result.Add(0xf4); break; + case 'ц': result.Add(0xf5); break; + case 'ч': result.Add(0xf7); break; + case 'ш': result.Add(0xf8); break; + case 'щ': result.Add(0xf9); break; + case 'ъ': result.Add(0xfb); break; + case 'ы': result.Add(0xfd); break; + case 'ь': result.Add(0xfe); break; + case 'э': result.Add(0xff); break; + case 'ю': result.Add(0xbf); break; + case 'я': result.Add(0xaf); break; + case '’': result.Add(0x81); break; + case '…': result.Add(0x82); break; + case '“': result.Add(0x83); break; + case '”': result.Add(0x84); break; + case '•': result.Add(0x85); break; + case '‘': result.Add(0x86); break; + case '™': result.Add(0x87); break; + case '–': result.Add(0x88); break; + case '—': result.Add(0x8e); break; + case 'ł': result.Add(0x8f); break; + case 'ї': result.Add(0x99); break; + case '': result.Add(0x9a); break; + case ' ': result.Add(0xa0); break; + case '£': result.Add(0xa3); break; + case '©': result.Add(0xa9); break; + case '®': result.Add(0xae); break; + case '°': result.Add(0xb0); break; + case '´': result.Add(0xb4); break; + case '·': result.Add(0xb7); break; + case '¼': result.Add(0xbc); break; + case 'Á': result.Add(0xc1); break; + case 'Í': result.Add(0xcd); break; + case 'Ü': result.Add(0xdc); break; + case 'à': result.Add(0xe0); break; + case 'á': result.Add(0xe1); break; + case 'ç': result.Add(0xe7); break; + case 'è': result.Add(0xe8); break; + case 'é': result.Add(0xe9); break; + case 'ê': result.Add(0xea); break; + case 'í': result.Add(0xed); break; + case 'ï': result.Add(0xef); break; + case 'ñ': result.Add(0xf1); break; + case 'ó': result.Add(0xf3); break; + case 'ö': result.Add(0xf6); break; + case 'ú': result.Add(0xfa); break; + case 'ü': result.Add(0xfc); break; + case '«': result.Add(0xab); break; + case '»': result.Add(0xbb); break; + case '¬': result.Add(0x0a); break; + default: result.Add((byte)text[i]); break; + } + } + return result.ToArray(); + } + + private string NFSDecoder(byte[] data) + { + string result = ""; + for(int i = 0; i < data.Length; i++) + { + switch (data[i]) + { + case 0xc0: result += "А"; break; + case 0xc2: result += "Б"; break; + case 0x90: result += "В"; break; + case 0x91: result += "Г"; break; + case 0xc3: result += "Д"; break; + case 0xc4: result += "Е"; break; + case 0x9c: result += "Ё"; break; + case 0xc5: result += "Ж"; break; + case 0xc6: result += "З"; break; + case 0xc7: result += "И"; break; + case 0x9e: result += "Й"; break; + case 0xc9: result += "К"; break; + case 0xca: result += "Л"; break; + case 0xcb: result += "М"; break; + case 0x92: result += "Н"; break; + case 0xcc: result += "О"; break; + case 0xce: result += "П"; break; + case 0xcf: result += "Р"; break; + case 0xd0: result += "С"; break; + case 0xd1: result += "Т"; break; + case 0xd2: result += "У"; break; + case 0xd3: result += "Ф"; break; + case 0xd4: result += "Х"; break; + case 0xd5: result += "Ц"; break; + case 0xd6: result += "Ч"; break; + case 0xd7: result += "Ш"; break; + case 0xd8: result += "Щ"; break; + case 0xd9: result += "Ъ"; break; + case 0xda: result += "Ы"; break; + case 0xdb: result += "Ь"; break; + case 0xdd: result += "Э"; break; + case 0xde: result += "Ю"; break; + case 0xdf: result += "Я"; break; + case 0x93: result += "а"; break; + case 0xe2: result += "б"; break; + case 0x8a: result += "в"; break; + case 0xe3: result += "г"; break; + case 0x94: result += "д"; break; + case 0x8b: result += "е"; break; + case 0x9b: result += "ё"; break; + case 0xe4: result += "ж"; break; + case 0xe5: result += "з"; break; + case 0x8c: result += "и"; break; + case 0xe6: result += "й"; break; + case 0xeb: result += "к"; break; + case 0x95: result += "л"; break; + case 0xec: result += "м"; break; + case 0x96: result += "н"; break; + case 0x89: result += "о"; break; + case 0x97: result += "п"; break; + case 0x8d: result += "р"; break; + case 0x98: result += "с"; break; + case 0xee: result += "т"; break; + case 0xf0: result += "у"; break; + case 0xf2: result += "ф"; break; + case 0xf4: result += "х"; break; + case 0xf5: result += "ц"; break; + case 0xf7: result += "ч"; break; + case 0xf8: result += "ш"; break; + case 0xf9: result += "щ"; break; + case 0xfb: result += "ъ"; break; + case 0xfd: result += "ы"; break; + case 0xfe: result += "ь"; break; + case 0xff: result += "э"; break; + case 0xbf: result += "ю"; break; + case 0xaf: result += "я"; break; + case 0x81: result += '’'; break; + case 0x82: result += '…'; break; + case 0x83: result += '“'; break; + case 0x84: result += '”'; break; + case 0x85: result += '•'; break; + case 0x86: result += '‘'; break; + case 0x87: result += '™'; break; + case 0x88: result += '–'; break; + case 0x8e: result += '—'; break; + case 0x8f: result += 'ł'; break; + case 0x99: result += 'ї'; break; + case 0x9a: result += ''; break; + case 0xa0: result += ' '; break; + case 0xa3: result += '£'; break; + case 0xa9: result += '©'; break; + case 0xae: result += '®'; break; + case 0xb0: result += '°'; break; + case 0xb4: result += '´'; break; + case 0xb7: result += '·'; break; + case 0xbc: result += '¼'; break; + case 0xc1: result += 'Á'; break; + case 0xcd: result += 'Í'; break; + case 0xdc: result += 'Ü'; break; + case 0xe0: result += 'à'; break; + case 0xe1: result += 'á'; break; + case 0xe7: result += 'ç'; break; + case 0xe8: result += 'è'; break; + case 0xe9: result += 'é'; break; + case 0xea: result += 'ê'; break; + case 0xed: result += 'í'; break; + case 0xef: result += 'ï'; break; + case 0xf1: result += 'ñ'; break; + case 0xf3: result += 'ó'; break; + case 0xf6: result += 'ö'; break; + case 0xfa: result += 'ú'; break; + case 0xfc: result += 'ü'; break; + case 0xab: result += '«'; break; + case 0xbb: result += '»'; break; + case 0x0a: result += '¬'; break; + default: result += (char)data[i]; break; + } + } + return result; + } + } + + internal class Entry + { + public uint Id { get; set; } + public int Offset { get; set; } + public byte[] StringArray { get; set; } + public string String { get; set; } + } +} diff --git a/toolnfs/NFSLocaleTool/NFSLocaleTool.csproj b/toolnfs/NFSLocaleTool/NFSLocaleTool.csproj new file mode 100644 index 0000000..3989499 --- /dev/null +++ b/toolnfs/NFSLocaleTool/NFSLocaleTool.csproj @@ -0,0 +1,76 @@ + + + + + Debug + AnyCPU + {721F5EEC-8CF1-4FA1-99A6-88506B5B42C5} + Exe + NFSLocaleTool + NFSLocaleTool + v4.8 + 512 + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + True + True + Resource1.resx + + + + + + + + + + + + + ResXFileCodeGenerator + Resource1.Designer.cs + + + + + + + + + + \ No newline at end of file diff --git a/toolnfs/NFSLocaleTool/Program.cs b/toolnfs/NFSLocaleTool/Program.cs new file mode 100644 index 0000000..5309d14 --- /dev/null +++ b/toolnfs/NFSLocaleTool/Program.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + + +namespace NFSLocaleTool +{ + internal class Program + { + + static void Main(string[] args) + { + NFSLocale nfs = new NFSLocale(); + if (args.Length == 0) + { + Console.WriteLine("Create CharsList:"); + Console.WriteLine(" -cl "); + Console.WriteLine("Create Histogram:"); + Console.WriteLine(" -hg "); + Console.WriteLine("Create Text:"); + Console.WriteLine(" -t "); + Console.WriteLine("Create Binary:"); + Console.WriteLine(" -b "); + + Console.WriteLine("FrostbiteTool.exe -cl chars_list.txt"); + Console.WriteLine("FrostbiteTool.exe -h histogram.chunk chars_list.txt newhistogram.chunk"); + Console.WriteLine("FrostbiteTool.exe -t nfsunbound.chunk newhistogram.chunk nfsunbound.chunk.txt"); + Console.WriteLine("FrostbiteTool.exe -b nfsunbound.chunk.txt newhistogram.chunk nfsunbound.chunk.ids newnfsunbound.chunk"); + return; + } + string arg = args[0]; + switch (arg) + { + case "-help": + { + Console.WriteLine("Create CharsList:"); + Console.WriteLine(" -cl "); + Console.WriteLine("Create Histogram:"); + Console.WriteLine(" -hg "); + Console.WriteLine("Create Text:"); + Console.WriteLine(" -t "); + Console.WriteLine("Create Binary:"); + Console.WriteLine(" -b "); + + Console.WriteLine("FrostbiteTool.exe -cl chars_list.txt"); + Console.WriteLine("FrostbiteTool.exe -hg histogram.chunk chars_list.txt newhistogram.chunk"); + Console.WriteLine("FrostbiteTool.exe -t nfsunbound.chunk newhistogram.chunk nfsunbound.chunk.txt"); + Console.WriteLine("FrostbiteTool.exe -b nfsunbound.chunk.txt newhistogram.chunk nfsunbound.chunk.ids newnfsunbound.chunk"); + return; + } + + case "-h": + { + Console.WriteLine("Create CharsList:"); + Console.WriteLine(" -cl "); + Console.WriteLine("Create Histogram:"); + Console.WriteLine(" -hg "); + Console.WriteLine("Create Text:"); + Console.WriteLine(" -t "); + Console.WriteLine("Create Binary:"); + Console.WriteLine(" -b "); + + Console.WriteLine("FrostbiteTool.exe -cl chars_list.txt"); + Console.WriteLine("FrostbiteTool.exe -hg histogram.chunk chars_list.txt newhistogram.chunk"); + Console.WriteLine("FrostbiteTool.exe -t nfsunbound.chunk newhistogram.chunk nfsunbound.chunk.txt"); + Console.WriteLine("FrostbiteTool.exe -b nfsunbound.chunk.txt newhistogram.chunk nfsunbound.chunk.ids newnfsunbound.chunk"); + return; + } + + case "-cl": + { + nfs.CreateListChars(args[1]); + return; + } + case "-hg": + { + nfs.HistogramWrite(args[2], args[1], args[3]); + return; + } + case "-t": + { + nfs.Read(args[1], args[2]); + nfs.ExtractText(args[3]); + return; + } + case "-b": + { + nfs.WriteFromText(args[1], args[2], args[4], args[3]); + return; + } + default: { + + return; + } + } + } + } +} diff --git a/toolnfs/NFSLocaleTool/Properties/AssemblyInfo.cs b/toolnfs/NFSLocaleTool/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..c967dc9 --- /dev/null +++ b/toolnfs/NFSLocaleTool/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Общие сведения об этой сборке предоставляются следующим набором +// набора атрибутов. Измените значения этих атрибутов для изменения сведений, +// связанные с этой сборкой. +[assembly: AssemblyTitle("NFSLocaleTool")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("NFSLocaleTool")] +[assembly: AssemblyCopyright("Copyright © 2023")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Установка значения False для параметра ComVisible делает типы в этой сборке невидимыми +// для компонентов COM. Если необходимо обратиться к типу в этой сборке через +// из модели COM задайте для атрибута ComVisible этого типа значение true. +[assembly: ComVisible(false)] + +// Следующий GUID представляет идентификатор typelib, если этот проект доступен из модели COM +[assembly: Guid("721f5eec-8cf1-4fa1-99a6-88506b5b42c5")] + +// Сведения о версии сборки состоят из указанных ниже четырех значений: +// +// Основной номер версии +// Дополнительный номер версии +// Номер сборки +// Номер редакции +// +// Можно задать все значения или принять номера сборки и редакции по умолчанию +// используя "*", как показано ниже: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/toolnfs/NFSLocaleTool/Resource1.Designer.cs b/toolnfs/NFSLocaleTool/Resource1.Designer.cs new file mode 100644 index 0000000..4811ee8 --- /dev/null +++ b/toolnfs/NFSLocaleTool/Resource1.Designer.cs @@ -0,0 +1,177 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace NFSLocaleTool { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resource1 { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resource1() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NFSLocaleTool.Resource1", typeof(Resource1).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] chars { + get { + object obj = ResourceManager.GetObject("chars", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] charslist { + get { + object obj = ResourceManager.GetObject("charslist", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized string similar to 0002 + ///0081 + ///0082 + ///0083 + ///0084 + ///0085 + ///0086 + ///0087 + ///0088 + ///0089 + ///008A + ///008B + ///008C + ///008D + ///008E + ///008F + ///0090 + ///0091 + ///0092 + ///0093 + ///0094 + ///0095 + ///0096 + ///0097 + ///0098 + ///0099 + ///009A + ///009B + ///009C + ///009D + ///009E + ///009F + ///00A0 + ///00A1 + ///00A2 + ///00A3 + ///00A4 + ///00A5 + ///00A6 + ///00A7 + ///00A8 + ///00A9 + ///00AA + ///00AB + ///00AC + ///00AD + ///00AE + ///00AF + ///00B0 + ///00B1 + ///00B2 + ///00B3 + ///00B4 + ///00B5 + ///00B6 + ///00B7 + ///00B8 + ///00B9 + ///00BA + ///00BB + ///00BC + ///00BD + ///00BE + ///00BF + ///00C0 + ///00C1 + ///00C2 + ///00C3 + ///00C4 + ///00C5 + ///00C6 + ///00C7 + ///00C8 + ///00C9 + ///00CA + ///00CB + ///00CC + ///00CD + ///00CE + ///00CF + ///00D0 + ///00D1 + ///00D2 + ///00D3 + ///00D4 + ///00 [rest of string was truncated]";. + /// + internal static string default_list_chunk_number { + get { + return ResourceManager.GetString("default_list_chunk_number", resourceCulture); + } + } + } +} diff --git a/toolnfs/NFSLocaleTool/Resource1.resx b/toolnfs/NFSLocaleTool/Resource1.resx new file mode 100644 index 0000000..0f1b79c --- /dev/null +++ b/toolnfs/NFSLocaleTool/Resource1.resx @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Resources\chars.ids;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Resources\charslist.txt;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Resources\default list.chunk_number.ids;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;windows-1251 + + \ No newline at end of file diff --git a/toolnfs/NFSLocaleTool/Resources/chars.ids b/toolnfs/NFSLocaleTool/Resources/chars.ids new file mode 100644 index 0000000..12dec35 Binary files /dev/null and b/toolnfs/NFSLocaleTool/Resources/chars.ids differ diff --git a/toolnfs/NFSLocaleTool/Resources/charslist.txt b/toolnfs/NFSLocaleTool/Resources/charslist.txt new file mode 100644 index 0000000..3fce381 Binary files /dev/null and b/toolnfs/NFSLocaleTool/Resources/charslist.txt differ diff --git a/toolnfs/NFSLocaleTool/Resources/default list.chunk_number.ids b/toolnfs/NFSLocaleTool/Resources/default list.chunk_number.ids new file mode 100644 index 0000000..3f36021 --- /dev/null +++ b/toolnfs/NFSLocaleTool/Resources/default list.chunk_number.ids @@ -0,0 +1,128 @@ +0002 +0081 +0082 +0083 +0084 +0085 +0086 +0087 +0088 +0089 +008A +008B +008C +008D +008E +008F +0090 +0091 +0092 +0093 +0094 +0095 +0096 +0097 +0098 +0099 +009A +009B +009C +009D +009E +009F +00A0 +00A1 +00A2 +00A3 +00A4 +00A5 +00A6 +00A7 +00A8 +00A9 +00AA +00AB +00AC +00AD +00AE +00AF +00B0 +00B1 +00B2 +00B3 +00B4 +00B5 +00B6 +00B7 +00B8 +00B9 +00BA +00BB +00BC +00BD +00BE +00BF +00C0 +00C1 +00C2 +00C3 +00C4 +00C5 +00C6 +00C7 +00C8 +00C9 +00CA +00CB +00CC +00CD +00CE +00CF +00D0 +00D1 +00D2 +00D3 +00D4 +00D5 +00D6 +00D7 +00D8 +00D9 +00DA +00DB +00DC +00DD +00DE +00DF +00E0 +00E1 +00E2 +00E3 +00E4 +00E5 +00E6 +00E7 +00E8 +00E9 +00EA +00EB +00EC +00ED +00EE +00EF +00F0 +00F1 +00F2 +00F3 +00F4 +00F5 +00F6 +00F7 +00F8 +00F9 +00FA +00FB +00FC +00FD +00FE +00FF \ No newline at end of file diff --git a/toolnfs/NFSLocaleTool/Utils.cs b/toolnfs/NFSLocaleTool/Utils.cs new file mode 100644 index 0000000..84ec090 --- /dev/null +++ b/toolnfs/NFSLocaleTool/Utils.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NFSLocaleTool +{ + public static class Utils + { + public static byte[] ReadNullTerminatedArray(BinaryReader reader) + { + List result = new List(); + while (true) + { + byte b = reader.ReadByte(); + if(b != 0) + { + result.Add(b); + continue; + } + break; + } + return result.ToArray(); + } + + + public static string ReadString(byte[] namebuf, Encoding encoding) + { + BinaryReader binaryReader = new BinaryReader(new MemoryStream(namebuf)); + if (encoding == null) throw new ArgumentNullException("encoding"); + + List data = new List(); + + while (binaryReader.BaseStream.Position < binaryReader.BaseStream.Length) + { + data.Add(binaryReader.ReadByte()); + + string partialString = encoding.GetString(data.ToArray(), 0, data.Count); + + if (partialString.Length > 0 && partialString.Last() == '\0') + return encoding.GetString(data.SkipLast(encoding.GetByteCount("\0")).ToArray()).TrimEnd('\0'); + } + throw new InvalidDataException("Hit end of stream while reading null-terminated string."); + } + public static string ReadString(this BinaryReader binaryReader, Encoding encoding) + { + if (binaryReader == null) throw new ArgumentNullException("binaryReader"); + if (encoding == null) throw new ArgumentNullException("encoding"); + + List data = new List(); + + while (binaryReader.BaseStream.Position < binaryReader.BaseStream.Length) + { + data.Add(binaryReader.ReadByte()); + + string partialString = encoding.GetString(data.ToArray(), 0, data.Count); + + if (partialString.Length > 0 && partialString.Last() == '\0') + return encoding.GetString(data.SkipLast(encoding.GetByteCount("\0")).ToArray()).TrimEnd('\0'); + } + throw new InvalidDataException("Hit end of stream while reading null-terminated string."); + } + private static IEnumerable SkipLast(this IEnumerable source, int count) + { + if (source == null) throw new ArgumentNullException("source"); + + Queue queue = new Queue(); + + foreach (TSource item in source) + { + queue.Enqueue(item); + + if (queue.Count > count) yield return queue.Dequeue(); + } + } + } +}