#include #include #include "Core/HLE/sceReg.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/ErrorCodes.h" #include "Common/Serialize/Serializer.h" #include "Common/Serialize/SerializeMap.h" #include "Common/StringUtils.h" #define SYSTEM_REGISTRY "/system" #define REG_KEYNAME_SIZE 27 enum RegKeyTypes { REG_TYPE_DIR = 1, REG_TYPE_INT = 2, REG_TYPE_STR = 3, REG_TYPE_BIN = 4, }; typedef unsigned int REGHANDLE; struct RegParam { unsigned int regtype; /* 0x0, set to 1 only for system */ char name[256]; /* 0x4-0x104 */ unsigned int namelen; /* 0x104 */ unsigned int unk2; /* 0x108 */ unsigned int unk3; /* 0x10C */ }; struct OpenCategory { std::string path; int openMode; void DoState(PointerWrap &p) { Do(p, path); Do(p, openMode); } }; static int g_openRegistryMode; static int g_handleGen; // TODO: The real PSP seems to use memory addresses. Probably it's doing allocations, which we don't really want to do unless we can match them exactly. static std::map g_openCategories; enum class ValueType { FAIL = 0, DIR = 1, INT = 2, STR = 3, BIN = 4, }; struct KeyValue { std::string name; ValueType type; std::string strValue; // also can be used for bin int intValue; const KeyValue *dirContents; // intValue is the count. }; // Dump of the PSP registry using tests/misc/reg.prx in pspautotests // TODO: /DATA/FONT/PROPERTY could just be generated from our fontRegistry in sceFont.cpp. // Dump of /DATA/FONT/PROPERTY/INFO0 static const KeyValue tree_DATA_FONT_PROPERTY_INFO0[] = { { "h_size", ValueType::INT, "", (int)0x00000288 }, { "v_size", ValueType::INT, "", (int)0x00000288 }, { "h_resolution", ValueType::INT, "", (int)0x00002000 }, { "v_resolution", ValueType::INT, "", (int)0x00002000 }, { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, { "weight", ValueType::INT, "", (int)0x00000000 }, { "family_code", ValueType::INT, "", (int)0x00000001 }, { "style", ValueType::INT, "", (int)0x00000067 }, { "sub_style", ValueType::INT, "", (int)0x00000000 }, { "language_code", ValueType::INT, "", (int)0x00000001 }, { "region_code", ValueType::INT, "", (int)0x00000000 }, { "country_code", ValueType::INT, "", (int)0x00000001 }, { "font_name", ValueType::STR, "FTT-NewRodin Pro DB" }, { "file_name", ValueType::STR, "jpn0.pgf" }, { "expire_date", ValueType::INT, "", (int)0x00000000 }, { "shadow_option", ValueType::INT, "", (int)0x00000000 }, }; // Dump of /DATA/FONT/PROPERTY/INFO1 static const KeyValue tree_DATA_FONT_PROPERTY_INFO1[] = { { "h_size", ValueType::INT, "", (int)0x00000288 }, { "v_size", ValueType::INT, "", (int)0x00000288 }, { "h_resolution", ValueType::INT, "", (int)0x00002000 }, { "v_resolution", ValueType::INT, "", (int)0x00002000 }, { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, { "weight", ValueType::INT, "", (int)0x00000000 }, { "family_code", ValueType::INT, "", (int)0x00000001 }, { "style", ValueType::INT, "", (int)0x00000001 }, { "sub_style", ValueType::INT, "", (int)0x00000000 }, { "language_code", ValueType::INT, "", (int)0x00000002 }, { "region_code", ValueType::INT, "", (int)0x00000000 }, { "country_code", ValueType::INT, "", (int)0x00000001 }, { "font_name", ValueType::STR, "FTT-NewRodin Pro Latin" }, { "file_name", ValueType::STR, "ltn0.pgf" }, { "expire_date", ValueType::INT, "", (int)0x00000000 }, { "shadow_option", ValueType::INT, "", (int)0x00000000 }, }; // Dump of /DATA/FONT/PROPERTY/INFO2 static const KeyValue tree_DATA_FONT_PROPERTY_INFO2[] = { { "h_size", ValueType::INT, "", (int)0x00000288 }, { "v_size", ValueType::INT, "", (int)0x00000288 }, { "h_resolution", ValueType::INT, "", (int)0x00002000 }, { "v_resolution", ValueType::INT, "", (int)0x00002000 }, { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, { "weight", ValueType::INT, "", (int)0x00000000 }, { "family_code", ValueType::INT, "", (int)0x00000002 }, { "style", ValueType::INT, "", (int)0x00000001 }, { "sub_style", ValueType::INT, "", (int)0x00000000 }, { "language_code", ValueType::INT, "", (int)0x00000002 }, { "region_code", ValueType::INT, "", (int)0x00000000 }, { "country_code", ValueType::INT, "", (int)0x00000001 }, { "font_name", ValueType::STR, "FTT-Matisse Pro Latin" }, { "file_name", ValueType::STR, "ltn1.pgf" }, { "expire_date", ValueType::INT, "", (int)0x00000000 }, { "shadow_option", ValueType::INT, "", (int)0x00000000 }, }; // Dump of /DATA/FONT/PROPERTY/INFO3 static const KeyValue tree_DATA_FONT_PROPERTY_INFO3[] = { { "h_size", ValueType::INT, "", (int)0x00000288 }, { "v_size", ValueType::INT, "", (int)0x00000288 }, { "h_resolution", ValueType::INT, "", (int)0x00002000 }, { "v_resolution", ValueType::INT, "", (int)0x00002000 }, { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, { "weight", ValueType::INT, "", (int)0x00000000 }, { "family_code", ValueType::INT, "", (int)0x00000001 }, { "style", ValueType::INT, "", (int)0x00000002 }, { "sub_style", ValueType::INT, "", (int)0x00000000 }, { "language_code", ValueType::INT, "", (int)0x00000002 }, { "region_code", ValueType::INT, "", (int)0x00000000 }, { "country_code", ValueType::INT, "", (int)0x00000001 }, { "font_name", ValueType::STR, "FTT-NewRodin Pro Latin" }, { "file_name", ValueType::STR, "ltn2.pgf" }, { "expire_date", ValueType::INT, "", (int)0x00000000 }, { "shadow_option", ValueType::INT, "", (int)0x00000000 }, }; // Dump of /DATA/FONT/PROPERTY/INFO4 static const KeyValue tree_DATA_FONT_PROPERTY_INFO4[] = { { "h_size", ValueType::INT, "", (int)0x00000288 }, { "v_size", ValueType::INT, "", (int)0x00000288 }, { "h_resolution", ValueType::INT, "", (int)0x00002000 }, { "v_resolution", ValueType::INT, "", (int)0x00002000 }, { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, { "weight", ValueType::INT, "", (int)0x00000000 }, { "family_code", ValueType::INT, "", (int)0x00000002 }, { "style", ValueType::INT, "", (int)0x00000002 }, { "sub_style", ValueType::INT, "", (int)0x00000000 }, { "language_code", ValueType::INT, "", (int)0x00000002 }, { "region_code", ValueType::INT, "", (int)0x00000000 }, { "country_code", ValueType::INT, "", (int)0x00000001 }, { "font_name", ValueType::STR, "FTT-Matisse Pro Latin" }, { "file_name", ValueType::STR, "ltn3.pgf" }, { "expire_date", ValueType::INT, "", (int)0x00000000 }, { "shadow_option", ValueType::INT, "", (int)0x00000000 }, }; // Dump of /DATA/FONT/PROPERTY/INFO5 static const KeyValue tree_DATA_FONT_PROPERTY_INFO5[] = { { "h_size", ValueType::INT, "", (int)0x00000288 }, { "v_size", ValueType::INT, "", (int)0x00000288 }, { "h_resolution", ValueType::INT, "", (int)0x00002000 }, { "v_resolution", ValueType::INT, "", (int)0x00002000 }, { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, { "weight", ValueType::INT, "", (int)0x00000000 }, { "family_code", ValueType::INT, "", (int)0x00000001 }, { "style", ValueType::INT, "", (int)0x00000005 }, { "sub_style", ValueType::INT, "", (int)0x00000000 }, { "language_code", ValueType::INT, "", (int)0x00000002 }, { "region_code", ValueType::INT, "", (int)0x00000000 }, { "country_code", ValueType::INT, "", (int)0x00000001 }, { "font_name", ValueType::STR, "FTT-NewRodin Pro Latin" }, { "file_name", ValueType::STR, "ltn4.pgf" }, { "expire_date", ValueType::INT, "", (int)0x00000000 }, { "shadow_option", ValueType::INT, "", (int)0x00000000 }, }; // Dump of /DATA/FONT/PROPERTY/INFO6 static const KeyValue tree_DATA_FONT_PROPERTY_INFO6[] = { { "h_size", ValueType::INT, "", (int)0x00000288 }, { "v_size", ValueType::INT, "", (int)0x00000288 }, { "h_resolution", ValueType::INT, "", (int)0x00002000 }, { "v_resolution", ValueType::INT, "", (int)0x00002000 }, { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, { "weight", ValueType::INT, "", (int)0x00000000 }, { "family_code", ValueType::INT, "", (int)0x00000002 }, { "style", ValueType::INT, "", (int)0x00000005 }, { "sub_style", ValueType::INT, "", (int)0x00000000 }, { "language_code", ValueType::INT, "", (int)0x00000002 }, { "region_code", ValueType::INT, "", (int)0x00000000 }, { "country_code", ValueType::INT, "", (int)0x00000001 }, { "font_name", ValueType::STR, "FTT-Matisse Pro Latin" }, { "file_name", ValueType::STR, "ltn5.pgf" }, { "expire_date", ValueType::INT, "", (int)0x00000000 }, { "shadow_option", ValueType::INT, "", (int)0x00000000 }, }; // Dump of /DATA/FONT/PROPERTY/INFO7 static const KeyValue tree_DATA_FONT_PROPERTY_INFO7[] = { { "h_size", ValueType::INT, "", (int)0x00000288 }, { "v_size", ValueType::INT, "", (int)0x00000288 }, { "h_resolution", ValueType::INT, "", (int)0x00002000 }, { "v_resolution", ValueType::INT, "", (int)0x00002000 }, { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, { "weight", ValueType::INT, "", (int)0x00000000 }, { "family_code", ValueType::INT, "", (int)0x00000001 }, { "style", ValueType::INT, "", (int)0x00000006 }, { "sub_style", ValueType::INT, "", (int)0x00000000 }, { "language_code", ValueType::INT, "", (int)0x00000002 }, { "region_code", ValueType::INT, "", (int)0x00000000 }, { "country_code", ValueType::INT, "", (int)0x00000001 }, { "font_name", ValueType::STR, "FTT-NewRodin Pro Latin" }, { "file_name", ValueType::STR, "ltn6.pgf" }, { "expire_date", ValueType::INT, "", (int)0x00000000 }, { "shadow_option", ValueType::INT, "", (int)0x00000000 }, }; // Dump of /DATA/FONT/PROPERTY/INFO8 static const KeyValue tree_DATA_FONT_PROPERTY_INFO8[] = { { "h_size", ValueType::INT, "", (int)0x00000288 }, { "v_size", ValueType::INT, "", (int)0x00000288 }, { "h_resolution", ValueType::INT, "", (int)0x00002000 }, { "v_resolution", ValueType::INT, "", (int)0x00002000 }, { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, { "weight", ValueType::INT, "", (int)0x00000000 }, { "family_code", ValueType::INT, "", (int)0x00000002 }, { "style", ValueType::INT, "", (int)0x00000006 }, { "sub_style", ValueType::INT, "", (int)0x00000000 }, { "language_code", ValueType::INT, "", (int)0x00000002 }, { "region_code", ValueType::INT, "", (int)0x00000000 }, { "country_code", ValueType::INT, "", (int)0x00000001 }, { "font_name", ValueType::STR, "FTT-Matisse Pro Latin" }, { "file_name", ValueType::STR, "ltn7.pgf" }, { "expire_date", ValueType::INT, "", (int)0x00000000 }, { "shadow_option", ValueType::INT, "", (int)0x00000000 }, }; // Dump of /DATA/FONT/PROPERTY/INFO9 static const KeyValue tree_DATA_FONT_PROPERTY_INFO9[] = { { "h_size", ValueType::INT, "", (int)0x000001c0 }, { "v_size", ValueType::INT, "", (int)0x000001c0 }, { "h_resolution", ValueType::INT, "", (int)0x00002000 }, { "v_resolution", ValueType::INT, "", (int)0x00002000 }, { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, { "weight", ValueType::INT, "", (int)0x00000000 }, { "family_code", ValueType::INT, "", (int)0x00000001 }, { "style", ValueType::INT, "", (int)0x00000001 }, { "sub_style", ValueType::INT, "", (int)0x00000000 }, { "language_code", ValueType::INT, "", (int)0x00000002 }, { "region_code", ValueType::INT, "", (int)0x00000000 }, { "country_code", ValueType::INT, "", (int)0x00000001 }, { "font_name", ValueType::STR, "FTT-NewRodin Pro Latin" }, { "file_name", ValueType::STR, "ltn8.pgf" }, { "expire_date", ValueType::INT, "", (int)0x00000000 }, { "shadow_option", ValueType::INT, "", (int)0x00000000 }, }; // Dump of /DATA/FONT/PROPERTY/INFO10 static const KeyValue tree_DATA_FONT_PROPERTY_INFO10[] = { { "h_size", ValueType::INT, "", (int)0x000001c0 }, { "v_size", ValueType::INT, "", (int)0x000001c0 }, { "h_resolution", ValueType::INT, "", (int)0x00002000 }, { "v_resolution", ValueType::INT, "", (int)0x00002000 }, { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, { "weight", ValueType::INT, "", (int)0x00000000 }, { "family_code", ValueType::INT, "", (int)0x00000002 }, { "style", ValueType::INT, "", (int)0x00000001 }, { "sub_style", ValueType::INT, "", (int)0x00000000 }, { "language_code", ValueType::INT, "", (int)0x00000002 }, { "region_code", ValueType::INT, "", (int)0x00000000 }, { "country_code", ValueType::INT, "", (int)0x00000001 }, { "font_name", ValueType::STR, "FTT-Matisse Pro Latin" }, { "file_name", ValueType::STR, "ltn9.pgf" }, { "expire_date", ValueType::INT, "", (int)0x00000000 }, { "shadow_option", ValueType::INT, "", (int)0x00000000 }, }; // Dump of /DATA/FONT/PROPERTY/INFO11 static const KeyValue tree_DATA_FONT_PROPERTY_INFO11[] = { { "h_size", ValueType::INT, "", (int)0x000001c0 }, { "v_size", ValueType::INT, "", (int)0x000001c0 }, { "h_resolution", ValueType::INT, "", (int)0x00002000 }, { "v_resolution", ValueType::INT, "", (int)0x00002000 }, { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, { "weight", ValueType::INT, "", (int)0x00000000 }, { "family_code", ValueType::INT, "", (int)0x00000001 }, { "style", ValueType::INT, "", (int)0x00000002 }, { "sub_style", ValueType::INT, "", (int)0x00000000 }, { "language_code", ValueType::INT, "", (int)0x00000002 }, { "region_code", ValueType::INT, "", (int)0x00000000 }, { "country_code", ValueType::INT, "", (int)0x00000001 }, { "font_name", ValueType::STR, "FTT-NewRodin Pro Latin" }, { "file_name", ValueType::STR, "ltn10.pgf" }, { "expire_date", ValueType::INT, "", (int)0x00000000 }, { "shadow_option", ValueType::INT, "", (int)0x00000000 }, }; // Dump of /DATA/FONT/PROPERTY/INFO12 static const KeyValue tree_DATA_FONT_PROPERTY_INFO12[] = { { "h_size", ValueType::INT, "", (int)0x000001c0 }, { "v_size", ValueType::INT, "", (int)0x000001c0 }, { "h_resolution", ValueType::INT, "", (int)0x00002000 }, { "v_resolution", ValueType::INT, "", (int)0x00002000 }, { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, { "weight", ValueType::INT, "", (int)0x00000000 }, { "family_code", ValueType::INT, "", (int)0x00000002 }, { "style", ValueType::INT, "", (int)0x00000002 }, { "sub_style", ValueType::INT, "", (int)0x00000000 }, { "language_code", ValueType::INT, "", (int)0x00000002 }, { "region_code", ValueType::INT, "", (int)0x00000000 }, { "country_code", ValueType::INT, "", (int)0x00000001 }, { "font_name", ValueType::STR, "FTT-Matisse Pro Latin" }, { "file_name", ValueType::STR, "ltn11.pgf" }, { "expire_date", ValueType::INT, "", (int)0x00000000 }, { "shadow_option", ValueType::INT, "", (int)0x00000000 }, }; // Dump of /DATA/FONT/PROPERTY/INFO13 static const KeyValue tree_DATA_FONT_PROPERTY_INFO13[] = { { "h_size", ValueType::INT, "", (int)0x000001c0 }, { "v_size", ValueType::INT, "", (int)0x000001c0 }, { "h_resolution", ValueType::INT, "", (int)0x00002000 }, { "v_resolution", ValueType::INT, "", (int)0x00002000 }, { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, { "weight", ValueType::INT, "", (int)0x00000000 }, { "family_code", ValueType::INT, "", (int)0x00000001 }, { "style", ValueType::INT, "", (int)0x00000005 }, { "sub_style", ValueType::INT, "", (int)0x00000000 }, { "language_code", ValueType::INT, "", (int)0x00000002 }, { "region_code", ValueType::INT, "", (int)0x00000000 }, { "country_code", ValueType::INT, "", (int)0x00000001 }, { "font_name", ValueType::STR, "FTT-NewRodin Pro Latin" }, { "file_name", ValueType::STR, "ltn12.pgf" }, { "expire_date", ValueType::INT, "", (int)0x00000000 }, { "shadow_option", ValueType::INT, "", (int)0x00000000 }, }; // Dump of /DATA/FONT/PROPERTY/INFO14 static const KeyValue tree_DATA_FONT_PROPERTY_INFO14[] = { { "h_size", ValueType::INT, "", (int)0x000001c0 }, { "v_size", ValueType::INT, "", (int)0x000001c0 }, { "h_resolution", ValueType::INT, "", (int)0x00002000 }, { "v_resolution", ValueType::INT, "", (int)0x00002000 }, { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, { "weight", ValueType::INT, "", (int)0x00000000 }, { "family_code", ValueType::INT, "", (int)0x00000002 }, { "style", ValueType::INT, "", (int)0x00000005 }, { "sub_style", ValueType::INT, "", (int)0x00000000 }, { "language_code", ValueType::INT, "", (int)0x00000002 }, { "region_code", ValueType::INT, "", (int)0x00000000 }, { "country_code", ValueType::INT, "", (int)0x00000001 }, { "font_name", ValueType::STR, "FTT-Matisse Pro Latin" }, { "file_name", ValueType::STR, "ltn13.pgf" }, { "expire_date", ValueType::INT, "", (int)0x00000000 }, { "shadow_option", ValueType::INT, "", (int)0x00000000 }, }; // Dump of /DATA/FONT/PROPERTY/INFO15 static const KeyValue tree_DATA_FONT_PROPERTY_INFO15[] = { { "h_size", ValueType::INT, "", (int)0x000001c0 }, { "v_size", ValueType::INT, "", (int)0x000001c0 }, { "h_resolution", ValueType::INT, "", (int)0x00002000 }, { "v_resolution", ValueType::INT, "", (int)0x00002000 }, { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, { "weight", ValueType::INT, "", (int)0x00000000 }, { "family_code", ValueType::INT, "", (int)0x00000001 }, { "style", ValueType::INT, "", (int)0x00000006 }, { "sub_style", ValueType::INT, "", (int)0x00000000 }, { "language_code", ValueType::INT, "", (int)0x00000002 }, { "region_code", ValueType::INT, "", (int)0x00000000 }, { "country_code", ValueType::INT, "", (int)0x00000001 }, { "font_name", ValueType::STR, "FTT-NewRodin Pro Latin" }, { "file_name", ValueType::STR, "ltn14.pgf" }, { "expire_date", ValueType::INT, "", (int)0x00000000 }, { "shadow_option", ValueType::INT, "", (int)0x00000000 }, }; // Dump of /DATA/FONT/PROPERTY/INFO16 static const KeyValue tree_DATA_FONT_PROPERTY_INFO16[] = { { "h_size", ValueType::INT, "", (int)0x000001c0 }, { "v_size", ValueType::INT, "", (int)0x000001c0 }, { "h_resolution", ValueType::INT, "", (int)0x00002000 }, { "v_resolution", ValueType::INT, "", (int)0x00002000 }, { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, { "weight", ValueType::INT, "", (int)0x00000000 }, { "family_code", ValueType::INT, "", (int)0x00000002 }, { "style", ValueType::INT, "", (int)0x00000006 }, { "sub_style", ValueType::INT, "", (int)0x00000000 }, { "language_code", ValueType::INT, "", (int)0x00000002 }, { "region_code", ValueType::INT, "", (int)0x00000000 }, { "country_code", ValueType::INT, "", (int)0x00000001 }, { "font_name", ValueType::STR, "FTT-Matisse Pro Latin" }, { "file_name", ValueType::STR, "ltn15.pgf" }, { "expire_date", ValueType::INT, "", (int)0x00000000 }, { "shadow_option", ValueType::INT, "", (int)0x00000000 }, }; // Dump of /DATA/FONT/PROPERTY/INFO17 static const KeyValue tree_DATA_FONT_PROPERTY_INFO17[] = { { "h_size", ValueType::INT, "", (int)0x00000288 }, { "v_size", ValueType::INT, "", (int)0x00000288 }, { "h_resolution", ValueType::INT, "", (int)0x00002000 }, { "v_resolution", ValueType::INT, "", (int)0x00002000 }, { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, { "weight", ValueType::INT, "", (int)0x00000000 }, { "family_code", ValueType::INT, "", (int)0x00000001 }, { "style", ValueType::INT, "", (int)0x00000001 }, { "sub_style", ValueType::INT, "", (int)0x00000000 }, { "language_code", ValueType::INT, "", (int)0x00000003 }, { "region_code", ValueType::INT, "", (int)0x00000000 }, { "country_code", ValueType::INT, "", (int)0x00000003 }, { "font_name", ValueType::STR, "AsiaNHH(512Johab)" }, { "file_name", ValueType::STR, "kr0.pgf" }, { "expire_date", ValueType::INT, "", (int)0x00000000 }, { "shadow_option", ValueType::INT, "", (int)0x00000000 }, }; // Dump of /DATA/FONT/PROPERTY static const KeyValue tree_DATA_FONT_PROPERTY[] = { { "INFO0", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO0), tree_DATA_FONT_PROPERTY_INFO0 }, { "INFO1", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO1), tree_DATA_FONT_PROPERTY_INFO1 }, { "INFO2", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO2), tree_DATA_FONT_PROPERTY_INFO2 }, { "INFO3", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO3), tree_DATA_FONT_PROPERTY_INFO3 }, { "INFO4", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO4), tree_DATA_FONT_PROPERTY_INFO4 }, { "INFO5", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO5), tree_DATA_FONT_PROPERTY_INFO5 }, { "INFO6", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO6), tree_DATA_FONT_PROPERTY_INFO6 }, { "INFO7", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO7), tree_DATA_FONT_PROPERTY_INFO7 }, { "INFO8", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO8), tree_DATA_FONT_PROPERTY_INFO8 }, { "INFO9", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO9), tree_DATA_FONT_PROPERTY_INFO9 }, { "INFO10", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO10), tree_DATA_FONT_PROPERTY_INFO10 }, { "INFO11", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO11), tree_DATA_FONT_PROPERTY_INFO11 }, { "INFO12", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO12), tree_DATA_FONT_PROPERTY_INFO12 }, { "INFO13", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO13), tree_DATA_FONT_PROPERTY_INFO13 }, { "INFO14", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO14), tree_DATA_FONT_PROPERTY_INFO14 }, { "INFO15", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO15), tree_DATA_FONT_PROPERTY_INFO15 }, { "INFO16", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO16), tree_DATA_FONT_PROPERTY_INFO16 }, { "INFO17", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO17), tree_DATA_FONT_PROPERTY_INFO17 }, }; // Dump of /DATA/FONT static const KeyValue tree_DATA_FONT[] = { { "path_name", ValueType::STR, "flash0:/font" }, { "num_fonts", ValueType::INT, "", (int)0x00000012 }, { "PROPERTY", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY), tree_DATA_FONT_PROPERTY }, }; // Dump of /DATA/COUNT static const KeyValue tree_DATA_COUNT[] = { { "boot_count", ValueType::INT, "", (int)0x00000000 }, { "game_exec_count", ValueType::INT, "", (int)0x00000046 }, { "slide_count", ValueType::INT, "", (int)0x00000000 }, { "usb_connect_count", ValueType::INT, "", (int)0x000000ec }, { "wifi_connect_count", ValueType::INT, "", (int)0x00000000 }, { "psn_access_count", ValueType::INT, "", (int)0x00000000 }, }; // Dump of /DATA static const KeyValue tree_DATA[] = { { "FONT", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT), tree_DATA_FONT }, { "COUNT", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_COUNT), tree_DATA_COUNT }, }; // Dump of /SYSPROFILE/RESOLUTION static const KeyValue tree_SYSPROFILE_RESOLUTION[] = { { "horizontal", ValueType::INT, "", (int)0x00002012 }, { "vertical", ValueType::INT, "", (int)0x00002012 }, }; // Dump of /SYSPROFILE static const KeyValue tree_SYSPROFILE[] = { { "sound_reduction", ValueType::INT, "", (int)0x00000000 }, { "RESOLUTION", ValueType::DIR, "", ARRAY_SIZE(tree_SYSPROFILE_RESOLUTION), tree_SYSPROFILE_RESOLUTION }, }; // There's also SYSTEM, CONFIG, REGISTRY but not adding them until they are needed. const KeyValue ROOT[] = { { "DATA", ValueType::DIR, "", ARRAY_SIZE(tree_DATA), tree_DATA }, { "SYSPROFILE", ValueType::DIR, "", ARRAY_SIZE(tree_SYSPROFILE), tree_SYSPROFILE }, }; // Updater checks for CONFIG/SYSTEM/XMB. void __RegInit() { g_openRegistryMode = 0; g_handleGen = 1337; g_openCategories.clear(); } void __RegShutdown() { g_openCategories.clear(); } static const KeyValue *LookupCategory(std::string_view path, int *count) { path = StripPrefix("/", path); std::vector parts; SplitString(path, '/', parts); const KeyValue *curDir = ROOT; int curCount = ARRAY_SIZE(ROOT); for (const auto part : parts) { bool found = false; for (int i = 0; i < curCount; i++) { if (equals(curDir[i].name, part)) { // Found the subdir. if (curDir[i].type == ValueType::DIR) { // Must update curCount before curDir, of course (since that line accesses it). curCount = curDir[i].intValue; curDir = curDir[i].dirContents; found = true; break; } else { ERROR_LOG(Log::sceReg, "Not a dir"); return nullptr; } } } if (!found) { WARN_LOG(Log::sceReg, "LookupCategory: Path not found: %.*s", (int)path.size(), path.data()); return nullptr; } } *count = curCount; return curDir; } void __RegDoState(PointerWrap &p) { auto s = p.Section("sceReg", 0, 1); if (!s) return; Do(p, g_openRegistryMode); Do(p, g_openCategories); } // Registry level (it seems only /system can exist, so kinda pointless) int sceRegOpenRegistry(u32 regParamAddr, int mode, u32 regHandleAddr) { // There's only one registry and its handle is 0. if (Memory::IsValid4AlignedAddress(regHandleAddr)) { Memory::WriteUnchecked_U32(0, regHandleAddr); } g_openRegistryMode = mode; return hleLogInfo(Log::sceReg, 0); } int sceRegCloseRegistry(int regHandle) { if (regHandle != 0) { return hleLogError(Log::sceReg, SCE_REG_ERROR_REGISTRY_NOT_FOUND); } g_openCategories.clear(); return hleLogInfo(Log::sceReg, 0); } int sceRegFlushRegistry(int regHandle) { if (regHandle != 0) { return hleLogError(Log::sceReg, SCE_REG_ERROR_REGISTRY_NOT_FOUND); } // For us this is a no-op. return hleLogInfo(Log::sceReg, 0); } // Seems dangerous! Have not dared to test this on hardware. int sceRegRemoveRegistry(u32 regParamAddr) { return hleLogError(Log::sceReg, 0, "UNIMPL"); } int sceRegOpenCategory(int regHandle, const char *name, int mode, u32 regHandleAddr) { if (!Memory::IsValid4AlignedAddress(regHandleAddr)) { return -1; } if (!name) { return hleLogError(Log::sceReg, SCE_REG_ERROR_INVALID_NAME); } if (regHandle != 0) { Memory::WriteUnchecked_U32(-1, regHandleAddr); return hleLogError(Log::sceReg, SCE_REG_ERROR_REGISTRY_NOT_FOUND, "Invalid registry"); } if (equals(name, "") || equals(name, "/")) { return hleLogError(Log::sceReg, SCE_REG_ERROR_INVALID_PATH); } int count = 0; const KeyValue *keyvals = LookupCategory(name, &count); if (!keyvals) { Memory::WriteUnchecked_U32(-1, regHandleAddr); return hleLogError(Log::sceReg, SCE_REG_ERROR_CATEGORY_NOT_FOUND); } // Let's see if this category is marked as inaccessible (presumably from user mode).. if (count == 1 && keyvals[0].type == ValueType::FAIL) { const int errorCode = keyvals[0].intValue; return hleLogWarning(Log::sceReg, errorCode, "Inaccessible category"); } int handle = g_handleGen++; OpenCategory cat{ name, mode }; g_openCategories[handle] = cat; Memory::WriteUnchecked_U32(handle, regHandleAddr); return hleLogInfo(Log::sceReg, 0, "open handle: %d", handle); } int sceRegCloseCategory(int regHandle) { auto iter = g_openCategories.find(regHandle); if (iter == g_openCategories.end()) { // Not found return hleLogError(Log::sceReg, 0, "Not an open category"); } g_openCategories.erase(iter); return hleLogInfo(Log::sceReg, 0); } int sceRegRemoveCategory(int regHandle, const char *name) { return hleLogError(Log::sceReg, 0, "UNIMPL"); } int sceRegFlushCategory(int regHandle) { return hleLogError(Log::sceReg, 0, "UNIMPL"); } // Key level int sceRegGetKeysNum(int catHandle, u32 numAddr) { auto iter = g_openCategories.find(catHandle); if (iter == g_openCategories.end()) { return hleLogError(Log::sceReg, 0, "Not an open category"); } if (!Memory::IsValid4AlignedAddress(numAddr)) { return -1; } int count = 0; const KeyValue *keyvals = LookupCategory(iter->second.path, &count); if (!keyvals) { Memory::WriteUnchecked_U32(-1, numAddr); return hleLogWarning(Log::sceReg, SCE_REG_ERROR_CATEGORY_NOT_FOUND); } Memory::WriteUnchecked_U32(count, numAddr); return hleLogInfo(Log::sceReg, 0); } int sceRegGetKeys(int catHandle, u32 bufAddr, int num) { auto iter = g_openCategories.find(catHandle); if (iter == g_openCategories.end()) { return hleLogError(Log::sceReg, 0, "Not an open category"); } if (!Memory::IsValidRange(bufAddr, num * 27)) { return hleLogError(Log::sceReg, -1, "bad output addr"); } const int addrLen = 27; // for some reason int count = 0; const KeyValue *keyvals = LookupCategory(iter->second.path, &count); if (!keyvals) { return hleLogWarning(Log::sceReg, SCE_REG_ERROR_CATEGORY_NOT_FOUND); } count = std::min(count, num); for (int i = 0; i < num; i++) { char *dest = (char *)Memory::GetPointerWrite(bufAddr + i * 27); strncpy(dest, keyvals[i].name.c_str(), 27); } return hleLogInfo(Log::sceReg, 0); } int sceRegGetKeyInfo(int catHandle, const char *name, u32 outKeyHandleAddr, u32 outTypeAddr, u32 outSizeAddr) { auto iter = g_openCategories.find(catHandle); if (iter == g_openCategories.end()) { return hleLogError(Log::sceReg, 0, "Not found"); } int count = 0; const KeyValue *keyvals = LookupCategory(iter->second.path, &count); if (!keyvals) { return hleLogWarning(Log::sceReg, SCE_REG_ERROR_CATEGORY_NOT_FOUND); } for (int i = 0; i < count; i++) { if (equals(keyvals[i].name, name)) { // Found it! if (Memory::IsValid4AlignedAddress(outKeyHandleAddr)) { // Let's just make the index the key handle. Memory::WriteUnchecked_U32(i, outKeyHandleAddr); } if (Memory::IsValid4AlignedAddress(outTypeAddr)) { // Let's just make the index the key handle. Memory::WriteUnchecked_U32((int)keyvals[i].type, outTypeAddr); } int size = 0; if (Memory::IsValid4AlignedAddress(outSizeAddr)) { switch (keyvals[i].type) { case ValueType::BIN: size = (int)keyvals[i].strValue.size(); break; case ValueType::STR: size = (int)keyvals[i].strValue.size() + 1; break; case ValueType::DIR: size = 0; break; case ValueType::INT: size = 4; break; default: break; } // Let's just make the index the key handle. Memory::WriteUnchecked_U32(size, outSizeAddr); } return hleLogInfo(Log::sceReg, 0, "handle: %d type: %d size: %d", i, (int)keyvals[i].type, size); } } return hleLogWarning(Log::sceReg, -1, "key with name '%s' not found", name); } int sceRegGetKeyInfoByName(int catHandle, const char *name, u32 typeAddr, u32 sizeAddr) { return hleLogError(Log::sceReg, 0); } int sceRegGetKeyValue(int catHandle, int keyHandle, u32 bufAddr, u32 size) { if (!Memory::IsValidRange(bufAddr, size)) { return -1; } auto iter = g_openCategories.find(catHandle); if (iter == g_openCategories.end()) { return hleLogError(Log::sceReg, 0, "Not found"); } int count = 0; const KeyValue *keyvals = LookupCategory(iter->second.path, &count); if (!keyvals) { return hleLogWarning(Log::sceReg, SCE_REG_ERROR_CATEGORY_NOT_FOUND); } if (keyHandle < 0 || keyHandle >= count) { return hleLogWarning(Log::sceReg, SCE_REG_ERROR_CATEGORY_NOT_FOUND); } const KeyValue &keyval = keyvals[keyHandle]; switch (keyval.type) { case ValueType::BIN: Memory::MemcpyUnchecked(bufAddr, keyval.strValue.data(), std::min(size, (u32)keyval.strValue.size())); return hleLogInfo(Log::sceReg, 0); case ValueType::STR: Memory::MemcpyUnchecked(bufAddr, keyval.strValue.data(), std::min(size, (u32)keyval.strValue.size() + 1)); return hleLogInfo(Log::sceReg, 0, "value: '%s'", keyval.strValue.data()); case ValueType::INT: Memory::WriteUnchecked_U32(keyval.intValue, bufAddr); return hleLogInfo(Log::sceReg, 0, "value: %d (0x%08x)", keyval.intValue, keyval.intValue); case ValueType::DIR: case ValueType::FAIL: default: // Return an error? return hleLogWarning(Log::sceReg, 0, "Unexpected type for sceRegGetKeyValue"); } } int sceRegGetKeyValueByName(int catHandle, const char *name, u32 bufAddr, u32 size) { return hleLogError(Log::sceReg, 0); } int sceRegSetKeyValue(int catHandle, const char *name, u32 bufAddr, u32 size) { return hleLogError(Log::sceReg, 0); } int sceRegCreateKey(int catHandle, const char *name, int type, u32 size) { return hleLogError(Log::sceReg, 0); } const HLEFunction sceReg[] = { { 0x92E41280, &WrapI_UIU, "sceRegOpenRegistry", 'i', "xix" }, { 0xFA8A5739, &WrapI_I, "sceRegCloseRegistry", 'i', "i" }, { 0xDEDA92BF, &WrapI_U, "sceRegRemoveRegistry", 'i', "x" }, { 0x1D8A762E, &WrapI_ICIU, "sceRegOpenCategory", 'i', "isix" }, { 0x0CAE832B, &WrapI_I, "sceRegCloseCategory", 'i', "i" }, { 0x39461B4D, &WrapI_I, "sceRegFlushRegistry", 'i', "i" }, { 0x0D69BF40, &WrapI_I, "sceRegFlushCategory", 'i', "i" }, { 0x57641A81, &WrapI_ICIU, "sceRegCreateKey", 'i', "isix" }, { 0x17768E14, &WrapI_ICUU, "sceRegSetKeyValue", 'i', "isxx" }, { 0xD4475AA8, &WrapI_ICUUU, "sceRegGetKeyInfo", 'i', "isxxx" }, { 0x28A8E98A, &WrapI_IIUU, "sceRegGetKeyValue", 'i', "iixx" }, { 0x2C0DB9DD, &WrapI_IU, "sceRegGetKeysNum", 'i', "ix" }, { 0x2D211135, &WrapI_IUI, "sceRegGetKeys", 'i', "ipi" }, { 0xC5768D02, &WrapI_ICUU, "sceRegGetKeyInfoByName", 'i', "isxx" }, { 0x30BE0259, &WrapI_ICUU, "sceRegGetKeyValueByName", 'i', "isxx" }, { 0x4CA16893, &WrapI_IC, "sceRegRemoveCategory", 'i', "i" }, { 0x3615BC87, nullptr, "sceRegRemoveKey", 'i', "i" }, { 0x9B25EDF1, nullptr, "sceRegExit", 'i', "i" }, // TODO: Add test for these. { 0xBE8C1263, nullptr, "sceRegGetCategoryNumAtRoot", 'i', "ii" }, { 0x835ECE6F, nullptr, "sceRegGetCategoryListAtRoot", 'i', "ipi" }, }; void Register_sceReg() { RegisterHLEModule("sceReg", ARRAY_SIZE(sceReg), sceReg); }