static void Main(string[] args) { Parser.Default.ParseArguments <Options>(args).WithParsed(o => { CharTable charTable = new CharTable(o.ChartablePath); Narc font = new Narc(o.FontPath); FontTable fontTable_0 = new FontTable(font.Files[0]); Generation.Gen gen = fontTable_0.Gen; switch (gen) { case Generation.Gen.Gen4: font.Files[0] = fontTable_0.Save(charTable); font.Files[1] = new FontTable(font.Files[1]).Save(charTable); font.Files[2] = new FontTable(font.Files[2]).Save(charTable, StyleType.TOP_LEFT); if (font.Files.Count == 10) // HGSS { font.Files[4] = new FontTable(font.Files[4]).Save(charTable, StyleType.ROUND); } break; case Generation.Gen.Gen5: font.Files[0] = fontTable_0.Save(charTable, StyleType.BOTTOM_RIGHT_5); font.Files[1] = new FontTable(font.Files[1]).Save(charTable, StyleType.BOTTOM_RIGHT_5, FontType.PIXEL_9); font.Files[2] = new FontTable(font.Files[2]).Save(charTable, StyleType.ROUND, FontType.PIXEL_9); break; default: return; } font.Save(o.OutputPath); }); }
/// <summary> /// 将文本根据保存为 narc 文件。 /// </summary> /// <param name="files">narc 文件</param> /// <param name="charTable">码表</param> public void Save(ref Narc msg, CharTable charTable) { if (this is Text_4) { ((Text_4)this).Save(ref msg, charTable); } else if (this is Text_5) { ((Text_5)this).Save(ref msg); } }
static void Main(string[] args) { Parser.Default.ParseArguments <Options>(args).WithParsed(o => { CharTable charTable = new CharTable(o.ChartablePath); Narc msg = new Narc(o.MessagePath); Text text; switch (msg.Files.Count) { case 610: // DP case 709: // Pt case 814: // HGSS text = new Text_4(msg, charTable); break; case 273: case 472: text = new Text_5(msg, charTable); break; default: throw new FormatException(); } if (o.ExtractPath != null) { text.Extract(o.ExtractPath); } if (o.ImportPath != null && o.OutputPath != null) { text.Import(o.ImportPath); text.Save(ref msg, charTable); msg.Save(o.OutputPath); } if (charTable.NoCode.Count > 0) { Console.WriteLine("以下字符未在码表中:" + string.Join("", charTable.NoCode)); } if (charTable.NoChar.Count > 0) { Console.WriteLine("以下编码未在码表中:" + string.Join(", ", charTable.NoChar)); } }); }
new public void Save(ref Narc files, CharTable charTable) { for (int i = 0; i < files.Files.Count; i++) { List <string> subList = TextList[0][i]; MemoryStream ms = new MemoryStream(); BinaryWriter bw = new BinaryWriter(ms); bw.Write((ushort)subList.Count); bw.Write((ushort)OriginalKeys[i]); int num = (OriginalKeys[i] * 0x2fd) & 0xffff, num4 = 4 + (subList.Count * 8); int[] numArray = new int[subList.Count]; for (int j = 0; j < subList.Count; j++) { int num2 = (num * (j + 1)) & 0xffff; int num3 = num2 | (num2 << 16); bw.Write((uint)(num4 ^ num3)); numArray[j] = GetRealSize(subList[j]); bw.Write((uint)(GetRealSize(subList[j]) ^ num3)); num4 += GetRealSize(subList[j]) * 2; } for (int k = 0; k < subList.Count; k++) { num = (0x91bd3 * (k + 1)) & 0xffff; int[] numArray2 = EncodeText(subList[k], numArray[k], charTable); for (int l = 0; l < numArray[k] - 1; l++) { bw.Write((short)(numArray2[l] ^ num)); num += 0x493d; num &= 0xffff; } bw.Write((short)(0xffff ^ num)); } byte[] bytes = new byte[ms.Position]; ms.Position = 0; ms.Read(bytes, 0, bytes.Length); files.Files[i] = bytes; bw.Close(); } }
private int[] EncodeText(string str, int stringSize, CharTable charTable) { int[] numArray = new int[stringSize - 1]; int index = 0; for (int i = 0; i < str.Length; i++) { switch (str[i]) { case '\\': switch (str[i + 1]) { case 'r': if (Version > 2) { numArray[index] = 0x25BD; } else { numArray[index] = 0x25BC; } i++; break; case 'f': if (Version > 2) { numArray[index] = 0x25BC; } else { numArray[index] = 0x25BD; } i++; break; case 'n': numArray[index] = 0xE000; i++; break; case 'v': numArray[index++] = 0xFFFE; numArray[index] = Convert.ToInt32(str.Substring(i + 2, 4), 16); i += 5; break; case 'x': numArray[index] = Convert.ToInt32(str.Substring(i + 2, 4), 16); i += 5; break; } break; case '[': int rightPos = str.IndexOf(']', i); string[] controlText = str.Substring(i + 1, rightPos - i - 1).Split(','); numArray[index++] = 0xFFFE; numArray[index++] = Convert.ToInt32(controlText[0], 16); if (controlText[0] == "0129") { numArray[index++] = controlText.Length - 1 + 1; } else { numArray[index++] = controlText.Length - 1; } for (int j = 1; j < controlText.Length; j++) { numArray[index++] = Convert.ToInt32(controlText[j], 16); } index--; i = rightPos; break; default: numArray[index] = charTable.WriteCharacter(str[i]); break; } index++; } return(numArray); }
public Text_4(Narc files, CharTable charTable) { Version = 3; TextList.Clear(); TextList.Add(new List <List <string> >()); foreach (byte[] bytes in files.Files) { BinaryReader br = new BinaryReader(new MemoryStream(bytes)); List <string> s4 = new List <string>(); bool flag2 = false; int stringCount = br.ReadUInt16(), originalKey = br.ReadUInt16(); OriginalKeys.Add(originalKey); int num = (originalKey * 0x2fd) & 0xffff; int[] numArray = new int[stringCount]; int[] numArray2 = new int[stringCount]; for (int i = 0; i < stringCount; i++) { int num2 = (num * (i + 1)) & 0xffff; int num3 = num2 | (num2 << 16); numArray[i] = br.ReadInt32(); numArray[i] = numArray[i] ^ num3; numArray2[i] = br.ReadInt32(); numArray2[i] = numArray2[i] ^ num3; } for (int j = 0; j < stringCount; j++) { int control = 0; num = (0x91bd3 * (j + 1)) & 0xffff; string text = ""; for (int k = 0; k < numArray2[j]; k++) { int num4 = br.ReadUInt16(); num4 ^= num; switch (control) { case 0: switch (num4) { case 0xE000: text += "\\n"; break; case 0x25BC: if (Version > 2) { text += "\\f"; } else { text += "\\r"; } break; case 0x25BD: if (Version > 2) { text += "\\r"; } else { text += "\\f"; } break; case 0xF100: flag2 = true; break; case 0xFFFE: text += "["; control = 1; break; case 0xFFFF: break; default: if (flag2) { int num5 = 0; int num6 = 0; string str = null; while (true) { if (num5 >= 15) { num5 -= 15; if (num5 > 0) { int num8 = num6 | (num4 << 9 - num5 & 511); if ((num8 & 255) == 255) { break; } if (num8 != 0 && num8 != 1) { char str2 = charTable.GetCharacter(num8); if (str2 == '\0') { text += "\\x" + num8.ToString("X4"); } else { text += str2; } } } } else { int num8 = num4 >> num5 & 511; if ((num8 & 255) == 255) { break; } if (num8 != 0 && num8 != 1) { char str3 = charTable.GetCharacter(num8); if (str3 == '\0') { text += "\\x" + num8.ToString("X4"); } else { text += str3; } } num5 += 9; if (num5 < 15) { num6 = num4 >> num5 & 511; num5 += 9; } num += 18749; num &= 65535; num4 = br.ReadUInt16(); num4 ^= num; k++; } } text += str; } else { char str3 = charTable.GetCharacter(num4); if (str3 == '\0') { text += "\\x" + num4.ToString("X4"); } else { text += str3; } } break; } break; case 1: text += num4.ToString("X4"); if (num4 == 0x0129) // 不知道为何,很奇怪的控制符 { control = 3; } else { control = 2; } break; case 2: control = -num4; if (control == 0) { text += "]"; } break; case 3: control = -num4 + 1; if (control == 0) { text += "]"; } break; default: text += "," + num4.ToString("X4"); control++; if (control == 0) { text += "]"; } break; } num += 18749; num &= 65535; } s4.Add(text); } TextList[0].Add(s4); } }
public Text_5(Narc files, CharTable charTable) { TextList.Clear(); TextList.Add(new List <List <string> >()); TextList.Add(new List <List <string> >()); foreach (byte[] bytes in files.Files) { BinaryReader br = new BinaryReader(new MemoryStream(bytes)); ushort numSections, numEntries, tmpCharCount, tmpUnknown, tmpChar; uint unk1, tmpOffset; uint[] sizeSections = new uint[] { 0, 0 }; uint[] sectionOffset = new uint[] { 0, 0 }; ushort key; numSections = br.ReadUInt16(); numEntries = br.ReadUInt16(); sizeSections[0] = br.ReadUInt32(); unk1 = br.ReadUInt32(); for (int i = 0; i < numSections; i++) { sectionOffset[i] = br.ReadUInt32(); } for (int i = 0; i < TextList.Count; i++) { List <string> s = new List <string>(); List <ushort> keys = new List <ushort>(); List <ushort> unknowns = new List <ushort>(); List <ushort> characterCount = new List <ushort>(); if (i < numSections) { br.BaseStream.Position = sectionOffset[i]; sizeSections[i] = br.ReadUInt32(); List <uint> tableOffsets = new List <uint>(); List <List <ushort> > encText = new List <List <ushort> >(); for (int j = 0; j < numEntries; j++) { tmpOffset = br.ReadUInt32(); tmpCharCount = br.ReadUInt16(); tmpUnknown = br.ReadUInt16(); tableOffsets.Add(tmpOffset); characterCount.Add(tmpCharCount); unknowns.Add(tmpUnknown); } for (int j = 0; j < numEntries; j++) { List <ushort> tmpEncChars = new List <ushort>(); br.BaseStream.Position = sectionOffset[i] + tableOffsets[j]; for (int k = 0; k < characterCount[j]; k++) { tmpChar = br.ReadUInt16(); tmpEncChars.Add(tmpChar); } encText.Add(tmpEncChars); key = (ushort)(encText[j][characterCount[j] - 1] ^ 0xFFFF); for (int k = characterCount[j] - 1; k >= 0; k--) { encText[j][k] ^= key; if (k == 0) { keys.Add(key); } key = (ushort)(((key >> 3) | (key << 13)) & 0xFFFF); } string line = ""; for (int k = 0; k < characterCount[j]; k++) { if (encText[j][k] > 20 && encText[j][k] <= 0xFFF0 && encText[j][k] != 0xF000) { line += (char)encText[j][k]; } else if (encText[j][k] == 0xFFFE) { line += "\\n"; } else if (encText[j][k] == 0xFFFF) { // line += "\\xFFFF"; } else if (encText[j][k] == 0xF000) { switch (encText[j][k + 1]) { case 0xBE00: line += "\\r"; break; case 0xBE01: line += "\\f"; break; default: line += $"[{encText[j][k + 1]:X4}"; for (int control = 0; control < encText[j][k + 2]; control++) { line += $",{encText[j][k + 3 + control]:X4}"; } line += "]"; break; } k += 2 + encText[j][k + 2]; } else { line += $"\\x{encText[j][k]:X4}"; } } s.Add(line); } } TextList[i].Add(s); Keys[i].Add(keys); Unknowns[i].Add(unknowns); OriginalLengths[i].Add(characterCount); } } }
public byte[] Save(CharTable charTable, StyleType style = StyleType.BOTTOM_RIGHT, FontType font = FontType.SONG_TI) { switch (Gen) { case Generation.Gen.Gen4: while (Table.Items.Length <= charTable.maxCharCode) { Table.AddNewItem(); } for (ushort i = 1; i <= charTable.maxCharCode; i++) { char c = charTable.GetCharacter(i); if (ChinesePunctuation.Contains(c)) { Table.Items[i - 1].Item = DrawChar.CharToValues(c, style, FontType.MS_GOTHIC, posX: -2 + ("?!".Contains(c) ? -3 : 0), posY: 2); Table.Items[i - 1].Width = 13; } else if (i >= ChineseCharStart) { Table.Items[i - 1].Item = DrawChar.CharToValues(c, style, font); Table.Items[i - 1].Width = 13; } } break; case Generation.Gen.Gen5: NFTRNitroFile tempTable = (NFTRNitroFile)Table; /* * foreach (char c in ChinesePunctuation) * { * ushort code = tempTable[c]; * if (code > 0 && code < tempTable.Items.Length) * { * CGLPFrame.Character item = (CGLPFrame.Character)tempTable.Items[code]; * switch (font) * { * case FontType.PIXEL_9: * item.Width = (byte)(((style == StyleType.BOTTOM_RIGHT_5) ? 9 : 10) - item.SpaceWidth); * break; * default: * item.Width = (byte)(12 - item.SpaceWidth); * break; * } * } * }*/ CMAPFrame lastFrame = (CMAPFrame)tempTable.Frames[tempTable.FramesCount - 1]; char[] originalChars = lastFrame.Keys, newChars = charTable.Values; ushort[] originalValues = lastFrame.Values, newValues = charTable.Keys; for (ushort i = 0, j = 0; i < originalChars.Length && j < newChars.Length; i++) { if (originalChars[i] >= 0x4E00 && originalChars[i] < 0xE000) { while (j < newChars.Length && (newChars[j] < 0x4E00 || newChars[j] >= 0xE000)) { j++; } if (j < newChars.Length) { lastFrame[originalValues[i]] = newChars[j]; CGLPFrame.Character item = (CGLPFrame.Character)tempTable.Items[originalValues[i]]; switch (font) { case FontType.PIXEL_9: item.Item = DrawChar.CharToValues(newChars[j], style, font, posX: -1, posY: -1); item.Width = (byte)((style == StyleType.BOTTOM_RIGHT_5) ? 9 : 10); break; default: item.Item = DrawChar.CharToValues(newChars[j], style, font); item.Width = 12; break; } item.SpaceWidth = 0; j++; } } } break; default: return(new byte[0]); } MemoryStream ms = new MemoryStream(); BinaryWriter bw = new BinaryWriter(ms); Table.WriteTo(bw); byte[] bytes = new byte[ms.Length]; ms.Position = 0; ms.Read(bytes, 0, bytes.Length); bw.Close(); return(bytes); }