From 1192c4575ea7afdf38e3fa0df4587a08620af11e Mon Sep 17 00:00:00 2001 From: root Date: Tue, 21 Jul 2020 10:00:46 +0200 Subject: SZS v2.18a --- project/src/lib-staticr.c | 6886 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 6886 insertions(+) create mode 100644 project/src/lib-staticr.c (limited to 'project/src/lib-staticr.c') diff --git a/project/src/lib-staticr.c b/project/src/lib-staticr.c new file mode 100644 index 0000000..2125714 --- /dev/null +++ b/project/src/lib-staticr.c @@ -0,0 +1,6886 @@ + +/*************************************************************************** + * _______ _______ _______ * + * | ___ |____ | ___ | * + * | | |_| / /| | |_| * + * | |_____ / / | |_____ * + * |_____ | / / |_____ | * + * _ | | / / _ | | * + * | |___| |/ /____| |___| | * + * |_______|_______|_______| * + * * + * Wiimms SZS Tools * + * https://szs.wiimm.de/ * + * * + *************************************************************************** + * * + * This file is part of the SZS project. * + * Visit https://szs.wiimm.de/ for project details and sources. * + * * + * Copyright (c) 2011-2020 by Dirk Clemens * + * * + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * See file gpl-2.0.txt or http://www.gnu.org/licenses/gpl-2.0.txt * + * * + ***************************************************************************/ + +#include "lib-staticr.h" +#include "crypt.h" +#include "db-dol.h" +#include "db-mkw.h" +#include "lib-mkw.h" +#include "db-ctcode.h" + +#include "libbz2/bzlib.h" +#include "lib-bzip2.h" + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// data: tracks + arenas /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static const u32 pal_track_offset[] = +{ + 0x37fcd0, + // 0x380ee0, // original has an alternative order here + 0x384f58, + 0x397da8, + 0x398130, + 0x39d040, + 0 +}; + +static const u32 pal_arena_offset[] = +{ + 0x384fd8, + 0x3974f8, + 0x397780, + 0x39c8e0, + 0 +}; + +//----------------------------------------------------------------------------- + +static const u32 usa_track_offset[] = +{ + 0x37fbe0, + // 0x380b70, // original has an alternative order here + 0x3839e0, + 0x397450, + 0x3977d8, + 0x39b300, + 0 +}; + +static const u32 usa_arena_offset[] = +{ + 0x383a60, + 0x39d130, + 0x39d3b8, + 0x39e988, + 0 +}; + +//----------------------------------------------------------------------------- + +static const u32 jap_track_offset[] = +{ + 0x37f9a0, + // 0x380bb0, // original has an alternative order here + 0x384c28, + 0x397588, + 0x397910, + 0x39c820, + 0 +}; + +static const u32 jap_arena_offset[] = +{ + 0x384ca8, + 0x396cd8, + 0x396f60, + 0x39c0c0, + 0 +}; + +//----------------------------------------------------------------------------- + +static const u32 kor_track_offset[] = +{ + 0x3800b0, + // 0x3812c8, // original has an alternative order here + 0x385348, + 0x3981e8, + 0x398570, + 0x39d480, + 0 +}; + +static const u32 kor_arena_offset[] = +{ + 0x3853c8, + 0x397938, + 0x397bc0, + 0x39cd20, + 0 +}; + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// data: region /////////////// +/////////////////////////////////////////////////////////////////////////////// + +typedef enum rpat_mode_t // bit field +{ + RPAT_FF = 1, // mask value by 0xff + RPAT_TEST = 2, // test mode, only patched on 'opt_x' +} +rpat_mode_t; + +typedef struct region_patch_t +{ + rpat_mode_t patch_mode; // bit field, see above + u32 offset[STR_ZBI_N]; // offsets for all 4 DVD types + u32 orig; // original value + u32 patch; // patch base value + ccp info; // info about impact +} +region_patch_t; + +static const region_patch_t vs_region_patch[] = +{ + {0,{0x143364,0x14325c,0x143050,0x14365c}, 0x80a30084,0x38a00000, "vs: locstring status" }, + {1,{0x149d54,0x149c4c,0x149a40,0x14a04c}, 0x80840084,0x38800000, "vs: check locstring, masked by 0xff" }, + {0,{0x148f2c,0x148e24,0x148c18,0x149224}, 0x80e50084,0x38e00000, "'vs_#' at regional matches." }, + {0,{0x149444,0x14933c,0x149130,0x14973c}, 0x80e50084,0x38e00000, "'vs_#' after friend connect" }, + {0,{0,0,0,0},0,0,0} +}; + +static const region_patch_t bt_region_patch[] = +{ + {0,{0x1433d0,0x1432c8,0x1430bc,0x1436c8}, 0x80c30084,0x38c00000, "bt: locstring status" }, + {1,{0x149da0,0x149c98,0x149a8c,0x14a098}, 0x80840084,0x38800000, "bt: check locstring, masked by 0xff" }, + {0,{0x148f80,0x148e78,0x148c6c,0x149278}, 0x80e50084,0x38e00000, "'bt_#' at regional matches." }, + {0,{0x149498,0x149390,0x149184,0x149790}, 0x80e50084,0x38e00000, "'bt_#' after friend connect" }, + {0,{0,0,0,0},0,0,0} +}; + +enum +{ + N_TAB_VS_REGION_PATCH = sizeof(vs_region_patch) / sizeof(*vs_region_patch) - 1, + N_VS_REGION_PATCH = N_TAB_VS_REGION_PATCH < MAX_REGION_PATCH + ? N_TAB_VS_REGION_PATCH : MAX_REGION_PATCH, + + N_TAB_BT_REGION_PATCH = sizeof(bt_region_patch) / sizeof(*bt_region_patch) - 1, + N_BT_REGION_PATCH = N_TAB_BT_REGION_PATCH < MAX_REGION_PATCH + ? N_TAB_BT_REGION_PATCH : MAX_REGION_PATCH, +}; + +//----------------------------------------------------------------------------- + +typedef struct region_info_t +{ + int * region; // vector with regions, -1=orig + const + region_patch_t * patch_tab; // patch table + uint max_patch; // N_(VS|BT)_REGION_PATCH + uint flag_known; // STR_S_(VS|BT)_REGION_KNOWN + uint flag_differ; // STR_S_(VS|BT)_REGION_KNOWN_DIFF + uint flag_unknown; // STR_S_(VS|BT)_REGION_UNKNOWN + ccp name; // "versus" or "battle" + + int *opt_region; // pointer to option + bool *opt_x; // pointer to x-mode + bool *opt_t; // pointer to t-mode +} +region_info_t; + +void SetupRegionInfo ( region_info_t *ri, staticr_t * str, bool is_battle ) +{ + DASSERT(ri); + + if (is_battle) + { + ri->region = str ? str->bt_region : 0; + ri->patch_tab = bt_region_patch; + ri->max_patch = N_BT_REGION_PATCH; + ri->flag_known = STR_S_BT_REGION_KNOWN; + ri->flag_differ = STR_S_BT_REGION_KNOWN_DIFF; + ri->flag_unknown= STR_S_BT_REGION_UNKNOWN; + ri->name = "battle"; + + ri->opt_region = &opt_str_bt_region; + ri->opt_x = &opt_str_xbt_region; + ri->opt_t = &opt_str_tbt_region; + } + else + { + ri->region = str ? str->vs_region : 0; + ri->patch_tab = vs_region_patch; + ri->max_patch = N_VS_REGION_PATCH; + ri->flag_known = STR_S_VS_REGION_KNOWN; + ri->flag_differ = STR_S_VS_REGION_KNOWN_DIFF; + ri->flag_unknown= STR_S_VS_REGION_UNKNOWN; + ri->name = "versus"; + + ri->opt_region = &opt_str_vs_region; + ri->opt_x = &opt_str_xvs_region; + ri->opt_t = &opt_str_tvs_region; + } +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +static char all_ranks_orig[] = "%s >= %d and %s <= %d"; +static char all_ranks_patch1[] = "(%s > %d or %s <= %d)"; +static char all_ranks_patch2[] = "(%s >= %d or %s < %d)"; +static int all_ranks_size = sizeof(all_ranks_orig); + +static const u32 pal_all_ranks_offset[] = +{ + 0x389f36, + 0x389f52, + 0 +}; + +static const u32 usa_all_ranks_offset[] = +{ + 0x389be6, + 0x389c02, + 0 +}; + +static const u32 jap_all_ranks_offset[] = +{ + 0x389716, + 0x389732, + 0 +}; + +static const u32 kor_all_ranks_offset[] = +{ + 0x38a34e, + 0x38a36a, + 0 +}; + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// data: vs/bat /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static const u32 pal_vs_offset[] = +{ + 0x389f1b, + 0x389f24, + 0x389f9e, + 0x389fa7, + 0 +}; + +static const u32 usa_vs_offset[] = +{ + 0x389bcb, + 0x389bd4, + 0x389c4e, + 0x389c57, + 0 +}; + +static const u32 jap_vs_offset[] = +{ + 0x3896fb, + 0x389704, + 0x38977e, + 0x389787, + 0 +}; + +static const u32 kor_vs_offset[] = +{ + 0x38a333, + 0x38a33c, + 0x38a3b6, + 0x38a3bf, + 0 +}; + +//----------------------------------------------------------------------------- + +static const u32 pal_bt_offset[] = +{ + 0x389f2a, + 0x389f33, + 0x389fad, + 0x389fb6, + 0 +}; + +static const u32 usa_bt_offset[] = +{ + 0x389bda, + 0x389be3, + 0x389c5d, + 0x389c66, + 0 +}; + +static const u32 jap_bt_offset[] = +{ + 0x38970a, + 0x389713, + 0x38978d, + 0x389796, + 0 +}; + +static const u32 kor_bt_offset[] = +{ + 0x38a342, + 0x38a34b, + 0x38a3c5, + 0x38a3ce, + 0 +}; + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// data: cannons /////////////// +/////////////////////////////////////////////////////////////////////////////// + +#define CANNON_N 3 +#define CANNON_SIZE 16 +#define CANNON_N_PARAM 4 + +typedef struct cannon_param_t +{ + bool valid; // TRUE: params are valid + float param[CANNON_N_PARAM]; // parameters +} +cannon_param_t; + +static cannon_param_t cannon_param[CANNON_N] = {{0}}; + +//----------------------------------------------------------------------------- + +static u32 GetCannonOffset ( const staticr_t * str ) +{ + ASSERT( sizeof(CannonDataLEX)-4 == sizeof(str->cannon_data) ); + ASSERT( sizeof(CannonDataLEX)-4 == CANNON_SIZE * CANNON_N ); + + if ( str && str->is_staticr ) + { + switch (str->mode) + { + case STR_M_PAL: return 0x3a5a08; + case STR_M_USA: return 0x3a54c8; + case STR_M_JAP: return 0x3a51e8; + case STR_M_KOR: return 0x3a5e60; + default: return 0; + } + } + return 0; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// data: /Scene/UI/MenuSingle /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static const u32 pal_menu_offset[] = +{ + 0x387b64, // /Scene/UI/MenuSingle + 0x387b9d, // /Scene/UI/MenuSingle + 0x387bea, // /Scene/UI/MenuSingle + 0x387c48, // /Scene/UI/MenuSingle + 0x387cd9, // /Scene/UI/MenuSingle + + 0x387b79, // /Scene/UI/MenuMulti + 0x387bb2, // /Scene/UI/MenuMulti + 0x387bd6, // /Scene/UI/MenuMulti + 0x387bff, // /Scene/UI/MenuMulti + + 0 +}; + +static const u32 usa_menu_offset[] = +{ + 0x38513c, // /Scene/UI/MenuSingle + 0x385175, // /Scene/UI/MenuSingle + 0x3851c2, // /Scene/UI/MenuSingle + 0x385220, // /Scene/UI/MenuSingle + 0x3852b1, // /Scene/UI/MenuSingle + + 0x385151, // /Scene/UI/MenuMulti + 0x38518a, // /Scene/UI/MenuMulti + 0x3851ae, // /Scene/UI/MenuMulti + 0x3851d7, // /Scene/UI/MenuMulti + + 0 +}; + +static const u32 jap_menu_offset[] = +{ + 0x387834, // /Scene/UI/MenuSingle + 0x38786d, // /Scene/UI/MenuSingle + 0x3878ba, // /Scene/UI/MenuSingle + 0x387918, // /Scene/UI/MenuSingle + 0x3879a9, // /Scene/UI/MenuSingle + + 0x387849, // /Scene/UI/MenuMulti + 0x387882, // /Scene/UI/MenuMulti + 0x3878a6, // /Scene/UI/MenuMulti + 0x3878cf, // /Scene/UI/MenuMulti + + 0 +}; + +static const u32 kor_menu_offset[] = +{ + 0x38846c, // /Scene/UI/MenuSingle + 0x3884a5, // /Scene/UI/MenuSingle + 0x3884f2, // /Scene/UI/MenuSingle + 0x388550, // /Scene/UI/MenuSingle + 0x3885e1, // /Scene/UI/MenuSingle + + 0x388481, // /Scene/UI/MenuMulti + 0x3884ba, // /Scene/UI/MenuMulti + 0x3884de, // /Scene/UI/MenuMulti + 0x388507, // /Scene/UI/MenuMulti + + 0 +}; + +static const int meno_patch_idx[] = +{ + 1, // Single: Global VS + Battle + 2, // Single: Room + 7, // Multi: Global VS + Battle + 8, // Multi: Room + -1 +}; + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// data: servers /////////////// +/////////////////////////////////////////////////////////////////////////////// + +const str_server_list_t ServerList[SERV__N+1] = +{ + { SERV_NONE, "NONE", 0, 0, "" }, + { SERV_NASW, "NASW", 90, 23, "naswii.nintendowifi.net" }, + { SERV_NASW_DEV, "NASW_DEV", 91, 27, "naswii.dev.nintendowifi.net" }, + { SERV_NASW_TEST, "NASW_TEST", 92, 28, "naswii.test.nintendowifi.net" }, + { SERV_MKW_RACE, "MKW_RACE", 93, 37, "mariokartwii.race.gs.nintendowifi.net" }, + { SERV_SAKE, "SAKE", 0, 37, "mariokartwii.sake.gs.nintendowifi.net" }, + { SERV_S_SAKE, "S_SAKE", 0, 27, "%s.sake.gs.nintendowifi.net" }, + { SERV_GS, "GS", 0, 19, "gs.nintendowifi.net" }, + {0,0,0,0,0} +}; + +/////////////////////////////////////////////////////////////////////////////// + +const str_server_patch_t ServerPatch[217+1] = +{ + { STR_M_PAL,0, 2,SERV_NONE, 0x38aa32, 5, "" }, + { STR_M_PAL,0, 2,SERV_NONE, 0x38ab4c, 5, "" }, + { STR_M_PAL,2, 2,SERV_MKW_RACE, 0x38a38c, 75, "/raceservice/maindl_%s_%s.ashx" }, + { STR_M_PAL,2, 2,SERV_MKW_RACE, 0x38a458, 78, "/raceservice/messagedl_%s_%s.ashx" }, + { STR_M_PAL,0, 2,SERV_MKW_RACE, 0x38a8f0, 84, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_PAL,0, 1,SERV_MKW_RACE, 0x38a945, 83, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_PAL,0, 2,SERV_SAKE, 0x38a3d8, 100, "/SakeFileServer/ghostdownload.aspx?gameid=1687®ion=0" }, + { STR_M_PAL,0, 0,SERV_GS, 0x38a9bc, 117, "/SakeFileServer/ghostupload.aspx?gameid=%d®ionid=%d&courseid=%d&score=%d&pid=%d&playerinfo=%s%s" }, + { STR_M_PAL,0, 0,SERV_GS, 0x38aaef, 92, "/SakeFileServer/ghostdownload.aspx?gameid=1687®ion=0&p0=%d&c0=%d&t0=%d" }, + { STR_M_PAL,0, 0,SERV_GS, 0x38ac9c, 58, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_PAL,0, 0,SERV_GS, 0x38ae05, 58, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_PAL,0, 0,SERV_GS, 0x38af33, 58, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_PAL,0, 0,SERV_GS, 0x38b014, 58, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_PAL,0, 0,SERV_GS, 0x38b109, 58, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_PAL,0, 0,SERV_GS, 0x38b21e, 58, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_PAL,0, 0,SERV_GS, 0x38b330, 58, "/RaceService/NintendoRacingService.asmx" }, + + { STR_M_PAL,9, 2,SERV_NONE, 0x2797f8, 8, "" }, // "https://" + { STR_M_PAL,9, 2,SERV_NONE, 0x279808, 8, "" }, // "https://" + { STR_M_PAL,9, 2,SERV_NONE, 0x279a78, 8, "" }, // "https://" + { STR_M_PAL,9, 2,SERV_NONE, 0x29d568, 8, "" }, // "https://" + { STR_M_PAL,9, 2,SERV_NONE, 0x29e388, 8, "" }, // "https://" + + { STR_M_PAL,5, 2,SERV_NASW, 0x276528, 34, "/ac" }, + { STR_M_PAL,1, 2,SERV_NASW, 0x2765a8, 34, "/pr" }, + { STR_M_PAL,5, 2,SERV_NASW_DEV, 0x27654c, 38, "/ac" }, + { STR_M_PAL,1, 2,SERV_NASW_DEV, 0x2765cc, 38, "/pr" }, + { STR_M_PAL,5, 2,SERV_NASW_TEST, 0x276500, 39, "/ac" }, + { STR_M_PAL,1, 2,SERV_NASW_TEST, 0x276580, 39, "/pr" }, + { STR_M_PAL,1, 2,SERV_S_SAKE, 0x275e58, 72, "/SakeStorageServer/StorageServer.asmx" }, + { STR_M_PAL,1, 2,SERV_S_SAKE, 0x275ea4, 62, "/SakeFileServer/upload.aspx" }, + { STR_M_PAL,1, 2,SERV_S_SAKE, 0x275ee4, 64, "/SakeFileServer/download.aspx" }, + { STR_M_PAL,1, 1,SERV_S_SAKE, 0x27a1a0, 71, "/SakeStorageServer/StorageServer.asmx" }, + { STR_M_PAL,1, 0,SERV_GS, 0x2718be, 19, "" }, + { STR_M_PAL,1, 0,SERV_GS, 0x272635, 19, "" }, + { STR_M_PAL,1, 0,SERV_GS, 0x272651, 19, "" }, + { STR_M_PAL,1, 0,SERV_GS, 0x272672, 19, "" }, + { STR_M_PAL,1, 0,SERV_GS, 0x272693, 19, "" }, + { STR_M_PAL,1, 0,SERV_GS, 0x2726b5, 19, "" }, + { STR_M_PAL,1, 0,SERV_GS, 0x2726d7, 19, "" }, + { STR_M_PAL,1, 0,SERV_GS, 0x2726f7, 19, "" }, + { STR_M_PAL,1, 0,SERV_GS, 0x272717, 19, "" }, + { STR_M_PAL,1, 0,SERV_GS, 0x272736, 19, "" }, + { STR_M_PAL,1, 0,SERV_GS, 0x272759, 19, "" }, + { STR_M_PAL,1, 0,SERV_GS, 0x27277e, 19, "" }, + { STR_M_PAL,1, 0,SERV_GS, 0x27279c, 19, "" }, + { STR_M_PAL,1, 0,SERV_GS, 0x276e65, 19, "" }, + { STR_M_PAL,1, 0,SERV_GS, 0x2775d5, 19, "" }, + { STR_M_PAL,1, 0,SERV_GS, 0x277fed, 19, "" }, + { STR_M_PAL,1, 0,SERV_GS, 0x27918e, 19, "" }, + { STR_M_PAL,1, 0,SERV_GS, 0x279b82, 19, "" }, + { STR_M_PAL,1, 0,SERV_GS, 0x279da8, 19, "" }, + { STR_M_PAL,1, 0,SERV_GS, 0x279dc4, 19, "" }, + { STR_M_PAL,1, 0,SERV_GS, 0x279de0, 19, "" }, + { STR_M_PAL,1, 0,SERV_GS, 0x279f30, 19, "" }, + { STR_M_PAL,1, 0,SERV_GS, 0x279fb4, 19, "" }, + + { STR_M_USA,0, 2,SERV_NONE, 0x38a3ba, 5, "" }, + { STR_M_USA,0, 2,SERV_NONE, 0x38a4d4, 5, "" }, + { STR_M_USA,2, 2,SERV_MKW_RACE, 0x389d14, 75, "/raceservice/maindl_%s_%s.ashx" }, + { STR_M_USA,2, 2,SERV_MKW_RACE, 0x389de0, 78, "/raceservice/messagedl_%s_%s.ashx" }, + { STR_M_USA,0, 2,SERV_MKW_RACE, 0x38a278, 84, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_USA,0, 1,SERV_MKW_RACE, 0x38a2cd, 83, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_USA,0, 2,SERV_SAKE, 0x389d60, 100, "/SakeFileServer/ghostdownload.aspx?gameid=1687®ion=0" }, + { STR_M_USA,0, 0,SERV_GS, 0x38a344, 117, "/SakeFileServer/ghostupload.aspx?gameid=%d®ionid=%d&courseid=%d&score=%d&pid=%d&playerinfo=%s%s" }, + { STR_M_USA,0, 0,SERV_GS, 0x38a477, 92, "/SakeFileServer/ghostdownload.aspx?gameid=1687®ion=0&p0=%d&c0=%d&t0=%d" }, + { STR_M_USA,0, 0,SERV_GS, 0x38a604, 58, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_USA,0, 0,SERV_GS, 0x38a76d, 58, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_USA,0, 0,SERV_GS, 0x38a89b, 58, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_USA,0, 0,SERV_GS, 0x38a97c, 58, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_USA,0, 0,SERV_GS, 0x38aa71, 58, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_USA,0, 0,SERV_GS, 0x38ab86, 58, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_USA,0, 0,SERV_GS, 0x38ac98, 58, "/RaceService/NintendoRacingService.asmx" }, + + { STR_M_USA,9, 2,SERV_NONE, 0x275498, 8, "" }, // "https://" + { STR_M_USA,9, 2,SERV_NONE, 0x2754a8, 8, "" }, // "https://" + { STR_M_USA,9, 2,SERV_NONE, 0x275718, 8, "" }, // "https://" + { STR_M_USA,9, 2,SERV_NONE, 0x299208, 8, "" }, // "https://" + { STR_M_USA,9, 2,SERV_NONE, 0x29a028, 8, "" }, // "https://" + + { STR_M_USA,5, 2,SERV_NASW, 0x2721c8, 34, "/ac" }, + { STR_M_USA,1, 2,SERV_NASW, 0x272248, 34, "/pr" }, + { STR_M_USA,5, 2,SERV_NASW_DEV, 0x2721ec, 38, "/ac" }, + { STR_M_USA,1, 2,SERV_NASW_DEV, 0x27226c, 38, "/pr" }, + { STR_M_USA,5, 2,SERV_NASW_TEST, 0x2721a0, 39, "/ac" }, + { STR_M_USA,1, 2,SERV_NASW_TEST, 0x272220, 39, "/pr" }, + { STR_M_USA,1, 2,SERV_S_SAKE, 0x271af8, 72, "/SakeStorageServer/StorageServer.asmx" }, + { STR_M_USA,1, 2,SERV_S_SAKE, 0x271b44, 62, "/SakeFileServer/upload.aspx" }, + { STR_M_USA,1, 2,SERV_S_SAKE, 0x271b84, 64, "/SakeFileServer/download.aspx" }, + { STR_M_USA,1, 1,SERV_S_SAKE, 0x275e40, 71, "/SakeStorageServer/StorageServer.asmx" }, + { STR_M_USA,1, 0,SERV_GS, 0x26d55e, 19, "" }, + { STR_M_USA,1, 0,SERV_GS, 0x26e2d5, 19, "" }, + { STR_M_USA,1, 0,SERV_GS, 0x26e2f1, 19, "" }, + { STR_M_USA,1, 0,SERV_GS, 0x26e312, 19, "" }, + { STR_M_USA,1, 0,SERV_GS, 0x26e333, 19, "" }, + { STR_M_USA,1, 0,SERV_GS, 0x26e355, 19, "" }, + { STR_M_USA,1, 0,SERV_GS, 0x26e377, 19, "" }, + { STR_M_USA,1, 0,SERV_GS, 0x26e397, 19, "" }, + { STR_M_USA,1, 0,SERV_GS, 0x26e3b7, 19, "" }, + { STR_M_USA,1, 0,SERV_GS, 0x26e3d6, 19, "" }, + { STR_M_USA,1, 0,SERV_GS, 0x26e3f9, 19, "" }, + { STR_M_USA,1, 0,SERV_GS, 0x26e41e, 19, "" }, + { STR_M_USA,1, 0,SERV_GS, 0x26e43c, 19, "" }, + { STR_M_USA,1, 0,SERV_GS, 0x272b05, 19, "" }, + { STR_M_USA,1, 0,SERV_GS, 0x273275, 19, "" }, + { STR_M_USA,1, 0,SERV_GS, 0x273c8d, 19, "" }, + { STR_M_USA,1, 0,SERV_GS, 0x274e2e, 19, "" }, + { STR_M_USA,1, 0,SERV_GS, 0x275822, 19, "" }, + { STR_M_USA,1, 0,SERV_GS, 0x275a48, 19, "" }, + { STR_M_USA,1, 0,SERV_GS, 0x275a64, 19, "" }, + { STR_M_USA,1, 0,SERV_GS, 0x275a80, 19, "" }, + { STR_M_USA,1, 0,SERV_GS, 0x275bd0, 19, "" }, + { STR_M_USA,1, 0,SERV_GS, 0x275c54, 19, "" }, + + { STR_M_JAP,0, 2,SERV_NONE, 0x38a212, 5, "" }, + { STR_M_JAP,0, 2,SERV_NONE, 0x38a32c, 5, "" }, + { STR_M_JAP,2, 2,SERV_MKW_RACE, 0x389b6c, 75, "/raceservice/maindl_%s_%s.ashx" }, + { STR_M_JAP,2, 2,SERV_MKW_RACE, 0x389c38, 78, "/raceservice/messagedl_%s_%s.ashx" }, + { STR_M_JAP,0, 2,SERV_MKW_RACE, 0x38a0d0, 84, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_JAP,0, 1,SERV_MKW_RACE, 0x38a125, 83, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_JAP,0, 2,SERV_SAKE, 0x389bb8, 100, "/SakeFileServer/ghostdownload.aspx?gameid=1687®ion=0" }, + { STR_M_JAP,0, 0,SERV_GS, 0x38a19c, 117, "/SakeFileServer/ghostupload.aspx?gameid=%d®ionid=%d&courseid=%d&score=%d&pid=%d&playerinfo=%s%s" }, + { STR_M_JAP,0, 0,SERV_GS, 0x38a2cf, 92, "/SakeFileServer/ghostdownload.aspx?gameid=1687®ion=0&p0=%d&c0=%d&t0=%d" }, + { STR_M_JAP,0, 0,SERV_GS, 0x38a47c, 58, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_JAP,0, 0,SERV_GS, 0x38a5e5, 58, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_JAP,0, 0,SERV_GS, 0x38a713, 58, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_JAP,0, 0,SERV_GS, 0x38a7f4, 58, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_JAP,0, 0,SERV_GS, 0x38a8e9, 58, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_JAP,0, 0,SERV_GS, 0x38a9fe, 58, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_JAP,0, 0,SERV_GS, 0x38ab10, 58, "/RaceService/NintendoRacingService.asmx" }, + + { STR_M_JAP,9, 2,SERV_NONE, 0x279178, 8, "" }, // "https://" + { STR_M_JAP,9, 2,SERV_NONE, 0x279188, 8, "" }, // "https://" + { STR_M_JAP,9, 2,SERV_NONE, 0x2793f8, 8, "" }, // "https://" + { STR_M_JAP,9, 2,SERV_NONE, 0x29cee8, 8, "" }, // "https://" + { STR_M_JAP,9, 2,SERV_NONE, 0x29dd08, 8, "" }, // "https://" + + { STR_M_JAP,5, 2,SERV_NASW, 0x275ea8, 34, "/ac" }, + { STR_M_JAP,1, 2,SERV_NASW, 0x275f28, 34, "/pr" }, + { STR_M_JAP,5, 2,SERV_NASW_DEV, 0x275ecc, 38, "/ac" }, + { STR_M_JAP,1, 2,SERV_NASW_DEV, 0x275f4c, 38, "/pr" }, + { STR_M_JAP,5, 2,SERV_NASW_TEST, 0x275e80, 39, "/ac" }, + { STR_M_JAP,1, 2,SERV_NASW_TEST, 0x275f00, 39, "/pr" }, + { STR_M_JAP,1, 2,SERV_S_SAKE, 0x2757d8, 72, "/SakeStorageServer/StorageServer.asmx" }, + { STR_M_JAP,1, 2,SERV_S_SAKE, 0x275824, 62, "/SakeFileServer/upload.aspx" }, + { STR_M_JAP,1, 2,SERV_S_SAKE, 0x275864, 64, "/SakeFileServer/download.aspx" }, + { STR_M_JAP,1, 1,SERV_S_SAKE, 0x279b20, 71, "/SakeStorageServer/StorageServer.asmx" }, + { STR_M_JAP,1, 0,SERV_GS, 0x27123e, 19, "" }, + { STR_M_JAP,1, 0,SERV_GS, 0x271fb5, 19, "" }, + { STR_M_JAP,1, 0,SERV_GS, 0x271fd1, 19, "" }, + { STR_M_JAP,1, 0,SERV_GS, 0x271ff2, 19, "" }, + { STR_M_JAP,1, 0,SERV_GS, 0x272013, 19, "" }, + { STR_M_JAP,1, 0,SERV_GS, 0x272035, 19, "" }, + { STR_M_JAP,1, 0,SERV_GS, 0x272057, 19, "" }, + { STR_M_JAP,1, 0,SERV_GS, 0x272077, 19, "" }, + { STR_M_JAP,1, 0,SERV_GS, 0x272097, 19, "" }, + { STR_M_JAP,1, 0,SERV_GS, 0x2720b6, 19, "" }, + { STR_M_JAP,1, 0,SERV_GS, 0x2720d9, 19, "" }, + { STR_M_JAP,1, 0,SERV_GS, 0x2720fe, 19, "" }, + { STR_M_JAP,1, 0,SERV_GS, 0x27211c, 19, "" }, + { STR_M_JAP,1, 0,SERV_GS, 0x2767e5, 19, "" }, + { STR_M_JAP,1, 0,SERV_GS, 0x276f55, 19, "" }, + { STR_M_JAP,1, 0,SERV_GS, 0x27796d, 19, "" }, + { STR_M_JAP,1, 0,SERV_GS, 0x278b0e, 19, "" }, + { STR_M_JAP,1, 0,SERV_GS, 0x279502, 19, "" }, + { STR_M_JAP,1, 0,SERV_GS, 0x279728, 19, "" }, + { STR_M_JAP,1, 0,SERV_GS, 0x279744, 19, "" }, + { STR_M_JAP,1, 0,SERV_GS, 0x279760, 19, "" }, + { STR_M_JAP,1, 0,SERV_GS, 0x2798b0, 19, "" }, + { STR_M_JAP,1, 0,SERV_GS, 0x279934, 19, "" }, + + { STR_M_KOR,2, 2,SERV_MKW_RACE, 0x38a7a4, 75, "/raceservice/maindl_%s_%s.ashx" }, + { STR_M_KOR,2, 2,SERV_MKW_RACE, 0x38a858, 78, "/raceservice/messagedl_%s_%s.ashx" }, + { STR_M_KOR,0, 2,SERV_MKW_RACE, 0x38ad10, 84, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_KOR,0, 2,SERV_MKW_RACE, 0x38ad65, 89, "/RaceServiceStage/NintendoRacingService.asmx" }, + { STR_M_KOR,0, 2,SERV_SAKE, 0x38a7f0, 100, "/SakeFileServer/ghostdownload.aspx?gameid=1687®ion=0" }, + { STR_M_KOR,0, 2,SERV_SAKE, 0x38adcb, 131, "/%s/ghostupload.aspx?gameid=%d®ionid=%d&courseid=%d&score=%d&pid=%d&playerinfo=%s%s" }, + { STR_M_KOR,0, 2,SERV_SAKE, 0x38af0b, 106, "/%s/ghostdownload.aspx?gameid=1687®ion=0&p0=%d&c0=%d&t0=%d" }, + { STR_M_KOR,0, 0,SERV_GS, 0x38b0dc, 58, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_KOR,0, 0,SERV_GS, 0x38b245, 58, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_KOR,0, 0,SERV_GS, 0x38b373, 58, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_KOR,0, 0,SERV_GS, 0x38b454, 58, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_KOR,0, 0,SERV_GS, 0x38b549, 58, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_KOR,0, 0,SERV_GS, 0x38b65e, 58, "/RaceService/NintendoRacingService.asmx" }, + { STR_M_KOR,0, 0,SERV_GS, 0x38b770, 58, "/RaceService/NintendoRacingService.asmx" }, + + { STR_M_KOR,9, 2,SERV_NONE, 0x2676a8, 8, "" }, // "https://" + { STR_M_KOR,9, 2,SERV_NONE, 0x2676b8, 8, "" }, // "https://" + { STR_M_KOR,9, 2,SERV_NONE, 0x267928, 8, "" }, // "https://" + { STR_M_KOR,9, 2,SERV_NONE, 0x28b570, 8, "" }, // "https://" + { STR_M_KOR,9, 2,SERV_NONE, 0x28c390, 8, "" }, // "https://" + + { STR_M_KOR,5, 2,SERV_NASW, 0x2643d8, 34, "/ac" }, + { STR_M_KOR,1, 2,SERV_NASW, 0x264458, 34, "/pr" }, + { STR_M_KOR,5, 2,SERV_NASW_DEV, 0x2643fc, 38, "/ac" }, + { STR_M_KOR,1, 2,SERV_NASW_DEV, 0x26447c, 38, "/pr" }, + { STR_M_KOR,5, 2,SERV_NASW_TEST, 0x2643b0, 39, "/ac" }, + { STR_M_KOR,1, 2,SERV_NASW_TEST, 0x264430, 39, "/pr" }, + { STR_M_KOR,1, 2,SERV_S_SAKE, 0x263c38, 72, "/SakeStorageServer/StorageServer.asmx" }, + { STR_M_KOR,1, 2,SERV_S_SAKE, 0x263c84, 62, "/SakeFileServer/upload.aspx" }, + { STR_M_KOR,1, 2,SERV_S_SAKE, 0x263cc4, 64, "/SakeFileServer/download.aspx" }, + { STR_M_KOR,1, 2,SERV_S_SAKE, 0x263d08, 75, "/SakeStorageServerDev/StorageServer.asmx" }, + { STR_M_KOR,1, 2,SERV_S_SAKE, 0x263d54, 65, "/SakeFileServerDev/upload.aspx" }, + { STR_M_KOR,1, 2,SERV_S_SAKE, 0x263d98, 67, "/SakeFileServerDev/download.aspx" }, + { STR_M_KOR,1, 1,SERV_S_SAKE, 0x268050, 71, "/SakeStorageServer/StorageServer.asmx" }, + { STR_M_KOR,1, 0,SERV_GS, 0x25f69e, 19, "" }, + { STR_M_KOR,1, 0,SERV_GS, 0x260415, 19, "" }, + { STR_M_KOR,1, 0,SERV_GS, 0x260431, 19, "" }, + { STR_M_KOR,1, 0,SERV_GS, 0x260452, 19, "" }, + { STR_M_KOR,1, 0,SERV_GS, 0x260473, 19, "" }, + { STR_M_KOR,1, 0,SERV_GS, 0x260495, 19, "" }, + { STR_M_KOR,1, 0,SERV_GS, 0x2604b7, 19, "" }, + { STR_M_KOR,1, 0,SERV_GS, 0x2604d7, 19, "" }, + { STR_M_KOR,1, 0,SERV_GS, 0x2604f7, 19, "" }, + { STR_M_KOR,1, 0,SERV_GS, 0x260516, 19, "" }, + { STR_M_KOR,1, 0,SERV_GS, 0x260539, 19, "" }, + { STR_M_KOR,1, 0,SERV_GS, 0x26055e, 19, "" }, + { STR_M_KOR,1, 0,SERV_GS, 0x26057c, 19, "" }, + { STR_M_KOR,1, 0,SERV_GS, 0x264d15, 19, "" }, + { STR_M_KOR,1, 0,SERV_GS, 0x265485, 19, "" }, + { STR_M_KOR,1, 0,SERV_GS, 0x265e9d, 19, "" }, + { STR_M_KOR,1, 0,SERV_GS, 0x26703e, 19, "" }, + { STR_M_KOR,1, 0,SERV_GS, 0x267a32, 19, "" }, + { STR_M_KOR,1, 0,SERV_GS, 0x267c58, 19, "" }, + { STR_M_KOR,1, 0,SERV_GS, 0x267c74, 19, "" }, + { STR_M_KOR,1, 0,SERV_GS, 0x267c90, 19, "" }, + { STR_M_KOR,1, 0,SERV_GS, 0x267de0, 19, "" }, + { STR_M_KOR,1, 0,SERV_GS, 0x267e64, 19, "" }, + + {0,0,0,0,0,0,0} +}; + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// data access /////////////// +/////////////////////////////////////////////////////////////////////////////// + +ccp GetStrModeName ( str_mode_t mode ) +{ + switch (mode) + { + case STR_M_UNKNOWN: return "---"; + case STR_M_PAL: return "PAL"; + case STR_M_USA: return "USA"; + case STR_M_JAP: return "JAP"; + case STR_M_KOR: return "KOR"; + case STR_M__N: return "???"; + } + return "???"; +} + +/////////////////////////////////////////////////////////////////////////////// + +char GetStrModeRegionChar ( str_mode_t mode ) +{ + switch (mode) + { + case STR_M_PAL: return 'P'; + case STR_M_USA: return 'E'; + case STR_M_JAP: return 'J'; + case STR_M_KOR: return 'K'; + default: return 0; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +static u32 GetIdAddress ( const staticr_t * str ) +{ + if (str) + { + switch (str->mode) + { + case STR_M_PAL: return 0x80276054; + case STR_M_USA: return 0x80271d14; + case STR_M_JAP: return 0x802759f4; + case STR_M_KOR: return 0x80263e34; + default: return 0; + } + } + return 0; +} + +//----------------------------------------------------------------------------- + +static char * GetIdPointer ( const staticr_t * str ) +{ + const u32 addr = GetIdAddress(str); + if (addr) + { + const dol_header_t *dol_head = (dol_header_t*)str->data; + const u32 off = GetDolOffsetByAddr(dol_head,addr,PATCHED_BY_SIZE,0); + if (off) + return (char*)str->data + off; + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +const u32 * GetTrackOffsetTab ( const staticr_t * str ) +{ + if (str) + { + switch (str->mode) + { + case STR_M_PAL: return pal_track_offset; + case STR_M_USA: return usa_track_offset; + case STR_M_JAP: return jap_track_offset; + case STR_M_KOR: return kor_track_offset; + default: return 0; + } + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +const u32 * GetArenaOffsetTab ( const staticr_t * str ) +{ + if (str) + { + switch (str->mode) + { + case STR_M_PAL: return pal_arena_offset; + case STR_M_USA: return usa_arena_offset; + case STR_M_JAP: return jap_arena_offset; + case STR_M_KOR: return kor_arena_offset; + default: return 0; + } + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +const u32 * GetAllRanksOffsetTab ( const staticr_t * str ) +{ + if (str) + { + switch (str->mode) + { + case STR_M_PAL: return pal_all_ranks_offset; + case STR_M_USA: return usa_all_ranks_offset; + case STR_M_JAP: return jap_all_ranks_offset; + case STR_M_KOR: return kor_all_ranks_offset; + default: return 0; + } + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +const u32 * GetVsBtOffsetTab ( const staticr_t * str, bool battle ) +{ + if (str) + { + if (battle) + { + switch (str->mode) + { + case STR_M_PAL: return pal_bt_offset; + case STR_M_USA: return usa_bt_offset; + case STR_M_JAP: return jap_bt_offset; + case STR_M_KOR: return kor_bt_offset; + default: return 0; + } + } + else + { + switch (str->mode) + { + case STR_M_PAL: return pal_vs_offset; + case STR_M_USA: return usa_vs_offset; + case STR_M_JAP: return jap_vs_offset; + case STR_M_KOR: return kor_vs_offset; + default: return 0; + } + } + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +const u32 * GetMenuOffsetTab ( str_mode_t mode ) +{ + switch (mode) + { + case STR_M_PAL: return pal_menu_offset; + case STR_M_USA: return usa_menu_offset; + case STR_M_JAP: return jap_menu_offset; + case STR_M_KOR: return kor_menu_offset; + default: return 0; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +#define ORIG_VBI_VALUE 0x4e800020 + +static u32 GetVbiAddress ( const staticr_t * str ) +{ + DASSERT(str); + switch (str->mode) + { + case STR_M_PAL: return 0x801bab20; + case STR_M_USA: return 0x801baa80; + case STR_M_JAP: return 0x801baa40; + case STR_M_KOR: return 0x801bae7c; + default: return FindDolAddressOfVBI(str->data,str->data_size); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +#define ORIG_SDK_VERS "001000\0" // one more '\0' is added by compiler + +static u32 GetSdkverAddress ( str_mode_t mode ) +{ + // return address of string '001000\0\0' + // string 'sdkver\0\0' follows with offset +8 + + switch (mode) + { + case STR_M_PAL: return 0x80384fd0; + case STR_M_USA: return 0x80380c50; + case STR_M_JAP: return 0x80384950; + case STR_M_KOR: return 0x80372fd0; + default: return 0; + } +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// second host at nas login /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static u32 GetSecondHostAddress ( str_mode_t mode, u32 *ret_orig ) +{ + // PAL: Offset 800ed868, original 0x480eb86d, neu 0x60000000 + // USA: Offset 800ed7c8, original 0x480eb86d, neu 0x60000000 + // JAP: Offset 800ed788, original 0x480eb86d, neu 0x60000000 + // KOR: Offset 800ed8e0, original 0x480ebb51, neu 0x60000000 + + if (ret_orig) + *ret_orig = mode == STR_M_KOR ? 0x480ebb51 : 0x480eb86d; + + switch (mode) + { + case STR_M_PAL: return 0x800ed868; + case STR_M_USA: return 0x800ed7c8; + case STR_M_JAP: return 0x800ed788; + case STR_M_KOR: return 0x800ed8e0; + default: return 0; + } +} + +//----------------------------------------------------------------------------- + +static u32 * GetSecondHostPointer ( const staticr_t * str, u32 *ret_orig ) +{ + const u32 addr = GetSecondHostAddress(str->mode,ret_orig); + if (addr) + { + const dol_header_t *dol_head = (dol_header_t*)str->data; + const u32 off = GetDolOffsetByAddr(dol_head,addr,4,0); + if (off) + return (u32*)(str->data + off); + } + return 0; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// wiimmfi codes /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static const u8 wiimmfi_code_pal_bz2[] = +{ + // 4 bytes decompressed len + 0x00,0x00,0x01,0x18, + + // bzipped data + 0x42,0x5a,0x68,0x39, 0x31,0x41,0x59,0x26, 0x53,0x59,0xe0,0xa4, 0xf4,0x97,0x00,0x00, + 0x27,0x7f,0xfd,0xff, 0xd7,0xcd,0x42,0xe6, 0x56,0x00,0x5c,0x74, 0x65,0x84,0x00,0x60, + 0x42,0x00,0x24,0x7c, 0x42,0x44,0x80,0x6d, 0x6c,0x00,0x04,0x54, 0x30,0x09,0x00,0xc4, + 0x5c,0xb0,0x00,0xd9, 0x8c,0x70,0xd3,0x4c, 0x10,0xc8,0x69,0xa6, 0x46,0x4c,0x20,0x1a, + 0x68,0x03,0x09,0xa3, 0x4c,0x98,0x00,0x40, 0xd0,0x6a,0x69,0x46, 0xd4,0xd0,0xd1,0xa4, + 0xc0,0x00,0x32,0x00, 0x00,0x8c,0x0d,0x00, 0x34,0x32,0x4c,0xc9, 0xa1,0x04,0x4d,0x4d, + 0x06,0x80,0x00,0x06, 0x80,0x34,0x0d,0x01, 0xa1,0x90,0x34,0x0c, 0x80,0x03,0x12,0x46, + 0x06,0xbe,0x9a,0x92, 0xa6,0x1b,0x60,0xf3, 0x6f,0x35,0x10,0x01, 0xa1,0xd6,0xd4,0x64, + 0x10,0xcb,0x04,0x73, 0x81,0xc8,0x82,0x20, 0x03,0x02,0xca,0xcd, 0x3d,0x4c,0xe4,0xb8, + 0xac,0x91,0xdc,0xa1, 0x90,0xe1,0xa8,0x81, 0xa2,0x9c,0x05,0xc6, 0xa0,0xf2,0x82,0xaa, + 0x02,0x49,0x45,0x0c, 0x04,0x26,0x10,0x90, 0xdc,0xf7,0x57,0x43, 0x99,0x8c,0x29,0x26, + 0x3f,0x8e,0x05,0x82, 0x03,0xa9,0x1a,0xe8, 0xde,0x7b,0x29,0x22, 0xfc,0x74,0x21,0x91, + 0x50,0x43,0x29,0x9d, 0xf4,0x8c,0x69,0xff, 0xb1,0x09,0xa4,0x5f, 0xd0,0xfc,0x66,0x24, + 0xd5,0x53,0x6c,0x59, 0x0d,0xb6,0x07,0xe0, 0x1b,0x98,0xcf,0xa9, 0xf1,0xa0,0x4b,0x23, + 0x2e,0xbf,0xcd,0xce, 0x59,0x65,0xdf,0x8d, 0xcd,0xa4,0xac,0x46, 0xc0,0xac,0x91,0xab, + 0xf8,0x3b,0x2b,0x49, 0x4c,0x24,0x1a,0x22, 0x3f,0x99,0xed,0x48, 0x28,0x06,0xad,0x2d, + 0x19,0x7b,0x07,0x61, 0x05,0x5c,0xf6,0x43, 0x93,0x95,0x54,0x58, 0xc0,0xe1,0xfb,0xba, + 0xd7,0x72,0x1a,0x68, 0x3a,0x9e,0x81,0xde, 0xa2,0xee,0x07,0x9e, 0x5a,0x9b,0x3c,0x04, + 0x9f,0xf8,0xbb,0x92, 0x29,0xc2,0x84,0x87, 0x05,0x27,0xa4,0xb8, + // [300 Bytes] +}; + +static BZ2Manager_t wiimmfi_code_pal_mgr + = { wiimmfi_code_pal_bz2, sizeof(wiimmfi_code_pal_bz2), 0, 0 }; + +//----------------------------------------------------------------------------- + +static const u8 wiimmfi_code_usa_bz2[] = +{ + // 4 bytes decompressed len + 0x00,0x00,0x01,0x18, + + // bzipped data + 0x42,0x5a,0x68,0x39, 0x31,0x41,0x59,0x26, 0x53,0x59,0x24,0x09, 0x21,0x7b,0x00,0x00, + 0x28,0x7f,0xfd,0xff, 0xd7,0xcd,0x42,0xe6, 0x56,0x00,0x5c,0x70, 0x65,0x84,0x44,0x60, + 0x42,0x00,0x24,0x7c, 0x42,0x44,0x80,0x6d, 0x6c,0x00,0x04,0x54, 0x30,0x09,0x00,0xc0, + 0x18,0xb0,0x00,0xd9, 0xb4,0x22,0x50,0x64, 0x68,0x30,0x98,0x40, 0x68,0x18,0x8c,0x02, + 0x00,0x68,0xc8,0x00, 0xc2,0x61,0x04,0x53, 0xd2,0x32,0x9a,0x32, 0x68,0x00,0x34,0x0c, + 0x80,0x1a,0x06,0x81, 0xa0,0x00,0x1a,0x68, 0xc4,0xf5,0x06,0xa6, 0xa7,0xa9,0xa8,0x00, + 0x06,0x80,0x00,0x03, 0x40,0x01,0xa1,0x90, 0x00,0x69,0xa0,0x0e, 0x65,0x49,0x81,0x7c, + 0xa8,0xd3,0x51,0x16, 0x82,0x77,0xf6,0x80, 0x90,0x34,0xb7,0xc7, 0x83,0x21,0x2c,0xb0, + 0x46,0x60,0xc8,0x84, 0x40,0x18,0x43,0x2b, 0xb4,0xf1,0xd9,0x96, 0x24,0x2e,0xa9,0xf7, + 0xa1,0x98,0xc6,0xc2, 0x0d,0x14,0xd0,0x5d, 0x2a,0xa3,0xac,0x1a, 0x89,0x0b,0x14,0x51, + 0x84,0x90,0xa0,0x0e, 0x12,0xdc,0xa7,0xf8, 0xc6,0x96,0xd8,0x51, 0x0a,0xbb,0x40,0xe8, + 0x80,0x5c,0x10,0x0f, 0x42,0x83,0x41,0xcc, 0x97,0x4a,0x6c,0x73, 0x0c,0x67,0x42,0xc0, + 0x28,0x34,0x5e,0xda, 0x0d,0xa6,0xff,0x18, 0xc9,0x15,0xa7,0x12, 0x0d,0x02,0x9a,0xca, + 0x2a,0x64,0x9f,0x40, 0x39,0x96,0x00,0xf7, 0x4d,0xdc,0x7a,0xfb, 0xa8,0x2a,0xd6,0xe8, + 0x09,0x44,0xe7,0xed, 0x3e,0x7c,0x91,0x47, 0x1d,0xe9,0x8c,0xb2, 0x58,0x06,0x31,0x84, + 0xa4,0x54,0x60,0x48, 0xea,0xa0,0x30,0x7c, 0x11,0x22,0xcb,0xbd, 0x2c,0x62,0x20,0xc4, + 0xe3,0x36,0xe8,0x45, 0x05,0xa1,0x80,0x43, 0xa4,0x35,0x99,0x55, 0x94,0x01,0x10,0x2b, + 0x8c,0x40,0xa4,0x42, 0x91,0x57,0xc0,0x87, 0x5c,0xe7,0x3a,0x38, 0x8d,0xef,0xf8,0xbb, + 0x92,0x29,0xc2,0x84, 0x81,0x20,0x49,0x0b, 0xd8, + // [297 Bytes] +}; + +static BZ2Manager_t wiimmfi_code_usa_mgr + = { wiimmfi_code_usa_bz2, sizeof(wiimmfi_code_usa_bz2), 0, 0 }; + +//----------------------------------------------------------------------------- + +static const u8 wiimmfi_code_jap_bz2[] = +{ + // 4 bytes decompressed len + 0x00,0x00,0x01,0x18, + + // bzipped data + 0x42,0x5a,0x68,0x39, 0x31,0x41,0x59,0x26, 0x53,0x59,0x19,0x2d, 0x5f,0x73,0x00,0x00, + 0x27,0x7f,0xfd,0xff, 0xd7,0xcd,0x46,0xe6, 0x56,0x00,0x5c,0x70, 0x65,0x84,0x00,0x64, + 0x42,0x00,0x24,0x7c, 0x42,0x44,0x80,0x6d, 0x6c,0x00,0x04,0x54, 0x24,0x11,0x00,0xc0, + 0x18,0xb0,0x00,0xd9, 0x34,0x35,0x10,0x6a, 0x68,0x34,0xd0,0x34, 0x00,0x34,0x34,0x64, + 0x34,0xd0,0x00,0xd0, 0x01,0xa6,0x26,0x80, 0x22,0x9e,0x94,0x64, 0x19,0x0d,0x1a,0x32, + 0x06,0x8d,0x34,0x00, 0x34,0x1a,0x62,0x34, 0x00,0x01,0x8d,0x47, 0xa8,0x41,0x13,0x53, + 0x40,0x00,0xd0,0x01, 0xa0,0x0d,0x03,0x40, 0xf5,0x06,0x40,0xd0, 0x32,0x00,0x32,0xa8, + 0x60,0xea,0xb1,0xaa, 0x2e,0x61,0xb8,0x0f, 0xb8,0x2b,0x09,0x00, 0x1a,0x5e,0x73,0x83, + 0x40,0x86,0x92,0x47, 0x38,0x1c,0x88,0x23, 0x80,0x24,0x5a,0x61, 0xb7,0xea,0x9c,0x99, + 0x16,0x14,0x3b,0xb4, 0xb3,0x1c,0x36,0x10, 0x36,0x54,0x00,0xb9, 0xd6,0x1e,0x91,0x17, + 0x40,0x2c,0x52,0x03, 0x11,0x09,0x84,0x25, 0xb9,0x45,0xe6,0x50, 0xea,0x73,0x9c,0x53, + 0xb5,0x58,0x24,0xfc, 0x88,0x0c,0x14,0x0e, 0xe5,0x23,0x43,0x89, 0xcc,0xa2,0x66,0xd5, + 0x31,0x9d,0x16,0x84, 0x72,0xd3,0x79,0xc1, 0x99,0x2f,0x5b,0xe3, 0x42,0x66,0xf6,0xa0, + 0x34,0x95,0x25,0x24, 0x27,0x32,0x1f,0x20, 0x72,0x96,0x07,0x0d, 0x6e,0x20,0x48,0x8a, + 0x94,0x96,0x17,0x5f, 0xef,0x2f,0xac,0x40, 0x7b,0x2f,0xd0,0xf6, 0xa2,0x6c,0x00,0xb2, + 0x24,0xb8,0xf1,0xce, 0xad,0x39,0x20,0x88, 0x7c,0x44,0x90,0x55, 0xf6,0xa0,0xc8,0x39, + 0x85,0x10,0xd3,0xe4, 0x25,0x04,0xd2,0xc4, 0x21,0xcc,0xb6,0x11, 0xb4,0x70,0x10,0x23, + 0xeb,0x63,0xe9,0x51, 0x92,0x81,0x12,0x8b, 0x00,0xc6,0x35,0x73, 0x1b,0xf1,0xed,0x1a, + 0x0f,0xe2,0xee,0x48, 0xa7,0x0a,0x12,0x03, 0x25,0xab,0xee,0x60, + // [300 Bytes] +}; + +static BZ2Manager_t wiimmfi_code_jap_mgr + = { wiimmfi_code_jap_bz2, sizeof(wiimmfi_code_jap_bz2), 0, 0 }; + +//----------------------------------------------------------------------------- + +static const u8 wiimmfi_code_kor_bz2[] = +{ + // 4 bytes decompressed len + 0x00,0x00,0x01,0x18, + + // bzipped data + 0x42,0x5a,0x68,0x39, 0x31,0x41,0x59,0x26, 0x53,0x59,0xc2,0x0b, 0xe6,0xb5,0x00,0x00, + 0x27,0x7f,0xfd,0xff, 0xd7,0xcd,0x42,0xe4, 0x76,0x00,0x5c,0x70, 0x61,0xd4,0x40,0x60, + 0x46,0x00,0x24,0x7c, 0x42,0x44,0x80,0x6d, 0x6c,0x00,0x04,0x54, 0x28,0x05,0x00,0xc0, + 0x18,0xb0,0x00,0xd9, 0xb5,0x11,0x28,0x34, 0x68,0x06,0x9a,0x69, 0xa6,0x4d,0x34,0xd1, + 0x91,0xa6,0x9a,0x1a, 0x18,0x20,0x0d,0x00, 0x68,0xda,0x43,0x6a, 0x0d,0x53,0xd2,0x99, + 0xa2,0x19,0x00,0xd0, 0x03,0x40,0x00,0x68, 0x00,0x00,0x00,0x34, 0x62,0x68,0x35,0x34, + 0x4d,0x46,0x80,0x00, 0x03,0x40,0x00,0x00, 0xd1,0xa0,0xd0,0x1a, 0x06,0x40,0x02,0xea, + 0x1c,0x46,0xbc,0x75, 0xa8,0x9c,0xd6,0x03, 0xad,0xfd,0x5f,0xa4, 0x0d,0x0e,0x35,0xc1, + 0x90,0x96,0x58,0x24, 0x20,0x20,0x88,0x44, 0x01,0x80,0xc9,0x5a, 0xd6,0xab,0xb4,0x16, + 0x13,0x5b,0x51,0x0d, 0xac,0xba,0x06,0xc2, 0x0c,0x94,0xd0,0x5c, 0xea,0x1b,0xa4,0x0a, + 0x69,0x12,0x0a,0x28, 0xc0,0x46,0x39,0x84, 0x76,0xa7,0x39,0x55, 0x2d,0xe6,0x38,0xf0, + 0x49,0x55,0x07,0x9f, 0x01,0x60,0x80,0xf1, 0xf6,0xf0,0xec,0x88, 0x16,0xae,0xa8,0xca, + 0xe7,0x3d,0x30,0xa9, 0x4c,0x6b,0x50,0xc4, 0x9b,0x7b,0x9f,0xed, 0x3b,0x3a,0x51,0x19, + 0x49,0x48,0x4a,0xad, 0x17,0xe5,0x60,0x0d, 0xab,0x70,0xe3,0xab, 0x67,0x91,0x81,0x42, + 0x51,0x19,0x42,0xc5, 0x18,0x03,0x12,0x73, 0x93,0x26,0x68,0x86, 0x3b,0x9f,0x8d,0xab, + 0x18,0x02,0xe5,0x09, 0x88,0xa5,0xfa,0x5e, 0xc9,0x60,0x90,0xf8, 0x44,0x65,0xa8,0xb5, + 0x18,0x93,0x42,0xb2, 0xe7,0x91,0xe8,0x3f, 0x14,0xa1,0xba,0xe1, 0x0e,0xae,0xb0,0xad, + 0x54,0x01,0x82,0x2a, 0x30,0xe4,0x04,0xd2, 0x34,0x16,0xc1,0x9e, 0x9a,0x42,0x12,0x63, + 0x53,0x87,0xfc,0x5d, 0xc9,0x14,0xe1,0x42, 0x43,0x08,0x2f,0x9a, 0xd4, + // [301 Bytes] +}; + +static BZ2Manager_t wiimmfi_code_kor_mgr + = { wiimmfi_code_kor_bz2, sizeof(wiimmfi_code_kor_bz2), 0, 0 }; + +//----------------------------------------------------------------------------- + +static BZ2Manager_t * GetWiimmfiCode ( str_mode_t mode ) +{ + switch (mode) + { + case STR_M_PAL: return &wiimmfi_code_pal_mgr; + case STR_M_USA: return &wiimmfi_code_usa_mgr; + case STR_M_JAP: return &wiimmfi_code_jap_mgr; + case STR_M_KOR: return &wiimmfi_code_kor_mgr; + default: return 0; + } +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// lecode data /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static const u8 lecode_loader_pal_bz2[] = +{ + // decompressed len: 0x200 = 512 bytes + 0x00,0x00,0x02,0x00, + + // bzipped data + 0x42,0x5a,0x68,0x39, 0x31,0x41,0x59,0x26, 0x53,0x59,0xa1,0xb1, 0x2c,0x5f,0x00,0x00, + 0x16,0x7f,0xff,0xfc, 0x76,0x45,0x30,0x60, 0xc7,0xc4,0x6f,0x2f, 0x6f,0xc4,0x84,0x7f, + 0xe7,0xfe,0x6e,0xdc, 0x04,0x44,0x0c,0x43, 0x60,0x00,0x15,0x54, 0x00,0x48,0x49,0x7a, + 0x40,0x00,0x01,0xb0, 0x01,0x59,0xb2,0x20, 0xd4,0xd4,0xd0,0xd1, 0x4d,0xa9,0xb5,0x34, + 0xf5,0x3d,0x40,0x7a, 0x80,0x68,0x1b,0x50, 0x64,0xf5,0x03,0x40, 0x3c,0xa1,0xa0,0x06, + 0x43,0xd4,0xc8,0xf5, 0x19,0x1e,0x88,0x7b, 0x54,0x22,0x9e,0x80, 0x98,0x4d,0x49,0xe9, + 0x3d,0x4f,0x24,0x01, 0xa0,0x00,0x0d,0x00, 0x1a,0x0d,0x00,0x00, 0xd3,0x4f,0x29,0x88, + 0x00,0x64,0x0d,0x4d, 0x48,0xd3,0x11,0x18, 0x09,0x9a,0x99,0x18, 0x9a,0x69,0x89,0x93, + 0x10,0xc9,0x84,0x32, 0x64,0x34,0x61,0x36, 0x8d,0x4c,0x68,0x8f, 0x51,0xa6,0x34,0x09, + 0x90,0x29,0xc9,0x9c, 0x3a,0x07,0xfa,0xe1, 0x92,0x40,0x83,0x36, 0x02,0x8a,0x62,0x3f, + 0xb9,0x73,0x96,0x54, 0x1d,0xea,0x43,0xbc, 0x8c,0xb1,0x75,0x00, 0xd4,0xe6,0x09,0x05, + 0xb5,0x08,0xc9,0x83, 0xc5,0x95,0xcb,0x97, 0xa4,0x10,0xfc,0x88, 0x6b,0x5c,0x06,0x08, + 0xa4,0x31,0x85,0xa7, 0x80,0x46,0xeb,0x37, 0x3a,0xa8,0x18,0x22, 0x01,0x17,0xf6,0x46, + 0x43,0x05,0xdc,0x21, 0x55,0x8e,0x6e,0xc5, 0x89,0xaa,0x1b,0x08, 0xa6,0x7c,0x55,0x37, + 0x85,0x02,0x55,0xaa, 0x2d,0x62,0xf7,0xf4, 0xde,0x0b,0x2e,0xbb, 0xf2,0xa3,0x29,0x42, + 0xe6,0x78,0x2d,0x2d, 0xeb,0x95,0xdb,0xb1, 0x49,0x30,0xb7,0x11, 0xd4,0xa1,0x0c,0x2b, + 0x2c,0x22,0x54,0xd8, 0x87,0xeb,0x40,0xe5, 0x18,0xca,0xfa,0x10, 0xe9,0x92,0x3a,0xee, + 0xc1,0x41,0x9c,0x0a, 0x45,0xe2,0x46,0xed, 0x58,0x1a,0x0a,0xf7, 0xe8,0x5c,0x42,0x4d, + 0xd6,0x77,0x31,0xf7, 0xac,0x48,0xc5,0x18, 0xe3,0x53,0x80,0x54, 0xd9,0x3d,0x52,0x40, + 0x8b,0x28,0xc4,0x73, 0x3f,0x3e,0x92,0xe1, 0x77,0xe7,0x0a,0x9a, 0xae,0x38,0xc3,0x64, + 0x75,0x14,0x14,0x14, 0x89,0x35,0x16,0x33, 0xc4,0x42,0x00,0x9d, 0xb6,0x0b,0x98,0x40, + 0xf6,0xcc,0xda,0xf4, 0x1f,0xd7,0x4c,0x76, 0x21,0x89,0x44,0x6a, 0x92,0x11,0x22,0x45, + 0x6b,0x4a,0x40,0x81, 0x27,0x8d,0xfa,0x48, 0x3e,0x21,0x02,0x47, 0x0a,0x8a,0x02,0xa2, + 0x95,0xcb,0xb2,0xe3, 0x01,0x17,0x3d,0xc5, 0x41,0xae,0x16,0xb7, 0x84,0xaf,0xa4,0x8b, + 0x62,0x06,0x18,0xd2, 0x12,0x28,0xe3,0x38, 0xa4,0x30,0x32,0x04, 0x4c,0x2a,0x4b,0x22, + 0xa4,0xe7,0x94,0x2d, 0x7c,0x63,0xf3,0x59, 0xcb,0xf7,0x6e,0xd0, 0x42,0x21,0x74,0x9b, + 0xeb,0x55,0x32,0xeb, 0xd8,0x97,0x3e,0xb7, 0xee,0x55,0xb1,0x58, 0x5d,0xb9,0x55,0xe9, + 0x47,0x11,0x18,0x7b, 0x34,0x02,0xb3,0xf9, 0xf9,0x06,0xfb,0x5b, 0x8e,0x30,0xd4,0xb2, + 0xd8,0x62,0xf8,0xae, 0x75,0x02,0x06,0x20, 0xf0,0x69,0x79,0x9e, 0x40,0x98,0x48,0xeb, + 0x63,0xa1,0x3b,0xd0, 0x1a,0xe8,0x64,0x67, 0xfe,0x51,0x09,0x4c, 0xe4,0xa7,0xbc,0xce, + 0xa1,0x94,0xad,0x87, 0xfe,0x2e,0xe4,0x8a, 0x70,0xa1,0x21,0x43, 0x62,0x58,0xbe, + // 0x1ef = 495 Bytes +}; + +static BZ2Manager_t lecode_loader_pal_mgr + = { lecode_loader_pal_bz2, sizeof(lecode_loader_pal_bz2), 0, 0 }; + +//----------------------------------------------------------------------------- + +static const u8 lecode_loader_usa_bz2[] = +{ + // decompressed len: 0x200 = 512 bytes + 0x00,0x00,0x02,0x00, + + // bzipped data + 0x42,0x5a,0x68,0x39, 0x31,0x41,0x59,0x26, 0x53,0x59,0x9f,0x2b, 0x3c,0x9b,0x00,0x00, + 0x16,0x7f,0xff,0xfc, 0x76,0x45,0x34,0x64, 0xc7,0xc0,0x6f,0x2f, 0x6f,0x8e,0x84,0x7f, + 0xe7,0xfe,0x6e,0xdc, 0x04,0x44,0x0c,0x43, 0x60,0x00,0x15,0x50, 0x40,0x48,0x49,0x7c, + 0x80,0x00,0x01,0xb0, 0x01,0x59,0x18,0xd8, 0x6a,0x68,0x20,0x9e, 0xa9,0xa7,0xa4,0x7a, + 0x23,0x40,0x00,0x07, 0x94,0x0d,0xa8,0x32, 0x01,0x84,0x00,0x1a, 0x1e,0x93,0xd2,0x69, + 0xa0,0x00,0x7e,0xa8, 0x45,0x4f,0xd3,0x53, 0x14,0xfd,0x15,0x3d, 0xa8,0x4d,0x3c,0x90, + 0x00,0x00,0x64,0xd3, 0x4d,0x00,0x34,0x00, 0x00,0x00,0x6d,0x13, 0x20,0x1a,0x7a,0x80, + 0x4a,0x9a,0x94,0xf4, 0x64,0x35,0x34,0x34, 0x64,0x18,0x8d,0x00, 0x62,0x06,0x81,0x84, + 0x68,0xc8,0x1a,0x32, 0x06,0x99,0x33,0x51, 0xa7,0xa9,0xa6,0x8c, 0x98,0x83,0x09,0x2b, + 0xc9,0x63,0x5c,0xfe, 0x70,0xc4,0x78,0x20, 0xbd,0xe2,0xad,0x5b, 0x0e,0xa6,0x38,0xb3, + 0x75,0xc5,0xa9,0x21, 0x3d,0x14,0xda,0x6d, 0x83,0xd5,0xaf,0x23, 0x10,0x3f,0x0d,0x4c, + 0xb1,0xd1,0x49,0xc4, 0x89,0x20,0x43,0xe3, 0x41,0x54,0xda,0x50, 0xcb,0xc2,0xc8,0xdf, + 0x00,0x22,0xa5,0x2b, 0x4a,0xb3,0x0a,0x19, 0x04,0x4b,0x97,0xfd, 0x97,0x2b,0x78,0x58, + 0x12,0xbb,0xd4,0x9a, 0xeb,0x24,0xd6,0x4e, 0x32,0x12,0xe1,0x3b, 0xe1,0x62,0xf8,0xf1, + 0xc6,0x57,0x0b,0x95, 0x52,0x23,0x0f,0x2e, 0xa7,0xb0,0x2d,0x64, 0x59,0x40,0x9a,0xf8, + 0x5b,0x72,0xf9,0x6c, 0xbd,0xbd,0x3f,0xd2, 0xa9,0xce,0xf5,0x3a, 0x6a,0x50,0xa8,0x93, + 0x5e,0x23,0x99,0xb1, 0xbe,0x27,0xa6,0x32, 0x1c,0x96,0xec,0x57, 0x8f,0x5a,0xe9,0xd9, + 0x90,0x90,0x11,0x74, 0x28,0x1b,0xb2,0x46, 0x9a,0x96,0x55,0x49, 0xee,0x39,0xd8,0x90, + 0xc3,0xdd,0x6d,0xcc, 0x99,0x24,0x3e,0xe0, 0xa1,0x12,0x36,0x89, 0xb1,0x5b,0x0c,0xc4, + 0x83,0x41,0x73,0x9c, 0xd0,0x6a,0x05,0x8a, 0x10,0x3e,0xfb,0x8f, 0x12,0x0e,0x72,0x51, + 0x21,0x6f,0x61,0x35, 0xb5,0x44,0x1f,0x09, 0x55,0x01,0x91,0x08, 0x24,0x9b,0x5a,0x72, + 0xf4,0xd5,0x05,0x79, 0x73,0x4d,0x0d,0x35, 0x84,0xd5,0x42,0x7a, 0x35,0x50,0x0f,0xad, + 0x30,0x52,0x35,0x27, 0x11,0x01,0x0b,0x84, 0xc8,0x04,0xc8,0x9c, 0xcf,0x37,0x3c,0x08, + 0x65,0xbb,0x89,0x4f, 0x4b,0x63,0x24,0x09, 0x49,0x5a,0x18,0xd5, 0x0c,0xc8,0x16,0x10, + 0x9a,0x46,0x51,0x21, 0xe0,0x6b,0xea,0x88, 0x4d,0x6d,0xb8,0xa4, 0xe9,0x06,0x36,0xd2, + 0x46,0x1b,0x0c,0x49, 0x7d,0x47,0x18,0x4c, 0x10,0x81,0x77,0xb1, 0xee,0xe5,0x45,0x5b, + 0xca,0x85,0x8b,0x3f, 0x7c,0x41,0xd6,0x5d, 0xf9,0x9b,0x13,0xb4, 0x9e,0x8a,0x3d,0x5a, + 0x05,0xdf,0xf4,0xf6, 0x13,0x9a,0xe2,0xc9, 0x67,0x37,0x17,0xef, 0xf4,0xbb,0xe6,0xf5, + 0xa4,0xb9,0x4c,0x41, 0x48,0x67,0x8f,0xdd, 0xc5,0x76,0x3f,0x45, 0xaf,0xe9,0x83,0x89, + 0x94,0xb5,0x4d,0xf2, 0x1d,0x19,0x5f,0x59, 0x61,0x8c,0x5b,0x19, 0xd6,0x69,0xad,0xba, + 0xc5,0x4e,0xff,0x17, 0x72,0x45,0x38,0x50, 0x90,0x9f,0x2b,0x3c, 0x9b, + // 0x1ed = 493 Bytes +}; + +static BZ2Manager_t lecode_loader_usa_mgr + = { lecode_loader_usa_bz2, sizeof(lecode_loader_usa_bz2), 0, 0 }; + +//----------------------------------------------------------------------------- + +static const u8 lecode_loader_jap_bz2[] = +{ + // decompressed len: 0x200 = 512 bytes + 0x00,0x00,0x02,0x00, + + // bzipped data + 0x42,0x5a,0x68,0x39, 0x31,0x41,0x59,0x26, 0x53,0x59,0x5f,0x33, 0xd7,0x7b,0x00,0x00, + 0x16,0x7f,0xff,0xfc, 0x76,0x45,0x30,0x60, 0xc7,0xc0,0x6f,0x2f, 0x7f,0xc4,0x84,0x7f, + 0xe7,0xfe,0x6e,0xdc, 0x44,0x44,0x0c,0x43, 0x60,0x00,0x15,0x50, 0x00,0x48,0x4d,0x6c, + 0x80,0x00,0x01,0xb0, 0x01,0x59,0x18,0xd8, 0x6a,0x04,0x34,0x4d, 0x4f,0x49,0xa7,0xa9, + 0xa7,0xa4,0x03,0xd4, 0x00,0x3f,0x54,0x0f, 0x28,0x00,0x6d,0x4c, 0x86,0x40,0xf4,0x8f, + 0x53,0x10,0xd0,0x00, 0x37,0xaa,0x11,0x53, 0xf4,0xd2,0x60,0x54, 0xf6,0xa1,0x3d,0x4f, + 0x6a,0x40,0x00,0x01, 0x90,0x01,0x90,0x00, 0x00,0x19,0x0c,0x98, 0x80,0x34,0x61,0x04, + 0xa9,0xa9,0x06,0x9a, 0x9b,0x48,0x1a,0x34, 0x68,0xc8,0x64,0x34, 0xc8,0xd1,0x91,0xa6, + 0x86,0x80,0x0d,0x34, 0xd0,0x64,0x7a,0x26, 0x9e,0xa1,0xb5,0x34, 0xd3,0x64,0x80,0xba, + 0x50,0x9e,0xb1,0xaa, 0x7f,0x38,0x3e,0x60, 0x41,0xfb,0xc5,0x9b, 0x37,0x20,0x53,0x71, + 0x66,0xda,0x16,0xaa, 0x87,0x0a,0x29,0xb4, 0x9e,0x18,0x8b,0x3c, 0x8b,0xb7,0x84,0xd4, + 0xcd,0x20,0x1d,0x6e, 0x24,0x99,0xc2,0x1f, 0x1a,0x4a,0xae,0xca, 0x88,0x4c,0x17,0x0f, + 0x4a,0x40,0x8a,0xa2, 0xad,0x36,0x97,0x51, 0x08,0x11,0x2f,0xb6, 0xf8,0xf2,0xef,0xb6, + 0x37,0x65,0x84,0x4a, 0xe1,0x51,0x51,0x10, 0x9d,0x09,0x2b,0x7d, 0xfd,0xd4,0x8d,0x34, + 0xc5,0x76,0x73,0x92, 0x46,0x41,0xe6,0xf6, 0x0f,0x86,0x45,0xb3, 0x87,0xef,0x83,0x8d, + 0x3b,0xb1,0x6d,0xee, 0x18,0x3d,0x64,0x31, 0xa7,0xd3,0xa6,0xc3, 0x02,0x44,0x12,0x89, + 0xeb,0x34,0x38,0x84, 0x08,0x94,0xa3,0x96, 0xe5,0x99,0x66,0x8e, 0x83,0x77,0xba,0x2d, + 0x98,0x0d,0x7e,0x76, 0x41,0x2c,0x52,0xb0, 0x96,0xae,0x82,0xd4, 0x2d,0x0a,0xd0,0x42, + 0xa5,0x76,0xf9,0x27, 0x32,0xd5,0xa3,0x70, 0x08,0xa3,0x3e,0xf1, 0x5a,0x15,0x61,0x21, + 0x4e,0x45,0x3d,0x03, 0x21,0x95,0x4e,0x11, 0x29,0xf7,0xd3,0x3c, 0xa7,0x31,0x85,0x04, + 0x64,0x9f,0x1d,0xad, 0xa6,0x21,0x08,0x49, 0xdd,0x06,0x7a,0x08, 0x40,0x4d,0xab,0x31, + 0x3b,0x48,0x8e,0xb4, 0xa8,0x96,0x66,0xad, 0x21,0x12,0x1f,0xa6, 0xcd,0x9a,0x66,0x07, + 0x29,0x0f,0x5c,0x07, 0xc8,0x30,0x3d,0xc2, 0xa2,0x01,0x51,0x13, 0x97,0x5d,0xc7,0x03, + 0x32,0xee,0x12,0x41, 0xe5,0x31,0x92,0x04, 0x94,0x93,0x31,0xa8, 0x19,0x71,0xa4,0x1e, + 0xb8,0x06,0x49,0x18, 0xe0,0xd8,0x51,0x50, 0x56,0x96,0xc5,0xaa, 0xe9,0x0b,0x1b,0xa5, + 0x0b,0xfd,0x59,0x01, 0x58,0xb5,0x64,0x25, 0x88,0x46,0x9c,0x1b, 0x3c,0x79,0xd5,0x6b, + 0x54,0x9d,0x6a,0xdd, 0x8c,0x32,0xb0,0xf7, 0xcf,0x04,0x87,0x4e, 0x44,0x51,0xec,0xc8, + 0x3f,0xc5,0xab,0xc4, 0x54,0x66,0x9c,0x5c, 0x86,0x22,0x3a,0xeb, 0x4c,0x43,0x4b,0xf5, + 0xc4,0x14,0x84,0x82, 0x24,0x1c,0xf8,0x25, 0xd1,0x72,0xf0,0x55, 0x5e,0xd4,0x44,0xaf, + 0xf4,0x1b,0x19,0x5f, 0x79,0x61,0x6b,0x75, 0x6b,0xaf,0xd6,0x4a, 0x29,0x71,0x6c,0xe0, + 0x7f,0x8b,0xb9,0x22, 0x9c,0x28,0x48,0x2f, 0x99,0xeb,0xbd,0x80, + // 0x1ec = 492 Bytes +}; + +static BZ2Manager_t lecode_loader_jap_mgr + = { lecode_loader_jap_bz2, sizeof(lecode_loader_jap_bz2), 0, 0 }; + +//----------------------------------------------------------------------------- + +static const u8 lecode_loader_kor_bz2[] = +{ + // decompressed len: 0x200 = 512 bytes + 0x00,0x00,0x02,0x00, + + // bzipped data + 0x42,0x5a,0x68,0x39, 0x31,0x41,0x59,0x26, 0x53,0x59,0xaa,0xbf, 0x22,0x0b,0x00,0x00, + 0x16,0x7f,0xff,0xfc, 0x76,0x45,0x30,0x60, 0xc7,0xc4,0x6f,0x2f, 0x6f,0x94,0x84,0x7f, + 0xe7,0xfe,0x6e,0xdc, 0x04,0x44,0x0c,0x43, 0x64,0x00,0x15,0x50, 0x00,0x48,0x49,0x6a, + 0x40,0x00,0x01,0xb0, 0x01,0x59,0xb2,0x36, 0x22,0x0a,0x7a,0x35, 0x43,0x1a,0x4d,0xa2, + 0x64,0x62,0x06,0x03, 0x28,0x61,0x1a,0x60, 0x06,0x90,0xd3,0x02, 0x18,0xd3,0x42,0x32, + 0x62,0x69,0xa3,0xf5, 0x08,0xa7,0xa0,0x98, 0x9a,0x68,0x29,0xe9, 0x92,0x00,0x68,0x00, + 0x00,0xc8,0x06,0x83, 0x40,0x01,0xa1,0xe8, 0x68,0x9e,0xa0,0x06, 0x80,0x4a,0x9a,0x90, + 0x9f,0xa9,0xa8,0xf4, 0x8c,0x80,0x60,0x8d, 0x0d,0x00,0x01,0x84, 0x69,0xa6,0x9a,0x06, + 0x9a,0x06,0x9a,0x34, 0xd3,0xd4,0x33,0x51, 0xbd,0x49,0xa6,0x86, 0x5a,0x6e,0xd6,0x68, + 0xd4,0x3f,0xde,0x1f, 0x36,0x20,0xfe,0xf1, 0x5e,0xbd,0x98,0x13, 0xde,0x69,0xdb,0x03, + 0x55,0x10,0xa2,0x8a, 0x75,0x36,0xc3,0x0d, 0xab,0xc8,0xb7,0x7f, 0x09,0x79,0xa4,0x03, + 0xae,0xda,0x49,0xd7, 0x10,0x7a,0x52,0xbb, 0x5c,0x51,0x05,0xb1, 0xd3,0xda,0x68,0x22, + 0xb7,0x95,0xa5,0x61, 0x6a,0x20,0x82,0x23, 0x3d,0xdf,0x1e,0x7e, 0x16,0x45,0x59,0x39, + 0xab,0xb8,0x26,0xe3, 0x36,0x29,0x4c,0x91, 0x55,0xbb,0x17,0xa4, 0x96,0x51,0x75,0x6e, + 0x57,0xad,0x4d,0xa0, 0x9d,0xfb,0xfb,0x98, 0xd3,0x14,0x28,0x44, 0x0b,0x43,0x1d,0x99, + 0xed,0xfa,0x3b,0xbe, 0xec,0x94,0x8e,0x98, 0x60,0xc6,0x0b,0x2d, 0x85,0xc8,0x5b,0xa9, + 0x85,0x80,0x7e,0xd8, 0x56,0xb4,0x35,0xf0, 0xcf,0x7b,0xa3,0xa8, 0xb7,0x01,0x00,0x2e, + 0x98,0x05,0x85,0x9f, 0x06,0xe7,0x4c,0x18, 0x1a,0x96,0x9e,0x74, 0x2e,0xbe,0x3d,0x07, + 0x88,0xd2,0x84,0xa4, 0x12,0xe6,0x16,0x80, 0xd3,0x06,0x21,0x08, 0x65,0x12,0xce,0x64, + 0x24,0x09,0x2d,0xc4, 0x12,0xd6,0x55,0x53, 0xa8,0x32,0x90,0x83, 0x48,0xa4,0x41,0xa9, + 0x2d,0x76,0x84,0x18, 0x0f,0xee,0x03,0x96, 0xc4,0x0e,0x55,0xdc, 0xa2,0x8a,0x8d,0xc7, + 0xe5,0x04,0x4a,0x22, 0xd4,0x80,0x89,0xb9, 0x15,0x4e,0xc1,0x01, 0x88,0x3c,0x69,0x39, + 0xa9,0x10,0x23,0x60, 0xa4,0xa0,0x29,0x29, 0x58,0xa9,0xd8,0x60, 0x23,0x90,0xb0,0xad, + 0x99,0xfd,0x45,0xad, 0xa1,0x32,0x92,0x45, 0xba,0xd8,0xc3,0x1a, 0x02,0x45,0x1c,0x60, + 0x29,0x0c,0x0e,0xbc, 0xdd,0x91,0x52,0x17, 0x43,0x4d,0xe6,0x94, 0x2e,0xa4,0x64,0xf3, + 0x70,0xe5,0xfa,0xa9, 0x74,0x21,0x10,0x91, 0x18,0x37,0x78,0x33, 0x6d,0x4d,0x2e,0x8c, + 0xf0,0x17,0xe4,0x2b, 0x1f,0x16,0xf8,0x63, 0x30,0xa2,0x8a,0x3d, 0x5c,0x07,0xf0,0xb9, + 0x98,0x71,0x39,0x37, 0x1f,0x45,0xb8,0x4c, 0x67,0x8b,0x78,0x89, 0xf3,0x50,0x41,0x48, + 0x48,0x3f,0x8c,0x55, 0xc8,0x59,0xfc,0x19, 0x9c,0x87,0x9a,0x27, 0xcc,0x16,0xc0,0x38, + 0x43,0x46,0xd8,0x60, 0x84,0x37,0x42,0x2f, 0x89,0xe2,0x7c,0x28, 0x33,0xdd,0xe2,0xee, + 0x48,0xa7,0x0a,0x12, 0x15,0x57,0xe4,0x41, 0x60, + // 0x1e9 = 489 Bytes +}; + +static BZ2Manager_t lecode_loader_kor_mgr + = { lecode_loader_kor_bz2, sizeof(lecode_loader_kor_bz2), 0, 0 }; + +//----------------------------------------------------------------------------- + +static BZ2Manager_t * GetLecodeLoader ( str_mode_t mode ) +{ + switch (mode) + { + case STR_M_PAL: return &lecode_loader_pal_mgr; + case STR_M_USA: return &lecode_loader_usa_mgr; + case STR_M_JAP: return &lecode_loader_jap_mgr; + case STR_M_KOR: return &lecode_loader_kor_mgr; + default: return 0; + } +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// more data /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static const u8 codehandleronly_bz2[] = +{ + // 4 bytes decompressed len + 0x00,0x00,0x0a,0xb8, + + // bzipped data, includes a GCH header of sizeof(gch_header_t) == 16 bytes + // 0x0: + 0x42,0x5a,0x68,0x39, 0x31,0x41,0x59,0x26, 0x53,0x59,0x88,0x5d, 0x08,0x9e,0x00,0x02, + 0x4f,0xff,0xff,0xff, 0xfd,0xe5,0xf5,0xff, 0xff,0xff,0xff,0xff, 0xfd,0xef,0xf6,0x7e, + 0xfd,0xfc,0xf7,0xff, 0xff,0xff,0xf5,0x7b, 0xff,0xfe,0x7d,0x4e, 0x75,0x75,0x45,0x46, + 0xe4,0xe4,0xff,0xd0, 0x05,0x3e,0xdd,0x80, 0x1d,0xd5,0xb5,0xd7, 0x1d,0x57,0x6e,0xa3, + 0x6c,0x11,0x4c,0x22, 0x64,0x9e,0xa9,0xfa, 0xa7,0xe9,0x95,0x3d, 0xa8,0x8f,0x53,0xda, + 0x93,0x41,0xb4,0x9e, 0x48,0xd1,0xfa,0xa0, 0x06,0x9e,0x46,0xa6, 0x9a,0x34,0x01,0xa3, + 0xd4,0x03,0x34,0x47, 0x84,0x86,0x8d,0x3d, 0x41,0xea,0x34,0xf4, 0x83,0xd4,0xd1,0xa3, + 0xf5,0x40,0x7a,0x80, 0x00,0x00,0x3d,0x4c, 0x86,0x80,0x00,0x68, 0x7a,0x8f,0x49,0xe5, + 0x04,0x53,0xd2,0x0d, 0x20,0x35,0x30,0x9a, 0x9e,0xa1,0xea,0x79, 0xa9,0x3d,0xaa,0x7a, + 0x9e,0x9e,0x82,0x65, 0x34,0x7a,0x81,0xe4, 0x46,0xd3,0x51,0xea, 0x6d,0x4d,0x0d,0xa9, + 0xea,0x1e,0x9a,0x4d, 0x34,0x01,0xea,0x68, 0xf5,0x1a,0x00,0x0c, 0x8d,0x03,0x41,0xa0, + 0xd1,0xea,0x06,0x80, 0x00,0x00,0x00,0x0d, 0x34,0x00,0x1a,0x15, 0x4f,0x4d,0x4c,0xa7, + 0xa9,0xa7,0x91,0xa6, 0xa1,0x1b,0x4c,0x9a, 0x00,0x00,0x00,0x08, 0xc0,0x02,0x60,0x98, + 0x00,0x03,0x40,0x46, 0x00,0x09,0x82,0x60, 0x00,0x26,0x00,0x00, 0x4c,0x46,0x00,0x02, + 0x60,0x26,0x00,0x1a, 0x08,0x00,0xd3,0x40, 0xc8,0x34,0x00,0x34, 0x0d,0x00,0xd0,0x06, + 0x43,0x43,0x4c,0x40, 0x0d,0x03,0x13,0x40, 0xd0,0x19,0x00,0x00, 0x00,0xc8,0xd1,0x88, + // 0x100: + 0x0d,0x00,0x00,0x00, 0x06,0x86,0x46,0x8c, 0x98,0x08,0xc9,0x93, 0x4d,0x03,0x4d,0x21, + 0x04,0xd3,0x49,0x95, 0x3d,0xa6,0x46,0x40, 0x53,0x4f,0x26,0xa7, 0x8d,0x29,0xb4,0xca, + 0x1a,0x79,0xa5,0x01, 0xe9,0x34,0x7a,0x83, 0x69,0xa9,0x82,0x68, 0x06,0x81,0x90,0x00, + 0x66,0x51,0x91,0xea, 0x7a,0x46,0x8c,0x8d, 0x36,0x8c,0xa7,0xea, 0x4c,0xd4,0xc9,0x91, + 0xa0,0x0d,0x01,0xfa, 0xa0,0x00,0x19,0x1a, 0x3c,0xa6,0x77,0x37, 0x61,0x49,0xb5,0xfd, + 0x12,0xb5,0x55,0x35, 0x28,0x01,0x28,0x12, 0xd4,0xf8,0x84,0x4a, 0xca,0xdc,0x30,0x0d, + 0x2a,0x2f,0x0e,0x06, 0xc4,0xbe,0x15,0xb5, 0x0c,0xca,0x0e,0x1b, 0x4f,0x31,0x16,0xd9, + 0xf1,0xbe,0x3b,0xdb, 0xd4,0xa2,0x22,0xda, 0x45,0x51,0xf9,0x21, 0xe0,0x31,0x35,0x0b, + 0x66,0x00,0xc0,0xb4, 0x89,0x10,0xc2,0x4d, 0x66,0x0f,0x5f,0x4d, 0x7e,0xeb,0xc4,0x29, + 0xdc,0xc1,0x45,0xbb, 0x74,0x39,0xaf,0xc5, 0xe1,0xa4,0x41,0x10, 0x7c,0x26,0x16,0x41, + 0xee,0x61,0xb3,0x88, 0x06,0x60,0x4e,0x20, 0x79,0x42,0x4a,0x51, 0xc5,0xe1,0x76,0x23, + 0xab,0xd1,0x6a,0x73, 0xd6,0x2b,0x05,0x12, 0x59,0xe4,0xa2,0x17, 0x6b,0x86,0x01,0x22, + 0x61,0x1a,0xe1,0x8b, 0x53,0x78,0x18,0xfa, 0xb6,0x82,0xa9,0x00, 0x82,0x27,0x2f,0x26, + 0xa2,0x2c,0x60,0xc9, 0x7a,0xba,0xa8,0x51, 0x20,0x66,0x87,0x8b, 0x06,0x7b,0xf7,0x8e, + 0x68,0x32,0xe2,0x5e, 0x26,0x73,0xbd,0x96, 0xc4,0x21,0x56,0xf1, 0x64,0x28,0x79,0xce, + 0x7a,0x47,0xc2,0xb9, 0xaf,0xa7,0xc6,0xf4, 0x25,0x99,0x40,0xb9, 0x8a,0x60,0x55,0x1c, + // 0x200: + 0x5b,0x75,0x74,0x40, 0xc3,0x0c,0xc7,0x35, 0x1c,0xa4,0xa9,0x07, 0x0f,0x3d,0x82,0xb0, + 0x89,0x26,0x89,0x09, 0x3e,0xeb,0xc7,0x51, 0x2f,0xec,0x75,0xee, 0x3b,0xa3,0xd3,0xbb, + 0xed,0x38,0x62,0xaa, 0xaf,0xf4,0xa3,0xac, 0x23,0xf3,0x28,0x91, 0xc2,0xa1,0x1e,0x22, + 0xd9,0x9a,0xf6,0x26, 0xac,0xce,0xae,0x73, 0x20,0x30,0x58,0x2a, 0x34,0xd2,0x20,0x50, + 0x7d,0xb6,0xf6,0xd4, 0xde,0x4f,0x28,0x43, 0x16,0x90,0x5c,0xc6, 0x3b,0x86,0xc2,0x36, + 0xd0,0xf4,0x98,0xf7, 0x4c,0x02,0x2f,0x73, 0x6f,0x32,0x60,0x24, 0x83,0xbd,0x2b,0xae, + 0x19,0x10,0x24,0xa2, 0x88,0x8e,0x20,0x5d, 0x52,0xc1,0x10,0xb5, 0x00,0x78,0x8d,0x8d, + 0x1b,0x99,0xba,0xa9, 0x59,0xd0,0xd6,0x08, 0x70,0x08,0xf9,0x32, 0xd5,0x04,0x5f,0xc4, + 0x89,0x3f,0xcc,0xa9, 0x4f,0x81,0xf3,0x5f, 0xe1,0x8c,0xc6,0xe5, 0x90,0x13,0xde,0x9b, + 0x65,0x67,0xb7,0xdb, 0x10,0x41,0x28,0x49, 0x42,0x2c,0x67,0x88, 0x00,0xff,0x22,0xe4, + 0x46,0xde,0x17,0x0d, 0xc1,0x82,0xe2,0xc2, 0xa3,0xd7,0x82,0x21, 0xbe,0x1c,0x88,0x05, + 0x88,0xd4,0x28,0x46, 0x68,0x28,0x40,0x9c, 0x1a,0xdb,0x70,0x44, 0x21,0xaa,0x01,0x07, + 0xdd,0x6b,0x6b,0x5c, 0x1f,0x23,0xae,0x20, 0x0d,0x02,0x81,0xa4, 0x38,0xee,0xb2,0x19, + 0x3a,0xfd,0xcf,0x94, 0x03,0x4c,0x42,0x12, 0x63,0x7d,0x9b,0x81, 0xae,0x3a,0xfc,0xce, + 0x39,0x73,0xca,0xae, 0xd3,0xee,0xd5,0xf7, 0x15,0x71,0xc6,0x5c, 0xf1,0xfb,0x15,0x4b, + 0xcd,0xd9,0x5f,0x36, 0xdb,0x65,0x5d,0xce, 0x4e,0xb2,0x7d,0x94, 0x39,0x8c,0x17,0x25, + // 0x300: + 0x10,0x3d,0x68,0x74, 0x9a,0xc0,0xe6,0x39, 0x06,0x49,0xd9,0xdf, 0x2e,0x47,0x81,0xad, + 0xcb,0x6b,0x8f,0x1d, 0xfd,0xff,0x7e,0x75, 0x61,0x6c,0xac,0x75, 0x41,0x0b,0x83,0x38, + 0xe2,0x90,0x43,0x01, 0xb8,0x82,0x68,0x96, 0xc1,0x4a,0x46,0x01, 0xa0,0x58,0x67,0x85, + 0xbc,0x82,0xc5,0x84, 0x90,0xc8,0x38,0x12, 0xc5,0x4e,0x05,0xb5, 0xd0,0x59,0x3e,0x08, + 0xdd,0x52,0x00,0x2d, 0x65,0x17,0x03,0x35, 0xa2,0x58,0xf8,0x0a, 0x5a,0x75,0x86,0x2e, + 0x34,0x15,0x10,0xf2, 0x3c,0x30,0xfa,0x80, 0x1e,0x51,0xb9,0x1d, 0x3c,0x93,0xc2,0x77, + 0x99,0x49,0x15,0xc4, 0xe1,0x86,0x9b,0x9d, 0x4a,0xc9,0xdf,0x15, 0x66,0xd9,0xcd,0x64, + 0xd2,0x1a,0x14,0x62, 0x6c,0x85,0x7f,0x99, 0x87,0x77,0x9b,0xe3, 0xca,0xc5,0xa3,0xfd, + 0x67,0xa4,0x83,0xb6, 0x0e,0xe8,0xc3,0x5c, 0x75,0x63,0x5b,0xf7, 0x35,0x82,0x6e,0x13, + 0xac,0xaa,0x29,0x91, 0xbb,0x10,0xbd,0xd4, 0x43,0xa8,0xa2,0xde, 0x20,0x26,0xd3,0x38, + 0xb4,0x77,0x24,0x67, 0x45,0xab,0xba,0xde, 0x7e,0x29,0xbc,0x68, 0x1f,0xe6,0xeb,0xc5, + 0xd1,0x08,0x26,0x42, 0xbb,0x56,0xba,0xc0, 0x0f,0x3a,0x81,0xfb, 0x19,0xb8,0x2f,0x2e, + 0x54,0x33,0x68,0xdd, 0xbc,0x26,0x94,0xff, 0xaf,0xf3,0xe5,0x51, 0xac,0x79,0xf0,0x40, + 0xc0,0xe5,0x2b,0x30, 0xec,0x79,0xe1,0xc6, 0x36,0xf5,0x28,0xd3, 0xe6,0x7c,0x1e,0x7c, + 0xf7,0xc1,0x07,0x96, 0x34,0x85,0x7a,0xd2, 0x3d,0xbd,0x8b,0xdb, 0xe1,0x1e,0x82,0xce, + 0xff,0xd2,0x14,0x39, 0x29,0x23,0x80,0x02, 0x12,0xe0,0x34,0x04, 0x15,0x12,0xe8,0xe9, + // 0x400: + 0x98,0x86,0x3f,0x68, 0xb4,0x51,0x0f,0x74, 0x09,0xbf,0xa0,0x0c, 0x49,0x32,0xcb,0x86, + 0xfa,0xfb,0x9f,0xd3, 0x1d,0xe4,0xac,0x27, 0xa6,0xde,0xe2,0xd7, 0x46,0xd9,0xb3,0x97, + 0x0b,0x1f,0x09,0xb5, 0x1f,0x4a,0xfb,0xe1, 0x31,0x82,0x16,0xac, 0x61,0xf6,0x15,0xa0, + 0xe0,0xe3,0xa0,0x1c, 0x50,0xe1,0x01,0x7f, 0x10,0x9d,0x1e,0x35, 0x13,0x67,0x81,0x48, + 0x8d,0x24,0xf0,0x02, 0x79,0x02,0xba,0xa2, 0x30,0x8e,0x7d,0xe8, 0x7a,0x34,0xe6,0x8a, + 0x0c,0xd1,0x8c,0x85, 0x03,0x13,0x4f,0x0c, 0x98,0x60,0x40,0x45, 0x48,0x9d,0x3a,0x47, + 0x2a,0x95,0x6c,0xa9, 0xf6,0x19,0x2d,0x99, 0x3e,0xc3,0x83,0xd6, 0xd6,0x51,0x63,0xe5, + 0x96,0x22,0x2b,0xa2, 0xa3,0x41,0x61,0x35, 0x4b,0xc9,0x2b,0x06, 0xbc,0x55,0xc4,0xc9, + 0x23,0x6e,0x50,0xa7, 0xba,0x3f,0xcf,0x5b, 0xf3,0x10,0x5a,0xfc, 0x38,0x81,0xdd,0x6a, + 0xca,0x2c,0x66,0x69, 0x60,0xbc,0xa4,0x04, 0xcd,0x7e,0x6a,0xab, 0x1d,0xae,0x01,0x08, + 0xd5,0x25,0x2c,0xa1, 0xaa,0x58,0x45,0x39, 0x34,0xc6,0x86,0x62, 0xa4,0x7e,0x49,0xab, + 0x65,0x25,0xf4,0x76, 0xb3,0xa7,0xaf,0x99, 0x1e,0x7c,0x93,0x42, 0x24,0xa4,0x20,0x08, + 0x39,0x5c,0x36,0x82, 0x76,0x3e,0x22,0x9e, 0xe3,0xe6,0xe1,0x7a, 0x8b,0xac,0x1d,0xca, + 0x98,0x73,0x6b,0x3b, 0xfa,0x0a,0xbf,0x80, 0xdb,0xd4,0x21,0x45, 0xed,0x7b,0xca,0xb6, + 0x28,0xaa,0x20,0xe4, 0xe7,0x0e,0xab,0x0a, 0x94,0x1c,0x23,0x84, 0x32,0x6a,0x26,0x76, + 0x5e,0xe1,0x8b,0xca, 0x4b,0x66,0x85,0x37, 0x2d,0x89,0x96,0x48, 0x50,0xa1,0xc2,0x16, + // 0x500: + 0x84,0x1f,0xf4,0xef, 0x70,0x94,0x3b,0x6e, 0xd5,0x49,0x6e,0x97, 0x04,0xa6,0xff,0x2c, + 0x2c,0x69,0x0e,0x92, 0x65,0xdb,0x5b,0xeb, 0xf5,0x5a,0x55,0xd2, 0x88,0xf0,0x78,0x49, + 0x57,0x4b,0x1d,0x5a, 0x68,0x4a,0x0b,0x48, 0x24,0x7a,0x26,0x19, 0x6b,0x22,0xfc,0x9a, + 0xe6,0xb2,0xd0,0x03, 0x36,0x77,0x04,0xb1, 0x1a,0x57,0x24,0xb9, 0xd9,0x6f,0x2c,0x65, + 0xb4,0x64,0x50,0xbc, 0xbc,0x5f,0x0d,0x6d, 0xd1,0xc1,0x30,0x0d, 0xd6,0xbc,0xa5,0xcf, + 0x47,0xac,0xce,0xa4, 0xb6,0x6d,0xa5,0x73, 0xdd,0xd5,0x49,0x7f, 0xb3,0xe8,0x76,0x88, + 0xa3,0x9c,0x2b,0x1a, 0xf7,0x13,0xdc,0xfd, 0x3d,0x89,0x55,0x04, 0xfe,0xc1,0xaf,0x1f, + 0x0c,0x2b,0xc4,0x1b, 0x72,0x0d,0x11,0x77, 0x0e,0x7b,0x40,0xea, 0x6c,0x57,0xc2,0x9f, + 0x15,0x35,0x11,0x70, 0x0a,0x20,0xa1,0x73, 0x31,0x4d,0x43,0x02, 0x72,0xeb,0x58,0xdf, + 0xd2,0x9a,0x16,0x82, 0xc0,0xb6,0x47,0xa5, 0x07,0xf7,0xa5,0xcf, 0xa2,0xcd,0x8a,0x24, + 0xc5,0x9c,0x1c,0x71, 0xab,0x10,0x3e,0x83, 0x68,0x84,0x58,0xcf, 0x6e,0x26,0x17,0x2f, + 0x54,0x44,0x52,0x88, 0x06,0x31,0x24,0xaa, 0x03,0x4c,0x4d,0x30, 0x85,0xd4,0x95,0xc1, + 0x5c,0x46,0x9d,0xba, 0x20,0xf8,0x24,0x42, 0x57,0xe5,0x08,0xff, 0x37,0xe2,0x3e,0x0a, + 0xa4,0x26,0xfb,0x9b, 0x5a,0xca,0x94,0x5a, 0x47,0x0a,0xac,0x3d, 0xc4,0x35,0x11,0xc5, + 0x9c,0x63,0x7e,0x4b, 0xac,0x74,0xc3,0x0d, 0x13,0xc5,0x36,0x30, 0x88,0x37,0x64,0x4e, + 0x0b,0xb1,0x01,0x03, 0xde,0xc9,0x5d,0x44, 0xae,0xa6,0x5f,0xe4, 0xbc,0x9b,0x3a,0x5a, + // 0x600: + 0x5b,0x4a,0xd9,0x64, 0x14,0x4d,0x44,0x01, 0xeb,0xfb,0x89,0xf6, 0x0f,0xc0,0x42,0x14, + 0x05,0x02,0x12,0x10, 0x91,0x4c,0x8d,0x85, 0xcd,0xd5,0xc7,0xa6, 0xb7,0x69,0x83,0xa7, + 0x30,0x2c,0xdd,0xa8, 0x39,0x71,0xa3,0xc6, 0x29,0x86,0x43,0xc6, 0x05,0x83,0x57,0xf3, + 0x86,0x77,0x7a,0x2c, 0x50,0xb9,0xc0,0xad, 0x26,0xec,0x10,0x40, 0x0c,0x0c,0x04,0xc4, + 0xcb,0xb2,0xeb,0xb6, 0x1b,0x9b,0x50,0x16, 0x62,0x42,0x57,0x56, 0x35,0xd1,0x49,0x0b, + 0x14,0x16,0xb6,0x48, 0x40,0xe6,0xd4,0xe8, 0x51,0x91,0x89,0x38, 0xa5,0x2e,0x71,0x7a, + 0x60,0xd8,0xc5,0x7f, 0x3b,0xcb,0xbd,0x88, 0x38,0x10,0x08,0xbb, 0xd6,0x31,0x83,0x05, + 0xfd,0x6e,0x8d,0x63, 0xb6,0x25,0x04,0xf0, 0x4b,0x09,0x0b,0x89, 0x67,0x5e,0x18,0x91, + 0x63,0x4e,0x14,0x20, 0x0d,0x09,0x7a,0xf2, 0x32,0xfe,0xd5,0x6b, 0x5e,0xc1,0x73,0xc8, + 0xa6,0xc5,0xed,0xd4, 0x32,0xc4,0x9d,0xce, 0xfc,0x17,0x94,0x15, 0x45,0x46,0x5d,0x8a, + 0x7b,0x20,0xf6,0xce, 0x67,0x03,0xc9,0x80, 0x45,0x3d,0x33,0x6d, 0x21,0x4b,0x37,0xf3, + 0xf3,0xce,0x43,0x3a, 0xa5,0x4e,0x59,0x66, 0xa4,0x52,0x29,0x17, 0x4a,0x31,0x9e,0x86, + 0x02,0x7a,0x65,0x36, 0x43,0x81,0x04,0x0b, 0xf7,0x92,0x32,0xff, 0x1e,0xa6,0x1c,0x01, + 0x41,0x00,0x36,0xbc, 0xfd,0x20,0xd5,0x0d, 0x64,0x69,0x67,0x6c, 0x4c,0x9f,0x3d,0xc1, + 0xec,0x1c,0xd2,0x22, 0xe1,0x49,0x86,0xaa, 0xca,0xa6,0xcd,0xe1, 0xb3,0x31,0x46,0xb9, + 0x47,0xab,0x91,0x20, 0x6a,0x21,0xc6,0x1e, 0xa9,0x53,0x6a,0xe2, 0x41,0xa2,0xc9,0x44, + // 0x700: + 0x9c,0x9f,0x2d,0x06, 0xc1,0x73,0xc3,0xb8, 0xc4,0xb5,0x26,0x41, 0x97,0x06,0xa6,0xcb, + 0x1c,0x0b,0x48,0x29, 0xfe,0xf7,0x90,0x70, 0xa2,0x8b,0x01,0xb1, 0xe3,0x34,0x55,0x6a, + 0x6d,0x01,0x02,0x5f, 0x6a,0xa2,0x1e,0x95, 0x52,0xa9,0xce,0x2d, 0xfb,0xd5,0x86,0xc0, + 0xd2,0x05,0x03,0x8a, 0x34,0xfc,0x45,0x48, 0x20,0x80,0x4d,0x3e, 0x27,0x03,0xa9,0xf5, + 0x5d,0xd4,0x15,0x2f, 0x90,0x8f,0x8e,0x30, 0x6b,0x9a,0x39,0x3d, 0x05,0xcc,0x0d,0x48, + 0xd5,0x65,0x09,0x7e, 0x1b,0x03,0xb7,0xbd, 0x1a,0x03,0xa2,0xaa, 0x88,0x34,0x56,0xee, + 0xaa,0xb5,0x00,0xda, 0x91,0x79,0xf3,0xea, 0x8e,0xd5,0xce,0x0a, 0x50,0x7f,0xe2,0xee, + 0x48,0xa7,0x0a,0x12, 0x11,0x0b,0xa1,0x13, 0xc0, + // 0x779 = 1913 Bytes +}; + +static BZ2Manager_t codehandleronly_mgr + = { codehandleronly_bz2, sizeof(codehandleronly_bz2), 0, 0 }; + +/////////////////////////////////////////////////////////////////////////////// + +static const u8 codehandler_bz2[] = +{ + // 4 bytes decompressed len + 0x00,0x00,0x10,0xc8, + + // bzipped data, includes a GCH header of sizeof(gch_header_t) == 16 bytes + // 0x0: + 0x42,0x5a,0x68,0x39, 0x31,0x41,0x59,0x26, 0x53,0x59,0x1e,0xd9, 0x97,0x25,0x00,0x03, + 0xe9,0xff,0xff,0xff, 0xfd,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xfd,0xff,0xff,0x7e, + 0xfd,0xff,0xff,0xff, 0xff,0xff,0xf7,0x7f, 0xff,0xfe,0x7f,0x4e, 0x77,0x75,0xe5,0x66, + 0xe6,0xf4,0xff,0xe0, 0x08,0x9f,0x5c,0xbe, 0xf8,0x7b,0x4e,0xb4, 0xe9,0xdd,0xb1,0xdf, + 0x6b,0x6f,0xb6,0xed, 0xb7,0xcd,0xe9,0xec, 0x7b,0xef,0x5a,0x1d, 0x8f,0x70,0x35,0x32, + 0x21,0x1a,0x27,0xa4, 0xd4,0xf2,0x66,0xa6, 0x46,0x54,0xf4,0x9f, 0x88,0x93,0xfd,0x52, + 0x69,0xfa,0x9a,0x6a, 0x1e,0xa7,0xb5,0x35, 0x07,0xa9,0xe9,0x1a, 0x33,0xd5,0x34,0xf6, + 0xa6,0x89,0xb1,0x21, 0xa6,0xd4,0xf4,0x8f, 0x14,0x3d,0x43,0xf5, 0x1a,0x64,0xd3,0x51, + 0xfa,0x51,0xe9,0x1e, 0xa0,0xf5,0x1e,0x48, 0x68,0x32,0x68,0x7a, 0x11,0xb4,0x83,0x47, + 0xa8,0x3d,0x46,0x81, 0xe9,0x00,0x06,0x86, 0x8f,0x48,0x7e,0xa9, 0xa6,0x41,0x13,0x50, + 0x84,0xfc,0x91,0xa9, 0xb5,0x18,0x99,0x4f, 0x49,0xa0,0xf6,0xa1, 0xe8,0x8f,0x50,0x8f, + 0x4d,0x36,0xa8,0x34, 0xd3,0xd2,0x62,0x0d, 0x1b,0x51,0xea,0x68, 0x06,0x9b,0x53,0xd4, + 0x0d,0x00,0x0d,0x34, 0x0d,0x00,0x06,0x80, 0x1a,0x34,0x00,0x34, 0xd0,0x1a,0x00,0x00, + 0x00,0x00,0x00,0x34, 0x00,0x04,0x44,0xd4, 0xc4,0xc4,0xc8,0xf4, 0x8d,0x1a,0x53,0xf4, + 0x26,0x9a,0x9b,0x50, 0xf2,0x9e,0xa1,0xb4, 0xd4,0x06,0x8f,0x50, 0x07,0xa8,0x3d,0x40, + 0x06,0x80,0x1a,0x68, 0xf2,0x8c,0x80,0x01, 0xa0,0x1e,0xa0,0x0c, 0x80,0x00,0x34,0x1a, + // 0x100: + 0x07,0xa8,0x00,0x00, 0x00,0x06,0x80,0x00, 0x00,0x69,0xa1,0x14, 0xf2,0x35,0x32,0x20, + 0x26,0x86,0x9a,0x26, 0x13,0x4d,0x34,0x34, 0x03,0x4c,0x8d,0xa9, 0xa1,0x90,0x1a,0x7a, + 0x9a,0x03,0x43,0x40, 0x34,0x06,0x80,0xd0, 0x03,0x40,0x00,0x01, 0xa0,0x00,0x0d,0x00, + 0x64,0x34,0x69,0xa0, 0x69,0xa0,0x00,0x00, 0x00,0x0d,0x00,0x03, 0x53,0xd2,0x41,0x26, + 0x9e,0x52,0x3d,0x13, 0xd4,0x69,0xe5,0x1e, 0xa0,0x3d,0x11,0xa1, 0xea,0x3d,0x20,0x32, + 0x00,0x00,0xf4,0x86, 0x80,0x00,0x00,0x00, 0x0d,0x0c,0x83,0x20, 0x00,0x00,0x01,0xa0, + 0x1a,0x0d,0x00,0x06, 0x80,0x00,0x00,0x00, 0x00,0x00,0x25,0x35, 0x08,0x26,0xa3,0x4c, + 0x24,0x6d,0x4c,0x8f, 0x54,0xc9,0xb4,0x62, 0x9b,0x42,0x6f,0x2a, 0x60,0x4f,0x29,0x93, + 0x6a,0x7a,0x8d,0x1a, 0x7a,0x46,0x9a,0x07, 0xa8,0x34,0xd0,0x64, 0xd0,0x34,0x7a,0x8d, + 0x03,0x43,0x43,0x20, 0x06,0x99,0x00,0x34, 0x03,0x43,0x40,0x0d, 0x1a,0x69,0xa0,0x00, + 0x34,0x00,0x34,0x03, 0x46,0x87,0xa9,0xb4, 0xde,0xf4,0x75,0xe1, 0x8b,0xbc,0x72,0xbd, + 0x73,0x68,0x58,0x04, 0x99,0x8b,0x84,0x6b, 0x11,0xac,0xe9,0x36, 0x54,0xef,0xb6,0x1d, + 0xac,0x8c,0x79,0x0a, 0xbb,0x3f,0xcd,0xf1, 0xac,0xb1,0xd1,0xd3, 0xb6,0x54,0x4c,0x17, + 0x24,0xca,0xac,0x92, 0xf6,0xf8,0x49,0x67, 0x6d,0x9b,0x8c,0x8f, 0x66,0x2c,0x5a,0x6b, + 0xcd,0xf7,0x23,0x77, 0x97,0x67,0x7c,0xf2, 0x4c,0xad,0x5c,0x67, 0x42,0xe4,0x18,0xd6, + 0x12,0x38,0x2f,0x61, 0xef,0x30,0x61,0x6d, 0xdb,0x51,0x04,0x4c, 0x58,0xf9,0x8b,0x04, + // 0x200: + 0x4a,0x75,0x24,0xbd, 0x41,0x04,0x88,0x35, 0x87,0x5e,0x18,0x80, 0x83,0x13,0x81,0x03, + 0xe0,0xe3,0xdb,0x63, 0xdd,0xe9,0xac,0xa5, 0xee,0x0e,0x36,0xda, 0xe5,0xe2,0x04,0x60, + 0xcf,0x1e,0x9c,0x51, 0xd0,0xab,0xb4,0x5d, 0xc9,0x04,0x87,0x18, 0xca,0x34,0x22,0xa4, + 0xe0,0x6e,0x9b,0xa2, 0xd5,0x0f,0x59,0x22, 0x90,0x5c,0xf6,0x61, 0xcd,0x18,0x9c,0xb2, + 0xb0,0x0c,0x02,0x74, 0x6e,0xd2,0xb2,0x05, 0x8e,0xba,0x3b,0x32, 0x83,0x14,0x7d,0x14, + 0xa9,0x87,0x19,0x66, 0xf2,0x3e,0x27,0x97, 0xa2,0xab,0x72,0x00, 0x2e,0xbe,0x5f,0x56, + 0x04,0x20,0x05,0x2b, 0x70,0x12,0x21,0x28, 0xcd,0x5c,0xa5,0x4d, 0xad,0x98,0xf9,0x67, + 0x8f,0x16,0xbd,0xdb, 0xca,0x16,0x38,0xe9, 0x4b,0x82,0xa4,0x6d, 0xc8,0x0b,0x6e,0x1a, + 0x21,0x00,0x82,0x20, 0xa5,0xaa,0x8c,0x04, 0x72,0x40,0xd9,0x96, 0xf9,0xe3,0xe8,0x49, + 0xe2,0x80,0xf4,0xa2, 0x01,0xe0,0x3c,0xa6, 0x06,0xc5,0x21,0x52, 0xe1,0x2b,0x08,0xa2, + 0x39,0x77,0xad,0x23, 0x9c,0x28,0x38,0xb7, 0x64,0x74,0xec,0xd4, 0x24,0xde,0x03,0x4e, + 0x92,0xcd,0x53,0x6e, 0x9a,0x38,0xc6,0x67, 0x84,0x12,0xb3,0x6d, 0x79,0x2b,0xaf,0x5d, + 0x26,0xf9,0xa6,0x1b, 0xec,0xa4,0x9d,0x08, 0x02,0xd0,0x64,0x08, 0x20,0x66,0x4c,0xee, + 0xe0,0x29,0x17,0x22, 0x42,0xd8,0xdf,0xc6, 0xaa,0x54,0x96,0xd2, 0x90,0x4f,0x40,0x5d, + 0xbb,0x2c,0xa4,0xb4, 0x6b,0xd5,0x98,0x03, 0x42,0xc0,0x0b,0x5a, 0x60,0x4b,0xf3,0x4a, + 0x1c,0xa0,0x88,0x58, 0x02,0x82,0x35,0x28, 0x08,0xf3,0x02,0x28, 0xb2,0x06,0xc6,0x24, + // 0x300: + 0x53,0x28,0x49,0x10, 0x62,0x4a,0x67,0x54, 0x41,0x58,0x93,0x84, 0x53,0x73,0xec,0xa1, + 0xe4,0xe3,0x94,0x79, 0x46,0x16,0x18,0x7c, 0x48,0x31,0x45,0x69, 0x30,0x73,0x00,0x4c, + 0x1f,0x7a,0x68,0xf0, 0x1d,0x6a,0x80,0xd4, 0xde,0x60,0x62,0x0a, 0x2a,0x26,0x28,0x7d, + 0x4e,0xa0,0x88,0x58, 0x56,0xce,0xcb,0xa5, 0x8d,0xb4,0xeb,0x48, 0xb1,0xf8,0xe9,0xd2, + 0x06,0x3d,0x34,0xf6, 0x80,0x5b,0x88,0x49, 0x05,0xd4,0x43,0x2a, 0x8a,0x01,0x65,0xa2, + 0xa7,0x7f,0x29,0x28, 0x42,0xa5,0x1c,0x71, 0xeb,0xc9,0x96,0xa2, 0xbf,0x48,0xa0,0xa8, + 0x34,0x65,0x89,0x68, 0x66,0xb2,0xf1,0xc6, 0xa4,0x7b,0xd6,0x56, 0xf2,0xcd,0xb2,0xd3, + 0x53,0x9d,0x64,0xdd, 0xb4,0x26,0x17,0x68, 0x68,0xb7,0x64,0xb1, 0x5e,0xa6,0x29,0x2d, + 0xcf,0x70,0xd5,0x2a, 0x09,0x21,0x2f,0x25, 0xce,0x22,0xaa,0x4e, 0x75,0x3d,0x83,0x99, + 0xa9,0xd3,0xe1,0x9e, 0xc0,0x65,0x51,0x32, 0x66,0xc9,0x2e,0x0a, 0xfd,0xac,0x9e,0xcc, + 0xd3,0x90,0x56,0x3a, 0x2d,0x53,0xa5,0x23, 0x65,0x5e,0xf9,0xcd, 0x0f,0x03,0xb7,0xbd, + 0xe0,0x44,0x6b,0x17, 0x86,0x5a,0x01,0xc4, 0x50,0xa9,0x05,0x06, 0x6e,0xfc,0x1a,0x47, + 0x53,0xe7,0x98,0x42, 0x49,0xf0,0x87,0x6f, 0x0c,0x36,0x45,0x4e, 0x59,0xf5,0x2d,0x63, + 0x93,0xf7,0xb4,0xb6, 0xb1,0xc4,0xe3,0x6f, 0xcc,0xec,0x06,0x3e, 0x3d,0x0e,0x09,0x9a, + 0x83,0x78,0x48,0xba, 0x45,0xf2,0xcc,0xa9, 0xc9,0x86,0x3d,0xbb, 0x7a,0xcf,0xaf,0x55, + 0xcd,0xb2,0x74,0x8a, 0x02,0x09,0x51,0x25, 0x49,0x69,0x58,0x61, 0x4b,0x88,0x90,0xc2, + // 0x400: + 0xd1,0x44,0xc7,0x24, 0xab,0xf0,0xc2,0x0f, 0xd4,0x95,0x23,0xf6, 0x55,0x57,0xe6,0x32, + 0x16,0xa9,0x87,0xf7, 0x1a,0x59,0x32,0xc5, 0xf5,0x23,0x68,0x6e, 0x26,0x0b,0xa3,0x46, + 0xe6,0x0d,0x7c,0x30, 0xde,0x00,0x79,0xd6, 0xd9,0x81,0x13,0x16, 0xfa,0x08,0xe7,0xa8, + 0x82,0xd5,0xce,0xdc, 0xf2,0x95,0x66,0x53, 0x62,0xc9,0x18,0x9e, 0x86,0xb1,0x13,0x06, + 0x1a,0x02,0x08,0x89, 0x6c,0xef,0xb6,0x30, 0x9f,0xbe,0x3b,0x43, 0x20,0xd3,0x90,0xd7, + 0xe9,0x84,0x2c,0x30, 0xe0,0x4c,0x58,0x42, 0x80,0x91,0x69,0x72, 0x90,0x6c,0xf7,0x41, + 0x45,0x73,0x07,0xe9, 0x4c,0x1a,0x63,0x14, 0x82,0x88,0x8e,0x22, 0x94,0x94,0x62,0x50, + 0x59,0x2c,0x71,0x48, 0x6d,0x8d,0xda,0x7b, 0x19,0xcf,0x11,0x4b, 0x46,0x05,0x7d,0x96, + 0x4b,0x0a,0xad,0xa5, 0xad,0xc4,0xaf,0xd2, 0xd5,0xde,0x40,0xe0, 0x10,0xc5,0xaa,0x66, + 0x25,0x45,0xcb,0xb2, 0x9a,0x72,0x3d,0xe4, 0x2e,0xf5,0xd5,0xa7, 0x33,0x65,0x7b,0xb7, + 0x1d,0x52,0xa4,0x36, 0x51,0x0c,0xce,0xe2, 0xaf,0x75,0x0f,0xd8, 0xd8,0x5f,0xec,0xe1, + 0x1a,0xdc,0x2b,0x0e, 0xf3,0xad,0x16,0x0b, 0xab,0x1a,0xda,0xb0, 0xc4,0xda,0x62,0xc2, + 0x4b,0x22,0x62,0x08, 0x7a,0x47,0x92,0x94, 0x23,0x71,0x18,0xed, 0x09,0xc2,0x40,0x1c, + 0xb0,0x46,0x55,0x54, 0xf0,0xb8,0x5c,0x51, 0x02,0xed,0x97,0x4c, 0x60,0xbd,0x19,0x1b, + 0xb5,0x61,0x5a,0x40, 0xb2,0xb6,0x32,0xb5, 0xf6,0xcd,0x9c,0x30, 0xc8,0xd1,0xe0,0xb3, + 0x73,0x84,0x02,0xa6, 0xe1,0x5d,0x83,0x74, 0x88,0x04,0x93,0xa6, 0x98,0x63,0x19,0xca, + // 0x500: + 0x88,0x61,0xc7,0x0d, 0x8c,0x8c,0x01,0xe7, 0xcc,0x12,0xd8,0x4c, 0x56,0x9e,0xce,0xff, + 0x38,0x1d,0xe8,0x67, 0x0b,0x37,0xf8,0x10, 0x6d,0xeb,0xcd,0xff, 0x57,0x5a,0x6b,0x95, + 0x32,0x0c,0x8d,0xbe, 0xeb,0x2e,0xd9,0xe2, 0xf8,0xa7,0xc1,0xb8, 0x77,0xa7,0x15,0xa5, + 0x9d,0xc2,0xc2,0xfb, 0xec,0x69,0x15,0xdb, 0x0e,0xc4,0xf2,0x86, 0xc7,0x0a,0x0b,0xf5, + 0xf9,0x0e,0xe2,0xcf, 0xdc,0xf9,0x2f,0xd6, 0x5e,0x2e,0x53,0x0a, 0x83,0x95,0x86,0xd6, + 0x2d,0x95,0xb6,0x37, 0xcd,0xc7,0xf6,0xa2, 0x7c,0x7d,0x24,0x4d, 0x2b,0xfe,0x5d,0xf7, + 0x32,0x0e,0x9c,0x11, 0x02,0x90,0x71,0xc7, 0x74,0xfa,0x6d,0x94, 0x5d,0xe3,0xb5,0x6a, + 0xeb,0xad,0xda,0xfb, 0x52,0x73,0xc7,0x18, 0xc6,0x99,0x7b,0x86, 0x66,0x69,0x2d,0xed, + 0x6b,0x12,0xc2,0xf0, 0x81,0x0c,0x7b,0xf7, 0x49,0x15,0x31,0x8f, 0xd5,0x20,0x2a,0x33, + 0x37,0x36,0x76,0x37, 0x31,0x6d,0x03,0x1a, 0xc1,0xd3,0x1e,0x82, 0xf5,0xe9,0x6e,0x8e, + 0x9b,0xbd,0x21,0x48, 0xc4,0x0a,0xbb,0x8c, 0xc4,0x89,0x91,0x35, 0xdd,0x3f,0x36,0x92, + 0x30,0x46,0x48,0x5c, 0x04,0x9a,0xde,0xf0, 0x15,0x34,0xa7,0xcc, 0xeb,0xcc,0x13,0xfe, + 0x26,0x2e,0xd5,0x74, 0xf2,0xcd,0xd1,0x03, 0x32,0x93,0xac,0xeb, 0x15,0xb2,0x79,0x0c, + 0x2a,0x08,0x0d,0x34, 0x0d,0x59,0x59,0x9c, 0x68,0xe0,0xaa,0x36, 0x95,0xa3,0x9d,0x55, + 0x20,0x8f,0x12,0x3e, 0x10,0xe9,0x04,0xfc, 0x5a,0x0b,0x53,0xa9, 0x27,0x54,0x85,0x44, + 0x35,0x47,0x07,0xc1, 0xd9,0xe2,0x07,0x84, 0x24,0x7c,0x28,0x20, 0xc8,0x4e,0x98,0x7e, + // 0x600: + 0x33,0x4a,0x0e,0xc6, 0x54,0xef,0xeb,0xe7, 0xf3,0x6a,0x98,0x04, 0x0b,0x82,0x7d,0xcb, + 0x47,0x60,0x3e,0xb7, 0x78,0xed,0xc6,0x9c, 0xc6,0x04,0x5d,0x50, 0x79,0x60,0xd1,0xd4, + 0x58,0x57,0x42,0x53, 0x23,0x9e,0x3e,0xd8, 0x10,0xa8,0x07,0x28, 0x53,0xa6,0x84,0xf1, + 0x0f,0x74,0x10,0xef, 0x2a,0xfd,0x3c,0x71, 0xce,0x06,0x2e,0x82, 0x39,0x64,0x13,0x3a, + 0x46,0x0b,0x30,0xa6, 0x68,0xd8,0x58,0x05, 0x92,0xf3,0x4d,0xc7, 0x20,0xd6,0xd3,0xe7, + 0x7b,0x5c,0x00,0x73, 0x17,0x3f,0x01,0x0f, 0xcd,0xfc,0x5f,0xf9, 0x10,0xa8,0x21,0x1d, + 0x3b,0x4c,0x8b,0x0d, 0x4c,0x04,0x42,0x01, 0x29,0x27,0x60,0xa4, 0x09,0x47,0x98,0x4c, + 0xdf,0x62,0x90,0x0b, 0xd1,0xad,0x18,0x19, 0x67,0xba,0x51,0xea, 0x2c,0x63,0xbe,0x94, + 0xb5,0xdd,0xac,0x3e, 0x16,0xc3,0x0a,0x43, 0x79,0xce,0xf9,0x45, 0xef,0xff,0xd9,0xed, + 0xf1,0x3f,0xd9,0x3a, 0x42,0x82,0xdd,0xfc, 0xba,0x7a,0x2d,0x48, 0x96,0xdb,0xb5,0x3c, + 0x0a,0x4b,0xc8,0x4b, 0x3d,0x94,0x4a,0x01, 0x9c,0xd9,0xe9,0xdb, 0x2a,0xd4,0xc9,0x2d, + 0xb9,0x8c,0xc0,0xb5, 0x5c,0xba,0x60,0xb8, 0x90,0x92,0x3d,0xc9, 0x69,0x86,0x66,0x48, + 0x06,0x1d,0x48,0x47, 0x30,0xa7,0xa6,0x43, 0x62,0xb0,0xf2,0xaa, 0x30,0xe3,0x9f,0xa0, + 0xad,0x14,0x30,0xe1, 0x1e,0x85,0x34,0x57, 0x23,0x91,0x51,0x93, 0x9b,0x33,0x64,0x87, + 0x03,0xfd,0x42,0x45, 0x9f,0x9b,0x55,0xf5, 0x1d,0x08,0x57,0x0e, 0xdc,0x20,0x88,0x4d, + 0xc9,0xf5,0x49,0xac, 0x36,0x24,0x0c,0x39, 0xc5,0x77,0xb3,0x5a, 0x6f,0x30,0xc7,0x50, + // 0x700: + 0x59,0x25,0x0d,0x92, 0x91,0x6c,0x29,0x82, 0x3f,0x65,0xee,0xb7, 0xa4,0x37,0xc9,0x1a, + 0x7f,0x58,0xd6,0xfd, 0x2e,0xa8,0x90,0x64, 0x74,0xa1,0x66,0x0f, 0xbb,0xe8,0x28,0xa5, + 0x45,0x4c,0x8a,0x4f, 0xb5,0x87,0x05,0xc4, 0xfa,0x0c,0xf2,0x0e, 0xcd,0x01,0x98,0x08, + 0x45,0x87,0xb2,0x2a, 0xa5,0x0c,0xb4,0x74, 0xd9,0xe1,0x5f,0x59, 0x68,0xf6,0x6e,0xe6, + 0x9b,0x25,0xd6,0x4b, 0xd6,0x2a,0xc6,0x5e, 0x75,0x4c,0xb0,0xfc, 0x5b,0x04,0x10,0x07, + 0xde,0xc7,0x35,0x99, 0x3a,0x27,0x45,0x20, 0x54,0x11,0x5a,0x7d, 0xb3,0x33,0x51,0xa9, + 0xc8,0x52,0x5c,0x4c, 0x25,0xe6,0x17,0x96, 0x5c,0x43,0xe8,0xd3, 0x60,0x95,0x92,0x66, + 0xdd,0x29,0x62,0x92, 0xfa,0xaa,0xd8,0x58, 0xeb,0x4f,0x8f,0x74, 0xf7,0x50,0xe5,0xee, + 0xd9,0x55,0x18,0x94, 0x72,0x2b,0x7a,0x1e, 0x8a,0x17,0x24,0x85, 0x07,0x36,0x51,0xb5, + 0x2d,0x3a,0xa9,0x21, 0x54,0xaa,0xb7,0x94, 0xee,0xe1,0x95,0x35, 0x23,0x3c,0x94,0x16, + 0x45,0x88,0xf5,0xe2, 0x11,0xb7,0x5c,0x86, 0x97,0xf9,0x15,0x9b, 0xd8,0x39,0x31,0xf5, + 0x0f,0xd7,0x90,0xab, 0x66,0xc2,0x0c,0x15, 0xeb,0x86,0x30,0x43, 0xea,0x63,0x77,0xc6, + 0x93,0xb6,0x56,0x80, 0x17,0x12,0x2d,0xc6, 0xd0,0xd0,0xe2,0xc3, 0x42,0x68,0xcc,0x8b, + 0x60,0x20,0x35,0x95, 0x50,0x62,0x92,0x7e, 0x81,0xd9,0x68,0xf4, 0xad,0xbe,0xc3,0x38, + 0x63,0x1f,0x1a,0xfe, 0xff,0xc8,0x02,0x3e, 0x34,0x52,0x0c,0x99, 0x28,0xa8,0xe1,0x61, + 0x63,0x97,0xc6,0x90, 0x5c,0xcb,0x79,0x9b, 0x84,0x4e,0x9b,0xd7, 0x5f,0x40,0x4a,0xa1, + // 0x800: + 0x0c,0xe0,0x62,0x34, 0xa6,0x6a,0xd0,0x88, 0x04,0xd2,0x84,0x10, 0xca,0xfe,0x17,0xef, + 0x3d,0x2b,0xf7,0x13, 0x9d,0xe4,0x57,0xac, 0x84,0x78,0xb6,0xae, 0xbf,0xb4,0xf9,0x4f, + 0x83,0xea,0xb2,0xd1, 0x56,0x75,0x8e,0xd1, 0x72,0xc2,0x1e,0xa2, 0xc0,0x91,0xd9,0x6f, + 0xcf,0x68,0x51,0xa5, 0x9f,0x87,0x78,0x37, 0x32,0xe7,0x29,0x58, 0xa3,0x6b,0x7c,0x56, + 0x03,0xc4,0xc2,0x85, 0x12,0xdd,0x10,0x52, 0x39,0xa0,0x98,0x12, 0xa1,0xa7,0xd5,0xf1, + 0x90,0x92,0x1d,0x24, 0x3e,0x16,0x3d,0x56, 0x28,0x90,0x9d,0xbf, 0x5f,0x55,0x07,0x18, + 0x80,0xda,0x9c,0xd2, 0x43,0xab,0xfc,0x4a, 0x8c,0x3d,0xba,0xcf, 0xdf,0xdb,0x28,0x2b, + 0x3d,0x83,0xd4,0xcf, 0xd0,0xf3,0x64,0x71, 0x71,0x98,0xd6,0x8f, 0x13,0x35,0x6a,0xfc, + 0xed,0x7a,0x41,0xed, 0x0c,0x62,0xab,0x46, 0x9c,0xc7,0x29,0x53, 0xc6,0x67,0x5e,0xf8, + 0x69,0x79,0x3c,0xe0, 0xc2,0xec,0x0a,0x52, 0x51,0x80,0x8e,0x7c, 0x9d,0x11,0x02,0x1f, + 0x91,0x6b,0x9c,0x96, 0xb4,0xa1,0x2d,0x79, 0x6c,0x5d,0x6e,0x12, 0x97,0x97,0x0e,0xb2, + 0xfb,0xba,0x4a,0x14, 0x6d,0xe0,0xe6,0x30, 0xb2,0xa0,0x19,0xc8, 0x86,0xb5,0x18,0x19, + 0xb3,0x80,0xb0,0x50, 0x40,0x44,0x4b,0x93, 0xa3,0x70,0x4a,0x9e, 0xdb,0xa9,0xd0,0x38, + 0x17,0x10,0xf4,0x66, 0xbb,0xa5,0x26,0x8a, 0xf2,0xb8,0xe7,0x8b, 0x2b,0xc2,0x41,0xf0, + 0xcb,0x80,0x30,0x0e, 0xa5,0x90,0x42,0x28, 0x65,0x13,0xb2,0xa9, 0x01,0xd1,0xd9,0x34, + 0x00,0xc2,0xc1,0x92, 0xd5,0x14,0xdb,0x94, 0xaf,0xd9,0x4b,0x28, 0x54,0x11,0xf4,0xe6, + // 0x900: + 0xbe,0xb9,0xac,0x06, 0x67,0xb3,0xc5,0xcc, 0x54,0xf9,0xa9,0x2c, 0x13,0x46,0xde,0x12, + 0xe6,0xc9,0x8c,0xa1, 0xeb,0xb6,0x0d,0x4b, 0xe7,0xa8,0xb1,0x4f, 0x31,0x0c,0x34,0xd3, + 0x6a,0xd3,0x73,0x49, 0x3c,0xbb,0xc3,0x32, 0xb2,0x9d,0x29,0x3e, 0x70,0x96,0x56,0xd4, + 0xb9,0x2a,0xc8,0x83, 0x47,0x51,0x67,0xe0, 0x7e,0x84,0x02,0x68, 0xc9,0x7d,0xbc,0xc1, + 0x93,0x3a,0x27,0x0d, 0x8d,0x0a,0x03,0x9c, 0xb0,0xdc,0x75,0xf1, 0xbb,0x34,0x59,0x8e, + 0x2d,0x9a,0xa7,0xf2, 0xff,0xa3,0x9f,0x3d, 0xa2,0x41,0xc4,0x74, 0xc9,0x03,0x69,0x5a, + 0xad,0x3b,0x53,0x49, 0xf8,0x80,0xb2,0x3f, 0x21,0x2f,0xa5,0x69, 0xf3,0x56,0x49,0xa6, + 0xab,0xcb,0x58,0x80, 0x80,0x01,0x9c,0xcc, 0x8c,0xc2,0x40,0xce, 0x86,0x75,0x57,0xa4, + 0x31,0x11,0x43,0x21, 0x93,0x09,0x32,0x4c, 0x21,0x0c,0xc2,0x43, 0x55,0xb0,0x70,0x61, + 0xfe,0x3a,0x49,0x6c, 0x6a,0xcd,0x34,0xa0, 0x90,0x25,0x84,0xcb, 0x9a,0x3a,0x43,0x96, + 0x82,0xe7,0x66,0x20, 0x4e,0xd3,0x34,0x73, 0x78,0xfd,0xe6,0x27, 0x8e,0xb2,0x02,0xc4, + 0x28,0x4c,0x1b,0x37, 0x9a,0xdb,0x13,0x5f, 0xd4,0xce,0xa1,0x40, 0x3c,0xa5,0x21,0x0c, + 0xb7,0xbc,0x31,0x34, 0xcc,0x47,0x7a,0xe6, 0x30,0xa8,0xed,0x6c, 0xf0,0x25,0xd7,0xf7, + 0xbc,0xe9,0xae,0xa9, 0xd7,0x11,0x36,0x43, 0x30,0x19,0x12,0x83, 0x6e,0x2a,0xd9,0x90, + 0x22,0x8e,0x8d,0x21, 0xd4,0x22,0xb9,0xc8, 0x30,0x80,0x75,0x7a, 0x74,0x44,0x3c,0x6a, + 0xa7,0x9a,0x83,0xd8, 0xf8,0xb5,0x45,0x8e, 0x20,0x42,0x60,0x45, 0xc5,0x7a,0x29,0x48, + // 0xa00: + 0x97,0xe1,0x04,0x6e, 0xee,0x01,0x54,0x80, 0xc1,0x60,0xfd,0x13, 0xda,0x4e,0x6b,0xe1, + 0x5b,0x64,0x2d,0x89, 0xe2,0x04,0x4a,0x66, 0x96,0x73,0x4c,0xa9, 0x5e,0xf0,0x94,0x2f, + 0x66,0x99,0xb1,0xb4, 0xfa,0x0c,0x3a,0xf6, 0x51,0xe1,0x5b,0xb8, 0x69,0xc8,0xb9,0x16, + 0xd7,0x3f,0x26,0x6c, 0xb3,0x8d,0xc0,0xf7, 0x22,0x49,0x23,0x7d, 0xa5,0x42,0x01,0x16, + 0xa6,0xc0,0xbb,0x90, 0x32,0x62,0x88,0x6b, 0x8b,0xe2,0x5c,0x14, 0x52,0x8d,0xb4,0x05, + 0x77,0x0e,0xc6,0x3a, 0x75,0xdd,0xac,0x52, 0xb3,0xd5,0x2c,0x9c, 0x8e,0xc5,0x66,0x74, + 0xd4,0x28,0x54,0x2c, 0x71,0x14,0x6e,0x9b, 0x62,0x39,0x27,0x30, 0x58,0xbd,0x93,0xfc, + 0xc7,0xb2,0x70,0x40, 0x82,0x20,0xdf,0x82, 0x61,0xcc,0xe8,0xf3, 0xe6,0x8b,0x56,0x49, + 0x2d,0x16,0xa3,0x21, 0x02,0x7d,0x26,0xab, 0xf0,0xa4,0x72,0x57, 0x51,0xf6,0xfc,0x2e, + 0xa1,0x3e,0x86,0xaa, 0xa5,0xc8,0x40,0xc5, 0x0d,0xbb,0x57,0x31, 0x18,0x35,0xa5,0x46, + 0x56,0x0d,0x6b,0xa8, 0x91,0x1d,0xab,0x58, 0xee,0xc4,0x55,0x6a, 0x6d,0x9a,0x2f,0xa1, + 0xb0,0xcd,0x86,0xc0, 0xc6,0x8c,0xeb,0x86, 0x0a,0xcc,0x10,0x7f, 0x59,0xb1,0x32,0x38, + 0x86,0x22,0xc6,0x4a, 0x82,0xa9,0xe9,0x98, 0xcb,0xff,0x5c,0x90, 0x12,0x10,0x0a,0x60, + 0x9e,0x0b,0x1f,0xe7, 0x72,0x29,0x9c,0x5c, 0xa5,0xae,0xb0,0xa8, 0xe4,0x34,0x92,0xcb, + 0x01,0x0b,0x28,0xc9, 0x72,0xd6,0xbe,0x0b, 0x7c,0xcb,0x52,0x38, 0x0a,0x7a,0x58,0x15, + 0xd9,0x96,0x36,0x3e, 0x64,0xcc,0x80,0x6a, 0x27,0x0e,0x50,0x53, 0xa1,0xa1,0x40,0x32, + // 0xb00: + 0x79,0xfe,0x0e,0xc2, 0x0a,0x11,0x1d,0xcf, 0x60,0x8a,0x41,0x1a, 0x2c,0xec,0xc8,0x36, + 0xa4,0xad,0xab,0x10, 0x7c,0x04,0x6f,0x64, 0x67,0x01,0x8b,0xb3, 0xdd,0xb2,0xaf,0x16, + 0x04,0x6c,0x56,0xe5, 0x0b,0xc3,0x12,0x10, 0xec,0x0c,0xab,0x19, 0x70,0x09,0x73,0x52, + 0xba,0x81,0x2d,0x24, 0x88,0x8c,0x33,0x25, 0x3e,0xab,0x56,0x20, 0x12,0x0e,0xd9,0x08, + 0x5e,0x63,0x00,0xc4, 0x00,0xb0,0xf0,0x62, 0x72,0xa4,0xc3,0xa8, 0x52,0x90,0xc9,0x63, + 0xd0,0x35,0x1c,0x7a, 0x54,0x2d,0x0f,0x81, 0x06,0x32,0x23,0x6b, 0xe3,0x07,0xca,0xd5, + 0xec,0xac,0xad,0xad, 0x52,0xc2,0x8a,0x6b, 0x24,0xc5,0x8a,0xdd, 0x27,0x21,0x08,0x1e, + 0xe7,0x60,0x6d,0xfd, 0x2e,0x37,0x11,0x16, 0x8d,0x39,0x1b,0x6a, 0xf6,0x93,0x41,0x82, + 0x63,0x72,0x49,0x2f, 0xf5,0x13,0x6d,0xd1, 0x9e,0x59,0xb8,0x4e, 0x78,0xd4,0x50,0xe5, + 0x66,0x63,0x03,0xa1, 0x8a,0xac,0x43,0xa0, 0x91,0xd6,0x2b,0xb6, 0x1d,0x86,0xf7,0xbd, + 0x98,0xc3,0x73,0xaf, 0x21,0xf6,0xc2,0x0c, 0x1d,0x7a,0x0b,0xce, 0xeb,0x05,0x4b,0xae, + 0x51,0xc6,0x33,0xd0, 0xc7,0xfe,0x2e,0xe4, 0x8a,0x70,0xa1,0x20, 0x3d,0xb3,0x2e,0x4a, + // 0xbc0 = 3008 Bytes +}; + +static BZ2Manager_t codehandler_mgr + = { codehandler_bz2, sizeof(codehandler_bz2), 0, 0 }; + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// struct staticr_t /////////////// +/////////////////////////////////////////////////////////////////////////////// + +void InitializeSTR ( staticr_t * str ) +{ + memset(str,0,sizeof(*str)); + memset(str->dol_flags,'-',sizeof(str->dol_flags)-1); + str->fname = EmptyString; +} + +/////////////////////////////////////////////////////////////////////////////// + +void ResetSTR ( staticr_t * str ) +{ + if (str) + { + if (str->data_alloced) + FREE(str->data); + FreeString(str->fname); + + InitializeSTR(str); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +static bool CheckSizeSTR ( staticr_t * str ) +{ + DASSERT(str); + + switch (str->data_size) + { + case 4903876: + str->mode = STR_M_PAL; + break; + + case 4902804: + str->mode = STR_M_USA; + break; + + case 4901564: + str->mode = STR_M_JAP; + break; + + case 4905468: + str->mode = STR_M_KOR; + break; + + default: + str->mode = STR_M_UNKNOWN; + str->str_status = STR_S_ANALYZED | STR_S_WRONG_SIZE; + return false; + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError LoadSTR +( + staticr_t * str, // valid pointer + bool initialize, // true: initialize 'bmg' + ccp fname, // filename of source + bool ignore_no_file // ignore if file does not exists + // and return warning ERR_NOT_EXISTS +) +{ + DASSERT(str); + DASSERT(fname); + TRACE("LoadSTR(%d,%d) fbname=%s\n",initialize,ignore_no_file,fname); + + if (initialize) + InitializeSTR(str); + else + ResetSTR(str); + + str->data_alloced = true; + enumError err = OpenReadFILE( fname, 0, ignore_no_file, + &str->data, &str->data_size, &str->fname, &str->fatt ); + if (err) + return err; + +// [[analyse-magic]] + str->fform = GetByMagicFF(str->data,str->data_size,str->data_size); + switch(str->fform) + { + case FF_STATICR: + if (!CheckSizeSTR(str)) + break; + str->is_staticr = true; + return ERR_OK; + + case FF_DOL: + str->is_dol = true; + return ERR_OK; + + default: + break; + } + + if (!ignore_no_file) + ERROR0(ERR_WARNING,"Neither StaticR nor DOL file: %s\n",fname); + return ERR_WARNING; +} + +/////////////////////////////////////////////////////////////////////////////// + +static bool ReplaceRegionChar ( staticr_t *str, char *buf, uint buf_size, ccp fname ) +{ + DASSERT(str); + DASSERT(buf); + DASSERT(buf_size>100); + + bool stat = false; + const char reg_char = GetStrModeRegionChar(str->mode); + + if (reg_char) + { + StringCopyS(buf,buf_size,fname); + char *p = strrchr(buf,'/'); + if (!p) + p = buf; + + for ( ; *p; p++ ) + if ( *p == '@' ) + { + *p = reg_char; + stat = true; + } + } + return stat; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// dol_sect_info_t /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static const dol_sect_info_t dol_info_pal[DOL_NN_SECTIONS] = +{ + { 0, "T0", 0x100, 0x80004000, 0x2460, 1,0,1, 0, + { 0x67,0xa0,0xfd,0x48,0x8f, 0x9b,0xe2,0xb8,0xa1,0x35, + 0xed,0x61,0x48,0xe7,0x41, 0x0b,0xb6,0x5b,0xdf,0x2f }}, + { 1, "T1", 0x2560, 0x800072c0, 0x23db20, 1,0,1, 0, + { 0x1c,0xbe,0x24,0xaf,0x98, 0x6a,0x6e,0x3e,0xbe,0xa1, + 0x5c,0xc9,0x66,0x49,0xce, 0xc7,0x7d,0x73,0x75,0x7b }}, + { 2, "T2", 0, 0, 0, 0,0,0, 0, {0} }, + { 3, "T3", 0, 0, 0, 0,0,0, 0, {0} }, + { 4, "T4", 0, 0, 0, 0,0,0, 0, {0} }, + { 5, "T5", 0, 0, 0, 0,0,0, 0, {0} }, + { 6, "T6", 0, 0, 0, 0,0,0, 0, {0} }, + { 7, "D0", 0x240080, 0x80006460, 0x5c0, 1,0,1, 0, + { 0xc8,0xbf,0xf1,0x5d,0x1d, 0x5a,0x05,0x77,0xbc,0xec, + 0x42,0x05,0xe7,0x11,0x76, 0x64,0xa1,0x87,0xfd,0x3d }}, + { 8, "D1", 0x240640, 0x80006a20, 0x8a0, 1,0,1, 0, + { 0x6c,0xe1,0x67,0x91,0x92, 0x92,0x44,0x05,0x12,0x12, + 0x64,0xff,0x57,0x7f,0xae, 0x81,0xe5,0xa8,0xf8,0x7a }}, + { 9, "D2", 0x240ee0, 0x80244de0, 0xc0, 1,0,1, 0, + { 0xf6,0x7f,0x2b,0x81,0x56, 0x65,0x9d,0xac,0xd2,0x56, + 0xb0,0xcd,0x6c,0xca,0xfd, 0x72,0x39,0xe5,0x3d,0x2e }}, + { 10, "D3", 0x240fa0, 0x80244ea0, 0x20, 1,0,1, 0, + { 0xeb,0x28,0xbc,0x20,0x23, 0x0a,0xce,0xa4,0xc9,0xe0, + 0x6d,0x67,0xee,0x25,0x20, 0x1c,0xa1,0x55,0x39,0x7d }}, + { 11, "D4", 0x240fc0, 0x80244ec0, 0x136c0, 1,0,1, 0, + { 0x4f,0xd6,0xcf,0x0f,0x65, 0x76,0xc1,0x23,0x96,0x86, + 0xc8,0x37,0x1b,0x95,0x93, 0x9f,0xba,0x72,0xf6,0xc5 }}, + { 12, "D5", 0x254680, 0x80258580, 0x4bac0, 1,0,1, 0, + { 0x4a,0x9a,0x76,0x06,0x69, 0x35,0x0b,0xd2,0x54,0xd2, + 0xbf,0x22,0xac,0xd9,0xf9, 0xc8,0x13,0xcf,0x95,0xd8 }}, + { 13, "D6", 0x2a0140, 0x80384c00, 0x13c0, 1,0,1, 0, + { 0xaa,0x9a,0x25,0x46,0xb8, 0xd9,0x57,0x5e,0x22,0x6d, + 0x72,0x2f,0x71,0xff,0x86, 0x49,0xc6,0x12,0x2d,0xcf }}, + { 14, "D7", 0x2a1500, 0x80386fa0, 0x21a0, 1,0,1, 0, + { 0x43,0x0d,0x6f,0xd3,0xe0, 0x12,0x72,0x2f,0x44,0x5b, + 0x9e,0xdc,0x92,0x1b,0xe0, 0x62,0x8e,0x72,0xe8,0x07 }}, + { 15, "D8", 0, 0, 0, 0,0,0, 0, {0} }, + { 16, "D9", 0, 0, 0, 0,0,0, 0, {0} }, + { 17, "D10", 0, 0, 0, 0,0,0, 0, {0} }, + { 18, "BSS", 0, 0x802a4080, 0xe50fc, 1,0,0, 0, {0} }, + { 19, "ENT", 0, 0x800060a4, 0, 1,0,0, 0, {0} }, +}; + +/////////////////////////////////////////////////////////////////////////////// + +static const dol_sect_info_t dol_info_usa[DOL_NN_SECTIONS] = +{ + { 0, "T0", 0x100, 0x80004000, 0x2460, 1,0,1, 0, + { 0x5e,0x16,0x94,0x9f,0x50, 0x5f,0xc6,0xc3,0x6e,0xca, + 0x76,0x5b,0x8a,0x07,0x6e, 0x23,0x68,0x77,0x84,0x67 }}, + { 1, "T1", 0x2560, 0x800072c0, 0x23da80, 1,0,1, 0, + { 0x3a,0x6d,0x28,0xc3,0xdd, 0xc8,0x10,0xcc,0xf0,0xb2, + 0x7f,0xe7,0xd8,0x7d,0x12, 0x8f,0x62,0x72,0xd0,0xed }}, + { 2, "T2", 0, 0, 0, 0,0,0, 0, {0} }, + { 3, "T3", 0, 0, 0, 0,0,0, 0, {0} }, + { 4, "T4", 0, 0, 0, 0,0,0, 0, {0} }, + { 5, "T5", 0, 0, 0, 0,0,0, 0, {0} }, + { 6, "T6", 0, 0, 0, 0,0,0, 0, {0} }, + { 7, "D0", 0x23ffe0, 0x80006460, 0x5c0, 1,0,1, 0, + { 0x47,0x6d,0x32,0x6c,0x21, 0xaa,0x65,0xf2,0x9e,0x69, + 0xf9,0xde,0xd2,0xaa,0xb6, 0xc2,0x76,0x94,0x19,0x09 }}, + { 8, "D1", 0x2405a0, 0x80006a20, 0x8a0, 1,0,1, 0, + { 0x73,0x5b,0x90,0x85,0x58, 0x13,0x3f,0x1e,0x56,0x67, + 0xeb,0x61,0x3a,0xa9,0xe9, 0x13,0xc4,0xd3,0xd5,0x6f }}, + { 9, "D2", 0x240e40, 0x80244d40, 0xc0, 1,0,1, 0, + { 0x4a,0x87,0x49,0xbd,0xa1, 0x78,0x9f,0x8c,0x9c,0x9e, + 0x25,0x6a,0x6b,0xda,0x19, 0x7f,0x7f,0xc7,0xf5,0x7f }}, + { 10, "D3", 0x240f00, 0x80244e00, 0x20, 1,0,1, 0, + { 0xe1,0x05,0x64,0x2d,0x86, 0x59,0xc9,0xac,0x76,0xde, + 0x8c,0x84,0xd0,0x67,0xc6, 0x9a,0x37,0x2f,0xd5,0xab }}, + { 11, "D4", 0x240f20, 0x80244e40, 0x13420, 1,0,1, 0, + { 0xbd,0x62,0x9a,0x5e,0x1b, 0xda,0xf5,0x46,0xe8,0x04, + 0xcb,0xa1,0xfa,0xca,0xac, 0x38,0xac,0x7a,0xe6,0xaf }}, + { 12, "D5", 0x254340, 0x80258260, 0x47aa0, 1,0,1, 0, + { 0x9b,0x08,0x11,0xf2,0xb5, 0xed,0x17,0x69,0x7e,0x4b, + 0xb3,0xef,0xb4,0x65,0x23, 0x78,0x21,0x24,0x27,0xc1 }}, + { 13, "D6", 0x29bde0, 0x80380880, 0x13c0, 1,0,1, 0, + { 0x98,0x55,0xd3,0xa2,0x15, 0x10,0xe6,0xd4,0x78,0xa8, + 0x40,0x51,0xe5,0x51,0x77, 0x04,0x10,0x18,0x29,0x63 }}, + { 14, "D7", 0x29d1a0, 0x80382c20, 0x21a0, 1,0,1, 0, + { 0x9b,0x2c,0x27,0x2b,0x6b, 0x43,0xff,0xce,0x11,0x05, + 0x92,0x29,0x42,0x26,0x6f, 0x9c,0x59,0xd6,0x55,0xe8 }}, + { 15, "D8", 0, 0, 0, 0,0,0, 0, {0} }, + { 16, "D9", 0, 0, 0, 0,0,0, 0, {0} }, + { 17, "D10", 0, 0, 0, 0,0,0, 0, {0} }, + { 18, "BSS", 0, 0x8029fd00, 0xe50fc, 1,0,0, 0, {0} }, + { 19, "ENT", 0, 0x800060a4, 0, 1,0,0, 0, {0} }, +}; + +/////////////////////////////////////////////////////////////////////////////// + +static const dol_sect_info_t dol_info_jap[DOL_NN_SECTIONS] = +{ + { 0, "T0", 0x100, 0x80004000, 0x2460, 1,0,1, 0, + { 0xa6,0x86,0x2e,0xbc,0x13, 0xdd,0x9e,0x7e,0xfa,0xa9, + 0x0d,0x49,0x19,0x5f,0x9b, 0xe6,0x30,0x19,0x01,0x4e }}, + { 1, "T1", 0x2560, 0x800072c0, 0x23da40, 1,0,1, 0, + { 0x93,0xb4,0x6b,0xbe,0xab, 0xf5,0x7d,0x98,0x93,0xf2, + 0x16,0x07,0x4f,0xc0,0x44, 0x82,0x01,0xd1,0x42,0x40 }}, + { 2, "T2", 0, 0, 0, 0,0,0, 0, {0} }, + { 3, "T3", 0, 0, 0, 0,0,0, 0, {0} }, + { 4, "T4", 0, 0, 0, 0,0,0, 0, {0} }, + { 5, "T5", 0, 0, 0, 0,0,0, 0, {0} }, + { 6, "T6", 0, 0, 0, 0,0,0, 0, {0} }, + { 7, "D0", 0x23ffa0, 0x80006460, 0x5c0, 1,0,1, 0, + { 0x7f,0xcd,0xe8,0xc8,0x06, 0xfb,0x10,0xbc,0x81,0x9c, + 0xb8,0xbb,0xa0,0x72,0x6a, 0xd8,0x75,0xb2,0xb7,0x6a }}, + { 8, "D1", 0x240560, 0x80006a20, 0x8a0, 1,0,1, 0, + { 0x5a,0x2c,0x70,0x39,0x11, 0x58,0xa0,0x71,0xc0,0xb9, + 0x09,0xac,0x3e,0xde,0x55, 0x64,0xb0,0x70,0xb7,0x52 }}, + { 9, "D2", 0x240e00, 0x80244d00, 0xc0, 1,0,1, 0, + { 0xb4,0x63,0xae,0x32,0x03, 0x5d,0xcc,0xa7,0xb0,0x64, + 0xee,0x4a,0x1c,0x24,0xd3, 0x10,0x84,0xd9,0xf7,0xe1 }}, + { 10, "D3", 0x240ec0, 0x80244dc0, 0x20, 1,0,1, 0, + { 0x40,0x65,0xb7,0x71,0x65, 0x6e,0xbc,0x7f,0x04,0x1c, + 0xe3,0x44,0xb5,0x32,0x42, 0x0d,0x43,0x05,0x76,0xa8 }}, + { 11, "D4", 0x240ee0, 0x80244e00, 0x13120, 1,0,1, 0, + { 0xba,0x43,0xcc,0x17,0x8b, 0x01,0x44,0xc0,0x5b,0x38, + 0x59,0x9d,0xfc,0x2c,0x14, 0xcd,0xa6,0x9b,0xc1,0x8a }}, + { 12, "D5", 0x254000, 0x80257f20, 0x4bac0, 1,0,1, 0, + { 0x16,0x24,0x5d,0xad,0xb9, 0x7f,0xe9,0x5f,0x00,0x7f, + 0xef,0x6f,0xec,0xf6,0x24, 0xe5,0x35,0xc1,0x7c,0x38 }}, + { 13, "D6", 0x29fac0, 0x80384580, 0x13c0, 1,0,1, 0, + { 0xb7,0x6b,0x13,0x92,0x1c, 0xad,0x77,0x78,0x92,0xe8, + 0xff,0xe4,0x5d,0x45,0xe6, 0x1c,0x06,0xb8,0x4d,0xdb }}, + { 14, "D7", 0x2a0e80, 0x80386920, 0x21a0, 1,0,1, 0, + { 0x4d,0xc4,0xf5,0x81,0x3b, 0x8b,0x9e,0x5d,0xc3,0x36, + 0xfb,0x91,0xa9,0xc0,0x5b, 0xd7,0x59,0x11,0xee,0x25 }}, + { 15, "D8", 0, 0, 0, 0,0,0, 0, {0} }, + { 16, "D9", 0, 0, 0, 0,0,0, 0, {0} }, + { 17, "D10", 0, 0, 0, 0,0,0, 0, {0} }, + { 18, "BSS", 0, 0x802a3a00, 0xe50fc, 1,0,0, 0, {0} }, + { 19, "ENT", 0, 0x800060a4, 0, 1,0,0, 0, {0} }, +}; + +/////////////////////////////////////////////////////////////////////////////// + +static const dol_sect_info_t dol_info_kor[DOL_NN_SECTIONS] = +{ + { 0, "T0", 0x100, 0x80004000, 0x2460, 1,0,1, 0, + { 0x8e,0x71,0x21,0xdf,0x02, 0x9f,0xff,0x15,0x45,0x5b, + 0xc9,0x30,0xdd,0xda,0x1a, 0x84,0x35,0x41,0xe8,0xc3 }}, + { 1, "T1", 0x2560, 0x800072c0, 0x23dea0, 1,0,1, 0, + { 0xfc,0xf6,0x28,0x91,0x85, 0x47,0x11,0xc3,0x4e,0xac, + 0x2e,0x61,0x47,0x53,0x5e, 0xe1,0x7c,0x3c,0xb8,0xe6 }}, + { 2, "T2", 0, 0, 0, 0,0,0, 0, {0} }, + { 3, "T3", 0, 0, 0, 0,0,0, 0, {0} }, + { 4, "T4", 0, 0, 0, 0,0,0, 0, {0} }, + { 5, "T5", 0, 0, 0, 0,0,0, 0, {0} }, + { 6, "T6", 0, 0, 0, 0,0,0, 0, {0} }, + { 7, "D0", 0x240400, 0x80006460, 0x5c0, 1,0,1, 0, + { 0x2d,0x62,0xc1,0xdb,0x2a, 0x82,0x64,0x0a,0xa7,0x61, + 0xdd,0x6d,0xfc,0x4a,0x4d, 0x59,0xb4,0x51,0x6c,0x27 }}, + { 8, "D1", 0x2409c0, 0x80006a20, 0x8a0, 1,0,1, 0, + { 0x8b,0x99,0x7f,0x81,0xdf, 0x8b,0x0e,0x1d,0x96,0x3e, + 0xbf,0xe7,0xa3,0xb2,0x0e, 0x92,0x7d,0xcc,0x5f,0x5b }}, + { 9, "D2", 0x241260, 0x80245160, 0xc0, 1,0,1, 0, + { 0x7f,0xcd,0xfb,0xdd,0x3e, 0x2b,0xf4,0xf2,0x35,0xd0, + 0x4a,0x57,0xcb,0x9a,0xb0, 0xa2,0x2a,0x86,0xf0,0xa5 }}, + { 10, "D3", 0x241320, 0x80245220, 0x20, 1,0,1, 0, + { 0xcd,0x27,0xcf,0xe9,0xce, 0x3f,0x28,0xbc,0x64,0xb3, + 0xb2,0x05,0x70,0x10,0xaf, 0x9a,0x5c,0xe6,0x04,0xf7 }}, + { 11, "D4", 0x241340, 0x80245240, 0x13100, 1,0,1, 0, + { 0x23,0x8c,0xc9,0x84,0xd1, 0x07,0x8a,0x1b,0xc4,0x56, + 0x1b,0x56,0x30,0xe0,0x1a, 0x4d,0xbc,0xa1,0x48,0x0c }}, + { 12, "D5", 0x254440, 0x80258340, 0x39d00, 1,0,1, 0, + { 0x4a,0x10,0xfb,0x98,0x57, 0xb0,0xa5,0x96,0xb7,0xf6, + 0x92,0x06,0xed,0xf2,0xdf, 0x04,0x5e,0x6d,0x63,0x55 }}, + { 13, "D6", 0x28e140, 0x80372c00, 0x13e0, 1,0,1, 0, + { 0xad,0x8f,0x5f,0x3d,0xf0, 0x9d,0xa5,0x26,0x9f,0x71, + 0xfb,0xeb,0x7b,0x68,0x99, 0x72,0x71,0xdc,0x65,0xcc }}, + { 14, "D7", 0x28f520, 0x80374fc0, 0x21a0, 1,0,1, 0, + { 0xc3,0x04,0xfc,0x7f,0xf8, 0x6f,0xf0,0x39,0xa9,0xe7, + 0xda,0x78,0xf3,0x1b,0xfa, 0x41,0x91,0x7d,0xf1,0x3c }}, + { 15, "D8", 0, 0, 0, 0,0,0, 0, {0} }, + { 16, "D9", 0, 0, 0, 0,0,0, 0, {0} }, + { 17, "D10", 0, 0, 0, 0,0,0, 0, {0} }, + { 18, "BSS", 0, 0x80292080, 0xe511c, 1,0,0, 0, {0} }, + { 19, "ENT", 0, 0x800060a4, 0, 1,0,0, 0, {0} }, +}; + +/////////////////////////////////////////////////////////////////////////////// + +const dol_sect_info_t * GetInfoDOL ( str_mode_t mode ) +{ + switch (mode) + { + case STR_M_PAL: return dol_info_pal; + case STR_M_USA: return dol_info_usa; + case STR_M_JAP: return dol_info_jap; + case STR_M_KOR: return dol_info_kor; + default: return 0; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +bool GetSectionDOL +( + staticr_t * str, // valid pointer + dol_sect_info_t * ret_info, // valid pointer: returned data + uint section, // 0 .. DOL_NN_SECTIONS + // (7*TEXT, 11*DATA, BSS, ENTRY ) + bool calc_hash // true: calculate SHA1 hash if data available + +) +{ + DASSERT(str); + DASSERT(ret_info); + + bool stat = GetDolSectionInfo( ret_info,( dol_header_t*)str->data, + str->data_size, section ); + if ( calc_hash && stat && ret_info->data_valid ) + { + ret_info->hash_valid = true; + SHA1( ret_info->data, ret_info->size, ret_info->hash ); + } + return stat; +} + +/////////////////////////////////////////////////////////////////////////////// + +const DolSectionMap_t * FindSectionDOL ( uint size, u8 *hash ) +{ + if ( !size || !hash ) + return 0; + + uint beg = 0; + uint end = N_DOL_SECTION_MAP - 1; + + while ( beg <= end ) + { + const uint idx = (beg+end)/2; + const DolSectionMap_t *dsm = DolSectionMap + idx; + if ( size < dsm->size ) + end = idx - 1 ; + else if ( size > dsm->size ) + beg = idx + 1; + else + { + const int stat = memcmp(hash,dsm->hash,sizeof(dsm->hash)); + if ( stat < 0 ) + end = idx - 1 ; + else if ( stat > 0 ) + beg = idx + 1; + else + return dsm; + } + } + return 0; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// ct-code dol extensions /////////////// +/////////////////////////////////////////////////////////////////////////////// +// [[ct_dol_ext_t]] + +typedef struct ct_dol_ext_t +{ + u32 t2_addr; + BZ2Source_t t2_src; + + u32 d8_addr; + BZ2Source_t d8_src; +} +ct_dol_ext_t; + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +ct_dol_ext_t ct_dol_ext_pal = +{ + 0x802a5000, + { "rmcp/boot_code.bin;boot_code.bin", + ctcode_boot_code_pal_bz2, sizeof(ctcode_boot_code_pal_bz2), + FF_CT0_CODE }, + + 0x80002800, + { "rmcp/boot_data.bin;boot_data.bin", + ctcode_boot_data_pal_bz2, sizeof(ctcode_boot_data_pal_bz2), + FF_CT0_DATA }, +}; + +//----------------------------------------------------------------------------- + +ct_dol_ext_t ct_dol_ext_usa = +{ + 0x802a5000, + { "rmce/boot_code.bin;boot_code.bin", + ctcode_boot_code_usa_bz2, sizeof(ctcode_boot_code_usa_bz2), + FF_CT0_CODE }, + + 0x80002800, + { "rmce/boot_data.bin;boot_data.bin", + ctcode_boot_data_usa_bz2, sizeof(ctcode_boot_data_usa_bz2), + FF_CT0_DATA }, +}; + +//----------------------------------------------------------------------------- + +ct_dol_ext_t ct_dol_ext_jap = +{ + 0x802a5000, + { "rmcj/boot_code.bin;boot_code.bin", + ctcode_boot_code_jap_bz2, sizeof(ctcode_boot_code_jap_bz2), + FF_CT0_CODE }, + + 0x80002800, + { "rmcj/boot_data.bin;boot_data.bin", + ctcode_boot_data_jap_bz2, sizeof(ctcode_boot_data_jap_bz2), + FF_CT0_DATA }, +}; + +//----------------------------------------------------------------------------- + +ct_dol_ext_t ct_dol_ext_kor = +{ + 0x802a5000, + { "rmck/boot_code.bin;boot_code.bin", + 0, 0, // [[2do]] [[ct-korea]] + FF_CT0_CODE }, + + 0x80002800, + { "rmck/boot_data.bin;boot_data.bin", + 0, 0, // [[2do]] [[ct-korea]] + FF_CT0_DATA }, +}; + +//----------------------------------------------------------------------------- + +ct_dol_ext_t * GetCtExtDOL ( str_mode_t mode ) +{ + switch (mode) + { + case STR_M_PAL: return &ct_dol_ext_pal; + case STR_M_USA: return &ct_dol_ext_usa; + case STR_M_JAP: return &ct_dol_ext_jap; + case STR_M_KOR: return &ct_dol_ext_kor; + default: return 0; + } +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// PatchHTTPS() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static uint PatchHTTPS_HTTP +( + staticr_t * str, // valid pointer + https_mode_t mode +) +{ + DASSERT(str); + char buf[200], domain_buf[100]; + + static const char nwn[] = "nintendowifi.net"; + static uint nwn_len = sizeof(nwn) - 1; + + const bool mode_sake = mode == HTTPS_SAKE0 || mode == HTTPS_SAKE1; + const bool repl_domain = mode == HTTPS_DOMAIN || mode_sake; + + if ( repl_domain && strlen(wifi_domain) > nwn_len ) + { + ERROR0(ERR_SEMANTIC, + "Domain must be smaller than %u characters if using --https=DOMAIN: %s", + nwn_len+1, wifi_domain ); + opt_https = mode = HTTPS_HTTP; // fall back + } + + uint count = 0; + const str_server_patch_t *pat; + const str_flags_t dol_flag = str->is_dol ? STR_F_IS_DOL : 0; + + for ( pat = ServerPatch; pat->mode; pat++ ) + { + // dirty code: pat->flags is either 0(srel), 1(mdol), 2(mdol+special) + if ( pat->mode != str->mode || (pat->flags & STR_F_IS_DOL) != dol_flag ) + continue; + if ( pat->flags & STR_F_IS_OPTIONAL && opt_wc24 ) + continue; + + const str_server_list_t *sl = ServerList + pat->serv_type; + memset(buf,0,sizeof(buf)); + + if ( pat->flags & STR_F_RESTORE_HTTPS ) + { + strncpy(buf,"https://",sizeof(buf)); + } + else if ( pat->flags & STR_F_IS_SPECIAL && wifi_domain_is_wiimmfi ) + { + switch (pat->serv_type) + { + case SERV_NASW: + snprintf(buf,sizeof(buf),"http://naswii.%s/ac",wifi_domain); + break; + + case SERV_NASW_DEV: + snprintf(buf,sizeof(buf),"https://main.nas.%s/p%c", + wifi_domain, + tolower((int)VersusPointsInfo[pat->mode].region_code) ); + break; + + case SERV_NASW_TEST: + snprintf(buf,sizeof(buf),"http://ca.nas.%s/ca",wifi_domain); + break; + + default: + ASSERT(0); + break; + } + PRINT("STR_F_IS_SPECIAL: %u %s\n",pat->serv_type,buf); + } + else if ( mode_sake && pat->serv_type == SERV_SAKE ) + { + // special case for SAKE servers + + if (!pat->is_http) + snprintf(buf,sizeof(buf),"gs.%s%s", nwn, pat->param ); + else + { + snprintf(buf,sizeof(buf),"%s://%s%s", + mode == HTTPS_SAKE0 && pat->is_http == 2 ? "https" : "http", + sl->domain, pat->param ); + } + } + else if ( pat->serv_type == SERV_NONE ) + { + DASSERT(pat->is_http==2); + char * dest = StringCopyS(buf,sizeof(buf), + mode == HTTPS_RESTORE ? "https" : "http" ); + if ( pat->url_len == 8 ) + StringCopyE(dest,buf+sizeof(buf),"://"); + } + else if (!pat->is_http) + { + snprintf(buf,sizeof(buf),"gs.%s%s", + repl_domain ? wifi_domain : nwn, pat->param); + } + else if ( repl_domain ) + { + snprintf(buf,sizeof(buf),"http://%.*s%s%s", + sl->domain_len - nwn_len, sl->domain, + wifi_domain, pat->param ); + } + else + { + ccp domain = sl->domain; + if ( mode == HTTPS_HTTP && !memcmp(domain,"naswii.",7) ) + { + snprintf(domain_buf,sizeof(domain_buf),"nas.%s",domain+7); + domain = domain_buf; + } + + snprintf(buf,sizeof(buf),"%s://%s%s", + mode == HTTPS_RESTORE && pat->is_http == 2 ? "https" : "http", + domain, pat->param ); + } + + char *data = (char*)str->data + pat->offset; + if (memcmp(data,buf,pat->url_len+1)) + { + //HexDump16(stderr,0,0,data,pat->url_len+1); + //HexDump16(stderr,0,0,buf,pat->url_len+1); + memcpy(data,buf,pat->url_len+1); + count++; + } + } + return count; +} + +/////////////////////////////////////////////////////////////////////////////// + +static uint PatchHTTPS +( + staticr_t * str // valid pointer +) +{ + switch (opt_https) + { + case HTTPS_RESTORE: + case HTTPS_HTTP: + case HTTPS_DOMAIN: + case HTTPS_SAKE0: + case HTTPS_SAKE1: + return PatchHTTPS_HTTP(str,opt_https); + + case HTTPS_NONE: + case HTTPS__N: + break; + } + return 0; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// main.dol support /////////////// +/////////////////////////////////////////////////////////////////////////////// + +void AnalyzeDOL +( + staticr_t * str, // valid pointer + bool restore // true: restore patched data +) +{ + DASSERT(str); + str->dol_status = DOL_S_ANALYZED; + + if (PatchHTTPS_HTTP(str,HTTPS_RESTORE)) + str->dol_status |= DOL_S_HTTPS; + + static str_mode_t tab_mode[] + = { STR_M_PAL, STR_M_USA, STR_M_JAP, STR_M_KOR, STR_M_UNKNOWN }; + + static sha1_hash_t tab_sha1_mode[] = + { + // STR_M_PAL + { 0x12, 0xb0, 0x2a, 0xf1, 0x9e, 0x07, 0xd3, 0x6d, 0x8a, 0x38, + 0xc9, 0xa7, 0xfe, 0x89, 0x15, 0x55, 0x2f, 0x2e, 0x58, 0x5f }, + + // STR_M_USA + { 0x0a, 0xed, 0x61, 0x96, 0x28, 0x11, 0xa1, 0x64, 0xf5, 0x8c, + 0xd7, 0xed, 0xfc, 0x71, 0x6e, 0xeb, 0x05, 0xb8, 0x4d, 0xab }, + + // STR_M_JAP + { 0x69, 0xed, 0xa1, 0xa4, 0x05, 0xde, 0x0e, 0xe1, 0x29, 0x09, + 0x15, 0x4f, 0xd5, 0xdc, 0x2c, 0x33, 0x62, 0x9f, 0x6f, 0x37 }, + + // STR_M_KOR + { 0x86, 0x2a, 0x38, 0xf2, 0xd7, 0x56, 0xe5, 0x96, 0x2c, 0xa1, + 0x9f, 0xd0, 0x62, 0xd0, 0xbd, 0x55, 0x67, 0x10, 0xed, 0x7e }, + }; + + if ( str->data_size < 0x1100 ) + return; + + sha1_hash_t hash; + SHA1(str->data+0x100,0x1000,hash); + + uint i; + for ( i = 0; tab_mode[i] != STR_M_UNKNOWN; i++ ) + { + if (!memcmp(tab_sha1_mode+i,hash,sizeof(hash))) + { + str->is_main = true; + str->mode = tab_mode[i]; + str->dol_status |= DOL_S_KNOWN; + + SHA1(str->data,str->data_size,hash); + const DolSectionMap_t *dsm = FindSectionDOL(str->data_size,hash); + if ( dsm && dsm->mode == str->mode && dsm->dol_stat ) + { + str->dol_status |= dsm->dol_stat; + str->dol_info = dsm->info; + if ( str->dol_status & DOL_S_WIIMMFI ) + str->dol_status &= ~DOL_S_HTTPS; + else if ( str->dol_status & DOL_S_HTTPS ) + str->dol_status &= ~DOL_S_ORIG; + } + break; + } + } + str->dol_info_flags = ( str->dol_info_flags & ~DIF_MODE ) + | ( str->mode - STR_M_PAL & DIF_MODE ); + + + //-- check VBI + + const u32 vbi_addr = GetVbiAddress(str); + if (vbi_addr) + { + dol_header_t *dh = (dol_header_t*)str->data; + const u32 offset = GetDolOffsetByAddr(dh,vbi_addr,4,0); + if (offset) + { + const u32 cur_value = be32(str->data+offset); + if ( cur_value != ORIG_VBI_VALUE ) + { + if (restore) + write_be32(str->data+offset,ORIG_VBI_VALUE); + str->dol_status = str->dol_status & ~DOL_S_ORIG | DOL_S_VBI; + + if ( ( cur_value & 0xff000000 ) == 0x4b000000 ) + { + str->vbi_address = cur_value & 0x00ffffff; + if ( str->vbi_address & 0x00800000 ) + str->vbi_address |= 0xff000000; + str->vbi_address += vbi_addr; + } + } + } + } + + + //-- check patched_by VERSION + + char *id_ptr = GetIdPointer(str); + if (id_ptr) + { + char *id_end = id_ptr + PATCHED_BY_SIZE; + char *end = id_ptr; + while ( end < id_end && (uchar)*end >= ' ' ) + end++; + while ( end > id_ptr && ( end[-1] == '*' || end[-1] == ' ' ) ) + end--; + + memset(str->patched_by,0,sizeof(str->patched_by)); + if ( id_ptr < end ) + memcpy(str->patched_by,id_ptr,end-id_ptr); + if (restore) + memset(id_ptr,'*',PATCHED_BY_SIZE); + } + + + //-- check sdkver VERSION + + const u32 vers_addr = GetSdkverAddress(str->mode); + if (vbi_addr) + { + dol_header_t *dh = (dol_header_t*)str->data; + const u32 offset = GetDolOffsetByAddr(dh,vers_addr,8,0); + if ( offset && memcmp(str->data+offset,ORIG_SDK_VERS,8) ) + { + memcpy(str->sdk_version,str->data+offset,8); + str->dol_status = str->dol_status & ~DOL_S_ORIG | DOL_S_SDKVER; + if (restore) + memcpy(str->data+offset,ORIG_SDK_VERS,8); + } + } + + + //-- check second host + + u32 h2_orig, *h2 = GetSecondHostPointer(str,&h2_orig); + if (h2) + { + if ( ntohl(*h2) == ASM_NOP ) + { + str->dol_status = str->dol_status & ~DOL_S_ORIG | DOL_S_2HOST; + if (restore) + *h2 = htonl(h2_orig); + } + } + + + //-- finish + + if (!str->dol_info_flags_set) + { + str->dol_info_flags_set = true; + if ( str->dol_status & DOL_S_ORIG ) + str->dol_info_flags |= DIF_ORIG; + } +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +void PrintStatusDOL +( + FILE * f, // destination file + int indent, // indention + staticr_t * str, // valid pointer + int long_mode // >0: print more track details if changed +) +{ + indent = NormalizeIndent(indent); + if (!(str->dol_status&DOL_S_ANALYZED)) + AnalyzeDOL(str,true); + + #ifdef TEST + if ( opt_new > 0 ) + { + u32 off1 = GetVbiAddress(str); + u32 off2 = FindDolAddressOfVBI(str->data,str->data_size); + printf("VBI: %08x %c= %08x : %s\n", + off1, off1 == off2 ? '=' : '!', + off2, str->fname ); + } + #endif + + switch (str->mode) + { + case STR_M_PAL: + fprintf(f,"%*sPAL version of main.dol found.\n", indent,"" ); + break; + + case STR_M_USA: + fprintf(f,"%*sNTSC/USA version of main.dol found.\n", indent,"" ); + break; + + case STR_M_JAP: + fprintf(f,"%*sNTSC/JAP version of main.dol found.\n", indent,"" ); + break; + + case STR_M_KOR: + fprintf(f,"%*sNTSC/KOREA version of main.dol found.\n", indent,"" ); + break; + + default: + fprintf(f,"%*sUnknown main.dol found.\n", indent,"" ); + return; + } + + if (str->dol_cleaned) + fprintf(f,"%*s- DOL cleaned before analysis.\n", indent,""); + + if ( str->patched_by[0] ) + fprintf(f,"%*s- Patched by: %s\n", indent,"", str->patched_by ); + + + if ( str->dol_status & DOL_S_HTTPS ) + { + fprintf(f,"%*s- Known 'https://' URLs modified.\n", indent,""); + } + else if (str->dol_info) + { + fprintf(f,"%*s- %s\n", indent,"",str->dol_info); + return; + } + + const dol_header_t *dh = (dol_header_t*)str->data; + if ( str->dol_status & DOL_S_VBI ) + { + if (str->vbi_address) + fprintf(f,"%*s- VBI hook to address 0x%08x%s found.\n", + indent,"", str->vbi_address, + GetDolSectionAddrInfo(dh,str->vbi_address,4) ); + else + fprintf(f,"%*s- VBI hook found.\n", indent,""); + } + + #ifdef HAVE_WIIMM_EXT + if ( str->dol_status & DOL_S_SDKVER ) + fprintf(f,"%*s- Value of 'sdkver' changed from '001000' to '%s'.\n", + indent,"", str->sdk_version ); + #endif + + if ( str->dol_status & DOL_S_2HOST ) + fprintf(f,"%*s- Suppress second 'Host:' header at login.\n", + indent,"" ); + + const dol_sect_info_t *orig = GetInfoDOL(str->mode); + if (orig) + { + uint sect; + for ( sect = 0; sect < DOL_NN_SECTIONS; sect++, orig++ ) + { + dol_sect_info_t info; + GetSectionDOL(str,&info,sect,true); + noPRINT("%-4s: %d,%d : %8x %8x %8x\n", + info.name, info.sect_valid, info.hash_valid, + info.off, info.addr, info.size ); + + if (info.sect_valid) + { + bool find_section = info.hash_valid; + + if (!orig->sect_valid) + fprintf(f,"%*s- Additional section %s.\n", indent,"", orig->name ); + else if ( orig->size != info.size ) + fprintf(f,"%*s- Size of section %s changed.\n", indent,"", orig->name ); + else if ( orig->hash_valid && memcmp(orig->hash,info.hash,sizeof(info.hash))) + fprintf(f,"%*s- Section %s modified.\n", indent,"", orig->name ); + else if ( orig->addr != info.addr ) + { + if ( sect == DOL_IDX_ENTRY ) + fprintf(f,"%*s- Entry point moved from %08x%s to %08x%s.\n", + indent,"", + orig->addr, GetDolSectionAddrInfo(dh,orig->addr,4), + info.addr, GetDolSectionAddrInfo(dh,info.addr,4) ); + else + fprintf(f,"%*s- Section %s moved.\n", indent,"", orig->name ); + } + else + find_section = false; + + if (find_section) + { + const DolSectionMap_t *dsm = FindSectionDOL(info.size,info.hash); + if (dsm) + printf("%*s- %s\n",indent+3,"",dsm->info); + else if (info.data) + { + bool found = false; + if ( info.addr == 0x80001800 && info.size > 0x800 ) + { + if ( be64(info.data+0x11c) == 0x3c6000d06063c0deull ) + { + found = true; + printf("%*s- Gecko Code Handler (Only)\n",indent+3,""); + } + else if ( be64(info.data+0x770) == 0x3c6000d06063c0deull ) + { + ccp attrib = "full"; + const u64 val = be64(info.data+0x56C); + if ( val == 0x92f8680090786810ull ) + attrib = "Slot A"; + else if ( val == 0x92f8681490786824ull ) + attrib = "Slot B"; + printf("%*s- Gecko Code Handler (%s).\n",indent+3,"",attrib); + found = true; + } + } + + if ( !found && info.addr == 0x802c0000 ) + printf("%*s- Maybe code loader by wstrt.\n",indent+3,""); + } + } + } + else if (orig->sect_valid) + fprintf(f,"%*s- Section %s removed.\n", indent,"", orig->name ); + } + } +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// versus points /////////////// +/////////////////////////////////////////////////////////////////////////////// + +uint GetVersusPointsOffset ( str_mode_t mode ) +{ + switch (mode) + { + case STR_M_PAL: return 0x37fd50; + case STR_M_USA: return 0x37fc60; + case STR_M_JAP: return 0x37fa20; + case STR_M_KOR: return 0x380130; + default: return 0; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// [[VersusPointsInfo]] + +const VersusPointsInfo_t VersusPointsInfo[STR_M__N] = +{ + { STR_M_UNKNOWN, '0', 0, 0 }, + { STR_M_PAL, 'P', 0x37fd50, 0x06890030 }, + { STR_M_USA, 'E', 0x37fc60, 0x0688bbc0 }, + { STR_M_JAP, 'J', 0x37fa20, 0x0688f680 }, + { STR_M_KOR, 'K', 0x380130, 0x0687e430 }, +}; + +/////////////////////////////////////////////////////////////////////////////// + +str_mode_t opt_cheat_region = STR_M_UNKNOWN; + +int ScanOptCheatRegion ( ccp arg ) +{ + if ( !arg || !*arg ) + { + opt_cheat_region = STR_M_UNKNOWN; + return 0; + } + + static const KeywordTab_t tab[] = + { + { STR_M_PAL, "EUROPE", "PAL", 0 }, + { STR_M_PAL, "AUSTRALIA", "OCEANIA", 0 }, + { STR_M_USA, "AMERICA", "NTSC", 0 }, + { STR_M_JAP, "JAPAN", 0, 0 }, + { STR_M_KOR, "KOREA", 0, 0 }, + { 0,0,0,0 } + }; + + const KeywordTab_t * cmd = ScanKeyword(0,arg,tab); + if (cmd) + { + opt_cheat_region = cmd->id; + return 0; + } + + ERROR0(ERR_SYNTAX,"Invalid cheat region (option --cheat): '%s'\n",arg); + return 1; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// analyze helpers /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static void AnalyzeTracks +( + staticr_t * str, // valid pointer + u8 * data, // data to analyze and modify + const u32 * offset_tab, // null terminated table with offsets + const u32 * ref_tab, // reference table + uint base_index, // base index of first track + uint n, // number of values in 'ref_tab' + int base_status // base status bit +) +{ + DASSERT(str); + DASSERT(data); + DASSERT(offset_tab); + DASSERT(ref_tab); + DASSERT(n>0); + DASSERT(n<=32); + + const uint cmp_size = n * sizeof(u32); + + uint i; + u32 be_ref[32]; + for ( i = 0; i < n; i++ ) + write_be32( be_ref + i, base_index + ref_tab[i] ); + TRACE_HEXDUMP16(0,0,be_ref,cmp_size); //putchar('\n'); + + uint ok_count = 0; // number of unmodified records + uint mod_count = 0; // number of modified records + + u8 *first = 0; + const u32 *off_ptr; + for ( off_ptr = offset_tab ; *off_ptr; off_ptr++ ) + { + DASSERT( *off_ptr < str->data_size ); + u8 * d = data + *off_ptr; + if (!memcmp(d,be_ref,cmp_size)) + { + ok_count++; + continue; + } + mod_count++; + + if (!first) + first = d; + else if (memcmp(first,d,cmp_size)) + str->str_status |= base_status << STR_S_SHIFT_ORDER_DIFF; + + uint fail_buf[32]; + memset(fail_buf,0,sizeof(fail_buf)); + for ( i = 0; i < n; i++ ) + { + const u32 idx = be32(d+4*i) - base_index; + if ( idx >= n ) + { + str->str_status |= base_status << STR_S_SHIFT_ORDER_DIFF; + break; + } + if ( fail_buf[idx] ) + { + str->str_status |= base_status << STR_S_SHIFT_ORDER_MULTI; + break; + } + fail_buf[idx]++; + } + if ( i == n ) + str->str_status |= base_status << STR_S_SHIFT_ORDER_ALT; + + TRACE_HEXDUMP16(0,*off_ptr,d,cmp_size); //putchar('\n'); + } + + if ( mod_count && ok_count ) + str->str_status |= base_status << STR_S_SHIFT_ORDER_DIFF; + + + //--- normalize + + for ( off_ptr = offset_tab ; *off_ptr; off_ptr++ ) + { + DASSERT( *off_ptr < str->data_size ); + u8 * d = data + *off_ptr; + memcpy(d,be_ref,cmp_size); + } +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +static void AnalyzeRegion +( + staticr_t * str, // valid pointer + u8 * data // data to analyze and modify +) +{ + DASSERT(str); + DASSERT(data); + + bool is_battle; + for ( is_battle = false; is_battle <= true; is_battle++ ) + { + region_info_t ri; + SetupRegionInfo(&ri,str,is_battle); + + uint ok_stat = ri.flag_known; + + const uint offset_idx = str->mode - STR_ZBI_FIRST; + memset(ri.region,0,MAX_REGION_PATCH*sizeof(*ri.region)); + uint idx, patch_count = 0, unknown_count = 0; + + for ( idx = 0; idx < ri.max_patch; idx++ ) + { + ri.region[idx] = -1; + const region_patch_t *rp = ri.patch_tab + idx; + if (!rp->orig) + break; + + u8 *focus = data + rp->offset[offset_idx]; + u32 val = be32(focus); + if ( val != rp->orig ) + { + patch_count++; + if ( ( val & 0xffff0000 ) == rp->patch ) + { + ri.region[idx] = (u16)val; + if ( ri.region[idx] != ri.region[0] ) + ok_stat = ri.flag_differ; + } + else + unknown_count++; + write_be32(focus,rp->orig); + } + } + + if (unknown_count) + str->str_status |= ri.flag_unknown; + else if (patch_count) + str->str_status |= ok_stat; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +static void AnalyzeAllRanks +( + staticr_t * str, // valid pointer + u8 * data, // data to analyze and modify + const u32 * offset_tab // null terminated table with offsets +) +{ + DASSERT(str); + DASSERT(data); + DASSERT(offset_tab); + + uint i, patch_count = 0, known_count = 0; + for ( i = 0; offset_tab[i]; i++ ) + { + u8 *d = data + offset_tab[i]; + if (memcmp(d,all_ranks_orig,all_ranks_size)) + { + patch_count++; + if ( memcmp(d,all_ranks_patch1,all_ranks_size) + || memcmp(d,all_ranks_patch2,all_ranks_size)) + { + known_count++; + } + memcpy(d,all_ranks_orig,all_ranks_size); + } + } + + if ( i == known_count ) + { + str->str_status |= STR_S_ALL_RANKS_KNOWN; + } + else if ( patch_count ) + str->str_status |= STR_S_ALL_RANKS_UNKNOWN; +} + +/////////////////////////////////////////////////////////////////////////////// + +static void AnalyzeVsBt +( + staticr_t * str, // valid pointer + u8 * data, // data to analyze and modify + const u32 * offset_tab, // null terminated table with offsets + ccp name, // 'vs' or 'bt' + uint flag // flag to set +) +{ + DASSERT(str); + DASSERT(data); + DASSERT(offset_tab); + + uint i; + for ( i = 0; offset_tab[i]; i++ ) + { + u8 *d = data + offset_tab[i]; + if (strncmp((ccp)d,name,3)) + { + str->str_status |= flag; + memcpy(d,name,2); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +static void AnalyzeVersusPoints +( + staticr_t * str, // valid pointer + u8 * data // data to analyze and modify +) +{ + DASSERT(str); + DASSERT(data); + + const u32 offset = GetVersusPointsOffset(str->mode); + if (offset) + { + data += offset; + if (memcmp(data,MkwPointsTab_NINTENDO,12*12)) + { + str->str_status |= STR_S_VERSUS_POINTS; + memcpy(data,MkwPointsTab_NINTENDO,12*12); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +static void AnalyzeCannon +( + staticr_t * str, // valid pointer + u8 * data // data to analyze and modify +) +{ + DASSERT(str); + DASSERT(data); + + const u32 off = GetCannonOffset(str); + if ( off && !(str->str_status&STR_S_CANNON) ) + { + memcpy(str->cannon_data,data+off,sizeof(str->cannon_data)); + if (memcmp(data+off,CannonDataLEX+4,sizeof(CannonDataLEX)-4)) + { + str->str_status |= STR_S_CANNON; + memcpy(data+off,CannonDataLEX+4,sizeof(CannonDataLEX)-4); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +static void AnalyzeMenO +( + staticr_t * str, // valid pointer + u8 * data // data to analyze and modify +) +{ + DASSERT(str); + DASSERT(data); + + const u32 *optr = GetMenuOffsetTab(str->mode); + if (optr) + { + uint count = 0, total = 0; + const int *idx; + for ( idx = meno_patch_idx; *idx >= 0; idx++ ) + { + total++; + u8 *d = data + optr[*idx] + 13; // 13 = 'O' offset + if ( *d == 'O' ) + { + *d = 'u'; + count++; + } + } + + if ( total == count ) + str->str_status |= STR_S_MENO; + } +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// analyze staticr /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static void AnalyzePAL +( + staticr_t * str // valid pointer +) +{ + DASSERT(str); + + + //--- first hash test + + static const u8 good_hash[20] = + { + 0x88,0x7b,0xcc,0x07,0x67, 0x81,0xf5,0xb0,0x05,0xcc, + 0x31,0x7a,0x6e,0x3c,0xc8, 0xfd,0x5f,0x91,0x13,0x00 + }; + + sha1_hash_t hash; + SHA1(str->data,str->data_size,hash); + if (!memcmp(hash,good_hash,sizeof(hash))) + { + if (!( str->str_status & STR_S_HTTPS )) + str->str_status |= STR_S_ORIG; + #ifndef TEST + return; + #endif + } + + + //--- create a copy + + u8 * data = MALLOC(str->data_size); + memcpy(data,str->data,str->data_size); + + + //--- ctgp 4.4 tests + + static const u32 ctgp44[] = + { + // addr orig value ctgp value + //------------------------------- + 0x3d22b8, 0x00000db4, 0xff750030, + 0x3d22c8, 0x00000db4, 0xff750030, + 0x40df78, 0x00012660, 0xff7742e0, + 0x40df88, 0x00012660, 0xff7742e0, + 0,0,0 + }; + + const u32 * ptr; + uint orig_failed = 0, ctgp_failed = 0; + for ( ptr = ctgp44; *ptr; ptr += 3 ) + { + DASSERT( *ptr + 4 <= str->data_size ); + const u32 val = be32( str->data + *ptr ); + if ( val != ptr[1] ) orig_failed++; + if ( val != ptr[2] ) ctgp_failed++; + write_be32( data + *ptr, ptr[1] ); + } + + if (orig_failed) + { + str->str_status |= STR_S_CTGP44_LIKE; + if (!ctgp_failed) + str->str_status |= STR_S_CTGP44; + } + + + //--- analyse tracks and arenas + + AnalyzeTracks( str, data, pal_track_offset, track_pos_default, + MKW_TRACK_BEG, MKW_N_TRACKS, STR_S_TRACK_ORDER ); + AnalyzeTracks( str, data, pal_arena_offset, arena_pos_default, + MKW_ARENA_BEG, MKW_N_ARENAS, STR_S_ARENA_ORDER ); + + + //--- analyse misc + + AnalyzeRegion(str,data); + AnalyzeAllRanks(str,data,pal_all_ranks_offset); + AnalyzeVsBt(str,data,pal_vs_offset,"vs",STR_S_VS); + AnalyzeVsBt(str,data,pal_bt_offset,"bt",STR_S_BT); + AnalyzeVersusPoints(str,data); + AnalyzeCannon(str,data); + AnalyzeMenO(str,data); + + + //--- last hash test + + SHA1(data,str->data_size,hash); + if (memcmp(hash,good_hash,sizeof(hash))) + str->str_status |= STR_S_UNKNOWN_PATCH; + + + //--- clean + + FREE(data); +} + +/////////////////////////////////////////////////////////////////////////////// + +static void AnalyzeUSA +( + staticr_t * str // valid pointer +) +{ + DASSERT(str); + + //--- first hash test + + static const u8 good_hash[20] = + { + 0x07,0x2b,0xa4,0x43,0x82, 0xfd,0xca,0x9b,0xf5,0xc0, + 0xec,0x9d,0x1e,0x9b,0x92, 0x2c,0xaf,0xd9,0x92,0x60 + }; + + sha1_hash_t hash; + SHA1(str->data,str->data_size,hash); + if (!memcmp(hash,good_hash,sizeof(hash))) + { + str->str_status |= STR_S_ORIG; + #ifndef TEST + return; + #endif + } + + + //--- create a copy + + u8 * data = MALLOC(str->data_size); + memcpy(data,str->data,str->data_size); + + + //--- ctgp 4.4 tests + + static const u32 ctgp44[] = + { + // addr orig value ctgp value + //------------------------------- + 0x3d1c38, 0x00000c14, 0xff7546e0, + 0x3d1c48, 0x00000c14, 0xff7546e0, + 0x40cda0, 0x00012098, 0xff778720, + 0x40cdb0, 0x00012098, 0xff778720, + 0,0,0 + }; + + const u32 * ptr; + uint orig_failed = 0, ctgp_failed = 0; + for ( ptr = ctgp44; *ptr; ptr += 3 ) + { + DASSERT( *ptr + 4 <= str->data_size ); + const u32 val = be32( str->data + *ptr ); + if ( val != ptr[1] ) orig_failed++; + if ( val != ptr[2] ) ctgp_failed++; + write_be32( data + *ptr, ptr[1] ); + } + + if (orig_failed) + { + str->str_status |= STR_S_CTGP44_LIKE; + if (!ctgp_failed) + str->str_status |= STR_S_CTGP44; + } + + + //--- anlyze tracks and arenas + + AnalyzeTracks( str, data, usa_track_offset, track_pos_default, + MKW_TRACK_BEG, MKW_N_TRACKS, STR_S_TRACK_ORDER ); + AnalyzeTracks( str, data, usa_arena_offset, arena_pos_default, + MKW_ARENA_BEG, MKW_N_ARENAS, STR_S_ARENA_ORDER ); + + + //--- analyse misc + + AnalyzeRegion(str,data); + AnalyzeAllRanks(str,data,usa_all_ranks_offset); + AnalyzeVsBt(str,data,usa_vs_offset,"vs",STR_S_VS); + AnalyzeVsBt(str,data,usa_bt_offset,"bt",STR_S_BT); + AnalyzeVersusPoints(str,data); + AnalyzeMenO(str,data); + + + //--- last hash test + + SHA1(data,str->data_size,hash); + if (memcmp(hash,good_hash,sizeof(hash))) + str->str_status |= STR_S_UNKNOWN_PATCH; + + + //--- clean + + FREE(data); +} + +/////////////////////////////////////////////////////////////////////////////// + +static void AnalyzeJAP +( + staticr_t * str // valid pointer +) +{ + DASSERT(str); + + //--- first hash test + + static const u8 good_hash[20] = + { + 0x20,0xb4,0x16,0x1d,0x41, 0x5e,0x40,0x92,0xa6,0x29, + 0x9b,0xb2,0x85,0xfa,0xa6, 0x22,0x83,0x5b,0x2b,0x16 + }; + + sha1_hash_t hash; + SHA1(str->data,str->data_size,hash); + if (!memcmp(hash,good_hash,sizeof(hash))) + { + str->str_status |= STR_S_ORIG; + #ifndef TEST + return; + #endif + } + + + //--- create a copy + + u8 * data = MALLOC(str->data_size); + memcpy(data,str->data,str->data_size); + + + //--- anlyze tracks and arenas + + AnalyzeTracks( str, data, jap_track_offset, track_pos_default, + MKW_TRACK_BEG, MKW_N_TRACKS, STR_S_TRACK_ORDER ); + AnalyzeTracks( str, data, jap_arena_offset, arena_pos_default, + MKW_ARENA_BEG, MKW_N_ARENAS, STR_S_ARENA_ORDER ); + + + //--- analyse misc + + AnalyzeRegion(str,data); + AnalyzeAllRanks(str,data,jap_all_ranks_offset); + AnalyzeVsBt(str,data,jap_vs_offset,"vs",STR_S_VS); + AnalyzeVsBt(str,data,jap_bt_offset,"bt",STR_S_BT); + AnalyzeVersusPoints(str,data); + AnalyzeMenO(str,data); + + + //--- last hash test + + SHA1(data,str->data_size,hash); + if (memcmp(hash,good_hash,sizeof(hash))) + str->str_status |= STR_S_UNKNOWN_PATCH; + + + //--- clean + + FREE(data); +} + +/////////////////////////////////////////////////////////////////////////////// + +static void AnalyzeKOR +( + staticr_t * str // valid pointer +) +{ + DASSERT(str); + + //--- first hash test + + static const u8 good_hash[20] = + { + 0xe0,0x00,0x62,0x50,0xb1, 0xe5,0xc1,0xbd,0xee,0x8b, + 0xdb,0x0e,0x78,0x9e,0xa2, 0x00,0xb3,0xa8,0x46,0xe4 + }; + + sha1_hash_t hash; + SHA1(str->data,str->data_size,hash); + if (!memcmp(hash,good_hash,sizeof(hash))) + { + str->str_status |= STR_S_ORIG; + #ifndef TEST + return; + #endif + } + + + //--- create a copy + + u8 * data = MALLOC(str->data_size); + memcpy(data,str->data,str->data_size); + + + //--- anlyze tracks and arenas + + AnalyzeTracks( str, data, kor_track_offset, track_pos_default, + MKW_TRACK_BEG, MKW_N_TRACKS, STR_S_TRACK_ORDER ); + AnalyzeTracks( str, data, kor_arena_offset, arena_pos_default, + MKW_ARENA_BEG, MKW_N_ARENAS, STR_S_ARENA_ORDER ); + + + //--- analyse misc + + AnalyzeRegion(str,data); + AnalyzeAllRanks(str,data,kor_all_ranks_offset); + AnalyzeVsBt(str,data,kor_vs_offset,"vs",STR_S_VS); + AnalyzeVsBt(str,data,kor_bt_offset,"bt",STR_S_BT); + AnalyzeVersusPoints(str,data); + AnalyzeMenO(str,data); + + + //--- last hash test + + SHA1(data,str->data_size,hash); + if (memcmp(hash,good_hash,sizeof(hash))) + str->str_status |= STR_S_UNKNOWN_PATCH; + + + //--- clean + + FREE(data); +} + +/////////////////////////////////////////////////////////////////////////////// + +void AnalyzeSTR +( + staticr_t * str // valid pointer +) +{ + DASSERT(str); + + if (str->is_dol) + { + if (!(str->dol_status&DOL_S_ANALYZED)) + AnalyzeDOL(str,true); + return; + } + + if (!CheckSizeSTR(str)) + return; + + str->str_status = STR_S_ANALYZED; + if (PatchHTTPS_HTTP(str,HTTPS_RESTORE)) + str->str_status |= STR_S_HTTPS; + + switch (str->mode) + { + case STR_M_PAL: + AnalyzePAL(str); + break; + + case STR_M_USA: + AnalyzeUSA(str); + break; + + case STR_M_JAP: + AnalyzeJAP(str); + break; + + case STR_M_KOR: + AnalyzeKOR(str); + break; + + default: + break; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +static void PrintStatusRegion +( + FILE * f, // destination file + int indent, // indention + staticr_t * str, // valid pointer + bool is_battle, // true: is battle + int long_mode // >0: print more track details if changed +) +{ + DASSERT(f); + DASSERT(str); + + region_info_t ri; + SetupRegionInfo(&ri,str,is_battle); + + if ( long_mode > 1 + || long_mode > 0 && str->str_status & (ri.flag_unknown|ri.flag_differ) ) + { + fprintf(f,"%*s- %c%s region settings:\n", + indent,"", toupper((int)ri.name[0]), ri.name+1 ); + + const region_patch_t *rp; + for ( rp = ri.patch_tab; rp->orig; rp++ ) + { + const uint offset = rp->offset[str->mode - STR_ZBI_FIRST]; + const u8 *d = str->data + offset; + fprintf(f,"%*s%9x: %02x %02x %02x %02x : ", + indent,"", offset, d[0], d[1], d[2], d[3] ); + const u32 val = be32(d); + if ( val == rp->orig ) + fprintf(f,"%-23s : %s\n","not patched",rp->info); + else if ( (val & 0xffff0000) == rp->patch ) + fprintf(f,"region %4x/hex = %5u : %s\n", + val&0xffff, val&0xffff, rp->info ); + else + fprintf(f,"%-23s : %s\n","unknown patch",rp->info); + } + } + else if ( str->str_status & ri.flag_differ ) + { + fprintf(f,"%*s- Known %s region patch found, regions = ", indent,"", ri.name ); + ccp sep = ""; + uint i; + for ( i = 0; i < ri.max_patch; i++ ) + { + if ( ri.region[i] < 0 ) + fprintf(f,"%sunpatched",sep); + else + fprintf(f,"%s%#x=%u",sep,ri.region[i],ri.region[i]); + sep = ", "; + } + fputc('\n',f); + } + else if ( str->str_status & ri.flag_known ) + fprintf(f,"%*s- Known %s region patch found, region = 0x%02x = %u\n", + indent,"", ri.name, ri.region[0], ri.region[0] ); + else if ( str->str_status & ri.flag_unknown ) + fprintf(f,"%*s- Unknown %s region patch found.\n", indent,"", ri.name ); +} + +/////////////////////////////////////////////////////////////////////////////// + +void PrintStatusSTR +( + FILE * f, // destination file + int indent, // indention + staticr_t * str, // valid pointer + int long_mode // >0: print more track details if changed +) +{ + DASSERT(f); + DASSERT(str); + + if (str->is_dol) + { + PrintStatusDOL(f,indent,str,long_mode); + return; + } + + indent = NormalizeIndent(indent); + if (!(str->str_status&STR_S_ANALYZED)) + AnalyzeSTR(str); + + switch (str->mode) + { + case STR_M_PAL: + fprintf(f,"%*sPAL version of StaticR found.\n", indent,"" ); + break; + + case STR_M_USA: + fprintf(f,"%*sNTSC/USA version of StaticR found.\n", indent,"" ); + break; + + case STR_M_JAP: + fprintf(f,"%*sNTSC/JAP version of StaticR found.\n", indent,"" ); + break; + + case STR_M_KOR: + fprintf(f,"%*sNTSC/KOREA version of StaticR found.\n", indent,"" ); + break; + + default: + fprintf(f,"%*sNo StaticR found.\n", indent,"" ); + break; + } + + const str_status_t st = str->str_status; + + if ( st & STR_S_WRONG_SIZE ) + fprintf(f,"%*s- Wrong file size.\n", indent,"" ); + + if ( st & STR_S_ORIG ) + fprintf(f,"%*s- Original file.\n", indent,"" ); + + if ( st & STR_S_HTTPS ) + fprintf(f,"%*s- Known 'https://' URLs modified.\n", indent,"" ); + + if ( st & STR_S_TRACK_ORDER_ALT ) + fprintf(f,"%*s- Valid alternative track order detected.\n", indent,"" ); + if ( st & STR_S_TRACK_ORDER_MULTI ) + fprintf(f,"%*s- Multiple usage of singe track detected.\n", indent,"" ); + if ( st & STR_S_TRACK_ORDER_BAD ) + fprintf(f,"%*s- Bad track index detected.\n", indent,"" ); + if ( st & STR_S_TRACK_ORDER_DIFF ) + fprintf(f,"%*s- Different track orders detected.\n", indent,"" ); + + if ( long_mode > 1 || long_mode > 0 && st & STR_S_TRACK_ORDER__FAIL ) + { + fprintf(f,"%*s- Track assigning tables:\n", indent,"" ); + const u32 *tab = GetTrackOffsetTab(str); + DASSERT(tab); + for(;;) + { + u32 offset = *tab++; + if (!offset) + break; + fprintf(f,"%*s%9x:", indent,"", offset ); + const u32 * d = (u32*)( str->data + offset ); + uint i; + for ( i = 0; i < MKW_N_TRACKS; i++ ) + { + if (!(i%4)) + fputc(' ',f); + fprintf(f,"%u%c", be32(d++), i == MKW_N_TRACKS-1 ? '\n' : ',' ); + } + } + } + + if ( st & STR_S_ARENA_ORDER_ALT ) + fprintf(f,"%*s- Valid alternative arena order detected.\n", indent,"" ); + if ( st & STR_S_ARENA_ORDER_MULTI ) + fprintf(f,"%*s- Multiple usage of singe arena detected.\n", indent,"" ); + if ( st & STR_S_ARENA_ORDER_BAD ) + fprintf(f,"%*s- Bad arena index detected.\n", indent,"" ); + if ( st & STR_S_ARENA_ORDER_DIFF ) + fprintf(f,"%*s- Different arena orders detected.\n", indent,"" ); + + if ( long_mode > 1 || long_mode > 0 && st & STR_S_ARENA_ORDER__FAIL ) + { + fprintf(f,"%*s- Arena assigning tables:\n", indent,"" ); + const u32 *tab = GetArenaOffsetTab(str); + DASSERT(tab); + for(;;) + { + u32 offset = *tab++; + if (!offset) + break; + fprintf(f,"%*s%9x:", indent,"", offset ); + const u32 * d = (u32*)( str->data + offset ); + uint i; + for ( i = 0; i < MKW_N_ARENAS; i++ ) + { + if (!(i%5)) + fputc(' ',f); + fprintf(f,"%u%c", be32(d++), i == MKW_N_ARENAS-1 ? '\n' : ',' ); + } + } + } + + if ( st & STR_S_CTGP44 ) + fprintf(f,"%*s- CTGP 4.4 modification found.\n", indent,"" ); + else if ( st & STR_S_CTGP44_LIKE ) + fprintf(f,"%*s- CTGP 4.4 like modification found.\n", indent,"" ); + + PrintStatusRegion( f, indent, str, false, long_mode ); + PrintStatusRegion( f, indent, str, true, long_mode ); + + if ( st & STR_S_ALL_RANKS_KNOWN ) + fprintf(f,"%*s- Known 'all ranks' patch found.\n", + indent,"" ); + else if ( st & STR_S_ALL_RANKS_UNKNOWN ) + fprintf(f,"%*s- Unknown 'all ranks' patch found.\n", indent,"" ); + + if ( st & STR_S_VS ) + { + fprintf(f,"%*s- Versus identification ('vs') patched:",indent,""); + const u32 *ptr; + for ( ptr = GetVsBtOffsetTab(str,false); *ptr; ptr++ ) + fprintf(f," %.2s",str->data+*ptr); + fputc('\n',f); + } + + if ( st & STR_S_BT ) + { + fprintf(f,"%*s- Battle identification ('bt') patched:",indent,""); + const u32 *ptr; + for ( ptr = GetVsBtOffsetTab(str,true); *ptr; ptr++ ) + fprintf(f," %.2s",str->data+*ptr); + fputc('\n',f); + } + + if ( st & STR_S_VERSUS_POINTS ) + { + const u32 offset = GetVersusPointsOffset(str->mode); + fprintf(f,"%*s- Versus points modified to '%s'.\n", + indent,"", GetMkwPointInfo(str->data+offset)->info ); + } + + if ( st & STR_S_CANNON ) + { + fprintf(f,"%*s- Cannon parameters modified.\n", indent,"" ); + const u8 *orig = CannonDataLEX+4; + const u8 *data = str->cannon_data; + int idx; + for ( idx = 0; orig < CannonDataLEX + sizeof(CannonDataLEX); + idx++, orig += CANNON_SIZE, data += CANNON_SIZE ) + { + if (memcmp(orig,data,CANNON_SIZE)) + { + printf("%*s > Cannon %u orig: %12.4f %12.4f %12.4f %12.4f\n", + indent,"", + idx, bef4(orig), bef4(orig+4), bef4(orig+8), bef4(orig+12) ); + printf("%*s Cannon %u data: %12.4f %12.4f %12.4f %12.4f\n", + indent,"", + idx, bef4(data), bef4(data+4), bef4(data+8), bef4(data+12) ); + } + } + } + + if ( st & STR_S_MENO ) + fprintf(f,"%*s- Known 'MenO' patches found.\n", indent,"" ); + + if ( st & STR_S_UNKNOWN_PATCH ) + fprintf(f,"%*s- Unknown patches found.\n", indent,"" ); +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// PatchSTR() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static uint PatchTracks +( + staticr_t * str, // valid pointer + const u32 * offset_tab, // null terminated table with offsets + const u32 * track_tab, // table with track indexes + uint base_index, // base index of first track + uint n // number of values in 'ref_tab' +) +{ + DASSERT(str); + DASSERT(offset_tab); + DASSERT(track_tab); + DASSERT(n>0); + DASSERT(n<=32); + + uint count = 0; + const uint copy_size = n * sizeof(u32); + + uint i; + u32 be_data[32]; + for ( i = 0; i < n; i++ ) + write_be32( be_data + i, base_index + track_tab[i] ); + TRACE_HEXDUMP16(0,0,be_data,copy_size); + + for ( ; *offset_tab; offset_tab++ ) + { + DASSERT( *offset_tab < str->data_size ); + u8 * d = str->data + *offset_tab; + if (memcmp(d,be_data,copy_size)) + { + count++; + memcpy(d,be_data,copy_size); + } + } + + return count; +} + +/////////////////////////////////////////////////////////////////////////////// + +static uint PatchVsBt +( + staticr_t *str, // valid pointer + bool is_bt, // false: VS, true: BT + enum VsBtMode mode, // mode + ccp patch // string to set +) +{ + DASSERT(str); + DASSERT(str); + + uint count = 0; + const u32 *tab = GetVsBtOffsetTab(str,is_bt); + switch (mode) + { + case VSBT_OFF: + break; + + case VSBT_PATCH: + while (*tab) + { + u8 *d = str->data + *tab++; + if ( d[0] != patch[0] || d[1] != patch[1] ) + { + *d++ = patch[0]; + *d = patch[1]; + count++; + } + } + break; + + case VSBT_TEST: + { + char c0 = is_bt ? 'b' : 'v'; + char c1 = '1'; + while (*tab) + { + u8 *d = str->data + *tab++; + if ( d[0] != c0 || d[1] != c1 ) + { + *d++ = c0; + *d = c1; + count++; + } + c1++; + } + } + break; + } + + return count; +} + +/////////////////////////////////////////////////////////////////////////////// +#if 0 // region specific patch functions not needed yet +/////////////////////////////////////////////////////////////////////////////// + +static uint PatchPAL +( + // returns: number of patches + + staticr_t * str // valid pointer +) +{ + DASSERT(str); + DASSERT(str->data); + DASSERT(str->data_size); + DASSERT( str->mode == STR_M_PAL ); + + uint count = 0; + + return count; +} + +/////////////////////////////////////////////////////////////////////////////// + +static uint PatchUSA +( + // returns: number of patches + + staticr_t * str // valid pointer +) +{ + DASSERT(str); + DASSERT(str->data); + DASSERT(str->data_size); + DASSERT( str->mode == STR_M_USA ); + + uint count = 0; + + return count; +} + +/////////////////////////////////////////////////////////////////////////////// + +static uint PatchJAP +( + // returns: number of patches + + staticr_t * str // valid pointer +) +{ + DASSERT(str); + DASSERT(str->data); + DASSERT(str->data_size); + DASSERT( str->mode == STR_M_JAP ); + + uint count = 0; + + return count; +} + +/////////////////////////////////////////////////////////////////////////////// + +static uint PatchKOR +( + // returns: number of patches + + staticr_t * str // valid pointer +) +{ + DASSERT(str); + DASSERT(str->data); + DASSERT(str->data_size); + DASSERT( str->mode == STR_M_KOR ); + + uint count = 0; + + return count; +} + +/////////////////////////////////////////////////////////////////////////////// +#endif // region specific patch functions not needed yet +/////////////////////////////////////////////////////////////////////////////// + +static uint PatchRegion +( + staticr_t * str, // valid pointer + bool is_battle // true: is battle +) +{ + DASSERT(str); + region_info_t ri; + SetupRegionInfo(&ri,str,is_battle); + + uint count = 0; + u8 temp[20]; + + DASSERT(ri.opt_region); + if ( *ri.opt_region == SREG_RESTORE ) + { + const region_patch_t *rp; + for ( rp = ri.patch_tab; rp->orig; rp++ ) + { + if ( rp->patch_mode & RPAT_TEST && !*ri.opt_x ) + continue; + + write_be32(temp,rp->orig); + u8 *d = str->data + rp->offset[str->mode - STR_ZBI_FIRST]; + if (memcmp(d,temp,4)) + { + memcpy(d,temp,4); + count++; + } + } + } + else if ( *ri.opt_region >= 0 ) + { + uint val = *ri.opt_region & 0xffff; + uint add = *ri.opt_t; + + const region_patch_t *rp; + for ( rp = ri.patch_tab; rp->orig; rp++ ) + { + if ( rp->patch_mode & RPAT_TEST && !*ri.opt_x ) + continue; + + write_be32( temp, rp->patch | ( rp->patch_mode & RPAT_FF ? val & 0xff : val ) ); + val += add; + u8 *d = str->data + rp->offset[str->mode - STR_ZBI_FIRST]; + if (memcmp(d,temp,4)) + { + memcpy(d,temp,4); + count++; + } + } + } + + return count; +} + +/////////////////////////////////////////////////////////////////////////////// + +uint PatchSTR +( + // returns: number of patches + + staticr_t * str // valid pointer +) +{ + DASSERT(str); + if (!str->data_size) + return 0; + DASSERT(str->data); + + if (str->is_dol) + return PatchDOL(str); + + if (!CheckSizeSTR(str)) + return 0; + + uint count = 0; + + + //--- patch tracks and arenas + + if (opt_tracks) + { + const u32 *tab = GetTrackOffsetTab(str); + if (tab) + count += PatchTracks( str, tab, track_pos, MKW_TRACK_BEG, MKW_N_TRACKS ); + } + + if (opt_arenas) + { + const u32 *tab = GetArenaOffsetTab(str); + if (tab) + count += PatchTracks( str, tab, arena_pos, MKW_ARENA_BEG, MKW_N_ARENAS ); + } + + + //--- patch region + + count += PatchRegion(str,false); + count += PatchRegion(str,true); + + + //--- patch all-ranks + + if ( opt_all_ranks ) + { + ccp p1, p2; + if ( opt_all_ranks < 0 ) + p1 = p2 = all_ranks_orig; + else + { + p1 = all_ranks_patch1; + p2 = all_ranks_patch2; + } + + const u32 *tab = GetAllRanksOffsetTab(str); + if (tab) + { + while (*tab) + { + u8 *d = str->data + *tab++; + if (memcmp(d,p1,all_ranks_size)) + { + memcpy(d,p1,all_ranks_size); + count++; + ccp temp = p1; + p1 = p2; + p2 = temp; + } + } + } + } + + + //--- patch vs & bt + + count += PatchVsBt(str,false,patch_vs_mode,patch_vs_str); + count += PatchVsBt(str,true, patch_bt_mode,patch_bt_str); + + + //--- patch versus points + + if (opt_points_used) + { + const u32 offset = GetVersusPointsOffset(str->mode); + if (offset) + { + u8 *data = str->data + offset; + if (memcmp(data,MkwPointsTab,12*12)) + { + count++; + memcpy(data,MkwPointsTab,12*12); + } + } + } + + + //--- patch cannon params + + u32 offset = GetCannonOffset(str); + if (offset) + { + u8 *data = str->data + offset; + uint i; + for ( i = 0; i < CANNON_N; i++ ) + { + const cannon_param_t *cp = cannon_param+i; + if (cp->valid) + { + uint j; + for ( j = 0; j < CANNON_N_PARAM; j++, data += sizeof(float) ) + write_bef4(data,cp->param[j]); + } + else + data += CANNON_SIZE; + } + } + + + //-- patch 'Menu*' -> 'MenO*' + + if ( opt_meno ) + { + const u32 *optr = GetMenuOffsetTab(str->mode); + if (optr) + { + const int *idx; + for ( idx = meno_patch_idx; *idx >= 0; idx++ ) + { + u8 *d = str->data + optr[*idx] + 13; // 13 = 'O' offset + if ( *d != 'O' ) + { + *d = 'O'; + count++; + } + } + } + } + + + //--- patch https + + count += PatchHTTPS(str); + + + #if 0 // region specific patch functions not needed yet + + //--- patch version specific + + str->str_status = STR_S_ANALYZED; + switch (str->mode) + { + case STR_M_PAL: + count += PatchPAL(str); + break; + + case STR_M_USA: + count += PatchUSA(str); + break; + + case STR_M_JAP: + count += PatchJAP(str); + break; + + case STR_M_KOR: + count += PatchKOR(str); + break; + + default: + break; + } + #endif + + return count + PatchByListWPF(str); +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// CleanDOL() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static bool CleanDol ( staticr_t * str ) // return TRUE if dol data modified. +{ + AnalyzeDOL(str,true); + if ( str->dol_status & DOL_S_ORIG ) + { + str->dol_status = 0; + return 0; + } + + uint sect_list; + dol_header_t *dol_head = (dol_header_t*)str->data; + + uint new_size = RemoveDolSections(dol_head,0x7f83,§_list,logging>2?stdlog:0); + bool stat = new_size > 0; + noPRINT("SIZE: %x -> %x / sect=%x\n",str->data_size,new_size,sect_list); + if (stat) + str->data_size = new_size; + + + //--- fix entry point + + const dol_sect_info_t *orig = GetInfoDOL(str->mode); + DASSERT(orig); + if ( orig[DOL_IDX_ENTRY].addr != ntohl(dol_head->entry_addr) ) + { + stat = true; + dol_head->entry_addr = htonl(orig[DOL_IDX_ENTRY].addr); + } + + + //--- restore HTTPS links + + PatchHTTPS_HTTP(str,HTTPS_RESTORE); + + + //--- terminate + + str->dol_status = 0; + str->dol_cleaned = true; + return stat; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// PatchDOL() /////////////// +/////////////////////////////////////////////////////////////////////////////// +// GCH support + +#define GCT_ADDRESS 0x80001800u +#define GCT_MAX 0x80003000u +#define GCT_MM_BASE (GCT_ADDRESS-sizeof(gch_header_t)) + +static MemMap_t gct_data_mem = {0}; // memory map of GCT section +static GrowBuffer_t gecko_data = {0}; +static GrowBuffer_t wcode_job = {0}; +static GrowBuffer_t wcode_data = {0}; + + +static bool use_gct_loader = false; + +/////////////////////////////////////////////////////////////////////////////// +// patched by + +#define STD_PATCHED_BY WSTRT_SHORT " v" VERSION " r" REVISION +static char opt_patched_by[PATCHED_BY_SIZE+1] = STD_PATCHED_BY; + +patched_by_t patched_by_mode = PBY_AUTO; + +//----------------------------------------------------------------------------- + +int ScanOptPBMode ( ccp arg ) +{ + if ( !arg || !*arg ) + { + patched_by_mode = PBY_AUTO; + return 0; + } + + static const KeywordTab_t tab[] = + { + { PBY_OFF, "OFF", 0, 0 }, + { PBY_RESET, "RESET", 0, 0 }, + { PBY_WIIMMFI, "WIIMMFI", 0, 0 }, + { PBY_AUTO, "AUTO", "DEFAULT", 0 }, + { PBY_ALWAYS, "ALWAYS", 0, 0 }, + { 0,0,0,0 } + }; + + const KeywordTab_t * cmd = ScanKeyword(0,arg,tab); + if (cmd) + { + patched_by_mode = cmd->id; + return 0; + } + + ERROR0(ERR_SYNTAX,"Invalid mode for option --pb-mode: '%s'\n",arg); + return 1; +} + +/////////////////////////////////////////////////////////////////////////////// + +#if defined(TEST) || defined(DEBUG) //|| HAVE_WIIMM_EXT + static void TraceGCT ( ccp info ) + { + fprintf(stdlog,"%s#GCT: gecko=%u/%u, wc-job=%u/%u, wc-data=%u/%u%s%s%s\n", + collog->b_cyan, + gecko_data.used, gecko_data.size, + wcode_job.used, wcode_job.size, + wcode_data.used, wcode_data.size, + info ? " : " : "", + info ? info : "", + collog->reset ); + } +#else + static inline void TraceGCT ( ccp info ) {} +#endif + +/////////////////////////////////////////////////////////////////////////////// + +static void InititializeGCT() +{ + static bool done = false; + if (!done) + { + done = true; + + InitializeMemMap(&gct_data_mem); + InitializeGrowBuffer(&gecko_data,MiB); + InitializeGrowBuffer(&wcode_job,MiB); + InitializeGrowBuffer(&wcode_data,MiB); + gecko_data.grow_size = 0x1000; + wcode_job.grow_size = 0x0100; + wcode_data.grow_size = 0x0400; + + if (logging>2) TraceGCT("Init"); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +static void ResetGCT() +{ + InititializeGCT(); + + ResetMemMap(&gct_data_mem); + ClearGrowBuffer(&gecko_data); + ClearGrowBuffer(&wcode_job); + ClearGrowBuffer(&wcode_data); +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError AddSectionHelper2 +( + // return ERR_OK | ERR_WARNING of created with warnings | ERR_ERROR on abort + staticr_t *str, // valid pointer + const wch_segment_t *seg, // segement info, local endian, data+size ignored + const u8 *seg_data, // segement data + uint seg_size, // segement data + ccp fname // filename for messages +) +{ + //--- patching possible? + + const u32 patch_addr = GetVbiAddress(str); + if (!patch_addr) + return 0; + + + //--- check overlaps + + dol_header_t *dh = (dol_header_t*)str->data; + const uint overlap = CountOverlappedDolSections(dh,seg->addr,seg_size); + if (overlap) + { + if (!force_count) + { + ERROR0(ERR_WARNING, + "New section would overlap %u existing section%s -> ignore: %s\n", + overlap, overlap == 1 ? "" : "s", fname ); + return ERR_ERROR; + } + + ERROR0(ERR_WARNING, + "New section overlaps %u existing section%s: %s\n", + overlap, overlap == 1 ? "" : "s", fname ); + } + + + //--- find first unused section + + int dol_seg_type; + switch (seg->type) + { + case 't': dol_seg_type = 0; break; // Any segment, TEXT first + case 'T': dol_seg_type = 1; break; // Only TEXT segment + case 'D': dol_seg_type = 2; break; // Only DATA segment + default: dol_seg_type = 3; break; // Any segment, DATA first (alias 'd') + } + + dol_sect_info_t di; + if (!FindFirstFreeDolSection(&di,dh,dol_seg_type)) + { + ERROR0(ERR_WARNING, + "DOL: No free section available: %s\n", str->fname ); + return ERR_ERROR; + } + PRINT("NEW SECTION: %s\n",di.name); + + + //--- append seg_data to end of dol + + uint offset = str->data_size; + str->data_size += seg_size; + str->data = REALLOC(str->data,str->data_size); + dh = (dol_header_t*)str->data; + memcpy( str->data + offset, seg_data, seg_size ); + + + //--- create section + + PRINT(" - create section %s [%08x..%08x], f-off 0x%06x, size 0x%x\n", + di.name, seg->addr, seg->addr+seg_size, offset, seg_size ); + + if ( verbose > 0 ) + fprintf(stdlog, + "- Create section %s [%08x..%08x], file offset 0x%06x, size 0x%x\n", + di.name, seg->addr, seg->addr+seg_size, offset, seg_size ); + + dh->sect_off [di.section] = htonl(offset); + dh->sect_addr[di.section] = htonl(seg->addr); + dh->sect_size[di.section] = htonl(seg_size); + + + //--- patch entry point + + u32 addr = seg->main_entry_old; + if (addr) + { + const u32 store = GetDolOffsetByAddr(dh,addr,sizeof(u32),0); + if (store) + memcpy(str->data+store,&dh->entry_addr,sizeof(u32)); + } + + if (seg->main_entry) + { + if ( verbose >= 1 ) + fprintf(stdlog, + "- Change entry point from %08x to %08x\n", + ntohl(dh->entry_addr), seg->main_entry ); + write_be32(&dh->entry_addr,seg->main_entry); + } + + + //--- patch VBI entry point + + if (seg->vbi_entry) + { + const u32 offset = GetDolOffsetByAddr(dh,patch_addr,sizeof(u32),0); + if (!offset) + { + ERROR0(ERR_WARNING, + "Can't patch DOL at address 0x%08x: %s\n", + patch_addr, str->fname ); + } + else + { + u32 addr = ntohl(seg->vbi_entry_old); + if (addr) + { + const u32 store = GetDolOffsetByAddr(dh,addr,sizeof(u32),0); + if (!store) + { + ERROR0(ERR_WARNING, + "Can't store old VBI at DOL address 0x%08x: %s\n", + seg->vbi_entry_old, str->fname ); + } + else + memcpy(str->data+store,str->data+offset,sizeof(u32)); + } + + const u32 code = ( seg->vbi_entry - patch_addr ) & 0xffffff | 0x4b000000; + PRINT("PATCH addr %08x off %08x from %08x to %08x\n", + patch_addr, offset, be32(str->data+offset), code ); + if ( verbose > 0 ) + fprintf(stdlog, + "- Patch address %08x (off %08x, VBI) from %08x to %08x\n", + patch_addr, offset, be32(str->data+offset), code ); + write_be32(str->data+offset,code); + } + } + + return ERR_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +typedef struct gct_sect_t +{ + u16 off; // source offset + u16 size; // size of section + u16 idx; // initial section index + u16 dest; // dest address of section (add 0x8000000 for real address) +} +gct_sect_t; + +//----------------------------------------------------------------------------- + +static int sort_sect_list_by_size + ( const gct_sect_t * a, const gct_sect_t * b ) +{ + return (int)b->size - (int)a->size; +} + +//----------------------------------------------------------------------------- + +static int sort_sect_list_by_dest + ( const gct_sect_t * a, const gct_sect_t * b ) +{ + return (int)a->dest - (int)b->dest; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +typedef struct cheat_code_loader_t +{ + u32 entry; // entry point => ASM: bl start + u32 dummy_04; // ... + + //--- data, see cheat-code-loader.sh + + u32 return_addr; // absolute return address + u32 var_version; // 'vars' version of current code loader + u32 space; // needed space, must not < source_len + + u32 patch_addr; // address of patch list, relative to 'vars' + u32 data_addr; // data address, relative to 'vars' + u32 data_end; // data-end address, relative to 'vars' + u32 gecko_off; // offset of first gecko code relative to data + + u32 verify_addr; // address to verify own codehandler + u32 verify_val; // use this to verify & to decode + u32 ch_patch_1; // abs address for first codehandler patch + u32 ch_patch_2; // abs address for second codehandler patch + u32 deny_user_gch; // 1: skip patching on !rSZS + u32 info_flags; // info flags for NAS (8 bits) +} +__attribute__ ((packed)) cheat_code_loader_t; + +#define CCL_VAR_OFFSET offsetof(cheat_code_loader_t,return_addr) + +/////////////////////////////////////////////////////////////////////////////// + +typedef enum { CHT_NONE, CHT_ONLY, CHT_FULL } code_handler_t; + +//----------------------------------------------------------------------------- + +static const u8 loader_asm_bz2[] = +{ + // decompressed len: 0x338 = 824 bytes + 0x00,0x00,0x03,0x38, + + // bzipped data + 0x42,0x5a,0x68,0x39, 0x31,0x41,0x59,0x26, 0x53,0x59,0x9d,0xf6, 0x23,0xf1,0x00,0x01, + 0x20,0xff,0xff,0xfd, 0xde,0xc7,0xf6,0xc5, 0xef,0xf5,0xff,0x64, 0x5b,0xef,0xd0,0x6a, + 0xdc,0xc5,0xd7,0xfc, 0xde,0x79,0xe0,0x53, 0xd6,0x51,0x10,0x55, 0xc3,0x41,0x65,0x45, + 0x84,0x65,0x44,0xc0, 0x01,0xf5,0xc2,0xca, 0xd2,0x1a,0xa6,0x8c, 0xa6,0x90,0xf5,0x3d, + 0x27,0xa9,0x90,0x00, 0xd0,0x06,0x26,0x83, 0xd2,0x00,0x69,0x88, 0x1a,0x00,0x19,0x00, + 0x1a,0x1a,0x32,0x01, 0xa0,0xf4,0x41,0x90, 0x32,0x00,0xc8,0x11, 0x34,0x41,0x1a,0x4f, + 0xd5,0x3d,0x27,0x94, 0xf5,0x32,0x1e,0xa0, 0x19,0x34,0x19,0x00, 0xd0,0xf4,0x80,0x00, + 0x00,0x00,0x00,0x00, 0x00,0x00,0x0d,0x00, 0xd0,0x06,0xd4,0x41, 0x80,0x4c,0x46,0x09, + 0x93,0x08,0x30,0x98, 0x98,0x13,0x00,0x43, 0x08,0xc0,0x43,0x02, 0x60,0x4c,0x26,0x08, + 0xc0,0x00,0x04,0xd0, 0xc2,0x62,0x69,0x81, 0x03,0x4d,0x42,0x98, 0x50,0x09,0xb4,0x3d, + 0x40,0x69,0xa8,0xc9, 0x80,0x68,0x00,0x01, 0x32,0x34,0xd1,0xa6, 0x00,0x11,0x81,0xa0, + 0x32,0x23,0x00,0x00, 0x08,0x69,0x91,0xe9, 0x0c,0xa2,0x54,0xaf, 0x84,0x8f,0x0a,0x52, + 0x54,0xba,0xa7,0xd1, 0x59,0x0d,0x00,0x4b, 0x69,0xdf,0xb0,0xb0, 0xb3,0xd3,0x4a,0x1c, + 0xa2,0x85,0xc9,0x8f, 0xc7,0xb6,0x9e,0x7e, 0x12,0x2b,0x1d,0x13, 0x3f,0x9e,0x9e,0x4b, + 0xb0,0x31,0x30,0x83, 0x55,0x67,0x43,0xde, 0x80,0x53,0x40,0x4f, 0xcd,0x7b,0x06,0x1c, + 0x04,0xd7,0x3e,0x0c, 0xc5,0xd2,0x66,0x27, 0xf5,0x19,0x65,0xeb, 0x81,0x01,0x48,0xa9, + 0x51,0x42,0x9b,0xba, 0x56,0x19,0x92,0x45, 0x52,0x6e,0x22,0xe0, 0xb5,0x97,0x2c,0x23, + 0xda,0x75,0x1c,0x16, 0x2e,0xb1,0x88,0x8e, 0x91,0xa0,0xcf,0x5a, 0xc9,0x5e,0x99,0x27, + 0xe1,0x52,0x18,0x16, 0x42,0x60,0x17,0x49, 0x28,0xc2,0x8e,0x18, 0x12,0x10,0xda,0x46, + 0x01,0x76,0x36,0xd4, 0x07,0xe3,0x9d,0x42, 0x5c,0xc2,0xba,0x55, 0x7f,0xbd,0x14,0x02, + 0x70,0x29,0x37,0x17, 0xf6,0xda,0x50,0x5b, 0x05,0xa1,0xb9,0x06, 0xcd,0xb0,0xde,0x93, + 0x88,0x8b,0x0f,0x9d, 0x2a,0x4d,0xc8,0x6b, 0x7c,0xf1,0x01,0xf2, 0x14,0x6b,0x11,0x48, + 0x27,0x7d,0xb8,0xab, 0x43,0x15,0x5d,0x46, 0x21,0x1f,0x70,0x56, 0x77,0x4a,0x82,0xcc, + 0x8b,0xf1,0xc9,0xc0, 0x73,0xde,0x98,0x74, 0x4b,0x96,0x39,0xb2, 0x6b,0x99,0xee,0x23, + 0x0d,0xf0,0x69,0x16, 0x12,0x26,0xf7,0x2c, 0xe8,0x60,0x78,0xfa, 0x13,0x3b,0x56,0xc8, + 0xaa,0x69,0x82,0x3e, 0xc8,0x2b,0xee,0xad, 0xb9,0x65,0x8e,0x44, 0x98,0x27,0x77,0xcd, + 0xc5,0xcf,0x48,0x17, 0x93,0x04,0x2a,0x82, 0x96,0xa2,0x6d,0x64, 0x1c,0x03,0x7d,0x91, + 0xd1,0x4f,0x38,0x78, 0x7f,0x2a,0xfb,0x03, 0xe6,0x2f,0xe3,0x9f, 0xe5,0x0b,0x36,0x58, + 0x8c,0x70,0xba,0x9d, 0x3b,0xf3,0x4b,0xfe, 0xb9,0x53,0x6a,0x4c, 0xe8,0x6c,0xb9,0xfc, + 0x32,0xa3,0x13,0xc9, 0xed,0x29,0x10,0x4c, 0x48,0xe1,0x32,0x81, 0x0a,0x24,0x80,0x20, + 0x15,0x82,0x0d,0x89, 0x26,0xa1,0x29,0x66, 0x08,0x0a,0xd0,0x9e, 0xe0,0xce,0x50,0x7b, + 0xc5,0xfb,0x95,0x66, 0x42,0x65,0x84,0xda, 0xdf,0x37,0x52,0x53, 0x23,0x06,0x09,0x39, + 0xf6,0x1f,0x63,0xf1, 0x0b,0x13,0xd6,0x9c, 0xa2,0x63,0x2d,0xef, 0xa2,0xb2,0x8d,0xd2, + 0xa0,0xdd,0xe8,0x39, 0x9e,0xf5,0x71,0xa4, 0xd1,0xc5,0x74,0x11, 0x11,0xbb,0x42,0x20, + 0x53,0x92,0xff,0xc5, 0x36,0x67,0x4e,0xa4, 0x1b,0x55,0x95,0xef, 0x3a,0x30,0x12,0x85, + 0xea,0xe2,0x75,0xbf, 0x1a,0xb8,0xc8,0xa8, 0x12,0x2d,0x19,0x17, 0x91,0xdd,0xa7,0x23, + 0xbb,0xe7,0x18,0xb4, 0x61,0x78,0xa8,0xc4, 0x3b,0x84,0x5a,0x2d, 0x35,0x5f,0xac,0xd8, + 0x82,0xae,0x21,0x8e, 0x23,0x7d,0xf3,0x93, 0x2d,0xff,0x7b,0xbc, 0xbd,0x42,0x65,0xfc, + 0x1e,0xf9,0x2d,0xf9, 0x69,0x5a,0x12,0x08, 0x20,0x90,0x41,0x00, 0xc9,0x62,0xd2,0x88, + 0xc2,0x2a,0xa2,0x95, 0xc6,0x52,0xab,0x53, 0x31,0xb5,0xae,0x62, 0x36,0x07,0x94,0x8f, + 0x05,0x87,0x98,0x4a, 0x26,0x1a,0x0f,0x1f, 0xdb,0x2e,0x20,0xbb, 0x00,0x3c,0xb8,0x74, + 0x4c,0xb2,0x04,0x8f, 0x98,0xec,0x1d,0x43, 0x10,0x97,0x08,0x33, 0x05,0x0a,0xa0,0x48, + 0x23,0x04,0x50,0xc0, 0xfd,0x68,0x2e,0x24, 0x97,0xb1,0x4c,0xac, 0xb6,0x12,0xd4,0x00, + 0x65,0xdb,0x5d,0x74, 0x19,0x20,0x9e,0x58, 0xc2,0x10,0x12,0x00, 0x2b,0x52,0x00,0xea, + 0xa8,0xe0,0x54,0x84, 0xd0,0x7e,0x52,0x38, 0x08,0x2a,0x82,0x40, 0x59,0x3c,0xde,0xc5, + 0x08,0x1c,0x8f,0x4a, 0x79,0x27,0x98,0xbb, 0x92,0x29,0xc2,0x84, 0x84,0xef,0xb1,0x1f, + 0x88, + // 0x2e1 = 737 Bytes +}; + +static BZ2Manager_t loader_asm_mgr + = { loader_asm_bz2, sizeof(loader_asm_bz2), 0, 0 }; + +/////////////////////////////////////////////////////////////////////////////// + +static enumError SetupCodeLoader +( + // return ERR_OK | ERR_WARNING of created with warnings, + // ERR_ERROR on abort, ERR_NOTHING_TO_DO if nothing to do + + staticr_t *str, // valid pointer + const wch_segment_t *seg, // NULL or segement info, seg->data is ignored + u8 *code_data, // NULL or code data + uint code_size, // NULL or size of code data + uint cheat_offset, // offset first cheat code + code_handler_t ch_type, // code handler type + ccp fname // filename for messages +) +{ + ASSERT( code_size >= cheat_offset ); + const uint total_data_size = wcode_job.used + wcode_data.used + + code_size - cheat_offset; + + #if defined(TEST) || defined(DEBUG) // || HAVE_WIIMM_EXT + if (logging>2) + fprintf(stderr, + "SetupCodeLoader() %d+%d+%d = %d, c-off=0x%x, ch-type=%d, seg=%d => %s\n", + code_size, wcode_job.used, wcode_data.used, total_data_size, + cheat_offset, ch_type, seg!=0, + total_data_size ? "\e[41;37;1m CREATE WIIMMFI CODE \e[0m" : "quit" ); + #endif + + if (!total_data_size) + return ERR_NOTHING_TO_DO; + + + //--- data + + GrowBuffer_t data; + InitializeGrowBuffer(&data,MiB); + data.grow_size = 0x1000; + + + //--- code handler + + const u32 security_off = GCT_REG_OFFSET + 16; // gecko register 4 + const u32 security_val = 0xdc020463; + + enumError err = ERR_OK; + if ( code_size ) + { + ASSERT(code_data); + write_be32(code_data+security_off,security_val); + write_be32(code_data+security_off+8,security_val); + write_be64(code_data+cheat_offset,GCT_TERM_NUM); + err = AddSectionHelper2(str,seg,code_data,cheat_offset+8,fname); + if (err) + goto abort; + code_data += cheat_offset; + code_size -= cheat_offset; + write_be64(code_data,GCT_MAGIC8_NUM); + str->dol_flags[DPF_CHEAT] = 'l'; + } + + + //--- setup data buffer + + DecodeBZIP2Manager(&loader_asm_mgr); + InsertGrowBuffer(&data,loader_asm_mgr.data,loader_asm_mgr.size); + cheat_code_loader_t ccl; + memcpy(&ccl,data.ptr,sizeof(ccl)); + ccl.info_flags = htonl(str->dol_info_flags); + + uint code_offset = loader_asm_mgr.size - CCL_VAR_OFFSET; + uint deny_user_gch = opt_allow_user_gch < OFFON_AUTO; + if (wcode_job.used) + { + ccl.patch_addr = htonl(code_offset); + InsertGrowBuffer(&data,wcode_job.ptr,wcode_job.used); + InsertGrowBuffer(&data,EmptyString,4); + code_offset += wcode_job.used + 4; + deny_user_gch = opt_allow_user_gch <= OFFON_AUTO; + } + str->dol_flags[DPF_ALLOW_USER] = deny_user_gch ? 'd' : 'a'; + if ( deny_user_gch && code_size ) + { + str->dol_flags[DPF_ALLOW_USER] = 's'; + deny_user_gch = 2; + } + ccl.deny_user_gch = htonl(deny_user_gch); + ccl.data_addr = htonl(code_offset); + ccl.gecko_off = htonl( wcode_data.used ); + + if (wcode_data.used) + InsertGrowBuffer(&data,wcode_data.ptr,wcode_data.used); + + if (code_size) + { + InsertGrowBuffer(&data,code_data,code_size); + ccl.verify_addr = htonl(seg->addr+security_off); + } + ccl.data_end = htonl(data.used-CCL_VAR_OFFSET); + const u32 space = data.used - CCL_VAR_OFFSET - code_offset; + ccl.space = htonl( space > opt_gct_space ? space : opt_gct_space ); + ccl.verify_val = htonl(security_val); + + if ( ch_type == CHT_FULL ) + { + ccl.ch_patch_1 = htonl(seg->addr+0x04DC); + ccl.ch_patch_2 = htonl(seg->addr+0x0758); + } + else if ( ch_type == CHT_ONLY ) + ccl.ch_patch_1 = htonl(seg->addr+0x0104); + + memcpy(data.ptr,&ccl,sizeof(ccl)); + + + //--- create segment + + wch_segment_t dseg; + memset(&dseg,0,sizeof(dseg)); + dseg.type = 't'; + dseg.size = data.used; + dseg.addr = opt_gct_addr < 0x80000000 + ? FindFreeBssSpaceDOL((dol_header_t*)str->data,dseg.size,32,0) + : opt_gct_addr; + dseg.main_entry = dseg.addr; + dseg.main_entry_old = dseg.addr + offsetof(cheat_code_loader_t,return_addr); + + u32 *ptr = (u32*)( data.ptr + loader_asm_mgr.size ); + u32 *end = (u32*)( data.ptr + data.used ); + u32 key = security_val; + while ( ptr < end ) + { + const u32 orig = be32(ptr); + const u32 val = orig ^ key; + write_be32(ptr, val << 19 | val >> 13 ); + key += orig >> 5; + ptr++; + } + + err = AddSectionHelper2(str,&dseg,data.ptr,dseg.size,fname); + + //--- clean +abort: + ResetGrowBuffer(&data); + ClearGrowBuffer(&wcode_job); + ClearGrowBuffer(&wcode_data); + + return err; +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError AddSectionHelper +( + // return ERR_OK | ERR_WARNING of created with warnings | ERR_ERROR on abort + staticr_t *str, // valid pointer + const wch_segment_t *seg, // segement info, seg->data is ignored + const u8 *seg_data, // segement data + ccp fname // filename for messages +) +{ + //--- patching possible? + + const u32 patch_addr = GetVbiAddress(str); + if (!patch_addr) + return 0; + + + //--- check presence of 'codehandleronly' or 'codehandler' + //--- and optional replace 'codehandleronly' by 'codehandler' + + u8 *new_data = 0; + uint seg_size = seg->size; + + code_handler_t ch_type = CHT_NONE; + uint cheat_offset = 0; + + BZ2Manager_t *cho = &codehandleronly_mgr; + DecodeBZIP2Manager(cho); + if ( cho->size > sizeof(gch_header_t) ) + { + const u8 *cho_data = cho->data + sizeof(gch_header_t); + const uint cho_size = cho->size - sizeof(gch_header_t); + if ( seg_size >= cho_size && !memcmp(cho_data,seg_data,cho_size) ) + { + ch_type = CHT_ONLY; + cheat_offset = cho_size; + + if (opt_full_gch) + { + PRINT("\e[35;1m Only: %u >= ( %u -> %u -> %u )\e[0m\n", + seg_size, codehandleronly_mgr.src_size, + codehandleronly_mgr.size, cho_size ); + + BZ2Manager_t *chf = &codehandler_mgr; + DecodeBZIP2Manager(chf); + if ( chf->size > sizeof(gch_header_t) ) + { + if ( verbose > 0 ) + fprintf(stdlog, + "- Replace 'codehandleronly' by 'codehandler'\n"); + + const u8 *chf_data = chf->data + sizeof(gch_header_t); + const uint chf_size = chf->size - sizeof(gch_header_t); + const uint new_size = seg_size - cho_size + chf_size; + new_data = MALLOC(new_size); + memcpy( new_data, chf_data, chf_size ); + memcpy( new_data+chf_size, seg_data+cho_size, seg_size-cho_size ); + seg_data = new_data; + seg_size = new_size; + + ch_type = CHT_FULL; + cheat_offset = chf_size; + } + } + } + } + + if ( ch_type == CHT_NONE ) + { + BZ2Manager_t *chf = &codehandler_mgr; + DecodeBZIP2Manager(chf); + if ( chf->size > sizeof(gch_header_t) ) + { + const u8 *chf_data = chf->data + sizeof(gch_header_t); + const uint chf_size = chf->size - sizeof(gch_header_t); + if ( seg_size >= chf_size && !memcmp(chf_data,seg_data,chf_size) ) + { + ch_type = CHT_FULL; + cheat_offset = chf_size; + } + } + } + + + //--- find and remove separators + + enum { MAX_SECT = 200 }; + gct_sect_t sect_list[MAX_SECT+1], + *sect = sect_list, + *sect_end = sect_list + MAX_SECT; + memset(sect_list,0,sizeof(sect_list)); + + if ( cheat_offset > sizeof(gch_header_t) && opt_gct_scan_sep ) + { + if (!new_data) + { + // we need modifiable data! + new_data = MEMDUP(seg_data,seg_size); + seg_data = new_data; + } + + u8 *src = new_data + cheat_offset; + u8 *dest = src; + u8 *end = new_data + seg_size; + + while ( src + 8 <= end ) + { + PRINT(">> LINE %3zd => %3zd : %08x %08x\n", + ( src - new_data - cheat_offset ) / 8, + ( dest - new_data - cheat_offset ) / 8, + be32(src), be32(src+4) ); + + uint copy_lines = 0; + if ( be32(src) == 0xf0000000 && !be32(src+4) ) + { + const u32 off = dest - new_data; + sect->size = off - sect->off; + sect++; + sect->idx = sect - sect_list; + sect->off = off; + sect->size = 8; + *(u64*)dest = *(u64*)src; + src += 8; + dest += 8; + break; + } + else if ( be32(src) == GCT_SEP_NUM1 && !be16(src+4) ) + { + if ( opt_gct_sep ) + { + const u32 off = dest - new_data; + if ( sect->off != off && sect < sect_end ) + { + sect->size = off - sect->off; + sect++; + sect->idx = sect - sect_list; + sect->off = off; + sect->size = 0; + } + } + + PRINT("\t>> SEP#%zu found: %08x %08x\n", + sect-sect_list, be32(src),be32(src+4) ); + copy_lines = be16(src+6); + src += 8; + } + else if ( *src == 0xc0 || *src == 0xc2 || *src == 0xd0 || *src == 0xd2 ) + { + if ( opt_gct_asm_sep ) + { + const u32 off = dest - new_data; + if ( sect->off != off && sect < sect_end ) + { + sect->size = off - sect->off; + sect++; + sect->idx = sect - sect_list; + sect->off = off; + sect->size = 0; + } + } + + PRINT(">> ASM#%zu found: %08x %08x\n", + sect-sect_list, be32(src), be32(src+4) ); + copy_lines = be32(src+4) + 1; + } + else if ( ( *src == 0x66 || *src == 0x68 ) + && ( src[1] == 0x00 || src[1] == 0x10 || src[1] == 0x20 ) ) + { + PRINT(">> GOTO/GOSUB#%zu found: %08x %08x\n", + sect-sect_list, be32(src), be32(src+4) ); + s16 go = be16(src+2); + if ( go >= 0 ) + copy_lines = go+1; + } + else + { + *(u64*)dest = *(u64*)src; + src += 8; + dest += 8; + continue; + } + + if ( copy_lines > 0 ) + { + // use it this way to detect bad large values + const uint max = ( end - src ) / 8; + if ( copy_lines > max ) + copy_lines = max; + copy_lines *= 8; // now we have copy_bytes! + + memmove(dest,src,copy_lines); + src += copy_lines; + dest += copy_lines; + } + } + + //PRINT(">>> %zd %zd /%zd\n",dest-new_data,src-new_data,end-new_data); + if ( src >= end ) + seg_size = dest - new_data; + else if ( src > dest ) + memset(dest,0,src-dest); + } + const int n_sect = sect - sect_list; + + + //--- move GCT part + + str->dol_flags[DPF_CHEAT] = 'c'; + + enumError err = ERR_OK; + if ( opt_gct_move >= OFFON_ON && cheat_offset >= 0x100 ) + { + use_loader:; + if (!new_data) + { + // we need modifiable data! + new_data = MEMDUP(seg_data,seg_size); + seg_data = new_data; + } + + err = SetupCodeLoader(str,seg,new_data,seg_size,cheat_offset,ch_type,fname); + goto abort; + } + + + //--- split GCT part + + const u32 off_end = seg->addr + seg_size; + PRINT("N=%d, of=%08x\n",n_sect,off_end); + if ( n_sect > 2 + && seg->addr + cheat_offset < 0x80002ff0 + && off_end >= 0x80003000 && off_end < 0x80004000 ) + { + #ifdef TEST0 + { + uint i; + for ( i = 0, sect = sect_list; i <= n_sect; i++, sect++ ) + PRINT(" -> SECT %2u: %4x .. %4x, size %4x\n", + i, sect->off, sect->off + sect->size, sect->size ); + } + #endif + + bool sorted = false; + restart:; + u8 data[0x4000]; + memset(data,0,sizeof(data)); + + const u32 base_addr = seg->addr - 0x80000000; + memcpy(data+base_addr,seg_data,cheat_offset+8); + + struct data_t { u32 used; u32 size; u8 *data; } data_tab[] = + { + { cheat_offset+8, 0x2ff8 - base_addr, data + base_addr }, + { 0, 0x37f8 - 0x3200, data + 0x3200 }, + { 0, 0x3ff8 - 0x3880, data + 0x3880 }, + {0,0,0} + }; + + uint i; + struct data_t *dp; + bool fail = false; + + if ( opt_gct_list > 1 ) + { + fprintf(stdlog,"\nSummary of detected GCT sections:\n"); + for ( i = 1, sect = sect_list+1; i < n_sect; i++, sect++ ) + fprintf(stdlog," S%02u: %04x .. %04x, size %04x = %4u/dec\n", + sect->idx, sect->off, sect->off+sect->size, + sect->size, sect->size ); + } + + for ( i = 1, sect = sect_list+1; i < n_sect; i++, sect++ ) + { + bool done = false; + for ( dp = data_tab; dp->data; dp++ ) + if ( sect->size <= dp->size - dp->used ) + { + memcpy(dp->data+dp->used,seg_data+sect->off,sect->size); + sect->dest = dp->data + dp->used - data; + dp->used += sect->size; + done = true; + break; + } + if (!done) + { + sect->dest = M1(sect->dest); + ERROR0(ERR_WARNING, + "No space for cheat code section %u (size %x): %s\n", + i, sect->size, fname ); + fail = true; + } + } + + #ifdef TEST0 + { + uint i; + const struct data_t *dp; + for ( i = 0, dp = data_tab; dp->data; i++, dp++ ) + printf(" -> %2u: %04zx .. %04zx : %4x / %4x : %4x\n", + i, dp->data - data, dp->data - data + dp->used, + dp->used, dp->size, dp->size - dp->used ); + } + #endif + + if (fail) + { + if (!sorted) + { + qsort( sect_list+1, n_sect-1, sizeof(*sect_list), + (qsort_func)sort_sect_list_by_size ); + sorted = true; + goto restart; + } + + FREE(new_data); + ERROR0(ERR_ERROR, + "Not enough space for cheat codes: %s\n",fname); + return ERR_WARNING; + } + + if ( opt_gct_list > 0 ) + { + qsort( sect_list+1, n_sect-1, sizeof(*sect_list), + (qsort_func)sort_sect_list_by_dest ); + fprintf(stdlog,"\nSummary of GCT section distribution:\n"); + for ( i = 1, sect = sect_list+1; i < n_sect; i++, sect++ ) + { + fprintf(stdlog, + " S%02u: %04x .. %04x, size %04x = %4u/dec => ", + sect->idx, sect->off, sect->off+sect->size, + sect->size, sect->size ); + if (IS_M1(sect->dest)) + fprintf(stdlog,"FAILED!\n"); + else + fprintf(stdlog,"%04x .. %04x\n",sect->dest,sect->dest+sect->size); + } + fputc('\n',stdlog); + } + + struct data_t *prev = 0; + for ( dp = data_tab; dp->data; dp++ ) + if ( dp->used) + { + if (prev) + { + u8 *dest = prev->data + prev->used; + write_be16(dest,0x6620); + write_be16( dest+2, ( dp->data - dest - 8 ) / 8 ); + write_be32(dest+4,0); + prev->used += 8; + } + prev = dp; + } + if (prev) + { + u8 *dest = prev->data + prev->used; + write_be32(dest,0xf0000000ul); + write_be32(dest+4,0); + prev->used += 8; + } + + #ifdef TEST0 + { + uint i; + const struct data_t *dp; + for ( i = 0, dp = data_tab; dp->data; i++, dp++ ) + printf(" -> %2u: %04zx .. %04zx : %4x / %4x : %4x\n", + i, dp->data - data, dp->data - data + dp->used, + dp->used, dp->size, dp->size - dp->used ); + } + #endif + + err = AddSectionHelper2(str,seg,data_tab->data,data_tab->used,fname); + if ( err == ERR_OK ) + { + wch_segment_t dseg; + memset(&dseg,0,sizeof(dseg)); + dseg.type = 'd'; + if ( data_tab[1].used ) + { + dseg.addr = data_tab[1].data - data + 0x80000000; + const uint size = data_tab[2].used + ? data_tab[2].data + data_tab[2].used - data_tab[1].data + : data_tab[1].used; + err = AddSectionHelper2(str,&dseg,data_tab[1].data,size,fname); + } + else if ( data_tab[2].used ) + { + dseg.addr = data_tab[2].data - data + 0x80000000; + err = AddSectionHelper2(str,&dseg,data_tab[2].data,data_tab[2].used,fname); + } + } + return err; + } + + + //--- warn if overlapping 0x80003xxx + + if ( ch_type != CHT_NONE + && ( seg->addr < 0x80004000 && off_end > 0x80003000 )) + { + if ( opt_gct_move >= OFFON_AUTO && cheat_offset >= 0x100 ) + goto use_loader; + + FREE(new_data); + ERROR0(ERR_ERROR, + "Cheat codes must not overlay 0x80003000..0x80004000: %s\n", + fname); + return ERR_WARNING; + } + + + //--- standard: use 1 section + + err = AddSectionHelper2(str,seg,seg_data,seg_size,fname); + + abort: + FREE(new_data); + return err; +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError ReadCodeFile ( staticr_t *str, ccp fname, u8 **data, uint *size ) +{ + DASSERT(str); + DASSERT(fname); + DASSERT(data); + DASSERT(size); + + *data = 0; + *size = 0; + + if ( fname && fname[0] == '@' ) + { + BZ2Manager_t *wcm = 0; + if (!strcmp(fname,"@LECODE")) wcm = GetLecodeLoader(str->mode); +// else if (!strcmp(fname,"@XXX")) wcm = GetXXXX(str->mode); + + if (wcm) + { + DecodeBZIP2Manager(wcm); + *data = wcm->data; + *size = wcm->size; + return ERR_OK; + } + } + + enumError err = OpenReadFILE(fname,0,true,data,size,0,0); + if (err) + { + char path_buf[PATH_MAX]; + if (ReplaceRegionChar(str,path_buf,sizeof(path_buf),fname)) + err = OpenReadFILE(path_buf,0,true,data,size,0,0); + + if (err) + { + ERROR0(ERR_WARNING,"Can't load file: %s\n",fname); + return err; + } + } + + return ERR_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError AddWCode ( cvp data, uint size ) +{ + DASSERT(data); + DASSERT(!(size&7)); + InititializeGCT(); + + u8 *ptr = (u8*)data; + u8 *end = ptr + size; + u32 buf[5]; + + if ( be64(ptr) == GCT_MAGIC8_NUM ) + ptr += 8; + + while ( ptr < end ) + { + switch (*ptr) + { + case 0x04: + buf[0] = htonl(0x04); + buf[1] = htonl( be32(ptr) & 0xffffff | 0x80000000 ); + buf[2] = ((u32*)ptr)[1]; + InsertGrowBuffer(&wcode_job,buf,12); + use_gct_loader = true; + ptr += 8; + break; + + case 0xc2: + { + const uint len = 8 * be32(ptr+4); + buf[0] = htonl(0xc2); + buf[1] = htonl( be32(ptr) & 0xffffff | 0x80000000 ); + buf[2] = htonl( wcode_data.used ); + buf[3] = htonl( wcode_data.used + len - 4 ); + InsertGrowBuffer(&wcode_job,buf,16); + InsertGrowBuffer(&wcode_data,ptr+8,len); + use_gct_loader = true; + ptr += 8 + len; + } + break; + + case 0xf0: + if ( be32(ptr) != GCT_SEP_NUM1 ) + goto term; + ptr += 8; // ignore separators + break; + + default: + return ERROR0(ERR_WARNING,"WCODE %02x not supported => ABORT\n",*ptr); + } + } + term: + if (logging>2) TraceGCT("WCode"); + return ERR_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +static enumError AddCheatCode +( + // returns ERR_OK, ERR_NOTHING_TO_DO, ERR_WARNING or ERR_INTERNAL + + const u8 *code_data, // cheat code data + uint code_size, // cheat code size + bool check_dup, // TRUE: check for duplicates + ccp fname // file name for error messages +) +{ + DASSERT(code_data); + + //--- verify code_size and skip magic and terminator + + code_size &= ~7; // multiple of 8, cut additional bytes + if ( code_size >= 8 && be64(code_data) == GCT_MAGIC8_NUM ) + { + // skip magic + code_data += 8; + code_size -= 8; + } + + if ( code_size >= 8 && be64(code_data+code_size-8) == GCT_TERM_NUM ) + { + // ignore terminator + code_size -= 8; + } + + if (!code_size) + return ERR_NOTHING_TO_DO; + + + //--- first code -> add code handler + + InititializeGCT(); + + if (!gct_data_mem.used) + { + BZ2Manager_t *mgr = opt_full_gch + ? &codehandler_mgr : &codehandleronly_mgr; + enumError err = DecodeBZIP2Manager(mgr); + if (err) + return ERROR0(ERR_INTERNAL,0); + + gct_data_mem.begin = GCT_ADDRESS; + MemMapItem_t *mi; + mi = InsertMemMap(&gct_data_mem,GCT_ADDRESS,mgr->size-sizeof(gch_header_t)); + StringCopyS(mi->info,sizeof(mi->info),"Code Handler"); + mi = InsertMemMap(&gct_data_mem,GCT_MM_BASE+mgr->size,8); + StringCopyS(mi->info,sizeof(mi->info),"GCT magic"); + if (!use_gct_loader) + { + mi = InsertMemMap(&gct_data_mem,GCT_MAX,0); + StringCopyS(mi->info,sizeof(mi->info),"-- max possible --"); + } + + InsertGrowBuffer(&gecko_data,mgr->data,mgr->size); + u64 magic = hton64(GCT_MAGIC8_NUM); + InsertGrowBuffer(&gecko_data,&magic,sizeof(magic)); + if (logging>2) + TraceGCT("Setup"); + } + + + //--- check, if same code already inserted + + if ( check_dup && code_size <= gecko_data.used ) + { + const u8 *ptr = gecko_data.ptr; + const u8 *end = ptr + gecko_data.used - code_size; + + while ( ptr <= end ) + { + if (!memcmp(ptr,code_data,code_size)) + return ERR_NOTHING_TO_DO; + ptr += 8; + } + } + + + //--- add cheat code + + MemMapItem_t *mi + = InsertMemMap(&gct_data_mem,GCT_MM_BASE+gecko_data.used,code_size); + snprintf(mi->info,sizeof(mi->info), + "%4u line%s of GCT file", code_size/8, code_size == 8 ? "" : "s" ); + + if ( opt_gct_scan_sep && opt_gct_sep && be32(code_data) != GCT_SEP_NUM1 ) + { + u32 buf[2]; + buf[0] = htonl(GCT_SEP_NUM1); + buf[1] = htonl(code_size/8); + InsertGrowBuffer(&gecko_data,buf,8); + } + + InsertGrowBuffer(&gecko_data,code_data,code_size); + return ERR_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError AddWCodeFile ( staticr_t *str, ccp fname ) +{ + DASSERT(str); + if ( !fname || !*fname ) + return ERR_OK; + + u8 *data; + uint size; + enumError err = ReadCodeFile(str,fname,&data,&size); + if (err) + return err; + +// [[analyse-magic]] + const file_format_t fform = GetByMagicFF(data,size,size); + if ( fform == FF_GCT ) + { + err = opt_wcode == WCODE_GECKO + ? AddCheatCode(data,size,true,fname) + : AddWCode(data,size); + } + else + err = ERROR0(ERR_WARNING,"Not a GCT file: %s\n",fname); + + FREE(data); + return err; +} + +/////////////////////////////////////////////////////////////////////////////// + +#if HAVE_XSRC + #include "xsrc/x-staticr.c" +#endif + +/////////////////////////////////////////////////////////////////////////////// + +static uint AddSectionGCH +( + staticr_t *str, // valid pointer + u8 *gh_data, // GCH data + uint gh_size, // GHC size + ccp fname, // filename for messages + bool get_min_addr // true: do nothing and get minimal section addr +) +{ + DASSERT(str); + DASSERT(str->data_size); + DASSERT(str->data); + DASSERT(str->is_dol); + DASSERT(gh_data||!gh_size); + + + //--- get param + + const u32 patch_addr = GetVbiAddress(str); + if (!patch_addr) + return 0; + + + //--- check for GCT + +// [[analyse-magic]] + const file_format_t fform = GetByMagicFF(gh_data,gh_size,gh_size); + if ( fform == FF_GCT ) + { + AddCheatCode(gh_data,gh_size,false,fname); + return 0; + } + + const gch_header_t *gh = (gch_header_t*)gh_data; + if (!IsValidGCH(gh,gh_size)) + { + #if HAVE_XSRC + return IsNotGCH(str,fname,gh_data,gh_size,get_min_addr); + #else + ERROR0(ERR_WARNING,"Not a valid GCH file: %s\n",fname); + return 0; + #endif + } + + gh_size -= sizeof(gch_header_t); // from now we only need the raw data size + + if (get_min_addr) + return ntohl(gh->addr); + + wch_segment_t seg; + memset(&seg,0,sizeof(seg)); + seg.type = 't'; + seg.addr = ntohl(gh->addr); + seg.size = gh_size; + seg.vbi_entry = ntohl(gh->vbi_entry); + + const enumError err = AddSectionHelper(str,&seg,gh->data,fname); + return err < ERR_ERROR; +} + +/////////////////////////////////////////////////////////////////////////////// + +static uint AddSectionDOL +( + staticr_t * str, // valid pointer + ccp fname, // filename to open + bool get_min_addr // true: do nothing and get minimal section addr +) +{ + DASSERT(str); + DASSERT(str->data_size); + DASSERT(str->data); + DASSERT(str->is_dol); + + if ( !fname || !*fname ) + return 0; + + + //--- get param + + const u32 patch_addr = GetVbiAddress(str); + if (!patch_addr) + return 0; + + + //--- load file + + u8 *gh_data = 0; + uint gh_size = 0; + enumError err = ReadCodeFile(str,fname,&gh_data,&gh_size); + if (err) + return err; + + const uint stat = AddSectionGCH(str,gh_data,gh_size,fname,get_min_addr); + FREE(gh_data); + return stat; +} + +/////////////////////////////////////////////////////////////////////////////// + +static uint AddSectionsDOL +( + staticr_t * str, // valid pointer + bool get_min_addr // true: do nothing and get minimal section addr +) +{ + DASSERT(str); + DASSERT(str->data_size); + DASSERT(str->data); + DASSERT(str->is_dol); + + uint i, count = get_min_addr ? 0xffffffff : 0; + for ( i = 0; i < opt_sect_list.used; i++ ) + { + ccp fname = opt_sect_list.field[i]; + const uint stat = AddSectionDOL(str,fname,get_min_addr); + if (!get_min_addr) + count += stat; + else if ( stat && count > stat ) + count = stat; + } + + if ( gecko_data.used ) + { + if (logging>0) + fprintf(stdlog,">> GCT DATA/GROW, %u = 0x%x bytes\n", + gecko_data.used, gecko_data.used ); + + if (!get_min_addr) + { + // terminate section and add it to dol + MemMapItem_t *mi = InsertMemMap(&gct_data_mem,GCT_MM_BASE+gecko_data.used,8); + StringCopyS(mi->info,sizeof(mi->info),"GCT terminator"); + + u64 term = hton64(GCT_TERM_NUM); + InsertGrowBuffer(&gecko_data,&term,sizeof(term)); + count += AddSectionGCH(str,gecko_data.ptr,gecko_data.used,"GCT",false); + + if ( verbose > 1 || logging > 1 ) + { + fputs("\n Memory map of code handler and GCT files:\n",stdlog); + PrintMemMap(&gct_data_mem,stdlog,5,"part"); + fputc('\n',stdlog); + } + } + else if ( count > 0x80001800 ) + count = 0x80001800; + ResetGCT(); + } + + return count; +} + +/////////////////////////////////////////////////////////////////////////////// + +static uint CreateSectionDOL +( + staticr_t * str // valid pointer +) +{ + DASSERT(str); + DASSERT(str->data_size); + DASSERT(str->data); + DASSERT(str->is_dol); + + enum + { + OFF_SECT_ADDR = 0x10, + OFF_REL_ENTRY = 0x14, + OFF_ORIG_ENTRY = 0x18, + OFF_RDOL_ADDR = 0x1c, + OFF_END_PARAM = 0x20, + + RED_DOL_SIZE = 0xe4 - 0x48, // reduced DOL size + }; + + u32 dol_sect_offset = 0; // file offset of DOL section + u32 dol_sect_addr = 0; // address of DOL section + dol_header_t *dh = (dol_header_t*)str->data; + + + //--- find max dol address + + u32 max_addr = dh->bss_addr + dh->bss_size; + uint sect; + for ( sect = 0; sect < DOL_N_SECTIONS; sect++ ) + { + const u32 size = ntohl(dh->sect_size[sect]); + if (size) + { + const u32 off = ntohl(dh->sect_addr[sect]) + size; + if ( max_addr < off ) + max_addr = off; + } + } + max_addr = ALIGN32(max_addr,4); + + + //--- iterate new section list + + uint count; + for ( count = sect = 0; sect < n_section_list; sect++ ) + { + dol_sect_select_t *sl = section_list + sect; + sl->offset = 0; + if ( sl->find_mode < 0 ) + continue; + + dol_sect_info_t si; + if (!FindDolSectionBySelector(&si,dh,sl)) + { + ERROR0(ERR_WARNING,"DOL section '%s' not available: %s\n", + sl->name, str->fname ); + return 0; + } + + bool is_dol_info = !strcasecmp(sl->fname,".dol"); + if (is_dol_info) + { + sl->use_param = 0; + sl->size = RED_DOL_SIZE; + } + else if (!sl->data) + { + if (OpenReadFILE( sl->fname, 0, true, &sl->data, &sl->size, 0, 0 )) + { + ERROR0(ERR_WARNING,"Can't load file for '%s': %s\n", + sl->name, sl->fname ); + sl->find_mode = -1; + continue; + } + } + count++; + + uint offset = str->data_size; + sl->offset = offset; + str->data_size += sl->size; + str->data = REALLOC(str->data,str->data_size); + dh = (dol_header_t*)str->data; + u8 *dest = str->data + offset; + + u32 sect_addr = !sl->addr && sl->use_param + ? be32(sl->data+OFF_SECT_ADDR) : sl->addr; + + if (is_dol_info) + { + sl->data = (u8*)&dh->sect_addr; + if (!sect_addr) + sect_addr = 0x80004000 - RED_DOL_SIZE; + dol_sect_addr = sect_addr; + dol_sect_offset = offset; + } + + if (!sect_addr) + sect_addr = max_addr; + const u32 end_addr = ALIGN32( sect_addr + sl->size, 4 ); + if ( max_addr < end_addr ) + max_addr = end_addr; + + u32 new_entry = 0; + bool param_valid = false; + if ( sl->use_param && sl->size >= OFF_END_PARAM ) + { + new_entry = be32(sl->data+OFF_REL_ENTRY); + if (!new_entry) + { + param_valid = true; + } + else if ( !(new_entry&3) && new_entry < sl->size ) + { + param_valid = true; + new_entry += sect_addr; + } + else + new_entry = 0; + } + if (!param_valid) + sl->use_param = false; + + + //--- create section + + PRINT(" - create section %s[%d] [%08x..%08x], f-off 0x%06x, size 0x%x, par=0x%x\n", + si.name, si.section, sect_addr, sect_addr + sl->size, + offset, sl->size, new_entry ); + + if (verbose>0) + { + fprintf(stdlog, + "- Create section %s [%08x..%08x], file offset 0x%06x, size 0x%x", + si.name, sect_addr, sect_addr + sl->size, offset, sl->size ); + if (new_entry) + fprintf(stdlog,", entry 0x%x\n",new_entry); + else if (param_valid) + fprintf(stdlog,", use param\n"); + else + fputc('\n',stdlog); + } + + dh->sect_off [si.section] = htonl(offset); + dh->sect_addr[si.section] = htonl(sect_addr); + dh->sect_size[si.section] = htonl(sl->size); + memcpy( dest, sl->data, sl->size ); + + //--- store original entry point + + memcpy(dest+OFF_ORIG_ENTRY,&dh->entry_addr,sizeof(u32)); + + //--- use relative entry point of new section + + if (new_entry) + dh->entry_addr = htonl(new_entry); + } + + + //--- final '.dol' section support + + if (dol_sect_offset) + { + //- refresh dol section + + PRINT("UPDATE RED-DOL\n"); + dol_header_t *dh = (dol_header_t*)str->data; + memcpy( str->data + dol_sect_offset, &dh->sect_addr, RED_DOL_SIZE ); + + //- update sections with 'use_param' + + for ( sect = 0; sect < n_section_list; sect++ ) + { + dol_sect_select_t *sl = section_list + sect; + PRINT("UPDATE sect %s [off=%x,param=%d] := %x\n", + sl->name, sl->offset+OFF_RDOL_ADDR, sl->use_param, dol_sect_addr ); + if ( sl->offset && sl->use_param ) + write_be32( str->data + sl->offset + OFF_RDOL_ADDR, dol_sect_addr ); + } + } + + return count; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +static uint PatchCTCODEDOL +( + staticr_t * str // valid pointer +) +{ + DASSERT(str); + DASSERT(str->data_size); + DASSERT(str->data); + DASSERT(str->is_dol); + + if (!opt_add_ctcode) + return 0; + + if (!(str->dol_status&DOL_S_ORIG)) + { + ERROR0(ERR_WARNING,"Can't add CT-CODE to modified DOL: %s\n",str->fname); + return 0; + } + + ct_dol_ext_t *ce = GetCtExtDOL(str->mode); + if (!ce) + { + ERROR0(ERR_WARNING,"Can't add CT-CODE: %s\n",str->fname); + return 0; + } + + BZ2Source_t *bs = &ce->t2_src; + SearchBZ2S(bs,ct_dir_list.field,ct_dir_list.used,SEA_LOG_OFF); + if ( !bs->data || !bs->size ) + { + missing_ctcode:; + ccp sem = strchr(bs->search,';'); + ERROR0(ERR_WARNING, + "Missing %.*s => Can't add CT-CODE: %s\n\n", + (int)( sem ? sem - bs->search : strlen(bs->search) ), + bs->search, str->fname ); + return 0; + } + + bs = &ce->d8_src; + SearchBZ2S(&ce->d8_src,ct_dir_list.field,ct_dir_list.used,SEA_LOG_OFF); + if ( !bs->data || !bs->size ) + goto missing_ctcode; + + const BZ2Source_t *t2 = &ce->t2_src; + const BZ2Source_t *d8 = &ce->d8_src; + + + //--- check data address + + bool move_d8 = opt_move_d8 || opt_sect_list.used; + u32 d8_addr = move_d8 ? 0x802a8000 : ce->d8_addr; + + dol_header_t *dh = (dol_header_t*)str->data; + if (CountOverlappedDolSections(dh,d8_addr,d8->size)) + { + move_d8 = true; + d8_addr = 0x802a8000; + if (CountOverlappedDolSections(dh,d8_addr,d8->size)) + { + ERROR0(ERR_WARNING,"No space for CTCODE/D8 section: %s\n",str->fname); + return 0; + } + } + + if (CountOverlappedDolSections(dh,ce->t2_addr,t2->size)) + { + ERROR0(ERR_WARNING,"No space for CTCODE/T2 section: %s\n",str->fname); + return 0; + } + + dol_sect_info_t t2info; + if (!FindFirstFreeDolSection(&t2info,dh,0)) + { + err2sect: + ERROR0(ERR_WARNING,"Need 2 unused sections for CTCODE: %s\n",str->fname); + return 0; + } + const int T_SECT = t2info.section; + dh->sect_size[T_SECT] = htonl(t2->size); // mark used for next search + + dol_sect_info_t d8info; + if (!FindFirstFreeDolSection(&d8info,dh,3)) + { + dh->sect_size[T_SECT] = htonl(0); + goto err2sect; + } + const int D_SECT = d8info.section; + + + //--- logging + + uint offset = str->data_size; + if ( verbose > 0 ) + { + fprintf(stdlog, + "- Create section %s [%08x..%08x], file offset 0x%06x, size 0x%x\n", + t2info.name, ce->t2_addr, + ce->t2_addr + t2->size, offset, t2->size ); + fprintf(stdlog, + "- Create section %s [%08x..%08x], file offset 0x%06x, size 0x%x\n", + d8info.name, ce->d8_addr, + ce->d8_addr + d8->size, offset + t2->size, d8->size ); + } + + + //--- assign data and add section + + str->data_size += t2->size + d8->size; + str->data = REALLOC(str->data,str->data_size); + dh = (dol_header_t*)str->data; + + PRINT("%s: off=%6x, addr=%8x, size=%6x\n",t2info.name,offset,ce->t2_addr,t2->size); + memcpy( str->data + offset, t2->data, t2->size ); + write_be32( str->data + offset + 0x14, d8_addr ); + dh->sect_off [T_SECT] = htonl(offset); + dh->sect_addr[T_SECT] = htonl(ce->t2_addr); + dh->sect_size[T_SECT] = htonl(t2->size); + + offset += t2->size; + PRINT("%s: off=%6x, addr=%8x, size=%6x\n",d8info.name,offset,ce->d8_addr,d8->size); + memcpy( str->data + offset, d8->data, d8->size ); + dh->sect_off [D_SECT] = htonl(offset); + dh->sect_addr[D_SECT] = htonl(d8_addr); + dh->sect_size[D_SECT] = htonl(d8->size); + + memcpy(&dh->entry_addr,t2->data+0x0c,4); + + ClearBZ2S(&ce->t2_src,1); + ClearBZ2S(&ce->d8_src,1); + str->dol_flags[DPF_CTCODE] = 'C'; + str->dol_info_flags |= DIF_CTCODE; + return 1; +} + +/////////////////////////////////////////////////////////////////////////////// + +uint PatchDOL +( + // returns: number of patches + + staticr_t * str // valid pointer +) +{ + DASSERT(str); + if (!str->data_size) + return 0; + DASSERT(str->data); + DASSERT(str->is_dol); + if (!str->is_dol) + return 0; + + uint clean_count = 0; + if ( opt_clean_dol && CleanDol(str) ) + clean_count++; + + if (!(str->dol_status&DOL_S_ANALYZED)) + AnalyzeDOL(str,false); + + InititializeGCT(); + if ( opt_wcode >= WCODE_ENABLED ) + { + if (wifi_domain_is_wiimmfi) + { + BZ2Manager_t *wcm = GetWiimmfiCode(str->mode); + if (wcm) + { + DecodeBZIP2Manager(wcm); + if ( opt_wcode == WCODE_GECKO ) + { + str->dol_flags[DPF_WCODE] = 'w'; + AddCheatCode(wcm->data,wcm->size,true,"WCODE"); + } + else + { + str->dol_flags[DPF_WCODE] = 'W'; + AddWCode(wcm->data,wcm->size); + } + } + } + + uint i; + for ( i = 0; i < opt_wcode_list.used; i++ ) + if (AddWCodeFile(str,opt_wcode_list.field[i])) + opt_wcode_list.field[i] = 0; + } + + uint patch_count = 0; + patch_count += PatchHTTPS(str); + patch_count += PatchCTCODEDOL(str); + patch_count += AddSectionsDOL(str,false); + patch_count += CreateSectionDOL(str); + patch_count += PatchByListWPF(str); + + if (use_gct_loader) + { + enumError err = SetupCodeLoader(str,0,0,0,0,CHT_NONE,0); + if ( err == ERR_OK || err == ERR_WARNING ) + patch_count++; + } + + + //-- sdkver by region + + if ( opt_str_vs_region >= 0 ) + { + const u32 vers_addr = GetSdkverAddress(str->mode); + if (vers_addr) + { + dol_header_t *dh = (dol_header_t*)str->data; + const u32 offset = GetDolOffsetByAddr(dh,vers_addr,8,0); + if (offset) + { + u8 old[8]; + memcpy(old,str->data+offset,sizeof(old)); + + char buf[20]; + snprintf(buf,sizeof(buf), "%05u", opt_str_vs_region & 0xffff); + memcpy(str->data+offset+1,buf,6); + if ( str->data[offset] == '0' ) + str->data[offset]++; + + if (memcmp(old,str->data+offset,sizeof(old))) + patch_count++; + } + } + } + + + //--- patch second host + + bool wiimmfi_patched = false; + if ( wifi_domain_is_wiimmfi || opt_wcode >= WCODE_ENABLED ) + { + u32 *h2 = GetSecondHostPointer(str,0); + noPRINT("h2=%p %x\n",h2,h2?ntohl(*h2):0); + if ( h2 && ntohl(*h2) != ASM_NOP ) + { + write_be32(h2,ASM_NOP); + patch_count++; + wiimmfi_patched = true; + } + } + + + //-- patched by + + patched_by_t pb_mode = patched_by_mode; + switch((int)pb_mode) + { + case PBY_WIIMMFI: + if (wiimmfi_patched) + pb_mode = PBY_ALWAYS; + break; + + case PBY_AUTO: + if (patch_count) + pb_mode = PBY_ALWAYS; + break; + } + + if ( pb_mode == PBY_RESET ) + { + char *dest = GetIdPointer(str); + if (dest) + memset(dest,'*',PATCHED_BY_SIZE); + } + else if ( pb_mode == PBY_ALWAYS ) + { + char *dest = GetIdPointer(str); + if (dest) + { + char *end = dest + PATCHED_BY_SIZE; + if (*str->dol_flags) + dest += snprintf( dest, PATCHED_BY_SIZE, "%.*s [%s]", + PATCHED_BY_SIZE - 3 - DPF__N, + opt_patched_by, str->dol_flags ); + else + dest = StringCopyE(dest,end,opt_patched_by); + while ( dest < end ) + *dest++ = ' '; + } + } + + return clean_count + patch_count; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// patch via WPF /////////////// +/////////////////////////////////////////////////////////////////////////////// + +uint PatchByListWPF +( + staticr_t *str // valid pointer +) +{ + DASSERT(str); + DASSERT(str->data_size); + DASSERT(str->data); + + uint i, count = 0; + for ( i = 0; i < opt_wpf_list.used; i++ ) + { + ccp fname = opt_wpf_list.field[i]; + if ( fname && *fname ) + { + const int stat = PatchByFileWPF(str,fname); + if ( stat < 0 ) + { + FreeString(opt_wpf_list.field[i]); + opt_wpf_list.field[i] = 0; + } + else if ( stat > 0 ) + count++; + } + } + + return count; +} + +/////////////////////////////////////////////////////////////////////////////// + +int PatchByFileWPF +( + staticr_t *str, // valid pointer + ccp fname +) +{ + DASSERT(str); + DASSERT(fname); + + + //--- load file + + u8 *data = 0; + uint size = 0; + if (OpenReadFILE(fname,0,true,&data,&size,0,0)) + { + ERROR0(ERR_WARNING,"Can't load WPF file: %s\n",fname); + return -1; + } + + + //--- analyse file + +// [[analyse-magic]] + const file_format_t fform = GetByMagicFF(data,size,size); + PRINT(">>> [%s,%u]: %s\n",GetNameFF(fform,0),size,fname); + bool done = false; + int stat = -1; + + if ( size > sizeof(wpf_head_t) && be32(data+4) <= size ) + { + wpf_t *wpf = (wpf_t*)(data+sizeof(wpf_head_t)); + if ( fform == FF_WPF ) + { + done = true; + stat = PatchByWPF( str, wpf, size-sizeof(wpf_head_t), fname ); + } + + #if HAVE_XSRC + if ( fform == FF_XPF ) + { + done = true; + stat = PatchByXPF( str, wpf, size-sizeof(wpf_head_t), fname ); + } + #endif + } + + if (!done) + ERROR0(ERR_WARNING,"Not a WPF file:: %s\n",fname); + FREE(data); + return stat; +} + +/////////////////////////////////////////////////////////////////////////////// + +int PatchByWPF +( + staticr_t *str, // valid pointer + const wpf_t *wpf, // wpf patch list + uint size, // size of data beginning at 'wpf' + ccp fname // filename for error messages +) +{ + DASSERT(str); + DASSERT(fname); + printf("PatchByWPF(): %s\n",fname); + + HexDump16(stdout,0,0,wpf, size < 32 ? size : 32); + return -1; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// options /////////////// +/////////////////////////////////////////////////////////////////////////////// + +bool opt_clean_dol = false; // true: remove additional DOL sections +bool opt_add_ctcode = false; // true: ad CT-CODE to main.dol +int opt_all_ranks = 0; // -1:off, 0:don't patch, 1:on +bool opt_move_d8 = false; // true: move CT-CODE D8 section to another place +bool opt_full_gch = false; // true: use full- of only- 'codehandler' + +bool opt_gct_scan_sep = true; // true: scan 'F0000001 0000xxxx' separators +bool opt_gct_sep = false; // true: search cheat code separators +bool opt_gct_asm_sep = false; // true: use beginning of ASM blocks as separator +uint opt_gct_list = false; // >0: print a summary / >1: be verbose +int opt_gct_move = OFFON_AUTO; // move GCT to heap +u32 opt_gct_addr = 0x802c0000; // address for opt_gct_move +u32 opt_gct_space = 0; // minimal code space for opt_gct_move +int opt_allow_user_gch = OFFON_AUTO; // allow user define Gecko Code Handler + +StringField_t opt_sect_list = {0}; // files with section data of type GCT|GCH|WCH +StringField_t opt_wpf_list = {0}; // files with patches of type WPF|XPF +StringField_t opt_wcode_list = {0}; // GCT files for wcode jobs + +int opt_str_vs_region = SREG_NONE; // versus region patch mode +bool opt_str_xvs_region = false; // true: patch also test offsets +bool opt_str_tvs_region = false; // true: enable test mode with incremented regions + +int opt_str_bt_region = SREG_NONE; // battle region patch mode +bool opt_str_xbt_region = false; // true: patch also test offsets +bool opt_str_tbt_region = false; // true: enable test mode with incremented regions + +bool opt_meno = false; // true: patch 'Menu*' to 'MenO*' + +/////////////////////////////////////////////////////////////////////////////// + +int ScanOptRegionHelper ( ccp arg, bool is_battle, ccp prefix ) +{ + region_info_t ri; + SetupRegionInfo(&ri,0,is_battle); + + DASSERT(ri.opt_region); + if ( !arg || !*arg ) + { + *ri.opt_region = SREG_NONE; + return 0; + } + + DASSERT(ri.opt_x); + *ri.opt_x = *arg == 'x' || *arg == 'X'; + if (*ri.opt_x) + arg++; + + DASSERT(ri.opt_t); + *ri.opt_t = ( *arg == 't' || *arg == 'T' ) && arg[1] >= '0' && arg[1] <= '9'; + if (*ri.opt_t) + arg++; + + if ( *arg >= '0' && *arg <= '9' ) + { + u32 num; + const enumError err = + ScanSizeOptU32( + &num, // u32 * num + arg, // ccp source + 1, // default_factor1 + 0, // int force_base + "region", // ccp opt_name + 0, // u64 min + 0xffff, // u64 max + 1, // u32 multiple + 0, // u32 pow2 + false // bool print_err + ); + + if ( err == ERR_OK ) + { + *ri.opt_region = num; + return 0; + } + } + + static const KeywordTab_t tab[] = + { + { SREG_JAPAN, "JAPAN", 0, 0 }, + { SREG_AMERICA, "AMERICA", "USA", 0 }, + { SREG_EUROPE, "EUROPE", 0, 0 }, + + { SREG_AUSTRALIA, "AUSTRALIA", "OCEANIA", 0 }, + { SREG_KOREA, "KOREA", 0, 0 }, + { SREG_TAIWAN, "TAIWAN", 0, 0 }, + { SREG_CHINA, "CHINA", 0, 0 }, + + { SREG_NONE, "NONE", 0, 0 }, + { SREG_RESTORE, "RESTORE", "NINTENDO", 0 }, + { SREG_TEST, "TEST", 0, 9001 }, + { 0,0,0,0 } + }; + + const KeywordTab_t * cmd = ScanKeyword(0,arg,tab); + if (cmd) + { + *ri.opt_region = cmd->id; + if ( *ri.opt_region == SREG_TEST ) + { + *ri.opt_region = cmd->opt; + *ri.opt_t = true; + } + return 0; + } + + ERROR0(ERR_SYNTAX,"Invalid `region' mode (option --%sregion): '%s'\n",prefix,arg); + return 1; +} + +/////////////////////////////////////////////////////////////////////////////// + +int ScanOptVersusRegion ( ccp arg ) +{ + return ScanOptRegionHelper(arg,false,"vs-"); +} + +/////////////////////////////////////////////////////////////////////////////// + +int ScanOptBattleRegion ( ccp arg ) +{ + return ScanOptRegionHelper(arg,true,"bt-"); +} + +/////////////////////////////////////////////////////////////////////////////// + +int ScanOptRegion ( ccp arg ) +{ + const int stat = ScanOptRegionHelper(arg,false,""); + + opt_str_bt_region = opt_str_vs_region; + opt_str_xbt_region = opt_str_xvs_region; + opt_str_tbt_region = opt_str_tvs_region; + if (opt_str_tbt_region) + opt_str_bt_region += N_TAB_VS_REGION_PATCH; + + return stat; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +int ScanOptAllRanks ( ccp arg ) +{ + if ( !arg || !*arg ) + { + opt_all_ranks = 1; + return 0; + } + + static const KeywordTab_t tab[] = + { + { -1, "RETORE", "NINTENDO", 0 }, + { -1, "RESET", 0, 0 }, // [obsolete]] in 2015 + { 0, "NONE", 0, 0 }, + { 1, "ON", 0, 0 }, + { 0,0,0,0 } + }; + + const KeywordTab_t * cmd = ScanKeyword(0,arg,tab); + if (cmd) + { + opt_all_ranks = cmd->id; + return 0; + } + + ERROR0(ERR_SYNTAX,"Invalid `all-ranks' mode (option --all-ranks): '%s'\n",arg); + return 1; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +const KeywordTab_t HttpsOptions[] = +{ + { HTTPS_NONE, "NONE", 0, 0 }, + { HTTPS_RESTORE, "RESTORE", "NINTENDO", 0 }, + { HTTPS_HTTP, "HTTP", 0, 0 }, + { HTTPS_DOMAIN, "DOMAIN", 0, 0 }, + { HTTPS_SAKE0, "SAKE0", "S0", 0 }, + { HTTPS_SAKE1, "SAKE1", "S1", 0 }, + { 0,0,0,0 } +}; + +https_mode_t opt_https; +bool opt_wc24 = false; +char mkw_domain[100] = "mariokartwii.gs.wiimmfi.de"; +ccp wifi_domain = mkw_domain + 16; +bool wifi_domain_is_wiimmfi = false; +wcode_t opt_wcode = WCODE_AUTO; + +/////////////////////////////////////////////////////////////////////////////// + +int ScanOptHttps ( ccp arg ) +{ + const KeywordTab_t *cmd = ScanKeyword(0,arg,HttpsOptions); + if (cmd) + { + opt_https = cmd->id; + return 0; + } + + ERROR0(ERR_SYNTAX,"Invalid mode for option --https: '%s'\n",arg); + return 1; +} + +/////////////////////////////////////////////////////////////////////////////// + +ccp GetHttpsName ( https_mode_t mode, ccp return_if_failed ) +{ + const KeywordTab_t *cmd; + for ( cmd = HttpsOptions; cmd->name1; cmd++ ) + if ( cmd->id == mode ) + return cmd->name1; + return return_if_failed; +} + +/////////////////////////////////////////////////////////////////////////////// + +int ScanOptDomain ( ccp https, ccp arg ) +{ + if (arg) + snprintf(mkw_domain,sizeof(mkw_domain),"mariokartwii.gs.%s",arg); + + int stat = https ? ScanOptHttps(https) : 0; + wifi_domain_is_wiimmfi = opt_https >= HTTPS_DOMAIN + && ( !strcmp(wifi_domain,"wiimmfi.de") + || !strcmp(wifi_domain,"test.wiimmfi.de") ); + return stat; +} + +/////////////////////////////////////////////////////////////////////////////// + +const KeywordTab_t wcode_keytab[] = +{ + { WCODE_OFF, "OFF", "0", 0 }, + { WCODE_AUTO, "AUTO", "DEFAULT", 0 }, + { WCODE_GECKO, "GECKO", "CHEAT", 0 }, + { WCODE_ON, "ON", "1", 0 }, + { 0,0,0,0 } +}; + +int ScanOptWCode ( ccp arg ) +{ + if (!arg) + { + opt_wcode = WCODE_ON; + return 0; + } + + int status; + const KeywordTab_t *key = ScanKeyword(&status,arg,wcode_keytab); + if (key) + { + opt_wcode = key->id; + return 0; + } + + PrintKeywordError(wcode_keytab,arg,status,0,"option --wcode"); + return 1; +} + +/////////////////////////////////////////////////////////////////////////////// + +int ScanOptPatchedBy ( ccp arg ) +{ + if (!*arg) + arg = ""; + + while ( *arg > 0 && *arg <= ' ' ) + arg++; + + if (!*arg) + StringCopyS(opt_patched_by,sizeof(opt_patched_by),STD_PATCHED_BY); + else if ( *arg == '+' ) + snprintf(opt_patched_by,sizeof(opt_patched_by), + "%s [%s]",STD_PATCHED_BY,arg+1); + else + StringCopyS(opt_patched_by,sizeof(opt_patched_by),arg); + + uchar *ptr; + for ( ptr = (uchar*)opt_patched_by; *ptr; ptr++ ) + if ( *ptr < ' ' || *ptr == 0xa0 ) + *ptr = ' '; + + noPRINT("< %s\n> %s\n",arg,opt_patched_by); + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +enum VsBtMode patch_vs_mode = VSBT_OFF; +enum VsBtMode patch_bt_mode = VSBT_OFF; +char patch_vs_str[2] = {0}; +char patch_bt_str[2] = {0}; + +int ScanOptVS ( bool is_bt, bool allow_2, ccp arg ) +{ + if (!arg) + return 0; + + ccp std_str; + char *str; + enum VsBtMode *mode; + if (is_bt) + { + std_str = "bt"; + str = patch_bt_str; + mode = &patch_bt_mode; + } + else + { + std_str = "vs"; + str = patch_vs_str; + mode = &patch_vs_mode; + } + + switch(strlen(arg)) + { + case 0: + *mode = VSBT_OFF; + return 0; + + case 1: + *mode = VSBT_PATCH; + str[0] = std_str[0]; + str[1] = arg[0]; + return 0; + + case 2: + if (allow_2) + { + *mode = VSBT_PATCH; + str[0] = arg[0]; + str[1] = arg[1]; + return 0; + } + break; + + case 4: + if (!strcasecmp(arg,"test")) + { + *mode = VSBT_TEST; + return 0; + } + break; + } + + if (allow_2) + ERROR0(ERR_SYNTAX,"Only 1 or 2 characters allowed for option --%s2: %s\n", + std_str, arg ); + else + ERROR0(ERR_SYNTAX,"Only 1 character allowed for option --%s: %s\n", + std_str, arg ); + return 1; +} + +/////////////////////////////////////////////////////////////////////////////// + +int ScanOptCannon ( ccp arg ) +{ + if ( !arg || !*arg ) + { + memset(cannon_param,0,sizeof(cannon_param)); + return 0; + } + + char *end; + uint index = str2ul(arg,&end,10); + if ( end == arg ) + return ERROR0(ERR_SYNTAX,"Option --cannon: Invalid argument: %s",arg); + if ( index >= CANNON_N ) + return ERROR0(ERR_SYNTAX,"Option --cannon: Invalid index: %d",index); + + cannon_param_t *cp = cannon_param + index; + memset(cp,0,sizeof(*cp)); + const u8 * orig = CannonDataLEX+4 + index * CANNON_SIZE; + uint i; + for ( i = 0; i < CANNON_N_PARAM; i++, orig += sizeof(float) ) + cp->param[i] = bef4(orig); + + for ( i = 0; i < CANNON_N_PARAM; i++ ) + { + arg = end; + while ( *arg == ' ' || *arg == '\t' || *arg == ',' ) + arg++; + double d = strtod(arg,&end); + if ( end == arg ) + break; + cp->param[i] = d; + } + if ( i > 0 ) + cp->valid = true; + + #if HAVE_PRINT + { + uint i; + cannon_param_t *cp = cannon_param; + for ( i = 0; i < CANNON_N; i++, cp++ ) + PRINT(">CANNON[%u]: valid=%d, %10f %10f %10f %10f\n", + i, cp->valid, cp->param[0], cp->param[1], cp->param[2], cp->param[3] ); + } + #endif + + return 0; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// Option --create-sect /////////////// +/////////////////////////////////////////////////////////////////////////////// + +dol_sect_select_t section_list[DOL_N_SECTIONS]; +uint n_section_list = 0; + +/////////////////////////////////////////////////////////////////////////////// + +int ScanOptGctMove ( ccp arg ) +{ + const int stat = ScanKeywordOffAutoOn(arg,OFFON_ON,OFFON_FORCE,"Option --gct-move"); + if ( stat == OFFON_ERROR ) + return 1; + + opt_gct_move = stat; + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +int ScanOptAllowUserGch ( ccp arg ) +{ + const int stat + = ScanKeywordOffAutoOn(arg,OFFON_ON,OFFON_FORCE,"Option --allow-user-gch"); + if ( stat == OFFON_ERROR ) + return 1; + + opt_allow_user_gch = stat; + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +int ScanOptGctAddr ( ccp arg ) +{ + return ScanSizeOptU32( + &opt_gct_addr, // u32 * num + arg, // ccp source + 1, // default_factor1 + 0, // int force_base + "gct-addr", // ccp opt_name + 0x00000000, // u64 min + 0x817fffff, // u64 max + 4, // u32 multiple + 0, // u32 pow2 + true // bool print_err + ) != ERR_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +int ScanOptGctSpace ( ccp arg ) +{ + return ScanSizeOptU32( + &opt_gct_space, // u32 * num + arg, // ccp source + 1, // default_factor1 + 0, // int force_base + "gct-space", // ccp opt_name + 0, // u64 min + 0x1000000, // u64 max + 4, // u32 multiple + 0, // u32 pow2 + true // bool print_err + ) != ERR_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +int ScanOptCreateSect ( ccp arg ) +{ + if ( !arg || !*arg ) + return 0; + + if ( n_section_list >= DOL_N_SECTIONS ) + { + ERROR0(ERR_SEMANTIC,"Section list for --create-sect is full.\n"); + return 1; + } + + + //--- check for 'P' + + ccp arg0 = arg; + bool use_param = *arg == 'P' || *arg == 'p'; + if (use_param) + { + arg++; + while ( *arg == ' ' || *arg == '\t' || *arg == ',' ) + arg++; + } + + + //--- check for 'T' 'D' 'T#' 'D#' + + int find_mode = 0, idx = -1; + if ( *arg == 'T' || *arg == 't' ) + { + find_mode = 1; + arg++; + if ( *arg >= '0' && *arg < '0' + DOL_N_TEXT_SECTIONS ) + idx = *arg++ - '0'; + } + else if ( *arg == 'D' || *arg == 'd' ) + { + find_mode = 2; + arg++; + if ( *arg >= '0' && *arg < '0' + DOL_N_DATA_SECTIONS ) + idx = *arg++ - '0' + DOL_N_TEXT_SECTIONS; + } + + if (find_mode) + { + ccp start = arg; + while ( *arg == ' ' || *arg == '\t' || *arg == ',' ) + arg++; + if ( arg == start && *arg != '=' ) + { + arg = arg0; + find_mode = 0; + idx = -1; + } + } + + //--- check for an addr + + char *end; + uint addr = str2ul(arg,&end,16); + if ( end > arg ) + { + arg = end; + if (addr) + addr |= 0x80000000; + } + else + addr = 0; + + if ( *arg != '=' ) + { + arg = arg0; + use_param = false; + find_mode = 0; + idx = -1; + addr = 0; + } + else + arg++; + + dol_sect_select_t *sl = section_list + n_section_list++; + memset(sl,0,sizeof(*sl)); + sl->find_mode = find_mode; + sl->sect_idx = idx; + sl->use_param = use_param; + sl->addr = addr; + sl->fname = arg; + + switch (sl->find_mode) + { + case 1: + sl->name[0] = 'T'; + sl->name[1] = sl->sect_idx < 0 ? '*' + : '0' + sl->sect_idx; + break; + + case 2: + sl->name[0] = 'D'; + sl->name[1] = sl->sect_idx < 0 ? '*' + : '0' + sl->sect_idx - DOL_N_TEXT_SECTIONS; + break; + + default: + sl->name[0] = '*'; + sl->name[1] = '*'; + break; + } + + PRINT("CREATE-SECTION[%s,%c]: %u,%2d %#10x : %s\n", + sl->name, sl->use_param ? 'W' : '-', + sl->find_mode, sl->sect_idx, sl->addr, sl->fname ); + + return 0; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// DumpSTR() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +enumError DumpSTR +( + FILE * f, // dump to this file + int indent, // indention + staticr_t * str, // valid pointer + bool use_c // true: print in C language fragments +) +{ + DASSERT(f); + DASSERT(str); + + if (str->is_dol) + return DumpDOL(f,indent,str,use_c); + + DASSERT(str->data); + DASSERT( str->data_size >= sizeof(rel_header_t) ); + + indent = NormalizeIndent(indent); + + + //----- dump header + + rel_header_t hd; + be32n( (u32*)&hd, (u32*)str->data, sizeof(rel_header_t)/sizeof(u32) ); + + ccp mod_name = "-"; + if ( hd.mod_name && hd.mod_name + hd.mod_name_len < str->data_size ) + mod_name = (ccp)str->data + hd.mod_name; + + + fprintf(f,"%*sId: %6u = 0x%x\n", indent,"", hd.id, hd.id ); + fprintf(f,"%*sN(sections): %6u\n", indent,"", hd.n_section ); + fprintf(f,"%*sModule Name: %6s\n", indent,"", mod_name ); + fprintf(f,"%*sReloc Offset: %6x\n", indent,"", hd.reloc_off ); + + fprintf(f,"\n%*sSection (0..%u):\n", indent,"", hd.n_section-1 ); + rel_sect_info_t *si = (rel_sect_info_t*)( str->data + hd.section_off ); + uint s; + for ( s = 0; s < hd.n_section; s++, si++ ) + { + u32 size = be32(&si->size); + if (size) + { + u32 offset = be32(&si->offset); + if (!offset) + fprintf(f,"%*s%4u. BSS %7x\n", indent,"", s, size ); + else + { + ccp type = offset & 1 ? "TEXT" : "DATA"; + offset &= ~1; + fprintf(f,"%*s%4u. %s %7x : %6x .. %6x\n", + indent,"", s, type, size, offset, offset + size - 1 ); + } + } + } + + return ERR_OK; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// DumpDOL() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +static enumError DumpDOL_c +( + FILE * f, // dump to this file + staticr_t * str // valid pointer +) +{ + DASSERT(f); + DASSERT(str); + DASSERT(str->data); + DASSERT( str->data_size >= sizeof(dol_header_t) ); + + dol_header_t dol; + if ( str->data_size < sizeof(dol) ) + return ERR_WARNING; + ntoh_dol_header(&dol,(dol_header_t*)str->data); + + fputs("\nstatic const dol_sect_info_t dol_info_xxx[DOL_NN_SECTIONS] =\n{\n",f); + char name[8]; + + uint sect; + for ( sect = 0; sect < DOL_NN_SECTIONS; sect++ ) + { + dol_sect_info_t info; + GetSectionDOL(str,&info,sect,true); + snprintf(name,sizeof(name),"\"%s\",",info.name); + fprintf(f," { %2u, %-7s%#8x, %#10x, %#8x, %u,0,%u, 0,", + sect, name, info.off, info.addr, info.size, + info.sect_valid, info.hash_valid ); + + if (info.hash_valid) + { + u8 *ptr = info.hash; + uint line; + for ( line = 0; line < 2; line++ ) + { + ccp sep = line ? ",\n\t\t " : "\n\t\t{ "; + uint idx; + for ( idx = 0; idx < sizeof(info.hash)/2; idx++ ) + { + fprintf(f,"%s%s0x%02x",sep, idx==sizeof(info.hash)/4 ? " " : "", *ptr++ ); + sep = ","; + } + } + fputs(" }},\n",f); + } + else + fputs(" {0} },\n",f); + } + + fputs("};\n\n",f); + return ERR_OK; +} + +/////////////////////////////////////////////////////////////////////////////// + +enumError DumpDOL +( + FILE * f, // dump to this file + int indent, // indention + staticr_t * str, // valid pointer + bool use_c // true: print in C language fragments +) +{ + DASSERT(f); + DASSERT(str); + + if (use_c) + return DumpDOL_c(f,str); + + DASSERT(str->data); + DASSERT( str->data_size >= sizeof(dol_header_t) ); + + DumpDolHeader( f, indent, (dol_header_t*)str->data, str->data_size, + long_count > 1 ? 7 : long_count > 0 ? 3 : 1 ); + return ERR_OK; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// ExtractSTR() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +enumError ExtractSTR +( + staticr_t * str, // valid pointer + ccp dest_dir // valid destination directory +) +{ + DASSERT(str); + DASSERT(str->data); + DASSERT(dest_dir); + + if (str->is_dol) + return ExtractDOL(str,dest_dir); + + return ERROR0(ERR_WARNING, + "Extraction of StaticR.rel files is not implemented yet!\n"); +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// ExtractDOL() /////////////// +/////////////////////////////////////////////////////////////////////////////// + +enumError ExtractDOL +( + staticr_t * str, // valid pointer + ccp dest_dir // valid destination directory +) +{ + DASSERT(str); + DASSERT(str->data); + DASSERT(str->is_dol); + DASSERT(dest_dir); + + CreatePath(dest_dir,true); + + //--- open log file + + char path_buf[PATH_MAX]; + ccp path = PathCatPP(path_buf,sizeof(path_buf),dest_dir,"dol-setup.txt"); + FILE *log = fopen(path,"wb"); + if (!log) + return ERROR0(ERR_CANT_CREATE, + "Can't create setup file: %s\n",path); + + static ccp sep = "#---------------------------------------------------------------------\n"; + fprintf(log,"\n%s#sect offset address size sha1 checksum\n%s",sep,sep); + + + //--- extract 'dol-header.bin' + + path = PathCatPP(path_buf,sizeof(path_buf),dest_dir,"dol-header.bin"); + FILE *f = fopen(path,"wb"); + if (!f) + { + fclose(log); + return ERROR0(ERR_CANT_CREATE, + "Can't create data file: %s\n",path); + } + fwrite(str->data,1,0x100,f); + fclose(f); + + + //--- extract sections + + uint sect; + for ( sect = 0; sect < DOL_NN_SECTIONS; sect++ ) + { + if ( sect == DOL_N_TEXT_SECTIONS || sect == DOL_N_SECTIONS ) + fputs(sep,log); + dol_sect_info_t info; + GetSectionDOL(str,&info,sect,true); + if (!info.sect_valid) + { + //fprintf(log,"%-4s= -\n",info.name); + continue; + } + + fprintf(log,"%-4s= %06x %08x %06x",info.name,info.off,info.addr,info.size); + if (info.data_valid) + { + if (info.hash_valid) + { + fputc(' ',log); + uint i; + for ( i = 0; i < sizeof(info.hash); i++ ) + fprintf(log,"%02x",info.hash[i]); + } + + path = PathCatPPE(path_buf,sizeof(path_buf),dest_dir,info.name,".bin"); + FILE *f = fopen(path,"wb"); + if (!f) + { + fclose(log); + return ERROR0(ERR_CANT_CREATE, + "Can't create data file: %s\n",path); + } + fwrite(info.data,1,info.size,f); + fclose(f); + } + fputc('\n',log); + } + fputs(sep,log); + + + //--- close log and return + + fprintf(log,"\n"); + fclose(log); + return ERR_OK; +} + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// ctcode_data_tab[] /////////////// +/////////////////////////////////////////////////////////////////////////////// + +#undef DEF_DATA +#undef DEF_BZIP +//#undef DEF_PATCH + +#define DEF_DATA(a) { #a, 0, a, sizeof(a) }, +#define DEF_BZIP(a) { #a, 1, a##_bz2, sizeof(a##_bz2) }, +//#define DEF_PATCH(m,a,b) { #a, m, b, sizeof(b), a }, + +const data_tab_t maindol_data_tab[] = +{ + DEF_BZIP(ctcode_boot_code_pal) + DEF_BZIP(ctcode_boot_code_usa) + DEF_BZIP(ctcode_boot_code_jap) + + DEF_BZIP(ctcode_boot_data_pal) + DEF_BZIP(ctcode_boot_data_usa) + DEF_BZIP(ctcode_boot_data_jap) + + DEF_BZIP(codehandler) + DEF_BZIP(codehandleronly) + + {0,0,0} +}; + +#undef DEF_DATA +#undef DEF_BZIP +//#undef DEF_PATCH + +// +/////////////////////////////////////////////////////////////////////////////// +/////////////// END /////////////// +/////////////////////////////////////////////////////////////////////////////// + -- cgit v1.3.1