#include #include #include #include #include #include #include #include #include /** Import palladium stb image */ #define STB_IMAGE_IMPLEMENTATION #include #define STB_IMAGE_WRITE_IMPLEMENTATION #include /** Could not use the palladium func due to only using headers */ const std::string FormatBytes(unsigned long long bytes) { if (bytes == 1) { // Only one Byte return std::format("{} Byte", bytes); } else if (bytes < 1024) { // less than one kilobyte return std::format("{} Bytes", bytes); } else if (bytes < 1048576) { // less than one megabyte return std::format("{:.1f} KB", (float)bytes / 1024.f); } else if (bytes < 1073741824) { // less than one gigabyte return std::format("{:.1f} MB", (float)bytes / 1048576.f); } else { // gigabyte return std::format("{:.1f} GB", (float)bytes / 1073741824.f); } } const std::map smdh_lang_table = { {ctrff::SMDH::Language_Japanese, "Japanese"}, {ctrff::SMDH::Language_English, "English"}, {ctrff::SMDH::Language_French, "French"}, {ctrff::SMDH::Language_German, "German"}, {ctrff::SMDH::Language_Italian, "Italian"}, {ctrff::SMDH::Language_Spanish, "Spanish"}, {ctrff::SMDH::Language_Chinese_Simplified, "Chinese Simplified"}, {ctrff::SMDH::Language_Korean, "Korean"}, {ctrff::SMDH::Language_Dutch, "Dutch"}, {ctrff::SMDH::Language_Portuguese, "Portuguese"}, {ctrff::SMDH::Language_Russian, "Russian"}, {ctrff::SMDH::Language_Chinese_Traditional, "Chinese Traditional"}, }; const std::map smdh_rating_table = { {ctrff::SMDH::Rating_CERO, "CERO"}, {ctrff::SMDH::Rating_ESRB, "ESRB"}, {ctrff::SMDH::Rating_USK, "USK"}, {ctrff::SMDH::Rating_PEGI_GEN, "PEGI_GEN"}, {ctrff::SMDH::Rating_PEGI_PTR, "PEGI_PTR"}, {ctrff::SMDH::Rating_PEGI_BBFC, "PEGI_BBFC"}, {ctrff::SMDH::Rating_COB, "COB"}, {ctrff::SMDH::Rating_GRB, "GRB"}, {ctrff::SMDH::Rating_CGSRR, "CGSRR"}, }; const std::map smdh_region_table = { {ctrff::SMDH::Region_JAPAN, "Japan"}, {ctrff::SMDH::Region_NORTH_AMERICA, "North America"}, {ctrff::SMDH::Region_EUROPE, "Europe"}, {ctrff::SMDH::Region_AUSTRALIA, "Australia"}, {ctrff::SMDH::Region_CHINA, "China"}, {ctrff::SMDH::Region_KOREA, "Korea"}, {ctrff::SMDH::Region_TAIWAN, "Taiwan"}, {ctrff::SMDH::Region_FREE, "Free"}, }; const std::map smdh_flag_table{ {ctrff::SMDH::Flag_VISIBLE, "Visible"}, {ctrff::SMDH::Flag_AUTO_BOOT, "Auto Boot"}, {ctrff::SMDH::Flag_ALLOW_3D, "Allow 3D"}, {ctrff::SMDH::Flag_REQUIRE_EULA, "Require EULA"}, {ctrff::SMDH::Flag_AUTO_SAVE_ON_EXIT, "Auto Save on Exit"}, {ctrff::SMDH::Flag_USE_EXTENDED_BANNER, "Use Extended Banner"}, {ctrff::SMDH::Flag_RATING_REQUIED, "Rating required"}, {ctrff::SMDH::Flag_USE_SAVE_DATA, "Use Save Data"}, {ctrff::SMDH::Flag_RECORD_USAGE, "Record usage"}, {ctrff::SMDH::Flag_DISABLE_SAVE_BACKUPS, "Disable Save backups"}, {ctrff::SMDH::Flag_NEW_3DS, "New 3DS"}, }; const std::map smdh_lang_stropts = { {"", ctrff::SMDH::Language_All}, {"jp", ctrff::SMDH::Language_Japanese}, {"en", ctrff::SMDH::Language_English}, {"fr", ctrff::SMDH::Language_French}, {"de", ctrff::SMDH::Language_German}, {"it", ctrff::SMDH::Language_Italian}, {"es", ctrff::SMDH::Language_Spanish}, {"cs", ctrff::SMDH::Language_Chinese_Simplified}, {"ko", ctrff::SMDH::Language_Korean}, {"du", ctrff::SMDH::Language_Dutch}, {"po", ctrff::SMDH::Language_Portuguese}, {"ru", ctrff::SMDH::Language_Russian}, {"ct", ctrff::SMDH::Language_Chinese_Traditional}, }; void MakeSMDH(const cf7::command::ArgumentList &data) { std::string l = cf7::command::GetArg(data, "long"); std::string s = cf7::command::GetArg(data, "short"); std::string a = cf7::command::GetArg(data, "author"); std::string i = cf7::command::GetArg(data, "icon"); std::string o = cf7::command::GetArg(data, "output"); if (l.empty() || s.empty() || a.empty() || i.empty() || o.empty()) { cf7::PrintFancy({ std::make_pair("Error", cf7::col(190, 0, 0)), std::make_pair("One or more Arguments are not set!", cf7::col(130, 0, 0)), }); return; } ctrff::SMDH smdh = ctrff::SMDH::Default(); smdh.SetLongTitle(l); smdh.SetShortTitle(s); smdh.SetAuthor(a); std::vector img; int w, h, c; PD::u8 *buf = stbi_load(i.c_str(), &w, &h, &c, 4); if (buf == nullptr) { cf7::PrintFancy({ std::make_pair("Error", cf7::col(190, 0, 0)), std::make_pair("Can't open icon File!", cf7::col(130, 0, 0)), }); return; } if (w != 48 || h != 48) { cf7::PrintFancy({ std::make_pair("Error", cf7::col(190, 0, 0)), std::make_pair("Icon is not 48x48 pixels!", cf7::col(130, 0, 0)), }); return; } img.assign(buf, buf + (w * h * 4)); smdh.SetIcon(img); std::fstream f(o, std::ios::out | std::ios::binary); smdh.Write(f); cf7::PrintFancy({ std::make_pair("File Generated", cf7::col(0, 190, 0)), }); } void ReadSMDH(const cf7::command::ArgumentList &data) { ctrff::SMDH smdh; if (cf7::command::GetArg(data, "input").empty()) { cf7::PrintFancy({ std::make_pair("Error", cf7::col(190, 0, 0)), std::make_pair("Input Argument not found!", cf7::col(130, 0, 0)), }); return; } try { smdh.Load(cf7::command::GetArg(data, "input")); } catch (const std::exception &e) { cf7::PrintFancy({ std::make_pair("Error", cf7::col(190, 0, 0)), std::make_pair(e.what(), cf7::col(130, 0, 0)), }); return; } cf7::PrintFancy({ std::make_pair("CTRFF", cf7::col(220, 160, 0)), std::make_pair("SMDH-Parser", cf7::col(240, 200, 0)), }); cf7::PrintFancy({ std::make_pair("Language", cf7::col(220, 160, 0)), std::make_pair("Short", cf7::col(240, 200, 0)), std::make_pair("Long", cf7::col(255, 230, 0)), std::make_pair("Author", cf7::col(255, 255, 0)), }); for (auto &e : smdh_lang_table) { cf7::PrintFancy({ std::make_pair(" " + e.second, cf7::col(220, 160, 0)), std::make_pair(smdh.GetShortTitle(e.first), cf7::col(240, 200, 0)), std::make_pair(smdh.GetLongTitle(e.first), cf7::col(255, 230, 0)), std::make_pair(smdh.GetAuthor(e.first), cf7::col(255, 255, 0)), }); } cf7::PrintFancy({ std::make_pair("Version", cf7::col(220, 160, 0)), std::make_pair(std::to_string(smdh.Version), cf7::col(240, 200, 0)), }); cf7::PrintFancy({ std::make_pair("Ratings", cf7::col(220, 160, 0)), }); cf7::PrintFancy({ std::make_pair("Flags", cf7::col(220, 160, 0)), }); for (auto &e : smdh_flag_table) { cf7::PrintFancy({ std::make_pair(" " + e.second, cf7::col(220, 160, 0)), std::make_pair( std::string((smdh.Settings.Flags & e.first) ? "true" : "false"), (smdh.Settings.Flags & e.first) ? cf7::col(0, 190, 0) : cf7::col(190, 0, 0)), }); } if (smdh.Settings.RegionLock == ctrff::SMDH::Region_FREE) { cf7::PrintFancy({ std::make_pair("Region", cf7::col(220, 160, 0)), std::make_pair("Free", cf7::col(240, 200, 0)), }); } else { for (auto &e : smdh_region_table) { cf7::PrintFancy({ std::make_pair("Regions", cf7::col(220, 160, 0)), }); cf7::PrintFancy({ std::make_pair(e.second, cf7::col(220, 160, 0)), std::make_pair( std::string(smdh.Settings.RegionLock & e.first ? "true" : "false"), smdh.Settings.RegionLock & e.first ? cf7::col(0, 190, 0) : cf7::col(190, 0, 0)), }); } } cf7::PrintFancy({ std::make_pair("MatchmakerID", cf7::col(220, 160, 0)), std::make_pair(std::to_string(smdh.Settings.MatchmakerID), cf7::col(240, 200, 0)), }); std::string icon_path = cf7::command::GetArg(data, "extract-icon"); if (!icon_path.empty()) { auto icon = smdh.GetIcon(); stbi_write_png(icon_path.c_str(), 48, 48, 4, icon.data(), 48 * 4); /* if (res) { // Error } else {*/ cf7::PrintFancy({ std::make_pair("Export", cf7::col(0, 190, 0)), std::make_pair(icon_path, cf7::col(0, 130, 0)), std::make_pair("Success", cf7::col(0, 80, 0)), }); // } } } void Read3DSX(const cf7::command::ArgumentList &data) { ctrff::_3dsx _3dsx; if (cf7::command::GetArg(data, "input").empty()) { cf7::PrintFancy({ std::make_pair("Error", cf7::col(190, 0, 0)), std::make_pair("Input Argument not found!", cf7::col(130, 0, 0)), }); return; } /*if (!*/ _3dsx.Load(cf7::command::GetArg(data, "input")); /*) { cf7::PrintFancy({ std::make_pair("Error", cf7::col(190, 0, 0)), std::make_pair("Could not load 3dsx!", cf7::col(130, 0, 0)), }); return; }*/ if (!_3dsx.HasMeta()) { cf7::PrintFancy({ std::make_pair("Error", cf7::col(190, 0, 0)), std::make_pair("3dsx has no meta!", cf7::col(130, 0, 0)), }); return; } ctrff::SMDH smdh = _3dsx.Meta; cf7::PrintFancy({ std::make_pair("CTRFF", cf7::col(220, 160, 0)), std::make_pair("SMDH-Parser", cf7::col(240, 200, 0)), }); cf7::PrintFancy({ std::make_pair("Language", cf7::col(220, 160, 0)), std::make_pair("Short", cf7::col(240, 200, 0)), std::make_pair("Long", cf7::col(255, 230, 0)), std::make_pair("Author", cf7::col(255, 255, 0)), }); for (auto &e : smdh_lang_table) { cf7::PrintFancy({ std::make_pair(" " + e.second, cf7::col(220, 160, 0)), std::make_pair(smdh.GetShortTitle(e.first), cf7::col(240, 200, 0)), std::make_pair(smdh.GetLongTitle(e.first), cf7::col(255, 230, 0)), std::make_pair(smdh.GetAuthor(e.first), cf7::col(255, 255, 0)), }); } cf7::PrintFancy({ std::make_pair("Version", cf7::col(220, 160, 0)), std::make_pair(std::to_string(smdh.Version), cf7::col(240, 200, 0)), }); cf7::PrintFancy({ std::make_pair("Ratings", cf7::col(220, 160, 0)), }); cf7::PrintFancy({ std::make_pair("Flags", cf7::col(220, 160, 0)), }); for (auto &e : smdh_flag_table) { cf7::PrintFancy({ std::make_pair(" " + e.second, cf7::col(220, 160, 0)), std::make_pair( std::string((smdh.Settings.Flags & e.first) ? "true" : "false"), (smdh.Settings.Flags & e.first) ? cf7::col(0, 190, 0) : cf7::col(190, 0, 0)), }); } if (smdh.Settings.RegionLock == ctrff::SMDH::Region_FREE) { cf7::PrintFancy({ std::make_pair("Region", cf7::col(220, 160, 0)), std::make_pair("Free", cf7::col(240, 200, 0)), }); } else { for (auto &e : smdh_region_table) { cf7::PrintFancy({ std::make_pair("Regions", cf7::col(220, 160, 0)), }); cf7::PrintFancy({ std::make_pair(e.second, cf7::col(220, 160, 0)), std::make_pair( std::string(smdh.Settings.RegionLock & e.first ? "true" : "false"), smdh.Settings.RegionLock & e.first ? cf7::col(0, 190, 0) : cf7::col(190, 0, 0)), }); } } cf7::PrintFancy({ std::make_pair("MatchmakerID", cf7::col(220, 160, 0)), std::make_pair(std::to_string(smdh.Settings.MatchmakerID), cf7::col(240, 200, 0)), }); std::string icon_path = cf7::command::GetArg(data, "extract-icon"); if (!icon_path.empty()) { auto icon = smdh.GetIcon(); stbi_write_png(icon_path.c_str(), 48, 48, 4, icon.data(), 48 * 4); /* if (res) { // Error } else {*/ cf7::PrintFancy({ std::make_pair("Export", cf7::col(0, 190, 0)), std::make_pair(icon_path, cf7::col(0, 130, 0)), std::make_pair("Success", cf7::col(0, 80, 0)), }); // } } } void Hex(const cf7::command::ArgumentList &data) { if (cf7::command::GetArg(data, "input").empty()) { cf7::PrintFancy({ std::make_pair("Error", cf7::col(190, 0, 0)), std::make_pair("Input Argument not found!", cf7::col(130, 0, 0)), }); return; } std::ifstream fr(data[0].second, std::ios::binary); if (!fr.is_open()) { cf7::PrintFancy({ std::make_pair("Error", cf7::col(190, 0, 0)), std::make_pair("Failed to open Input File!", cf7::col(130, 0, 0)), }); return; } std::vector buf(std::istreambuf_iterator(fr), {}); fr.close(); cf7::PrintFancy({ std::make_pair("CTRFF HEXDUMP", cf7::col(255, 165, 0)), std::make_pair(data[0].second, cf7::col(255, 210, 0)), std::make_pair(FormatBytes(buf.size()), cf7::col(255, 255, 0)), }); std::cout << "+----------+-------------------------------------------------+-" "-----------------+" << std::endl; std::cout << "| Adress | 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F | " "ASCII |" << std::endl; std::cout << "+----------+-------------------------------------------------+-" "-----------------+" << std::endl; std::cout << "| " << std::hex << std::setw(8) << std::setfill('0') << (unsigned int)0 << " | "; std::vector ascii; int lidx = 0; for (size_t i = 0; i < buf.size(); i++) { lidx++; ascii.push_back((char)buf[i]); std::cout << std::hex << std::setw(2) << std::setfill('0') << std::uppercase << (int)buf[i] << " "; if (((i + 1) % 0x10) == 0 && i > 14) { std::cout << "| "; for (auto &it : ascii) std::cout << std::dec << (((int)it >= 32) && ((int)it <= 126) ? it : '.'); ascii.clear(); std::cout << " |" << std::endl; std::cout << "| " << std::hex << std::setw(8) << std::setfill('0') << (unsigned int)i + 1 << " | "; lidx = 0; } } if (lidx < 16) { for (int i = lidx; i < 16; i++) { ascii.push_back('X'); std::cout << "XX "; if (i == 15) { std::cout << "| "; for (auto &it : ascii) std::cout << std::dec << (((int)it >= 32) && ((int)it <= 126) ? it : '.'); ascii.clear(); std::cout << " |" << std::endl; } } std::cout << "+----------+-------------------------------------------------+-" "-----------------+" << std::endl; } } void LZ11Compress(const cf7::command::ArgumentList &data) { std::string i = cf7::command::GetArg(data, "input"); std::string o = cf7::command::GetArg(data, "output"); std::fstream in(i, std::ios::in | std::ios::binary); in.seekg(0, std::ios::end); size_t s = in.tellg(); in.seekg(0, std::ios::beg); std::vector buf(s); in.read(reinterpret_cast(buf.data()), s); in.close(); cf7::PrintFancy({ std::make_pair("Input", cf7::col(255, 165, 0)), std::make_pair(i, cf7::col(255, 210, 0)), std::make_pair(FormatBytes(buf.size()), cf7::col(255, 255, 0)), }); auto res = ctrff::LZ11::Compress(buf); cf7::PrintFancy({ std::make_pair("Output", cf7::col(255, 165, 0)), std::make_pair(o, cf7::col(255, 210, 0)), std::make_pair(FormatBytes(res.size()), cf7::col(255, 255, 0)), }); std::fstream out(o, std::ios::out | std::ios::binary); out.write(reinterpret_cast(res.data()), res.size()); out.close(); } int main(int argc, char *argv[]) { cf7::fancy_print = true; cf7::colors_supported = true; cf7::arg_mgr mgr(argc, argv); mgr.SetAppInfo("ctrff", "1.0.0"); auto makesmdh_cmd = cf7::command("makesmdh", "Create a SMDH File"); makesmdh_cmd.AddSubEntry( cf7::command::sub("i", "icon", "Icon file path (48x48)", true)); makesmdh_cmd.AddSubEntry( cf7::command::sub("o", "output", "Output smdh path", true)); for (auto &it : smdh_lang_stropts) { if (it.first.empty()) { makesmdh_cmd.AddSubEntry(cf7::command::sub( "s", "short", "Short Title (All Languages)", false)); makesmdh_cmd.AddSubEntry( cf7::command::sub("l", "long", "Long Title (All Languages)", false)); makesmdh_cmd.AddSubEntry( cf7::command::sub("a", "author", "Author (All Languages)", false)); } else { makesmdh_cmd.AddSubEntry(cf7::command::sub( "s-" + it.first, "short-" + it.first, "Short Title " + smdh_lang_table.at(it.second), false)); makesmdh_cmd.AddSubEntry(cf7::command::sub( "l-" + it.first, "long-" + it.first, "Long Title " + smdh_lang_table.at(it.second), false)); makesmdh_cmd.AddSubEntry( cf7::command::sub("a-" + it.first, "author-" + it.first, "Author " + smdh_lang_table.at(it.second), false)); } } makesmdh_cmd.SetFunction(MakeSMDH); mgr.AddCommand(makesmdh_cmd); mgr.AddCommand( cf7::command("readsmdh", "Reads a smdh file and can extract icon") .AddSubEntry( cf7::command::sub("i", "input", "Input smdh path!", true)) .AddSubEntry(cf7::command::sub("e", "extract-icon", "Path to Extract Icon to", false)) .SetFunction(ReadSMDH)); mgr.AddCommand(cf7::command("read3dsx", "Read Data of a 3dsx file") .AddSubEntry(cf7::command::sub("i", "input", "Input 3dsx path!", true)) .AddSubEntry(cf7::command::sub("e", "extract-icon", "Output icon path!", false)) .SetFunction(Read3DSX)); mgr.AddCommand( cf7::command("lz11", "Creates a LZ11 Compressed File") .AddSubEntry(cf7::command::sub("i", "input", "Input file path", true)) .AddSubEntry( cf7::command::sub("o", "output", "Output file path", true)) .SetFunction(LZ11Compress)); mgr.AddCommand( cf7::command("hex", "Show Hex view of a File") .AddSubEntry(cf7::command::sub("i", "input", "Input File path", true)) .SetFunction(Hex)); mgr.Execute(); return 0; }