]> Chaos Git - corbenik/corbenik.git/commitdiff
Experimental single-file locale emu with comment support. No clue whether it will...
authorchaoskagami <chaos.kagami@gmail.com>
Mon, 23 May 2016 23:44:20 +0000 (19:44 -0400)
committerchaoskagami <chaos.kagami@gmail.com>
Mon, 23 May 2016 23:44:20 +0000 (19:44 -0400)
Makefile
external/loader/source/config.h
external/loader/source/patcher.c
host/generate_langemu_conf.sh [new file with mode: 0755]
source/config.c
source/config.h
source/patch_format.h

index 061813b0c6742b34f17493051c9e17ec964cd1d5..ecb94ee4fe4059de1f0b07d9206fedc1c6e945fc 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -28,7 +28,7 @@ objects_cfw = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
                          $(call rwildcard, $(dir_source), *.s *.c)))
 
 .PHONY: all
-all: a9lh modules external
+all: a9lh modules external host/langemu.conf
 
 .PHONY: modules
 modules:
@@ -41,10 +41,17 @@ external:
 .PHONY: a9lh
 a9lh: $(dir_out)/arm9loaderhax.bin
 
+host/langemu.conf:
+       echo "Generating langemu.conf - may take a bit"
+       cd host && ./generate_langemu_conf.sh
+       mkdir -p $(dir_out)/corbenik/etc
+       cp host/langemu.conf $(dir_out)/corbenik/etc/langemu.conf
+
 .PHONY: clean
 clean:
        make -C modules clean
        make -C external clean
+       rm host/langemu.conf
        rm -rf $(dir_out) $(dir_build)
 
 .PHONY: $(dir_out)/arm9loaderhax.bin
index 0602091eaf48498eb2aaf628721977e55f5b2266..9e298f305acea511d26d37fa4ca0df43aaff2065 100644 (file)
@@ -8,6 +8,7 @@ __attribute__((unused)) static unsigned int config_version = 1;
 // Structure of config file
 struct config_file {
     char magic[4];              // "OVAN" for shits and giggles again.
+
     uint32_t config_ver;        // Config file version.
 
     uint8_t  options[256];      // Options in the menu - deliberately large to avoid config version bumps.
@@ -15,75 +16,8 @@ struct config_file {
     uint64_t patch_ids[256];    // What patches are enabled by UUID. 256 is an arbitrary limit - contact me if you hit it.
 }__attribute__((packed));
 
-/*
-extern struct config_file config;
-
-enum type {
-       boolean_val, // Toggle
-       ranged_val   // N1 - N2, left and right to pick.
-       mask_val     // Bitmask allowed values.
-};
-
-struct range_str {
-       int a, b;
-};
-
-struct option {
-       int config_index;
-       char name_text[64];
-       enum type allowed;
-       uint32_t a, b;
-}__attribute__((packed));
-
-
-static struct options[] = {
-       { 0, "Signature Patch", boolean_val, 0 },
-       { 1, "FIRM Protection", boolean_val, 0 },
-       { 2, "SysModule Replacement", boolean_val, 0 },
-       { 3, "Service Replacement", boolean_val, 0 },
-       { 4, "ARM9 Thread", boolean_val, 0 },
-
-       { 5, "Autoboot", boolean_val, 0 },
-       { 6, "Silence w/ Autoboot", boolean_val, 0 },
-       { 7, "Step through with button", boolean_val, 0 },
-
-       { 8, "Don't draw background color", boolean_val, 0 },
-       { 9, "Preserve framebuffer data", boolean_val, 0 },
-
-       { 10, "Hide Help from menu", boolean_val, 0 },
-
-       { 11, "Loader: CPU L2 enable", boolean_val, 0 },
-       { 12, "Loader: CPU 800Mhz mode", boolean_val, 0 },
-       { 13, "Loader: Language Emulation", boolean_val, 0 },
-
-       { 14, "No dependency tracking", boolean_val, 0 },
-       { 15, "Allow unsafe options", boolean_val, 0 },
-}
-*/
-#define OPTION_SIGPATCH     0  // Use builtin signature patch.
-#define OPTION_FIRMPROT     1  // Protect firmware from writes.
-#define OPTION_LOADER       2  // Use builtin loader module replacer.
-#define OPTION_SERVICES     3  // Inject services (including backdoor for 11)
-#define OPTION_ARM9THREAD   4  // Use builtin ARM9 thread injector.
-
-#define OPTION_AUTOBOOT     5  // Skip menu unless L is held.
-#define OPTION_SILENCE      6  // Don't print debug information.
-#define OPTION_TRACE        7  // Pause for A key on each step.
-
-#define OPTION_TRANSP_BG    8  // Background color is not drawn under text.
-#define OPTION_NO_CLEAR_BG  9  // Framebuffer is preserved from whatever ran before us.
-#define OPTION_READ_ME      10 // Remove Help/Readme from menu.
-
 #define OPTION_LOADER_CPU_L2   11   // Enable L2 cache.
 #define OPTION_LOADER_CPU_800MHZ 12 // Enable 800Mhz mode.
 #define OPTION_LOADER_LANGEMU  13 // Enable 800Mhz mode.
 
-#define IGNORE_PATCH_DEPS    14  // Ignore patch UUID dependencies. Not recommended.
-#define IGNORE_BROKEN_SHIT   15 // Allow enabling patches which are marked as 'incompatible'. Chances are there's a reason.
-
-//#define HEADER_COLOR        12 // Color of header text.
-//#define BG_COLOR            13 // Color of background.
-//#define TEXT_COLOR          14 // Color of most text.
-//#define ARROW_COLOR         15 // Color of Arrow.
-
 #endif
index f76cf25c6252b78cae6d587f60eb263404959d70..26c154592a7ff3a0f43f983e99ff82f557d6a7be 100644 (file)
@@ -151,64 +151,107 @@ static int loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId)
 
     char path[] = "/corbenik/etc/locale.conf"; // The locale config file.
 
