Skip to content

Commit

Permalink
Proper BMG implementation, other minor cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
XorTroll committed Apr 5, 2024
1 parent 46583c0 commit 89e6629
Show file tree
Hide file tree
Showing 43 changed files with 1,894 additions and 695 deletions.
5 changes: 5 additions & 0 deletions NitroEdit_ds/include/base_Include.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ constexpr ntr::Result ResultUiSpriteInvalidGraphicsData = 0xa003;
constexpr ntr::Result ResultUiUnableToLoadFont = 0xa004;
constexpr ntr::Result ResultUiLodepngDecodeError = 0xa005;

constexpr ntr::Result ResultEditBMGInvalidEscapeByte = 0xa101;
constexpr ntr::Result ResultEditBMGUnexpectedEscapeOpen = 0xa101;
constexpr ntr::Result ResultEditBMGUnexpectedEscapeClose = 0xa101;
constexpr ntr::Result ResultEditBMGUnclosedEscape = 0xa101;

constexpr std::pair<ntr::Result, const char*> ResultDescriptionTable[] = {
{ ResultUiSpriteNotCreated, "UI sprite not created before loading" },
{ ResultUiUnableToAllocateSpriteIndex, "Unable to allocate UI sprite index" },
Expand Down
121 changes: 116 additions & 5 deletions NitroEdit_ds/source/ui/menu/menu_BMGEditMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,94 @@ namespace ui::menu {

ntr::fmt::BMG g_BMG = {};

std::string FormatEscape(const ntr::fmt::BMG::MessageEscape &esc) {
std::stringstream strm;
strm << "{";
for(ntr::u32 i = 0; i < esc.esc_data.size(); i++) {
strm << std::hex << std::uppercase << std::setw(2) << std::setfill('0') << static_cast<ntr::u32>(esc.esc_data.at(i));
if((i + 1) < esc.esc_data.size()) {
strm << "-";
}
}
strm << "}";
return strm.str();
}

ntr::Result BuildMessage(const std::string &input, ntr::fmt::BMG::Message &out_msg) {
out_msg = {};
ntr::fmt::BMG::MessageToken cur_token = {};
std::string cur_escape_byte;

#define _NEDIT_BMG_MSG_BUILD_CHECK_PUSH_TEXT_TOKEN { \
if(cur_token.text.length() > 0) { \
cur_token.type = ntr::fmt::BMG::MessageTokenType::Text; \
out_msg.msg.push_back(cur_token); \
} \
}

#define _NEDIT_BMG_MSG_BUILD_PUSH_ESCAPE_BYTE { \
u32 byte; \
if(ntr::util::ConvertStringToNumber(cur_escape_byte, byte, 16)) { \
cur_token.escape.esc_data.push_back(byte & 0xFF); \
cur_escape_byte = ""; \
} \
else { \
return ResultEditBMGInvalidEscapeByte; \
} \
}

for(const auto &ch: input) {
if(ch == '{') {
if(cur_token.type == ntr::fmt::BMG::MessageTokenType::Escape) {
return ResultEditBMGUnexpectedEscapeOpen;
}

_NEDIT_BMG_MSG_BUILD_CHECK_PUSH_TEXT_TOKEN
cur_token = {
.type = ntr::fmt::BMG::MessageTokenType::Escape
};
}
else if(ch == '}') {
if(cur_token.type != ntr::fmt::BMG::MessageTokenType::Escape) {
return ResultEditBMGUnexpectedEscapeClose;
}

if(!cur_escape_byte.empty()) {
_NEDIT_BMG_MSG_BUILD_PUSH_ESCAPE_BYTE
}

out_msg.msg.push_back(cur_token);
cur_token = {};
}
else if(ch == '-') {
if(cur_token.type != ntr::fmt::BMG::MessageTokenType::Escape) {
return ResultEditBMGUnexpectedEscapeClose;
}
if(cur_escape_byte.empty()) {
return ResultEditBMGInvalidEscapeByte;
}

_NEDIT_BMG_MSG_BUILD_PUSH_ESCAPE_BYTE
}
else {
if(cur_token.type == ntr::fmt::BMG::MessageTokenType::Escape) {
cur_escape_byte += ch;
}
else {
cur_token.text += ch;
}
}
}

if(cur_token.type == ntr::fmt::BMG::MessageTokenType::Escape) {
return ResultEditBMGUnclosedEscape;
}

_NEDIT_BMG_MSG_BUILD_CHECK_PUSH_TEXT_TOKEN

NTR_R_SUCCEED();
}

