mirror of
https://github.com/pret/pokeheartgold.git
synced 2024-11-26 22:50:22 +00:00
msgenc: Allow leading whitespace, comments, and commands in charmap
This commit is contained in:
parent
15530ce0a6
commit
f4ea6b23f0
24
charmap.txt
24
charmap.txt
@ -1,3 +1,9 @@
|
||||
// Character mapping for Pokémon HeartGold and SoulSilver
|
||||
// Version 2021.08.17
|
||||
// Format is HEXCODE=<character> or HEXCODE={<command>}
|
||||
// Comments are preceded by double forward slashes as in C99 and C++.
|
||||
// Leading spaces and tabs are ignored; trailing spaces and tabs are not.
|
||||
|
||||
0000=\x0000
|
||||
0001=
|
||||
0002=ぁ
|
||||
@ -2874,3 +2880,21 @@
|
||||
E000=\n
|
||||
25BC=\r
|
||||
25BD=\f
|
||||
|
||||
// Function codes
|
||||
0100={STRVAR_1}
|
||||
0300={STRVAR_3}
|
||||
0400={STRVAR_4}
|
||||
3400={STRVAR_34}
|
||||
0200={YESNO}
|
||||
0201={PAUSE}
|
||||
0202={WAIT}
|
||||
0203={CURSOR_X}
|
||||
0204={CURSOR_Y}
|
||||
0205={ALN_CENTER}
|
||||
0206={ALN_RIGHT}
|
||||
0207={UNK_207}
|
||||
0208={UNK_208}
|
||||
FF00={COLOR}
|
||||
FF01={SIZE}
|
||||
FF02={UNK_FF02}
|
||||
|
@ -415,8 +415,8 @@ MSGFILE_BIN := $(patsubst %.txt,%.bin,$(MSGFILE_TXT))
|
||||
$(MSGDATA_MSG_DIR).narc: %.narc: $(MSGFILE_BIN)
|
||||
$(KNARC) -d $* -p $@ -i
|
||||
|
||||
$(MSGFILE_BIN): %.bin: %.txt %.key
|
||||
$(MSGENC) -e $^ charmap.txt $@
|
||||
$(MSGFILE_BIN): %.bin: %.txt %.key charmap.txt
|
||||
$(MSGENC) -e $^ $@
|
||||
|
||||
#%.narc:
|
||||
# $(KNARC) -d $* -p $@
|
||||
|
@ -1,5 +1,15 @@
|
||||
#include "MessagesConverter.h"
|
||||
|
||||
void MessagesConverter::CharmapRegisterCharacter(string &code, uint16_t value)
|
||||
{
|
||||
throw runtime_error("calling parent class method MessagesConverter::CharmapRegisterCharacter when child class method is required");
|
||||
}
|
||||
|
||||
void MessagesConverter::CmdmapRegisterCommand(string &command, uint16_t value)
|
||||
{
|
||||
throw runtime_error("calling parent class method MessagesConverter::CmdmapRegisterCommand when child class method is required");
|
||||
}
|
||||
|
||||
string MessagesConverter::ReadTextFile(string& filename) {
|
||||
ifstream file(filename);
|
||||
if (!file.good()) {
|
||||
@ -20,21 +30,42 @@ void MessagesConverter::WriteTextFile(string& filename, string const& contents)
|
||||
file.close();
|
||||
}
|
||||
|
||||
void MessagesConverter::ReadCharmap(string& filename) {
|
||||
string raw = ReadTextFile(filename);
|
||||
size_t pos, eqpos, last_pos = 0;
|
||||
while (last_pos != string::npos && (pos = raw.find_first_of("\r\n", last_pos)) != string::npos) {
|
||||
eqpos = raw.find('=', last_pos);
|
||||
void MessagesConverter::ReadCharmap() {
|
||||
string raw = ReadTextFile(charmapfilename);
|
||||
string line;
|
||||
size_t pos, eqpos, last_pos = 0, lineno = 0;
|
||||
|
||||
for (
|
||||
last_pos = 0;
|
||||
last_pos != string::npos && (pos = raw.find_first_of("\r\n", last_pos)) != string::npos;
|
||||
last_pos = raw.find_last_of("\r\n", pos + 1, 2) + 1, lineno++
|
||||
) {
|
||||
line = raw.substr(last_pos, pos - last_pos);
|
||||
if (line.find("//") != string::npos) {
|
||||
line = line.substr(0, line.find("//"));
|
||||
}
|
||||
if (line.find_first_not_of(" \t") == string::npos)
|
||||
continue;
|
||||
line = line.substr(
|
||||
line.find_first_not_of(" \t")
|
||||
);
|
||||
eqpos = line.find('=');
|
||||
if (eqpos == string::npos) {
|
||||
stringstream s;
|
||||
s << "charmap syntax error at " << (charmap.size() + 1);
|
||||
s << "charmap syntax error at " << (lineno + 1);
|
||||
throw(runtime_error(s.str()));
|
||||
}
|
||||
string value = raw.substr(last_pos, eqpos - last_pos);
|
||||
string code = raw.substr(eqpos + 1, pos - eqpos - 1);
|
||||
string value = line.substr(0, eqpos);
|
||||
string code = line.substr(eqpos + 1);
|
||||
uint16_t value_i = stoi(value, nullptr, 16);
|
||||
charmap[code] = value_i;
|
||||
last_pos = raw.find_last_of("\r\n", pos + 1, 2) + 1;
|
||||
if (code[0] == '{' && code[code.length() - 1] == '}') {
|
||||
code = code.substr(1, code.length() - 2);
|
||||
CmdmapRegisterCommand(code, value_i);
|
||||
if (code.rfind("STRVAR_", 0) == 0)
|
||||
strvar_codes.insert(value_i);
|
||||
} else {
|
||||
CharmapRegisterCharacter(code, value_i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -52,38 +53,21 @@ static inline void DecryptU16String(u16string & message, int & i) {
|
||||
}
|
||||
|
||||
class MessagesConverter{
|
||||
virtual void CharmapRegisterCharacter(string& code, uint16_t value);
|
||||
virtual void CmdmapRegisterCommand(string& command, uint16_t value);
|
||||
protected:
|
||||
ConvertMode mode;
|
||||
string textfilename;
|
||||
string keyfilename;
|
||||
string charmapfilename;
|
||||
string binfilename;
|
||||
map<string, uint16_t> charmap;
|
||||
|
||||
MsgArcHeader header = {};
|
||||
vector<MsgAlloc> alloc_table;
|
||||
vector<string> vec_decoded;
|
||||
vector<u16string> vec_encoded;
|
||||
|
||||
map<string, uint16_t> cmdmap = {
|
||||
{"STRVAR_1", 0x0100},
|
||||
{"STRVAR_3", 0x0300},
|
||||
{"STRVAR_4", 0x0400},
|
||||
{"STRVAR_34", 0x3400},
|
||||
{"YESNO", 0x200},
|
||||
{"PAUSE", 0x201},
|
||||
{"WAIT", 0x202},
|
||||
{"CURSOR_X", 0x203},
|
||||
{"CURSOR_Y", 0x204},
|
||||
{"ALN_CENTER", 0x205},
|
||||
{"ALN_RIGHT", 0x206},
|
||||
{"UNK_207", 0x207},
|
||||
{"UNK_208", 0x208},
|
||||
{"COLOR", 0xFF00},
|
||||
{"SIZE", 0xFF01},
|
||||
{"UNK_FF02", 0xFF02},
|
||||
};
|
||||
|
||||
vector<uint16_t> strvar_codes = {0x0100, 0x0300, 0x0400, 0x3400};
|
||||
set<uint16_t> strvar_codes;
|
||||
|
||||
template <typename key_type, typename mapped_type> void CreateInverseMap(map<key_type, mapped_type>const& _in, map<mapped_type, key_type>& _out) {
|
||||
for (auto _pair : _in) {
|
||||
@ -92,16 +76,15 @@ protected:
|
||||
}
|
||||
static string ReadTextFile(string& filename);
|
||||
static void WriteTextFile(string& filename, string const & contents);
|
||||
void ReadCharmap(string& charmapfname);
|
||||
public:
|
||||
MessagesConverter(string &_textfilename, string &_keyfilename, string &_charmapfilename, string &_binfilename) :
|
||||
MessagesConverter(ConvertMode _mode, string &_textfilename, string &_keyfilename, string &_charmapfilename, string &_binfilename) :
|
||||
mode(_mode),
|
||||
textfilename(_textfilename),
|
||||
keyfilename(_keyfilename),
|
||||
charmapfilename(_charmapfilename),
|
||||
binfilename(_binfilename)
|
||||
{
|
||||
ReadCharmap(charmapfilename);
|
||||
}
|
||||
{}
|
||||
void ReadCharmap();
|
||||
virtual void ReadInput() = 0;
|
||||
virtual void Convert() = 0;
|
||||
virtual void WriteOutput() = 0;
|
||||
|
@ -1,6 +1,16 @@
|
||||
#include <algorithm>
|
||||
#include "MessagesDecoder.h"
|
||||
|
||||
void MessagesDecoder::CmdmapRegisterCommand(string &command, uint16_t value)
|
||||
{
|
||||
cmdmap[value] = command;
|
||||
}
|
||||
|
||||
void MessagesDecoder::CharmapRegisterCharacter(string &code, uint16_t value)
|
||||
{
|
||||
charmap[value] = code;
|
||||
}
|
||||
|
||||
static string ConvertIntToHexStringN(unsigned value, StrConvMode mode, int n) {
|
||||
string dest;
|
||||
bool printing_zeroes = mode == STR_CONV_MODE_LEADING_ZEROS;
|
||||
@ -79,8 +89,8 @@ string MessagesDecoder::DecodeMessage(u16string &message, int &i) {
|
||||
uint16_t code = message[j];
|
||||
debug_printf("%04X ", code);
|
||||
|
||||
if (charmap_dec.find(code) != charmap_dec.end()) {
|
||||
decoded += charmap_dec[code];
|
||||
if (charmap.find(code) != charmap.end()) {
|
||||
decoded += charmap[code];
|
||||
}
|
||||
else if (code == (is_trname ? 0x01FF : 0xFFFF)) {
|
||||
break;
|
||||
@ -96,8 +106,8 @@ string MessagesDecoder::DecodeMessage(u16string &message, int &i) {
|
||||
is_strvar = true;
|
||||
command = "STRVAR_" + ConvertIntToHexStringN((code >> 8), STR_CONV_MODE_LEFT_ALIGN, 2);
|
||||
}
|
||||
else if (cmdmap_dec.find(code) != cmdmap_dec.end()) {
|
||||
command = cmdmap_dec[code];
|
||||
else if (cmdmap.find(code) != cmdmap.end()) {
|
||||
command = cmdmap[code];
|
||||
} else {
|
||||
throw runtime_error("Invalid control code in " + binfilename + ": " + ConvertIntToHexStringN(code, STR_CONV_MODE_LEADING_ZEROS, 4) + " at line " + to_string(i) + ":" + to_string(j));
|
||||
}
|
||||
|
@ -12,19 +12,18 @@ enum StrConvMode {
|
||||
|
||||
class MessagesDecoder : public MessagesConverter
|
||||
{
|
||||
map <uint16_t, string> cmdmap_dec;
|
||||
map <uint16_t, string> charmap_dec;
|
||||
map <uint16_t, string> cmdmap;
|
||||
map <uint16_t, string> charmap;
|
||||
|
||||
void ReadMessagesFromBin(string& filename);
|
||||
void WriteMessagesToText(string& filename);
|
||||
static void WriteBinaryFile(string& filename, void* data, streamsize size);
|
||||
static u16string DecodeTrainerNameMessage(u16string const &message);
|
||||
string DecodeMessage(u16string& message, int& i);
|
||||
void CharmapRegisterCharacter(string& code, uint16_t value) override;
|
||||
void CmdmapRegisterCommand(string& command, uint16_t value) override;
|
||||
public:
|
||||
MessagesDecoder(string &_textfilename, string &_keyfilename, string &_charmapfilename, string &_binfilename) : MessagesConverter(_textfilename, _keyfilename, _charmapfilename, _binfilename) {
|
||||
CreateInverseMap(charmap, charmap_dec);
|
||||
CreateInverseMap(cmdmap, cmdmap_dec);
|
||||
}
|
||||
MessagesDecoder(string &_textfilename, string &_keyfilename, string &_charmapfilename, string &_binfilename) : MessagesConverter(CONV_DECODE, _textfilename, _keyfilename, _charmapfilename, _binfilename) {}
|
||||
void ReadInput() override;
|
||||
void Convert() override;
|
||||
void WriteOutput() override;
|
||||
|
@ -1,5 +1,15 @@
|
||||
#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;
|
||||
@ -62,7 +72,7 @@ u16string MessagesEncoder::EncodeMessage(const string & message, int & i) {
|
||||
encoded += (char16_t)(command_i);
|
||||
debug_printf("%04X ", command_i);
|
||||
encoded += (char16_t)(args.size());
|
||||
debug_printf("%04X ", args.size());
|
||||
debug_printf("%04X ", (unsigned)args.size());
|
||||
for (auto num_i : args) {
|
||||
encoded += (char16_t)(num_i);
|
||||
debug_printf("%04X ", num_i);
|
||||
@ -81,9 +91,10 @@ u16string MessagesEncoder::EncodeMessage(const string & message, int & i) {
|
||||
string substr;
|
||||
for (k = 0; k < message.size() - j; k++) {
|
||||
substr = message.substr(j, k + 1);
|
||||
code = charmap[substr];
|
||||
if (code != 0 || substr == "\\x0000")
|
||||
try {
|
||||
code = charmap.at(substr);
|
||||
break;
|
||||
} catch (out_of_range) { /* silently discard */}
|
||||
}
|
||||
if (code == 0 && substr != "\\x0000") {
|
||||
stringstream ss;
|
||||
|
@ -6,12 +6,17 @@
|
||||
|
||||
class MessagesEncoder : public MessagesConverter
|
||||
{
|
||||
map <string, uint16_t> cmdmap;
|
||||
map <string, uint16_t> charmap;
|
||||
|
||||
void ReadKeyFile(string& keyfname);
|
||||
void ReadMessagesFromText(string& filename);
|
||||
void WriteMessagesToBin(string& filename);
|
||||
u16string EncodeMessage(const string& message, int & i);
|
||||
void CharmapRegisterCharacter(string& code, uint16_t value) override;
|
||||
void CmdmapRegisterCommand(string& command, uint16_t value) override;
|
||||
public:
|
||||
MessagesEncoder(string &_textfilename, string &_keyfilename, string &_charmapfilename, string &_binfilename) : MessagesConverter(_textfilename, _keyfilename, _charmapfilename, _binfilename) {}
|
||||
MessagesEncoder(string &_textfilename, string &_keyfilename, string &_charmapfilename, string &_binfilename) : MessagesConverter(CONV_ENCODE, _textfilename, _keyfilename, _charmapfilename, _binfilename) {}
|
||||
void ReadInput() override;
|
||||
void Convert() override;
|
||||
void WriteOutput() override;
|
||||
|
@ -5,21 +5,44 @@
|
||||
* msgenc TXTFILE KEYFILE CHARMAP OUTFILE
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "MessagesDecoder.h"
|
||||
#include "MessagesEncoder.h"
|
||||
|
||||
static const string version = "2021.08.17";
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
// msgenc TXTFILE KEYFILE CHARMAP OUTFILE
|
||||
if (argc < 6)
|
||||
// msgenc -d|-e TXTFILE KEYFILE CHARMAP OUTFILE
|
||||
if (argc < 2)
|
||||
throw invalid_argument("usage: msgenc -d|-e TXTFILE KEYFILE CHARMAP BINFILE");
|
||||
|
||||
string mode_s(argv[1]);
|
||||
ConvertMode mode;
|
||||
if (mode_s == "-d")
|
||||
mode = CONV_DECODE;
|
||||
else if (mode_s == "-e")
|
||||
mode = CONV_ENCODE;
|
||||
else if (mode_s == "-h") {
|
||||
cout << argv[0] << " v" << version << endl;
|
||||
cout << "Usage: " << argv[0] << " [-h] [-v] -d|-e TEXTFILE KEYFILE CHARMAP BINFILE" << endl;
|
||||
cout << endl;
|
||||
cout << "-d Decode from binary to text, also save the key" << endl;
|
||||
cout << "-e Encode from text to binary using the provided key" << endl;
|
||||
cout << "TEXTFILE Path to the plaintext file to encode (-e) or write (-d)." << endl;
|
||||
cout << "KEYFILE Path to a binary file that encodes the 16-bit encryption key for this message bank." << endl;
|
||||
cout << "CHARMAP Path to a text file with a character mapping, for example pokeheartgold/charmap.txt." << endl;
|
||||
cout << "BINFILE Path to the encoded binary file to decode (-d) or write (-e)." << endl;
|
||||
cout << "-v Print the program version and exit." << endl;
|
||||
cout << "-h Print this message and exit." << endl;
|
||||
return 0;
|
||||
} else if (mode_s == "-v") {
|
||||
cout << argv[0] << " v" << version << endl;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
throw invalid_argument(string("invalid mode: ") + mode_s);
|
||||
if (argc < 6)
|
||||
throw invalid_argument("usage: msgenc -d|-e TXTFILE KEYFILE CHARMAP BINFILE");
|
||||
string textfile(argv[2]);
|
||||
string keyfile(argv[3]);
|
||||
string charmapfile(argv[4]);
|
||||
@ -31,6 +54,7 @@ int main(int argc, char ** argv) {
|
||||
else
|
||||
converter = new MessagesEncoder(textfile, keyfile, charmapfile, binfile);
|
||||
converter->ReadInput();
|
||||
converter->ReadCharmap();
|
||||
converter->Convert();
|
||||
converter->WriteOutput();
|
||||
delete converter;
|
||||
|
Loading…
Reference in New Issue
Block a user