From 0d5bf9a14ed76a15d3757485bfebfeae71a3baa5 Mon Sep 17 00:00:00 2001 From: N2614 Date: Wed, 22 Feb 2012 02:25:50 +0000 Subject: [PATCH] =?UTF-8?q?UIG=E8=A3=BD=E3=81=AE=E3=82=B3=E3=83=BC?= =?UTF-8?q?=E3=83=89=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@651 385bec56-5757-e545-9c3a-d8741f4650f1 --- .../idb/include/CTR_LegacyData.h | 645 +++++ trunk/SkipFirstLaunch/idb/include/CtrIcon.h | 55 + trunk/SkipFirstLaunch/idb/include/IDB.h | 227 ++ trunk/SkipFirstLaunch/idb/include/IDBUT.h | 76 + trunk/SkipFirstLaunch/idb/include/IDBi.h | 117 + trunk/SkipFirstLaunch/idb/src/IDB.cpp | 82 + trunk/SkipFirstLaunch/idb/src/IDBUT.cpp | 724 +++++ trunk/SkipFirstLaunch/idb/src/IDBi.cpp | 926 +++++++ trunk/SkipFirstLaunch/syokaikidou.cpp | 96 + trunk/SkipFirstLaunch/sysFile.cpp | 927 +++++++ trunk/SkipFirstLaunch/sysFile.h | 102 + trunk/SkipFirstLaunch/sysInput.cpp | 212 ++ trunk/SkipFirstLaunch/sysInput.h | 159 ++ .../SkipFirstLaunch/sysSharedExtSaveData.cpp | 286 ++ trunk/SkipFirstLaunch/sysSharedExtSaveData.h | 43 + trunk/SkipFirstLaunch/sysUserInfoAccessor.cpp | 2462 +++++++++++++++++ trunk/SkipFirstLaunch/sysUserInfoAccessor.h | 522 ++++ 17 files changed, 7661 insertions(+) create mode 100644 trunk/SkipFirstLaunch/idb/include/CTR_LegacyData.h create mode 100644 trunk/SkipFirstLaunch/idb/include/CtrIcon.h create mode 100644 trunk/SkipFirstLaunch/idb/include/IDB.h create mode 100644 trunk/SkipFirstLaunch/idb/include/IDBUT.h create mode 100644 trunk/SkipFirstLaunch/idb/include/IDBi.h create mode 100644 trunk/SkipFirstLaunch/idb/src/IDB.cpp create mode 100644 trunk/SkipFirstLaunch/idb/src/IDBUT.cpp create mode 100644 trunk/SkipFirstLaunch/idb/src/IDBi.cpp create mode 100644 trunk/SkipFirstLaunch/syokaikidou.cpp create mode 100644 trunk/SkipFirstLaunch/sysFile.cpp create mode 100644 trunk/SkipFirstLaunch/sysFile.h create mode 100644 trunk/SkipFirstLaunch/sysInput.cpp create mode 100644 trunk/SkipFirstLaunch/sysInput.h create mode 100644 trunk/SkipFirstLaunch/sysSharedExtSaveData.cpp create mode 100644 trunk/SkipFirstLaunch/sysSharedExtSaveData.h create mode 100644 trunk/SkipFirstLaunch/sysUserInfoAccessor.cpp create mode 100644 trunk/SkipFirstLaunch/sysUserInfoAccessor.h diff --git a/trunk/SkipFirstLaunch/idb/include/CTR_LegacyData.h b/trunk/SkipFirstLaunch/idb/include/CTR_LegacyData.h new file mode 100644 index 0000000..6f327e6 --- /dev/null +++ b/trunk/SkipFirstLaunch/idb/include/CTR_LegacyData.h @@ -0,0 +1,645 @@ +/*---------------------------------------------------------------------------* + Project: Horizon + File: CTR_LgyData.h + + Copyright (C)2010 Nintendo Co., Ltd. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Rev$ + *---------------------------------------------------------------------------*/ +#ifndef CTR_LGYDATA_H_ +#define CTR_LGYDATA_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +namespace nn { namespace CTR { + +#define NN_CTR_ROMHEADER_CORP_ID "NINTENDO " +#define NN_CTR_TITLE_NAME_MAX 12 +#define NN_CTR_GAME_CODE_MAX 4 +#define NN_CTR_MAKER_CODE_MAX 2 + +#define NN_CTR_DIGEST_SIZE_SHA1 20 +#define NN_CTR_NINTENDO_LOGO_DATA_LENGTH 0x9c +#define NN_CTR_PARENTAL_CONTROL_INFO_SIZE 0x10 + + +/*===========================================================================* + * ROM FORMAT + *===========================================================================*/ + +// ROM access control info +typedef struct LegacyRomAccessControl { + u32 common_client_key :1; // launcher deliver common client Key + u32 hw_aes_slot_B :1; // launcher deliver HW AES slot B setting for ES + u32 hw_aes_slot_C :1; // launcher deliver HW AES slot C setting for NAM + u32 sd_card_access :1; // sd card access control + u32 nand_access :1; // NAND access control + u32 game_card_on :1; // NANDアプリでゲームカード電源ON(ノーマルモード) + u32 shared2_file :1; // shared file in "nand:/shared2" + u32 hw_aes_slot_B_SignJPEGForLauncher :1; // launcher deliver HW AES slot B setting for Sign JPEG for Launcher + u32 game_card_nitro_mode :1; // NANDアプリでゲームカードNTR互換領域へアクセス + u32 hw_aes_slot_A_SSLClientCert :1; // launcher deliver HW AES slot A setting for SSL Client Certificate + u32 hw_aes_slot_B_SignJPEGForUser :1; // launcher deliver HW AES slot B setting for Sign JPEG for User + u32 photo_access_read :1; // "photo:" archive read-access control + u32 photo_access_write :1; // "photo:" archive write-access control + u32 sdmc_access_read :1; // "sdmc:" archive read-access control + u32 sdmc_access_write :1; // "sdmc:" archive write-access control + u32 backup_access_read :1; // CARD-backup read-access control + u32 backup_access_write :1; // CARD-backup write-access control + u32: 14; + u32 common_client_key_for_debugger_sysmenu :1; // launcher deliver common client Key +} LegacyRomAccessControl; + +// ROM expansion flags +typedef struct LegacyRomExpansionFlags { + u8 codec_mode:1; // 0:NTR mode, 1:TWL mode // undeveloped + u8 agree_EULA:1; // 1: necessary agree EULA + u8 availableSubBannerFile:1; // 1: Available SubBannerFile + u8 WiFiConnectionIcon :1; // 1: WiFiConnectionをランチャーで表示 + u8 DSWirelessIcon :1; // 1: DSWirelessIconをランチャーで表示 + u8 rsv_d5:1; + u8 enable_nitro_whitelist_signature :1; // 1: NITROホワイトリスト署名有効フラグ + u8 developer_encrypt:1; // 1: 開発用セキュリティがかかっている場合に"1"。製品版では"0" (※TwlSDK UIG_branch/RC2以降はこちらが有効) +} LegacyRomExpansionFlags; + +//--------------------------------------------------------------------------- +// Section A ROM HEADER +//--------------------------------------------------------------------------- + +typedef struct LegacyRomHeader +{ + //========================================================== + // + // NTR/TWL common + // + //========================================================== + + // + // 0x000 System Reserved + // + char title_name[NN_CTR_TITLE_NAME_MAX]; // Soft title name + char game_code[NN_CTR_GAME_CODE_MAX]; // Game code + char maker_code[NN_CTR_MAKER_CODE_MAX]; // Maker code + char platform_code; // Platform code bit0: not support NTR, bit1: support TWL ( NTR_only=0x00, NTR/TWL=0x03, TWL_only=0x02 ) + u8 rom_type; // Rom type + u8 rom_size; // Rom size (2のrom_size乗 Mbit: ex. 128Mbitのときrom_size = 7) + + u8 reserved_A[7]; // System Reserved A ( Set ALL 0 ) + + u8 enable_signature:1; // enable ROM Header signature + u8 enable_aes:1; // enable AES encryption + u8 developer_encrypt_old:1; // 開発用セキュリティがかかっている場合に"1"。製品版では"0" (※TwlSDK RC plusまではこちらが有効) + u8 disable_debug:1; // デバッグ禁止フラグ + u8: 4; + + u8 permit_landing_normal_jump:1; // アプリジャンプのノーマルジャンプで呼び出されることを許可する( for TWL Application Jump ) + u8 permit_landing_tmp_jump:1; // アプリジャンプのTMPジャンプで呼び出されることを許可する( for TWL Application Jump ) + // ※NTR体験版アプリはDSダウンロードプレイの署名しかついていないので、このフラグはNTR-ROMヘッダの0x160bytes内の領域に格納する必要がある。 + u8: 4; + u8 for_korea:1; // For Korea + u8 for_china:1; // For China + + u8 rom_version; // Rom version + + u8 comp_arm9_boot_area:1; // Compress arm9 boot area + u8 comp_arm7_boot_area:1; // Compress arm7 boot area + u8 inspect_card:1; // Show inspect card + u8 disable_clear_memory_pad:1; // for Debugger + u8 enable_twl_rom_cache_read:1; // Enable TWL ROM cacheRead command + u8 :1; // reserved. + u8 warning_no_spec_rom_speed:1;// Warning not to specify rom speed + u8 disable_detect_pull_out:1; // Decect CARD removal by checking ROM-ID + + // + // 0x020 for Static modules (Section:B) + // + // ARM9 + u32 main_rom_offset; // ROM offset + void *main_entry_address; // Entry point + void *main_ram_address; // RAM address + u32 main_size; // Module size + + // ARM7 + u32 sub_rom_offset; // ROM offset + void *sub_entry_address; // Entry point + void *sub_ram_address; // RAM address + u32 sub_size; // Module size + + // + // 0x040 for File Name Table[FNT] (Section:C) + // + struct ROM_FNT *fnt_offset; // ROM offset + u32 fnt_size; // Table size + + // + // 0x048 for File Allocation Table[FAT] (Section:E) + // + struct ROM_FAT *fat_offset; // ROM offset + u32 fat_size; // Table size + + // + // 0x050 for Overlay Tables[OVT] (Section:D) + // + // ARM9 + struct ROM_OVT *main_ovt_offset; // ROM offset + u32 main_ovt_size; // Table size + + // ARM7 + struct ROM_OVT *sub_ovt_offset; // ROM offset + u32 sub_ovt_size; // Table size + + // 0x060 for ROM control parameter (Section:F) + u32 game_cmd_param; // Game command parameter + u32 secure_cmd_param; // Secure command parameter + + u32 banner_offset; // Banner ROM offset + + u16 secure_area_crc16; // Secure area CRC-16 + u16 secure_cmd_latency; // Secure command latency ((param+2)*256 system cycles) + + // since NITRO-SDK 2.0PR4 + void *main_autoload_done; // ARM9 autoload done callback address (debug purpose) + void *sub_autoload_done; // ARM7 autoload done callback address (debug purpose) + + u8 ctrl_reserved_B[8]; // Ctrl Reserved B (Set 0) + + // since NITRO-SDK 2.0PR6 + u32 rom_valid_size; // ROM Original Size + u32 rom_header_size; // ROM Header size + u32 main_module_param_offset; // Offset for table of ARM9 module parameters + u32 sub_module_param_offset; // Offset for table of ARM7 module parameters + + // 0x090 - 0x0C0 System Reserved + u16 twl_card_normal_area_rom_offset; // undeveloped + u16 twl_card_keytable_area_rom_offset; // undeveloped + u16 nand_card_dl_area_rom_offset; // undeveloped + u16 nand_card_bk_area_rom_offset; // undeveloped + u8 nand_card_flag; // undeveloped + u8 reserved_B[39]; + + // 0x0C0 for NINTENDO logo data + u8 nintendo_logo[ NN_CTR_NINTENDO_LOGO_DATA_LENGTH ]; // NINTENDO logo data + u16 nintendo_logo_crc16; // CRC-16 + + // 0x15E ROM header CRC-16 + u16 header_crc16; // ROM header CRC-16 + + // 0x160 - 0x180 Debugger Reserved + u8 reserved_C[32]; // Debugger Reserved (Set ALL 0) + + //========================================================== + // + // TWL only + // + //========================================================== + + // 0x180 - 0x190 TWL-WRAM A/B/C ARM9 configuration data + u32 main_wram_config_data[8]; // developing... + + // 0x1A0 - 0x1B0 TWL-WRAM A/B/C ARM7 configuration data + u32 sub_wram_config_data[4]; // developing... + + // 0x1B0 - Card Region bitmap + u32 card_region_bitmap; + + // 0x1B4 - AccessControl + LegacyRomAccessControl access_control; + /* 注意: fatfs_command.c 内で 0x01b4 のアドレスを + ハードコーディングしています。 このメンバのオフセットを変更しないで下さい。 */ + + // 0x1B8 - ARM7-SCFG + u32 arm7_scfg_ext; // SCFG-EXT + + // padding(3byte) + u8 reserved_ltd_A2[ 3 ]; + + // 0x1BF - TWL expansion flags + LegacyRomExpansionFlags exFlags; + + // 0x1C0 for EX Static modules + // + // ARM9 + u32 main_ltd_rom_offset; // ROM offset // undeveloped + u8 reserved_ltd_B[ 4 ]; + void *main_ltd_ram_address; // RAM address // undeveloped // + u32 main_ltd_size; // Module size // undeveloped // + + // ARM7 + u32 sub_ltd_rom_offset; // ROM offset // undeveloped + void *sub_mount_info_ram_address; // ARM7 MountInfo RAM address. + void *sub_ltd_ram_address; // RAM address // undeveloped // + u32 sub_ltd_size; // Module size // undeveloped // + /* 注意: os_reset.c / crt0.HYB.c / crt0.LTD.c 内で 0x01c0 ~ 0x01e0 のアドレスを + ハードコーディングしています。 これら8つのメンバのオフセットを変更しないで下さい。 */ + + // 0x01E0 - 0x01E8 for NITRO digest area offset & size + u32 nitro_digest_area_rom_offset; + u32 nitro_digest_area_size; + + // 0x01E8 - 0x01F0 for TWL digest area offset & size + u32 twl_digest_area_rom_offset; + u32 twl_digest_area_size; + + // 0x01F0 - 0x01F8 for FS digest table1 offset & size + u32 digest1_table_offset; + u32 digest1_table_size; + + // 0x01F8 - 0x0200 for FS digest table2 offset & size + u32 digest2_table_offset; + u32 digest2_table_size; + + // 0x0200 - 0x0208 for FS digest config parameters + u32 digest1_block_size; + u32 digest2_covered_digest1_num; + + // 0x0208 - 0x020C for TWL banner size. + u32 banner_size; + + // 0x020C - 0x020E for shared2 files size + u8 shared2_file0_size; // shared2 file [0] + u8 shared2_file1_size; // shared2 file [1] + /* 注意: fatfs_command.c 内で 0x020C-0x020D のアドレスを + ハードコーディングしています。 このメンバのオフセットを変更しないで下さい。 */ + + // 0x020E for Agree EULA version + u8 agree_EULA_version; + + // 0x020F TWL Administration flags + u8 unnecessary_rating_display:1; // レーティング表記がいらないROMのときに立てる(管理用:ランチャーでは不使用) + u8: 7; + + // 0x0210 - 0x0214 for TWL rom valid size + u32 twl_rom_valid_size; // ROM Original Size + + // 0x0214 - 0x0218 for shared2 files size + u8 shared2_file2_size; // shared2 file [2] + u8 shared2_file3_size; // shared2 file [3] + u8 shared2_file4_size; // shared2 file [4] + u8 shared2_file5_size; // shared2 file [5] + /* 注意: fatfs_command.c 内で 0x0214 - 0x0217 のアドレスを + ハードコーディングしています。 このメンバのオフセットを変更しないで下さい。 */ + + // 0x0218 - 0x0220 for TWL ltd module param offset + u32 main_ltd_module_param_offset; // Offset for table of ARM9 ltd module parameters + u32 sub_ltd_module_param_offset; // Offset for table of ARM7 ltd module parameters + + // 0x0220 - 0x0230 for AES target offset & size + u32 aes_target_rom_offset; + u32 aes_target_size; + u32 aes_target2_rom_offset; // 予約 + u32 aes_target2_size; // 予約 + + // 0x0230 - 0x0238 for TitleID + union { + u64 titleID; +// struct { + u8 titleID_Lo[ 4 ]; +// u32 titleID_Hi; +// }; + }; + /* 注意: os_reset.c / crt0.HYB.c / crt0.LTD.c / fatfs_command.c 内で 0x0234 をハードコーディングしています。 + titleID_Hi のオフセットを変更しないで下さい。 */ + + // 0x0238 - 0x0240 for Public & Private Save Data Size + u32 public_save_data_size; + u32 private_save_data_size; + + // 0x0240 - 0x02f0 reserved. + u8 reserved_ltd_F[ 0x2f0 - 0x240 ]; + + // 0x02f0 - 0x0300 Parental Controls Rating Info + u8 parental_control_rating_info[ NN_CTR_PARENTAL_CONTROL_INFO_SIZE ]; + + // 0x0300 - 0x0378 Rom Segment Digest + u8 main_static_digest[ NN_CTR_DIGEST_SIZE_SHA1 ]; + u8 sub_static_digest[ NN_CTR_DIGEST_SIZE_SHA1 ]; + u8 digest2_table_digest[ NN_CTR_DIGEST_SIZE_SHA1 ]; + u8 banner_digest[ NN_CTR_DIGEST_SIZE_SHA1 ]; + u8 main_ltd_static_digest[ NN_CTR_DIGEST_SIZE_SHA1 ]; + u8 sub_ltd_static_digest[ NN_CTR_DIGEST_SIZE_SHA1 ]; + +} LegacyRomHeader; + + +// include\nn\drivers\card\CTR\ARM946ES\extra.h を移植 --------------------------------------------------- + +#define NN_CTR_SDK_128M + +/* MC1 */ + +#define NN_CTR_REG_MI_MC1_CC_SHIFT 16 +#define NN_CTR_REG_MI_MC1_CC_SIZE 16 +#define NN_CTR_REG_MI_MC1_CC_MASK 0xffff0000 + +#define NN_CTR_REG_MI_MC1_SWP_SHIFT 15 +#define NN_CTR_REG_MI_MC1_SWP_SIZE 1 +#define NN_CTR_REG_MI_MC1_SWP_MASK 0x00008000 + +#define NN_CTR_REG_MI_MC1_SL2_STATUS_SHIFT 4 +#define NN_CTR_REG_MI_MC1_SL2_STATUS_SIZE 4 +#define NN_CTR_REG_MI_MC1_SL2_STATUS_MASK 0x000000f0 + +#define NN_CTR_REG_MI_MC1_SL2_M1_SHIFT 7 +#define NN_CTR_REG_MI_MC1_SL2_M1_SIZE 1 +#define NN_CTR_REG_MI_MC1_SL2_M1_MASK 0x00000080 + +#define NN_CTR_REG_MI_MC1_SL2_M0_SHIFT 6 +#define NN_CTR_REG_MI_MC1_SL2_M0_SIZE 1 +#define NN_CTR_REG_MI_MC1_SL2_M0_MASK 0x00000040 + +#define NN_CTR_REG_MI_MC1_SL2_CDET_SHIFT 4 +#define NN_CTR_REG_MI_MC1_SL2_CDET_SIZE 1 +#define NN_CTR_REG_MI_MC1_SL2_CDET_MASK 0x00000010 + +#define NN_CTR_REG_MI_MC1_SL1_STATUS_SHIFT 0 +#define NN_CTR_REG_MI_MC1_SL1_STATUS_SIZE 4 +#define NN_CTR_REG_MI_MC1_SL1_STATUS_MASK 0x0000000f + +#define NN_CTR_REG_MI_MC1_SL1_M1_SHIFT 3 +#define NN_CTR_REG_MI_MC1_SL1_M1_SIZE 1 +#define NN_CTR_REG_MI_MC1_SL1_M1_MASK 0x00000008 + +#define NN_CTR_REG_MI_MC1_SL1_M0_SHIFT 2 +#define NN_CTR_REG_MI_MC1_SL1_M0_SIZE 1 +#define NN_CTR_REG_MI_MC1_SL1_M0_MASK 0x00000004 + +#define NN_CTR_REG_MI_MC1_SL1_CDET_SHIFT 0 +#define NN_CTR_REG_MI_MC1_SL1_CDET_SIZE 1 +#define NN_CTR_REG_MI_MC1_SL1_CDET_MASK 0x00000001 + +#ifndef SDK_ASM +#define NN_CTR_REG_MI_MC1_FIELD( cc, swp, sl2_status, sl2_m1, sl2_m0, sl2_cdet, sl1_status, sl1_m1, sl1_m0, sl1_cdet ) \ + (u32)( \ + ((u32)(cc) << NN_CTR_REG_MI_MC1_CC_SHIFT) | \ + ((u32)(swp) << NN_CTR_REG_MI_MC1_SWP_SHIFT) | \ + ((u32)(sl2_status) << NN_CTR_REG_MI_MC1_SL2_STATUS_SHIFT) | \ + ((u32)(sl2_m1) << NN_CTR_REG_MI_MC1_SL2_M1_SHIFT) | \ + ((u32)(sl2_m0) << NN_CTR_REG_MI_MC1_SL2_M0_SHIFT) | \ + ((u32)(sl2_cdet) << NN_CTR_REG_MI_MC1_SL2_CDET_SHIFT) | \ + ((u32)(sl1_status) << NN_CTR_REG_MI_MC1_SL1_STATUS_SHIFT) | \ + ((u32)(sl1_m1) << NN_CTR_REG_MI_MC1_SL1_M1_SHIFT) | \ + ((u32)(sl1_m0) << NN_CTR_REG_MI_MC1_SL1_M0_SHIFT) | \ + ((u32)(sl1_cdet) << NN_CTR_REG_MI_MC1_SL1_CDET_SHIFT)) +#endif + +/* MC */ + +#define NN_CTR_REG_MI_MC_SWP_SHIFT 15 +#define NN_CTR_REG_MI_MC_SWP_SIZE 1 +#define NN_CTR_REG_MI_MC_SWP_MASK 0x8000 + +#define NN_CTR_REG_MI_MC_SL2_MODE_SHIFT 6 +#define NN_CTR_REG_MI_MC_SL2_MODE_SIZE 2 +#define NN_CTR_REG_MI_MC_SL2_MODE_MASK 0x00c0 + +#define NN_CTR_REG_MI_MC_SL2_CDET_SHIFT 4 +#define NN_CTR_REG_MI_MC_SL2_CDET_SIZE 1 +#define NN_CTR_REG_MI_MC_SL2_CDET_MASK 0x0010 + +#define NN_CTR_REG_MI_MC_SL1_MODE_SHIFT 2 +#define NN_CTR_REG_MI_MC_SL1_MODE_SIZE 2 +#define NN_CTR_REG_MI_MC_SL1_MODE_MASK 0x000c + +#define NN_CTR_REG_MI_MC_SL1_CDET_SHIFT 0 +#define NN_CTR_REG_MI_MC_SL1_CDET_SIZE 1 +#define NN_CTR_REG_MI_MC_SL1_CDET_MASK 0x0001 + +#ifndef SDK_ASM +#define NN_CTR_REG_MI_MC_FIELD( swp, sl2_mode, sl2_cdet, sl1_mode, sl1_cdet ) \ + (u16)( \ + ((u32)(swp) << NN_CTR_REG_MI_MC_SWP_SHIFT) | \ + ((u32)(sl2_mode) << NN_CTR_REG_MI_MC_SL2_MODE_SHIFT) | \ + ((u32)(sl2_cdet) << NN_CTR_REG_MI_MC_SL2_CDET_SHIFT) | \ + ((u32)(sl1_mode) << NN_CTR_REG_MI_MC_SL1_MODE_SHIFT) | \ + ((u32)(sl1_cdet) << NN_CTR_REG_MI_MC_SL1_CDET_SHIFT)) +#endif + +/* EXMEMCNT_L */ + +#define NN_CTR_REG_MI_EXMEMCNT_L_EP_SHIFT 15 +#define NN_CTR_REG_MI_EXMEMCNT_L_EP_SIZE 1 +#define NN_CTR_REG_MI_EXMEMCNT_L_EP_MASK 0x8000 + +#define NN_CTR_REG_MI_EXMEMCNT_L_EMODE_SHIFT 14 +#define NN_CTR_REG_MI_EXMEMCNT_L_EMODE_SIZE 1 +#define NN_CTR_REG_MI_EXMEMCNT_L_EMODE_MASK 0x4000 + +#define NN_CTR_REG_MI_EXMEMCNT_L_ECE2_SHIFT 13 +#define NN_CTR_REG_MI_EXMEMCNT_L_ECE2_SIZE 1 +#define NN_CTR_REG_MI_EXMEMCNT_L_ECE2_MASK 0x2000 + +#define NN_CTR_REG_MI_EXMEMCNT_L_MP_SHIFT 11 +#define NN_CTR_REG_MI_EXMEMCNT_L_MP_SIZE 1 +#define NN_CTR_REG_MI_EXMEMCNT_L_MP_MASK 0x0800 + +#define NN_CTR_REG_MI_EXMEMCNT_L_MP_A_SHIFT 11 +#define NN_CTR_REG_MI_EXMEMCNT_L_MP_A_SIZE 1 +#define NN_CTR_REG_MI_EXMEMCNT_L_MP_A_MASK 0x0800 + +#define NN_CTR_REG_MI_EXMEMCNT_L_MP_B_SHIFT 10 +#define NN_CTR_REG_MI_EXMEMCNT_L_MP_B_SIZE 1 +#define NN_CTR_REG_MI_EXMEMCNT_L_MP_B_MASK 0x0400 + +#define NN_CTR_REG_MI_EXMEMCNT_L_CP_SHIFT 7 +#define NN_CTR_REG_MI_EXMEMCNT_L_CP_SIZE 1 +#define NN_CTR_REG_MI_EXMEMCNT_L_CP_MASK 0x0080 + +#define NN_CTR_REG_MI_EXMEMCNT_L_PHI_SHIFT 5 +#define NN_CTR_REG_MI_EXMEMCNT_L_PHI_SIZE 2 +#define NN_CTR_REG_MI_EXMEMCNT_L_PHI_MASK 0x0060 + +#define NN_CTR_REG_MI_EXMEMCNT_L_ROM2nd_SHIFT 4 +#define NN_CTR_REG_MI_EXMEMCNT_L_ROM2nd_SIZE 1 +#define NN_CTR_REG_MI_EXMEMCNT_L_ROM2nd_MASK 0x0010 + +#define NN_CTR_REG_MI_EXMEMCNT_L_ROM1st_SHIFT 2 +#define NN_CTR_REG_MI_EXMEMCNT_L_ROM1st_SIZE 2 +#define NN_CTR_REG_MI_EXMEMCNT_L_ROM1st_MASK 0x000c + +#define NN_CTR_REG_MI_EXMEMCNT_L_RAM_SHIFT 0 +#define NN_CTR_REG_MI_EXMEMCNT_L_RAM_SIZE 2 +#define NN_CTR_REG_MI_EXMEMCNT_L_RAM_MASK 0x0003 + +#ifndef SDK_ASM +#define NN_CTR_REG_MI_EXMEMCNT_L_FIELD( ep, emode, ece2, mp, mp_a, mp_b, cp, phi, rom2nd, rom1st, ram ) \ + (u16)( \ + ((u32)(ep) << NN_CTR_REG_MI_EXMEMCNT_L_EP_SHIFT) | \ + ((u32)(emode) << NN_CTR_REG_MI_EXMEMCNT_L_EMODE_SHIFT) | \ + ((u32)(ece2) << NN_CTR_REG_MI_EXMEMCNT_L_ECE2_SHIFT) | \ + ((u32)(mp) << NN_CTR_REG_MI_EXMEMCNT_L_MP_SHIFT) | \ + ((u32)(mp_a) << NN_CTR_REG_MI_EXMEMCNT_L_MP_A_SHIFT) | \ + ((u32)(mp_b) << NN_CTR_REG_MI_EXMEMCNT_L_MP_B_SHIFT) | \ + ((u32)(cp) << NN_CTR_REG_MI_EXMEMCNT_L_CP_SHIFT) | \ + ((u32)(phi) << NN_CTR_REG_MI_EXMEMCNT_L_PHI_SHIFT) | \ + ((u32)(rom2nd) << NN_CTR_REG_MI_EXMEMCNT_L_ROM2nd_SHIFT) | \ + ((u32)(rom1st) << NN_CTR_REG_MI_EXMEMCNT_L_ROM1st_SHIFT) | \ + ((u32)(ram) << NN_CTR_REG_MI_EXMEMCNT_L_RAM_SHIFT)) +#endif + + +/* EXMEMCNT_H */ + +#define NN_CTR_REG_MI_EXMEMCNT_H_PHI33M_SHIFT 7 +#define NN_CTR_REG_MI_EXMEMCNT_H_PHI33M_SIZE 1 +#define NN_CTR_REG_MI_EXMEMCNT_H_PHI33M_MASK 0x0080 + +#define NN_CTR_REG_MI_EXMEMCNT_H_WW1_2nd_SHIFT 5 +#define NN_CTR_REG_MI_EXMEMCNT_H_WW1_2nd_SIZE 1 +#define NN_CTR_REG_MI_EXMEMCNT_H_WW1_2nd_MASK 0x0020 + +#define NN_CTR_REG_MI_EXMEMCNT_H_WW1_1st_SHIFT 3 +#define NN_CTR_REG_MI_EXMEMCNT_H_WW1_1st_SIZE 2 +#define NN_CTR_REG_MI_EXMEMCNT_H_WW1_1st_MASK 0x0018 + +#define NN_CTR_REG_MI_EXMEMCNT_H_WW0_2nd_SHIFT 2 +#define NN_CTR_REG_MI_EXMEMCNT_H_WW0_2nd_SIZE 1 +#define NN_CTR_REG_MI_EXMEMCNT_H_WW0_2nd_MASK 0x0004 + +#define NN_CTR_REG_MI_EXMEMCNT_H_WW0_1st_SHIFT 0 +#define NN_CTR_REG_MI_EXMEMCNT_H_WW0_1st_SIZE 2 +#define NN_CTR_REG_MI_EXMEMCNT_H_WW0_1st_MASK 0x0003 + +#ifndef SDK_ASM +#define NN_CTR_REG_MI_EXMEMCNT_H_FIELD( phi33m, ww1_2nd, ww1_1st, ww0_2nd, ww0_1st ) \ + (u16)( \ + ((u32)(phi33m) << NN_CTR_REG_MI_EXMEMCNT_H_PHI33M_SHIFT) | \ + ((u32)(ww1_2nd) << NN_CTR_REG_MI_EXMEMCNT_H_WW1_2nd_SHIFT) | \ + ((u32)(ww1_1st) << NN_CTR_REG_MI_EXMEMCNT_H_WW1_1st_SHIFT) | \ + ((u32)(ww0_2nd) << NN_CTR_REG_MI_EXMEMCNT_H_WW0_2nd_SHIFT) | \ + ((u32)(ww0_1st) << NN_CTR_REG_MI_EXMEMCNT_H_WW0_1st_SHIFT)) +#endif + + +#define NN_CTR_AES_KEY_SIZE 16 // 128 bit +#define NN_CTR_GAME_CODE_MAX 4 +#define NN_CTR_AES_BLOCK_SIZE 16 + +// define NN_CTR_data--------------------------------------------- + +#define NN_CTR_BANNER_IMAGE_SIZE (32 * 32 / (8/4)) +#define NN_CTR_BANNER_PLTT_SIZE (16 * 2) +#define NN_CTR_BANNER_LANG_LENGTH 128 +#define NN_CTR_BANNER_LANG_SIZE (BANNER_LANG_LENGTH * 2) + +#define NN_CTR_BANNER_VER_NTR_MIN 1 // NTRバナーver.MIN. +#define NN_CTR_BANNER_VER_NTR_MAX 3 // NTRバナーver.MAX.(smaller than UCHAR_MAX) +#define NN_CTR_BANNER_VER_TWL_MIN 3 // TWLバナーver.MIN. +#define NN_CTR_BANNER_VER_TWL_MAX 3 // TWLバナーver.MAX.(smaller than UCHAR_MAX) + +#define NN_CTR_BANNER_CHINESE_SUPPORT_VER 2 // 中国語サポートver. +#define NN_CTR_BANNER_KOREAN_SUPPORT_VER 3 // 韓国語サポートver. + +#define NN_CTR_BANNER_LANG_NUM_RSV 8 // 言語予約領域数 +#define NN_CTR_BANNER_ANIME_PATTERN_NUM 8 // バナーアニメパターン数 +#define NN_CTR_BANNER_ANIME_CONTROL_INFO_NUM 64 // バナーアニメコントロール情報数 + + +// バナーファイル上の言語配置順序 +typedef enum { + NN_CTR_BANNER_PRIO_JAPANESE = 0, + NN_CTR_BANNER_PRIO_ENGLISH, + NN_CTR_BANNER_PRIO_FRENCH, + NN_CTR_BANNER_PRIO_GERMAN, + NN_CTR_BANNER_PRIO_ITALIAN, + NN_CTR_BANNER_PRIO_SPANISH, + NN_CTR_BANNER_PRIO_CHINESE, + NN_CTR_BANNER_PRIO_KOREAN, + NN_CTR_BANNER_LANG_NUM, + + NN_CTR_BANNER_LANG_NUM_V1 = NN_CTR_BANNER_PRIO_CHINESE, + NN_CTR_BANNER_LANG_NUM_V2 = NN_CTR_BANNER_PRIO_KOREAN - NN_CTR_BANNER_PRIO_CHINESE, + NN_CTR_BANNER_LANG_NUM_V3 = NN_CTR_BANNER_LANG_NUM - NN_CTR_BANNER_PRIO_KOREAN +} LegacyBannerLanguagePriorityIdx; + +// プラットフォームコード +typedef enum { + NN_CTR_BANNER_PLATFORM_NTR = 0, + NN_CTR_BANNER_PLATFORM_TWL = 1, + + NN_CTR_BANNER_PLATFORM_MAX = 2 +} LegacyBannerPlatformCode; + + +// バナーアニメデータ構造体(bannercvtr.exeが出力するデータ) +typedef struct { + u8 image [ NN_CTR_BANNER_ANIME_PATTERN_NUM ][ NN_CTR_BANNER_IMAGE_SIZE ]; + u8 pltt [ NN_CTR_BANNER_ANIME_PATTERN_NUM ][ NN_CTR_BANNER_PLTT_SIZE ]; + struct { + u8 frameCount : 8; + union { + struct { + u8 cellNo : 3; + u8 plttNo : 3; + u8 flipType : 2; + }normal; + u8 animeType; + }; + } control[ NN_CTR_BANNER_ANIME_CONTROL_INFO_NUM ]; +} LegacyBannerAnime; + + +// バナーヘッダ +typedef struct { + u8 version; + u8 platform; // 上記BannerPlatformCodeで指定 + u16 crc16_v1; + u16 crc16_v2; + u16 crc16_v3; + u16 crc16_anime; + u8 reserved_B[ 22 ]; +} LegacyBannerHeader; + + +// バナーver.1 ボディ +typedef struct { + u8 image[ NN_CTR_BANNER_IMAGE_SIZE ]; + u8 pltt[ NN_CTR_BANNER_PLTT_SIZE ]; + u16 gameName[ NN_CTR_BANNER_LANG_NUM_V1 ][ NN_CTR_BANNER_LANG_LENGTH ]; +} LegacyBannerFileV1; + + +// バナーver.2 ボディ追加分 +typedef struct { + u16 gameName[ NN_CTR_BANNER_LANG_NUM_V2 ][ NN_CTR_BANNER_LANG_LENGTH ]; +} LegacyBannerFileV2; + + +// バナーver.3 ボディ追加分 +typedef struct { + u16 gameName[ NN_CTR_BANNER_LANG_NUM_V3 ][ NN_CTR_BANNER_LANG_LENGTH ]; +} LegacyBannerFileV3; + + +// バナーgameName 言語拡張予約領域 +typedef struct { + u16 gameName[ NN_CTR_BANNER_LANG_NUM_RSV ][ NN_CTR_BANNER_LANG_LENGTH ]; +} LegacyBannerFileRsv; + + + +// TWLバナーファイル構造体 +typedef struct { + LegacyBannerHeader h; + LegacyBannerFileV1 v1; + LegacyBannerFileV2 v2; + LegacyBannerFileV3 v3; // <--- ここまではNTRバナーと共通 + LegacyBannerFileRsv rsv; + LegacyBannerAnime anime; +} LegacyTwlBannerFile; + +} +} + +#ifdef __cplusplus +} +#endif + +#endif //CTR_LGYDATA_H_ diff --git a/trunk/SkipFirstLaunch/idb/include/CtrIcon.h b/trunk/SkipFirstLaunch/idb/include/CtrIcon.h new file mode 100644 index 0000000..9203b58 --- /dev/null +++ b/trunk/SkipFirstLaunch/idb/include/CtrIcon.h @@ -0,0 +1,55 @@ +// CtrIcon.cpp : コンソール アプリケーションのエントリ ポイントを定義します。 +// + +#ifndef __IDB_CTR_ICON_H_ +#define __IDB_CTR_ICON_H_ + +#include +#include + +#define BIG_TEXTURE_WIDTH 64 // 通常アイコンのテクスチャサイズ +#define BIG_TEXTURE_HEIGHT 64 + +#define SMALL_TEXTURE_WIDTH 32 // 小さなアイコンのテクスチャサイズ +#define SMALL_TEXTURE_HEIGHT 32 + +#define BIG_ICON_WIDTH nn::CTR::SYSTEMMENUDATA_BIG_ICON_WIDTH +#define BIG_ICON_HEIGHT nn::CTR::SYSTEMMENUDATA_BIG_ICON_HEIGHT + +#define SMALL_ICON_WIDTH nn::CTR::SYSTEMMENUDATA_SMALL_ICON_HEIGHT // 小さなアイコンの使用領域&アイコンデータのサイズ +#define SMALL_ICON_HEIGHT nn::CTR::SYSTEMMENUDATA_SMALL_ICON_HEIGHT + +#define TWL_ICON_WIDTH 32 +#define TWL_ICON_HEIGHT 32 + +#define PIXEL_SIZE sizeof(u16) // 1ピクセルのビット深度 + +#define DATA_BLOCK_WIDTH 8 // ブロックサイズ +#define DATA_BLOCK_HEIGHT 8 +#define DATA_BLOCK_LENGTH (DATA_BLOCK_WIDTH * DATA_BLOCK_HEIGHT) +#define DATA_BLOCK_SIZE (DATA_BLOCK_LENGTH* PIXEL_SIZE) + +// ブロック単位での大きさ +#define BIG_ICON_BLOCK_WIDTH (BIG_ICON_WIDTH / DATA_BLOCK_WIDTH) +#define BIG_ICON_BLOCK_HEIGHT (BIG_ICON_HEIGHT/ DATA_BLOCK_HEIGHT) +#define SMALL_ICON_BLOCK_WIDTH (SMALL_ICON_WIDTH / DATA_BLOCK_WIDTH) +#define SMALL_ICON_BLOCK_HEIGHT (SMALL_ICON_HEIGHT/ DATA_BLOCK_HEIGHT) + +#define TWL_ICON_BLOCK_WIDTH (TWL_ICON_WIDTH / DATA_BLOCK_WIDTH) +#define TWL_ICON_BLOCK_HEIGHT (TWL_ICON_HEIGHT/ DATA_BLOCK_HEIGHT) + +#define BIG_TEXTURE_BLOCK_WIDTH (BIG_TEXTURE_WIDTH / DATA_BLOCK_WIDTH) +#define BIG_TEXTURE_BLOCK_HEIGHT (BIG_TEXTURE_HEIGHT/ DATA_BLOCK_HEIGHT) +#define SMALL_TEXTURE_BLOCK_WIDTH (SMALL_TEXTURE_WIDTH / DATA_BLOCK_WIDTH) +#define SMALL_TEXTURE_BLOCK_HEIGHT (SMALL_TEXTURE_HEIGHT/ DATA_BLOCK_HEIGHT) + +// アイコン画像をテクスチャに変換したデータ(2の乗数にするためのパディングつき) +typedef struct +{ + u16 little[SMALL_TEXTURE_HEIGHT*SMALL_TEXTURE_WIDTH]; + u16 big[BIG_TEXTURE_HEIGHT*BIG_TEXTURE_WIDTH]; +} IDB_TextureData; + +typedef nn::CTR::SystemMenuDataIcon IDB_IconData; + +#endif // ifndef __IDB_IDB_H_ diff --git a/trunk/SkipFirstLaunch/idb/include/IDB.h b/trunk/SkipFirstLaunch/idb/include/IDB.h new file mode 100644 index 0000000..70c4c5c --- /dev/null +++ b/trunk/SkipFirstLaunch/idb/include/IDB.h @@ -0,0 +1,227 @@ +// IDB.cpp : コンソール アプリケーションのエントリ ポイントを定義します。 +// + +#ifndef __IDB_IDB_H_ +#define __IDB_IDB_H_ + +#include + +#include +#include + +#include "CtrIcon.h" +#include + + +#ifndef BOOL + typedef int BOOL; +#endif //BOOL + +#ifndef TRUE + // Any non zero value is considered TRUE + #define TRUE 1 +#endif //TRUE + +#ifndef FALSE + #define FALSE 0 +#endif // FALSE + +#define IDB_VERSION 9 // アイコンデータベースのバージョン + +#define IDB_ICON_DATA_MAX 512 // アイコンデータの最大件数 +#define IDB_OWNER_ICON_DATA_MAX 256 // オーナーアイコンデータの最大件数 + +#define IDB_PICTURE_DATA_WIDTH 48 // アイコンテクスチャの幅 +#define IDB_PICTURE_DATA_HEIGHT 48 // アイコンテクスチャの高さ +#define IDB_PICTURE_DATA_DEPTH 2 // アイコンテクスチャのbit深度 +#define IDB_PICTURE_DATA_SIZE (IDB_PICTURE_DATA_WIDTH*IDB_PICTURE_DATA_HEIGHT*IDB_PICTURE_DATA_DEPTH) + +#define IDB_APP_INFO_SHORT_TITLE_LENGTH 64 // 短いソフトタイトル(1行) +#define IDB_APP_INFO_LONG_TITLE_LENGTH 128 // 長いソフトタイトル(2行) +#define IDB_APP_INFO_PUBLISHER_LENGTH 64 // 発売元 + +#define IDB_RATING_MAX 16 // 1つのROMに設定できる最大レーティング数 +#define IDB_LANGUAGE_MAX 16 // 1つのアイコン情報に入る最大言語数 + +enum IDB_IconFormat +{ + IDB_ICON_FORMAT_CTR, + IDB_ICON_FORMAT_TWL, + IDB_ICON_FORMAT_NTR, + + IDB_ICON_FORMAT_MAX, + IDB_ICON_FORMAT_INVALID = 0x7fffffff // 問合せ時にIDB_ICON_FORMAT_INVALIDを +}; + +// データベースを取得するためのキーとなるユニークなID +struct IDB_Key +{ + nn::ProgramId programID; // プログラムID + s32 remasterVersion; // リマスターバージョン() + + u8 padding[4]; // パディング(常に0) +}; +#define IDB_KEY_LATEST_VERSION (-1) // IDB_Key.remasterVersionにこれを指定するとオーナー枠、フレンド枠問わず最新のバージョンを取得する +#define IDB_KEY_LATEST_VERSION_OWNER (-2) // IDB_Key.remasterVersionにこれを指定するとオーナー枠を優先して最新のバージョンを取得する + + +// アプリ情報 +struct IDB_SoftwareInfo +{ + wchar_t shortTitle[IDB_APP_INFO_SHORT_TITLE_LENGTH]; // 短いタイトル + wchar_t longTitle[IDB_APP_INFO_LONG_TITLE_LENGTH]; // 長いタイトル + wchar_t publisher[IDB_APP_INFO_PUBLISHER_LENGTH]; // 発売元 +} ; + +// NTR互換アイコン本体 +struct IDB_NTRIconDataRaw +{ + u8 image[ NN_CTR_BANNER_IMAGE_SIZE ]; + u8 pltt[ NN_CTR_BANNER_PLTT_SIZE ]; +}; + +// NTR互換アイコン +struct IDB_NTRIconData +{ + IDB_NTRIconDataRaw data; + + // このパディングは無効な領域を参照している事があるのでアクセスしてはならない + u8 padding[sizeof(nn::CTR::SystemMenuDataIcon)-sizeof(IDB_NTRIconDataRaw)]; +}; + +// TWL互換アイコン +struct IDB_TWLIconData +{ + nn::CTR::LegacyBannerAnime data; + + // このパディングは無効な領域を参照している事があるのでアクセスしてはならない + u8 padding[sizeof(nn::CTR::SystemMenuDataIcon)-sizeof(nn::CTR::LegacyBannerAnime)]; +}; + +// 1つのアイコンの全データ +struct IDB_Icon +{ + IDB_Key key; + nn::CTR::SystemMenuDataRegion region; // リージョン情報(リージョン違いのアイコンは区別するが、gameCodeに含まれているため) + + u8 rating[IDB_RATING_MAX]; // レーティング情報 + u32 matchMakeGameCode; // 合流ゲームID + u64 matchMakeGameCodeBit; // 合流ゲームモードビット + nn::CTR::SystemMenuDataTitle info[IDB_LANGUAGE_MAX]; // タイトル名などのソフト情報 + + IDB_IconFormat format; + + union + { // それぞれIDB_IconFormatが + nn::CTR::SystemMenuDataIcon *data; // ≒ IDB_IconPicture *data; IDB_ICON_FORMAT_CTRのとき + IDB_TWLIconData *twlData; // IDB_ICON_FORMAT_TWLのとき + IDB_NTRIconData *ntrData; // IDB_ICON_FORMAT_NTRのとき + }; +}; + + +///////////////////////////////////////////////////////////////////////////////// +// コンパイル時アサート(静的アサート) +///////////////////////////////////////////////////////////////////////////////// +// NW_COMPILER_ASSERT( sizeof(char)==1 ); // 8bit +// NW_COMPILER_ASSERT( sizeof(u8)==1 ); // 8bit +// NW_COMPILER_ASSERT( sizeof(u16)==2 ); // 16bit +// NW_COMPILER_ASSERT( sizeof(u32)==4 ); // 32bit + +// NW_COMPILER_ASSERT( sizeof(IDB_FormatType)==sizeof(s32) ); // enumは32bit +// NW_COMPILER_ASSERT( sizeof(IDB_Region)==sizeof(s32) ); // enumは32bit + +// NW_COMPILER_ASSERT( IDB_ICON_DATA_MAX>IDB_OWNER_ICON_DATA_MAX ); // オーナー枠はアイコンデータの最大個数以下 + + +///////////////////////////////////////////////////////////////////////////////// +// 関数宣言 +///////////////////////////////////////////////////////////////////////////////// + +/*! + @brief ライブラリの初期化を行います。 + IDB_GetBufferSize()とIDB_IsInitialized()を除く、 + 他の関数を呼び出す前に一回だけ呼んでください。 + + @param[in] buffer IDBが使用するバッファを指定します。 + 同じonMemory引数を指定したIDB_GetBufferSize()で + 取得したサイズのバッファを指定してください。 + 指定したバッファはライブラリで占有しますので、 + IDB_Finalize()で開放するまでは外部からアクセスしないで下さい。 + @param[in] onMemory 全ファイル(7M前後)をメモリにロードしたままにします。 + 高速に動作しますが、大量のメモリを必要とします。 + また、IDB_Finalizeが低速になります。 + @param[in] readOnly trueの時、ReadOnlyモードで動作するようになります。 + ReadOnlyモードの時はIDB_Update()関数を呼ぶことが出来ません。 + この引数がfalseの時はIDBの整合性を保つためHOMEメニューをはじめとする + 各種アプレットに移行するときにFinalizeを呼ぶ必要があります。 + ReadOnlyモードでも、IDBのファイルが存在しないなどの時には + IDB_Initialize()中にファイルの書き込みが行われる事があります。 + IDB_Initialize()中はHOME等のアプレットへは遷移しないで下さい。 + また、データの最終アクセス日時も更新されなくなります。 + この結果、よく参照するアイコンデータが消えやすくなります。 +*/ +void IDB_Initialize( u8 *buffer, bool onMemory, bool readOnly ); + +/*! + @brief ライブラリの終了処理を行います。 + IDB_Initilize()で指定したbufferを返します。 + このバッファは開放することができます。 + 呼んだ後、再度使用する場合はIDB_Initilize()を呼んでください。 + 通常はIDBへのライトバックが行われますが、 + ReadOnlyモードで動作しているときは行われません。 + ReadOnlyモードで動作していないときは + 各種アプレットに移行するときにこの関数を呼ぶ必要があります。 +*/ +u8 * IDB_Finalize( void ); + +/*! + @brief IDBが使用するバッファのサイズを返します。 + IDB_Initilize()を呼ぶ前にも呼ぶことができます。 + onMemoryがfalseの時は12kbyte前後のバッファを使用します。 + onmemoryをtrueにした場合、IDB_Initilizeのonmemory + をtrueに指定した時に要求されるサイズを返します。(7M前後) + + @param[in] onMemory IDB_Initialize()のonMemoryと同じ値を与えてください。 +*/ +u32 IDB_GetBufferSize( bool onMemory = false ); + + +/*! + @brief IDBを使用する準備が出来たかどうかを返します。 + IDB_Initilize()を呼ぶ前にも呼ぶことができます。 +*/ +BOOL IDB_IsInitialized( void ); + + +/*! + @brief アイコンデータの登録を行います。IDB_Index型の変数を返します。 + 必ずアイコンデータが登録されるという保証はありません。 + 登録できなかった場合はFALSEを返します。 + 関数は値のコピーを行いますので、登録したアイコンデータ(inIcon)の + インスタンスは本関数呼出し後に削除してもかまいません。 + + @param[in] inIcon 登録するアイコンデータへのポインタです。 +*/ +BOOL IDB_Update( IDB_Icon *inIcon ); + +/*! + @brief アイコンデータの取得を行います。 + データが存在した場合はTRUEを、しなかった場合はFALSEを返します。 + FALSEを返したとき、*outIconの中身は更新されません。 + IDB_Updateでアイコンを登録した直後でも存在しないことがあります。 + + @param[in] outIcon データを取得するアイコンデータへのポインタです。 + 実体を初期化する必要はありませんが、 + outIcon->dataだけは有効なIDB_IconPicture型を指している必要があります。 + @param[key] outIcon 取得するデータを一意に識別するキーです。 + + @return データが取得できた場合はTRUE +*/ +BOOL IDB_Select( IDB_Icon *outIcon, IDB_Key *key ); + +BOOL IDB_IsContains( IDB_Key *key ); +u32 IDB_GetDataNum(); + + +#endif // ifndef __IDB_IDB_H_ diff --git a/trunk/SkipFirstLaunch/idb/include/IDBUT.h b/trunk/SkipFirstLaunch/idb/include/IDBUT.h new file mode 100644 index 0000000..e47b1aa --- /dev/null +++ b/trunk/SkipFirstLaunch/idb/include/IDBUT.h @@ -0,0 +1,76 @@ +/*! + @file IDBUT.h + @brief アイコンデータベース用のユーティリティです +*/ + + +#ifndef __IDB_IDBUT_H_ +#define __IDB_IDBUT_H_ + +#include +#include +#include + +#include "IDB.h" + +namespace nn +{ +namespace CTR +{ + struct SystemMenuDataTitle; +} +} + +///////////////////////////////////////////////////////////////////////////////// +// 関数宣言 +///////////////////////////////////////////////////////////////////////////////// + +// SystemMenuDataTitleを初期化します +void IDBUT_InitSoftwareInfo( nn::CTR::SystemMenuDataTitle *info ); + + +void IDBUT_InitIcon( IDB_Icon *icon ); + +// アイコンデータから適切な言語のインデックスを返します +int IDBUT_GetLanguageIndex( IDB_Icon *icon, nn::cfg::CTR::CfgRegionCode region, nn::cfg::CTR::CfgLanguageCode language ); +int IDBUT_GetLanguageIndexReceiverSide( IDB_Icon *icon, nn::cfg::CTR::CfgRegionCode receiverRegion, nn::cfg::CTR::CfgLanguageCode receiverLanguage ); + +void IDBUT_GetTextureFromIcon( IDB_TextureData* dstTex, const IDB_IconData* srcIcon ); +void IDBUT_GetIconFromTexture( IDB_IconData* dstIcon, const IDB_TextureData* srcTex ); +s32 IDBUT_GetIconDataSize(void); + +// CTRのROMアイコンヘッダのnn::CTR::SystemMenuDataから、IDBで使用する形式のデータに変換します。 +void IDBUT_GetIconFromSystemMenuData( IDB_Icon* idbIcon, const IDB_Key *key, nn::CTR::SystemMenuData* sysMenuData ); + +// TWL/NTRのバナーファイルのnn::CTR::LegacyTwlBannerFileから、IDBで使用する形式のデータに変換します。 +void IDBUT_GetIconFromLegacyBannerData( IDB_Icon* idbIcon, const IDB_Key *key, nn::CTR::LegacyTwlBannerFile* legacyBannerData ); + +// TWL のアニメ情報とアニメのコマ数を指定すると +// そのコマにおけるアイコンのテクスチャを取得できます。 +void IDBUT_GetTwlIconTextureByControlInfoNo( u16* dstTwlIconTexture, + const nn::CTR::LegacyBannerAnime* bannerAnm, + const u8 controlInfoNo, u8* workBuffer ); + +// TWL のアニメ情報のインデックス通りのアイコンのテクスチャを取得できます。 +void IDBUT_GetTwlIconTextureByCellNo( u16* dstTwlIconTexture, + const nn::CTR::LegacyBannerAnime* bannerAnm, + const u8 cellNo, u8* workBuffer ); + +// GetTwlIconTexture に必要なバッファのサイズを取得します +s32 IDBUT_GetWorkBufferSizeForConvertTwlIcon(void); + +// GetTwlIconTexture の dstTwlIconTexture のサイズを取得します。 +s32 IDBUT_GetTwlIconTextureSize(void); + +// NTR のアイコンをテクスチャへ変換します。 +void IDBUT_GetNtrIconTexture( u16* dstNtrIconTexture, + const IDB_NTRIconDataRaw* ntrIconDataRaw, + u8* workBuffer ); + +// NTR のアイコンを変換するのに必要なバッファのサイズを取得します。 +s32 IDBUT_GetWorkBufferSizeForConvertNtrIcon(void); + +// NTR のアイコンを変換後のサイズを取得します。 +s32 IDBUT_GetNtrIconTextureSize(void); + +#endif // ifndef __IDB_IDBUT_H_ diff --git a/trunk/SkipFirstLaunch/idb/include/IDBi.h b/trunk/SkipFirstLaunch/idb/include/IDBi.h new file mode 100644 index 0000000..353c3fc --- /dev/null +++ b/trunk/SkipFirstLaunch/idb/include/IDBi.h @@ -0,0 +1,117 @@ +// IDBi.h : コンソール アプリケーションのエントリ ポイントを定義します。 +// + +#ifndef __IDB_IDBi_H_ +#define __IDB_IDBi_H_ + +#include +#include "IDB.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif // ifdef __cplusplus + +// IDBi_Time型 +// 2000年1月1日 UTCの真夜中からの閏秒を考慮しない経過秒数 +// 最大で2133年前後まで記録できる +typedef u32 IDBi_Time; + +// データベースを取得するためのキーとなるインデックス +typedef u16 IDBi_Index; +#define IDBi_INDEX_INVALID 0xffff // 無効なインデックス + +// アプレットをマスクするときのID +static const nn::ProgramId IDBi_MASK_PROGRAM_ID = 0xffffffffffffff00ull; + +// データ比較用のテーブル +typedef struct +{ + bit64 programID; + u32 lastAccess; // IDBi_Time lastAccess : 最終アクセス日時 + u16 remasterVersion; // リマスターバージョン + + u8 reserved0; // 予約領域(必ず0で埋める) + u8 reserved1; // 予約領域(必ず0で埋める) +} IDBi_IconTable; + + +// 1つのアイコンのデータ本体 +typedef struct +{ + u16 region; // IDB_Region region : リージョン + u8 format; // IDB_IconFormat format : フォーマット + u8 padding[1]; // パディング + u8 rating[IDB_RATING_MAX]; // レーティング情報 + u32 matchMakeGameCode; // マッチメイクゲームコード + u64 matchMakeGameCodeBit; // マッチメイクゲームコードビット + IDB_SoftwareInfo info[IDB_LANGUAGE_MAX]; + IDB_IconData data; // アイコン画像 +} IDBi_IconData; + + +// アイコンのデータベース、テーブルファイルフォーマット +typedef struct +{ + u16 ownerDataCount; // 保存されているオーナーデータ数 + u8 padding[6]; // パディング + IDBi_IconTable iconTable[IDB_ICON_DATA_MAX]; // 比較用のテーブル +} IDBi_TableFile; + +// アイコンのデータベース、アイコンファイルフォーマット +typedef struct +{ + IDBi_IconData iconData[IDB_ICON_DATA_MAX]; // データ本体 +} IDBi_DataFile; + + +// データ区分 +typedef enum +{ + IDBi_DIVISION_OWNER, // オーナー枠 + IDBi_DIVISION_FRIEND, // フレンド枠 + IDBi_DIVISION_NONE, // 区分に無い + + IDBi_DIVISION_INVALID = 0x7fffffff +} IDBi_Division; + + +///////////////////////////////////////////////////////////////////////////////// +// コンパイル時アサート(静的アサート) +///////////////////////////////////////////////////////////////////////////////// +// NW_COMPILER_ASSERT( sizeof(u8)==1 ); // 8bit +// NW_COMPILER_ASSERT( sizeof(u16)==2 ); // 16bit +// NW_COMPILER_ASSERT( sizeof(u32)==4 ); // 32bit +// NW_COMPILER_ASSERT( sizeof(int)>=4 ); // intは32bit以上 + +// NW_COMPILER_ASSERT( (1ULL<<(8*sizeof(s8)-1)) > IDB_FORMAT_MAX ); // IDB_FORMAT_MAXはs8で表せる最大サイズ以下 +// NW_COMPILER_ASSERT( (1ULL<<(8*sizeof(IDBi_Index))) > IDB_ICON_DATA_MAX ); // IDBi_IndexはIDB_ICON_DATA_MAX分のindexを表現できる +// NW_COMPILER_ASSERT( (1ULL<<(8*sizeof(IDBi_Time ))) > 60ULL*60*24*(365+1)*100 ); // IDBi_Timeは秒単位で100年以上表現できる +// // 秒 分 時 日 年 + +///////////////////////////////////////////////////////////////////////////////// +// 関数宣言 +///////////////////////////////////////////////////////////////////////////////// +void IDBi_Initialize( u8 * buffer, bool onMemory, bool readOnly ); +u8 * IDBi_Finalize( void ); +u32 IDBi_GetBufferSize( bool onMemory ); +BOOL IDBi_IsInitialized( void ); + +IDBi_Index IDBi_Update( IDB_Icon * inIcon, IDBi_Division division ); +BOOL IDBi_Select( IDB_Icon * outIcon, IDB_Key * key, BOOL updateLastAccess = TRUE ); +BOOL IDBi_SelectFromIndex( IDB_Icon * outIcon, IDBi_Index index, BOOL updateLastAccess = TRUE ); +BOOL IDBi_IsContains( IDB_Key * key ); + +void IDBi_MaskProgramID( nn::ProgramId* programID ); + +IDBi_Index IDBi_GetIndex( const IDB_Key * restrict inKey ); +nn::ProgramId IDBi_GetProgramID( const int index ); + +void IDBi_Save(void); +void IDBi_Load(void); + +#ifdef __cplusplus +} +#endif // ifdef __cplusplus + +#endif // ifndef __IDB_IDB_H_ diff --git a/trunk/SkipFirstLaunch/idb/src/IDB.cpp b/trunk/SkipFirstLaunch/idb/src/IDB.cpp new file mode 100644 index 0000000..215424d --- /dev/null +++ b/trunk/SkipFirstLaunch/idb/src/IDB.cpp @@ -0,0 +1,82 @@ +// IDB.cpp : コンソール アプリケーションのエントリ ポイントを定義します。 +// + +#include "IDB.h" +#include "IDBi.h" +#include + +///////////////////////////////////////////////////////////////////////////////// +// 関数定義 +///////////////////////////////////////////////////////////////////////////////// + +// 初期化 +void IDB_Initialize( u8 *buffer, bool onMemory, bool readOnly ) +{ + NN_NULL_ASSERT( buffer ); + if ( buffer==NULL ) return; + + IDBi_Initialize( buffer, onMemory, readOnly); +} + +// 開放 +u8 * IDB_Finalize( void ) +{ + return IDBi_Finalize(); +} + +// 必要なバッファサイズを返す +u32 IDB_GetBufferSize( bool onMemory ) +{ + return IDBi_GetBufferSize(onMemory); +} + +BOOL IDB_IsInitialized( void ) +{ + return IDBi_IsInitialized(); +} + +// 指定したアイコン情報をフレンド枠に追加する +// 追加したindexを返す +// データが追加できなかったときはFALSEを返す +BOOL IDB_Update( IDB_Icon *inIcon ) +{ + NN_NULL_ASSERT( inIcon ); + if ( inIcon==NULL ) return FALSE; + + return IDBi_Update( inIcon, IDBi_DIVISION_FRIEND ) != IDBi_INDEX_INVALID; +} + +// 指定したキーを持つアイコンデータをロードする +// データが存在しない場合はfalseを返す +BOOL IDB_Select( IDB_Icon *outIcon, IDB_Key *key ) +{ + NN_NULL_ASSERT( outIcon ); + NN_NULL_ASSERT( key ); + + if ( outIcon==NULL ) return FALSE; + if ( key==NULL ) return FALSE; + + return IDBi_Select(outIcon, key, TRUE); +} + +// 指定したインデックスを持つアイコンデータをロードする +// データが存在しない場合はfalseを返す +BOOL IDB_SelectFromIndex( IDB_Icon *outIcon, IDBi_Index index ) +{ + NN_NULL_ASSERT( outIcon ); + + if ( outIcon==NULL ) return FALSE; + + return IDBi_SelectFromIndex(outIcon, index, TRUE); +} + +// 指定したキーのデータが存在するかどうかを返す +// データが存在したらtrue、存在しない場合はfalseを返す +BOOL IDB_IsContains( IDB_Key *key ) +{ + NN_NULL_ASSERT( key ); + + if ( key==NULL ) return FALSE; + + return IDBi_IsContains( key ); +} diff --git a/trunk/SkipFirstLaunch/idb/src/IDBUT.cpp b/trunk/SkipFirstLaunch/idb/src/IDBUT.cpp new file mode 100644 index 0000000..1569d1a --- /dev/null +++ b/trunk/SkipFirstLaunch/idb/src/IDBUT.cpp @@ -0,0 +1,724 @@ +// IDBUT.cpp : コンソール アプリケーションのエントリ ポイントを定義します。 +// + +#include "IDBUT.h" +//#include "IDBi.h" + +#include +#include +#include + +#include + + +// TWL アイコンの変換のためのバッファ +typedef struct +{ + u8 tmpBuf[ TWL_ICON_WIDTH * TWL_ICON_HEIGHT * 3 ]; + u8 nativeBuf[ TWL_ICON_WIDTH * TWL_ICON_HEIGHT * 3 ]; +}SConvertBuf; + +enum IDB_TwlAlphaColor +{ + IDB_TWL_ALPHA_COLOR_R = 235, + IDB_TWL_ALPHA_COLOR_G = 235, + IDB_TWL_ALPHA_COLOR_B = 235 +}; + +// 内部関数 +void IDBUT_ConvertTwl555To888( u8* pDst, const u8* pSrc, const u8* pPltt ); +void IDBUT_Convert888To565( u16* pDst, const u8* pSrc, int width, int height ); +void IDBUT_ConvertLineToNative( u8* pDst, const u8* pSrc, int width, int height ); +void IDBUT_GetLegacyIconTexture( u16* pDst, const u8* pImage, const u8* pPltt, u8* workBuffer ); +void IDBUT_SetBlock8( u8* pDst, const u8* pSrc, int width, int height, int posX, int posY ); +void IDBUT_SetBlock4( u8* pDst, const u8* pSrc, int width, int height, int posX, int posY ); +void IDBUT_SetBlock2( u8* pDst, const u8* pSrc, int width, int height, int posX, int posY ); + +int IDBUT_GetCtrLanguageIndex( IDB_Icon *icon, nn::cfg::CTR::CfgRegionCode region, nn::cfg::CTR::CfgLanguageCode language ); +int IDBUT_GetCtrLanguageIndexReceiverSide( IDB_Icon *icon, nn::cfg::CTR::CfgLanguageCode receiverLanguage ); +int IDBUT_GetTwlLanguageIndex( IDB_Icon *icon, nn::cfg::CTR::CfgRegionCode region, nn::cfg::CTR::CfgLanguageCode language ); + +///////////////////////////////////////////////////////////////////////////////// +// 関数定義 +///////////////////////////////////////////////////////////////////////////////// + +/*! + @brief SystemMenuDataTitleを初期化します