void OnOtherInput(const u32 k_down) {
if(k_down & KEY_B) {
const auto res = ShowSaveConfirmationDialog();
Expand Down Expand Up @@ -39,18 +127,41 @@ namespace ui::menu {
.newline_allowed = true,
.max_len = 0
};
auto edit_str = ntr::util::ConvertFromUnicode(g_BMG.messages[idx].msg_str);
if(ShowKeyboard(ctx, edit_str)) {
g_BMG.messages[idx].msg_str = ntr::util::ConvertToUnicode(edit_str);
ReloadBMGEditMenu();

const auto &cur_msg = g_BMG.messages.at(idx);

std::string edit_msg_str;
for(const auto &msg_token: cur_msg.msg) {
switch(msg_token.type) {
case ntr::fmt::BMG::MessageTokenType::Escape: {
edit_msg_str += FormatEscape(msg_token.escape);
break;
}
case ntr::fmt::BMG::MessageTokenType::Text: {
const auto utf8_text = ntr::util::ConvertFromUnicode(msg_token.text);
edit_msg_str += utf8_text;
break;
}
}
}

if(ShowKeyboard(ctx, edit_msg_str)) {
ntr::fmt::BMG::Message new_msg;
const auto rc = BuildMessage(edit_msg_str, new_msg);
if(rc.IsSuccess()) {
std::swap(g_BMG.messages.at(idx), new_msg);
ReloadBMGEditMenu();
}
else {
ShowOkDialog("Unable to save message:\n'" + FormatResult(rc) + "'");
}
}
}

void ReloadBMGEditMenu() {
std::vector<ScrollMenuEntry> entries;
auto text_icon_gfx = GetTextIcon();
for(u32 i = 0; i < g_BMG.messages.size(); i++) {
const auto str = ntr::util::ConvertFromUnicode(g_BMG.messages[i].msg_str);
entries.push_back({
.icon_gfx = text_icon_gfx,
.text = "Message " + std::to_string(i),
Expand Down
128 changes: 119 additions & 9 deletions NitroEdit_pc/modules/Bmg/source/mod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <ntr/util/util_String.hpp>
#include <iomanip>
#include <fstream>
#include <sstream>

namespace {

Expand All @@ -26,6 +27,114 @@ namespace {
return "<unk>";
}

std::string FormatEscape(const ntr::fmt::BMG::MessageEscape &esc) {
std::stringstream strm;
strm << "{";
for(ntr::u32 i = 0; i < esc.esc_data.size(); i++) {
strm << std::hex << std::uppercase << std::setw(2) << std::setfill('0') << static_cast<ntr::u32>(esc.esc_data.at(i));
if((i + 1) < esc.esc_data.size()) {
strm << "-";
}
}
strm << "}";
return strm.str();
}

bool BuildMessage(const std::string &input, ntr::fmt::BMG::Message &out_msg) {
out_msg = {};
ntr::fmt::BMG::MessageToken cur_token = {};
std::string cur_escape_byte;

#define _NEDIT_MOD_BMG_MSG_BUILD_CHECK_PUSH_TEXT_TOKEN \
if(cur_token.text.length() > 0) { \
cur_token.type = ntr::fmt::BMG::MessageTokenType::Text; \
out_msg.msg.push_back(cur_token); \
}

#define _NEDIT_MOD_BMG_MSG_BUILD_PUSH_ESCAPE_BYTE \
try { \
int byte = std::stoi(cur_escape_byte, nullptr, 16); \
cur_token.escape.esc_data.push_back(byte & 0xFF); \
cur_escape_byte = ""; \
} \
catch(std::exception&) { \
std::cerr << "Formatting error: invalid escape byte supplied (" << cur_escape_byte << "), they must be in hexadecimal like here: {FF-00-AA-12}" << std::endl; \
return false; \
}

for(const auto &ch: input) {
if(ch == '{') {
if(cur_token.type == ntr::fmt::BMG::MessageTokenType::Escape) {
std::cerr << "Formatting error: parsed escape opening symbol '{' with an already opened escape" << std::endl;
return false;
}

_NEDIT_MOD_BMG_MSG_BUILD_CHECK_PUSH_TEXT_TOKEN
cur_token = {
.type = ntr::fmt::BMG::MessageTokenType::Escape
};
}
else if(ch == '}') {
if(cur_token.type != ntr::fmt::BMG::MessageTokenType::Escape) {
std::cerr << "Formatting error: parsed escape closing symbol '}' without any previous escape opening symbol '{'" << std::endl;
return false;
}

if(!cur_escape_byte.empty()) {
_NEDIT_MOD_BMG_MSG_BUILD_PUSH_ESCAPE_BYTE
}

out_msg.msg.push_back(cur_token);
cur_token = {};
}
else if(ch == '-') {
if(cur_token.type != ntr::fmt::BMG::MessageTokenType::Escape) {
std::cerr << "Formatting error: parsed escape closing symbol '}' without any previous escape opening symbol '{'" << std::endl;
return false;
}
if(cur_escape_byte.empty()) {
std::cerr << "Formatting error: found empty escape byte" << std::endl;
return false;
}

_NEDIT_MOD_BMG_MSG_BUILD_PUSH_ESCAPE_BYTE
}
else {
if(cur_token.type == ntr::fmt::BMG::MessageTokenType::Escape) {
cur_escape_byte += ch;
}
else {
cur_token.text += ch;
}
}
}

if(cur_token.type == ntr::fmt::BMG::MessageTokenType::Escape) {
std::cerr << "Formatting error: reached end with unclosed escape" << std::endl;
return false;
}

_NEDIT_MOD_BMG_MSG_BUILD_CHECK_PUSH_TEXT_TOKEN

return true;
}

void PrintMessage(const ntr::fmt::BMG::Message &msg) {
for(const auto &msg_token: msg.msg) {
switch(msg_token.type) {
case ntr::fmt::BMG::MessageTokenType::Escape: {
std::cout << FormatEscape(msg_token.escape);
break;
}
case ntr::fmt::BMG::MessageTokenType::Text: {
const auto utf8_text = ntr::util::ConvertFromUnicode(msg_token.text);
std::cout << utf8_text;
break;
}
}
}
}

bool ReadEncoding(const std::string &enc_str, ntr::fmt::BMG::Encoding &out_enc) {
const auto enc_l_str = ntr::util::ToLowerString(enc_str);

Expand All @@ -52,8 +161,7 @@ namespace {
std::cout << " - Messages:" << std::endl;
}
for(const auto &msg: bmg.messages) {
const auto utf8_str = ntr::util::ConvertFromUnicode(msg.msg_str);
std::cout << utf8_str;
PrintMessage(msg);

if(verbose) {
if(bmg.info.GetAttributesSize() > 0) {
Expand All @@ -62,6 +170,7 @@ namespace {
std::cout << std::hex << std::setfill('0') << std::setw(2) << static_cast<ntr::u32>(attr_byte);
}
std::cout << ")";

}
}

Expand Down Expand Up @@ -93,9 +202,8 @@ namespace {
if(rc.IsSuccess()) {
if(idx < bmg.messages.size()) {
const auto &msg = bmg.messages.at(idx);

const auto utf8_str = ntr::util::ConvertFromUnicode(msg.msg_str);
std::cout << utf8_str << std::endl;
PrintMessage(msg);
std::cout << std::endl;
}
else {
std::cerr << "Invalid index supplied (out of bounds): BMG only has " << bmg.messages.size() << " messages..." << std::endl;
Expand Down Expand Up @@ -123,10 +231,12 @@ namespace {
std::vector<ntr::fmt::BMG::Message> msgs;
std::string txt_str;
while(std::getline(ifs, txt_str)) {
const ntr::fmt::BMG::Message msg = {
.msg_str = ntr::util::ConvertToUnicode(txt_str),
.attrs = {}
};
ntr::fmt::BMG::Message msg;

if(!BuildMessage(txt_str, msg)) {
return;
}

msgs.push_back(msg);
}

Expand Down
3 changes: 3 additions & 0 deletions docs/annotated.html
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@
<tr id="row_0_0_1_1_" class="even" style="display:none;"><td class="entry"><span style="width:64px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="structntr_1_1fmt_1_1BMG_1_1Header.html" target="_self">Header</a></td><td class="desc"></td></tr>
<tr id="row_0_0_1_2_" class="even" style="display:none;"><td class="entry"><span style="width:64px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="structntr_1_1fmt_1_1BMG_1_1InfoSection.html" target="_self">InfoSection</a></td><td class="desc"></td></tr>
<tr id="row_0_0_1_3_" class="even" style="display:none;"><td class="entry"><span style="width:64px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="structntr_1_1fmt_1_1BMG_1_1Message.html" target="_self">Message</a></td><td class="desc"></td></tr>
<tr id="row_0_0_1_4_" class="even" style="display:none;"><td class="entry"><span style="width:64px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="structntr_1_1fmt_1_1BMG_1_1MessageEscape.html" target="_self">MessageEscape</a></td><td class="desc"></td></tr>
<tr id="row_0_0_1_5_" class="even" style="display:none;"><td class="entry"><span style="width:64px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="structntr_1_1fmt_1_1BMG_1_1MessageIdSection.html" target="_self">MessageIdSection</a></td><td class="desc"></td></tr>
<tr id="row_0_0_1_6_" class="even" style="display:none;"><td class="entry"><span style="width:64px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="structntr_1_1fmt_1_1BMG_1_1MessageToken.html" target="_self">MessageToken</a></td><td class="desc"></td></tr>
<tr id="row_0_0_2_" class="even"><td class="entry"><span style="width:48px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="structntr_1_1fmt_1_1CommonBlock.html" target="_self">CommonBlock</a></td><td class="desc"></td></tr>
<tr id="row_0_0_3_" class="odd"><td class="entry"><span style="width:48px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="structntr_1_1fmt_1_1CommonHeader.html" target="_self">CommonHeader</a></td><td class="desc"></td></tr>
<tr id="row_0_0_4_" class="even"><td class="entry"><span style="width:48px;display:inline-block;">&#160;</span><span class="icona"><span class="icon">C</span></span><a class="el" href="structntr_1_1fmt_1_1CommonMultiMagicHeader.html" target="_self">CommonMultiMagicHeader</a></td><td class="desc"></td></tr>
Expand Down
2 changes: 1 addition & 1 deletion docs/classes.html
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@
<dd><a class="el" href="structntr_1_1fmt_1_1SBNK_1_1KeySplit.html">SBNK::KeySplit</a> (ntr::fmt)</dd><dd><a class="el" href="structntr_1_1fmt_1_1SBNK_1_1KeySplitHeader.html">SBNK::KeySplitHeader</a> (ntr::fmt)</dd></dl>
<dl class="classindex odd">
<dt class="alphachar"><a id="letter_M" name="letter_M">M</a></dt>
<dd><a class="el" href="structntr_1_1fmt_1_1MagicStartBase.html">MagicStartBase</a> (ntr::fmt)</dd><dd><a class="el" href="structntr_1_1fmt_1_1BMG_1_1Message.html">BMG::Message</a> (ntr::fmt)</dd><dd><a class="el" href="structntr_1_1fmt_1_1MultiMagicStartBase.html">MultiMagicStartBase</a> (ntr::fmt)</dd></dl>
<dd><a class="el" href="structntr_1_1fmt_1_1MagicStartBase.html">MagicStartBase</a> (ntr::fmt)</dd><dd><a class="el" href="structntr_1_1fmt_1_1BMG_1_1Message.html">BMG::Message</a> (ntr::fmt)</dd><dd><a class="el" href="structntr_1_1fmt_1_1BMG_1_1MessageEscape.html">BMG::MessageEscape</a> (ntr::fmt)</dd><dd><a class="el" href="structntr_1_1fmt_1_1BMG_1_1MessageIdSection.html">BMG::MessageIdSection</a> (ntr::fmt)</dd><dd><a class="el" href="structntr_1_1fmt_1_1BMG_1_1MessageToken.html">BMG::MessageToken</a> (ntr::fmt)</dd><dd><a class="el" href="structntr_1_1fmt_1_1MultiMagicStartBase.html">MultiMagicStartBase</a> (ntr::fmt)</dd></dl>
<dl class="classindex even">
<dt class="alphachar"><a id="letter_N" name="letter_N">N</a></dt>
<dd><a class="el" href="structntr_1_1fmt_1_1NARC.html">NARC</a> (ntr::fmt)</dd><dd><a class="el" href="structntr_1_1fmt_1_1NCGR.html">NCGR</a> (ntr::fmt)</dd><dd><a class="el" href="structntr_1_1fmt_1_1NCLR.html">NCLR</a> (ntr::fmt)</dd><dd><a class="el" href="structntr_1_1fmt_1_1nfs_1_1NitroDirectory.html">NitroDirectory</a> (ntr::fmt::nfs)</dd><dd><a class="el" href="structntr_1_1fmt_1_1nfs_1_1NitroEntryBase.html">NitroEntryBase</a> (ntr::fmt::nfs)</dd><dd><a class="el" href="structntr_1_1fmt_1_1nfs_1_1NitroFile.html">NitroFile</a> (ntr::fmt::nfs)</dd><dd><a class="el" href="structntr_1_1fmt_1_1nfs_1_1NitroFsFileFormat.html">NitroFsFileFormat</a> (ntr::fmt::nfs)</dd><dd><a class="el" href="structntr_1_1fmt_1_1nfs_1_1NitroFsFileHandle.html">NitroFsFileHandle</a> (ntr::fmt::nfs)</dd><dd><a class="el" href="structntr_1_1fmt_1_1NSCR.html">NSCR</a> (ntr::fmt)</dd></dl>
Expand Down
6 changes: 6 additions & 0 deletions docs/doxygen_crawl.html
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@
<a href="structntr_1_1fmt_1_1BMG_1_1InfoSection-members.html"/>
<a href="structntr_1_1fmt_1_1BMG_1_1Message.html"/>
<a href="structntr_1_1fmt_1_1BMG_1_1Message-members.html"/>
<a href="structntr_1_1fmt_1_1BMG_1_1MessageEscape.html"/>
<a href="structntr_1_1fmt_1_1BMG_1_1MessageEscape-members.html"/>
<a href="structntr_1_1fmt_1_1BMG_1_1MessageIdSection.html"/>
<a href="structntr_1_1fmt_1_1BMG_1_1MessageIdSection-members.html"/>
<a href="structntr_1_1fmt_1_1BMG_1_1MessageToken.html"/>
<a href="structntr_1_1fmt_1_1BMG_1_1MessageToken-members.html"/>
<a href="structntr_1_1fmt_1_1CommonBlock.html"/>
<a href="structntr_1_1fmt_1_1CommonBlock-members.html"/>
<a href="structntr_1_1fmt_1_1CommonHeader.html"/>
Expand Down
Loading

0 comments on commit 89e6629

Please sign in to comment.