-    char progIdStr[17]; // Sizeof titleid as string + null terminator
-       progIdStr[sizeof(progIdStr)-1] = 0; // Set null term
-
-       // Hexdump progId
-       for(int i=0; i < 8; i++) {
-        static const char hexDigits[] = "0123456789ABCDEF";
-        progIdStr[i*2]   = hexDigits[(((uint8_t*)&progId)[i] >> 4) & 0xf];
-        progIdStr[i*2+1] = hexDigits[ ((uint8_t*)&progId)[i] & 0xf];
+    char progid_str[16];
+
+    // Hexdump.
+    for(int i=0; i < 16; i += 2) {
+      progid_str[i]   = ("0123456789ABCDEF")[ (((u8*)&progId)[0] >> 4) & 0xf ];
+      progid_str[i+1] = ("0123456789ABCDEF")[  ((u8*)&progId)[0] & 0xf       ];
     }
 
+    static const char *regions[] = {"JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"};
+    static const char *languages[] = {"JA", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"};
+
     IFile file;
-    Result ret = fileOpen(&file, ARCHIVE_SDMC, path, FS_OPEN_READ);
-    if(R_SUCCEEDED(ret))
+    Result eof = fileOpen(&file, ARCHIVE_SDMC, path, FS_OPEN_READ);
+    if(R_SUCCEEDED(eof))
     {
-        char buf[6];
+        char c;
+        char buf_prog[16];
+        char country_tmp[16];
+        char lang_tmp[16];
         u64 total;
 
                // TODO - Open and seek file properly
 
-        ret = IFile_Read(&file, &total, buf, 6);
-        IFile_Close(&file);
-
-        if(!R_SUCCEEDED(ret) || total < 6) return -1;
+        int i = 0;
+        int state = 0; // State. 0 = get_titleid, 1 = get_region, 2 = get_language, 3 = process entry
+        while(1) {
+          eof = IFile_Read(&file, &total, &c, 1); // Read character.
 
-               // TODO - Split by nl/spaces strtok style. This is not acceptable code.
-               // Entries should be of the format:
-               //   <tid> <region> <lang>
-               // No attempt will be made to fix dumbass use of CRLF or CR-only, but newline
-               // characters should be treated as spaces.
-
-        for(u32 i = 0; i < 7; ++i)
-        {
-                       // TODO - Permit alternative names. They're using fixed strings for ease of use;
-                       // we need to permit names like 'Japan', 'Europe', etc
-                       // Maybe read locale data from the FS? http://cldr.unicode.org/
-            static const char *regions[] = {"JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"};
+          if (c == ' ' || c == '\n' || c == '\r' || c == '\t') // Skip space characters.
+            continue;
 
-            if(memcmp(buf, regions[i], 3) == 0)
-            {
-                *regionId = (u8)i;
-                break;
+          if (c == '#') { // Comment! Skip until a \n or \r.
+            while(c != '\n' && c != '\r') {
+              eof = IFile_Read(&file, &total, &c, 1); // Read character.
             }
-        }
-
-        for(u32 i = 0; i < 12; ++i)
-        {
-                       // TODO - Same as above.
-            static const char *languages[] = {"JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"};
+            continue; // Resume loop.
+          }
+
+          switch(state) {
+            case 0:
+              // Read titleID.
+              for(i = 0; i < 16; i++) {
+                buf_prog[i] = c;
+                if (i != 15)
+                  eof = IFile_Read(&file, &total, &c, 1); // Read character.
+              }
+              state = 1;
+              break;
+            case 1:
+              // Read country name. Must be <16 chars, past that is ignored.
+              i = 0;
+              while (c != ' ' && c != '\n' && c != '\r' && c != '\t') { // While we're not reading a space...
+                if (i < 15) {
+                  country_tmp[i] = c;
+                  i++;
+                }
+                eof = IFile_Read(&file, &total, &c, 1); // Read character unless last one.
+              }
+              state = 2;
+              break;
+            case 2:
+              // Read language name. See country name, code is basically identical.
+              i = 0;
+              while (c != ' ' && c != '\n' && c != '\r' && c != '\t') { // While we're not reading a space...
+                if (i < 15) { // Only read in if <16.
+                  lang_tmp[i] = c;
+                  i++;
+                }
+                eof = IFile_Read(&file, &total, &c, 1); // Read character unless last one.
+              }
+              state = 3;
+              break;
+            case 3:
+              // Process entry, return and apply if matched.
+              if(!memcmp(progid_str, buf_prog, 16)) {
+                // TitleID matched. Apply language emulation; but first, process language and country.
+                for(i = 0; i < 7; i++) {
+                  if(!memcmp(country_tmp, regions[i], 3)) {
+                    *regionId = (u8)i;
+                  }
+                }
 
-            if(memcmp(buf + 4, languages[i], 2) == 0)
-            {
-                *languageId = (u8)i;
+                for(u32 i = 0; i < 12; i++) {
+                  if(!memcmp(lang_tmp, languages[i], 2)) {
+                    *languageId = (u8)i;
+                  }
+                }
+                state = 4; // Processed. Go on.
                 break;
-            }
+              }
+              state = 0; // Nope. Move onto the next one.
+              break;
+          }
+
+          if(!R_SUCCEEDED(eof) || total == 0 || state == 4)
+            break;
         }
     }
 
-    return ret;
+    IFile_Close(&file); // Read to memory.
+    return eof;
 }
 
 static u8 *getCfgOffsets(u8 *code, u32 size, u32 *CFGUHandleOffset)
diff --git a/host/generate_langemu_conf.sh b/host/generate_langemu_conf.sh
new file mode 100755 (executable)
index 0000000..5354778
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+# Downloads the XML from 3dsdb, parses it, and using this information generates
+# a langemu config for single-language single-region games, which can have langemu
+# without any ill consequences.
+
+# Fetch XML.
+wget "http://3dsdb.com/xml.php" -O 3ds.tmp
+
+# Extract all needed fields: titleID, region, language
+grep '<titleid>'   3ds.tmp | sed -e 's|[[:space:]]*||g' -e 's|</*titleid>||g'   > titleid.tmp
+grep '<region>'    3ds.tmp | sed -e 's|[[:space:]]*||g' -e 's|</*region>||g'    > region.tmp
+grep '<languages>' 3ds.tmp | sed -e 's|[[:space:]]*||g' -e 's|</*languages>||g' > languages.tmp
+
+ENTS=0
+
+# Open all three files and read into full file, checking validity as we go
+while true; do
+  read -r titleid <&3 || break
+  read -r region <&4 || break
+  read -r languages <&5 || break
+
+  if [ "${#titleid}" == "16" ]; then
+    # Length of TID is correct.
+    echo "$languages" | grep ',' 2>&1 >/dev/null
+    R=$?
+    if [ ! $R = 0 ]; then
+      # Only one language found, since no comma.
+      # Output an entry.
+      echo "$titleid $region $languages" | tr [:lower:] [:upper:] | sed -e 's|GER|EUR|g' -e 's|ITA|EUR|g' -e 's|FRA|EUR|g' -e 's|UKV|EUR|g' -e 's|NLD|EUR|g' -e 's|WLD|JPN|g' >> langemu.tmp
+      ENTS=$((ENTS + 1))
+    fi
+  fi
+done 3<titleid.tmp 4<region.tmp 5<languages.tmp
+
+echo "# Autogenerated - $(date) - $ENTS entries" > langemu.conf
+cat langemu.tmp | sort | uniq >> langemu.conf
+rm -f *.tmp
index b8687bf65379975f645a5cfcf0754399338cb18b..497a62e52a04c6fc86cbb2d575d20d9755de511d 100644 (file)
@@ -6,12 +6,7 @@ struct config_file config;
 
 void regenerate_config() {
        f_mkdir(PATH_CFW);
-       f_mkdir(PATH_CFW "/lib");
-    f_mkdir(PATH_FIRMWARES);
-    f_mkdir(PATH_PATCHES);
-    f_mkdir(PATH_TEMP);
-    f_mkdir(PATH_KEYS);
-    f_mkdir(PATH_EXEFS);
+       f_mkdir(PATH_CONFIG);
 
     fprintf(BOTTOM_SCREEN, "Created directory structure.\n");
 
index c87a314a5707f2f0157ba5cf532ea5f55d74121c..e972179d95e45f828112a4b88b60383f636024b6 100644 (file)
@@ -8,6 +8,7 @@ _UNUSED static unsigned int config_version = 1;
 // Structure of config file
 struct config_file {
     char magic[4];              // "OVAN" for shits and giggles again.
+
     uint32_t config_ver;        // Config file version.
 
     uint8_t  options[256];      // Options in the menu - deliberately large to avoid config version bumps.
index 27d13cc7b039162fee25d612ffdb839d4de20a10..2f624ddde493ec9a0f63625c07b36401ecf0939a 100644 (file)
@@ -29,7 +29,7 @@
 
 #define PATH_CONFIG_DIR PATH_CFW "/etc"                   // Config file directory.
 #define PATH_CONFIG     PATH_CONFIG_DIR "/main.conf"      // Config file.
-#define PATH_LOCEMU     PATH_CONFIG_DIR "/locale.conf"    // Locale emulation config
+#define PATH_LOCEMU     PATH_CONFIG_DIR "/langemu.conf"    // Locale emulation config
 #define PATH_CPU_CFG    PATH_CONFIG_DIR "/cpu.conf"       // CPU settings config
 
 #define PATH_PATCHES    PATH_CFW "/bin"            // Patch binary folder.