+ + @param[in/out] info 初期化する構造体 +*/ +void IDBUT_InitSoftwareInfo( nn::CTR::SystemMenuDataTitle *info ) +{ + memset( info->shortName, 0, sizeof(info->shortName) ); + memset( info->longName, 0, sizeof(info->longName) ); + memset( info->publisher, 0, sizeof(info->publisher) ); +} + +/*! + @brief アイコンデータを初期化します。

+ + icon->dataはNULLに初期化されますので、
+ アプリケーションの側で実体を指し示すようにする必要があります。 + + @param[in/out] icon 初期化する構造体 +*/ +void IDBUT_InitIcon( IDB_Icon *icon ) +{ + int i; + + icon->key.programID = nn::CTR::INVALID_PROGRAM_ID; + icon->key.remasterVersion = 0; + memset( icon->key.padding, 0, sizeof( icon->key.padding ) ); + + icon->region = nn::CTR::BNR_REGION_JAPAN; + memset( icon->rating, 0, sizeof(icon->rating) ); + icon->matchMakeGameCode = 0; + icon->matchMakeGameCodeBit= 0; + icon->format = IDB_ICON_FORMAT_INVALID; + + for ( i=0; iinfo ); + } + + icon->data = NULL; +} + +/*! + @brief アイコンデータから適切な言語のインデックスを返します

+ + 本体の設定言語のタイトルが無かった場合、代替の言語を表示しますが、
+ リージョンによって優先するべき言語が異なります。
+ この関数は、本体リージョンとユーザーの言語から、
+ 表示するべき言語のインデックスを返します。 + + @param[in] icon 対象のIDB_Icon + @param[in] region 本体リージョン + @param[in] language ユーザーの言語 + + @return 表示するべきインデックスを返します。(nn::cfg::CTR::CfgLanguageCodeと同じ値です) +*/ +int IDBUT_GetLanguageIndex( IDB_Icon *icon, nn::cfg::CTR::CfgRegionCode region, nn::cfg::CTR::CfgLanguageCode language ) +{ + // これが返ることはないはず + int ret = nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; + + if( icon->format == IDB_ICON_FORMAT_CTR ) + { + ret = IDBUT_GetCtrLanguageIndex( icon, region, language ); + } + else if( icon->format == IDB_ICON_FORMAT_TWL || icon->format == IDB_ICON_FORMAT_NTR ) + { + ret = IDBUT_GetTwlLanguageIndex( icon, region, language ); + } + + return ret; +} + +/*! + @brief 別の本体から受信したアイコンデータを使用する際の適切な言語のインデックスを返します

+ + 本体の設定言語のタイトルが無かった場合、代替の言語を表示しますが、
+ リージョンによって優先するべき言語が異なります。
+ この関数は、受信側本体リージョンとユーザーの言語から、
+ 表示するべき言語のインデックスを返します。 + + @param[in] icon 対象のIDB_Icon + @param[in] region 受信側本体リージョン + @param[in] language 受信側ユーザーの言語 + + @return 表示するべきインデックスを返します。(nn::cfg::CTR::CfgLanguageCodeと同じ値です) + */ +int IDBUT_GetLanguageIndexReceiverSide( IDB_Icon *icon, nn::cfg::CTR::CfgRegionCode region, nn::cfg::CTR::CfgLanguageCode language ) +{ + // これが返ることはないはず + int ret = nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; + + if( icon->format == IDB_ICON_FORMAT_CTR ) + { + ret = IDBUT_GetCtrLanguageIndexReceiverSide( icon, language ); + } + else if( icon->format == IDB_ICON_FORMAT_TWL || icon->format == IDB_ICON_FORMAT_NTR ) + { + ret = IDBUT_GetTwlLanguageIndex( icon, region, language ); + } + + return ret; +} + +int IDBUT_GetCtrLanguageIndex( IDB_Icon *icon, nn::cfg::CTR::CfgRegionCode region, nn::cfg::CTR::CfgLanguageCode language ) +{ + switch ( region ) + { + case nn::cfg::CTR::CFG_REGION_JAPAN: + return nn::cfg::CTR::CFG_LANGUAGE_JAPANESE; + + case nn::cfg::CTR::CFG_REGION_AMERICA: + case nn::cfg::CTR::CFG_REGION_EUROPE: // CFG_REGION_AUSTRALIA + case nn::cfg::CTR::CFG_REGION_TAIWAN: + if ( icon->info[language].longName[0] != L'\0' && + icon->info[language].shortName[0] != L'\0' ) return language; + return nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; + + case nn::cfg::CTR::CFG_REGION_CHINA: + return nn::cfg::CTR::CFG_LANGUAGE_SIMP_CHINESE; + + case nn::cfg::CTR::CFG_REGION_KOREA: + return nn::cfg::CTR::CFG_LANGUAGE_KOREAN; + } + + return nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; // ここに来る事は無いはず +} + +int IDBUT_GetCtrLanguageIndexReceiverSide( IDB_Icon *icon, nn::cfg::CTR::CfgLanguageCode language ) +{ + if ( icon->info[language].longName[0] != L'\0' && + icon->info[language].shortName[0] != L'\0' ) return language; + + return nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; +} + +int IDBUT_GetTwlLanguageIndex( IDB_Icon *icon, nn::cfg::CTR::CfgRegionCode region, nn::cfg::CTR::CfgLanguageCode language ) +{ + // これがそのまま返ることはない + int ret = nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; + + if ( icon->info[ language ].longName[ 0 ] != L'\0' ) + { + ret = language; + } + else + { + const int TWL_LANGUAGE_PRIORITY_JUET_NUM = 6; + const int TWL_LANGUAGE_PRIORITY_CK_NUM = 8; + int languagePriority[ TWL_LANGUAGE_PRIORITY_CK_NUM ]; + int priorityMaxNum = TWL_LANGUAGE_PRIORITY_JUET_NUM; + memset( languagePriority, 0, sizeof( languagePriority ) ); + + switch( region ) + { + case nn::cfg::CTR::CFG_REGION_JAPAN: + case nn::cfg::CTR::CFG_REGION_TAIWAN: + priorityMaxNum = TWL_LANGUAGE_PRIORITY_JUET_NUM; + languagePriority[ 0 ] = nn::cfg::CTR::CFG_LANGUAGE_JAPANESE; + languagePriority[ 1 ] = nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; + languagePriority[ 2 ] = nn::cfg::CTR::CFG_LANGUAGE_GERMAN; + languagePriority[ 3 ] = nn::cfg::CTR::CFG_LANGUAGE_FRENCH; + languagePriority[ 4 ] = nn::cfg::CTR::CFG_LANGUAGE_SPANISH; + languagePriority[ 5 ] = nn::cfg::CTR::CFG_LANGUAGE_ITALIAN; + break; + case nn::cfg::CTR::CFG_REGION_AMERICA: + priorityMaxNum = TWL_LANGUAGE_PRIORITY_JUET_NUM; + languagePriority[ 0 ] = nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; + languagePriority[ 1 ] = nn::cfg::CTR::CFG_LANGUAGE_FRENCH; + languagePriority[ 2 ] = nn::cfg::CTR::CFG_LANGUAGE_SPANISH; + languagePriority[ 3 ] = nn::cfg::CTR::CFG_LANGUAGE_GERMAN; + languagePriority[ 4 ] = nn::cfg::CTR::CFG_LANGUAGE_ITALIAN; + languagePriority[ 5 ] = nn::cfg::CTR::CFG_LANGUAGE_JAPANESE; + break; + case nn::cfg::CTR::CFG_REGION_EUROPE: + case nn::cfg::CTR::CFG_REGION_AUSTRALIA: + priorityMaxNum = TWL_LANGUAGE_PRIORITY_JUET_NUM; + languagePriority[ 0 ] = nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; + languagePriority[ 1 ] = nn::cfg::CTR::CFG_LANGUAGE_GERMAN; + languagePriority[ 2 ] = nn::cfg::CTR::CFG_LANGUAGE_FRENCH; + languagePriority[ 3 ] = nn::cfg::CTR::CFG_LANGUAGE_SPANISH; + languagePriority[ 4 ] = nn::cfg::CTR::CFG_LANGUAGE_ITALIAN; + languagePriority[ 5 ] = nn::cfg::CTR::CFG_LANGUAGE_JAPANESE; + break; + case nn::cfg::CTR::CFG_REGION_CHINA: + priorityMaxNum = TWL_LANGUAGE_PRIORITY_CK_NUM; + languagePriority[ 0 ] = nn::cfg::CTR::CFG_LANGUAGE_SIMP_CHINESE; + languagePriority[ 1 ] = nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; + languagePriority[ 2 ] = nn::cfg::CTR::CFG_LANGUAGE_GERMAN; + languagePriority[ 3 ] = nn::cfg::CTR::CFG_LANGUAGE_FRENCH; + languagePriority[ 4 ] = nn::cfg::CTR::CFG_LANGUAGE_SPANISH; + languagePriority[ 5 ] = nn::cfg::CTR::CFG_LANGUAGE_ITALIAN; + languagePriority[ 6 ] = nn::cfg::CTR::CFG_LANGUAGE_JAPANESE; + languagePriority[ 7 ] = nn::cfg::CTR::CFG_LANGUAGE_KOREAN; + break; + case nn::cfg::CTR::CFG_REGION_KOREA: + priorityMaxNum = TWL_LANGUAGE_PRIORITY_CK_NUM; + languagePriority[ 0 ] = nn::cfg::CTR::CFG_LANGUAGE_KOREAN; + languagePriority[ 1 ] = nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; + languagePriority[ 2 ] = nn::cfg::CTR::CFG_LANGUAGE_JAPANESE; + languagePriority[ 3 ] = nn::cfg::CTR::CFG_LANGUAGE_GERMAN; + languagePriority[ 4 ] = nn::cfg::CTR::CFG_LANGUAGE_FRENCH; + languagePriority[ 5 ] = nn::cfg::CTR::CFG_LANGUAGE_SPANISH; + languagePriority[ 6 ] = nn::cfg::CTR::CFG_LANGUAGE_ITALIAN; + languagePriority[ 7 ] = nn::cfg::CTR::CFG_LANGUAGE_SIMP_CHINESE; + break; + default: break; + } + + // 優先順位順にタイトルが存在する言語を探す + for( int i = 0; i < priorityMaxNum; ++i ) + { + int languageID = languagePriority[ i ]; + if( icon->info[ languageID ].longName[ 0 ] != L'\0' ) + { + ret = languageID; + break; + } + } + } + + return ret; +} + + + +int IDBUTi_GetLastIndexOfReturn( const wchar_t * const str, size_t len ) +{ + for ( int i = len - 1; i>=0; i-- ) + { + if ( str[i]==L'\n' ) return i; + } + return -1; +} + + +/*! + @brief IDB_IconDataからIDB_TextureDataへデータ形式を変換します

+ + IDBで保存しているIDB_IconDataは48*48と24*24のテクスチャですが、
+ 実際に表示する時はGPUの制約上、64*64と32*32にパディングする必要があります。
+ パディングを行ったフォーマットがIDB_TextureDataです。 + + @param[in] srcIcon 変換元のIDB_IconData + @param[out] dstTex 変換先のIDB_TextureData +*/ +void IDBUT_GetTextureFromIcon( IDB_TextureData* dstTex, const IDB_IconData* srcIcon ) +{ + const IDB_IconData *src =(IDB_IconData *)srcIcon; + + for ( int y=0; ybig[ y * DATA_BLOCK_LENGTH * BIG_TEXTURE_BLOCK_WIDTH ], + &src->big[ y * DATA_BLOCK_LENGTH * BIG_ICON_BLOCK_WIDTH ], + DATA_BLOCK_SIZE * BIG_ICON_BLOCK_WIDTH ); + + // 鯣芧듣芽闣芣蛤벜뫧릧黣莻鯦몷꜊ + memset( &dstTex->big[ y * DATA_BLOCK_LENGTH * BIG_TEXTURE_BLOCK_WIDTH + DATA_BLOCK_LENGTH * BIG_ICON_BLOCK_WIDTH ], + 0xff, + ((BIG_TEXTURE_WIDTH-BIG_ICON_WIDTH)/DATA_BLOCK_WIDTH)*DATA_BLOCK_SIZE ); + } + + for ( int y=0; ylittle[ y * DATA_BLOCK_LENGTH * SMALL_TEXTURE_BLOCK_WIDTH ], + &src->little[ y * DATA_BLOCK_LENGTH * SMALL_ICON_BLOCK_WIDTH ], + DATA_BLOCK_SIZE * SMALL_ICON_BLOCK_WIDTH ); + + // 鯣芧듣芽闣芣蛤벜뫧릧黣莻鯦몷꜊ + memset( &dstTex->little[ y * DATA_BLOCK_LENGTH * SMALL_TEXTURE_BLOCK_WIDTH + DATA_BLOCK_LENGTH * SMALL_ICON_BLOCK_WIDTH ], + 0xff, + ((SMALL_TEXTURE_WIDTH-SMALL_ICON_WIDTH)/DATA_BLOCK_WIDTH)*DATA_BLOCK_SIZE ); + } + + // テクスチャフィルタ対策に一ドット縁取りをする + const int rightEdgeIndex[8] = { 21, 23, 29, 31, 53, 55, 61, 63 }; // 8*8のブロックの右端のインデックス + const int bottomEdgeIndex[8] = { 42, 43, 46, 47, 58, 59, 62, 63 }; // 8*8のブロックの下端のインデックス + const int nextBlockOffsetX = 21; // ブロックを跨いだときの隣のドットのオフセット + const int nextBlockOffsetY = 42; // ブロックを跨いだときの隣のドットのオフセット + + const int rightBBlockIndex[ BIG_ICON_BLOCK_HEIGHT] = { 5, 11, 17, 23, 29, 35 }; // ブロック単位での右端のインデックス(アイコン大) + const int bottomBBlockIndex[BIG_ICON_BLOCK_WIDTH] = { 30, 31, 32, 33, 34, 35 }; // ブロック単位での下端のインデックス(アイコン大) + const int rightSBlockIndex[ SMALL_ICON_BLOCK_HEIGHT] = { 2, 5, 8 }; // ブロック単位での右端のインデックス(アイコン小) + const int bottomSBlockIndex[SMALL_ICON_BLOCK_WIDTH] = { 6, 7, 8 }; // ブロック単位での下端のインデックス(アイコン小) + + const int rightBBlockTexIndex[ BIG_ICON_BLOCK_HEIGHT] = { 6, 14, 22, 30, 38, 46 }; // ブロック単位での右端の隣のインデックス(テクスチャ大) + const int bottomBBlockTexIndex[BIG_ICON_BLOCK_WIDTH] = { 48, 49, 50, 51, 52, 53 }; // ブロック単位での下端の隣のインデックス(テクスチャ大) + const int rightSBlockTexIndex[ SMALL_ICON_BLOCK_HEIGHT] = { 3, 7, 11 }; // ブロック単位での右端の隣のインデックス(テクスチャ小) + const int bottomSBlockTexIndex[SMALL_ICON_BLOCK_WIDTH] = { 12, 13, 14 }; // ブロック単位での下端の隣のインデックス(テクスチャ小) + + // 下 + for ( int bx=0; bxbig[ bottomBBlockTexIndex[bx] *DATA_BLOCK_LENGTH + bottomEdgeIndex[x] - nextBlockOffsetY ] = + src->big[ bottomBBlockIndex[bx] *DATA_BLOCK_LENGTH + bottomEdgeIndex[x] ]; + } + } + + for ( int sx=0; sxlittle[ bottomSBlockTexIndex[sx] *DATA_BLOCK_LENGTH + bottomEdgeIndex[x] - nextBlockOffsetY ] = + src->little[ bottomSBlockIndex[sx] *DATA_BLOCK_LENGTH + bottomEdgeIndex[x] ]; + } + } + + // 右 + for ( int by=0; bybig[ rightBBlockTexIndex[by] *DATA_BLOCK_LENGTH + rightEdgeIndex[y] - nextBlockOffsetX ] = + src->big[ rightBBlockIndex[by] *DATA_BLOCK_LENGTH + rightEdgeIndex[y] ]; + } + } + + for ( int sy=0; sylittle[ rightSBlockTexIndex[sy] *DATA_BLOCK_LENGTH + rightEdgeIndex[y] - nextBlockOffsetX ] = + src->little[ rightSBlockIndex[sy] *DATA_BLOCK_LENGTH + rightEdgeIndex[y] ]; + } + } +} + +/*! + @brief IDB_TextureDataからIDB_IconDataへデータ形式を変換します

+ + IDBで保存しているIDB_IconDataは48*48と24*24のテクスチャですが、
+ 実際に表示する時はGPUの制約上、64*64と32*32にパディングする必要があります。
+ パディングを行ったフォーマットがIDB_TextureDataです。 + + @param[in] srcTex 変換元のIDB_TextureData + @param[out] dstIcon 変換先のIDB_IconData +*/ +void IDBUT_GetIconFromTexture( IDB_IconData* dstIcon, const IDB_TextureData* srcTex ) +{ + int y; + IDB_IconData *dst =(IDB_IconData *)dstIcon; + + for ( y=0; ybig[y * DATA_BLOCK_LENGTH * BIG_ICON_BLOCK_WIDTH ], + &srcTex->big[y * DATA_BLOCK_LENGTH * BIG_TEXTURE_BLOCK_WIDTH ], + DATA_BLOCK_SIZE*BIG_ICON_BLOCK_WIDTH ); + } + + for ( y=0; ylittle[y * DATA_BLOCK_LENGTH * SMALL_ICON_BLOCK_WIDTH ], + &srcTex->little[y * DATA_BLOCK_LENGTH * SMALL_TEXTURE_BLOCK_WIDTH ], + DATA_BLOCK_SIZE*SMALL_ICON_BLOCK_WIDTH ); + } +} + +/*! + @brief IDB_IconDataのサイズを取得します。

+ + @return IDB_IconDataのサイズを返します。 +*/ +s32 IDBUT_GetIDB_IconDataSize(void) +{ + return sizeof(IDB_IconData); +} + +/*! + @brief CTRのROMアイコンヘッダのnn::CTR::SystemMenuDataから、IDBで使用する形式のデータに変換します

+       idbIconの中でsysMenuData内のデータを参照しますので、idbIconを使用している間はsysMenuDataを破棄する事はできません + + @param[out] idbIcon 出力先のIDB_Icon + @param[in] key 変換元のIDB_Key + @param[in] sysMenuData 変換元のSystemMenuData +*/ +void IDBUT_GetIconFromSystemMenuData( IDB_Icon* idbIcon, const IDB_Key *key, nn::CTR::SystemMenuData* sysMenuData ) +{ + const nn::CTR::SystemMenuDataHeader *header = &sysMenuData->header; + + if ( key!=NULL ) + { + memcpy( &idbIcon->key, key, sizeof(idbIcon->key) ); + }else{ + idbIcon->key.programID = nn::CTR::INVALID_PROGRAM_ID; + idbIcon->key.remasterVersion = 0; + } + memset( idbIcon->key.padding, 0, sizeof( idbIcon->key.padding ) ); + + idbIcon->region = header->region; + memcpy( idbIcon->rating, header->rating, sizeof( idbIcon->rating ) ); + idbIcon->matchMakeGameCode = header->matchMakeGameCode; + idbIcon->matchMakeGameCodeBit = header->matchMakeGameCodeBit; + + memcpy( idbIcon->info, header->title, sizeof(idbIcon->info) ); + + idbIcon->format = IDB_ICON_FORMAT_CTR; + idbIcon->data = &sysMenuData->raw; +} + +/*! + @brief TWL/NTRのバナーファイルのnn::CTR::LegacyTwlBannerFileから、IDBで使用する形式のデータに変換します。 +       idbIconの中でlegacyBannerData内のデータを参照しますので、idbIconを使用している間はlegacyBannerDataを破棄する事はできません + + @param[out] idbIcon 出力先のIDB_Icon + @param[in] key 変換元のIDB_Key + @param[in] legacyBannerData 変換元のLegacyTwlBannerFile +*/ +void IDBUT_GetIconFromLegacyBannerData( IDB_Icon* idbIcon, const IDB_Key *key, nn::CTR::LegacyTwlBannerFile* legacyBannerData ) +{ + if ( key!=NULL ) + { + idbIcon->key = *key; + }else{ + idbIcon->key.programID = nn::CTR::INVALID_PROGRAM_ID; + idbIcon->key.remasterVersion = 0; + } + memset( idbIcon->key.padding, 0, sizeof( idbIcon->key.padding ) ); + + idbIcon->region = nn::CTR::BNR_REGION_ALL; // TODO : NTRではいいとして、TWLのリージョンは? + memset( idbIcon->rating, 0x80, sizeof( idbIcon->rating ) ); // TODO : レーティングは全部? + idbIcon->matchMakeGameCode = 0; + idbIcon->matchMakeGameCodeBit = 0; + + if ( legacyBannerData->h.platform == nn::CTR::NN_CTR_BANNER_PLATFORM_NTR ) + { + // NN_LOG("IDB_ICON_FORMAT_NTR\n"); + + idbIcon->format = IDB_ICON_FORMAT_NTR; + idbIcon->ntrData = (IDB_NTRIconData *)&legacyBannerData->v1.image; + + // TODO: NTRのバナーデータはバージョン違いがありますが未対応です。 + }else{ + // NN_LOG("IDB_ICON_FORMAT_TWL\n"); + + idbIcon->format = IDB_ICON_FORMAT_TWL; + idbIcon->twlData = (IDB_TWLIconData *)&legacyBannerData->anime; + + // TODO: TWLのバナーデータはバージョン違いがありますが未対応です。 + } + + for ( int i=0; iinfo[i].longName, 0, sizeof(idbIcon->info[i].longName) ); + memset( idbIcon->info[i].shortName, 0, sizeof(idbIcon->info[i].shortName) ); + memset( idbIcon->info[i].publisher, 0, sizeof(idbIcon->info[i].publisher) ); + + wcsncpy( idbIcon->info[i].longName, (wchar_t *)legacyBannerData->v1.gameName[i], NN_CTR_BANNER_LANG_LENGTH); + } + + int langNum = nn::CTR::NN_CTR_BANNER_LANG_NUM_V1; + // 中国語のサポートがあるバージョンか? + if( legacyBannerData->h.version >= NN_CTR_BANNER_CHINESE_SUPPORT_VER ) + { + // 中国語のタイトルを埋め込み + for( int i = 0; i < nn::CTR::NN_CTR_BANNER_LANG_NUM_V2; ++i ) + { + int ofs = langNum + i; + memset( idbIcon->info[ofs].longName, 0, sizeof(idbIcon->info[ofs].longName) ); + memset( idbIcon->info[ofs].shortName, 0, sizeof(idbIcon->info[ofs].shortName) ); + memset( idbIcon->info[ofs].publisher, 0, sizeof(idbIcon->info[ofs].publisher) ); + + wcsncpy( idbIcon->info[ofs].longName, (wchar_t *)legacyBannerData->v2.gameName[i], NN_CTR_BANNER_LANG_LENGTH); + } + langNum += nn::CTR::NN_CTR_BANNER_LANG_NUM_V2; + if( legacyBannerData->h.version >= NN_CTR_BANNER_KOREAN_SUPPORT_VER ) + { + // 韓国語のタイトルを埋め込み + for( int i = 0; i < nn::CTR::NN_CTR_BANNER_LANG_NUM_V3; ++i ) + { + int ofs = langNum + i; + memset( idbIcon->info[ofs].longName, 0, sizeof(idbIcon->info[ofs].longName) ); + memset( idbIcon->info[ofs].shortName, 0, sizeof(idbIcon->info[ofs].shortName) ); + memset( idbIcon->info[ofs].publisher, 0, sizeof(idbIcon->info[ofs].publisher) ); + + wcsncpy( idbIcon->info[ofs].longName, (wchar_t *)legacyBannerData->v3.gameName[i], NN_CTR_BANNER_LANG_LENGTH); + } + langNum += nn::CTR::NN_CTR_BANNER_LANG_NUM_V3; + } + } + // 残りの言語は全て0埋め + for ( int i=langNum; iinfo[i].longName, 0, sizeof(idbIcon->info[i].longName) ); + memset( idbIcon->info[i].shortName, 0, sizeof(idbIcon->info[i].shortName) ); + memset( idbIcon->info[i].publisher, 0, sizeof(idbIcon->info[i].publisher) ); + } +} + +void IDBUT_GetTwlIconTextureByControlInfoNo( u16* dstTwlIconTexture, + const nn::CTR::LegacyBannerAnime* bannerAnm, + const u8 controlInfoNo, u8* workBuffer ) +{ + u8 cellNo = bannerAnm->control[ controlInfoNo ].normal.cellNo; + IDBUT_GetTwlIconTextureByCellNo( dstTwlIconTexture, bannerAnm, cellNo, workBuffer ); +} + +void IDBUT_GetTwlIconTextureByCellNo( u16* dstTwlIconTexture, + const nn::CTR::LegacyBannerAnime* bannerAnm, + const u8 cellNo, u8* workBuffer ) +{ + u8 plttNo = 0; + IDBUT_GetLegacyIconTexture( dstTwlIconTexture, + bannerAnm->image[ cellNo ], bannerAnm->pltt[ plttNo ], + workBuffer ); +} + +s32 IDBUT_GetWorkBufferSizeForConvertTwlIcon(void) +{ + return 3 * TWL_ICON_WIDTH * TWL_ICON_HEIGHT * 2; +} + +s32 IDBUT_GetTwlIconTextureSize(void) +{ + return sizeof( u16 ) * TWL_ICON_WIDTH * TWL_ICON_HEIGHT; +} + +void IDBUT_GetNtrIconTexture( u16* dstNtrIconTexture, + const IDB_NTRIconDataRaw* ntrIconDataRaw, + u8* workBuffer ) +{ + IDBUT_GetLegacyIconTexture( dstNtrIconTexture, + ntrIconDataRaw->image, ntrIconDataRaw->pltt, + workBuffer ); +} + +s32 IDBUT_GetWorkBufferSizeForConvertNtrIcon(void) +{ + return IDBUT_GetWorkBufferSizeForConvertTwlIcon(); +} + +s32 IDBUT_GetNtrIconTextureSize(void) +{ + return IDBUT_GetTwlIconTextureSize(); +} + +void IDBUT_GetLegacyIconTexture( u16* dstIconTexture, + const u8* pImage, const u8* pPltt, u8* workBuffer ) +{ + SConvertBuf* convBuf = reinterpret_cast(workBuffer); + memset( convBuf->tmpBuf, 0, sizeof(convBuf->tmpBuf) ); + memset( convBuf->nativeBuf, 0, sizeof(convBuf->nativeBuf) ); + + // NTR の bgr555 のバッファを bgr888 へ変換 + IDBUT_ConvertTwl555To888( convBuf->tmpBuf, pImage, pPltt ); + + // bgr888 のバッファをネイティブフォーマットへ変換 + IDBUT_ConvertLineToNative( convBuf->nativeBuf, convBuf->tmpBuf, + TWL_ICON_WIDTH, TWL_ICON_HEIGHT ); + + // bgr888 のバッファを bgr565 のバッファへ変換 + IDBUT_Convert888To565( dstIconTexture, convBuf->nativeBuf, + TWL_ICON_WIDTH, TWL_ICON_HEIGHT ); +} + +void IDBUT_ConvertTwl555To888( u8* pDst, const u8* pSrc, const u8* pPltt ) +{ + // パレットを変換 + u8 dstPltt[ NN_CTR_BANNER_PLTT_SIZE / 2 ][ 3 ]; + memset( dstPltt, 0, sizeof( dstPltt ) ); + // パレット0は抜きの色で、CTR 全体で統一されている + dstPltt[ 0 ][ 0 ] = IDB_TWL_ALPHA_COLOR_B; + dstPltt[ 0 ][ 1 ] = IDB_TWL_ALPHA_COLOR_G; + dstPltt[ 0 ][ 2 ] = IDB_TWL_ALPHA_COLOR_R; + for( int i = 1; i < NN_CTR_BANNER_PLTT_SIZE / 2; ++i ) + { + u16 color = *( (u16*)pPltt + i ); + dstPltt[ i ][ 0 ] = (u8)( (u16)( (f64)( ( color >> 10 ) & 0x1f ) / 31.0 * 255.0 ) ); + dstPltt[ i ][ 1 ] = (u8)( (u16)( (f64)( ( color >> 5 ) & 0x1f ) / 31.0 * 255.0 ) ); + dstPltt[ i ][ 2 ] = (u8)( (u16)( (f64)( ( color >> 0 ) & 0x1f ) / 31.0 * 255.0 ) ); + //NN_LOG("[%02x] %04x\n", i, color); + } + + // 画像を変換 + for( int i = 0; i < TWL_ICON_WIDTH * TWL_ICON_HEIGHT / 2; ++i ) + { + // ブロック単位(8×8)でどの位置か + int blockX = ( i / 4 ) % 4; + int blockY = i / 128; + // ブロックの始めの数字 + int start = 128 * blockY + 32 * blockX; + // ブロックの始めからどの位置かで id を決定する + int id = start + ( ( i % 32 ) % 4 ) + 4 * ( ( i / 16 ) % 8 ); + int prev = 2 * i * 3; + int next = ( 2 * i + 1 ) * 3; + + u8 plttPrev = ( pSrc[ id ] & 0x0f ); + u8 plttNext = ( pSrc[ id ] & 0xf0 ) >> 4; + + //NN_LOG("[%d] %02x [%d] %02x\n", prev, plttPrev, next, plttNext); + + for( int j = 0; j < 3; ++ j ) + { + pDst[ prev + j ] = dstPltt[ plttPrev ][ j ]; + pDst[ next + j ] = dstPltt[ plttNext ][ j ]; + } + } +} + +void IDBUT_Convert888To565( u16* pDst, const u8* pSrc, int width, int height ) +{ + for( int h = 0; h < height; ++h ) + { + for( int w = 0; w < width; ++w ) + { + u16 r = pSrc[3 * (h * width + w) + 0] >> 3; + u16 g = pSrc[3 * (h * width + w) + 1] >> 2; + u16 b = pSrc[3 * (h * width + w) + 2] >> 3; + pDst[h * width + w] = ( ( r & 0x1f ) << 0 ) | ( ( g & 0x3f ) << 5 ) | ( ( b & 0x1f ) << 11 ); + } + } +} + +void IDBUT_ConvertLineToNative( u8* pDst, const u8* pSrc, int width, int height ) +{ + for( int h = 0; h < height; h += DATA_BLOCK_HEIGHT ) + { + for( int w = 0; w < width; w += DATA_BLOCK_WIDTH ) + { + IDBUT_SetBlock8( pDst, pSrc, width, height, w, h ); + } + } +} + +void IDBUT_SetBlock8( u8* pDst, const u8* pSrc, int width, int height, int posX, int posY ) +{ + for( int h = 0; h < 8; h += 4 ) + { + for( int w = 0; w < 8; w += 4 ) + { + IDBUT_SetBlock4( pDst, pSrc, width, height, posX + w, posY + h ); + } + } +} + +void IDBUT_SetBlock4( u8* pDst, const u8* pSrc, int width, int height, int posX, int posY ) +{ + for( int h = 0; h < 4; h += 2 ) + { + for( int w = 0; w < 4; w += 2 ) + { + IDBUT_SetBlock2( pDst, pSrc, width, height, posX + w, posY + h ); + } + } +} + +void IDBUT_SetBlock2( u8* pDst, const u8* pSrc, int width, int height, int posX, int posY ) +{ + NN_UNUSED_VAR( height ); + + static int dstW = 0; + static int dstH = 0; + if( posX == 0 && posY == 0) + { + dstW = 0; + dstH = 0; + } + for( int h = 0; h < 2; ++h ) + { + for( int w = 0; w < 2; ++w ) + { + int dstPos = 3 * ( dstH * width + dstW ); + int srcPos = 3 * ( ( posY + h ) * width + ( posX + w ) ); + pDst[ dstPos + 0 ] = pSrc[ srcPos + 0 ]; + pDst[ dstPos + 1 ] = pSrc[ srcPos + 1 ]; + pDst[ dstPos + 2 ] = pSrc[ srcPos + 2 ]; + ++dstW; + if( dstW >= width ) + { + dstW = 0; + ++dstH; + } + } + } +} diff --git a/trunk/SkipFirstLaunch/idb/src/IDBi.cpp b/trunk/SkipFirstLaunch/idb/src/IDBi.cpp new file mode 100644 index 0000000..2f129e7 --- /dev/null +++ b/trunk/SkipFirstLaunch/idb/src/IDBi.cpp @@ -0,0 +1,926 @@ +// IDBi.c : コンソール アプリケーションのエントリ ポイントを定義します。 +// + +#include "IDBi.h" + +//#define DEBUG_SD 1 // この定義を有効にするとSDカード版になります(デバッグ用) + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static bool sReadOnly = false; // ReadOnlyモードのときはtrue +static IDBi_TableFile * restrict spTable = NULL; +static IDBi_IconData * restrict spIconBuf = NULL; // データ読み書き用の一時的なアイコンバッファ。 +static IDBi_IconData * restrict spTmpIconBuf = NULL; // 交換用の一時的なアイコンバッファ + // 使用頻度が高いので、未使用でもアロケートは常にしておく +static IDBi_DataFile * restrict spDataBuf = NULL; // オンメモリバージョンのバッファ、こちらを使用しているときは + // spIconBufはNULLになる。 + +static const char * const sArchiveName = "IDB"; + +#ifndef DEBUG_SD +static const bit32 sShardExtID = 0xF000000B; // アイコンデータベースID +#endif + +static const bit64 sInvalidProgramID = 0xffffffffffffffff; +static const wchar_t * const sTableFileName= L"IDB:/idbt.dat"; +static const wchar_t * const sDataFileName = L"IDB:/idb.dat"; + +// ファイル外部非公開関数宣言 +static void IDBi_InitTable( void ); + +static IDBi_Index IDBi_Append( const IDB_Icon * restrict inIcon, IDBi_Division division ); +static IDBi_Index IDBi_AppendCore( const IDB_Icon * restrict inIcon, IDBi_Division division ); +static void IDBi_SetFromIndex( const IDB_Icon * restrict inIcon, IDBi_Index index ); +static IDBi_Index IDBi_ExpandOwner( void ); +static IDBi_Index IDBi_MoveToOwner( IDBi_Index index ); + +static IDBi_Index IDBi_UpdateLastAccess( const IDB_Key * restrict inKey ); // アクセス日時を上書き + +static IDBi_Index IDBi_GetOldestIndex(IDBi_Division division ); +static IDBi_Time IDBi_GetCurrentTime( void ); + +static IDBi_Division IDBi_GetDivision( const IDB_Key * restrict key ); +static IDBi_Division IDBi_GetDivisionFromIndex( IDBi_Index index ); + +static IDBi_Index IDBi_GetEmptyIndex(IDBi_Division division); +static BOOL IDBi_IsOwnerDivisionFull( void ); +static BOOL IDBi_IsFriendDivisionFull( void ); + +static void IDBi_Move( IDBi_Index dest, IDBi_Index src ); +static void IDBi_Exchange( IDBi_Index dest, IDBi_Index src ); +static void IDBi_ReadData(IDBi_Index index); +static void IDBi_WriteData(IDBi_Index index); + + +///////////////////////////////////////////////////////////////////////////////// +// 関数定義 +///////////////////////////////////////////////////////////////////////////////// + +// 初期化 +void IDBi_Initialize( u8 * buffer, bool onMemory, bool readOnly ) +{ + NN_NULL_ASSERT( buffer ); + NN_ASSERT( spTable == NULL ); + NN_ASSERT( spIconBuf == NULL ); + NN_ASSERT( spTmpIconBuf == NULL ); + + if ( buffer==NULL ) return; + if ( spTable != NULL ) return; + if ( spIconBuf != NULL ) return; + if( spTmpIconBuf != NULL ) return; + + sReadOnly = readOnly; + spTable = (IDBi_TableFile *)buffer; // reinterpret_cast + spTmpIconBuf = (IDBi_IconData *)(buffer+sizeof(IDBi_TableFile)); // reinterpret_cast + if ( onMemory ) + { + spDataBuf = (IDBi_DataFile *)(buffer+sizeof(IDBi_TableFile)+sizeof(IDBi_IconData) ); // reinterpret_cast + spIconBuf = NULL; + }else{ + spIconBuf = (IDBi_IconData *)(buffer+sizeof(IDBi_TableFile)+sizeof(IDBi_IconData) ); // reinterpret_cast + spDataBuf = NULL; + } + + nn::Result res; +#ifndef DEBUG_SD + NN_LOG("IDB::MountSharedExtSaveData start\n"); + res = nn::fs::MountSharedExtSaveData( sArchiveName, sShardExtID ); + NN_LOG("IDB::MountSharedExtSaveData done\n"); + NN_ASSERT_RESULT( res ); +#else + NN_LOG("IDB::MountSdmc start\n"); + nn::fs::MountSdmc( sArchiveName ); + NN_LOG("IDB::MountSdmc done\n"); +#endif + + // ファイルが存在しなかった場合は作成 + nn::fs::FileOutputStream os; + bool fileCreated = false; + res = os.TryInitialize( sDataFileName, false ); + + if ( res.IsFailure() ) + { + NN_LOG( "res = os.TryInitialize( sDataFileName, false ); failure\n" ); + + fileCreated = true; + NN_LOG("IDB::CreateFile start\n"); + res = nn::fs::TryCreateFile( sDataFileName, sizeof(IDBi_DataFile) ); + NN_LOG("IDB::CreateFile done\n"); + + if ( res.IsSuccess() ) + { + res = os.TryInitialize( sDataFileName, false ); + NN_ASSERT_RESULT( res ); + } + } + + if ( res.IsSuccess() ) + { + s64 size = 0; + res = os.TryGetSize(&size); + + if ( res.IsFailure() || fileCreated ) + { + if ( spDataBuf ) + { + NN_LOG("IDB::Format start (on memory)\n"); + memset(spDataBuf, 0x0, sizeof(IDBi_DataFile ) ); + + s32 len; + res = os.TryWrite( &len, spDataBuf, sizeof(IDBi_DataFile ), false ); + NN_LOG("IDB::Format done (on memory)\n"); + }else{ // オンメモリでは無い場合のフォーマットはかなり遅い + NN_LOG("IDB::Format start (small memory) %d\n", IDBi_GetBufferSize(false) ); + + + const s32 max = IDB_ICON_DATA_MAX * sizeof(IDBi_IconData ); + const s32 chunk = IDBi_GetBufferSize(false); + s32 current = 0; + s32 len; + + int i=0; + memset(buffer, 0x0, chunk ); + while( current+chunkkey.programID != 0 ); // 0は登録できません。 + NN_ASSERT( inIcon->key.programID != nn::CTR::INVALID_PROGRAM_ID ); // nn::CTR::INVALID_PROGRAM_IDは登録できません。 + + if ( spTable==NULL ) return IDBi_INDEX_INVALID; + if ( inIcon==NULL ) return IDBi_INDEX_INVALID; + if ( sReadOnly ) return IDBi_INDEX_INVALID; + if ( inIcon->key.programID == 0 ) return IDBi_INDEX_INVALID; // 無効なIDが指定された時は何もしない + if ( inIcon->key.programID == nn::CTR::INVALID_PROGRAM_ID ) return IDBi_INDEX_INVALID; + if ( nn::CTR::IsTwlSystemApp( inIcon->key.programID ) ) return IDBi_INDEX_INVALID; // TwlSystemアプリの場合は登録しない + + // アプレットのプログラムIDに対して下位8ビットを無視するようにする + IDBi_MaskProgramID( &inIcon->key.programID ); + + IDBi_Division origDivision = IDBi_GetDivision( &inIcon->key ); + + NN_ASSERT( division!=IDBi_DIVISION_NONE ); // divisionが有効な値である + if ( division==IDBi_DIVISION_NONE ) return IDBi_INDEX_INVALID; + + NN_LOG( "update time %d\n" , IDBi_GetCurrentTime() ); + + IDBi_Index ret = IDBi_INDEX_INVALID; + + switch ( origDivision ) + { + case IDBi_DIVISION_OWNER: + ret = IDBi_UpdateLastAccess( &inIcon->key ); + break; + + case IDBi_DIVISION_FRIEND: + if ( division== IDBi_DIVISION_FRIEND ) + { + ret = IDBi_UpdateLastAccess( &inIcon->key ); + } + else + { + ret = IDBi_MoveToOwner( IDBi_GetIndex( &inIcon->key ) ); + } + break; + + case IDBi_DIVISION_NONE: + ret = IDBi_Append( inIcon, division ); + break; + } + + return ret; +} + +// データを取得する +// データが存在しなかった場合はFALSEを返す +BOOL IDBi_Select( IDB_Icon * outIcon, IDB_Key * key, BOOL updateLastAccess ) +{ + NN_NULL_ASSERT( spTable ); // Initialize済 + NN_NULL_ASSERT( outIcon ); + NN_NULL_ASSERT( key ); + + if ( spTable==NULL ) return FALSE; + if ( outIcon==NULL ) return FALSE; + if ( key ==NULL ) return FALSE; + + if( key->programID == sInvalidProgramID ){ return FALSE; } + + // アプレットのプログラムIDに対して下位8ビットを無視するようにする + IDBi_MaskProgramID( &key->programID ); + + IDBi_Index index = IDBi_GetIndex( key ); + if ( index == IDBi_INDEX_INVALID ) return FALSE; + + return IDBi_SelectFromIndex( outIcon, index, updateLastAccess ); +} + +// データを取得する +// データが存在しなかった場合はFALSEを返す +BOOL IDBi_SelectFromIndex( IDB_Icon * outIcon, IDBi_Index index, BOOL updateLastAccess ) +{ + NN_NULL_ASSERT( spTable ); // Initialize済 + NN_NULL_ASSERT( outIcon ); + NN_ASSERT( 0<=index && indexiconTable[index]; + + IDBi_IconData * restrict pData; + if ( spDataBuf ) + { + pData = &spDataBuf->iconData[index]; + }else{ + IDBi_ReadData( index ); + pData = spIconBuf; + } + + if ( pTable->programID == sInvalidProgramID ) return FALSE; + if ( updateLastAccess ) + { + pTable->lastAccess = IDBi_GetCurrentTime(); + } + + outIcon->key.programID = pTable->programID; + outIcon->key.remasterVersion = pTable->remasterVersion; + + memset( outIcon->key.padding, 0, sizeof(outIcon->key.padding) ); + + memcpy( outIcon->info, pData->info, sizeof( pData->info ) ); + memcpy( outIcon->rating, pData->rating, sizeof( pData->rating ) ); + outIcon->region = (nn::CTR::SystemMenuDataRegion)pData->region; + + outIcon->format = (IDB_IconFormat)pData->format; + + // フォーマットが違っていても(TWL等)、あまりの部分は0で埋めているので問題ない + memcpy( outIcon->data, &pData->data, sizeof( IDB_IconData ) ); + + return TRUE; +} + +// 指定したキーのデータが存在するかどうかを返す +// データが存在したらtrue、存在しない場合はfalseを返す +BOOL IDBi_IsContains( IDB_Key *key ) +{ + NN_NULL_ASSERT( spTable ); // Initialize済 + + if ( spTable==NULL ) return FALSE; + if ( key->programID == sInvalidProgramID ){ return FALSE; } + + // アプレットのプログラムIDに対して下位8ビットを無視するようにする + IDBi_MaskProgramID( &key->programID ); + + return IDBi_GetIndex( key ) != IDBi_INDEX_INVALID; +} + + +// データが存在する区分を返す +// 存在しなかった場合はIDBi_DIVISION_NONEを返す +IDBi_Division IDBi_GetDivision( const IDB_Key * restrict key ) +{ + NN_NULL_ASSERT( key ); + if ( key==NULL ) return IDBi_DIVISION_NONE; + + IDBi_Index index = IDBi_GetIndex( key ); + + return IDBi_GetDivisionFromIndex( index ); +} + +// データが存在する区分を返す +// 存在しなかった場合はIDBi_DIVISION_NONEを返す +IDBi_Division IDBi_GetDivisionFromIndex( IDBi_Index index ) +{ + if ( index == IDBi_INDEX_INVALID ) return IDBi_DIVISION_NONE; + + NN_ASSERT( 0<=index && indexownerDataCount ) return IDBi_DIVISION_OWNER; + else return IDBi_DIVISION_FRIEND; +} + +// 空のインデックスを返す +// 空きが存在しなかった時はIDBi_INDEX_INVALIDを返す +IDBi_Index IDBi_GetEmptyIndex(IDBi_Division division) +{ + int from = division == IDBi_DIVISION_OWNER ? 0 : spTable->ownerDataCount; + int to = division == IDBi_DIVISION_OWNER ? spTable->ownerDataCount : IDB_ICON_DATA_MAX; + int i; + + for ( i=from; iiconTable[i].programID == sInvalidProgramID ) return (IDBi_Index)i; + } + + return IDBi_INDEX_INVALID; +} + +// オーナー枠が満タンならTrueを返す +// (拡張すれば空きが存在する可能性もある) +BOOL IDBi_IsOwnerDivisionFull( void ) +{ + int i; + for ( i=0; iownerDataCount; i++ ) + { + if ( spTable->iconTable[i].programID == sInvalidProgramID ) return FALSE; + } + + return TRUE; +} + +// フレンド枠が満タンならTrueを返す +BOOL IDBi_IsFriendDivisionFull( void ) +{ + int i; + for ( i=IDB_ICON_DATA_MAX-1; i>=spTable->ownerDataCount; i-- ) + { + if ( spTable->iconTable[i].programID == sInvalidProgramID ) return FALSE; + } + + return TRUE; +} + +// 内部データを移動する +void IDBi_Move( IDBi_Index dest, IDBi_Index src ) +{ + NN_ASSERT( 0<=dest && desticonTable[dest] = spTable->iconTable[src]; + //spTable->iconTable[dest].lastAccess = IDBi_GetCurrentTime(); + + if( spDataBuf == NULL ) + { + IDBi_ReadData( src ); + }else{ + memcpy( &spDataBuf->iconData[ dest ], &spDataBuf->iconData[ src ], sizeof( IDBi_IconData ) ); + } + IDBi_WriteData( dest ); + + spTable->iconTable[src].programID = sInvalidProgramID; +} + +// 内部データを交換する +void IDBi_Exchange( IDBi_Index dest, IDBi_Index src ) +{ + NN_ASSERT( 0<=dest && desticonTable[dest]; + spTable->iconTable[dest] = spTable->iconTable[src]; + spTable->iconTable[src] = tmpTable; + spTable->iconTable[dest].lastAccess = IDBi_GetCurrentTime(); + + if( spDataBuf != NULL ) + { + memcpy( spTmpIconBuf, &spDataBuf->iconData[ dest ], sizeof( IDBi_IconData ) ); + memcpy( &spDataBuf->iconData[ dest ], &spDataBuf->iconData[ src ], sizeof( IDBi_IconData ) ); + memcpy( &spDataBuf->iconData[ src ], spTmpIconBuf, sizeof( IDBi_IconData ) ); + } + else if( spIconBuf != NULL ) + { + IDBi_ReadData( dest ); + memcpy( spTmpIconBuf, spIconBuf, sizeof( IDBi_IconData ) ); + // src を dest へ + IDBi_ReadData( src ); + IDBi_WriteData( dest ); + // dest を src へ + memcpy( spIconBuf, spTmpIconBuf, sizeof( IDBi_IconData ) ); + IDBi_WriteData( src ); + } +} + +/////////////////////////////////////////////////////////////////// +// ファイル外部非公開関数 +/////////////////////////////////////////////////////////////////// + +// テーブルのデータを初期化する +void IDBi_InitTable( void ) +{ + int i; + + spTable->ownerDataCount = 0; + memset( spTable->padding, 0, sizeof(spTable->padding) ); + for ( i=0; iiconTable[i]; + + table->programID = sInvalidProgramID; // 無効ID + table->lastAccess = 0; // IDBi_Time lastAccess : 最終アクセス日時 + table->remasterVersion = 0; // ソフトバージョン + table->reserved0 = 0; // 予約(必ず0で埋める) + table->reserved1 = 0; // 予約(必ず0で埋める) + } + + IDBi_Save(); +} + + +// データを追加する場合の処理 +// 可能であるのならオーナー枠の拡張などを行う +IDBi_Index IDBi_Append( const IDB_Icon * restrict inIcon, IDBi_Division division ) +{ + NN_NULL_ASSERT( inIcon ); + if ( inIcon==NULL ) return IDBi_INDEX_INVALID; + + switch ( division ) + { + case IDBi_DIVISION_OWNER: + if ( !IDBi_IsOwnerDivisionFull() ) + { + }else if ( spTable->ownerDataCounticonTable[index]; + pTable->programID = inIcon->key.programID; + pTable->remasterVersion = inIcon->key.remasterVersion; + pTable->reserved0 = 0; + pTable->reserved1 = 0; + + pTable->lastAccess = IDBi_GetCurrentTime(); + + IDBi_IconData * restrict pData; + if ( spDataBuf ) + { + pData = &spDataBuf->iconData[index]; + }else{ + pData = spIconBuf; + } + + memcpy( pData->info, inIcon->info, sizeof( pData->info ) ); + memcpy( pData->rating, inIcon->rating, sizeof( pData->rating ) ); + pData->region = (u16)inIcon->region; + pData->format = (u8)inIcon->format; + + switch ( pData->format ) + { + case IDB_ICON_FORMAT_CTR: + memcpy( &pData->data, inIcon->data, sizeof( IDB_IconData ) ); + break; + + case IDB_ICON_FORMAT_TWL: + memcpy( &pData->data, inIcon->twlData, sizeof( nn::CTR::LegacyBannerAnime ) ); + memset( ((u8*)&pData->data) + sizeof( nn::CTR::LegacyBannerAnime ), 0, sizeof( IDB_IconData )-sizeof( nn::CTR::LegacyBannerAnime ) ); + break; + + case IDB_ICON_FORMAT_NTR: + memcpy( &pData->data, inIcon->ntrData, sizeof( IDB_NTRIconDataRaw ) ); + memset( ((u8*)&pData->data) + sizeof( IDB_NTRIconDataRaw ), 0, sizeof( IDB_IconData )-sizeof( IDB_NTRIconDataRaw ) ); + break; + + default: + NN_ASSERT(false); + return; + } + + IDBi_WriteData( index ); +} + +// オーナー枠を拡張する +// 拡張したオーナー枠を返す +IDBi_Index IDBi_ExpandOwner( void ) +{ + // 拡張した際にフレンド枠のデータを破壊してしまう場合は追い出されたデータを移動する + if ( spTable->iconTable[spTable->ownerDataCount].programID != sInvalidProgramID ) + { + //NN_LOG("%llx %llx\n", spTable->iconTable[spTable->ownerDataCount].programID, sInvalidProgramID ); + + IDBi_Index dropped = spTable->ownerDataCount; + IDBi_Index change; + + change = IDBi_GetEmptyIndex( IDBi_DIVISION_FRIEND ); + if( change != IDBi_INDEX_INVALID ) + { + // 空きがあったのでそこに入れる + IDBi_Move( change, dropped ); + } + else + { + // 空きがないのもっとも古い更新時刻のインデックを探す + change = IDBi_GetOldestIndex( IDBi_DIVISION_FRIEND ); + if ( change!=IDBi_INDEX_INVALID ) // このルーチンでInvalidが返ってくる事は無いが、念のため + { + if ( spTable->iconTable[change].lastAccess < spTable->iconTable[dropped].lastAccess ) + { + IDBi_Move( change, dropped ); + } + else + { + // 追い出されたところを空きにする + spTable->iconTable[ dropped ].programID = sInvalidProgramID; + } + } + } + spTable->ownerDataCount++; + // NN_LOG("change:%d dropped:%d\n", change, dropped); + }else{ + spTable->ownerDataCount++; + } + return spTable->ownerDataCount; +} + +// フレンド枠のデータをオーナー枠に移動する +IDBi_Index IDBi_MoveToOwner( IDBi_Index src ) +{ + IDBi_Index dest = IDBi_GetEmptyIndex( IDBi_DIVISION_OWNER ); + NN_ASSERT( spTable->ownerDataCount <= src && src < IDB_ICON_DATA_MAX ); // indexのデータはフレンド枠にある + + if ( dest == IDBi_INDEX_INVALID ) + { + // フレンド枠にあるものを移したいときなので、移動先の要素と交換する + if ( spTable->ownerDataCountownerDataCount; + spTable->ownerDataCount++; + } + else + { + // 最も古いデータを交換 + dest = IDBi_GetOldestIndex( IDBi_DIVISION_OWNER ); + } + // NN_LOG("move to owner exchange src:%d dest:%d ownerDataCount:%d\n", src, dest, spTable->ownerDataCount); + IDBi_Exchange( dest, src ); + } + else + { + // NN_LOG("move to owner copy src:%d dest:%d ownerDataCount:%d\n", src, dest, spTable->ownerDataCount); + IDBi_Move( dest, src ); + spTable->iconTable[dest].lastAccess = IDBi_GetCurrentTime(); + } + return dest; +} + +// 最終アクセス日時を更新する +IDBi_Index IDBi_UpdateLastAccess( const IDB_Key * restrict inKey ) +{ + IDBi_Index index = IDBi_GetIndex( inKey ); + if ( index == IDBi_INDEX_INVALID ) return IDBi_INDEX_INVALID; + + NN_NULL_ASSERT( inKey ); + if ( inKey==NULL ) return IDBi_INDEX_INVALID; + + spTable->iconTable[index].lastAccess = IDBi_GetCurrentTime(); + return index; +} + +// 該当キーのインデックスを返す +// 存在しない時にはIDBi_INDEX_INVALIDを返す +IDBi_Index IDBi_GetIndex( const IDB_Key * restrict inKey ) +{ + int i; + + NN_NULL_ASSERT( inKey ); + if ( inKey==NULL ) return IDBi_INDEX_INVALID; + + if ( inKey->remasterVersion == IDB_KEY_LATEST_VERSION ) + { // 最新バージョンモード + int latestVer = -1; + IDBi_Index latestIndex = IDBi_INDEX_INVALID; + + for ( i=0; iiconTable[i].programID ==inKey->programID ) + { + if ( latestVer < spTable->iconTable[i].remasterVersion ) + { + latestVer = spTable->iconTable[i].remasterVersion; + latestIndex = (IDBi_Index)i; + } + } + } + return latestIndex; + }else if ( inKey->remasterVersion == IDB_KEY_LATEST_VERSION_OWNER ) + { // オーナー枠優先モード + int latestScore = -1; // 多いほうを優先 + IDBi_Index latestIndex = IDBi_INDEX_INVALID; + + for ( i=0; iiconTable[i].programID ==inKey->programID ) + { + const int U16_MAX = 0xffff; + int iVer = spTable->iconTable[i].remasterVersion; + int iScore = IDBi_GetDivisionFromIndex(i)==IDBi_DIVISION_OWNER ? iVer+U16_MAX : iVer; + + if ( latestScore < iScore ) + { + latestScore = iScore; + latestIndex = (IDBi_Index)i; + } + } + } + return latestIndex; + }else{ // 完全一致モード + for ( i=0; iiconTable[i].programID ==inKey->programID && + spTable->iconTable[i].remasterVersion ==inKey->remasterVersion ) + { + return (IDBi_Index)i; + } + } + return IDBi_INDEX_INVALID; + } +} + +// 最もアクセス日時が遅いインデックスを返す +// データベースが空の時はIDBi_INDEX_INVALIDを返す +IDBi_Index IDBi_GetOldestIndex(IDBi_Division division ) +{ + int from = division == IDBi_DIVISION_OWNER ? 0 : spTable->ownerDataCount; + int to = division == IDBi_DIVISION_OWNER ? spTable->ownerDataCount : IDB_ICON_DATA_MAX; + + int i; + u32 oldestTime = std::numeric_limits::max(); // U32_MAX; + int oldestIndex= IDBi_INDEX_INVALID; + + NN_ASSERT( division!=IDBi_DIVISION_NONE ); + if ( division==IDBi_DIVISION_NONE ) return IDBi_INDEX_INVALID; + + for ( i=from; iiconTable[i].programID==sInvalidProgramID ) continue; + + if ( spTable->iconTable[i].lastAccessiconTable[i].lastAccess; + } + } + + NN_LOG("IDBi_GetOldestIndex %d from %d to %d\n", oldestIndex, from, to ); + return (IDBi_Index)oldestIndex; +} + +// IDB形式の現在時間を取得する +IDBi_Time IDBi_GetCurrentTime( void ) +{ + nn::fnd::TimeSpan now = nn::fnd::DateTime::GetNow() - nn::fnd::DateTime(); + return (IDBi_Time)now.GetSeconds(); +} + +// データをバッファにロードする +void IDBi_ReadData(IDBi_Index index) +{ + if ( spIconBuf==NULL ) return; // オンメモリ版は常時ロード + if ( index == IDBi_INDEX_INVALID ) return; + + nn::fs::FileInputStream is(sDataFileName); + is.Seek( index * sizeof(IDBi_IconData) ,nn::fs::POSITION_BASE_BEGIN ); + is.Read( spIconBuf, sizeof(IDBi_IconData) ); + is.Finalize(); +} + +// バッファのデータをファイルに書き込む +void IDBi_WriteData(IDBi_Index index) +{ + NN_ASSERT( 0<=index && indexiconData[index], sizeof(IDBi_IconData) ); + }else{ + os.Write( spIconBuf, sizeof(IDBi_IconData) ); + } + os.Finalize(); +} + +// 指定したインデックスのプログラムIDを取得する +nn::ProgramId IDBi_GetProgramID( const int index ) +{ + NN_ASSERT( 0<=index && indexiconTable[index].programID; +} + +// IDBを保存する +void IDBi_Save(void) +{ + nn::fs::FileOutputStream os; + nn::Result res = os.TryInitialize( sTableFileName, false ); + if ( res.IsFailure() ) + { + nn::fs::CreateFile( sTableFileName, sizeof(*spTable) ); + res = os.TryInitialize( sTableFileName, false ); + NN_RESULT_ASSERT(res); + if ( res.IsFailure() ) + { + os.Finalize(); + return; + } + } + + s32 size; + res = os.TryWrite( &size, spTable, sizeof(*spTable) ); + os.Finalize(); +} + +// IDBをロードする +void IDBi_Load(void) +{ + nn::Result res; + nn::fs::FileInputStream is; + + res = is.TryInitialize( sTableFileName ); + if ( res.IsSuccess() ) + { + s32 size; + res = is.TryRead( &size, spTable, sizeof(*spTable) ); + is.Finalize(); + }else{ + NN_LOG("idb reset start\n"); + + IDBi_InitTable(); + } + + // オンメモリ版は全てをロードしておく + if ( spDataBuf ) + { + nn::fs::FileInputStream dis; + res = dis.TryInitialize(sDataFileName); + if ( res.IsSuccess() ) + { + s32 size; + res = dis.TryRead( &size, spDataBuf, sizeof(IDBi_DataFile) ); + } + dis.Finalize(); + } +} + +// アプレットのプログラムID に対して下位8ビットにマスクをかける +void IDBi_MaskProgramID( nn::ProgramId* programID ) +{ + NN_NULL_ASSERT(programID); + if ( programID==NULL ) return; + + if( !nn::CTR::IsTwlApp( *programID ) ) + { + if( nn::CTR::GetCategoryOf( *programID ) == nn::CTR::PROGRAM_ID_CATEGORY_APPLET ) + { + nn::ProgramId pid = *programID & IDBi_MASK_PROGRAM_ID; + *programID = pid; + } + } +} diff --git a/trunk/SkipFirstLaunch/syokaikidou.cpp b/trunk/SkipFirstLaunch/syokaikidou.cpp new file mode 100644 index 0000000..81bf66f --- /dev/null +++ b/trunk/SkipFirstLaunch/syokaikidou.cpp @@ -0,0 +1,96 @@ + + +//========================================================================== +// 初回起動時処理 +//========================================================================== +void OtherFnc::fnc_1st_setting() +{ + sys::SharedExtSaveData::deleteData(); + sys::SharedExtSaveData::createData(); + + // IDBの初期化 + { + u32 size = IDB_GetBufferSize(); + u8* buf = new( sys::Mem::getMainHeap() ) u8[size]; + + IDB_Initialize( buf, false, false ); + + // MSETとPNOTEのアイコンを特別にIDBに登録 + { + nn::Result result; + IDB_Icon idbIcon; + IDB_Key idbKey; + nn::CTR::SystemMenuData sysMenuData; // これが4KB弱でIDBも喰うのでスレッドスタック16KBでは不足 + nn::am::ProgramInfo pinfo; + nn::ProgramId pids[2] = + { + nn::CTR::MakeProgramId( nn::CTR::PROGRAM_ID_CATEGORY_SYSTEM_APPLICATION, + get_programid_mset_with_region_(), + nn::CTR::PROGRAM_ID_VERSION_APP ), // MSETのプログラムID + nn::CTR::MakeProgramId( nn::CTR::PROGRAM_ID_CATEGORY_SYSTEM_APPLICATION, + get_programid_pnote_with_region_(), + nn::CTR::PROGRAM_ID_VERSION_APP ), // PNOTEのプログラムID + }; + + for( int i = 0; i < 2; i++ ) + { + BOOL bret; + + // アイコンバナーヘッダ取得 + result = nn::fs::CTR::GetSystemMenuData( &sysMenuData, nn::fs::MEDIA_TYPE_NAND, pids[i] ); + NN_DBG_PRINT_RESULT( result ); + if( result.IsFailure() ) + { + continue; // 開発中のみciaを入れていなかったら失敗 + } + + // アイコンバナーヘッダが取れたらROMヘッダ情報も取れる(バージョン情報取得) + result = nn::am::GetProgramInfos( &pinfo, nn::fs::MEDIA_TYPE_NAND, &pids[i], 1 ); + //NN_DBG_PRINT_RESULT( result ); + + IDBUT_InitIcon( &idbIcon ); + idbKey.programID = pids[i]; + idbKey.remasterVersion = static_cast( pinfo.version ); + + IDBUT_GetIconFromSystemMenuData( &idbIcon, &idbKey, &sysMenuData ); + + bret = IDBi_Update( &idbIcon, IDBi_DIVISION_OWNER ); // アイコンをIDBに登録 + if( bret ) + { + NN_LOG( "IDB Registration : PID=%llx, VERSION=%04x\n", idbKey.programID, idbKey.remasterVersion ); + } + else + { + NN_LOG( "IDB registration failed!\n" ); + } + } + } + + IDB_Finalize(); + + delete []buf; + } +} + +//========================================================================== +// 初回起動時処理2 +//========================================================================== +void OtherFnc::fnc_starting_set() +{ +// プレイ履歴クリア + nn::pl::CTR::ClearPlayHistory(); + +// 歩数クリア + nn::pl::CTR::ClearStepHistory(); + + sys::UserInfoAccessor::setFirstAll( true ); + + sys::UserInfoAccessor::setBossTask(); + + sys::UserInfoAccessor::saveFirstInfo( 1, net ); + +// cfg 情報送信のタスク登録 + sys::UserInfoAccessor::setBossSendInfoTaskFirst(); +} + + diff --git a/trunk/SkipFirstLaunch/sysFile.cpp b/trunk/SkipFirstLaunch/sysFile.cpp new file mode 100644 index 0000000..f6b320e --- /dev/null +++ b/trunk/SkipFirstLaunch/sysFile.cpp @@ -0,0 +1,927 @@ +/*! + @file sysFile.cpp + @brief ファイルアクセス + */ +#include "sys.h" + +#include "sysFile.h" +#include +#include +#include + +namespace sys +{ + +const char* File::mMmenSysArcName = "SYS:"; +const wchar_t* File::mMmenSysSaveDataPath = L"SYS:/Launcher.dat"; +const char* File::mMsetSysArcName = "MSETSYS:"; +const wchar_t* File::mMsetSysSaveDataPath[ File::eSysSaveDataTypeNum ] = +{ L"MSETSYS:/Mset.dat", L"MSETSYS:/MsetForBoss.dat", }; +const char* File::mMsetExtArcName = "MSETEXT:"; +const wchar_t* File::mMsetExtSaveDataPath[ File::eExtSaveDataTypeNum ] = +{ L"MSETEXT:/MsetExt.dat", }; + +#ifndef NW_RELEASE +bool File::smDebugPrintFlag = true; +#endif + +/* + char型でのファイルの読み込み + @param device デバイスメモリに読み込むかどうか + @param prefix ファイルのパスに接頭フォルダ名をつけるかどうか + */ +u8* File::read( const char* fileName, u32* size, bool device, bool prefix ) +{ + wchar_t name[128]; + memset( name, 0, sizeof( name ) ); + + int i = 0; + while( fileName[i] != '\0' ) + { + name[i] = fileName[i]; + if( ++i > 128 ) break; + } + + return read( name, size, device, prefix ); +} + +/* + wchar_t型でのファイルの読み込み + @param device デバイスメモリに読み込むかどうか + @param prefix ファイルのパスに接頭フォルダ名をつけるかどうか + */ +u8* File::read( const wchar_t* fileName, u32* size, bool device, bool prefix ) +{ + nn::Result result; + nn::fs::FileReader fileReader; + u8* buffer = NULL; + s64 fileSize = 0; + s32 readSize = 0; + wchar_t name[128]; + + memset( name, 0, sizeof( name ) ); + + if( prefix ) + { + // ファイルシステム内にこれを書くのは正直どうかと思う + // resLoader側に移動するかも +#ifdef NW_PLATFORM_CTR + swprintf( name, 128, L"rom:/%ls", (wchar_t*)fileName ); +#else + swprintf( name, 128, L"data/%s", fileName ); +#endif + } + else + { + swprintf( name, 128, fileName ); + } + + result = fileReader.TryInitialize( name ); + + if( !result.IsSuccess() ) + { + debug_print_(); + return NULL; + } + + result = fileReader.TryGetSize( &fileSize ); + + if( !result.IsSuccess() || fileSize <= 0 ) + { + debug_print_(); + fileReader.Finalize(); + return NULL; + } + + *size = static_cast( fileSize ); + if( device ) buffer = new( Mem::getDeviceHeap(), sys::cDefaultDeviceAlignment ) u8[ *size ]; + else buffer = new( Mem::getMainHeap() ) u8[ *size ]; + + if( buffer == NULL ) + { + debug_print_(); + fileReader.Finalize(); + return NULL; + } + + result = fileReader.TryRead( &readSize, buffer, *size ); + if( !result.IsSuccess() ) + { + debug_print_(); + fileReader.Finalize(); + delete buffer; + return NULL; + } + + fileReader.Finalize(); + + return buffer; +} + +/*! + 圧縮ファイルのリード + */ +u8* File::readLZ( const char* fileName, u32* size ) +{ + u8* comp_buf = read( fileName, size, false, false ); + u32 arc_size = nn::cx::GetUncompressedSize( comp_buf ); + u8* arc_buf = new( Mem::getDeviceHeap() ) u8[arc_size]; + + nn::cx::UncompressLZ( comp_buf, arc_buf ); + + *size = arc_size; + + delete []comp_buf; + + return arc_buf; +} + +/*! + 共有データのマウント + */ +u8* File::mountShare( const char* name, nn::ProgramId tit_id, int data_num, int files, int dirs ) +{ + int size = nn::fs::GetContentRequiredMemorySize( nn::fs::MEDIA_TYPE_NAND, + tit_id, data_num, files, dirs ); + u8* buf = new( Mem::getMainHeap() ) u8[size]; + nn::Result result = nn::fs::MountContent( name, nn::fs::MEDIA_TYPE_NAND, + tit_id, data_num, files, dirs, buf, size ); + + if( result.IsFailure() ) + { + delete []buf; + return NULL; + } + + return buf; +} + +/*! + MSET のシステムセーブデータの初期化 + */ +void File::initializeMsetSys() +{ +nn::Result result = nn::fs::MountSystemSaveData( mMsetSysArcName, getMsetSaveDataId() ); + + NN_DBG_PRINT_RESULT( result ); + + if( result.IsFailure() ) + { + nn::fs::SystemSaveDataId saveDataId = getMsetSaveDataId(); + // ファイルの最大数とディレクトリの最大数は念のため多めにとっておきます。 + size_t maxFiles = 2; + size_t maxDirectories = 1; + bool isDuplicateAll = true; + + if( result <= nn::fs::ResultNotFound() ) + { + // 存在していないため、作成する必要があります。 + result = nn::fs::CreateSystemSaveData( saveDataId, + maxFiles, maxDirectories, + eMsetSaveDataSize, isDuplicateAll ); + NN_LOG("create mset system save data\n"); + } + else if( result <= nn::fs::ResultOperationDenied() ) + { + // 指定した ID のシステムセーブデータは、他のプロセスによってマウントされている可能性があります。 + // それ以外の理由で、このエラーが発生することは、まずありません。 + NN_ASSERT_RESULT( result ); + } + else if( result <= nn::fs::ResultNotFormatted() ) + { + // フォーマットを行なう必要があります。 + result = nn::fs::DeleteSystemSaveData( saveDataId ); + if( result.IsSuccess() ) + { + result = nn::fs::CreateSystemSaveData( saveDataId, + maxFiles, maxDirectories, + eMsetSaveDataSize, isDuplicateAll ); + NN_LOG("create mset system save data\n"); + } + } + else if( result <= nn::fs::ResultBadFormat() ) + { + // フォーマットを行なう必要があります。 + result = nn::fs::DeleteSystemSaveData( saveDataId ); + if( result.IsSuccess() ) + { + result = nn::fs::CreateSystemSaveData( saveDataId, + maxFiles, maxDirectories, + eMsetSaveDataSize, isDuplicateAll ); + NN_LOG("create mset system save data\n"); + } + } + else if( result <= nn::fs::ResultVerificationFailed() ) + { + // フォーマットを行なう必要があります。 + result = nn::fs::DeleteSystemSaveData( saveDataId ); + if( result.IsSuccess() ) + { + result = nn::fs::CreateSystemSaveData( saveDataId, + maxFiles, maxDirectories, + eMsetSaveDataSize, isDuplicateAll ); + NN_LOG("create mset system save data\n"); + } + } + else if( result <= nn::fs::ResultOperationDenied() ) + { + // このエラーが発生することは、まずありません。 + // ただ、発生した場合にカードの挿し直しや本体の再起動で復帰する可能性があります。 + nn::dbg::Panic(); + } + else + { + // 上記以外のエラーは発生しません。 + nn::dbg::Panic(); + } + + NN_DBG_PRINT_RESULT( result ); + + // フォーマット後の判定 + if( result.IsFailure() ) + { + // セーブデータのフォーマットが失敗することはまずありません。 + nn::dbg::Panic(); + } + else + { + // 再マウント + result = nn::fs::MountSystemSaveData( mMsetSysArcName, saveDataId ); + if( result.IsFailure() ) + { + // フォーマットに成功した後に、マウントが失敗することはまずありません。 + nn::dbg::Panic(); + } + else + { + NN_LOG("mset system savedata mount\n"); + } + } + } + else + { + NN_LOG("mset system savedata mount\n"); + } +} + + +/*! + MSET のシステムセーブデータの終了処理 + */ +void File::finalizeMsetSys() +{ + nn::fs::Unmount( mMsetSysArcName ); +} + + +/*! + MSET の追加データをつくる必要があるかどうか + */ +int File::checkMsetExt() +{ +nn::Result result = nn::fs::MountExtSaveData( mMsetExtArcName, getMsetExtSaveDataId() ); +int ret = eExtResultSuccess; + + NN_LOG( "check ext save data\n" ); + NN_DBG_PRINT_RESULT( result ); + + if( result.IsFailure() ) + { + if( result <= nn::fs::ResultNotFound() ) + { + if( result <= nn::fs::ResultMediaNotFound() ) + { + ret = eExtResultDefaultError; + } + else + { + ret = eExtResultNeedCreate; + } + } + else if( result <= nn::fs::ResultNotFormatted() ) + { + ret = eExtResultNeedCreate; + } + else if( result <= nn::fs::ResultBadFormat() ) + { + ret = eExtResultDefaultError; + } + else if( result <= nn::fs::ResultVerificationFailed() ) + { + ret = eExtResultNeedCreate; + } + else if( result <= nn::fs::ResultOperationDenied() ) + { + ret = eExtResultDefaultError; + } + else + { + ret = eExtResultDefaultError; + } + } + + nn::fs::Unmount( mMsetExtArcName ); + return ret; +} + + +/*! + MSET の追加データの初期化 + */ +int File::initializeMsetExt() +{ +nn::Result result = nn::fs::MountExtSaveData( mMsetExtArcName, getMsetExtSaveDataId() ); +int ret = eExtResultSuccess; + + NN_LOG( "mount ext save data\n" ); + NN_DBG_PRINT_RESULT( result ); + + if( result.IsFailure() ) + { + nn::fs::ExtSaveDataId saveDataId = getMsetExtSaveDataId(); + u32 iconData = 0; + size_t iconDataSize = sizeof( iconData ); + // ファイルの最大数とディレクトリの最大数は念のため多めにとっておきます。 + u32 maxDirectories = 1; + u32 maxFiles = 2; + + if( result <= nn::fs::ResultNotFound() ) + { + if( result <= nn::fs::ResultMediaNotFound() ) + { + // SD カードが挿さっていません。 + // (補足) 壊れた SD カードや SD カードではないメディアが挿されているときにも、このエラーが返ります。 + // 但し、その場合は RegisterSdmcInsertedEvent で登録した挿入イベントはシグナルされます。 + ret = eExtResultDefaultError; + } + else + { + // 指定した拡張セーブデータは存在していないので、作成する必要があります。 + // (補足) 開発中は、指定した ID が正しいか確認をしてください。 + result = nn::fs::CreateExtSaveData( saveDataId, + &iconData, iconDataSize, + maxDirectories, maxFiles); + ret = eExtResultNeedCreate; + } + } + else if( result <= nn::fs::ResultNotFormatted() ) + { + // 拡張セーブデータを作り直す必要があります。 + // (理由) 拡張セーブデータの作成に失敗した状態です。 + result = nn::fs::DeleteExtSaveData( saveDataId ); + if( result.IsSuccess() ) + { + result = nn::fs::CreateExtSaveData( saveDataId, + &iconData, iconDataSize, + maxDirectories, maxFiles); + } + ret = eExtResultNeedCreate; + } + else if( result <= nn::fs::ResultBadFormat() ) + { + // SD カードをフォーマットする必要があります。 + ret = eExtResultDefaultError; + } + else if( result <= nn::fs::ResultVerificationFailed() ) + { + // 拡張セーブデータを作り直す必要があります。 + // (理由) セーブデータが壊れているか、改竄されています。 + result = nn::fs::DeleteExtSaveData( saveDataId ); + if( result.IsSuccess() ) + { + result = nn::fs::CreateExtSaveData( saveDataId, + &iconData, iconDataSize, + maxDirectories, maxFiles); + } + ret = eExtResultNeedCreate; + } + else if( result <= nn::fs::ResultOperationDenied() ) + { + if( result <= nn::fs::ResultWriteProtected() ) + { + // SD カードが書き込み禁止にされています。 + // (補足) マウント時にデータの復旧シーケンスが実行されることがあり、そのときに発生します。 + } + else if( result <= nn::fs::ResultMediaAccessError() ) + { + // 接触不良等によるハードウェエア的な要因のときのみ、このエラーが返ります。 + // そのときは、SD カードの挿し直し、本体の再起動などで復帰する可能性があります。 + } + else + { + // SD カード上のファイル、もしくはディレクトリが読み取り専用にされている可能性があります。 + // (補足) マウント時にデータの復旧シーケンスが実行されることがあり、そのときに発生します。 + } + ret = eExtResultDefaultError; + } + else + { + // 上記以外は、想定外のエラーです。 + // 但し、拡張セーブデータへのアクセスで、FATAL エラーは発生させないようにしてください。 + ret = eExtResultDefaultError; + } + + // 作成後の判定 + if( result.IsFailure() ) + { + if( result <= nn::fs::ResultNotEnoughSpace() ) + { + // SD カードに必要な空き容量がありません。 + ret = eExtResultNotFreeError; + } + else if( result <= nn::fs::ResultNotFormatted() ) + { + // エラーが発生し、作成が途中で中断されました。 + ret = eExtResultDefaultError; + } + else if( result <= nn::fs::ResultOperationDenied() ) + { + if( result <= nn::fs::ResultWriteProtected() ) + { + // SD カードが書き込み禁止にされています。 + } + else if( result <= nn::fs::ResultMediaAccessError() ) + { + // 接触不良等によるハードウェエア的な要因のときのみ、このエラーが返ります。 + // そのときは、リトライ処理、ゲームカードの挿し直し、本体の再起動などで復帰する可能性があります。 + } + else + { + // SD カード上のディレクトリが読み取り専用にされている可能性があります。 + // (補足) マウント時にデータの復旧シーケンスが実行されることがあり、そのときに発生します。 + } + ret = eExtResultDefaultError; + } + else + { + // 上記以外は、想定外のエラーです。 + // 但し、拡張セーブデータへのアクセスで、FATAL エラーは発生させないようにしてください。 + // (補足) 開発中は、iconData, iconDataSize に不正な値を渡していないか確かめてください。 + ret = eExtResultDefaultError; + } + } + else + { + // 再マウント + result = nn::fs::MountExtSaveData( mMsetExtArcName, getMsetExtSaveDataId() ); + if( result.IsFailure() ) + { + // 始めの呼び出し時と同様。 + // (補足) SD カードが抜かれない限り、作成直後にマウントが失敗することは、まずありません。 + ret = eExtResultDefaultError; + } + } + } + + return ret; +} + + +/*! + MSET の追加データの終了処理 + */ +void File::finalizeMsetExt() +{ + nn::fs::Unmount( mMsetExtArcName ); +} + + +/*! + MSET のセーブデータ読み込み + */ +void File::readMsetFile( u8* pSaveData, const size_t size, int type ) +{ +u32 readSize = 0; +u8* pTmp = NULL; + + pTmp = sys::File::read( mMsetSysSaveDataPath[ type ], &readSize, false, false ); + if( pTmp == NULL ) + { + switch( type ) + { + case eSysSaveDataTypeDsi: + // ファイルがないので初期化 + // 無効な programID で埋める + memset( pSaveData, 0xFF, size ); + break; + + case eSysSaveDataTypeBoss: + memset( pSaveData, 0, size ); + break; + } + } + else + { + // 管理ファイルが読み込めた + memcpy( pSaveData, pTmp, size ); + delete[] pTmp; + } +} + + +/*! + MSET の拡張セーブデータ読み込み + */ +void File::readMsetExtFile( u8* pSaveData, const size_t size, int type ) +{ +u32 readSize = 0; +u8* pTmp = NULL; + + pTmp = sys::File::read( mMsetExtSaveDataPath[ type ], &readSize, false, false ); + if( pTmp == NULL ) + { + // ファイルがないので初期化 + // 無効な programID で埋める + memset( pSaveData, 0xFF, size ); + } + else + { + // 管理ファイルが読み込めた + memcpy( pSaveData, pTmp, size ); + delete[] pTmp; + } +} + + +/*! + システムセーブデータのセーブ + マウントは外で行ってください + */ +void File::saveMmenSys( const u8* saveData, const size_t size ) +{ +nn::Result result; +nn::fs::FileWriter fileWriter; + + // 自分で他のセーブデータへファイルをつくることはしない + result = fileWriter.TryInitialize( mMmenSysSaveDataPath, false ); + NN_LOG("mmen sys try initialize\n"); + NN_DBG_PRINT_RESULT( result ); + if( result.IsSuccess() ) + { + s32 out = 0; + result = fileWriter.TryWrite( &out, saveData, size ); + if( result.IsSuccess() ) + { + result = nn::fs::CommitSystemSaveData( mMmenSysArcName ); + if( result.IsFailure() ) + { + // これがエラーになってたらパニックだ + nn::dbg::Panic(); + } + else + { + NN_LOG( "save to %ls\n", mMmenSysSaveDataPath ); + } + } + fileWriter.Finalize(); + } +} + +void File::saveMsetSys( const u8* saveData, const size_t size, int type ) +{ +nn::Result result; +nn::fs::FileOutputStream fileWriter; + + // なかった場合はファイル作成 + result = fileWriter.TryInitialize( mMsetSysSaveDataPath[ type ], false ); + if( result.IsFailure() ) + { + if( result <= nn::fs::ResultNotFound() ) + { + result = nn::fs::TryCreateFile( mMsetSysSaveDataPath[ type ], size ); + if( result.IsFailure() ) + { + return; + } + else + { + result = fileWriter.TryInitialize( mMsetSysSaveDataPath[ type ], false ); + if( result.IsFailure() ) + { + return; + } + } + } + else if(result <= nn::fs::ResultVerificationFailed()) + { + // 作り直し + result = nn::fs::TryDeleteFile( mMsetSysSaveDataPath[ type ] ); + if( result.IsFailure() ) + { + return; + } + else + { + result = nn::fs::TryCreateFile( mMsetSysSaveDataPath[ type ], size ); + if( result.IsFailure() ) + { + return; + } + else + { + result = fileWriter.TryInitialize( mMsetSysSaveDataPath[ type ], false ); + if( result.IsFailure() ) + { + return; + } + } + } + } + else + { + return; + } + } + + s64 fSize = 0; + result = fileWriter.TryGetSize( &fSize ); + if( result.IsFailure() ) + { + fileWriter.Finalize(); + return; + } + + if( fSize != size ) + { + result = fileWriter.TrySetSize( size ); + if( result.IsFailure() ) + { + fileWriter.Finalize(); + return; + } + } + + s32 out = 0; + result = fileWriter.TryWrite( &out, saveData, size ); + if( result.IsFailure() ) + { + // このときどうしようもない + fileWriter.Finalize(); + return; + } + else + { + fileWriter.Finalize(); + // コミットしなければ反映されない + result = nn::fs::CommitSystemSaveData( mMsetSysArcName ); + if( result.IsFailure() ) + { + // これがエラーになってたらパニックだ + nn::dbg::Panic(); + } + NN_LOG( "save to %ls\n", mMsetSysSaveDataPath[ type ] ); + } +} + +/*! + 拡張セーブデータのセーブ + マウントは外で行ってください + */ +void File::saveMsetExt( const u8* saveData, const size_t size, int type ) +{ +nn::Result result; +nn::fs::FileOutputStream fileWriter; + + // なかった場合はファイル作成 + result = fileWriter.TryInitialize( mMsetExtSaveDataPath[ type ], false ); + + NN_LOG("try save mset ext\n"); + NN_DBG_PRINT_RESULT( result ); + if( result.IsFailure() ) + { + if( result <= nn::fs::ResultNotFound() ) + { + if( result <= nn::fs::ResultMediaNotFound() ) + { + return; + } + else + { + NN_LOG("try create mset ext\n"); + result = nn::fs::TryCreateFile( mMsetExtSaveDataPath[ type ], size ); + NN_DBG_PRINT_RESULT( result ); + if( result.IsFailure() ) + { + if(result <= nn::fs::ResultNotFound()) + { + return; + } + else if(result <= nn::fs::ResultAlreadyExists()) + { + NN_LOG("try delete mset ext\n"); + result = nn::fs::TryDeleteFile( mMsetExtSaveDataPath[ type ] ); + NN_DBG_PRINT_RESULT( result ); + if( result.IsFailure() ) + { + return; + } + else + { + NN_LOG("try create mset ext\n"); + result = nn::fs::TryCreateFile( mMsetExtSaveDataPath[ type ], size ); + NN_DBG_PRINT_RESULT( result ); + if( result.IsFailure() ) + { + return; + } + else + { + result = fileWriter.TryInitialize( mMsetExtSaveDataPath[ type ], false ); + if( result.IsFailure() ) + { + return; + } + } + } + } + } + } + } + else if(result <= nn::fs::ResultVerificationFailed()) + { + NN_LOG("try delete mset ext\n"); + result = nn::fs::TryDeleteFile( mMsetExtSaveDataPath[ type ] ); + NN_DBG_PRINT_RESULT( result ); + if( result.IsFailure() ) + { + return; + } + else + { + NN_LOG("try create mset ext\n"); + result = nn::fs::TryCreateFile( mMsetExtSaveDataPath[ type ], size ); + NN_DBG_PRINT_RESULT( result ); + if( result.IsFailure() ) + { + return; + } + else + { + result = fileWriter.TryInitialize( mMsetExtSaveDataPath[ type ], false ); + if( result.IsFailure() ) + { + return; + } + } + } + } + else + { + return; + } + } + + s64 fSize = 0; + result = fileWriter.TryGetSize( &fSize ); + if( result.IsFailure() ) + { + fileWriter.Finalize(); + return; + } + + if( fSize != size ) + { + result = fileWriter.TrySetSize( size ); + if( result.IsFailure() ) + { + fileWriter.Finalize(); + return; + } + } + + s32 out = 0; + result = fileWriter.TryWrite( &out, saveData, size ); + if( result.IsFailure() ) + { + // このときどうしようもない + fileWriter.Finalize(); + return; + } + else + { + fileWriter.Finalize(); + NN_LOG( "save to %ls\n", mMsetExtSaveDataPath[ type ] ); + } +} + + +/*! + ファイル読み込み失敗デバッグ表示 + */ +void File::debug_print_() +{ +#ifndef NW_RELEASE + if( smDebugPrintFlag ) + { + NN_LOG("Fail fileRead "); +/* + int i = 0; + while( name[i] != L'\0' ) + { + NN_LOG("%c", name[i]); + if( ++i == 128 ) break; + } +*/ + NN_LOG("\n"); + } +#endif +} + + +//========================================================================== +// システムセーブデータのID取得 +//========================================================================== +nn::fs::SystemSaveDataId File::getMmenSaveDataId() +{ +nn::fs::SystemSaveDataId ret; + + switch( nn::cfg::CTR::GetRegion() ) + { + case nn::cfg::CTR::CFG_REGION_JAPAN: + ret = 0x00020082; + break; + case nn::cfg::CTR::CFG_REGION_EUROPE: + case nn::cfg::CTR::CFG_REGION_AUSTRALIA: + ret = 0x00020098; + break; + case nn::cfg::CTR::CFG_REGION_CHINA: + ret = 0x000200A1; + break; + case nn::cfg::CTR::CFG_REGION_KOREA: + ret = 0x000200A9; + break; + case nn::cfg::CTR::CFG_REGION_TAIWAN: + ret = 0x000200B1; + break; + case nn::cfg::CTR::CFG_REGION_AMERICA: + default: + ret = 0x0002008f; + break; + } + + return ret; +} + +nn::fs::SystemSaveDataId File::getMsetSaveDataId() +{ +nn::fs::SystemSaveDataId ret; + + switch( nn::cfg::CTR::GetRegion() ) + { + case nn::cfg::CTR::CFG_REGION_JAPAN: + ret = 0x00020200; + break; + case nn::cfg::CTR::CFG_REGION_EUROPE: + case nn::cfg::CTR::CFG_REGION_AUSTRALIA: + ret = 0x00020220; + break; + case nn::cfg::CTR::CFG_REGION_CHINA: + ret = 0x00020260; + break; + case nn::cfg::CTR::CFG_REGION_KOREA: + ret = 0x00020270; + break; + case nn::cfg::CTR::CFG_REGION_TAIWAN: + ret = 0x00020280; + break; + case nn::cfg::CTR::CFG_REGION_AMERICA: + default: + ret = 0x00020210; + break; + } + + return ret; +} + +nn::fs::ExtSaveDataId File::getMsetExtSaveDataId() +{ +nn::fs::ExtSaveDataId ret; + + switch( nn::cfg::CTR::GetRegion() ) + { + case nn::cfg::CTR::CFG_REGION_JAPAN: + ret = nn::CTR::PROGRAM_ID_UNIQUE_ID_MSET; + break; + case nn::cfg::CTR::CFG_REGION_EUROPE: + case nn::cfg::CTR::CFG_REGION_AUSTRALIA: + ret = nn::CTR::PROGRAM_ID_UNIQUE_ID_MSET_EU; + break; + case nn::cfg::CTR::CFG_REGION_CHINA: + ret = nn::CTR::PROGRAM_ID_UNIQUE_ID_MSET_CN; + break; + case nn::cfg::CTR::CFG_REGION_KOREA: + ret = nn::CTR::PROGRAM_ID_UNIQUE_ID_MSET_KR; + break; + case nn::cfg::CTR::CFG_REGION_TAIWAN: + ret = nn::CTR::PROGRAM_ID_UNIQUE_ID_MSET_TW; + break; + case nn::cfg::CTR::CFG_REGION_AMERICA: + default: + ret = nn::CTR::PROGRAM_ID_UNIQUE_ID_MSET_US; + break; + } + + return ret; +} + +} diff --git a/trunk/SkipFirstLaunch/sysFile.h b/trunk/SkipFirstLaunch/sysFile.h new file mode 100644 index 0000000..1800b0d --- /dev/null +++ b/trunk/SkipFirstLaunch/sysFile.h @@ -0,0 +1,102 @@ +/*! + @file sysFile.h + @brief ファイルアクセス + */ +#ifndef SYS_FILE_H_ +#define SYS_FILE_H_ + +#include + +namespace sys +{ + +class File +{ +public: + File(){} + ~File(){} + + static u8* read( const char* fileName, u32* size, bool device = false, bool prefix = true ); + static u8* read( const wchar_t* fileName, u32* size, bool device = false, bool prefix = true ); + + static void readMsetFile( u8* pSaveData, const size_t size, int type ); + static void readMsetExtFile( u8* pSaveData, const size_t size, int type ); + +#ifndef NW_RELEASE + static void setDebugPrintFlag( bool flag ){ smDebugPrintFlag = flag; } +#endif + + static u8* readLZ( const char* fileName, u32* size ); + static u8* mountShare( const char* name, nn::ProgramId tit_id, int data_num, int files, int dirs ); + + static void initializeMsetSys(); + static void finalizeMsetSys(); + + enum + { + eSysSaveDataTypeDsi = 0, + eSysSaveDataTypeBoss, + + eSysSaveDataTypeNum + }; + + enum + { + eExtSaveDataTypeDsi = 0, + + eExtSaveDataTypeNum + }; + + enum + { + eExtResultSuccess, + eExtResultNeedCreate, + // これ以降は失敗 + eExtResultNotFreeError, // 空き容量が足りない + eExtResultDefaultError + }; + static int checkMsetExt(); // マウントできるかどうか + static int initializeMsetExt(); + static void finalizeMsetExt(); + + static void saveMmenSys( const u8* saveData, const size_t size ); + static void saveMsetSys( const u8* saveData, const size_t size, int type ); + static void saveMsetExt( const u8* saveData, const size_t size, int type ); + + static nn::fs::SystemSaveDataId getMmenSaveDataId(); + static nn::fs::SystemSaveDataId getMsetSaveDataId(); + static nn::fs::ExtSaveDataId getMsetExtSaveDataId(); + + // --------------------------------------------------------------------------- + + static const char* getMmenSysArcName() { return mMmenSysArcName; } + static const char* getMsetSysArcName() { return mMsetSysArcName; } + static const char* getMsetExtArcName() { return mMsetExtArcName; } + static const wchar_t* getMmenSysSaveDataPath() { return mMmenSysSaveDataPath; } + static const wchar_t* getMsetSysSaveDataPath( int type ) { return mMsetSysSaveDataPath[ type ]; } + static const wchar_t* getMsetExtSaveDataPath( int type ) { return mMsetExtSaveDataPath[ type ]; } + + enum + { + eMsetSaveDataSize = 64 * 1024, + eMsetExtSaveDataSize = 120 * 1024 + }; + +private: + + static void debug_print_(); + +#ifndef NW_RELEASE + static bool smDebugPrintFlag; +#endif + + static const char* mMmenSysArcName; + static const wchar_t* mMmenSysSaveDataPath; + static const char* mMsetSysArcName; + static const wchar_t* mMsetSysSaveDataPath[ eSysSaveDataTypeNum ]; + static const char* mMsetExtArcName; + static const wchar_t* mMsetExtSaveDataPath[ eExtSaveDataTypeNum ]; +}; + +} +#endif diff --git a/trunk/SkipFirstLaunch/sysInput.cpp b/trunk/SkipFirstLaunch/sysInput.cpp new file mode 100644 index 0000000..2a4ec6d --- /dev/null +++ b/trunk/SkipFirstLaunch/sysInput.cpp @@ -0,0 +1,212 @@ +/*! + @file sysInput.cpp + @brief 入力 + */ +#include "sys.h" + +#include "sysInput.h" + +#ifndef NW_RELEASE +#include "utScreenCapture.h" +#endif + +#ifdef DEBUG_TEXT +#include "lytManager.h" +#endif + +namespace sys +{ + +u16 Input::msPad; // 現在の入力 +u16 Input::msPadPrev; // 1フレーム前の入力 +u16 Input::msPadTrig; // 現在のトリガ + +bool Input::msTP; +bool Input::msTPTouch; + +nw::math::VEC2 Input::msTPPos; +nw::math::VEC2 Input::msTPFloatPos; + +nn::hid::CTR::PadReader* Input::mspPadReader; +nn::hid::CTR::PadStatus* Input::mspPadStatus; +nn::hid::CTR::TouchPanelReader* Input::mspTpReader; +nn::hid::CTR::TouchPanelStatus* Input::mspTpStatus; +nn::hid::CTR::PadReaderWithSvr2* Input::smpPadReaderWithSvr2; + +/*! + 初期化 + */ +void Input::init() +{ + msPad = 0; + msPadPrev = 0; + msPadTrig = 0; + + //nn::Result result; +// nn::hid::Initialize(); + //NN_UTIL_PANIC_IF_FAILED(result); + + mspPadReader = new( sys::Mem::getMainHeap() ) nn::hid::CTR::PadReader(); + mspPadStatus = new( sys::Mem::getMainHeap() ) nn::hid::CTR::PadStatus(); + + mspPadReader->SetStickClampMode( nn::hid::CTR::PadReader::STICK_CLAMP_MODE_CROSS ); + + mspTpReader = new( sys::Mem::getMainHeap() ) nn::hid::CTR::TouchPanelReader(); + mspTpStatus = new( sys::Mem::getMainHeap() ) nn::hid::CTR::TouchPanelStatus(); + + smpPadReaderWithSvr2 = new( sys::Mem::getMainHeap() ) nn::hid::CTR::PadReaderWithSvr2(); +} + +/*! + 更新 + */ +void Input::update( int system_stt ) +{ + // ステートが通常以外になったときは更新を止めつつ、処理をリセットさせる + if( system_stt != sys::eSystemStt_Normal ) + { + return; + } + + msTPTouch = msTP; + + // 入力取得 + bool pad_ret = mspPadReader->ReadLatest( mspPadStatus ); + bool tp_ret = mspTpReader->ReadLatest( mspTpStatus ); + + if( tp_ret && mspTpStatus->touch == 1 ) + { + // タッチパネル座標系をレイアウト座標系に変換します. + nw::math::VEC2 tpStatus; + tpStatus.x = (f32)( mspTpStatus->x - cDown_Width / 2 ); + tpStatus.y = -(f32)( mspTpStatus->y - cDown_Height / 2 ); + + // 遊び範囲内での動作は, + // チャタリング対策のため非常に遅い追従率で追従させます. + // 遊び範囲を超えたときは完全に一致させます. + static const f32 cPlayRadius = 1.5f; // 遊び半径. + static const f32 cSensitivity = 0.1f; // 遊び半径内での追従係数. + if( msTP && nn::math::VEC2DistSq( msTPFloatPos, tpStatus ) < cPlayRadius * cPlayRadius ) + { + msTPFloatPos += ( tpStatus - msTPFloatPos ) * cSensitivity; + } + else + { + msTPFloatPos = tpStatus; + } + + // 小数のまま使用すると,スライダーバーやタッチスライダーで, + // 終端判定以降にじりじり動いてしまう問題が発生したため, + // 整数に丸めて使用します. + msTPPos.x = (int)msTPFloatPos.x; + msTPPos.y = (int)msTPFloatPos.y; + + msTP = true; + } + else msTP = false; + + if( pad_ret ) + { + msPadTrig = (u16)( msPad & ~msPadPrev ); + msPadPrev = msPad; + } + +#ifndef NW_RELEASE + // キャプチャー用テストコード + if( isButtonHold( BUTTON_R | BUTTON_L ) ) + { + if( isButtonHold( KEY_UP ) ) ut::SaveDisplayBufferSD( eDisp_Up ); + else if( isButtonHold( KEY_DOWN ) ) ut::SaveDisplayBufferSD( eDisp_Down ); + } +#endif + +#ifdef DEBUG_TEXT + if( isButtonHold( BUTTON_R | BUTTON_L ) && + isTouched() ) + { + static bool visible = false; + visible = !visible; + lyt::Manager::setDebugVisible( visible ); + } +#endif +} + +/*! + 終了処理 + */ +void Input::finish() +{ +// nn::hid::Finalize(); +} + +/*! + 押した + */ +u16 Input::isTouched() +{ + return msTP && !msTPTouch; +} + +/*! + 離した + */ +u16 Input::isReleased() +{ + return !msTP && msTPTouch; +} + +/*! + 押してる + */ +u16 Input::isTouching() +{ + return msTP; +} + +/*! + 現在のPADのトリガ入力を取得 + */ +u16 Input::getPadTrig() +{ + return mspPadStatus->trigger; +} + +/*! + 押された瞬間かどうか(トリガ) +*/ +bool Input::isButtonTrig( u16 button ) +{ + return ( mspPadStatus->trigger & button ) ? true: false; +} + +/*! + 押されている状態かどうか(コント) +*/ +bool Input::isButtonHold( u16 button ) +{ + return ( mspPadStatus->hold & button )? true: false; +} + +/*! + 3D視差ボリューム取得 + 0.0f〜1.0fの値が返ります + */ +f32 Input::getSvr2Volume() +{ + return smpPadReaderWithSvr2->GetSvr2Volume(); +} + +/* + アナログスティックの値 +*/ +f32 Input::getNormalizeX() +{ + return mspPadReader->NormalizeStick( mspPadStatus->stick.x ); +} + +f32 Input::getNormalizeY() +{ + return mspPadReader->NormalizeStick( mspPadStatus->stick.y ); +} + +} diff --git a/trunk/SkipFirstLaunch/sysInput.h b/trunk/SkipFirstLaunch/sysInput.h new file mode 100644 index 0000000..fbcd795 --- /dev/null +++ b/trunk/SkipFirstLaunch/sysInput.h @@ -0,0 +1,159 @@ +/*! + @file sysInput.h + @brief 入力 + */ +#ifndef SYS_INPUT_H_ +#define SYS_INPUT_H_ + +#ifdef NW_PLATFORM_CTR +#include +#include +#else +#include +#endif + +#include "guiManager.h" +#include "guiButton.h" +#include "guiRadioButton.h" +#include "guiRepeatButton.h" +#include "guiSliderBar.h" +#include "guiMayaButton.h" +#include "guiTouchSlider.h" +#include "utUtil.h" +#include "sysDialogManager.h" + +#include "sceneCalibrationLayout.h" +#include "sceneCalibrationGuiOperator.h" +#include "sceneStartLayout.h" +#include "sceneCoppaLayout.h" + +#ifndef NW_RELEASE +#include "sceneSceneController.h" +#include "sceneDebugLayout.h" +#include "sceneDialogScene.h" +#include "sceneDataMngLayout.h" +#include "sceneDataCmmLayout.h" + +#ifdef NW_PLATFORM_CTR +#include "sceneInternetThread.h" +#include "sceneDataMngThread.h" +#include "sceneCoppaThread.h" +#include "sceneCheckScene.h" +#endif + +#endif + +namespace sys +{ + +class Input +{ +public: +#ifdef NW_PLATFORM_CTRWIN + static const int BUTTON_A = nn::hw::pad::BUTTON_A; + static const int BUTTON_B = nn::hw::pad::BUTTON_B; + static const int BUTTON_SELECT = nn::hw::pad::BUTTON_SELECT; + static const int BUTTON_START = nn::hw::pad::BUTTON_START; + static const int KEY_RIGHT = nn::hw::pad::KEY_RIGHT; + static const int KEY_LEFT = nn::hw::pad::KEY_LEFT; + static const int KEY_UP = nn::hw::pad::KEY_UP; + static const int KEY_DOWN = nn::hw::pad::KEY_DOWN; + static const int BUTTON_R = nn::hw::pad::BUTTON_R; + static const int BUTTON_L = nn::hw::pad::BUTTON_L; + static const int BUTTON_X = nn::hw::pad::BUTTON_X; + static const int BUTTON_Y = nn::hw::pad::BUTTON_Y; + static const int BUTTON_DEBUG = nn::hw::pad::BUTTON_DEBUG; +#endif + +#ifdef NW_PLATFORM_CTR + static const int BUTTON_A = nn::hid::CTR::BUTTON_A; + static const int BUTTON_B = nn::hid::CTR::BUTTON_B; + static const int BUTTON_SELECT = nn::hid::CTR::PSEUDO_BUTTON_SELECT; + static const int BUTTON_START = nn::hid::CTR::BUTTON_START; + static const int KEY_RIGHT = nn::hid::CTR::BUTTON_RIGHT; + static const int KEY_LEFT = nn::hid::CTR::BUTTON_LEFT; + static const int KEY_UP = nn::hid::CTR::BUTTON_UP; + static const int KEY_DOWN = nn::hid::CTR::BUTTON_DOWN; + static const int BUTTON_R = nn::hid::CTR::BUTTON_R; + static const int BUTTON_L = nn::hid::CTR::BUTTON_L; + static const int BUTTON_X = nn::hid::CTR::BUTTON_X; + static const int BUTTON_Y = nn::hid::CTR::BUTTON_Y; + static const int BUTTON_DEBUG = nn::hid::CTR::BUTTON_DEBUG; +#endif + + static void init(); + static void update( int system_stt ); + static void finish(); + + static f32 getSvr2Volume(); + + static f32 getNormalizeX(); + static f32 getNormalizeY(); + + static const f32 c3dVolume = 0.85f; + +private: + + static u16 isTouched(); + static u16 isReleased(); + static u16 isTouching(); + + static const nw::math::VEC2& getPos(){ return msTPPos; } + + static u16 getPadTrig(); + static bool isButtonTrig( u16 button ); + static bool isButtonHold( u16 button ); + + static u16 msPad; + static u16 msPadPrev; + static u16 msPadTrig; + + static bool msTP; // タッチしているときtrue. + static bool msTPTouch; // 1フレーム前にタッチしていたときtrue. + static nw::math::VEC2 msTPPos; // タッチしているときのタッチ位置の整数値. + static nw::math::VEC2 msTPFloatPos; // タッチしているときのタッチ位置. + +#ifdef NW_PLATFORM_CTR + static nn::hid::CTR::PadReader* mspPadReader; + static nn::hid::CTR::PadStatus* mspPadStatus; + + static nn::hid::CTR::TouchPanelReader* mspTpReader; + static nn::hid::CTR::TouchPanelStatus* mspTpStatus; + + static nn::hid::CTR::PadReaderWithSvr2* smpPadReaderWithSvr2; +#else + static LRESULT Callback( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, BOOL *handled ); +#endif + + friend class gui::Manager; + friend class gui::Button; + friend class gui::RepeatButton; + friend class gui::RadioButton; + friend class gui::SliderBar; + friend class gui::MayaButton; + friend class gui::TouchSlider; + friend class DialogManager; + friend class DialogButton; + friend int ut::IsInBoundPane( lyt::Object* lyt_obj, const char* group_name ); + + friend class scene::CalibrationLayout; + friend class scene::CalibrationGuiOperator; + friend class scene::StartLayout; + friend class scene::CoppaLayout; + +#ifndef NW_RELEASE + friend class scene::SceneController; + friend class scene::DebugLayout; + friend class scene::DialogScene; + friend class scene::DataMngLayout; + friend class scene::DataCmmLayout; + friend class scene::CheckScene; + + friend class scene::InternetFnc; + friend class scene::DataMngFnc; + friend class scene::CoppaFnc; +#endif +}; + +} +#endif diff --git a/trunk/SkipFirstLaunch/sysSharedExtSaveData.cpp b/trunk/SkipFirstLaunch/sysSharedExtSaveData.cpp new file mode 100644 index 0000000..cdee6a5 --- /dev/null +++ b/trunk/SkipFirstLaunch/sysSharedExtSaveData.cpp @@ -0,0 +1,286 @@ +// sysFirmware.cpp : コンソール アプリケーションのエントリ ポイントを定義します。 +// + +#include "sysSharedExtSaveData.h" + +#include +#include +#include +#include +#include +#include +//#include + +#include + +namespace sys +{ + namespace + { + struct Parameter + { + size_t defaultLimitSize; + size_t limitSize; + u32 entryFile; + u32 entryDirectory; + }; + +#if 0 + // refreshLimitSize を呼ぶ場合の初期値 + Parameter cPnoteMPPotoParam = { 64 * 1024 * 1024 , 0 , 501 , 505 }; + Parameter cSnoteSoundParam = { 1232 * 1024 , 0 , 20 , 1 }; + Parameter cNewsBossDataParam = { 0 , 0 , 100 , 1 }; + Parameter cCommonDataParam = { 0 , 0 , 8 , 0 }; + Parameter cBashotoryaDataParam = { 0 , 0 , 6 , 1 }; +#else + // 直で呼ぶ場合の初期値 今はこっち + Parameter cPnoteMPPotoParam = { 0 , 64 * 1024 * 1024 , 511 , 511 }; + Parameter cSnoteSoundParam = { 0 , 1232 * 1024 , 32 , 16 }; + Parameter cNewsBossDataParam = { 0 , 4354048 , 127 , 16 }; + Parameter cCommonDataParam = { 0 , 9277440 , 16 , 16 }; + Parameter cBashotoryaDataParam = { 0 , 2785280 , 16 , 16 }; + // = 2719744(データ5件+キャッシュ) + 64kb + // = 2498560(データ4件+おしらせ1件+キャッシュ) + 32kb + 220kb(データ-おしらせ) + 28kb +#endif + + Parameter* cParams[SharedExtSaveData::cIDCount] = { + &cPnoteMPPotoParam, + &cSnoteSoundParam, + &cNewsBossDataParam, + &cCommonDataParam, + &cBashotoryaDataParam, + }; + + const char *cParamsString[SharedExtSaveData::cIDCount] = { + "PnoteMPPoto ", + "SnoteSound ", + "NewsBossData ", + "CommonData ", + "BashotoryaData ", + }; + } + + const bit32 SharedExtSaveData::cIDs[SharedExtSaveData::cIDCount] = { + SharedExtSaveData::cPnoteMPPoto, + SharedExtSaveData::cSnoteSound, + SharedExtSaveData::cNewsBossData, + SharedExtSaveData::cCommonData, + SharedExtSaveData::cBashotorya, + }; + + void SharedExtSaveData::refreshLimitSize() + { + for ( int i = 0; i < cIDCount; ++ i ) + { + switch ( i ) + { + // ファイルが 100 作れて、ファイル自体の合計は 4M になるように + case eType_BossData: + { + s64 size = 0; + const s64 filesize_table[ 1 ] = { 4 * 1024 * 1024 }; + nn::Result result = nn::fs::QueryTotalQuotaSize( &size , + cParams[ i ]->entryDirectory , + cParams[ i ]->entryFile , + filesize_table , + 1 ); + if ( result.IsSuccess() ) + { + cParams[ i ]->limitSize = static_cast< size_t > ( size ); + NN_LOG( "%s dir: %d file: %d size: %d\n" , cParamsString[ i ] , + cParams[ i ]->entryDirectory , + cParams[ i ]->entryFile , + cParams[ i ]->limitSize ); + } + } + break; + + // 汎用データ→IDB+GameCoin+LBL+GBL+BindingFolder+Mii + case eType_Common: + { + s64 size = 0; + const s64 filesize_table[ 8 ] = + { + 7159808 , // idb + 8200 , // idbt + 20 , // gamecoin + 12000 , // LBL + 97328 , // GBL + 4 , // BindingFolder + 310560 , // Mii1 + 310560 , // Mii2 + }; + nn::Result result = nn::fs::QueryTotalQuotaSize( &size , + cParams[ i ]->entryDirectory , + cParams[ i ]->entryFile , + filesize_table , + 8 ); + if ( result.IsSuccess() ) + { + cParams[ i ]->limitSize = static_cast< size_t > ( size ); + NN_LOG( "%s dir: %d file: %d size: %d\n" , cParamsString[ i ] , + cParams[ i ]->entryDirectory , + cParams[ i ]->entryFile , + cParams[ i ]->limitSize ); + } + } + break; + + // バショトリャー + case eType_Bashotorya: + { + s64 size = 0; + const s64 filesize_table[ 6 ] = + { + 274 * 1024 + 52 , + 274 * 1024 + 52 , + 274 * 1024 + 52 , + 274 * 1024 + 52 , + 274 * 1024 + 52 , + 1096 * 1024 , + }; + nn::Result result = nn::fs::QueryTotalQuotaSize( &size , + cParams[ i ]->entryDirectory , + cParams[ i ]->entryFile , + filesize_table , + sizeof( filesize_table ) / sizeof( *filesize_table ) ); + if ( result.IsSuccess() ) + { + cParams[ i ]->limitSize = static_cast< size_t > ( size ); + NN_LOG( "%s dir: %d file: %d size: %d\n" , cParamsString[ i ] , + cParams[ i ]->entryDirectory , + cParams[ i ]->entryFile , + cParams[ i ]->limitSize ); + } + } + break; + + // 初期値をコピーする + default: + cParams[ i ]->limitSize = cParams[ i ]->defaultLimitSize; + NN_LOG( "%s dir: %d file: %d size: %d\n" , cParamsString[ i ] , + cParams[ i ]->entryDirectory , + cParams[ i ]->entryFile , + cParams[ i ]->limitSize ); + break; + } + } + } + + void SharedExtSaveData::createData() + { + //refreshLimitSize(); // QueryTotalQuotaSize を計算する + + nn::Result res; + + for ( int i=0; ientryDirectory, cParams[i]->entryFile, cParams[i]->limitSize ); + + NN_LOG( "%d size -> %d %d\n" , i , cParams[ i ]->limitSize , res.IsSuccess() ); + NN_ASSERT_RESULT( res ); + + if ( res.IsFailure() ) + { + NN_LOG( "result = %d %d %d\n" , res.GetLevel() , res.GetSummary() , res.GetModule() ); + } + } + } + + void SharedExtSaveData::deleteData() + { + nn::Result res; + + for ( int i=0; ientryDirectory, cParams[i]->entryFile, cParams[i]->limitSize); + } + else if(res <= nn::fs::ResultNotFormatted()) + { + // フォーマットされていない。フォーマットを行なう。 + // - まず発生しないはず。 + //res = nn::fs::DeleteSharedExtSaveData( cIDs[i] ); + //NN_ASSERT_RESULT( res ); + + res = nn::fs::CreateSharedExtSaveData(cIDs[i], + cParams[i]->entryDirectory, cParams[i]->entryFile, cParams[i]->limitSize); + } + else if(res <= nn::fs::ResultBadFormat()) + { + // 不正なフォーマット。フォーマットを行なう。 + // - ノイズ等の可能性もあるので、リトライしてもよい? + res = nn::fs::CreateSharedExtSaveData(cIDs[i], + cParams[i]->entryDirectory, cParams[i]->entryFile, cParams[i]->limitSize); + } + else if(res <= nn::fs::ResultVerificationFailed()) + { + // 検証に失敗。フォーマットを行なう。 + res = nn::fs::CreateSharedExtSaveData(cIDs[i], + cParams[i]->entryDirectory, cParams[i]->entryFile, cParams[i]->limitSize); + } + else + { + // それ以外は、発生しないはず。FATALへ。 + // - ノイズ等の可能性もあるので、リトライしてもよい? + } + + if(res.IsFailure()) + { + // ここで失敗した場合は、さすがに FATAL へ。 + } + else + { + // 再マウント + // - ここで失敗した場合は、さすがに FATAL へ。 + res = nn::fs::MountSharedExtSaveData(volume, cIDs[i] ); + + if ( res.IsFailure() ) + { + // ここも FATAL?(河野) + }else{ + nn::fs::Unmount(volume); + } + } + }else{ + nn::fs::Unmount(volume); + } + NN_ASSERT_RESULT( res ); + } + } + + // 領域の説明を返す + const char *SharedExtSaveData::getInfoString( bit32 id ) + { + for ( int i = 0; i + +namespace sys +{ + class SharedExtSaveData + { + public: + + enum SharedExtSaveDataType + { + eType_Photo = 0 , + eType_Sound , + eType_BossData , + eType_Common , + eType_Bashotorya , + eType_Max + }; + static const int cIDCount = eType_Max; + static const bit32 cIDs[cIDCount]; + + static const bit32 cPnoteMPPoto = 0xF0000001; // PNOTEのMP画像(写真) + static const bit32 cSnoteSound = 0xF0000002; // SNOTEのAACデータ(音声) + static const bit32 cNewsBossData = 0xF0000009; // おしらせBOSSデータ 7168KB 128 8 拡張セーブデータでした + static const bit32 cCommonData = 0xF000000B; // 汎用データ + static const bit32 cBashotorya = 0xF000000C; // バショトリャー + + static void createData(); + static void deleteData(); + static void checkData(); + static void refreshLimitSize(); + + // 領域の説明を返す + static const char *getInfoString( bit32 id ); + }; +} + +#endif // ifndef __SYS_SHARED_EXT_SAVE_DATA_H_ diff --git a/trunk/SkipFirstLaunch/sysUserInfoAccessor.cpp b/trunk/SkipFirstLaunch/sysUserInfoAccessor.cpp new file mode 100644 index 0000000..c5431e9 --- /dev/null +++ b/trunk/SkipFirstLaunch/sysUserInfoAccessor.cpp @@ -0,0 +1,2462 @@ +/*! + @file sysUserInfoAccessor.cpp + @brief ユーザ情報アクセサ + */ +#ifndef MAKE_AREACHECK + +#include "sys.h" + +#include "sysUserInfoAccessor.h" +#include "sysKeyboardManager.h" +#include "sysSystem.h" +#include "sysFile.h" +#include "sysInput.h" + +#include "sceneOtherThread.h" +#include "sceneDataTable.h" + +#include "ImageDb.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef NW_RELEASE +#include "sceneDebugLayout.h" +#endif + +#define MOUNT_SHARED_AREA +#define MOUNT_SHARED_EULA + +namespace sys +{ + +//========================================================================== +// +//========================================================================== +const nn::ProgramId cSharedAreaId[] = +{ + nn::pl::CTR::SHAREDDATA_TITLEID_COUNTRY_REGION, +}; + +#ifdef MOUNT_SHARED_AREA + +static const char* cSharedCountryFile[] = +{ + "area:/JP/country_LZ.bin", + "area:/US/country_LZ.bin", + "area:/EU/country_LZ.bin", + "area:/EU/country_LZ.bin", + "area:/CN/country_LZ.bin", + "area:/KR/country_LZ.bin", + "area:/TW/country_LZ.bin", +}; + +static const char* cSharedAreaFile[] = +{ + "area:/JP/%d_LZ.bin", + "area:/US/%d_LZ.bin", + "area:/EU/%d_LZ.bin", + "area:/EU/%d_LZ.bin", + "area:/CN/%d_LZ.bin", + "area:/KR/%d_LZ.bin", + "area:/TW/%d_LZ.bin", +}; + +#else +// 共有データにするとき不要 +static const char* cCountryFile[] = +{ + "rom:/country/JP/country_LZ.bin", + "rom:/country/US/country_LZ.bin", + "rom:/country/EU/country_LZ.bin", + "rom:/country/EU/country_LZ.bin", + "rom:/country/CN/country_LZ.bin", + "rom:/country/KR/country_LZ.bin", + "rom:/country/TW/country_LZ.bin", +}; + +static const char* cAreaFile[] = +{ + "rom:/country/JP/%d_LZ.bin", + "rom:/country/US/%d_LZ.bin", + "rom:/country/EU/%d_LZ.bin", + "rom:/country/EU/%d_LZ.bin", + "rom:/country/CN/%d_LZ.bin", + "rom:/country/KR/%d_LZ.bin", + "rom:/country/TW/%d_LZ.bin", +}; +#endif + +#ifdef MOUNT_SHARED_EULA +const nn::ProgramId cSharedEulaId[] = +{ + nn::pl::CTR::SHAREDDATA_TITLEID_EULA_JP, + nn::pl::CTR::SHAREDDATA_TITLEID_EULA_US, + nn::pl::CTR::SHAREDDATA_TITLEID_EULA_EU, + nn::pl::CTR::SHAREDDATA_TITLEID_EULA_EU, + nn::pl::CTR::SHAREDDATA_TITLEID_EULA_CN, + nn::pl::CTR::SHAREDDATA_TITLEID_EULA_KR, + nn::pl::CTR::SHAREDDATA_TITLEID_EULA_TW, +}; +#else +static const char* cEulaCountry[] = +{ + "rom:/eula/JP/country.bin", + "rom:/eula/US/country.bin", + "rom:/eula/EU/country.bin", + "rom:/eula/EU/country.bin", + "rom:/eula/CN/country.bin", + "rom:/eula/KR/country.bin", + "rom:/eula/TW/country.bin", +}; +#endif + + +//---------------------------------------------------------------- +// TWLでユーザ名、コメントとして入力可能な文字コードリスト +const u16 cTwlUserInfoFontCodeTable[] = +{ + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002A,0x002B,0x002C,0x002D,0x002E,0x002F, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004A,0x004B,0x004C,0x004D,0x004E,0x004F, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005A,0x005B,0x005C,0x005D,0x005E,0x005F, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007A,0x007B,0x007D,0x007E,0x00A1,0x00A2, + 0x00A3,0x00A9,0x00AE,0x00B0,0x00B1,0x00BF,0x00C0,0x00C1, + 0x00C2,0x00C4,0x00C7,0x00C8,0x00C9,0x00CA,0x00CB,0x00CC, + 0x00CD,0x00CE,0x00CF,0x00D1,0x00D2,0x00D3,0x00D4,0x00D6, + 0x00D7,0x00D9,0x00DA,0x00DB,0x00DC,0x00DF,0x00E0,0x00E1, + 0x00E2,0x00E4,0x00E7,0x00E8,0x00E9,0x00EA,0x00EB,0x00EC, + 0x00ED,0x00EE,0x00EF,0x00F1,0x00F2,0x00F3,0x00F4,0x00F6, + 0x00F7,0x00F9,0x00FA,0x00FB,0x00FC,0x0152,0x0153,0x02C6, + 0x02DC,0x201C,0x201D,0x2022,0x2026,0x2033,0x203B,0x20AC, + 0x2122,0x2190,0x2191,0x2192,0x2193,0x221E,0x2234,0x25A0, + 0x25A1,0x25B2,0x25B3,0x25BC,0x25BD,0x25C6,0x25C7,0x25CB, + 0x25CE,0x25CF,0x2605,0x2606,0x266A,0x266D,0x3000,0x3001, + 0x3002,0x300C,0x300D,0x3012,0x3041,0x3042,0x3043,0x3044, + 0x3045,0x3046,0x3047,0x3048,0x3049,0x304A,0x304B,0x304C, + 0x304D,0x304E,0x304F,0x3050,0x3051,0x3052,0x3053,0x3054, + 0x3055,0x3056,0x3057,0x3058,0x3059,0x305A,0x305B,0x305C, + 0x305D,0x305E,0x305F,0x3060,0x3061,0x3062,0x3063,0x3064, + 0x3065,0x3066,0x3067,0x3068,0x3069,0x306A,0x306B,0x306C, + 0x306D,0x306E,0x306F,0x3070,0x3071,0x3072,0x3073,0x3074, + 0x3075,0x3076,0x3077,0x3078,0x3079,0x307A,0x307B,0x307C, + 0x307D,0x307E,0x307F,0x3080,0x3081,0x3082,0x3083,0x3084, + 0x3085,0x3086,0x3087,0x3088,0x3089,0x308A,0x308B,0x308C, + 0x308D,0x308E,0x308F,0x3092,0x3093,0x30A1,0x30A2,0x30A3, + 0x30A4,0x30A5,0x30A6,0x30A7,0x30A8,0x30A9,0x30AA,0x30AB, + 0x30AC,0x30AD,0x30AE,0x30AF,0x30B0,0x30B1,0x30B2,0x30B3, + 0x30B4,0x30B5,0x30B6,0x30B7,0x30B8,0x30B9,0x30BA,0x30BB, + 0x30BC,0x30BD,0x30BE,0x30BF,0x30C0,0x30C1,0x30C2,0x30C3, + 0x30C4,0x30C5,0x30C6,0x30C7,0x30C8,0x30C9,0x30CA,0x30CB, + 0x30CC,0x30CD,0x30CE,0x30CF,0x30D0,0x30D1,0x30D2,0x30D3, + 0x30D4,0x30D5,0x30D6,0x30D7,0x30D8,0x30D9,0x30DA,0x30DB, + 0x30DC,0x30DD,0x30DE,0x30DF,0x30E0,0x30E1,0x30E2,0x30E3, + 0x30E4,0x30E5,0x30E6,0x30E7,0x30E8,0x30E9,0x30EA,0x30EB, + 0x30EC,0x30ED,0x30EE,0x30EF,0x30F2,0x30F3,0x30F4,0x30F5, + 0x30F6,0x30FC,0xE000,0xE001,0xE002,0xE003,0xE004,0xE005, + 0xE006,0xE007,0xE008,0xE009,0xE00A,0xE00B,0xE00C,0xE00D, + 0xE00E,0xE00F,0xE010,0xE011,0xE012,0xE013,0xE015,0xE016, + 0xE017,0xE018,0xE019,0xE01A,0xE01B,0xE01C,0xE028,0xFF01, + 0xFF0F,0xFF1F,0xFF3C,0xFF3E,0xFF5B,0xFF5C,0xFF5D,0xFF5E +}; //計392文字 + +//---------------------------------------------------------------- +// BOSS へ情報を送信する際のタスクID +static const char* cSendBossInfoTaskId = "sendcfg"; +static const char* cSendBossMmenTaskId = "sendmgn"; +static const char* cSendPhuTaskId = "phu"; +static const char* cSendTiuTaskId = "tiu"; +static const char* cSendSpluTaskId = "splu"; +static const char* cSendBossPnoteTaskId = "URUP"; + +//********************************************************************************* +// 変数 +//********************************************************************************* +FirstInfo UserInfoAccessor::msFirst; // 初回起動用フラグ + +UserInfo UserInfoAccessor::msUserInfo; // 更新中のデータ +UserInfo UserInfoAccessor::msBackupUserInfo; // リセット用のバックアップデータ + +TwlInfo UserInfoAccessor::msTwlInfo; +TwlInfo UserInfoAccessor::msBackupTwlInfo; + +TwlInfo2 UserInfoAccessor::msTwlInfo2; +TwlInfo2 UserInfoAccessor::msBackupTwlInfo2; + +WorkInfo UserInfoAccessor::msWorkInfo; +WorkInfo UserInfoAccessor::msBackupWorkInfo; + +nn::cfg::CTR::ParentalControlInfo UserInfoAccessor::msParentInfo; +nn::cfg::CTR::ParentalControlInfo UserInfoAccessor::msBackupParentInfo; + +nn::cfg::CTR::detail::CoppacsCfgData UserInfoAccessor::msCoppaInfo; +nn::cfg::CTR::detail::CoppacsCfgData UserInfoAccessor::msBackupCoppaInfo; + +nn::cfg::CTR::detail::FirstLaunchInfoCfgData UserInfoAccessor::msFirstInfo; + +NetInfo UserInfoAccessor::msNetInfo; +NetInfo UserInfoAccessor::msBackupNetInfo; + +int UserInfoAccessor::msAccNum = -1; // 接続先 +int UserInfoAccessor::msTmpNum; // 設定先 + +BossSendInfo UserInfoAccessor::msBossSendInfo; + +u32 UserInfoAccessor::msDirty = 0; + +u16 UserInfoAccessor::msCountryNum = 1; + +u8* UserInfoAccessor::mpSharedAreaBuf = NULL; + +bool UserInfoAccessor::msIsNetSave; +bool UserInfoAccessor::msIsCoppa = false; + +// スライダーバーで使用する要素 +wchar_t UserInfoAccessor::msSlideStr[UserInfoAccessor::eFactNum][UserInfoAccessor::eStrSize]; + +const wchar_t* UserInfoAccessor::mspSlideFact[UserInfoAccessor::eFactNum] = +{ + msSlideStr[0], msSlideStr[1], msSlideStr[2], msSlideStr[3], msSlideStr[4], + msSlideStr[5], msSlideStr[6], msSlideStr[7], msSlideStr[8], msSlideStr[9], + msSlideStr[10], msSlideStr[11], msSlideStr[12], msSlideStr[13], msSlideStr[14], + msSlideStr[15], msSlideStr[16], msSlideStr[17], msSlideStr[18], msSlideStr[19], + msSlideStr[20], msSlideStr[21], msSlideStr[22], msSlideStr[23], msSlideStr[24], + msSlideStr[25], msSlideStr[26], msSlideStr[27], msSlideStr[28], msSlideStr[29], + msSlideStr[30], msSlideStr[31], msSlideStr[32], msSlideStr[33], msSlideStr[34], + msSlideStr[35], msSlideStr[36], msSlideStr[37], msSlideStr[38], msSlideStr[39], + msSlideStr[40], msSlideStr[41], msSlideStr[42], msSlideStr[43], msSlideStr[44], + msSlideStr[45], msSlideStr[46], msSlideStr[47], msSlideStr[48], msSlideStr[49], + msSlideStr[50], msSlideStr[51], msSlideStr[52], msSlideStr[53], msSlideStr[54], + msSlideStr[55], msSlideStr[56], msSlideStr[57], msSlideStr[58], msSlideStr[59], + msSlideStr[60], msSlideStr[61], msSlideStr[62], msSlideStr[63], msSlideStr[64], + msSlideStr[65], msSlideStr[66], msSlideStr[67], msSlideStr[68], msSlideStr[69], + msSlideStr[70], msSlideStr[71], msSlideStr[72], msSlideStr[73], msSlideStr[74], + msSlideStr[75], msSlideStr[76], msSlideStr[77], msSlideStr[78], msSlideStr[79], + msSlideStr[80], msSlideStr[81], msSlideStr[82], msSlideStr[83], msSlideStr[84], + msSlideStr[85], msSlideStr[86], msSlideStr[87], msSlideStr[88], msSlideStr[89], + msSlideStr[90], msSlideStr[91], msSlideStr[92], msSlideStr[93], msSlideStr[94], + msSlideStr[95], msSlideStr[96], msSlideStr[97], msSlideStr[98], msSlideStr[99], +}; + + +//********************************************************************************* +// 初期化 +//********************************************************************************* +//========================================================================== +// +//========================================================================== +void UserInfoAccessor::init( int flg ) +{ +int event = eUserInfo_Save1; + +// 各Infoのクリア + memset( &msUserInfo, 0, sizeof( msUserInfo ) ); + memset( &msTwlInfo, 0, sizeof( msTwlInfo ) ); + memset( &msTwlInfo2, 0, sizeof( msTwlInfo2 ) ); + memset( &msParentInfo, 0, sizeof( msParentInfo ) ); + memset( &msCoppaInfo, 0, sizeof( msCoppaInfo ) ); + memset( &msNetInfo, 0, sizeof( msNetInfo ) ); + memset( &msWorkInfo, 0, sizeof( msWorkInfo ) ); + memset( &msFirst, 0, sizeof( msFirst ) ); + + msDirty = eNoneInfo; + msIsNetSave = true; + + if( flg == 0 ) + { + // リージョン + { + System::set_region_( nn::cfg::CTR::GetRegion() ); + System::set_language_( nn::cfg::CTR::GetLanguage() ); + } + + // 初回起動フラグのload + data_user_info_( eKindFirst, 0 ); + } + + check_first_set_(); + + if( msFirstInfo.mmen == 0 ) // 初回起動のとき + { + // 初回起動用パラメータ + setFirstParam(); + + event = eUserInfo_Save2; + } +#ifndef NW_RELEASE + else + { + // (デバッグ機能)初回起動をしないでMSETに入ったときのため + { + if( wcslen( msUserInfo.usr_name.userName.userName ) == 0 ) + { + swprintf( msUserInfo.usr_name.userName.userName, 11, L"USER_NAME" ); + } + + if( msUserInfo.usr_birthday.month == 0 ) + { + msUserInfo.usr_birthday.month = 1; + msUserInfo.usr_birthday.day = 1; + } + + if( msUserInfo.usr_address.regionName[0][0] == L'\0' ) + { + swprintf( msUserInfo.usr_address.regionName[0], 10, L"-" ); + } + } + } + + //フォントテーブルが昇順で並んでいることを確認する + NN_ASSERT(check_order_twl_user_info_font_table_()); +#endif + + set_country_info_(); + + msDirty = eAllInfo; + + // 初回起動のときは通信系プロセスが起動してないので、その部分を書き込まない + if( msFirstInfo.mmen == 0 ) msDirty &= ~eNetInfo; + + eventProc( event ); +} + + +//========================================================================== +// 破棄 +//========================================================================== +void UserInfoAccessor::destroy() +{ + delete mpSharedAreaBuf; +} + + +//========================================================================== +// 共有データの読み込み +// flg : 0 国データ、1 地域データ +//========================================================================== +u8* UserInfoAccessor::readCountryData( int flg ) +{ +u8* p_data = NULL; +u8* mount_buf = NULL; +u32 size; + +#ifdef MOUNT_SHARED_AREA + mount_buf = sys::File::mountShare( "area:", cSharedAreaId[0], 0, 200, 10 ); + + if( mount_buf != NULL ) + { + NN_LOG( "area data mount\n" ); + } + + if( flg == 0 ) + { + p_data = sys::File::readLZ( cSharedCountryFile[System::getRegion()], &size ); + } + else + { + char file[40] = ""; + + UT_SPRINTF( file, cSharedAreaFile[System::getRegion()], msWorkInfo.country_id ); + p_data = sys::File::readLZ( file, &size ); + + NN_LOG( "file %s\n", file ); + } + + nn::fs::Unmount( "area:" ); + delete []mount_buf; +#else + if( flg == 0 ) + { + p_data = sys::File::readLZ( cCountryFile[System::getRegion()], &size ); + } + else + { + char file[40] = ""; + + UT_SPRINTF( file, cAreaFile[System::getRegion()], msWorkInfo.country_id ); + p_data = sys::File::readLZ( file, &size ); + + NN_LOG( "file %s\n", file ); + } + +#endif + return p_data; +} + + +//========================================================================== +// 初回起動チェック +//========================================================================== +void UserInfoAccessor::check_first_set_() +{ +#ifdef MAKE_ACCTEST +// 接続検証 + { + // ユーザー情報をNANDから読み込み + for( int i = eKindUserName; i <= eKindDsEula; i++ ) + { + data_user_info_( i, 0 ); + } + + // ネット設定 + { + nn::ac::InitializeInternal(); + nn::ac::LoadNetworkSetting( 0, msNetInfo.setting[0] ); + nn::ac::LoadNetworkSetting( 1, msNetInfo.setting[1] ); + nn::ac::LoadNetworkSetting( 2, msNetInfo.setting[2] ); + nn::ac::FinalizeInternal(); + +#ifndef NW_RELEASE + print_net_save_(); // ネットワーク設定のNAND内容をデバッグ表示 +#endif + } + + setFirstAll( true ); + + msBackupUserInfo = msUserInfo; + msBackupTwlInfo = msTwlInfo; + msBackupTwlInfo2 = msTwlInfo2; + msBackupParentInfo = msParentInfo; + msBackupCoppaInfo = msCoppaInfo; + msBackupNetInfo = msNetInfo; + msBackupWorkInfo = msWorkInfo; + } +#else +// MSET + if( msFirstInfo.mmen == 0 ) // 初回起動のとき + { + ProcessManager::rejectPowerBtn( true ); + ProcessManager::rejectSleep( true ); + + setFirstAll( false ); + + if( System::isSafeMode() ) + { + msIsNetSave = false; + } + + // TWLの初期化 + { + scene::OtherFnc::ClearNorSetting(); // 通信プロセス起動前にNORをクリアする + + data_user_info_( eKindDsData, 0 ); + } + + // ネット設定初期化はDaemon類が起動してないので後回しにします + + // ImageDbの初期化処理 + { + imgdb::Result result = imgdb::SetupTwlNand( System::getSdkAllocator() ); + + if( result == imgdb::ResultSuccess ) + { + // 初期化成功 + NN_LOG( "ImageDb Initialize Success\n" ); + } + else + { + // ここに来た場合は致命的なエラー + // NANDなどが壊れていたりするとこの結果になるかもしれません + // 詳細は未定 +// NN_PANIC( "Error! Result=%d\n", result ); + NN_WARNING( false, "Error! Result = %d\n", result); + } + } + + NN_LOG( "first boot( 0 )\n" ); + } + else // 初回起動が終わっているとき + { + // ユーザー情報をNANDから読み込み + for( int i = eKindUserName; i <= eKindDsEula; i++ ) + { + if( i != eKindCoppa ) + { + data_user_info_( i, 0 ); + } + } + + // ネット設定 + { + nn::ac::InitializeInternal(); + nn::ac::LoadNetworkSetting( 0, msNetInfo.setting[0] ); + nn::ac::LoadNetworkSetting( 1, msNetInfo.setting[1] ); + nn::ac::LoadNetworkSetting( 2, msNetInfo.setting[2] ); + nn::ac::FinalizeInternal(); + } + + setFirstAll( true ); + + msBackupUserInfo = msUserInfo; + msBackupTwlInfo = msTwlInfo; + msBackupTwlInfo2 = msTwlInfo2; + msBackupParentInfo = msParentInfo; + msBackupNetInfo = msNetInfo; + msBackupWorkInfo = msWorkInfo; + } + +// COPPACSは必ずロードする + { + // COPPACSは必要な国か? + setCoppacs(); + + // Coppaは必ずloadする + data_user_info_( eKindCoppa, 0 ); + + msBackupCoppaInfo = msCoppaInfo; + } +#endif +} + + +//========================================================================== +// 初回起動時の国情報の読み込み +//========================================================================== +void UserInfoAccessor::set_country_info_() +{ +u8* mount_buf = NULL; + + { + u8* p_data = readCountryData( 0 ); + int* p_data1 = reinterpret_cast( p_data ); + int cid = msUserInfo.usr_address.id>>24; + + msCountryNum = *p_data1++; + + if( msCountryNum == 1 ) // 国が1つのときは、最初に国情報をセーブしておく + { + CountryInfo* p_country = reinterpret_cast( p_data1 ); + int id = (p_country->id)>>24; + + msWorkInfo.country_id = id; + msWorkInfo.area_num = p_country->numRegion; + + if( id != cid ) + { + msUserInfo.usr_address.id = (id<<24); + + for( int i = 0; i < eAddrLangageNum; i++ ) + { + swprintf( msUserInfo.usr_address.countryName[i], + eAddrNameLength, (const wchar_t*)p_country->countryName[i] ); + } + + if( p_country->newEntry ) + { + msTwlInfo2.ds_country.country = nn::cfg::CTR::CFG_COUNTRY_OTHERS; + } + else + { + msTwlInfo2.ds_country.country = (u8)id; + } + } + } + else + { + CountryInfo* p_country = reinterpret_cast( p_data1 ); + int id; + + for( int i = 0; i < msCountryNum; i++ ) + { + id = (p_country->id)>>24; + + if( id == cid ) + { + msWorkInfo.country_id = id; + msWorkInfo.area_num = p_country->numRegion; + break; + } + p_country++; + } + } + + delete []p_data; + } + +// 1言語しかないリージョンのとき + switch( System::getRegion() ) + { + case nn::cfg::CTR::CFG_REGION_JAPAN: + msUserInfo.usr_language.languageCode = nn::cfg::CTR::CFG_LANGUAGE_JAPANESE; + msTwlInfo.ds_data.option.language = nn::cfg::CTR::CFG_LANGUAGE_JAPANESE; + msTwlInfo.ds_data_ex.language = nn::cfg::CTR::CFG_LANGUAGE_JAPANESE; + break; + + case nn::cfg::CTR::CFG_REGION_CHINA: + msUserInfo.usr_language.languageCode = nn::cfg::CTR::CFG_LANGUAGE_SIMP_CHINESE; + msTwlInfo.ds_data.option.language = nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; + msTwlInfo.ds_data_ex.language = nn::cfg::CTR::CFG_LANGUAGE_SIMP_CHINESE; + break; + + case nn::cfg::CTR::CFG_REGION_KOREA: + msUserInfo.usr_language.languageCode = nn::cfg::CTR::CFG_LANGUAGE_KOREAN; + msTwlInfo.ds_data.option.language = nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; + msTwlInfo.ds_data_ex.language = nn::cfg::CTR::CFG_LANGUAGE_KOREAN; + break; + + case nn::cfg::CTR::CFG_REGION_TAIWAN: + if( msFirstInfo.mmen == 0 ) // 初回起動のとき + { + msUserInfo.usr_language.languageCode = nn::cfg::CTR::CFG_LANGUAGE_TRAD_CHINESE; + msTwlInfo.ds_data.option.language = nn::cfg::CTR::CFG_LANGUAGE_JAPANESE; + msTwlInfo.ds_data_ex.language = nn::cfg::CTR::CFG_LANGUAGE_JAPANESE; + } + break; + + // US・EUリージョン + default: + if( msFirstInfo.mmen == 0 ) // 初回起動のとき + { + msUserInfo.usr_language.languageCode = nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; + msTwlInfo.ds_data.option.language = nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; + msTwlInfo.ds_data_ex.language = nn::cfg::CTR::CFG_LANGUAGE_ENGLISH; + } + break; + } +} + + +//========================================================================== +// 初回起動用パラメータ +//========================================================================== +void UserInfoAccessor::setFirstParam() +{ + msUserInfo.usr_sound.soundOutputMode = nn::cfg::CFG_SOUND_OUTPUT_MODE_SURROUND; + + msUserInfo.usr_birthday.month = 1; + msUserInfo.usr_birthday.day = 1; + + msTwlInfo.ds_data.owner.birthday.month = 1; + msTwlInfo.ds_data.owner.birthday.day = 1; + + msTwlInfo.ds_data.owner.userColor = 15; + + msTwlInfo.ds_data.option.isSetBirthday = 1; + msTwlInfo.ds_data.option.isSetUserColor = 1; + msTwlInfo.ds_data.option.isSetLanguage = 1; + msTwlInfo.ds_data.option.isSetNickname = 1; + + msTwlInfo2.ds_eula.agreeEulaVersion = 0xff; + + msWorkInfo.time[0] = 10; + msWorkInfo.time[1] = 0; + + switch( System::getRegion() ) + { + case nn::cfg::CTR::CFG_REGION_CHINA: + case nn::cfg::CTR::CFG_REGION_KOREA: + case nn::cfg::CTR::CFG_REGION_TAIWAN: + msWorkInfo.date[0] = 12; + break; + + default: + msWorkInfo.date[0] = 11; + break; + } + + msWorkInfo.date[1] = 1; + msWorkInfo.date[2] = 1; +} + + +//========================================================================== +// 初回起動フラグのセット・リセット +//========================================================================== +void UserInfoAccessor::setFirstAll( bool set ) +{ + if( set ) + { + msFirstInfo.mmen = 1; + + msFirst.end = 1; + msFirst.langage = 1; + msFirst.date = 1; + msFirst.time = 1; + + msFirst.name = 1; + msFirst.birthday = 1; + msFirst.country = 1; + msFirst.area = 1; + + msFirst.view = 1; + msFirst.eula = 1; + } + else + { + memset( &msFirstInfo, 0, sizeof( msFirstInfo ) ); + memset( &msFirst, 0, sizeof( msFirst ) ); + } +} + + +//********************************************************************************* +// イベント +//********************************************************************************* +void UserInfoAccessor::eventProc( int info_event ) +{ +int type = 1; +bool lang_change = false; + + switch( info_event ) + { + case eUserInfo_Save2: + type = 2; + + case eUserInfo_Save: + case eUserInfo_Save1: + if( msDirty > 0 ) + { + bool nand_write = false; + bool cop_check = false; + + if( msDirty & eUserInfo ) + { + bool save = false; + + // ユーザー情報のNAND書き込み + for( int i = eKindUserName; i <= eKindSound; i++ ) + { + if( data_user_info_( i, type ) ) + { + save = true; + + if( i == eKindAddressCountry ) + { + setBossTask(); + cop_check = true; + } + else if( i == eKindLanguage ) + { + System::set_language_( msUserInfo.usr_language.languageCode ); + + if( System::getRegion() == nn::cfg::CTR::CFG_REGION_TAIWAN ) + { + scene::Table::adjustSmngTable(); + } + + setBossTask(); + lang_change = true; + } + } + } + + if( save ) + { + nand_write = true; + NN_LOG( "Save UserInfo\n" ); + } + + msBackupUserInfo = msUserInfo; + } + + if( msDirty & eTwlInfo ) + { + if( data_user_info_( eKindDsData, type ) ) + { + NN_LOG( "Save TwlInfo\n" ); + } + + msBackupTwlInfo = msTwlInfo; + } + + if( msDirty & eTwlInfo2 ) + { + bool save = false; + + for( int i = eKindDsCountry; i <= eKindDsEula; i++ ) + { + if( data_user_info_( i, type ) ) + { + save = true; + } + } + + if( save ) + { + nand_write = true; + NN_LOG( "Save TwlInfo2\n" ); + } + + msBackupTwlInfo2 = msTwlInfo2; + } + + if( msDirty & eNetInfo ) + { + if( info_event != eUserInfo_Save1 ) + { + // ネットワーク設定のNAND書き込み + flush_net_setting_(); + } + + msBackupNetInfo = msNetInfo; + } + + if( msDirty & eNetInfo2 ) + { + bool save = false; + + // NAND書き込み + for( int i = eKindEula; i <= eKindBoss; i++ ) + { + if( data_user_info_( i, type ) ) + { + save = true; + } + } + + if( save ) + { + nand_write = true; + NN_LOG( "Save NetInfo2\n" ); + } + + msBackupNetInfo = msNetInfo; + } + + if( msDirty & eParentInfo ) + { + if( data_user_info_( eKindParental, type ) ) + { + nand_write = true; + NN_LOG( "Save Parental\n" ); + } + + msBackupParentInfo = msParentInfo; + } + +#ifdef NW_RELEASE +// COPPACSが必要な国だけCOPPACSのセーブあり(リリース以外は全バージョンでセーブあり) + if( msIsCoppa ) +#endif + { + if( msDirty & eCoppaInfo ) + { + if( type != 2 ) + { + if( data_user_info_( eKindCoppa, type ) ) + { + nand_write = true; + NN_LOG( "Save Coppa\n" ); + } + + msBackupCoppaInfo = msCoppaInfo; + } + } + } + + if( msDirty & eWorkInfo ) + { + msBackupWorkInfo = msWorkInfo; + } + + msDirty = eNoneInfo; + + if( nand_write ) // NAND書き込み + { + nn::Result result = nn::cfg::CTR::init::FlushConfig(); + + // COPPACSチェック + if( cop_check ) + { + setCoppacs(); + } + +#ifndef NW_RELEASE + NN_LOG( "flush_cnf = %d\n", result.IsSuccess() ); +#endif + } + } + break; + + case eUserInfo_Reset: + msUserInfo = msBackupUserInfo; + msTwlInfo = msBackupTwlInfo; + msTwlInfo2 = msBackupTwlInfo2; + msParentInfo = msBackupParentInfo; + msCoppaInfo = msBackupCoppaInfo; + msNetInfo = msBackupNetInfo; + msWorkInfo = msBackupWorkInfo; + + msDirty = eNoneInfo; + break; + + default: + break; + } + + // 完全にFlushしてから行う + if( lang_change ) + { + sys::KeyboardManager::repreload(); + } +} + + +//********************************************************************************* +// ユーザー情報 +//********************************************************************************* +//========================================================================== +// セーブ準備 +//========================================================================== +void UserInfoAccessor::setUserInfo( UserInfo& user_info ) +{ + msUserInfo = user_info; + msDirty |= eUserInfo; +} + + +//========================================================================== +// セーブ準備 +//========================================================================== +void UserInfoAccessor::setTwlInfo( TwlInfo& twl_info ) +{ + msTwlInfo = twl_info; + msDirty |= eTwlInfo; +} + + +//========================================================================== +// セーブ準備 +//========================================================================== +void UserInfoAccessor::setTwlInfo2( TwlInfo2& twl_info ) +{ + msTwlInfo2 = twl_info; + msDirty |= eTwlInfo2; +} + + +//========================================================================== +// ワーク +//========================================================================== +void UserInfoAccessor::setWorkInfo( WorkInfo& work_info ) +{ + msWorkInfo = work_info; + msDirty |= eWorkInfo; +} + + +//********************************************************************************* +// ペアレンタル情報 +//********************************************************************************* +//========================================================================== +// セーブ準備 +//========================================================================== +void UserInfoAccessor::setParentInfo( nn::cfg::CTR::ParentalControlInfo& parent_info ) +{ + msParentInfo = parent_info; + msDirty |= eParentInfo; +} + + +//========================================================================== +// ペアレンタルクリア +//========================================================================== +void UserInfoAccessor::clrParentInfo( bool eula ) +{ + memset( &msParentInfo, 0, sizeof( msParentInfo ) ); + memset( &msTwlInfo2.ds_pare, 0, sizeof( nn::cfg::CTR::detail::TwlParentalControlInfoCfgData ) ); + + msDirty |= eParentInfo; + msDirty |= eTwlInfo2; + + if( eula ) + { + clrNet2(); + } +} + + +//========================================================================== +// ペアレンタル設定が更新されたかチェック +//========================================================================== +bool UserInfoAccessor::isCheckParentInfo() +{ +s8* org = (s8*)( &msParentInfo ); +s8* back = (s8*)( &msBackupParentInfo ); +int size = sizeof( msParentInfo ); + + for( int i = 0; i < size; i++ ) + { + if( *org++ != *back++ ) + { + return true; // 変更があったらtrue + } + } + return false; +} + + +//********************************************************************************* +// COPPACS情報 +//********************************************************************************* +//========================================================================== +// セーブ準備 +//========================================================================== +void UserInfoAccessor::setCoppaInfo( nn::cfg::CTR::detail::CoppacsCfgData& coppa_info ) +{ + msCoppaInfo = coppa_info; + msDirty |= eCoppaInfo; +} + + +//========================================================================== +// COPPACS設定が更新されたかチェック +//========================================================================== +bool UserInfoAccessor::isCheckCoppaInfo() +{ +s8* org = (s8*)( &msCoppaInfo ); +s8* back = (s8*)( &msBackupCoppaInfo ); +int size = sizeof( msCoppaInfo ); + + for( int i = 0; i < size; i++ ) + { + if( *org++ != *back++ ) + { + return true; // 変更があったらtrue + } + } + return false; +} + + +//========================================================================== +// セーブ +//========================================================================== +void UserInfoAccessor::saveCoppaInfo( nn::cfg::CTR::detail::CoppacsCfgData& coppa_info ) +{ + msCoppaInfo = coppa_info; + + if( data_user_info_( eKindCoppa, 1 ) ) + { + nn::cfg::CTR::init::FlushConfig(); + + NN_LOG( "Save Coppa\n" ); + } + + msBackupCoppaInfo = msCoppaInfo; +} + + +//========================================================================== +// COPPACSが必要かどうか +//========================================================================== +void UserInfoAccessor::setCoppacs() +{ +#ifdef NW_RELEASE + msIsCoppa = nn::cfg::IsCoppacsSupported(); // COPPACSある地域か? +#else + msIsCoppa = true; +#endif +} + + +//********************************************************************************* +// ネットワーク +//********************************************************************************* +//========================================================================== +// セーブ準備 +//========================================================================== +void UserInfoAccessor::setNetInfo( NetInfo& net_info ) +{ + msNetInfo = net_info; + msDirty |= eNetInfo; +} + +//========================================================================== +void UserInfoAccessor::setNetWireless( int num, nn::ac::CTR::WirelessSetting& wireless ) +{ + msNetInfo.setting[num].wireless = wireless; + msDirty |= eNetInfo; +} + +//========================================================================== +void UserInfoAccessor::setNetIp( int num, nn::ac::CTR::IpSetting& ip ) +{ + msNetInfo.setting[num].ip = ip; + msDirty |= eNetInfo; +} + +//========================================================================== +void UserInfoAccessor::setNetProxy( int num, nn::ac::CTR::ProxySetting& proxy ) +{ + msNetInfo.setting[num].proxy = proxy; + msDirty |= eNetInfo; +} + +//========================================================================== +void UserInfoAccessor::setNetOther( int num, nn::ac::CTR::OtherSetting& other ) +{ + msNetInfo.setting[num].other = other; + msDirty |= eNetInfo; +} + +//========================================================================== +// 初回起動特別API、ProcessManagerから呼ばれる +void UserInfoAccessor::set_first_boot_ac_() +{ + // ネット設定初期化 + nn::ac::CTR::InitializeInternal(); + + nn::ac::CTR::RemoveNetworkSetting( 0 ); + nn::ac::CTR::RemoveNetworkSetting( 1 ); + nn::ac::CTR::RemoveNetworkSetting( 2 ); + + nn::ac::FlushNetworkSetting(); + nn::ac::CTR::FinalizeInternal(); + + // ネットワーク設定のNAND書き込み + flush_net_setting_(); +} + +//========================================================================== +// BOSS設定 +//========================================================================== +void UserInfoAccessor::setNetBg24Get( bool used ) +{ +nn::Result result; +bool optout = !used; + +// BOSS の受信 + msNetInfo.net_boss.isAllowedPushApp = used; + +// バショトリャーの受信 +// NN_LOG( "used:%d, optout:%d\n", used, optout ); + result = nn::news::CTR::boss::SaveBashotoryaTaskOptoutFlag( getHomePid(), optout ); + NN_ASSERT_RESULT( result ); + + msDirty |= eNetInfo2; +} + +void UserInfoAccessor::setNetBg24Send( bool used ) +{ +nn::Result result; +bool optout = !used; + +// 本体情報の送信 + msNetInfo.net_boss.isAllowedUploadPersonalData = used; + +// プレイ履歴のアップロードタスク + result = nn::news::CTR::boss::SavePlayLogUploadTaskOptoutFlag( getHomePid(), optout ); + NN_ASSERT_RESULT( result ); +// BOSS へ送信する情報 + saveBossSendInfoTaskOptoutFlag( optout ); + + msDirty |= eNetInfo2; +} + +void UserInfoAccessor::clrNetBg24() +{ +nn::Result result; +bit64 homePid = getHomePid(); + + msNetInfo.net_boss.isAllowedPushApp = false; + msNetInfo.net_boss.isAllowedUploadPersonalData = false; + +// バショトリャーの受信、履歴の送信 + result = nn::news::CTR::boss::SaveBashotoryaTaskOptoutFlag( homePid, true ); + result = nn::news::CTR::boss::SavePlayLogUploadTaskOptoutFlag( homePid, true ); + NN_ASSERT_RESULT( result ); + + msDirty |= eNetInfo2; +} + +nn::ProgramId UserInfoAccessor::getHomePid() +{ +nn::ProgramId pid; +bit32 uid = nn::CTR::PROGRAM_ID_UNIQUE_ID_HOMEMENU; +bit8 ver = nn::CTR::PROGRAM_ID_VERSION_HOMEMENU; + + switch( System::getRegion() ) + { + case nn::cfg::CTR::CFG_REGION_AMERICA: + uid = nn::CTR::PROGRAM_ID_UNIQUE_ID_SYSMENU_US; + ver = nn::CTR::PROGRAM_ID_VERSION_SYSMENU_US; + break; + + case nn::cfg::CTR::CFG_REGION_EUROPE: + case nn::cfg::CTR::CFG_REGION_AUSTRALIA: + uid = nn::CTR::PROGRAM_ID_UNIQUE_ID_SYSMENU_EU; + ver = nn::CTR::PROGRAM_ID_VERSION_SYSMENU_EU; + break; + + case nn::cfg::CTR::CFG_REGION_CHINA: + uid = nn::CTR::PROGRAM_ID_UNIQUE_ID_SYSMENU_CN; + ver = nn::CTR::PROGRAM_ID_VERSION_SYSMENU_CN; + break; + + case nn::cfg::CTR::CFG_REGION_KOREA: + uid = nn::CTR::PROGRAM_ID_UNIQUE_ID_SYSMENU_KR; + ver = nn::CTR::PROGRAM_ID_VERSION_SYSMENU_KR; + break; + + case nn::cfg::CTR::CFG_REGION_TAIWAN: + uid = nn::CTR::PROGRAM_ID_UNIQUE_ID_SYSMENU_TW; + ver = nn::CTR::PROGRAM_ID_VERSION_SYSMENU_TW; + break; + } + + pid = nn::CTR::MakeProgramId( nn::CTR::PROGRAM_ID_CATEGORY_APPLET, + uid, + ver ); // プログラムID + NN_LOG( "menu pid:%016llX\n", pid ); + + return pid; +} + +nn::ProgramId UserInfoAccessor::getMsetPid() +{ +nn::ProgramId pid; +bit32 uid = nn::CTR::PROGRAM_ID_UNIQUE_ID_MSET; +bit8 ver = nn::CTR::PROGRAM_ID_VERSION_MSET; + + switch( System::getRegion() ) + { + case nn::cfg::CTR::CFG_REGION_AMERICA: + uid = nn::CTR::PROGRAM_ID_UNIQUE_ID_MSET_US; + ver = nn::CTR::PROGRAM_ID_VERSION_MSET_US; + break; + + case nn::cfg::CTR::CFG_REGION_EUROPE: + case nn::cfg::CTR::CFG_REGION_AUSTRALIA: + uid = nn::CTR::PROGRAM_ID_UNIQUE_ID_MSET_EU; + ver = nn::CTR::PROGRAM_ID_VERSION_MSET_EU; + break; + + case nn::cfg::CTR::CFG_REGION_CHINA: + uid = nn::CTR::PROGRAM_ID_UNIQUE_ID_MSET_CN; + ver = nn::CTR::PROGRAM_ID_VERSION_MSET_CN; + break; + + case nn::cfg::CTR::CFG_REGION_KOREA: + uid = nn::CTR::PROGRAM_ID_UNIQUE_ID_MSET_KR; + ver = nn::CTR::PROGRAM_ID_VERSION_MSET_KR; + break; + + case nn::cfg::CTR::CFG_REGION_TAIWAN: + uid = nn::CTR::PROGRAM_ID_UNIQUE_ID_MSET_TW; + ver = nn::CTR::PROGRAM_ID_VERSION_MSET_TW; + break; + } + + pid = nn::CTR::MakeProgramId( nn::CTR::PROGRAM_ID_CATEGORY_SYSTEM_APPLICATION, + uid, + ver ); // プログラムID + NN_LOG( "mset pid:%016llX\n", pid ); + + return pid; +} + +nn::ProgramId UserInfoAccessor::getPnotePid() +{ +nn::ProgramId pid; +bit32 uid = nn::CTR::PROGRAM_ID_UNIQUE_ID_PNOTE; +bit8 ver = nn::CTR::PROGRAM_ID_VERSION_APP; + + switch( System::getRegion() ) + { + case nn::cfg::CTR::CFG_REGION_AMERICA: + uid = nn::CTR::PROGRAM_ID_UNIQUE_ID_PNOTE_US; + break; + + case nn::cfg::CTR::CFG_REGION_EUROPE: + case nn::cfg::CTR::CFG_REGION_AUSTRALIA: + uid = nn::CTR::PROGRAM_ID_UNIQUE_ID_PNOTE_EU; + break; + + case nn::cfg::CTR::CFG_REGION_CHINA: + uid = nn::CTR::PROGRAM_ID_UNIQUE_ID_PNOTE_CN; + break; + + case nn::cfg::CTR::CFG_REGION_KOREA: + uid = nn::CTR::PROGRAM_ID_UNIQUE_ID_PNOTE_KR; + break; + + case nn::cfg::CTR::CFG_REGION_TAIWAN: + uid = nn::CTR::PROGRAM_ID_UNIQUE_ID_PNOTE_TW; + break; + } + + pid = nn::CTR::MakeProgramId( nn::CTR::PROGRAM_ID_CATEGORY_SYSTEM_APPLICATION, + uid, + ver ); // プログラムID + NN_LOG( "pnote pid:%016llX\n", pid ); + + return pid; +} + +const char* UserInfoAccessor::getMsetBossCode() +{ +const char* ret = "H1qQXKK4O6t57mXV"; + + switch( System::getRegion() ) + { + case nn::cfg::CTR::CFG_REGION_AMERICA: + ret = "RuVtKeBFoN25TrSW"; + break; + + case nn::cfg::CTR::CFG_REGION_EUROPE: + case nn::cfg::CTR::CFG_REGION_AUSTRALIA: + ret = "JoCrq7bGXiCdPfPb"; + break; + + case nn::cfg::CTR::CFG_REGION_CHINA: + ret = "BjXT9luy7CYEvk6B"; + break; + + case nn::cfg::CTR::CFG_REGION_KOREA: + ret = "9VBflZvACW6nC7zZ"; + break; + + case nn::cfg::CTR::CFG_REGION_TAIWAN: + ret = "9CdgDvc3yDYx755y"; + break; + } + + return ret; +} + +//========================================================================== +void UserInfoAccessor::clrNet2() +{ + msNetInfo.net_eula.agreeVersion.version = 0; + msDirty |= eNetInfo2; + + msTwlInfo2.ds_eula.isAgreeEula = false; +// msTwlInfo2.ds_eula.agreeEulaVersion = 0; // todo: 同意EULAバージョンをクリアするならここで + msDirty |= eTwlInfo2; +} + +//========================================================================== +void UserInfoAccessor::prepareBossSendInfo() +{ + memset( &msBossSendInfo, 0, sizeof( msBossSendInfo ) ); + + // cfg の情報のセット + prepare_boss_send_cfg_info_(); + + // インターネット設定の情報のセット + prepare_boss_send_net_info_(); + + // 工場出荷時のキャリブ情報のセット + prepare_boss_send_factory_cal_info_(); +} + +void UserInfoAccessor::prepare_boss_send_cfg_info_() +{ +int size = 0; +bit32 key = 0; + + size = sizeof( msBossSendInfo.cfgInfo.touchPanel ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_HID, + nn::cfg::CTR::detail::NN_CFG_HID_CAL_TOUCHPANEL ); + nn::cfg::CTR::init::GetConfig( &msBossSendInfo.cfgInfo.touchPanel, size, key ); + + size = sizeof( msBossSendInfo.cfgInfo.analogStick ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_HID, + nn::cfg::CTR::detail::NN_CFG_HID_CAL_ANALOGSTICK ); + nn::cfg::CTR::init::GetConfig( &msBossSendInfo.cfgInfo.analogStick, size, key ); + + size = sizeof( msBossSendInfo.cfgInfo.gyro ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_HID, + nn::cfg::CTR::detail::NN_CFG_HID_CAL_GYROSCOPE ); + nn::cfg::CTR::init::GetConfig( &msBossSendInfo.cfgInfo.gyro, size, key ); + + size = sizeof( msBossSendInfo.cfgInfo.accel ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_HID, + nn::cfg::CTR::detail::NN_CFG_HID_CAL_ACCELEROMETER ); + nn::cfg::CTR::init::GetConfig( &msBossSendInfo.cfgInfo.accel, size, key ); + + size = sizeof( msBossSendInfo.cfgInfo.backLight ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_LCD, + nn::cfg::CTR::detail::NN_CFG_LCD_BACKLIGHT ); + nn::cfg::CTR::init::GetConfig( &msBossSendInfo.cfgInfo.backLight, size, key ); + + size = sizeof( msBossSendInfo.cfgInfo.camera ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_CAMERA, + nn::cfg::CTR::detail::NN_CFG_CAMERA_CAL ); + nn::cfg::CTR::init::GetConfig( &msBossSendInfo.cfgInfo.camera, size, key ); + + size = sizeof( msBossSendInfo.cfgInfo.sound ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_SOUND, + nn::cfg::CTR::detail::NN_CFG_SOUND_SETTING ); + nn::cfg::CTR::init::GetConfig( &msBossSendInfo.cfgInfo.sound, size, key ); + + size = sizeof( msBossSendInfo.cfgInfo.language ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_USER_INFO, + nn::cfg::CTR::detail::NN_CFG_USER_INFO_LANGUAGE ); + nn::cfg::CTR::init::GetConfig( &msBossSendInfo.cfgInfo.language, size, key ); + + size = sizeof( msBossSendInfo.cfgInfo.simpleAddress ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_SIMPLE_ADDRESS, + nn::cfg::CTR::detail::NN_CFG_SIMPLE_ADDRESS_ID ); + nn::cfg::CTR::init::GetConfig( &msBossSendInfo.cfgInfo.simpleAddress, size, key ); + + size = sizeof( msBossSendInfo.cfgInfo.parental ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_PARENTAL_CONTROL, + nn::cfg::CTR::detail::NN_CFG_PARENTAL_CONTROL_INFO ); + nn::cfg::CTR::init::GetConfig( &msBossSendInfo.cfgInfo.parental, size, key ); + + size = sizeof( msBossSendInfo.cfgInfo.eula ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_EULA, + nn::cfg::CTR::detail::NN_CFG_EULA_INFO ); + nn::cfg::CTR::init::GetConfig( &msBossSendInfo.cfgInfo.eula, size, key ); + + size = sizeof( msBossSendInfo.cfgInfo.boss ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_BOSS, + nn::cfg::CTR::detail::NN_CFG_BOSS_SETTING ); + nn::cfg::CTR::init::GetConfig( &msBossSendInfo.cfgInfo.boss, size, key ); + + msBossSendInfo.cfgInfo.svr2Vol = sys::Input::getSvr2Volume(); + nn::hid::CTR::GetSoundVolume( &msBossSendInfo.cfgInfo.sndVol ); + + size = sizeof( msBossSendInfo.coppacsInfo ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_PARENTAL_CONTROL, + nn::cfg::CTR::detail::NN_CFG_PARENTAL_CONTROL_COPPACS ); + nn::cfg::CTR::init::GetConfig( &msBossSendInfo.coppacsInfo, size, key ); +} + +void UserInfoAccessor::prepare_boss_send_net_info_() +{ +NetInfo netInfo; + + memset( &netInfo, 0, sizeof( netInfo ) ); + + nn::ac::InitializeInternal(); + nn::ac::LoadNetworkSetting( 0, netInfo.setting[0] ); + nn::ac::LoadNetworkSetting( 1, netInfo.setting[1] ); + nn::ac::LoadNetworkSetting( 2, netInfo.setting[2] ); + nn::ac::FinalizeInternal(); + + for( int i = 0; i < NetInfo::eInfoMax; ++i ) + { + if( netInfo.setting[i].wireless.enable ) + { + msBossSendInfo.netInfo[i].networkVersion = netInfo.setting[i].version; + msBossSendInfo.netInfo[i].wirelessEnable = netInfo.setting[i].wireless.enable; + msBossSendInfo.netInfo[i].wirelessEditableEssidSecrity = netInfo.setting[i].wireless.editableEssidSecurity; + msBossSendInfo.netInfo[i].multiSsidEnable = netInfo.setting[i].wireless.multiSsid.enable; + msBossSendInfo.netInfo[i].ipEnableDHCP = netInfo.setting[i].ip.enableDHCP; + msBossSendInfo.netInfo[i].ipAutoDNSSetting = netInfo.setting[i].ip.autoDNSSetting; + msBossSendInfo.netInfo[i].proxyEnable = netInfo.setting[i].proxy.enable; + msBossSendInfo.netInfo[i].otherEnableUPnP = netInfo.setting[i].other.enableUPnP; + msBossSendInfo.netInfo[i].essidSecurityMode = netInfo.setting[i].wireless.essidSecurity.securityMode; + msBossSendInfo.netInfo[i].multiSsidType = netInfo.setting[i].wireless.multiSsid.multiSsidType; + msBossSendInfo.netInfo[i].proxyAuthType = netInfo.setting[i].proxy.authType; + msBossSendInfo.netInfo[i].padding = 0; + } + } +} + +void UserInfoAccessor::prepare_boss_send_factory_cal_info_() +{ +nn::Result result; + + result = nn::cfg::CTR::init::GetCameraFactoryCal( &msBossSendInfo.factoryCalInfo.camera ); + if( result.IsFailure() ) + { + // 異常状態なのでバッファをクリアしておく + NN_LOG("get camera factory cal error!\n"); + memset( &msBossSendInfo.factoryCalInfo.camera, 0, sizeof( msBossSendInfo.factoryCalInfo.camera ) ); + } + result = nn::cfg::CTR::init::GetAnalogStickFactoryCal( &msBossSendInfo.factoryCalInfo.analogStick ); + if( result.IsFailure() ) + { + // 異常状態なのでバッファをクリアしておく + NN_LOG("get analog stick factory cal error!\n"); + memset( &msBossSendInfo.factoryCalInfo.analogStick, 0, sizeof( msBossSendInfo.factoryCalInfo.analogStick ) ); + } +} + +//========================================================================== +// NET設定の「新規設定」を選択したときに作られるパラメータ +//========================================================================== +void UserInfoAccessor::setNetNewParam( int num ) +{ + memset( &msNetInfo.setting[num], 0, sizeof( nn::ac::CTR::NetworkSetting ) ); + + msNetInfo.setting[num].wireless.editableEssidSecurity = true; // SSIDエディット可能 + msNetInfo.setting[num].ip.enableDHCP = true; // IP自動取得 + msNetInfo.setting[num].ip.autoDNSSetting = true; // DNS自動取得 + msNetInfo.setting[num].proxy.enable = false; // Proxy使用しない + msNetInfo.setting[num].proxy.authType = nn::ac::CTR::PROXY_AUTH_TYPE_NONE; // Basic認証なし + msNetInfo.setting[num].other.enableUPnP = false; // UPnP無効 + + msNetInfo.setting[num].proxy.port = 1; // port = 1 + msNetInfo.setting[num].other.mtu = 1400; // MTU = 1400 + +// バックアップにも書き込む + msBackupNetInfo.setting[num] = msNetInfo.setting[num]; + + msDirty |= eNetInfo; +} + + +//========================================================================== +// 接続設定の消去 +//========================================================================== +void UserInfoAccessor::delNetSetInfo( int num ) +{ +nn::Result result; + + nn::ac::InitializeInternal(); + + result = nn::ac::RemoveNetworkSetting( num ); + +#ifndef NW_RELEASE + NN_DBG_PRINT_RESULT( result ); +#endif + + nn::ac::FlushNetworkSetting(); + nn::ac::FinalizeInternal(); + + memset( &msNetInfo.setting[num], 0, sizeof( nn::ac::CTR::NetworkSetting ) ); + msBackupNetInfo = msNetInfo; +} + + +//========================================================================== +// ネット設定が更新されたかチェック +//========================================================================== +bool UserInfoAccessor::isCheckNetworkInfo() +{ +s8* org = (s8*)( &msNetInfo.setting[msAccNum] ); +s8* back = (s8*)( &msBackupNetInfo.setting[msAccNum] ); +int size = sizeof( nn::ac::CTR::NetworkSetting )/*-sizeof( msNetInfo.setting[msAccNum].reserve )*/; // reserve分引く + + for( int i = 0; i < size; i++ ) + { + if( *org++ != *back++ ) + { + return false; + } + } + return true; +} + + +//========================================================================== +// ネットワーク設定のNAND書き込み +//========================================================================== +void UserInfoAccessor::flush_net_setting_() +{ + NN_LOG("flush_net_setting_\n"); + + if( ( msAccNum >= 0 ) && ( msAccNum <= 2 ) ) + { + memset( &msNetInfo.setting[msAccNum].scanlessConnect, 0, sizeof( nn::ac::ScanlessConnectSetting ) ); + } + + nn::ac::InitializeInternal(); + + for( int i = 0; i < 3; i++ ) + { + if( msNetInfo.setting[i].wireless.enable ) + { + nn::ac::UpdateNetworkSetting( i, msNetInfo.setting[i] ); + + NN_LOG( "net set save = %d\n", i ); + } + } + + nn::ac::FlushNetworkSetting(); + nn::ac::FinalizeInternal(); + + NN_LOG( "Save NetInfo\n" ); +} + + +//********************************************************************************* +// CFG +//********************************************************************************* +//========================================================================== +// CFGデータ(ユーザー設定)の Load / Save +// type 0: Load / 1: save / 2: 強制save +//========================================================================== +bool UserInfoAccessor::data_user_info_( int kind, int type ) +{ +bool ret = ( type == 2 ); +u8* org = NULL; +u8* back = NULL; +int size; +bit32 key; + + switch( kind ) + { + case eKindUserName: + org = (u8*)( &msUserInfo.usr_name ); + back = (u8*)( &msBackupUserInfo.usr_name ); + size = sizeof( nn::cfg::CTR::detail::UserNameCfgData ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_USER_INFO, + nn::cfg::CTR::detail::NN_CFG_USER_INFO_USER_NAME ); + break; + + case eKindAddressId: + org = (u8*)( &msUserInfo.usr_address.id ); + back = (u8*)( &msBackupUserInfo.usr_address.id ); + size = sizeof( nn::cfg::CTR::detail::SimpleAddressIdCfgData ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_SIMPLE_ADDRESS, + nn::cfg::CTR::detail::NN_CFG_SIMPLE_ADDRESS_ID ); + break; + + case eKindAddressCountry: + org = (u8*)( &msUserInfo.usr_address.countryName[0][0] ); + back = (u8*)( &msBackupUserInfo.usr_address.countryName[0][0] ); + size = sizeof( nn::cfg::CTR::detail::SimpleAddressCountryNameCfgData ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_SIMPLE_ADDRESS, + nn::cfg::CTR::detail::NN_CFG_SIMPLE_ADDRESS_COUNTRY_NAME ); + break; + + case eKindAddressRegion: + org = (u8*)( &msUserInfo.usr_address.regionName[0][0] ); + back = (u8*)( &msBackupUserInfo.usr_address.regionName[0][0] ); + size = sizeof( nn::cfg::CTR::detail::SimpleAddressRegionNameCfgData ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_SIMPLE_ADDRESS, + nn::cfg::CTR::detail::NN_CFG_SIMPLE_ADDRESS_REGION_NAME ); + break; + + case eKindAddressPosition: + org = (u8*)( &msUserInfo.usr_address.latitude ); + back = (u8*)( &msBackupUserInfo.usr_address.latitude ); + size = sizeof( nn::cfg::CTR::detail::SimpleAddressPositionCfgData ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_SIMPLE_ADDRESS, + nn::cfg::CTR::detail::NN_CFG_SIMPLE_ADDRESS_POSITION ); + break; + + case eKindBirthday: + org = (u8*)( &msUserInfo.usr_birthday ); + back = (u8*)( &msBackupUserInfo.usr_birthday ); + size = sizeof( nn::cfg::CTR::detail::BirthdayCfgData ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_USER_INFO, + nn::cfg::CTR::detail::NN_CFG_USER_INFO_BIRTHDAY ); + break; + + case eKindLanguage: + org = (u8*)( &msUserInfo.usr_language ); + back = (u8*)( &msBackupUserInfo.usr_language ); + size = sizeof( nn::cfg::CTR::detail::LanguageCfgData ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_USER_INFO, + nn::cfg::CTR::detail::NN_CFG_USER_INFO_LANGUAGE ); + break; + + case eKindSound: + org = (u8*)( &msUserInfo.usr_sound ); + back = (u8*)( &msBackupUserInfo.usr_sound ); + size = sizeof( nn::cfg::CTR::detail::SoundSettingCfgData ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_SOUND, + nn::cfg::CTR::detail::NN_CFG_SOUND_SETTING ); + break; + + case eKindEula: + org = (u8*)( &msNetInfo.net_eula ); + back = (u8*)( &msBackupNetInfo.net_eula ); + size = sizeof( nn::cfg::CTR::detail::EulaInfoCfgData ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_EULA, + nn::cfg::CTR::detail::NN_CFG_EULA_INFO ); + break; + + case eKindBoss: + org = (u8*)( &msNetInfo.net_boss ); + back = (u8*)( &msBackupNetInfo.net_boss ); + size = sizeof( nn::cfg::CTR::detail::BossSettingCfgData ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_BOSS, + nn::cfg::CTR::detail::NN_CFG_BOSS_SETTING ); + break; + + case eKindParental: + org = (u8*)( &msParentInfo ); + back = (u8*)( &msBackupParentInfo ); + size = sizeof( nn::cfg::CTR::ParentalControlInfo ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_PARENTAL_CONTROL, + nn::cfg::CTR::detail::NN_CFG_PARENTAL_CONTROL_INFO ); + break; + + case eKindCoppa: + org = (u8*)( &msCoppaInfo ); + back = (u8*)( &msBackupCoppaInfo ); + size = sizeof( nn::cfg::CTR::detail::CoppacsCfgData ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_PARENTAL_CONTROL, + nn::cfg::CTR::detail::NN_CFG_PARENTAL_CONTROL_COPPACS ); + break; + + case eKindDsData: + org = (u8*)( &msTwlInfo ); + back = (u8*)( &msBackupTwlInfo ); + size = sizeof( TwlInfo ); + break; + + case eKindDsCountry: + org = (u8*)( &msTwlInfo2.ds_country ); + back = (u8*)( &msBackupTwlInfo2.ds_country ); + size = sizeof( nn::cfg::CTR::detail::TwlCountryCodeCfgData ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_TWL, + nn::cfg::CTR::detail::NN_CFG_TWL_COUNTRY_CODE ); + break; + + case eKindDsParental: + org = (u8*)( &msTwlInfo2.ds_pare ); + back = (u8*)( &msBackupTwlInfo2.ds_pare ); + size = sizeof( nn::cfg::CTR::detail::TwlParentalControlInfoCfgData ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_TWL, + nn::cfg::CTR::detail::NN_CFG_TWL_PARENTAL_CONTROL_INFO ); + break; + + case eKindDsEula: + org = (u8*)( &msTwlInfo2.ds_eula ); + back = (u8*)( &msBackupTwlInfo2.ds_eula ); + size = sizeof( nn::cfg::CTR::detail::TwlEulaInfoCfgData ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_TWL, + nn::cfg::CTR::detail::NN_CFG_TWL_EULA_INFO ); + break; + + case eKindFirst: + org = (u8*)( &msFirstInfo.mmen ); + size = sizeof( nn::cfg::CTR::detail::FirstLaunchInfoCfgData ); + key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_MENU, + nn::cfg::CTR::detail::NN_CFG_MENU_FIRST_LAUNCH ); + ret = true; + break; + + default: + return ret; + } + + if( type >= 1 ) // save + { + if( !ret && ( back != NULL ) ) + { + for( int i = 0; i < size; i++ ) + { + if( org[i] != back[i] ) + { + ret = true; + break; + } + } + } + + if( ret ) + { + nn::Result result; + + if( kind == eKindDsData ) + { + result = nn::cfg::nor::CTR::SetNtrSetting( &msTwlInfo.ds_data, &msTwlInfo.ds_data_ex ); + } + else + { + result = nn::cfg::CTR::init::SetConfig( key, org, size ); + } + + ret = result.IsSuccess(); + +#ifndef NW_RELEASE + scene::DebugLayout::setSaveScc( ret, kind ); +#endif + NN_LOG( "save %d ( %d )\n", kind, result.IsSuccess() ); + } + } + else // load + { + nn::Result result; + + if( kind == eKindDsData ) + { + result = nn::cfg::nor::CTR::GetNtrSetting( &msTwlInfo.ds_data, &msTwlInfo.ds_data_ex ); + } + else + { + result = nn::cfg::CTR::init::GetConfig( org, size, key ); + } + + NN_LOG( "load %d ( %d )\n", kind, result.IsSuccess() ); + } + + return ret; +} + + +#ifndef NW_RELEASE +//========================================================================== +// 初回起動の最後にもう一度Ds設定をNANDから読み込む +//========================================================================== +void UserInfoAccessor::getLastDsData() +{ +nn::Result result = nn::cfg::nor::CTR::GetNtrSetting( &msTwlInfo.ds_data, &msTwlInfo.ds_data_ex ); + + NN_LOG( "ds_name = %ls ( %d ) (%d)\n", msTwlInfo.ds_data.owner.nickname.buffer, + msTwlInfo.ds_data.owner.nickname.length , result.IsSuccess() ); +} +#endif + + +//========================================================================== +// スライドパッドのデータ取得 +//========================================================================== +void UserInfoAccessor::getAnalogData( nn::cfg::CTR::detail::AnalogStickCfgData* para, int flg ) +{ +int size = sizeof( nn::cfg::CTR::detail::AnalogStickCfgData ); +bit32 key = get_cfg_key_( nn::cfg::CTR::detail::NN_CFG_HID, + nn::cfg::CTR::detail::NN_CFG_HID_CAL_ANALOGSTICK ); + + if( flg == 0 ) + { + nn::cfg::CTR::init::GetConfig( para, size, key ); + } + else + { + nn::cfg::CTR::init::SetConfig( key, para, size ); + nn::cfg::CTR::init::FlushConfig(); + } +} + + +//========================================================================== +// CTR->TWLに文字列の変換 +//========================================================================== +void UserInfoAccessor::replaceUnusableString( wchar_t* buffer, int len ) +{ + replaceUnusableStringWithTwlUserInfoFontTable(buffer,len); +} + +void UserInfoAccessor::replaceUnusableStringWithTwlUserInfoFontTable(wchar_t* buffer, int len) +{ +#ifndef NW_RELEASE +// NN_LOG( "twl user info font table size = %d\n", sizeof( cTwlUserInfoFontCodeTable )/sizeof( u16 ) ); +#endif + for( int i = 0; i < len; i++ ) + { + if( buffer[i] == L'\0' ) + { + break; + } + else + { + if(binarySearchFromTwlUserInfoFontTable(buffer[i])) + { + //表示可能文字なので何もしない + } + else + { + //表示不可能文字なので置換する + buffer[i] = L'?'; + } + } + } +} + +bool UserInfoAccessor::binarySearchFromTwlUserInfoFontTable(u16 wc) +{ + //二分探索 + int begin = 0; + int end = sizeof( cTwlUserInfoFontCodeTable )/sizeof( u16 ) - 1; + + while(begin <= end) + { + int idx = (begin+end)/2; + + if(cTwlUserInfoFontCodeTable[idx] == wc) + { + //見つかった + return true; + } + else if(cTwlUserInfoFontCodeTable[idx] < wc) + { + //wcがあるとしたらidxより後ろ + begin = idx+1; + } + else + { + //wcがあるとしたらidxより前 + end = idx-1; + } + } + + return false; +} + + +//========================================================================== +// 初回起動フラグのセーブ +//========================================================================== +void UserInfoAccessor::saveFirstInfo( int mmen, u8 net ) +{ + if( mmen >= 0 ) + { + msFirstInfo.mmen = (u16)mmen; + } + + msFirstInfo.internet = net; + + if( msIsNetSave ) + { + if( data_user_info_( eKindFirst, 1 ) ) + { + nn::cfg::CTR::init::FlushConfig(); + + NN_LOG( "Save FirstInfo\n" ); + } + } +} + + +//========================================================================== +// EULAのチェック +//========================================================================== +int UserInfoAccessor::checkEula() +{ +EulaDef eula_data; +u8* mount_buf = NULL; +int region = System::getRegion(); + +#ifdef MOUNT_SHARED_EULA +// Eula情報のマウント + { + mount_buf = sys::File::mountShare( "eula:", cSharedEulaId[region], 0, 40, 2 ); + if( mount_buf != NULL ) + { + NN_LOG( "Eula data mount\n" ); + } + } +#endif + +// EULAデータの読み込み + { + u32 size; +#ifdef MOUNT_SHARED_EULA + u8* p_file = sys::File::read( "eula:/country.bin", &size, false, false ); +#else + u8* p_file = sys::File::read( cEulaCountry[region], &size, false, false ); +#endif + int country_num = p_file[0]; + int country_id = (msUserInfo.usr_address.id>>24); + + memset( &eula_data, 0, sizeof( EulaDef ) ); + + NN_LOG( "country_id = %d ( %d )\n", country_id, country_num ); + + { + EulaDef* p_eula = (EulaDef*)&p_file[16]; + + for( int i = 0; i < country_num; i++ ) + { + if( country_id == p_eula[i].id ) + { + eula_data = p_eula[i]; + break; + } + } + } + + delete []p_file; + } + +#ifdef MOUNT_SHARED_EULA + nn::fs::Unmount( "eula:" ); + delete []mount_buf; +#endif + + msWorkInfo.eula_minor = eula_data.minorVersion; + msWorkInfo.eula_major = eula_data.majorVersion; + msBackupWorkInfo = msWorkInfo; + +// その国にEULAがあるか? + if( ( eula_data.majorVersion == 0 ) && ( eula_data.minorVersion == 0 ) ) + { + NN_LOG( "No EULA\n" ); + return -1; // EULAがない + } + +// EULAに同意しているか? + else if( msNetInfo.net_eula.agreeVersion.version == 0 ) + { + NN_LOG( "Not agree\n" ); + return 0; // 同意していない + } + +// 同意バージョンより新しいEULAがあるか? + else if( ( msNetInfo.net_eula.agreeVersion.version == ((eula_data.majorVersion<<8) | eula_data.minorVersion)) ) + { + NN_LOG( "old agree\n" ); + return 1; // 新しいEULAがなかった + } + + NN_LOG( "new agree\n" ); + return 2; // 新しいEULAがある +} + + +//========================================================================== +// EULAデータ読み直し +//========================================================================== +void UserInfoAccessor::loadEula() +{ + data_user_info_( eKindEula, 0 ); + data_user_info_( eKindBoss, 0 ); + data_user_info_( eKindDsEula, 0 ); + + msBackupNetInfo.net_eula = msNetInfo.net_eula; + msBackupNetInfo.net_boss = msNetInfo.net_boss; + msBackupTwlInfo2.ds_eula = msTwlInfo2.ds_eula; +} + + +//========================================================================== +// bossタスクセット +//========================================================================== +void UserInfoAccessor::setBossTask() +{ + if( msFirstInfo.mmen != 0 ) // 初回起動のときセットしない + { + const char* lang = nn::cfg::CTR::GetLanguageCodeA2( (nn::cfg::CTR::CfgLanguageCode)System::getCfgLanguage() ); + const char* country = nn::cfg::CTR::GetCountryCodeA2( (nn::cfg::CTR::CfgCountryCode)( msUserInfo.usr_address.id>>24 ) ); + const char* boss_code = nn::news::CTR::boss::GetBossCodeA3( (nn::cfg::CTR::CfgRegionCode)System::getRegion() ); + + nn::news::CTR::boss::RegisterSystemTask( boss_code, country, lang ); + + NN_LOG( "Boss Task Set\n" ); + } +} + + +void UserInfoAccessor::setBossSendInfoTask() +{ + // 初回起動シーケンスを通っていなかったら何もしない + if( isFirst() ) + { + NN_LOG("not initialize mset\n"); + return; + } + + // BOSS への送信がオプトアウトされてたら何もしない + data_user_info_( eKindBoss, 0 ); + if( !msNetInfo.net_boss.isAllowedUploadPersonalData ) + { + NN_LOG("not allow upload\n"); + return; + } + + if( !save_boss_send_info_() ) + { + // 更新がなかったので情報は送信しない + NN_LOG("no change send boss info\n"); + return; + } + + // タスクの登録 + set_boss_send_info_task_(); +} + +void UserInfoAccessor::setBossSendInfoTaskFirst() +{ + // 初回起動シーケンスのときは EULA に同意していたらセットする + if( !isEula() ) + { + return; + } + + if( !save_boss_send_info_() ) + { + // 更新がなかったので情報は送信しない + NN_LOG("no change send boss info\n"); + return; + } + + // タスクの登録 + set_boss_send_info_task_(); +} + +void UserInfoAccessor::set_boss_send_info_task_() +{ +const u16 cTaskExecuteTime = 1; +const u16 cTaskExecuteCount = 1; +const char* cTaskUrl = "https://npul.c.app.nintendowifi.net/p01/recv/%s/%s"; +const nn::boss::TaskPermission permission = nn::boss::TASK_PERMISSION_IN_PARENTAL_CONTROL; +const wchar_t* filePath = sys::File::getMsetSysSaveDataPath( sys::File::eSysSaveDataTypeBoss ); +const int setSha1HashLen = 41; + +nn::Result result; +nn::fs::FileReader file; +nn::boss::Task task; +nn::boss::TaskPolicy policy; +nn::boss::UploadAction action; +u8* readData = NULL; +u8* readDataSha1 = NULL; +char setSha1Hash[ setSha1HashLen ]; +size_t readDataSize = 0; + + // システムセーブデータのマウント + sys::File::initializeMsetSys(); + + result = task.Initialize( cSendBossInfoTaskId ); + NN_RESULT_ASSERT( result ); + + result = policy.Initialize( cTaskExecuteTime, cTaskExecuteCount ); + NN_RESULT_ASSERT( result ); + result = policy.SetProperty( nn::boss::TASK_PERMISSION, &permission, sizeof( permission ) ); + NN_RESULT_ASSERT( result ); + + // すでに登録されていた場合を考慮してタスクを削除します。 + // デーモンをとめていないと失敗する可能性がありますが、 + // MSET では起動時にデーモンを止めているため、 + // ここでデーモンを止める処理は呼びません。 + // また、失敗しても作業を続けるため、戻り値のチェックはしません。 + // ファイルがクローズされないようにファイルオープンよりも先に + // タスクは削除します。 + nn::boss::UnregisterTask( &task ); + + // ファイルの読み込み + result = file.TryInitialize( filePath ); + if( result.IsFailure() ) + { + // ここにきた際にファイルが読み込めないことはないはず + // 読み込めなかったらこの先の処理も意味がなくなるのでリターンしてしまう + file.Finalize(); + NN_LOG("can't initialize sendBossInfo file\n"); + sys::File::finalizeMsetSys(); + return; + } + + { + const int len = 100; + char url[ len ]; + snprintf( url, len, cTaskUrl, getMsetBossCode(), cSendBossInfoTaskId ); + NN_LOG("url:%s\n", url); + result = action.InitializeForBossDb( url, file.GetHandle() ); + } + NN_RESULT_ASSERT( result ); + + // クライアント証明書の設定 + result = action.SetClientCert( NNSSL_CLIENTCERT_DEFAULT ); + NN_RESULT_ASSERT( result ); + + // SSL証明書を設定します. + result = action.SetRootCa( nn::ssl::CACERT_PUBLIC_CA_1 ); + NN_RESULT_ASSERT( result ); + result = action.SetRootCa( nn::ssl::CACERT_NINTENDO_CA_G3 ); + NN_RESULT_ASSERT( result ); + + // 読み込んだファイルの中身をsha-1でハッシュ値計算 + { + // ファイル読み込み + // 中で fileReader のinitialize が再び行われるのが少し冗長だが安全に読み込むため + readData = sys::File::read( filePath, &readDataSize, false, false ); + if( readData == NULL ) + { + // 読み込み失敗 + file.Finalize(); + NN_LOG("can't read sendBossInfo file\n"); + sys::File::finalizeMsetSys(); + return; + } + readDataSha1 = new( sys::Mem::getMainHeap(), 4 ) u8[ nn::crypto::Sha1Context::HASH_SIZE ]; + nn::crypto::CalculateSha1( readDataSha1, readData, readDataSize ); + snprintf( setSha1Hash, setSha1HashLen, + "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + readDataSha1[ 0 ], readDataSha1[ 1 ], readDataSha1[ 2 ], + readDataSha1[ 3 ], readDataSha1[ 4 ], readDataSha1[ 5 ], + readDataSha1[ 6 ], readDataSha1[ 7 ], readDataSha1[ 8 ], + readDataSha1[ 9 ], readDataSha1[ 10 ], readDataSha1[ 11 ], + readDataSha1[ 12 ], readDataSha1[ 13 ], readDataSha1[ 14 ], + readDataSha1[ 15 ], readDataSha1[ 16 ], readDataSha1[ 17 ], + readDataSha1[ 18 ], readDataSha1[ 19 ] ); + NN_LOG("setSha1Hash:%s\n", setSha1Hash); + + result = action.AddHeaderField( "X-Boss-Digest", setSha1Hash ); + delete[] readDataSha1; + delete[] readData; + NN_RESULT_ASSERT( result ); + } + + result = nn::boss::RegisterTask( &task, &policy, &action ); + NN_RESULT_ASSERT( result ); + + result = task.Start(); + NN_RESULT_ASSERT( result ); + + file.Finalize(); + sys::File::finalizeMsetSys(); + + NN_LOG("task set send boss info\n"); +} + + +void UserInfoAccessor::saveBossSendInfoTaskOptoutFlag( bool optoutFlag ) +{ +nn::Result result; + + if( optoutFlag ) + { + NN_LOG("send boss info task cancel\n"); + result = nn::boss::CancelTask( getMsetPid(), cSendBossInfoTaskId ); + NN_LOG("mset cancel task\n"); + NN_DBG_PRINT_RESULT( result ); + result = nn::boss::CancelTask( getHomePid(), cSendBossMmenTaskId ); + NN_LOG("mmen cancel task\n"); + NN_DBG_PRINT_RESULT( result ); + result = nn::boss::CancelTask( getHomePid(), cSendPhuTaskId ); + NN_LOG("pedometer cancel task\n"); + NN_DBG_PRINT_RESULT( result ); + result = nn::boss::CancelTask( getHomePid(), cSendTiuTaskId ); + NN_LOG("task info cancel task\n"); + NN_DBG_PRINT_RESULT( result ); + result = nn::boss::CancelTask( getHomePid(), cSendSpluTaskId ); + NN_LOG("street pass cancel task\n"); + NN_DBG_PRINT_RESULT( result ); + result = nn::boss::CancelTask( getPnotePid(), cSendBossPnoteTaskId ); + NN_LOG("pnote cancel task\n"); + NN_DBG_PRINT_RESULT( result ); + } + else + { + NN_LOG("send boss info task start\n"); + result = nn::boss::StartTask( getMsetPid(), cSendBossInfoTaskId ); + NN_LOG("mset start task\n"); + NN_DBG_PRINT_RESULT( result ); + result = nn::boss::StartTask( getHomePid(), cSendBossMmenTaskId ); + NN_LOG("mmen start task\n"); + NN_DBG_PRINT_RESULT( result ); + result = nn::boss::StartTask( getHomePid(), cSendPhuTaskId ); + NN_LOG("pedometer start task\n"); + NN_DBG_PRINT_RESULT( result ); + result = nn::boss::StartTask( getHomePid(), cSendTiuTaskId ); + NN_LOG("task info start task\n"); + NN_DBG_PRINT_RESULT( result ); + result = nn::boss::StartTask( getHomePid(), cSendSpluTaskId ); + NN_LOG("street pass start task\n"); + NN_DBG_PRINT_RESULT( result ); + result = nn::boss::StartTask( getPnotePid(), cSendBossPnoteTaskId ); + NN_LOG("pnote start task\n"); + NN_DBG_PRINT_RESULT( result ); + } + // 消尽回数1回のタスクがあるので、すでにタスクがなかったときのためにアサートしない + //NN_RESULT_ASSERT( result ); +} + + +bool UserInfoAccessor::save_boss_send_info_() +{ +size_t size = sizeof( BossSendInfo ); +BossSendInfo* pSaveData = new( sys::Mem::getMainHeap() ) BossSendInfo; +bool ret = false; + + sys::File::initializeMsetSys(); + sys::File::readMsetFile( (u8*)pSaveData, size, sys::File::eSysSaveDataTypeBoss ); + + // 送信情報の取得 + prepareBossSendInfo(); + if( checkUpdateBossSendInfo( pSaveData ) ) + { + // 更新があったときのみセーブする + NN_LOG("save send boss info\n"); + memcpy( pSaveData, &msBossSendInfo, size ); + sys::File::saveMsetSys( (u8*)pSaveData, size, sys::File::eSysSaveDataTypeBoss ); + ret = true; + } + sys::File::finalizeMsetSys(); + + if( pSaveData != NULL ) { delete pSaveData; } + + return ret; +} + + +bool UserInfoAccessor::checkUpdateBossSendInfo( BossSendInfo* pSaveData ) +{ +bool ret = false; + + // BossSendInfo のサイズが4で割り切れることを利用して実装しているため + // 4で割り切れなかったときは警告 + NN_LOG("sizeof( BossSendInfo ):%d\n", sizeof( BossSendInfo )); + NN_ASSERT( sizeof( BossSendInfo ) % sizeof( u32 ) == 0 ); + +#if 0 + for( int i = 0; i < NetInfo::eInfoMax; ++i ) + { + NN_LOG("[%d]networkVersion:%d %d\n", i, + pSaveData->netInfo[i].networkVersion, msBossSendInfo.netInfo[i].networkVersion); + NN_LOG("[%d]wirelessEnable:%d %d\n", i, + pSaveData->netInfo[i].wirelessEnable, msBossSendInfo.netInfo[i].wirelessEnable); + NN_LOG("[%d]wirelessEditableEssidSecrity:%d %d\n", i, + pSaveData->netInfo[i].wirelessEditableEssidSecrity, msBossSendInfo.netInfo[i].wirelessEditableEssidSecrity); + NN_LOG("[%d]multiSsidEnable:%d %d\n", i, + pSaveData->netInfo[i].multiSsidEnable, msBossSendInfo.netInfo[i].multiSsidEnable); + NN_LOG("[%d]ipEnableDHCP:%d %d\n", i, + pSaveData->netInfo[i].ipEnableDHCP, msBossSendInfo.netInfo[i].ipEnableDHCP); + NN_LOG("[%d]ipAutoDNSSetting:%d %d\n", i, + pSaveData->netInfo[i].ipAutoDNSSetting, msBossSendInfo.netInfo[i].ipAutoDNSSetting); + NN_LOG("[%d]proxyEnable:%d %d\n", i, + pSaveData->netInfo[i].proxyEnable, msBossSendInfo.netInfo[i].proxyEnable); + NN_LOG("[%d]otherEnableUPnP:%d %d\n", i, + pSaveData->netInfo[i].otherEnableUPnP, msBossSendInfo.netInfo[i].otherEnableUPnP); + NN_LOG("[%d]essidSecurityMode:%d %d\n", i, + pSaveData->netInfo[i].essidSecurityMode, msBossSendInfo.netInfo[i].essidSecurityMode); + NN_LOG("[%d]multiSsidType:%d %d\n", i, + pSaveData->netInfo[i].multiSsidType, msBossSendInfo.netInfo[i].multiSsidType); + NN_LOG("[%d]proxyAuthType:%d %d\n", i, + pSaveData->netInfo[i].proxyAuthType, msBossSendInfo.netInfo[i].proxyAuthType); + NN_LOG("[%d]padding:%d %d\n", i, + pSaveData->netInfo[i].padding, msBossSendInfo.netInfo[i].padding); + } +#endif + + u32* pSave = (u32*)pSaveData; + u32* pCfg = (u32*)(&msBossSendInfo); + + for( int i = 0; i < ( sizeof( BossSendInfo ) / sizeof( u32 ) ); ++i ) + { + if( pSave[ i ] != pCfg[ i ] ) + { + NN_LOG("i:%d change %08x != %08x\n", i, pSave[ i ], pCfg[ i ]); + ret = true; + break; + } + } + + return ret; +} + + +#ifdef MAKE_ACCTEST +#ifndef NW_RELEASE +//========================================================================== +// CFGデータ(ネット設定)のモニタ +//========================================================================== +void UserInfoAccessor::print_net_save_() +{ + NN_LOG( "****** Net wireless SAVE DATA ******\n" ); + + for( int i = 0; i < 3; i++ ) + { + NN_LOG( "--- Setting %d ---\n", i+1 ); + if( !msNetInfo.setting[i].wireless.enable ) + { + NN_LOG( " no set\n\n" ); + continue; + } + + NN_LOG( "version : %d\n", msNetInfo.setting[i].version ); + NN_LOG( "wireless\n" ); + NN_LOG( " editable : %d\n\n", msNetInfo.setting[i].wireless.editableEssidSecurity ); + NN_LOG( "essidSecurity\n" ); + + { + char ssid[40] = ""; + + for( int j = 0; j < 32; j++ ) + { + ssid[j] = msNetInfo.setting[i].wireless.essidSecurity.ssid[j]; + } + NN_LOG( " ssid : %s\n", ssid ); + } + + NN_LOG( " ssidLength : %d\n", msNetInfo.setting[i].wireless.essidSecurity.ssidLength ); + NN_LOG( " securityMode = %d\n", msNetInfo.setting[i].wireless.essidSecurity.securityMode ); + + { + char pass[70] = ""; + + for( int j = 0; j < 64; j++ ) + { + pass[j] = msNetInfo.setting[i].wireless.essidSecurity.passphrase[j]; + } + NN_LOG( " passphrase : %s\n", pass ); + } + + NN_LOG( " key :\n" ); + for( int j = 0; j < 64; j++ ) + { + NN_LOG( "%02x ", msNetInfo.setting[i].wireless.essidSecurity.key[j] ); + if( (j%16) == 15 ) + { + NN_LOG( "\n" ); + } + } + + if( !msNetInfo.setting[i].wireless.multiSsid.enable ) + { + NN_LOG( " Multi no set\n\n" ); + continue; + } + + NN_LOG( " Multi Setting type : %d\n", msNetInfo.setting[i].wireless.multiSsid.multiSsidType ); + NN_LOG( " Setting num = %d\n", msNetInfo.setting[i].wireless.multiSsid.settingNum ); + + for( int n = 0; n < 4; n++ ) + { + { + char ssid[40] = ""; + + for( int j = 0; j < 32; j++ ) + { + ssid[j] = msNetInfo.setting[i].wireless.multiSsid.setting[n].ssid[j]; + } + NN_LOG( " ssid : %s\n", ssid ); + } + + NN_LOG( " ssidLength : %d\n", msNetInfo.setting[i].wireless.multiSsid.setting[n].ssidLength ); + NN_LOG( " securityMode = %d\n", msNetInfo.setting[i].wireless.multiSsid.setting[n].securityMode ); + + { + char pass[70] = ""; + + for( int j = 0; j < 64; j++ ) + { + pass[j] = msNetInfo.setting[i].wireless.multiSsid.setting[n].passphrase[j]; + } + NN_LOG( " passphrase : %s\n", pass ); + } + + NN_LOG( " key :\n" ); + for( int j = 0; j < 64; j++ ) + { + NN_LOG( "%02x ", msNetInfo.setting[i].wireless.multiSsid.setting[n].key[j] ); + if( (j%16) == 15 ) + { + NN_LOG( "\n" ); + } + } + + NN_LOG( "\n" ); + } + + NN_LOG( "\n" ); + } + + NN_LOG( "****** Net wireless SAVE DATA END ******\n" ); +} +#endif +#endif + +#ifndef NW_RELEASE + bool UserInfoAccessor::check_order_twl_user_info_font_table_() + { + int size = sizeof( cTwlUserInfoFontCodeTable )/sizeof( u16 ); + //データが昇順であることを確認する + for(s32 i=1;i +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "sysProcessManager.h" + +namespace sys +{ + +//========================================================================== +// 初回起動、どこまで終わったかをチェックする +// 全て終わるとendをセット +//========================================================================== +struct FirstInfo +{ + u32 end : 1; + u32 langage : 1; + u32 date : 1; + u32 time : 1; + + u32 name : 1; + u32 birthday : 1; + u32 country : 1; + u32 area : 1; + + u32 view : 1; // 3D確認 + u32 eula : 1; // EULA確認 + + u32 rsv : 22; +}; + +struct EulaDef +{ + u8 id; // 国ID + u8 numLanguage; // 言語数 + u8 minorVersion; // EULAマイナーバージョン + u8 majorVersion; // EULAメジャーバージョン + u8 language[4]; // EULA用の言語定数(本体設定より多い)。言語名表示のため + u8 fileNo[4]; // EULAファイル番号(EULAファイル名を .bin にしておく) +}; + + +//========================================================================== +// 一般設定でセーブされる情報 +//========================================================================== +struct UserInfo +{ + nn::cfg::CTR::detail::UserNameCfgData usr_name; // ユーザーネーム + nn::cfg::CTR::SimpleAddress usr_address; // アドレス + + nn::cfg::CTR::detail::BirthdayCfgData usr_birthday; // 誕生日 + nn::cfg::CTR::detail::LanguageCfgData usr_language; // 言語 + + nn::cfg::CTR::detail::SoundSettingCfgData usr_sound; // サウンド +}; + + +//========================================================================== +// TWL用にセーブされる情報 +//========================================================================== +struct TwlInfo +{ + nn::cfg::CTR::NtrSettingData ds_data; + nn::cfg::CTR::NtrSettingDataEx ds_data_ex; +}; + +struct TwlInfo2 +{ + nn::cfg::CTR::detail::TwlCountryCodeCfgData ds_country; + + nn::cfg::CTR::detail::TwlParentalControlInfoCfgData ds_pare; + + nn::cfg::CTR::detail::TwlEulaInfoCfgData ds_eula; +}; + + +//========================================================================== +// インターネット設定でセーブされる情報 +//========================================================================== +struct NetInfo +{ + enum + { + eInfoMax = 3 + }; + + nn::ac::CTR::NetworkSetting setting[eInfoMax]; // 接続設定 + + nn::cfg::CTR::detail::EulaInfoCfgData net_eula; // EULA + nn::cfg::CTR::detail::BossSettingCfgData net_boss; // BOSS +}; + + +//========================================================================== +// 国・地域情報(セーブ不要) +//========================================================================== +enum +{ + eAddrLangageNum = nn::cfg::CTR::CFG_SIMPLE_ADDRESS_NUM_LANGUAGES, + eAddrNameLength = nn::cfg::CTR::CFG_SIMPLE_ADDRESS_NAME_LENGTH +}; + +struct CountryInfo +{ + u32 id; // 国ID + u32 numRegion; // 地域数 + bool newEntry; // CTRで新たに追加された国はtrue + u8 pad[3]; + u16 countryName[eAddrLangageNum][eAddrNameLength]; + u8 order[eAddrLangageNum]; // 言語ごとの国名並び順(最初の国は0) + u8 rsv[32]; +}; + +struct AreaInfo +{ + u32 id; // 国IDと地域IDの組み合わせ + u16 regionName[eAddrLangageNum][eAddrNameLength]; + u8 order[eAddrLangageNum]; // 言語ごとの国名並び順(最初の国は0) + u16 latitude; // 緯度 + u16 longitude; // 経度 +}; + + +//========================================================================== +// その他、セーブ不要の情報 +//========================================================================== +struct WorkInfo +{ +// 地域 + int country_id; // 選んでいる国のID + int country; // 国設定のスライダーバーでの位置 + int area; // 地域設定のスライダーバーでの位置 + int area_num; // 選んでいる国の地域数 + int language; + +// 日付、時刻 + int time[2]; // 0:時 1:分 + int date[3]; // 0:年 1:月 2:日 + + u8 eula_minor; + u8 eula_major; + + u8 padding[2]; +}; + + +//========================================================================== +// BOSS で送信する情報 +//========================================================================== +// ------------------------------------------------------------------- +// cfg の情報 +// ------------------------------------------------------------------- +struct BossSendCfgInfo +{ + nn::cfg::CTR::detail::TouchPanelCfgData touchPanel; // タッチパネル + nn::cfg::CTR::detail::AnalogStickCfgData analogStick; // アナログスティック + nn::cfg::CTR::detail::GyroscopeCfgData gyro; // ジャイロ + nn::cfg::CTR::detail::AccelCfgData accel; // 加速度センサ + nn::cfg::CTR::detail::BackLightCfgData backLight; // バックライト + nn::cfg::CTR::detail::CameraCfgData camera; // カメラ + nn::cfg::CTR::detail::SoundSettingCfgData sound; // サウンド + nn::cfg::CTR::detail::LanguageCfgData language; // 言語 + nn::cfg::CTR::detail::SimpleAddressIdCfgData simpleAddress; // 簡易アドレス + nn::cfg::CTR::detail::ParentalControlInfoCfgData parental; // ペアレンタルコントロール + nn::cfg::CTR::detail::EulaInfoCfgData eula; // EULA + nn::cfg::CTR::detail::BossSettingCfgData boss; // BOSS + f32 svr2Vol; // 3D ボリューム + u8 sndVol; // サウンドボリューム +}; + +// ------------------------------------------------------------------- +// インターネット設定の情報 +// ------------------------------------------------------------------- +struct BossSendNetInfo +{ + u8 networkVersion; // NetworkSetting の version + bool wirelessEnable; // WirelessSetting の enable + bool wirelessEditableEssidSecrity; // WirelessSetting の editableEssidSecurity + bool multiSsidEnable; // MultiSsidSetting の enable + bool ipEnableDHCP; // IpSetting の enableDHCP + bool ipAutoDNSSetting; // IpSetting の autoDNSSetting + bool proxyEnable; // ProxySetting の enable + bool otherEnableUPnP; // OtherSetting の enableUPnP + nn::ac::CTR::SecurityMode essidSecurityMode; // EssidSecurity の securityMode + nn::ac::CTR::MultiSsidType multiSsidType; // MultiSsidType の multiSsidType + nn::ac::CTR::ProxyAuthType proxyAuthType; // ProxySetting の authType + u8 padding; // パディング +}; + +// ------------------------------------------------------------------- +// 工場出荷時のキャリブレーションの情報 +// ------------------------------------------------------------------- +struct FactoryCalInfo +{ + nn::cfg::CTR::detail::CameraCfgData camera; // カメラ + nn::cfg::CTR::detail::AnalogStickCfgData analogStick; // アナログスティック +}; + +struct BossSendInfo +{ + BossSendCfgInfo cfgInfo; + BossSendNetInfo netInfo[NetInfo::eInfoMax]; + FactoryCalInfo factoryCalInfo; + nn::cfg::CTR::detail::CoppacsCfgData coppacsInfo; +}; + + +//****************************************************************************** +// 各種情報にアクセスするためのクラス +//****************************************************************************** +//========================================================================== +// +//========================================================================== +class UserInfoAccessor +{ +public: + UserInfoAccessor(){} + ~UserInfoAccessor(){} + + static void init( int flg = 0 ); + static void eventProc( int info_event ); + static void destroy(); + + static int checkEula(); // EULAの情報を調べる + static void loadEula(); + static void setBossTask(); + static void setBossSendInfoTask(); + static void setBossSendInfoTaskFirst(); + static void saveBossSendInfoTaskOptoutFlag( bool optout ); + static bool checkUpdateBossSendInfo( BossSendInfo* pSaveData ); + static void getAnalogData( nn::cfg::CTR::detail::AnalogStickCfgData* para, int flg = 0 ); + +//========================================================================== +// 初回起動設定用 + static void saveFirstInfo( int mmen, u8 net ); // 初回起動のセーブ + + static bool isFirst(){ return ( msFirst.end == 0 ); } + static const FirstInfo& getFirst(){ return msFirst; } + static void setFirst( FirstInfo& first ){ msFirst = first; } + + static void setFirstParam(); // 初回起動用パラメータ + static void setFirstAll( bool set ); + + static void getSharedArea(); + +//========================================================================== +// ユーザー情報設定アクセス用 + static void setUserInfo( UserInfo& user_info ); + static const UserInfo& getUserInfo(){ return msUserInfo; } + static const UserInfo* getUserInfoPtr(){ return &msUserInfo; } + +//========================================================================== +// Twlユーザー情報設定アクセス用 + static void setTwlInfo( TwlInfo& twl_info ); + static const TwlInfo& getTwlInfo(){ return msTwlInfo; } + static const TwlInfo* getTwlInfoPtr(){ return &msTwlInfo; } + + static void setTwlInfo2( TwlInfo2& twl_info ); + static const TwlInfo2& getTwlInfo2(){ return msTwlInfo2; } + static const TwlInfo2* getTwlInfo2Ptr(){ return &msTwlInfo2; } + + + //TWLで入力不可能な文字を'?'に置換する + static void replaceUnusableString( wchar_t* buffer, int len ); + //TWLで入力不可能な文字を'?'に置換する(TWLで入力可能な文字テーブルを使用する方法) + static void replaceUnusableStringWithTwlUserInfoFontTable(wchar_t* buffer, int len); + static bool binarySearchFromTwlUserInfoFontTable(u16 wc); + +//========================================================================== +// ネットワーク設定アクセス用 + static bool isCheckNetworkInfo(); // オリジナルとバックアップの比較(setting単位) + + static int getAccNum(){ return msAccNum; } // 接続先の番号取得 + static void setAccNum( int num ){ msAccNum = num; } // 接続先のセット + + static int getTmpNum(){ return msTmpNum; } + static void setTmpNum( int num ){ msTmpNum = num; } + + static void setNetInfo( NetInfo& net_info ); + static const NetInfo& getNetInfo(){ return msNetInfo; } + static const NetInfo* getNetInfoPtr(){ return &msNetInfo; } + + static const nn::ac::CTR::WirelessSetting& getNetWireInfo( int num ){ return msNetInfo.setting[num].wireless; } + static const nn::ac::CTR::IpSetting& getNetIpInfo( int num ){ return msNetInfo.setting[num].ip; } + static const nn::ac::CTR::ProxySetting& getNetProxyInfo( int num ){ return msNetInfo.setting[num].proxy; } + static const nn::ac::CTR::OtherSetting& getNetOtherInfo( int num ){ return msNetInfo.setting[num].other; } + static const nn::ac::CTR::MultiSsidSetting& getNetMultiInfo( int num ){ return msNetInfo.setting[num].wireless.multiSsid; } + + static const nn::ac::CTR::NetworkSetting* getNetSettingPtr( int num ){ return &msNetInfo.setting[num]; } + + static void setNetNewParam( int num ); // TODO:アクセスポイント初期設定(仮) + + static void setNetWireless( int num, nn::ac::CTR::WirelessSetting& wireless ); + static void setNetIp( int num, nn::ac::CTR::IpSetting& ip ); + static void setNetProxy( int num, nn::ac::CTR::ProxySetting& proxy ); + static void setNetOther( int num, nn::ac::CTR::OtherSetting& other ); + + static void delNetSetInfo( int num ); + + static u8* readCountryData( int flg ); // 国地域情報の読み込み + +#ifdef MAKE_ACCTEST +#ifndef NW_RELEASE + static void print_net_save_(); +#endif +#endif + +#ifndef NW_RELEASE + static void getLastDsData(); +#endif + + static bool isNetSet(){ return msFirstInfo.internet; } + static bool isEula(){ return ( msNetInfo.net_eula.agreeVersion.version > 0 ); } + static bool isEulaCoppa(){ return ( msNetInfo.net_eula.agreeVersion.version >= 0x0101 ); } + + static void setNetInit( bool used ); + static void setNetBg24Get( bool used ); + static void setNetBg24Send( bool used ); + static void clrNetBg24(); + static nn::ProgramId getHomePid(); + static nn::ProgramId getMsetPid(); + static nn::ProgramId getPnotePid(); + static const char* getMsetBossCode(); + static void clrNet2(); + static void prepareBossSendInfo(); + +//========================================================================== +// ペアレンタルコントロール設定アクセス用 + static void setParentInfo( nn::cfg::CTR::ParentalControlInfo& parent_info ); + static const nn::cfg::CTR::ParentalControlInfo& getParentInfo(){ return msParentInfo; } + static const nn::cfg::CTR::ParentalControlInfo* getParentInfoPtr(){ return &msParentInfo; } + + static void clrParentInfo( bool eula ); + static bool isCheckParentInfo(); + + static bool isParentalLock(){ return msParentInfo.flags.isSetParentalControl != 0; } + static bool is3dLock(){ return msParentInfo.flags.ulcd != 0; } + +//========================================================================== +// COPPACS設定アクセス用 + static void setCoppaInfo( nn::cfg::CTR::detail::CoppacsCfgData& coppa_info ); + static const nn::cfg::CTR::detail::CoppacsCfgData& getCoppaInfo(){ return msCoppaInfo; } + static const nn::cfg::CTR::detail::CoppacsCfgData* getCoppaInfoPtr(){ return &msCoppaInfo; } + + static bool isCheckCoppaInfo(); + static void saveCoppaInfo( nn::cfg::CTR::detail::CoppacsCfgData& coppa_info ); + static bool isCoppa(){ return msIsCoppa; } + static void setCoppacs(); + +//========================================================================== +// WorkInfoアクセス用 + static void setWorkInfo( WorkInfo& work_info ); + static const WorkInfo& getWorkInfo(){ return msWorkInfo; } + static const WorkInfo* getWorkInfoPtr(){ return &msWorkInfo; } + +//========================================================================== +// スライダーバーで使用する要素 + static void setSlideWord( int i, int j, wchar_t w ){ msSlideStr[i][j] = w; } + static wchar_t* getSlideStr( int i ){ return msSlideStr[i]; } + static const wchar_t** getSlideFact(){ return mspSlideFact; } + +//========================================================================== +// 現リージョンで存在する国数の取得 + static u16 getCountryNum(){ return msCountryNum; } + +//========================================================================== +private: + static void check_first_set_(); + static void set_country_info_(); + static void flush_net_setting_(); + static void set_boss_send_info_task_(); + static bool save_boss_send_info_(); + static void prepare_boss_send_cfg_info_(); + static void prepare_boss_send_net_info_(); + static void prepare_boss_send_factory_cal_info_(); + +#ifndef NW_RELEASE + //二分探索するため、テーブルが昇順で並んでいることを確認する(Development用)。 + //昇順であればtrue,そうでなければfalse。 + static bool check_order_twl_user_info_font_table_(); +#endif + + +//========================================================================== + static bool data_user_info_( int kind, int type ); // CFGデータLoad/Save + + static bit32 get_cfg_key_( bit32 category, bit32 id ) + { + return ( ( static_cast( category ) << 16 ) | ( static_cast( id ) ) ); + } + +//========================================================================== + static void set_first_boot_ac_(); + +//========================================================================== + static UserInfo msUserInfo; + static UserInfo msBackupUserInfo; + +//========================================================================== + static TwlInfo msTwlInfo; + static TwlInfo msBackupTwlInfo; + + static TwlInfo2 msTwlInfo2; + static TwlInfo2 msBackupTwlInfo2; + +//========================================================================== +// 設定用ワーク + static WorkInfo msWorkInfo; + static WorkInfo msBackupWorkInfo; + +//========================================================================== + static nn::cfg::CTR::ParentalControlInfo msParentInfo; + static nn::cfg::CTR::ParentalControlInfo msBackupParentInfo; + +//========================================================================== + static nn::cfg::CTR::detail::CoppacsCfgData msCoppaInfo; + static nn::cfg::CTR::detail::CoppacsCfgData msBackupCoppaInfo; + +//========================================================================== + static NetInfo msNetInfo; + static NetInfo msBackupNetInfo; + +// インターネット設定用 + static int msAccNum; // 接続先 + static int msTmpNum; // 設定先 + +//========================================================================== +// BOSS 送信情報 + static BossSendInfo msBossSendInfo; + +//========================================================================== +// データ更新用 + enum + { + eNoneInfo = 0, + + eUserInfo = 0x01, + eTwlInfo = 0x02, + eTwlInfo2 = 0x04, + eNetInfo = 0x08, + + eParentInfo = 0x10, + eNetInfo2 = 0x20, + eCoppaInfo = 0x40, + eWorkInfo = 0x80, + + eAllInfo = 0xff + }; + + enum + { + eKindUserName = 0, // eUserInfo + eKindAddressId, + eKindAddressCountry, + eKindAddressRegion, + eKindAddressPosition, + eKindBirthday, + eKindLanguage, + eKindSound, + + eKindEula, // eNetInfo2 + eKindBoss, + + eKindParental, // eParentInfo + eKindCoppa, // eCoppaInfo + + eKindDsData, // eTwlInfo + + eKindDsCountry, // eTwlInfo2 + eKindDsParental, + eKindDsEula, + + eKindFirst, // 別 + + eKindMax + }; + + static u32 msDirty; // セーブのためのフラグ + +//========================================================================== + static nn::cfg::CTR::detail::FirstLaunchInfoCfgData msFirstInfo; + + static FirstInfo msFirst; + + static u16 msCountryNum; // 現リージョンでの国数 + static u8* mpSharedAreaBuf; + + static bool msIsNetSave; + + static bool msIsCoppa; + +//========================================================================== +// スライダーバーで使用する要素(全スライダーバー共通で使用) + enum + { + eFactNum = 100, + eStrSize = 64 + }; + + static wchar_t msSlideStr[eFactNum][eStrSize]; + static const wchar_t* mspSlideFact[eFactNum]; + + friend class ProcessManager; +}; + +} + +#endif