/// <summary> /// Replaces Unicode symbols from message.bin with human readable text tokens /// </summary> /// <param name="text">Encoded text</param> public string UnicodeDecode(string text) { var sb = new StringBuilder(); var textBytes = Encoding.Unicode.GetBytes(text); for (int i = 0; i < textBytes.Length; i += 2) { ushort shortCharacter = BitConverter.ToUInt16(textBytes, i); if (EntriesByUnicode.TryGetValue(shortCharacter, out var entry)) { // A direct match for the character was found sb.Append($"[{entry.CodeString}]"); } else if (EntriesByUnicode.TryGetValue((ushort)(shortCharacter & 0xFF00), out entry)) { // A match for the low bytes was found, which means that it encodes some other value. // The amount of words to decode is found in the Length. uint encodedValue = shortCharacter & 0xFFu; if (entry.Length > 0) { encodedValue = 0; for (int j = 0; j < entry.Length; j++) { i += (j + 1) * 2; uint partialValue = BitConverter.ToUInt16(textBytes, i); encodedValue |= partialValue << (j * 2); } encodedValue--; } string encodedValueString; if (ConstantReplacementTable.TryGetValue(entry.CodeString, out var enumType)) { encodedValueString = Enum.GetName(enumType, encodedValue) ?? encodedValue.ToString(); } else { encodedValueString = encodedValue.ToString(); } sb.Append($"[{entry.CodeString}{encodedValueString}]"); } else { sb.Append(Encoding.Unicode.GetString(textBytes, i, 2)); } } return(sb.ToString()); }
/// <summary> /// Replaces special text tokens with Unicode symbols for message.bin /// </summary> /// <param name="text">User-friendly text</param> public string UnicodeEncode(string text) { var sb = new StringBuilder(); var match = StringTokenRegex.Match(text); int lastStringPos = 0; while (match.Success) { sb.Append(text.Substring(lastStringPos, match.Index - lastStringPos)); string directive = match.Groups[1].Value; string?valueString = match.Groups.Count > 1 ? match.Groups[2].Value : null; if (!string.IsNullOrEmpty(valueString) && EntriesByCodeString.TryGetValue(directive + valueString, out var entry)) { // Sometimes the directive and value are both included (e.g. [M:B01]) sb.Append((char)entry.UnicodeValue); } else if (EntriesByCodeString.TryGetValue(directive, out entry)) { ushort unicodeValue = entry.UnicodeValue; if (entry.DigitFlag && valueString != null) { uint value; if (ConstantReplacementTable.TryGetValue(entry.CodeString, out var enumType)) { value = Convert.ToUInt32(Enum.Parse(enumType, valueString)); } else { value = uint.Parse(valueString); } // Encode the value into the two low bytes. // It seems like one of the bytes inside the value is encoded redundantly. unicodeValue = (ushort)((unicodeValue & 0xFF00) | (byte)value); sb.Append((char)unicodeValue); if (entry.Length > 0) { if (entry.Length > 2) { throw new Exception("Invalid entry length."); } byte[] bytes = BitConverter.GetBytes(value + 1); sb.Append(Encoding.Unicode.GetString(bytes, 0, entry.Length * 2)); } } else { sb.Append((char)unicodeValue); } } else { sb.Append(match.Value); } lastStringPos = match.Index + match.Length; match = match.NextMatch(); } sb.Append(text.Substring(lastStringPos, text.Length - lastStringPos)); return(sb.ToString()); }