summaryrefslogtreecommitdiff
path: root/tools/msgenc/MessagesEncoder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/msgenc/MessagesEncoder.cpp')
-rw-r--r--tools/msgenc/MessagesEncoder.cpp165
1 files changed, 165 insertions, 0 deletions
diff --git a/tools/msgenc/MessagesEncoder.cpp b/tools/msgenc/MessagesEncoder.cpp
new file mode 100644
index 00000000..8450fba0
--- /dev/null
+++ b/tools/msgenc/MessagesEncoder.cpp
@@ -0,0 +1,165 @@
+#include "MessagesEncoder.h"
+
+void MessagesEncoder::CmdmapRegisterCommand(string &command, uint16_t value)
+{
+ cmdmap[command] = value;
+}
+
+void MessagesEncoder::CharmapRegisterCharacter(string &code, uint16_t value)
+{
+ charmap[code] = value;
+}
+
+void MessagesEncoder::ReadMessagesFromText(string& fname) {
+ string text = ReadTextFile(fname);
+ size_t pos = 0;
+ do {
+ text = text.substr(pos);
+ if (text.empty())
+ break;
+ pos = text.find_first_of("\r\n");
+ vec_decoded.push_back(text.substr(0, pos));
+ pos = text.find_last_of("\r\n", pos + 1, 2);
+ if (pos == string::npos)
+ break;
+ pos++;
+ } while (pos != string::npos);
+ header.count = vec_decoded.size();
+ debug_printf("%d lines\n", header.count);
+}
+
+u16string MessagesEncoder::EncodeMessage(const string & message, int & i) {
+ u16string encoded;
+ bool is_trname = false;
+ uint32_t trnamebuf = 0;
+ int bit = 0;
+
+ for (size_t j = 0; j < message.size(); j++) {
+ if (message[j] == '{') {
+ size_t k = message.find('}', j);
+ string enclosed = message.substr(j + 1, k - j - 1);
+ j = k;
+ size_t pos = enclosed.find(' ');
+ string command = enclosed.substr(0, pos);
+ enclosed = enclosed.substr(pos + 1);
+ if (cmdmap.find(command) != cmdmap.end()) {
+ uint16_t command_i = cmdmap[command];
+ encoded += (char16_t)(0xFFFE);
+ debug_printf("%04X ", 0xFFFE);
+ vector<uint16_t> args;
+ if (pos != string::npos) {
+ do {
+ k = enclosed.find(',');
+ string num = enclosed.substr(0, k);
+ uint16_t num_i = stoi(num);
+ args.push_back(num_i);
+ enclosed = enclosed.substr(k + 1);
+ } while (k != string::npos);
+ if (command.rfind("STRVAR_", 0) == 0) {
+ command_i |= args[0];
+ args.erase(args.begin());
+ }
+ }
+ encoded += (char16_t)(command_i);
+ debug_printf("%04X ", command_i);
+ encoded += (char16_t)(args.size());
+ debug_printf("%04X ", (unsigned)args.size());
+ for (auto num_i : args) {
+ encoded += (char16_t)(num_i);
+ debug_printf("%04X ", num_i);
+ }
+ } else if (command == "TRNAME") {
+ is_trname = true;
+ encoded += (char16_t)(0xF100);
+ debug_printf("%04X ", 0xF100);
+ } else {
+ encoded += (char16_t)(stoi(enclosed, nullptr, 16));
+ debug_printf("%04X ", stoi(enclosed, nullptr, 16));
+ }
+ } else {
+ uint16_t code = 0;
+ size_t k;
+ string substr;
+ for (k = 0; k < message.size() - j; k++) {
+ substr = message.substr(j, k + 1);
+ try {
+ code = charmap.at(substr);
+ break;
+ } catch (out_of_range& oor) { /* silently discard */}
+ }
+ if (code == 0 && substr != "\\x0000") {
+ stringstream ss;
+ ss << "unrecognized character in " << textfilename << ": line " << i << " pos " << (j + 1) << " value " << substr;
+ throw runtime_error(ss.str());
+ }
+ debug_printf("%04X ", code);
+ if (is_trname) {
+ if (code & ~0x1FF) {
+ stringstream ss;
+ ss << "invalid character for bitpacked string: " << substr;
+ throw runtime_error(ss.str());
+ }
+ trnamebuf |= code << bit;
+ bit += 9;
+ if (bit >= 15) {
+ bit -= 15;
+ encoded += (char16_t)(trnamebuf & 0x7FFF);
+ trnamebuf >>= 15;
+ }
+ } else {
+ encoded += (char16_t)(code);
+ }
+ j += k;
+ }
+ }
+ if (is_trname && bit > 1) {
+ trnamebuf |= 0xFFFF << bit;
+ encoded += (char16_t)(trnamebuf & 0x7FFF);
+ debug_printf("%04X ", trnamebuf & 0x7FFF);
+ }
+ encoded += (char16_t)(0xFFFF);
+ debug_printf("%04X ", 0xFFFF);
+ return encoded;
+}
+
+void MessagesEncoder::WriteMessagesToBin(string& filename) {
+ ofstream outfile(filename, ios_base::binary);
+ if (!outfile.good()) {
+ throw ofstream::failure("Unable to open file \"" + filename + "\" for writing");
+ }
+ outfile.write((char *)&header, sizeof(header));
+ for (int i = 1; i <= (int)alloc_table.size(); i++) {
+ alloc_table[i - 1].encrypt(header.key, i);
+ EncryptU16String(vec_encoded[i - 1], i);
+ }
+ outfile.write((char *)alloc_table.data(), (streamsize)(sizeof(MsgAlloc) * alloc_table.size()));
+ for (const u16string & m : vec_encoded) {
+ outfile.write((char *)m.c_str(), (streamsize)(m.size() * 2));
+ }
+ outfile.close();
+}
+
+// Public virtual functions
+
+void MessagesEncoder::ReadInput()
+{
+ ReadMessagesFromText(textfilename);
+}
+
+void MessagesEncoder::Convert() {
+ MsgAlloc alloc {(uint32_t)(sizeof(header) + sizeof(MsgAlloc) * header.count), 0};
+ int i = 1;
+ for (const auto& message : vec_decoded) {
+ u16string encoded = EncodeMessage(message, i);
+ alloc.length = encoded.size();
+ vec_encoded.push_back(encoded);
+ debug_printf("msg %d: at 0x%08X, count %d\n", i, alloc.offset, alloc.length);
+ alloc_table.push_back(alloc);
+ alloc.offset += alloc.length * 2;
+ i++;
+ }
+}
+
+void MessagesEncoder::WriteOutput() {
+ WriteMessagesToBin(binfilename);
+}