mirror of
https://github.com/pumpitupdev/pumptools.git
synced 2026-09-27 09:23:15 +03:00
Appl new code style on whole code base
Use a similar code style to bemanitools though reduce indentation to 2 spaces. Also some other tweaks to be more similar to google style.
This commit is contained in:
@@ -4,46 +4,46 @@
|
||||
|
||||
#define ENC_DEC_INIT_SEED 0xEBADA1
|
||||
|
||||
struct asset_f2_usb_rank* asset_f2_usb_rank_new(void)
|
||||
struct asset_f2_usb_rank *asset_f2_usb_rank_new(void)
|
||||
{
|
||||
// TODO
|
||||
return malloc(sizeof(struct asset_f2_usb_rank));
|
||||
// TODO
|
||||
return malloc(sizeof(struct asset_f2_usb_rank));
|
||||
}
|
||||
|
||||
void asset_f2_usb_rank_finalize(struct asset_f2_usb_rank* rank)
|
||||
void asset_f2_usb_rank_finalize(struct asset_f2_usb_rank *rank)
|
||||
{
|
||||
/* don't include the checksum field */
|
||||
/*
|
||||
rank->header.adler32 = util_adler32_calc(rank->header.adler_seed,
|
||||
&rank->header.adler_seed,
|
||||
sizeof(struct f2_profile_rank) - sizeof(uint32_t));
|
||||
*/
|
||||
/* don't include the checksum field */
|
||||
/*
|
||||
rank->header.adler32 = util_adler32_calc(rank->header.adler_seed,
|
||||
&rank->header.adler_seed,
|
||||
sizeof(struct f2_profile_rank) - sizeof(uint32_t));
|
||||
*/
|
||||
}
|
||||
|
||||
char* asset_f2_usb_rank_to_string(const struct asset_f2_usb_rank* rank)
|
||||
char *asset_f2_usb_rank_to_string(const struct asset_f2_usb_rank *rank)
|
||||
{
|
||||
// TODO
|
||||
return "";
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
|
||||
void asset_f2_usb_rank_decrypt(uint8_t* buf, size_t len)
|
||||
void asset_f2_usb_rank_decrypt(uint8_t *buf, size_t len)
|
||||
{
|
||||
uint32_t seed = ENC_DEC_INIT_SEED;
|
||||
uint32_t seed = ENC_DEC_INIT_SEED;
|
||||
|
||||
for (int i = 0; i < len; i++){
|
||||
uint8_t smbuff = buf[i];
|
||||
buf[i] ^= (seed >> 8) & 0xff ;
|
||||
seed = 0x68993 * (smbuff + seed) + 0x4FDCF;
|
||||
}
|
||||
for (int i = 0; i < len; i++) {
|
||||
uint8_t smbuff = buf[i];
|
||||
buf[i] ^= (seed >> 8) & 0xff;
|
||||
seed = 0x68993 * (smbuff + seed) + 0x4FDCF;
|
||||
}
|
||||
}
|
||||
|
||||
void asset_f2_usb_rank_encrypt(uint8_t* buf, size_t len)
|
||||
void asset_f2_usb_rank_encrypt(uint8_t *buf, size_t len)
|
||||
{
|
||||
uint32_t seed = ENC_DEC_INIT_SEED;
|
||||
uint32_t seed = ENC_DEC_INIT_SEED;
|
||||
|
||||
for (size_t i = 0; i < len; i++){
|
||||
uint8_t smbuff = buf[i] ^ ((seed >> 8) & 0xff);
|
||||
buf[i] = smbuff ;
|
||||
seed = 0x68993 * (smbuff + seed) + 0x4FDCF;
|
||||
}
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
uint8_t smbuff = buf[i] ^ ((seed >> 8) & 0xff);
|
||||
buf[i] = smbuff;
|
||||
seed = 0x68993 * (smbuff + seed) + 0x4FDCF;
|
||||
}
|
||||
}
|
||||
@@ -4,18 +4,18 @@
|
||||
#include <stdint.h>
|
||||
|
||||
struct asset_f2_usb_rank {
|
||||
// TODO
|
||||
// TODO
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_f2_usb_rank* asset_f2_usb_rank_new(void);
|
||||
struct asset_f2_usb_rank *asset_f2_usb_rank_new(void);
|
||||
|
||||
// update checksum and prepare profile to get encrypted
|
||||
void asset_f2_usb_rank_finalize(struct asset_f2_usb_rank* rank);
|
||||
void asset_f2_usb_rank_finalize(struct asset_f2_usb_rank *rank);
|
||||
|
||||
char* asset_f2_usb_rank_to_string(const struct asset_f2_usb_rank* rank);
|
||||
char *asset_f2_usb_rank_to_string(const struct asset_f2_usb_rank *rank);
|
||||
|
||||
void asset_f2_usb_rank_decrypt(uint8_t* buf, size_t len);
|
||||
void asset_f2_usb_rank_decrypt(uint8_t *buf, size_t len);
|
||||
|
||||
void asset_f2_usb_rank_encrypt(uint8_t* buf, size_t len);
|
||||
void asset_f2_usb_rank_encrypt(uint8_t *buf, size_t len);
|
||||
|
||||
#endif
|
||||
@@ -4,44 +4,45 @@
|
||||
|
||||
#define ENC_DEC_INIT_SEED 0xEBADA1
|
||||
|
||||
struct asset_f2_usb_save* asset_f2_usb_save_new(void)
|
||||
struct asset_f2_usb_save *asset_f2_usb_save_new(void)
|
||||
{
|
||||
// TODO
|
||||
return malloc(sizeof(struct asset_f2_usb_save));
|
||||
// TODO
|
||||
return malloc(sizeof(struct asset_f2_usb_save));
|
||||
}
|
||||
|
||||
void asset_f2_usb_save_finalize(struct asset_f2_usb_save* save)
|
||||
void asset_f2_usb_save_finalize(struct asset_f2_usb_save *save)
|
||||
{
|
||||
/* don't include the checksum field */
|
||||
save->header.adler32 = util_adler32_calc(save->header.adler_seed,
|
||||
&save->header.adler_seed,
|
||||
sizeof(struct asset_f2_usb_save) - sizeof(uint32_t));
|
||||
/* don't include the checksum field */
|
||||
save->header.adler32 = util_adler32_calc(
|
||||
save->header.adler_seed,
|
||||
&save->header.adler_seed,
|
||||
sizeof(struct asset_f2_usb_save) - sizeof(uint32_t));
|
||||
}
|
||||
|
||||
char* asset_f2_usb_save_to_string(const struct asset_f2_usb_save* save)
|
||||
char *asset_f2_usb_save_to_string(const struct asset_f2_usb_save *save)
|
||||
{
|
||||
// TODO
|
||||
return "";
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
|
||||
void asset_f2_usb_save_decrypt(uint8_t* buf, size_t len)
|
||||
void asset_f2_usb_save_decrypt(uint8_t *buf, size_t len)
|
||||
{
|
||||
uint32_t seed = ENC_DEC_INIT_SEED;
|
||||
uint32_t seed = ENC_DEC_INIT_SEED;
|
||||
|
||||
for (int i = 0; i < len; i++){
|
||||
uint8_t smbuff = buf[i];
|
||||
buf[i] ^= (seed >> 8) & 0xff ;
|
||||
seed = 0x68993 * (smbuff + seed) + 0x4FDCF;
|
||||
}
|
||||
for (int i = 0; i < len; i++) {
|
||||
uint8_t smbuff = buf[i];
|
||||
buf[i] ^= (seed >> 8) & 0xff;
|
||||
seed = 0x68993 * (smbuff + seed) + 0x4FDCF;
|
||||
}
|
||||
}
|
||||
|
||||
void asset_f2_usb_save_encrypt(uint8_t* buf, size_t len)
|
||||
void asset_f2_usb_save_encrypt(uint8_t *buf, size_t len)
|
||||
{
|
||||
uint32_t seed = ENC_DEC_INIT_SEED;
|
||||
uint32_t seed = ENC_DEC_INIT_SEED;
|
||||
|
||||
for (size_t i = 0; i < len; i++){
|
||||
uint8_t smbuff = buf[i] ^ (seed >> 8) & 0xff;
|
||||
buf[i] = smbuff ;
|
||||
seed = 0x68993 * (smbuff + seed) + 0x4FDCF;
|
||||
}
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
uint8_t smbuff = buf[i] ^ (seed >> 8) & 0xff;
|
||||
buf[i] = smbuff;
|
||||
seed = 0x68993 * (smbuff + seed) + 0x4FDCF;
|
||||
}
|
||||
}
|
||||
@@ -5,101 +5,101 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
struct asset_f2_usb_save_machine_stats {
|
||||
uint32_t beginner_mode_play_count;
|
||||
uint32_t maniac_mode_play_count;
|
||||
uint32_t unkn;
|
||||
uint32_t unkn2;
|
||||
uint32_t battle_mode_play_count;
|
||||
uint32_t mission_zone_play_count;
|
||||
uint32_t skill_zone_play_count;
|
||||
uint32_t coop_mission_play_count;
|
||||
uint32_t beginner_mode_play_count;
|
||||
uint32_t maniac_mode_play_count;
|
||||
uint32_t unkn;
|
||||
uint32_t unkn2;
|
||||
uint32_t battle_mode_play_count;
|
||||
uint32_t mission_zone_play_count;
|
||||
uint32_t skill_zone_play_count;
|
||||
uint32_t coop_mission_play_count;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_f2_usb_save_machine_info {
|
||||
/* NULL terminated */
|
||||
char version[8];
|
||||
/* NULL terminated */
|
||||
char cpu[128];
|
||||
/* NULL terminated */
|
||||
char motherboard[128];
|
||||
/* NULL terminated */
|
||||
char gfxcard[128];
|
||||
/* NULL terminated */
|
||||
char hdd[32];
|
||||
uint32_t total_ram_bytes;
|
||||
uint32_t haspkey_id;
|
||||
/* NULL terminated */
|
||||
char version[8];
|
||||
/* NULL terminated */
|
||||
char cpu[128];
|
||||
/* NULL terminated */
|
||||
char motherboard[128];
|
||||
/* NULL terminated */
|
||||
char gfxcard[128];
|
||||
/* NULL terminated */
|
||||
char hdd[32];
|
||||
uint32_t total_ram_bytes;
|
||||
uint32_t haspkey_id;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_f2_usb_save_header {
|
||||
uint32_t adler32;
|
||||
uint32_t adler_seed;
|
||||
/* NULL terminated */
|
||||
char player_id[8];
|
||||
uint32_t region;
|
||||
uint32_t avatar_id;
|
||||
uint32_t level;
|
||||
float total_calories;
|
||||
float total_v02;
|
||||
uint64_t num_running_steps;
|
||||
uint64_t num_games_played;
|
||||
uint64_t exp;
|
||||
uint64_t arcade_score;
|
||||
uint32_t num_missions_completed;
|
||||
uint32_t num_coop_missions_completed;
|
||||
uint32_t battle_count_wins;
|
||||
uint32_t battle_count_loses;
|
||||
uint32_t battle_count_draws;
|
||||
/* TODO: modifier stuff? */
|
||||
uint64_t unlock;
|
||||
uint32_t unlock_seed;
|
||||
uint32_t adler32;
|
||||
uint32_t adler_seed;
|
||||
/* NULL terminated */
|
||||
char player_id[8];
|
||||
uint32_t region;
|
||||
uint32_t avatar_id;
|
||||
uint32_t level;
|
||||
float total_calories;
|
||||
float total_v02;
|
||||
uint64_t num_running_steps;
|
||||
uint64_t num_games_played;
|
||||
uint64_t exp;
|
||||
uint64_t arcade_score;
|
||||
uint32_t num_missions_completed;
|
||||
uint32_t num_coop_missions_completed;
|
||||
uint32_t battle_count_wins;
|
||||
uint32_t battle_count_loses;
|
||||
uint32_t battle_count_draws;
|
||||
/* TODO: modifier stuff? */
|
||||
uint64_t unlock;
|
||||
uint32_t unlock_seed;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_f2_usb_save_machine_highscore_entry {
|
||||
uint32_t song_id;
|
||||
uint8_t difficulty;
|
||||
uint8_t mode;
|
||||
uint8_t grade;
|
||||
uint8_t clear_state;
|
||||
uint32_t score_total;
|
||||
uint32_t play_count;
|
||||
uint32_t unkn;
|
||||
/* NULL terminated */
|
||||
char player_id[8];
|
||||
uint32_t unkn2;
|
||||
uint32_t null_padding;
|
||||
uint32_t song_id;
|
||||
uint8_t difficulty;
|
||||
uint8_t mode;
|
||||
uint8_t grade;
|
||||
uint8_t clear_state;
|
||||
uint32_t score_total;
|
||||
uint32_t play_count;
|
||||
uint32_t unkn;
|
||||
/* NULL terminated */
|
||||
char player_id[8];
|
||||
uint32_t unkn2;
|
||||
uint32_t null_padding;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_f2_usb_save_highscore_entry {
|
||||
uint32_t song_id;
|
||||
uint8_t difficulty;
|
||||
uint8_t mode;
|
||||
uint8_t grade;
|
||||
uint8_t clear_and_unlock_state;
|
||||
uint32_t score_total;
|
||||
uint32_t play_count;
|
||||
uint32_t null_padding;
|
||||
uint32_t song_id;
|
||||
uint8_t difficulty;
|
||||
uint8_t mode;
|
||||
uint8_t grade;
|
||||
uint8_t clear_and_unlock_state;
|
||||
uint32_t score_total;
|
||||
uint32_t play_count;
|
||||
uint32_t null_padding;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_f2_usb_save {
|
||||
/* start offset: 0x00 */
|
||||
struct asset_f2_usb_save_header header;
|
||||
/* start offset: 0x120 */
|
||||
struct asset_f2_usb_save_machine_info machine_info;
|
||||
struct asset_f2_usb_save_machine_stats machine_stats;
|
||||
/* start offset: 0x2F0 */
|
||||
/* start offset: 0x00 */
|
||||
struct asset_f2_usb_save_header header;
|
||||
/* start offset: 0x120 */
|
||||
struct asset_f2_usb_save_machine_info machine_info;
|
||||
struct asset_f2_usb_save_machine_stats machine_stats;
|
||||
/* start offset: 0x2F0 */
|
||||
|
||||
// TODO continue
|
||||
// TODO continue
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_f2_usb_save* asset_f2_usb_save_new(void);
|
||||
struct asset_f2_usb_save *asset_f2_usb_save_new(void);
|
||||
|
||||
// update checksum and prepare profile to get encrypted
|
||||
void asset_f2_usb_save_finalize(struct asset_f2_usb_save* save);
|
||||
void asset_f2_usb_save_finalize(struct asset_f2_usb_save *save);
|
||||
|
||||
char* asset_f2_usb_save_to_string(const struct asset_f2_usb_save* save);
|
||||
char *asset_f2_usb_save_to_string(const struct asset_f2_usb_save *save);
|
||||
|
||||
void asset_f2_usb_save_decrypt(uint8_t* buf, size_t len);
|
||||
void asset_f2_usb_save_decrypt(uint8_t *buf, size_t len);
|
||||
|
||||
void asset_f2_usb_save_encrypt(uint8_t* buf, size_t len);
|
||||
void asset_f2_usb_save_encrypt(uint8_t *buf, size_t len);
|
||||
|
||||
#endif
|
||||
@@ -7,90 +7,100 @@
|
||||
|
||||
#include "util.h"
|
||||
|
||||
struct asset_f2_usb_rank* asset_f2_util_rank_usb_load_from_file(const char* path, bool encrypted)
|
||||
struct asset_f2_usb_rank *
|
||||
asset_f2_util_rank_usb_load_from_file(const char *path, bool encrypted)
|
||||
{
|
||||
struct asset_f2_usb_rank* rank;
|
||||
size_t size;
|
||||
struct asset_f2_usb_rank *rank;
|
||||
size_t size;
|
||||
|
||||
if (!util_file_load(path, (void**) &rank, &size, false)) {
|
||||
log_error("Loading f2 rank file %s failed", path);
|
||||
return NULL;
|
||||
}
|
||||
if (!util_file_load(path, (void **) &rank, &size, false)) {
|
||||
log_error("Loading f2 rank file %s failed", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size != sizeof(struct asset_f2_usb_rank)) {
|
||||
log_error("Invalid size of f2 rank file %s: %d != %d", path, size,
|
||||
sizeof(struct asset_f2_usb_rank));
|
||||
free(rank);
|
||||
return NULL;
|
||||
}
|
||||
if (size != sizeof(struct asset_f2_usb_rank)) {
|
||||
log_error(
|
||||
"Invalid size of f2 rank file %s: %d != %d",
|
||||
path,
|
||||
size,
|
||||
sizeof(struct asset_f2_usb_rank));
|
||||
free(rank);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (encrypted) {
|
||||
asset_f2_usb_rank_decrypt((uint8_t*) rank, size);
|
||||
}
|
||||
if (encrypted) {
|
||||
asset_f2_usb_rank_decrypt((uint8_t *) rank, size);
|
||||
}
|
||||
|
||||
return rank;
|
||||
return rank;
|
||||
}
|
||||
|
||||
bool asset_f2_util_rank_usb_save_to_file(const char* path, const struct asset_f2_usb_rank* rank, bool encrypt)
|
||||
bool asset_f2_util_rank_usb_save_to_file(
|
||||
const char *path, const struct asset_f2_usb_rank *rank, bool encrypt)
|
||||
{
|
||||
struct asset_f2_usb_rank rank_enc;
|
||||
struct asset_f2_usb_rank rank_enc;
|
||||
|
||||
memcpy(&rank_enc, rank, sizeof(struct asset_f2_usb_rank));
|
||||
memcpy(&rank_enc, rank, sizeof(struct asset_f2_usb_rank));
|
||||
|
||||
if (encrypt) {
|
||||
asset_f2_usb_rank_encrypt((uint8_t*) &rank_enc,
|
||||
sizeof(struct asset_f2_usb_rank));
|
||||
}
|
||||
if (encrypt) {
|
||||
asset_f2_usb_rank_encrypt(
|
||||
(uint8_t *) &rank_enc, sizeof(struct asset_f2_usb_rank));
|
||||
}
|
||||
|
||||
if (!util_file_save(path, (void**) &rank_enc,
|
||||
sizeof(struct asset_f2_usb_rank))) {
|
||||
log_error("Storing f2 rank data to %s failed", path);
|
||||
return false;
|
||||
}
|
||||
if (!util_file_save(
|
||||
path, (void **) &rank_enc, sizeof(struct asset_f2_usb_rank))) {
|
||||
log_error("Storing f2 rank data to %s failed", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct asset_f2_usb_save* asset_f2_util_usb_save_load_from_file(const char* path, bool encrypted)
|
||||
struct asset_f2_usb_save *
|
||||
asset_f2_util_usb_save_load_from_file(const char *path, bool encrypted)
|
||||
{
|
||||
struct asset_f2_usb_save* save;
|
||||
size_t size;
|
||||
struct asset_f2_usb_save *save;
|
||||
size_t size;
|
||||
|
||||
if (!util_file_load(path, (void**) &save, &size, false)) {
|
||||
log_error("Loading f2 save file %s failed", path);
|
||||
return NULL;
|
||||
}
|
||||
if (!util_file_load(path, (void **) &save, &size, false)) {
|
||||
log_error("Loading f2 save file %s failed", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size != sizeof(struct asset_f2_usb_save)) {
|
||||
log_error("Invalid size of f2 save file %s: %d != %d", path, size,
|
||||
sizeof(struct asset_f2_usb_save));
|
||||
free(save);
|
||||
return NULL;
|
||||
}
|
||||
if (size != sizeof(struct asset_f2_usb_save)) {
|
||||
log_error(
|
||||
"Invalid size of f2 save file %s: %d != %d",
|
||||
path,
|
||||
size,
|
||||
sizeof(struct asset_f2_usb_save));
|
||||
free(save);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (encrypted) {
|
||||
asset_f2_usb_save_decrypt((uint8_t*) save, size);
|
||||
}
|
||||
if (encrypted) {
|
||||
asset_f2_usb_save_decrypt((uint8_t *) save, size);
|
||||
}
|
||||
|
||||
return save;
|
||||
return save;
|
||||
}
|
||||
|
||||
bool asset_f2_util_usb_save_save_to_file(const char* path, const struct asset_f2_usb_save* save, bool encrypt)
|
||||
bool asset_f2_util_usb_save_save_to_file(
|
||||
const char *path, const struct asset_f2_usb_save *save, bool encrypt)
|
||||
{
|
||||
struct asset_f2_usb_save save_enc;
|
||||
struct asset_f2_usb_save save_enc;
|
||||
|
||||
memcpy(&save_enc, save, sizeof(struct asset_f2_usb_save));
|
||||
memcpy(&save_enc, save, sizeof(struct asset_f2_usb_save));
|
||||
|
||||
if (encrypt) {
|
||||
asset_f2_usb_save_encrypt((uint8_t*) &save_enc,
|
||||
sizeof(struct asset_f2_usb_save));
|
||||
}
|
||||
if (encrypt) {
|
||||
asset_f2_usb_save_encrypt(
|
||||
(uint8_t *) &save_enc, sizeof(struct asset_f2_usb_save));
|
||||
}
|
||||
|
||||
if (!util_file_save(path, (const void*) &save_enc,
|
||||
sizeof(struct asset_f2_usb_save))) {
|
||||
log_error("Storing f2 save data to %s failed", path);
|
||||
return false;
|
||||
}
|
||||
if (!util_file_save(
|
||||
path, (const void *) &save_enc, sizeof(struct asset_f2_usb_save))) {
|
||||
log_error("Storing f2 save data to %s failed", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
@@ -7,15 +7,19 @@
|
||||
#include "usb-save.h"
|
||||
|
||||
// load from file and decrypt, returns decrypted struct
|
||||
struct asset_f2_usb_rank* asset_f2_util_usb_rank_load_from_file(const char* path, bool encrypted);
|
||||
struct asset_f2_usb_rank *
|
||||
asset_f2_util_usb_rank_load_from_file(const char *path, bool encrypted);
|
||||
|
||||
// takes decrypted rank data, encrypts it and writes it to file
|
||||
bool asset_f2_util_usb_rank_save_to_file(const char* path, const struct asset_f2_usb_rank* rank, bool encrypt);
|
||||
bool asset_f2_util_usb_rank_save_to_file(
|
||||
const char *path, const struct asset_f2_usb_rank *rank, bool encrypt);
|
||||
|
||||
// load from file and decrypt, returns decrypted struct
|
||||
struct asset_f2_usb_save* asset_f2_util_usb_save_load_from_file(const char* path, bool encrypted);
|
||||
struct asset_f2_usb_save *
|
||||
asset_f2_util_usb_save_load_from_file(const char *path, bool encrypted);
|
||||
|
||||
// takes decrypted save data, encrypts it and writes it to file
|
||||
bool asset_f2_util_usb_save_save_to_file(const char* path, const struct asset_f2_usb_save* save, bool encrypt);
|
||||
bool asset_f2_util_usb_save_save_to_file(
|
||||
const char *path, const struct asset_f2_usb_save *save, bool encrypt);
|
||||
|
||||
#endif
|
||||
@@ -2,31 +2,30 @@
|
||||
|
||||
#include "usb-rank.h"
|
||||
|
||||
struct asset_fex_usb_rank* asset_fex_usb_rank_new(void)
|
||||
struct asset_fex_usb_rank *asset_fex_usb_rank_new(void)
|
||||
{
|
||||
return malloc(sizeof(struct asset_fex_usb_rank));
|
||||
return malloc(sizeof(struct asset_fex_usb_rank));
|
||||
}
|
||||
|
||||
void asset_fex_usb_rank_finalize(struct asset_fex_usb_rank* rank)
|
||||
void asset_fex_usb_rank_finalize(struct asset_fex_usb_rank *rank)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
char* asset_fex_usb_rank_to_string(const struct asset_fex_usb_rank* rank)
|
||||
char *asset_fex_usb_rank_to_string(const struct asset_fex_usb_rank *rank)
|
||||
{
|
||||
return malloc(0);
|
||||
return malloc(0);
|
||||
}
|
||||
|
||||
void asset_fex_usb_rank_decrypt(uint8_t* buf, size_t len)
|
||||
void asset_fex_usb_rank_decrypt(uint8_t *buf, size_t len)
|
||||
{
|
||||
for (size_t a = len - 1; a > 0; --a) {
|
||||
buf[a] = (buf[a] ^ buf[a - 1]) + ((a * 1234567) >> 8);
|
||||
}
|
||||
for (size_t a = len - 1; a > 0; --a) {
|
||||
buf[a] = (buf[a] ^ buf[a - 1]) + ((a * 1234567) >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
void asset_fex_usb_rank_encrypt(uint8_t* buf, size_t len)
|
||||
void asset_fex_usb_rank_encrypt(uint8_t *buf, size_t len)
|
||||
{
|
||||
for (size_t a = 1; a < len; ++a) {
|
||||
buf[a] = (buf[a] - ((a * 1234567) >> 8)) ^ buf[a - 1];
|
||||
}
|
||||
for (size_t a = 1; a < len; ++a) {
|
||||
buf[a] = (buf[a] - ((a * 1234567) >> 8)) ^ buf[a - 1];
|
||||
}
|
||||
}
|
||||
@@ -5,24 +5,24 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
struct asset_fex_usb_rank_header {
|
||||
uint32_t adler32;
|
||||
/* NULL terminated */
|
||||
char player_id[8];
|
||||
uint32_t adler32;
|
||||
/* NULL terminated */
|
||||
char player_id[8];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_fex_usb_rank {
|
||||
struct asset_fex_usb_rank_header header;
|
||||
struct asset_fex_usb_rank_header header;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_fex_usb_rank* asset_fex_usb_rank_new(void);
|
||||
struct asset_fex_usb_rank *asset_fex_usb_rank_new(void);
|
||||
|
||||
// update checksum and prepare profile to get encrypted
|
||||
void asset_fex_usb_rank_finalize(struct asset_fex_usb_rank* rank);
|
||||
void asset_fex_usb_rank_finalize(struct asset_fex_usb_rank *rank);
|
||||
|
||||
char* asset_fex_usb_rank_to_string(const struct asset_fex_usb_rank* rank);
|
||||
char *asset_fex_usb_rank_to_string(const struct asset_fex_usb_rank *rank);
|
||||
|
||||
void asset_fex_usb_rank_decrypt(uint8_t* buf, size_t len);
|
||||
void asset_fex_usb_rank_decrypt(uint8_t *buf, size_t len);
|
||||
|
||||
void asset_fex_usb_rank_encrypt(uint8_t* buf, size_t len);
|
||||
void asset_fex_usb_rank_encrypt(uint8_t *buf, size_t len);
|
||||
|
||||
#endif
|
||||
+257
-278
@@ -7,333 +7,312 @@
|
||||
|
||||
#include "usb-save.h"
|
||||
|
||||
static char* fex_profile_save_header_to_string(
|
||||
const struct asset_fex_usb_save_header* header)
|
||||
static char *fex_profile_save_header_to_string(
|
||||
const struct asset_fex_usb_save_header *header)
|
||||
{
|
||||
char* buffer;
|
||||
char *buffer;
|
||||
|
||||
buffer = (char*) util_xmalloc(256);
|
||||
memset(buffer, 0, 256);
|
||||
buffer = (char *) util_xmalloc(256);
|
||||
memset(buffer, 0, 256);
|
||||
|
||||
util_str_format(buffer, 256,
|
||||
"-------------- header --------------\n"
|
||||
"adler32: %X\n"
|
||||
"usb_serial: %s\n"
|
||||
"dongle_serial: %X\n",
|
||||
header->adler32,
|
||||
header->usb_serial,
|
||||
header->dongle_serial);
|
||||
util_str_format(
|
||||
buffer,
|
||||
256,
|
||||
"-------------- header --------------\n"
|
||||
"adler32: %X\n"
|
||||
"usb_serial: %s\n"
|
||||
"dongle_serial: %X\n",
|
||||
header->adler32,
|
||||
header->usb_serial,
|
||||
header->dongle_serial);
|
||||
|
||||
return buffer;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static char* fex_profile_save_player_to_string(
|
||||
const struct asset_fex_usb_save_player* player)
|
||||
static char *fex_profile_save_player_to_string(
|
||||
const struct asset_fex_usb_save_player *player)
|
||||
{
|
||||
char* buffer;
|
||||
char *buffer;
|
||||
|
||||
buffer = (char*) util_xmalloc(1024);
|
||||
memset(buffer, 0, 1024);
|
||||
buffer = (char *) util_xmalloc(1024);
|
||||
memset(buffer, 0, 1024);
|
||||
|
||||
util_str_format(buffer, 1024,
|
||||
"-------------- player --------------\n"
|
||||
"unkn: %X\n"
|
||||
"unkn2: %X\n"
|
||||
"avatar_id: %d\n"
|
||||
"player_lvl: %d\n"
|
||||
"unkn3: %X\n"
|
||||
"player_id: %s\n"
|
||||
"unkn4: %X\n"
|
||||
"unkn5: %X\n"
|
||||
"unkn6: %X\n"
|
||||
"unkn7: %X\n"
|
||||
"unkn8: %X\n"
|
||||
"unkn9: %X\n"
|
||||
"unkn10: %X\n"
|
||||
"unkn11: %X\n"
|
||||
"unkn12: %X\n"
|
||||
"unkn13: %X\n"
|
||||
"unkn14: %X\n"
|
||||
"unkn15: %X\n"
|
||||
"total_step: %d\n"
|
||||
"play_count: %d\n"
|
||||
"exp: %d\n"
|
||||
"num_quest_world_passed: %d\n"
|
||||
"unkn16: %X\n"
|
||||
"arcade_score: %d\n"
|
||||
"num_battle_wins: %d\n"
|
||||
"num_battle_loss: %d\n"
|
||||
"num_battle_draw: %d\n",
|
||||
player->unkn,
|
||||
player->unkn2,
|
||||
player->avatar_id,
|
||||
player->player_lvl,
|
||||
player->unkn3,
|
||||
player->player_id,
|
||||
player->unkn4,
|
||||
player->unkn5,
|
||||
player->unkn6,
|
||||
player->unkn7,
|
||||
player->unkn8,
|
||||
player->unkn9,
|
||||
player->unkn10,
|
||||
player->unkn11,
|
||||
player->unkn12,
|
||||
player->unkn13,
|
||||
player->unkn14,
|
||||
player->unkn15,
|
||||
player->total_step,
|
||||
player->play_count,
|
||||
player->exp,
|
||||
player->num_quest_world_passed,
|
||||
player->unkn16,
|
||||
player->arcade_score,
|
||||
player->num_battle_wins,
|
||||
player->num_battle_loss,
|
||||
player->num_battle_draw);
|
||||
util_str_format(
|
||||
buffer,
|
||||
1024,
|
||||
"-------------- player --------------\n"
|
||||
"unkn: %X\n"
|
||||
"unkn2: %X\n"
|
||||
"avatar_id: %d\n"
|
||||
"player_lvl: %d\n"
|
||||
"unkn3: %X\n"
|
||||
"player_id: %s\n"
|
||||
"unkn4: %X\n"
|
||||
"unkn5: %X\n"
|
||||
"unkn6: %X\n"
|
||||
"unkn7: %X\n"
|
||||
"unkn8: %X\n"
|
||||
"unkn9: %X\n"
|
||||
"unkn10: %X\n"
|
||||
"unkn11: %X\n"
|
||||
"unkn12: %X\n"
|
||||
"unkn13: %X\n"
|
||||
"unkn14: %X\n"
|
||||
"unkn15: %X\n"
|
||||
"total_step: %d\n"
|
||||
"play_count: %d\n"
|
||||
"exp: %d\n"
|
||||
"num_quest_world_passed: %d\n"
|
||||
"unkn16: %X\n"
|
||||
"arcade_score: %d\n"
|
||||
"num_battle_wins: %d\n"
|
||||
"num_battle_loss: %d\n"
|
||||
"num_battle_draw: %d\n",
|
||||
player->unkn,
|
||||
player->unkn2,
|
||||
player->avatar_id,
|
||||
player->player_lvl,
|
||||
player->unkn3,
|
||||
player->player_id,
|
||||
player->unkn4,
|
||||
player->unkn5,
|
||||
player->unkn6,
|
||||
player->unkn7,
|
||||
player->unkn8,
|
||||
player->unkn9,
|
||||
player->unkn10,
|
||||
player->unkn11,
|
||||
player->unkn12,
|
||||
player->unkn13,
|
||||
player->unkn14,
|
||||
player->unkn15,
|
||||
player->total_step,
|
||||
player->play_count,
|
||||
player->exp,
|
||||
player->num_quest_world_passed,
|
||||
player->unkn16,
|
||||
player->arcade_score,
|
||||
player->num_battle_wins,
|
||||
player->num_battle_loss,
|
||||
player->num_battle_draw);
|
||||
|
||||
return buffer;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static char* fex_profile_save_mods_to_string(
|
||||
const struct asset_fex_usb_save_player_mods* mods)
|
||||
static char *fex_profile_save_mods_to_string(
|
||||
const struct asset_fex_usb_save_player_mods *mods)
|
||||
{
|
||||
char* buffer;
|
||||
char *buffer;
|
||||
|
||||
buffer = (char*) util_xmalloc(128);
|
||||
memset(buffer, 0, 128);
|
||||
buffer = (char *) util_xmalloc(128);
|
||||
memset(buffer, 0, 128);
|
||||
|
||||
util_str_format(buffer, 128,
|
||||
"-------------- modifiers --------------\n"
|
||||
"modifiers: %X\n"
|
||||
"half_speed_mod: %X\n"
|
||||
"noteskin: %X\n",
|
||||
mods->modifiers,
|
||||
mods->half_speed_mod,
|
||||
mods->noteskin);
|
||||
util_str_format(
|
||||
buffer,
|
||||
128,
|
||||
"-------------- modifiers --------------\n"
|
||||
"modifiers: %X\n"
|
||||
"half_speed_mod: %X\n"
|
||||
"noteskin: %X\n",
|
||||
mods->modifiers,
|
||||
mods->half_speed_mod,
|
||||
mods->noteskin);
|
||||
|
||||
return buffer;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static char* fex_profile_save_mod_unlocks_to_string(
|
||||
const struct asset_fex_usb_save_mod_unlocks* unlocks)
|
||||
static char *fex_profile_save_mod_unlocks_to_string(
|
||||
const struct asset_fex_usb_save_mod_unlocks *unlocks)
|
||||
{
|
||||
char* merged;
|
||||
char* buffer;
|
||||
char* tmp;
|
||||
const size_t buf_size = 512;
|
||||
char *merged;
|
||||
char *buffer;
|
||||
char *tmp;
|
||||
const size_t buf_size = 512;
|
||||
|
||||
merged = (char*) util_xmalloc(buf_size);
|
||||
memset(merged, 0, buf_size);
|
||||
merged = (char *) util_xmalloc(buf_size);
|
||||
memset(merged, 0, buf_size);
|
||||
|
||||
buffer = (char*) util_xmalloc(buf_size);
|
||||
memset(buffer, 0, buf_size);
|
||||
buffer = (char *) util_xmalloc(buf_size);
|
||||
memset(buffer, 0, buf_size);
|
||||
|
||||
util_str_format(buffer, buf_size,
|
||||
"-------------- mod unlocks --------------\n" );
|
||||
util_str_format(
|
||||
buffer, buf_size, "-------------- mod unlocks --------------\n");
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
|
||||
for (uint32_t i = 0; i < 0x12; i++) {
|
||||
util_str_format(buffer, buf_size, "unkn0[%d]: %d\n", i, unlocks->unkn0[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 0x12; i++) {
|
||||
util_str_format(buffer, buf_size,
|
||||
"unkn0[%d]: %d\n",
|
||||
i,
|
||||
unlocks->unkn0[i]);
|
||||
util_str_format(buffer, buf_size, "display_va: %d\n", unlocks->display_va);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
util_str_format(buffer, buf_size,
|
||||
"display_va: %d\n",
|
||||
unlocks->display_va);
|
||||
for (uint32_t i = 0; i < 0x0D; i++) {
|
||||
util_str_format(buffer, buf_size, "unkn1[%d]: %d\n", i, unlocks->unkn1[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 0x0D; i++) {
|
||||
util_str_format(buffer, buf_size,
|
||||
"unkn1[%d]: %d\n",
|
||||
i,
|
||||
unlocks->unkn1[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 0x10; i++) {
|
||||
util_str_format(buffer, buf_size,
|
||||
"noteskins[%d]: %d\n",
|
||||
i,
|
||||
unlocks->noteskins[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 0x04; i++) {
|
||||
util_str_format(buffer, buf_size,
|
||||
"unkn2[%d]: %d\n",
|
||||
i,
|
||||
unlocks->unkn2[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 0x03; i++) {
|
||||
util_str_format(buffer, buf_size,
|
||||
"path[%d]: %d\n",
|
||||
i,
|
||||
unlocks->path[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 0x06; i++) {
|
||||
util_str_format(buffer, buf_size,
|
||||
"unkn3[%d]: %d\n",
|
||||
i,
|
||||
unlocks->unkn3[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
util_str_format(buffer, buf_size,
|
||||
"xj: %d\n",
|
||||
unlocks->xj);
|
||||
for (uint32_t i = 0; i < 0x10; i++) {
|
||||
util_str_format(
|
||||
buffer, buf_size, "noteskins[%d]: %d\n", i, unlocks->noteskins[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 0x02; i++) {
|
||||
util_str_format(buffer, buf_size,
|
||||
"system[%d]: %d\n",
|
||||
i,
|
||||
unlocks->system[i]);
|
||||
for (uint32_t i = 0; i < 0x04; i++) {
|
||||
util_str_format(buffer, buf_size, "unkn2[%d]: %d\n", i, unlocks->unkn2[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 0x08; i++) {
|
||||
util_str_format(buffer, buf_size,
|
||||
"rush[%d]: %d\n",
|
||||
i,
|
||||
unlocks->rush[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 0x1A; i++) {
|
||||
util_str_format(buffer, buf_size,
|
||||
"unkn4[%d]: %d\n",
|
||||
i,
|
||||
unlocks->unkn4[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
static char* fex_profile_save_mission_state_to_string(
|
||||
const struct asset_fex_usb_save_mission_state* state)
|
||||
{
|
||||
char* buffer;
|
||||
|
||||
buffer = (char*) util_xmalloc(128);
|
||||
memset(buffer, 0, 128);
|
||||
|
||||
util_str_format(buffer, 128,
|
||||
"-------------- mission state --------------\n"
|
||||
"quest_world_location: %X\n"
|
||||
"skill_up_zone_location: %X\n",
|
||||
state->quest_world_location,
|
||||
state->skill_up_zone_location);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
struct asset_fex_usb_save* asset_fex_usb_save_new(void)
|
||||
{
|
||||
return malloc(sizeof(struct asset_fex_usb_save));
|
||||
}
|
||||
|
||||
void asset_fex_usb_save_finalize(struct asset_fex_usb_save* save)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
char* asset_fex_usb_save_to_string(const struct asset_fex_usb_save* save)
|
||||
{
|
||||
char* header;
|
||||
char* player;
|
||||
char* mods;
|
||||
char* unlocks;
|
||||
char* mission_state;
|
||||
char* merged;
|
||||
char* merged2;
|
||||
|
||||
header = fex_profile_save_header_to_string(&save->header);
|
||||
player = fex_profile_save_player_to_string(&save->player);
|
||||
mods = fex_profile_save_mods_to_string(&save->mods);
|
||||
unlocks = fex_profile_save_mod_unlocks_to_string(&save->mod_unlocks);
|
||||
mission_state = fex_profile_save_mission_state_to_string(&save->mission_state);
|
||||
|
||||
merged = util_str_merge(header, player);
|
||||
merged2 = util_str_merge(merged, mods);
|
||||
free(merged);
|
||||
merged = util_str_merge(merged2, unlocks);
|
||||
free(merged2);
|
||||
merged2 = util_str_merge(merged, mission_state);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 0x03; i++) {
|
||||
util_str_format(buffer, buf_size, "path[%d]: %d\n", i, unlocks->path[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
free(header);
|
||||
free(player);
|
||||
free(mods);
|
||||
free(unlocks);
|
||||
free(mission_state);
|
||||
for (uint32_t i = 0; i < 0x06; i++) {
|
||||
util_str_format(buffer, buf_size, "unkn3[%d]: %d\n", i, unlocks->unkn3[i]);
|
||||
|
||||
return merged2;
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
util_str_format(buffer, buf_size, "xj: %d\n", unlocks->xj);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
|
||||
for (uint32_t i = 0; i < 0x02; i++) {
|
||||
util_str_format(
|
||||
buffer, buf_size, "system[%d]: %d\n", i, unlocks->system[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 0x08; i++) {
|
||||
util_str_format(buffer, buf_size, "rush[%d]: %d\n", i, unlocks->rush[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 0x1A; i++) {
|
||||
util_str_format(buffer, buf_size, "unkn4[%d]: %d\n", i, unlocks->unkn4[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
void asset_fex_usb_save_decrypt(uint8_t* buf, size_t len)
|
||||
static char *fex_profile_save_mission_state_to_string(
|
||||
const struct asset_fex_usb_save_mission_state *state)
|
||||
{
|
||||
for (size_t a = len - 1; a > 0; --a) {
|
||||
buf[a] = (buf[a] ^ buf[a - 1]) + ((a * 1234567) >> 8);
|
||||
}
|
||||
char *buffer;
|
||||
|
||||
buffer = (char *) util_xmalloc(128);
|
||||
memset(buffer, 0, 128);
|
||||
|
||||
util_str_format(
|
||||
buffer,
|
||||
128,
|
||||
"-------------- mission state --------------\n"
|
||||
"quest_world_location: %X\n"
|
||||
"skill_up_zone_location: %X\n",
|
||||
state->quest_world_location,
|
||||
state->skill_up_zone_location);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void asset_fex_usb_save_encrypt(uint8_t* buf, size_t len)
|
||||
struct asset_fex_usb_save *asset_fex_usb_save_new(void)
|
||||
{
|
||||
for (size_t a = 1; a < len; ++a) {
|
||||
buf[a] = (buf[a] - ((a * 1234567) >> 8)) ^ buf[a - 1];
|
||||
}
|
||||
return malloc(sizeof(struct asset_fex_usb_save));
|
||||
}
|
||||
|
||||
void asset_fex_usb_save_finalize(struct asset_fex_usb_save *save)
|
||||
{
|
||||
}
|
||||
|
||||
char *asset_fex_usb_save_to_string(const struct asset_fex_usb_save *save)
|
||||
{
|
||||
char *header;
|
||||
char *player;
|
||||
char *mods;
|
||||
char *unlocks;
|
||||
char *mission_state;
|
||||
char *merged;
|
||||
char *merged2;
|
||||
|
||||
header = fex_profile_save_header_to_string(&save->header);
|
||||
player = fex_profile_save_player_to_string(&save->player);
|
||||
mods = fex_profile_save_mods_to_string(&save->mods);
|
||||
unlocks = fex_profile_save_mod_unlocks_to_string(&save->mod_unlocks);
|
||||
mission_state =
|
||||
fex_profile_save_mission_state_to_string(&save->mission_state);
|
||||
|
||||
merged = util_str_merge(header, player);
|
||||
merged2 = util_str_merge(merged, mods);
|
||||
free(merged);
|
||||
merged = util_str_merge(merged2, unlocks);
|
||||
free(merged2);
|
||||
merged2 = util_str_merge(merged, mission_state);
|
||||
free(merged);
|
||||
|
||||
free(header);
|
||||
free(player);
|
||||
free(mods);
|
||||
free(unlocks);
|
||||
free(mission_state);
|
||||
|
||||
return merged2;
|
||||
}
|
||||
|
||||
void asset_fex_usb_save_decrypt(uint8_t *buf, size_t len)
|
||||
{
|
||||
for (size_t a = len - 1; a > 0; --a) {
|
||||
buf[a] = (buf[a] ^ buf[a - 1]) + ((a * 1234567) >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
void asset_fex_usb_save_encrypt(uint8_t *buf, size_t len)
|
||||
{
|
||||
for (size_t a = 1; a < len; ++a) {
|
||||
buf[a] = (buf[a] - ((a * 1234567) >> 8)) ^ buf[a - 1];
|
||||
}
|
||||
}
|
||||
+152
-152
@@ -5,187 +5,187 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
enum asset_fex_usb_save_noteskins {
|
||||
ASSET_FEX_USB_SAVE_SKIN_DEFAULT = 0x00,
|
||||
ASSET_FEX_USB_SAVE_SKIN_HANAFUDA = 0x01,
|
||||
ASSET_FEX_USB_SAVE_SKIN_CLASSIC = 0x02,
|
||||
ASSET_FEX_USB_SAVE_SKIN_CANDY = 0x03,
|
||||
ASSET_FEX_USB_SAVE_SKIN_PORING = 0x04,
|
||||
ASSET_FEX_USB_SAVE_SKIN_MUSICAL_NOTES = 0x05,
|
||||
ASSET_FEX_USB_SAVE_SKIN_CANON_D = 0x06,
|
||||
ASSET_FEX_USB_SAVE_SKIN_PLAYING_CARDS = 0x07,
|
||||
ASSET_FEX_USB_SAVE_SKIN_NX = 0x08,
|
||||
ASSET_FEX_USB_SAVE_SKIN_DIGNITY = 0x09,
|
||||
ASSET_FEX_USB_SAVE_SKIN_HORSE_HEAD = 0x0A,
|
||||
ASSET_FEX_USB_SAVE_SKIN_DOG = 0x0B,
|
||||
ASSET_FEX_USB_SAVE_SKIN_GIRL = 0x0C,
|
||||
ASSET_FEX_USB_SAVE_SKIN_FIRE = 0x0D,
|
||||
ASSET_FEX_USB_SAVE_SKIN_ICE = 0x0E,
|
||||
ASSET_FEX_USB_SAVE_SKIN_WIND = 0x0F,
|
||||
ASSET_FEX_USB_SAVE_SKIN_RED_DP = 0x10,
|
||||
ASSET_FEX_USB_SAVE_SKIN_BLUE_DP = 0x11,
|
||||
ASSET_FEX_USB_SAVE_SKIN_YELLOW_DP = 0x12,
|
||||
ASSET_FEX_USB_SAVE_SKIN_NXA = 0x13,
|
||||
ASSET_FEX_USB_SAVE_SKIN_NX2 = 0x14,
|
||||
ASSET_FEX_USB_SAVE_SKIN_ELECTRIC_FIESTA = 0x15,
|
||||
ASSET_FEX_USB_SAVE_SKIN_DRUM = 0x16,
|
||||
ASSET_FEX_USB_SAVE_SKIN_BULLET = 0x17,
|
||||
ASSET_FEX_USB_SAVE_SKIN_BLUE_DRUM = 0x18,
|
||||
ASSET_FEX_USB_SAVE_SKIN_RED_DRUM = 0x19,
|
||||
ASSET_FEX_USB_SAVE_SKIN_YELLOW_DRUM = 0x1A,
|
||||
ASSET_FEX_USB_SAVE_SKIN_WORLD_CUP = 0x1B,
|
||||
ASSET_FEX_USB_SAVE_SKIN_PREX3 = 0x1C,
|
||||
ASSET_FEX_USB_SAVE_SKIN_FIESTA_BASIC = 0x1D,
|
||||
ASSET_FEX_USB_SAVE_SKIN_DEFAULT = 0x00,
|
||||
ASSET_FEX_USB_SAVE_SKIN_HANAFUDA = 0x01,
|
||||
ASSET_FEX_USB_SAVE_SKIN_CLASSIC = 0x02,
|
||||
ASSET_FEX_USB_SAVE_SKIN_CANDY = 0x03,
|
||||
ASSET_FEX_USB_SAVE_SKIN_PORING = 0x04,
|
||||
ASSET_FEX_USB_SAVE_SKIN_MUSICAL_NOTES = 0x05,
|
||||
ASSET_FEX_USB_SAVE_SKIN_CANON_D = 0x06,
|
||||
ASSET_FEX_USB_SAVE_SKIN_PLAYING_CARDS = 0x07,
|
||||
ASSET_FEX_USB_SAVE_SKIN_NX = 0x08,
|
||||
ASSET_FEX_USB_SAVE_SKIN_DIGNITY = 0x09,
|
||||
ASSET_FEX_USB_SAVE_SKIN_HORSE_HEAD = 0x0A,
|
||||
ASSET_FEX_USB_SAVE_SKIN_DOG = 0x0B,
|
||||
ASSET_FEX_USB_SAVE_SKIN_GIRL = 0x0C,
|
||||
ASSET_FEX_USB_SAVE_SKIN_FIRE = 0x0D,
|
||||
ASSET_FEX_USB_SAVE_SKIN_ICE = 0x0E,
|
||||
ASSET_FEX_USB_SAVE_SKIN_WIND = 0x0F,
|
||||
ASSET_FEX_USB_SAVE_SKIN_RED_DP = 0x10,
|
||||
ASSET_FEX_USB_SAVE_SKIN_BLUE_DP = 0x11,
|
||||
ASSET_FEX_USB_SAVE_SKIN_YELLOW_DP = 0x12,
|
||||
ASSET_FEX_USB_SAVE_SKIN_NXA = 0x13,
|
||||
ASSET_FEX_USB_SAVE_SKIN_NX2 = 0x14,
|
||||
ASSET_FEX_USB_SAVE_SKIN_ELECTRIC_FIESTA = 0x15,
|
||||
ASSET_FEX_USB_SAVE_SKIN_DRUM = 0x16,
|
||||
ASSET_FEX_USB_SAVE_SKIN_BULLET = 0x17,
|
||||
ASSET_FEX_USB_SAVE_SKIN_BLUE_DRUM = 0x18,
|
||||
ASSET_FEX_USB_SAVE_SKIN_RED_DRUM = 0x19,
|
||||
ASSET_FEX_USB_SAVE_SKIN_YELLOW_DRUM = 0x1A,
|
||||
ASSET_FEX_USB_SAVE_SKIN_WORLD_CUP = 0x1B,
|
||||
ASSET_FEX_USB_SAVE_SKIN_PREX3 = 0x1C,
|
||||
ASSET_FEX_USB_SAVE_SKIN_FIESTA_BASIC = 0x1D,
|
||||
};
|
||||
|
||||
struct asset_fex_usb_save_header {
|
||||
/* 0x00 */
|
||||
uint32_t adler32;
|
||||
/* 0x04: NULL terminated */
|
||||
char usb_serial[0x40];
|
||||
/* 0x44: Deprecated from old games */
|
||||
uint32_t dongle_serial;
|
||||
/* 0x00 */
|
||||
uint32_t adler32;
|
||||
/* 0x04: NULL terminated */
|
||||
char usb_serial[0x40];
|
||||
/* 0x44: Deprecated from old games */
|
||||
uint32_t dongle_serial;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_fex_usb_save_player {
|
||||
/* 0x48 */
|
||||
uint32_t unkn;
|
||||
/* 0x4C */
|
||||
uint32_t unkn2;
|
||||
/* 0x50 */
|
||||
uint8_t avatar_id;
|
||||
/* 0x51: Range: 0x00 - 0x21 */
|
||||
uint8_t player_lvl;
|
||||
/* 0x52: PumBi sets it to 0xC4 */
|
||||
uint16_t unkn3;
|
||||
/* 0x54: NULL terminated */
|
||||
char player_id[8];
|
||||
/* 0x5C */
|
||||
uint32_t unkn4;
|
||||
/* 0x60 */
|
||||
uint32_t unkn5;
|
||||
/* 0x64: Each time you save, it inc. by 6... */
|
||||
uint32_t unkn6;
|
||||
/* 0x68 */
|
||||
uint32_t unkn7;
|
||||
/* 0x6C */
|
||||
uint32_t unkn8;
|
||||
/* 0x70 */
|
||||
uint32_t unkn9;
|
||||
/* 0x74 */
|
||||
uint32_t unkn10;
|
||||
/* 0x78 */
|
||||
uint32_t unkn11;
|
||||
/* 0x7C */
|
||||
uint32_t unkn12;
|
||||
/* 0x80 */
|
||||
uint32_t unkn13;
|
||||
/* 0x84 */
|
||||
uint32_t unkn14;
|
||||
/* 0x88 */
|
||||
uint32_t unkn15;
|
||||
/* 0x8C */
|
||||
uint32_t total_step;
|
||||
/* 0x90 */
|
||||
uint32_t play_count;
|
||||
/* 0x94 */
|
||||
uint32_t exp;
|
||||
/* 0x98 */
|
||||
uint32_t num_quest_world_passed;
|
||||
/* 0x9C */
|
||||
uint32_t unkn16;
|
||||
/* 0xA0 */
|
||||
uint32_t arcade_score;
|
||||
/* 0xA8 */
|
||||
uint32_t num_battle_wins;
|
||||
/* 0xAC */
|
||||
uint32_t num_battle_loss;
|
||||
/* 0xB0 */
|
||||
uint32_t num_battle_draw;
|
||||
/* 0x48 */
|
||||
uint32_t unkn;
|
||||
/* 0x4C */
|
||||
uint32_t unkn2;
|
||||
/* 0x50 */
|
||||
uint8_t avatar_id;
|
||||
/* 0x51: Range: 0x00 - 0x21 */
|
||||
uint8_t player_lvl;
|
||||
/* 0x52: PumBi sets it to 0xC4 */
|
||||
uint16_t unkn3;
|
||||
/* 0x54: NULL terminated */
|
||||
char player_id[8];
|
||||
/* 0x5C */
|
||||
uint32_t unkn4;
|
||||
/* 0x60 */
|
||||
uint32_t unkn5;
|
||||
/* 0x64: Each time you save, it inc. by 6... */
|
||||
uint32_t unkn6;
|
||||
/* 0x68 */
|
||||
uint32_t unkn7;
|
||||
/* 0x6C */
|
||||
uint32_t unkn8;
|
||||
/* 0x70 */
|
||||
uint32_t unkn9;
|
||||
/* 0x74 */
|
||||
uint32_t unkn10;
|
||||
/* 0x78 */
|
||||
uint32_t unkn11;
|
||||
/* 0x7C */
|
||||
uint32_t unkn12;
|
||||
/* 0x80 */
|
||||
uint32_t unkn13;
|
||||
/* 0x84 */
|
||||
uint32_t unkn14;
|
||||
/* 0x88 */
|
||||
uint32_t unkn15;
|
||||
/* 0x8C */
|
||||
uint32_t total_step;
|
||||
/* 0x90 */
|
||||
uint32_t play_count;
|
||||
/* 0x94 */
|
||||
uint32_t exp;
|
||||
/* 0x98 */
|
||||
uint32_t num_quest_world_passed;
|
||||
/* 0x9C */
|
||||
uint32_t unkn16;
|
||||
/* 0xA0 */
|
||||
uint32_t arcade_score;
|
||||
/* 0xA8 */
|
||||
uint32_t num_battle_wins;
|
||||
/* 0xAC */
|
||||
uint32_t num_battle_loss;
|
||||
/* 0xB0 */
|
||||
uint32_t num_battle_draw;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_fex_usb_save_player_mods {
|
||||
/* 0xB4: The first set of saved modifiers (see MOD_1 below) */
|
||||
uint32_t modifiers;
|
||||
/* 0xB8: If the +0.5x mod is enabled (boolean) */
|
||||
uint32_t half_speed_mod;
|
||||
/* 0xBC: Which noteskin is currently selected (see NOTE_S below) */
|
||||
uint32_t noteskin;
|
||||
/* 0xB4: The first set of saved modifiers (see MOD_1 below) */
|
||||
uint32_t modifiers;
|
||||
/* 0xB8: If the +0.5x mod is enabled (boolean) */
|
||||
uint32_t half_speed_mod;
|
||||
/* 0xBC: Which noteskin is currently selected (see NOTE_S below) */
|
||||
uint32_t noteskin;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_fex_usb_save_mod_unlocks {
|
||||
/* 0xC0: Unknown Unlocks Area */
|
||||
uint8_t unkn0[0x12];
|
||||
/* 0xD2: Boolean for unlocking VA Mod. */
|
||||
uint8_t display_va;
|
||||
/* 0xD3: Unknown Unlocks Area */
|
||||
uint8_t unkn1[0x0D];
|
||||
/* 0xE0: Array of bools - Which Noteskins are Unlocked. */
|
||||
uint8_t noteskins[0x10];
|
||||
/* 0xF0: Unknown Unlocks Area */
|
||||
uint8_t unkn2[0x04];
|
||||
/* 0xF4: Array of bools - Which Path Mods are Unlocked. */
|
||||
uint8_t path[0x03];
|
||||
/* 0xF7: Unknown Unlocks Area */
|
||||
uint8_t unkn3[0x06];
|
||||
/* 0xFE: Boolean for unlocking XJ */
|
||||
uint8_t xj;
|
||||
/* 0x100: Array of bools - Which System Mods are Unlocked. */
|
||||
uint8_t system[0x02];
|
||||
/* 0x102: Array of bools - Which Rush/NOT Modes are Unlocked. */
|
||||
uint8_t rush[0x08];
|
||||
/* 0x10A: Unknown Unlocks Area */
|
||||
uint8_t unkn4[0x1A];
|
||||
/* 0xC0: Unknown Unlocks Area */
|
||||
uint8_t unkn0[0x12];
|
||||
/* 0xD2: Boolean for unlocking VA Mod. */
|
||||
uint8_t display_va;
|
||||
/* 0xD3: Unknown Unlocks Area */
|
||||
uint8_t unkn1[0x0D];
|
||||
/* 0xE0: Array of bools - Which Noteskins are Unlocked. */
|
||||
uint8_t noteskins[0x10];
|
||||
/* 0xF0: Unknown Unlocks Area */
|
||||
uint8_t unkn2[0x04];
|
||||
/* 0xF4: Array of bools - Which Path Mods are Unlocked. */
|
||||
uint8_t path[0x03];
|
||||
/* 0xF7: Unknown Unlocks Area */
|
||||
uint8_t unkn3[0x06];
|
||||
/* 0xFE: Boolean for unlocking XJ */
|
||||
uint8_t xj;
|
||||
/* 0x100: Array of bools - Which System Mods are Unlocked. */
|
||||
uint8_t system[0x02];
|
||||
/* 0x102: Array of bools - Which Rush/NOT Modes are Unlocked. */
|
||||
uint8_t rush[0x08];
|
||||
/* 0x10A: Unknown Unlocks Area */
|
||||
uint8_t unkn4[0x1A];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_fex_usb_save_mission_state {
|
||||
/* 0x124 */
|
||||
uint32_t quest_world_location;
|
||||
/* 0x128 */
|
||||
uint32_t skill_up_zone_location;
|
||||
/* 0x124 */
|
||||
uint32_t quest_world_location;
|
||||
/* 0x128 */
|
||||
uint32_t skill_up_zone_location;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_fex_usb_save {
|
||||
struct asset_fex_usb_save_header header;
|
||||
struct asset_fex_usb_save_player player;
|
||||
struct asset_fex_usb_save_player_mods mods;
|
||||
struct asset_fex_usb_save_mod_unlocks mod_unlocks;
|
||||
struct asset_fex_usb_save_mission_state mission_state;
|
||||
struct asset_fex_usb_save_header header;
|
||||
struct asset_fex_usb_save_player player;
|
||||
struct asset_fex_usb_save_player_mods mods;
|
||||
struct asset_fex_usb_save_mod_unlocks mod_unlocks;
|
||||
struct asset_fex_usb_save_mission_state mission_state;
|
||||
|
||||
/* Not verified, yet. just notes from old tools */
|
||||
/* Not verified, yet. just notes from old tools */
|
||||
|
||||
/* 0x17AD (0x0A): Quest world inventory */
|
||||
/* 0x17B7: ??? */
|
||||
/* 0x17B8 (0x1C): Quest world warp unlocks */
|
||||
/* 0x17AD (0x0A): Quest world inventory */
|
||||
/* 0x17B7: ??? */
|
||||
/* 0x17B8 (0x1C): Quest world warp unlocks */
|
||||
|
||||
/* 0x17AC (0x11): QW inventory */
|
||||
/* 0x17AC (0x11): QW inventory */
|
||||
|
||||
/* 0x17D4 or 0x17D5 ? (0x14): favorites channel */
|
||||
/* 0x2E48 - 0x1A5EF: step chart blacklist */
|
||||
/* 0x2E48 - 0x1A5EF: step chart unlocks = blacklist */
|
||||
/* 0x17D4 or 0x17D5 ? (0x14): favorites channel */
|
||||
/* 0x2E48 - 0x1A5EF: step chart blacklist */
|
||||
/* 0x2E48 - 0x1A5EF: step chart unlocks = blacklist */
|
||||
|
||||
/* pumbi stepcharts */
|
||||
/* 0x6047: pumbi stepchart 1009 Level S15 */
|
||||
/* 0x6083 */
|
||||
/* 0x60AB */
|
||||
/* 0x647F */
|
||||
/* 0x64BB */
|
||||
/* 0x64CF */
|
||||
/* 0x650B */
|
||||
/* 0x6533 */
|
||||
/* 0x655B */
|
||||
/* 0x65AB */
|
||||
/* 0x660F */
|
||||
/* pumbi stepcharts */
|
||||
/* 0x6047: pumbi stepchart 1009 Level S15 */
|
||||
/* 0x6083 */
|
||||
/* 0x60AB */
|
||||
/* 0x647F */
|
||||
/* 0x64BB */
|
||||
/* 0x64CF */
|
||||
/* 0x650B */
|
||||
/* 0x6533 */
|
||||
/* 0x655B */
|
||||
/* 0x65AB */
|
||||
/* 0x660F */
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_fex_usb_save* asset_fex_usb_save_new(void);
|
||||
struct asset_fex_usb_save *asset_fex_usb_save_new(void);
|
||||
|
||||
// update checksum and prepare profile to get encrypted
|
||||
void asset_fex_usb_save_finalize(struct asset_fex_usb_save* save);
|
||||
void asset_fex_usb_save_finalize(struct asset_fex_usb_save *save);
|
||||
|
||||
char* asset_fex_usb_save_to_string(const struct asset_fex_usb_save* save);
|
||||
char *asset_fex_usb_save_to_string(const struct asset_fex_usb_save *save);
|
||||
|
||||
void asset_fex_usb_save_decrypt(uint8_t* buf, size_t len);
|
||||
void asset_fex_usb_save_decrypt(uint8_t *buf, size_t len);
|
||||
|
||||
void asset_fex_usb_save_encrypt(uint8_t* buf, size_t len);
|
||||
void asset_fex_usb_save_encrypt(uint8_t *buf, size_t len);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,94 +7,94 @@
|
||||
|
||||
#include "util.h"
|
||||
|
||||
struct asset_fex_usb_rank* asset_fex_usb_rank_load_from_file(const char* path,
|
||||
bool encrypted)
|
||||
struct asset_fex_usb_rank *
|
||||
asset_fex_usb_rank_load_from_file(const char *path, bool encrypted)
|
||||
{
|
||||
struct asset_fex_usb_rank* rank;
|
||||
size_t size;
|
||||
struct asset_fex_usb_rank *rank;
|
||||
size_t size;
|
||||
|
||||
if (!util_file_load(path, (void**) &rank, &size, false)) {
|
||||
log_error("Loading fex rank file %s failed", path);
|
||||
return NULL;
|
||||
}
|
||||
if (!util_file_load(path, (void **) &rank, &size, false)) {
|
||||
log_error("Loading fex rank file %s failed", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// if (size != sizeof(struct fex_profile_rank)) {
|
||||
// log_error("Invalid size of fex rank file %s: %d != %d", path, size,
|
||||
// sizeof(struct fex_profile_rank));
|
||||
// free(rank);
|
||||
// return NULL;
|
||||
// }
|
||||
// if (size != sizeof(struct fex_profile_rank)) {
|
||||
// log_error("Invalid size of fex rank file %s: %d != %d", path, size,
|
||||
// sizeof(struct fex_profile_rank));
|
||||
// free(rank);
|
||||
// return NULL;
|
||||
// }
|
||||
|
||||
if (encrypted) {
|
||||
asset_fex_usb_rank_decrypt((uint8_t*) rank, size);
|
||||
}
|
||||
if (encrypted) {
|
||||
asset_fex_usb_rank_decrypt((uint8_t *) rank, size);
|
||||
}
|
||||
|
||||
return rank;
|
||||
return rank;
|
||||
}
|
||||
|
||||
bool asset_fex_usb_rank_save_to_file(const char* path,
|
||||
const struct asset_fex_usb_rank* rank, bool encrypt)
|
||||
bool asset_fex_usb_rank_save_to_file(
|
||||
const char *path, const struct asset_fex_usb_rank *rank, bool encrypt)
|
||||
{
|
||||
struct asset_fex_usb_rank rank_enc;
|
||||
struct asset_fex_usb_rank rank_enc;
|
||||
|
||||
memcpy(&rank_enc, rank, sizeof(struct asset_fex_usb_rank));
|
||||
memcpy(&rank_enc, rank, sizeof(struct asset_fex_usb_rank));
|
||||
|
||||
if (encrypt) {
|
||||
asset_fex_usb_rank_encrypt((uint8_t*) &rank_enc,
|
||||
sizeof(struct asset_fex_usb_rank));
|
||||
}
|
||||
if (encrypt) {
|
||||
asset_fex_usb_rank_encrypt(
|
||||
(uint8_t *) &rank_enc, sizeof(struct asset_fex_usb_rank));
|
||||
}
|
||||
|
||||
if (!util_file_save(path, (void**) &rank_enc,
|
||||
sizeof(struct asset_fex_usb_rank))) {
|
||||
log_error("Storing fex rank data to %s failed", path);
|
||||
return false;
|
||||
}
|
||||
if (!util_file_save(
|
||||
path, (void **) &rank_enc, sizeof(struct asset_fex_usb_rank))) {
|
||||
log_error("Storing fex rank data to %s failed", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct asset_fex_usb_save* asset_fex_usb_save_load_from_file(const char* path,
|
||||
bool encrypted)
|
||||
struct asset_fex_usb_save *
|
||||
asset_fex_usb_save_load_from_file(const char *path, bool encrypted)
|
||||
{
|
||||
struct asset_fex_usb_save* save;
|
||||
size_t size;
|
||||
struct asset_fex_usb_save *save;
|
||||
size_t size;
|
||||
|
||||
if (!util_file_load(path, (void**) &save, &size, false)) {
|
||||
log_error("Loading fex save file %s failed", path);
|
||||
return NULL;
|
||||
}
|
||||
if (!util_file_load(path, (void **) &save, &size, false)) {
|
||||
log_error("Loading fex save file %s failed", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// if (size != sizeof(struct fex_profile_save)) {
|
||||
// log_error("Invalid size of fex save file %s: %d != %d", path, size,
|
||||
// sizeof(struct fex_profile_save));
|
||||
// free(save);
|
||||
// return NULL;
|
||||
// }
|
||||
// if (size != sizeof(struct fex_profile_save)) {
|
||||
// log_error("Invalid size of fex save file %s: %d != %d", path, size,
|
||||
// sizeof(struct fex_profile_save));
|
||||
// free(save);
|
||||
// return NULL;
|
||||
// }
|
||||
|
||||
if (encrypted) {
|
||||
asset_fex_usb_save_decrypt((uint8_t*) save, size);
|
||||
}
|
||||
if (encrypted) {
|
||||
asset_fex_usb_save_decrypt((uint8_t *) save, size);
|
||||
}
|
||||
|
||||
return save;
|
||||
return save;
|
||||
}
|
||||
|
||||
bool asset_fex_usb_save_save_to_file(const char* path,
|
||||
const struct asset_fex_usb_save* save, bool encrypt)
|
||||
bool asset_fex_usb_save_save_to_file(
|
||||
const char *path, const struct asset_fex_usb_save *save, bool encrypt)
|
||||
{
|
||||
struct asset_fex_usb_save save_enc;
|
||||
struct asset_fex_usb_save save_enc;
|
||||
|
||||
memcpy(&save_enc, save, sizeof(struct asset_fex_usb_save));
|
||||
memcpy(&save_enc, save, sizeof(struct asset_fex_usb_save));
|
||||
|
||||
if (encrypt) {
|
||||
asset_fex_usb_save_encrypt((uint8_t*) &save_enc,
|
||||
sizeof(struct asset_fex_usb_save));
|
||||
}
|
||||
if (encrypt) {
|
||||
asset_fex_usb_save_encrypt(
|
||||
(uint8_t *) &save_enc, sizeof(struct asset_fex_usb_save));
|
||||
}
|
||||
|
||||
if (!util_file_save(path, (const void*) &save_enc,
|
||||
sizeof(struct asset_fex_usb_save))) {
|
||||
log_error("Storing fex save data to %s failed", path);
|
||||
return false;
|
||||
}
|
||||
if (!util_file_save(
|
||||
path, (const void *) &save_enc, sizeof(struct asset_fex_usb_save))) {
|
||||
log_error("Storing fex save data to %s failed", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
@@ -7,15 +7,19 @@
|
||||
#include "usb-save.h"
|
||||
|
||||
// load from file and decrypt, returns decrypted struct
|
||||
struct asset_fex_usb_rank* asset_fex_usb_rank_load_from_file(const char* path, bool encrypted);
|
||||
struct asset_fex_usb_rank *
|
||||
asset_fex_usb_rank_load_from_file(const char *path, bool encrypted);
|
||||
|
||||
// takes decrypted rank data, encrypts it and writes it to file
|
||||
bool asset_fex_usb_rank_save_to_file(const char* path, const struct asset_fex_usb_rank* rank, bool encrypt);
|
||||
bool asset_fex_usb_rank_save_to_file(
|
||||
const char *path, const struct asset_fex_usb_rank *rank, bool encrypt);
|
||||
|
||||
// load from file and decrypt, returns decrypted struct
|
||||
struct asset_fex_usb_save* asset_fex_usb_save_load_from_file(const char* path, bool encrypted);
|
||||
struct asset_fex_usb_save *
|
||||
asset_fex_usb_save_load_from_file(const char *path, bool encrypted);
|
||||
|
||||
// takes decrypted save data, encrypts it and writes it to file
|
||||
bool asset_fex_usb_save_save_to_file(const char* path, const struct asset_fex_usb_save* save, bool encrypt);
|
||||
bool asset_fex_usb_save_save_to_file(
|
||||
const char *path, const struct asset_fex_usb_save *save, bool encrypt);
|
||||
|
||||
#endif
|
||||
@@ -9,146 +9,150 @@
|
||||
|
||||
#include "util/str.h"
|
||||
|
||||
int main(int argc, char** argv)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
char* rank_path;
|
||||
char* save_path;
|
||||
int ret;
|
||||
char *rank_path;
|
||||
char *save_path;
|
||||
|
||||
if (argc < 3) {
|
||||
printf("Usage: %s [cmd: new, dec, enc, dump] "
|
||||
"[path containing fiestaex_rank.bin fiestaex_save.bin]\n", argv[0]);
|
||||
return -1;
|
||||
if (argc < 3) {
|
||||
printf(
|
||||
"Usage: %s [cmd: new, dec, enc, dump] "
|
||||
"[path containing fiestaex_rank.bin fiestaex_save.bin]\n",
|
||||
argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
rank_path = util_str_merge(argv[2], "fiestaex_rank.bin");
|
||||
save_path = util_str_merge(argv[2], "fiestaex_save.bin");
|
||||
|
||||
if (!strcmp(argv[1], "new")) {
|
||||
struct asset_fex_usb_rank *rank = asset_fex_usb_rank_new();
|
||||
struct asset_fex_usb_save *save = asset_fex_usb_save_new();
|
||||
|
||||
asset_fex_usb_rank_finalize(rank);
|
||||
asset_fex_usb_save_finalize(save);
|
||||
|
||||
if (!asset_fex_usb_rank_save_to_file(rank_path, rank, true)) {
|
||||
fprintf(stderr, "Creating rank file %s failed\n", rank_path);
|
||||
ret = -2;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
if (!asset_fex_usb_save_save_to_file(save_path, save, true)) {
|
||||
fprintf(stderr, "Creating save file %s failed\n", save_path);
|
||||
ret = -3;
|
||||
}
|
||||
|
||||
rank_path = util_str_merge(argv[2], "fiestaex_rank.bin");
|
||||
save_path = util_str_merge(argv[2], "fiestaex_save.bin");
|
||||
free(rank);
|
||||
free(save);
|
||||
} else {
|
||||
struct asset_fex_usb_rank *rank;
|
||||
struct asset_fex_usb_save *save;
|
||||
bool encrypted;
|
||||
|
||||
if (!strcmp(argv[1], "new")) {
|
||||
struct asset_fex_usb_rank* rank = asset_fex_usb_rank_new();
|
||||
struct asset_fex_usb_save* save = asset_fex_usb_save_new();
|
||||
if (!strcmp(argv[1], "enc")) {
|
||||
char *tmp;
|
||||
|
||||
asset_fex_usb_rank_finalize(rank);
|
||||
asset_fex_usb_save_finalize(save);
|
||||
encrypted = false;
|
||||
|
||||
if (!asset_fex_usb_rank_save_to_file(rank_path, rank, true)) {
|
||||
fprintf(stderr, "Creating rank file %s failed\n", rank_path);
|
||||
ret = -2;
|
||||
}
|
||||
tmp = util_str_merge(rank_path, ".dec");
|
||||
free(rank_path);
|
||||
rank_path = tmp;
|
||||
|
||||
if (!asset_fex_usb_save_save_to_file(save_path, save, true)) {
|
||||
fprintf(stderr, "Creating save file %s failed\n", save_path);
|
||||
ret = -3;
|
||||
}
|
||||
|
||||
free(rank);
|
||||
free(save);
|
||||
tmp = util_str_merge(save_path, ".dec");
|
||||
free(save_path);
|
||||
save_path = tmp;
|
||||
} else {
|
||||
struct asset_fex_usb_rank* rank;
|
||||
struct asset_fex_usb_save* save;
|
||||
bool encrypted;
|
||||
|
||||
if (!strcmp(argv[1], "enc")) {
|
||||
char* tmp;
|
||||
|
||||
encrypted = false;
|
||||
|
||||
tmp = util_str_merge(rank_path, ".dec");
|
||||
free(rank_path);
|
||||
rank_path = tmp;
|
||||
|
||||
tmp = util_str_merge(save_path, ".dec");
|
||||
free(save_path);
|
||||
save_path = tmp;
|
||||
} else {
|
||||
encrypted = true;
|
||||
}
|
||||
|
||||
rank = asset_fex_usb_rank_load_from_file(rank_path, encrypted);
|
||||
save = asset_fex_usb_save_load_from_file(save_path, encrypted);
|
||||
|
||||
if (!rank) {
|
||||
fprintf(stderr, "Loading %s failed", rank_path);
|
||||
ret = -4;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!save) {
|
||||
fprintf(stderr, "Loading %s failed", save_path);
|
||||
ret = -5;
|
||||
free(rank);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "dec")) {
|
||||
char* rank_path_dec;
|
||||
char* save_path_dec;
|
||||
|
||||
rank_path_dec = util_str_merge(rank_path, ".dec");
|
||||
save_path_dec = util_str_merge(save_path, ".dec");
|
||||
|
||||
if (!asset_fex_usb_rank_save_to_file(rank_path_dec, rank, false)) {
|
||||
fprintf(stderr, "Saving decrypted rank file to %s failed\n",
|
||||
rank_path_dec);
|
||||
ret = -6;
|
||||
}
|
||||
|
||||
if (!asset_fex_usb_save_save_to_file(save_path_dec, save, false)) {
|
||||
fprintf(stderr, "Saving decrypted save file to %s failed\n",
|
||||
save_path_dec);
|
||||
ret = -7;
|
||||
}
|
||||
|
||||
free(rank_path_dec);
|
||||
free(save_path_dec);
|
||||
} else if (!strcmp(argv[1], "enc")) {
|
||||
char* rank_path_enc;
|
||||
char* save_path_enc;
|
||||
|
||||
rank_path_enc = util_str_merge(rank_path, ".enc");
|
||||
save_path_enc = util_str_merge(save_path, ".enc");
|
||||
|
||||
if (!asset_fex_usb_rank_save_to_file(rank_path_enc, rank, true)) {
|
||||
fprintf(stderr, "Saving encrypted rank file to %s failed\n",
|
||||
rank_path_enc);
|
||||
ret = -6;
|
||||
}
|
||||
|
||||
if (!asset_fex_usb_save_save_to_file(save_path_enc, save, true)) {
|
||||
fprintf(stderr, "Saving encrypted save file to %s failed\n",
|
||||
save_path_enc);
|
||||
ret = -7;
|
||||
}
|
||||
|
||||
free(rank_path_enc);
|
||||
free(save_path_enc);
|
||||
} else if (!strcmp(argv[1], "dump")) {
|
||||
char* rank_str;
|
||||
char* save_str;
|
||||
|
||||
rank_str = asset_fex_usb_rank_to_string(rank);
|
||||
save_str = asset_fex_usb_save_to_string(save);
|
||||
|
||||
printf("----------------- rank -----------------\n"
|
||||
"%s----------------- save -----------------\n%s",
|
||||
rank_str, save_str);
|
||||
|
||||
free(rank_str);
|
||||
free(save_str);
|
||||
} else {
|
||||
fprintf(stderr, "Unknown command %s\n", argv[1]);
|
||||
ret = -4;
|
||||
}
|
||||
|
||||
free(rank);
|
||||
free(save);
|
||||
encrypted = true;
|
||||
}
|
||||
|
||||
rank = asset_fex_usb_rank_load_from_file(rank_path, encrypted);
|
||||
save = asset_fex_usb_save_load_from_file(save_path, encrypted);
|
||||
|
||||
if (!rank) {
|
||||
fprintf(stderr, "Loading %s failed", rank_path);
|
||||
ret = -4;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!save) {
|
||||
fprintf(stderr, "Loading %s failed", save_path);
|
||||
ret = -5;
|
||||
free(rank);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "dec")) {
|
||||
char *rank_path_dec;
|
||||
char *save_path_dec;
|
||||
|
||||
rank_path_dec = util_str_merge(rank_path, ".dec");
|
||||
save_path_dec = util_str_merge(save_path, ".dec");
|
||||
|
||||
if (!asset_fex_usb_rank_save_to_file(rank_path_dec, rank, false)) {
|
||||
fprintf(
|
||||
stderr, "Saving decrypted rank file to %s failed\n", rank_path_dec);
|
||||
ret = -6;
|
||||
}
|
||||
|
||||
if (!asset_fex_usb_save_save_to_file(save_path_dec, save, false)) {
|
||||
fprintf(
|
||||
stderr, "Saving decrypted save file to %s failed\n", save_path_dec);
|
||||
ret = -7;
|
||||
}
|
||||
|
||||
free(rank_path_dec);
|
||||
free(save_path_dec);
|
||||
} else if (!strcmp(argv[1], "enc")) {
|
||||
char *rank_path_enc;
|
||||
char *save_path_enc;
|
||||
|
||||
rank_path_enc = util_str_merge(rank_path, ".enc");
|
||||
save_path_enc = util_str_merge(save_path, ".enc");
|
||||
|
||||
if (!asset_fex_usb_rank_save_to_file(rank_path_enc, rank, true)) {
|
||||
fprintf(
|
||||
stderr, "Saving encrypted rank file to %s failed\n", rank_path_enc);
|
||||
ret = -6;
|
||||
}
|
||||
|
||||
if (!asset_fex_usb_save_save_to_file(save_path_enc, save, true)) {
|
||||
fprintf(
|
||||
stderr, "Saving encrypted save file to %s failed\n", save_path_enc);
|
||||
ret = -7;
|
||||
}
|
||||
|
||||
free(rank_path_enc);
|
||||
free(save_path_enc);
|
||||
} else if (!strcmp(argv[1], "dump")) {
|
||||
char *rank_str;
|
||||
char *save_str;
|
||||
|
||||
rank_str = asset_fex_usb_rank_to_string(rank);
|
||||
save_str = asset_fex_usb_save_to_string(save);
|
||||
|
||||
printf(
|
||||
"----------------- rank -----------------\n"
|
||||
"%s----------------- save -----------------\n%s",
|
||||
rank_str,
|
||||
save_str);
|
||||
|
||||
free(rank_str);
|
||||
free(save_str);
|
||||
} else {
|
||||
fprintf(stderr, "Unknown command %s\n", argv[1]);
|
||||
ret = -4;
|
||||
}
|
||||
|
||||
free(rank);
|
||||
free(save);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(rank_path);
|
||||
free(save_path);
|
||||
free(rank_path);
|
||||
free(save_path);
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
@@ -3,36 +3,36 @@
|
||||
|
||||
/* Note: Version IDs must be sync with server code */
|
||||
enum asset_game_version {
|
||||
ASSET_GAME_VERSION_INVALID = 0,
|
||||
ASSET_GAME_VERSION_FIRST = 1,
|
||||
ASSET_GAME_VERSION_SECOND = 2,
|
||||
ASSET_GAME_VERSION_OBG = 3,
|
||||
ASSET_GAME_VERSION_OBG_SE = 4,
|
||||
ASSET_GAME_VERSION_THE_COLLECTION = 5,
|
||||
ASSET_GAME_VERSION_PERFECT_COLLECTION = 6,
|
||||
ASSET_GAME_VERSION_EXTRA = 7,
|
||||
ASSET_GAME_VERSION_PREMIERE_1 = 8,
|
||||
ASSET_GAME_VERSION_PREX_1 = 9,
|
||||
ASSET_GAME_VERSION_REBIRTH = 10,
|
||||
ASSET_GAME_VERSION_PREMIERE_2 = 11,
|
||||
ASSET_GAME_VERSION_PREX_2 = 12,
|
||||
ASSET_GAME_VERSION_PREMIERE_3 = 13,
|
||||
ASSET_GAME_VERSION_PREX_3 = 14,
|
||||
ASSET_GAME_VERSION_EXCEED = 15,
|
||||
ASSET_GAME_VERSION_EXCEED_2 = 16,
|
||||
ASSET_GAME_VERSION_ZERO = 17,
|
||||
ASSET_GAME_VERSION_NX = 18,
|
||||
ASSET_GAME_VERSION_PRO = 19,
|
||||
ASSET_GAME_VERSION_NX2 = 20,
|
||||
ASSET_GAME_VERSION_NXA = 21,
|
||||
ASSET_GAME_VERSION_FIESTA = 22,
|
||||
ASSET_GAME_VERSION_PRO2 = 23,
|
||||
ASSET_GAME_VERSION_FIESTA_EX = 24,
|
||||
ASSET_GAME_VERSION_FIESTA_2 = 25,
|
||||
ASSET_GAME_VERSION_INFINITY = 26,
|
||||
ASSET_GAME_VERSION_PRIME = 27,
|
||||
ASSET_GAME_VERSION_PRIME_2 = 28,
|
||||
ASSET_GAME_VERSION_XX = 29
|
||||
ASSET_GAME_VERSION_INVALID = 0,
|
||||
ASSET_GAME_VERSION_FIRST = 1,
|
||||
ASSET_GAME_VERSION_SECOND = 2,
|
||||
ASSET_GAME_VERSION_OBG = 3,
|
||||
ASSET_GAME_VERSION_OBG_SE = 4,
|
||||
ASSET_GAME_VERSION_THE_COLLECTION = 5,
|
||||
ASSET_GAME_VERSION_PERFECT_COLLECTION = 6,
|
||||
ASSET_GAME_VERSION_EXTRA = 7,
|
||||
ASSET_GAME_VERSION_PREMIERE_1 = 8,
|
||||
ASSET_GAME_VERSION_PREX_1 = 9,
|
||||
ASSET_GAME_VERSION_REBIRTH = 10,
|
||||
ASSET_GAME_VERSION_PREMIERE_2 = 11,
|
||||
ASSET_GAME_VERSION_PREX_2 = 12,
|
||||
ASSET_GAME_VERSION_PREMIERE_3 = 13,
|
||||
ASSET_GAME_VERSION_PREX_3 = 14,
|
||||
ASSET_GAME_VERSION_EXCEED = 15,
|
||||
ASSET_GAME_VERSION_EXCEED_2 = 16,
|
||||
ASSET_GAME_VERSION_ZERO = 17,
|
||||
ASSET_GAME_VERSION_NX = 18,
|
||||
ASSET_GAME_VERSION_PRO = 19,
|
||||
ASSET_GAME_VERSION_NX2 = 20,
|
||||
ASSET_GAME_VERSION_NXA = 21,
|
||||
ASSET_GAME_VERSION_FIESTA = 22,
|
||||
ASSET_GAME_VERSION_PRO2 = 23,
|
||||
ASSET_GAME_VERSION_FIESTA_EX = 24,
|
||||
ASSET_GAME_VERSION_FIESTA_2 = 25,
|
||||
ASSET_GAME_VERSION_INFINITY = 26,
|
||||
ASSET_GAME_VERSION_PRIME = 27,
|
||||
ASSET_GAME_VERSION_PRIME_2 = 28,
|
||||
ASSET_GAME_VERSION_XX = 29
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,64 +5,69 @@
|
||||
#include "util/adler32.h"
|
||||
#include "util/mem.h"
|
||||
|
||||
struct asset_nx_settings* asset_nx_settings_new(void)
|
||||
struct asset_nx_settings *asset_nx_settings_new(void)
|
||||
{
|
||||
struct asset_nx_settings* settings;
|
||||
struct asset_nx_settings *settings;
|
||||
|
||||
settings = util_xmalloc(sizeof(struct asset_nx_settings));
|
||||
settings = util_xmalloc(sizeof(struct asset_nx_settings));
|
||||
|
||||
memset(settings->ff_pad, 0xFF, sizeof(settings->ff_pad));
|
||||
memcpy(settings->ident, "NX10", 4);
|
||||
/* Updated using finalize */
|
||||
settings->adler32 = 0;
|
||||
settings->total_uptime = 0;
|
||||
settings->language = ASSET_NX_SETTINGS_LANG_ENG;
|
||||
memset(settings->song_play_count, 0, sizeof(uint32_t) * ASSET_NX_SETTINGS_MAX_SONGS);
|
||||
settings->game_option_default_station = ASSET_NX_SETTINGS_STATION_TRAIN;
|
||||
settings->game_mode = ASSET_NX_SETTINGS_GAME_MODE_NORMAL;
|
||||
settings->game_level = ASSET_NX_SETTINGS_LEVEL_NORMAL;
|
||||
settings->game_stage_break = ASSET_NX_SETTINGS_STAGE_BREAK_2ND;
|
||||
settings->game_demo_sound = 1;
|
||||
settings->game_show_help = 1;
|
||||
settings->game_mercy_ticket = 0;
|
||||
settings->game_score_per_ticket = 0;
|
||||
settings->coin_limit = 0;
|
||||
settings->coin1_setting = 1;
|
||||
settings->coin2_setting = 1;
|
||||
memset(settings->unknown_unlock_flags, 0, ASSET_NX_SETTINGS_NUM_UNLOCK_FLAGS);
|
||||
settings->unkn2 = 0x2A;
|
||||
settings->unkn3 = 0;
|
||||
settings->bookkeeping_coin1_total = 0;
|
||||
settings->bookkeeping_coin2_total = 0;
|
||||
settings->bookkeeping_service_total = 0;
|
||||
settings->bookkeeping_play_total = 0;
|
||||
settings->bookkeeping_faep21_play_count = 0;
|
||||
settings->bookkeeping_ticket_1 = 0;
|
||||
settings->bookkeeping_ticket_2 = 0;
|
||||
settings->region = 0xFF;
|
||||
memset(settings->censor_table, 0, ASSET_NX_SETTINGS_MAX_SONGS);
|
||||
memset(settings->ff_pad, 0xFF, sizeof(settings->ff_pad));
|
||||
memcpy(settings->ident, "NX10", 4);
|
||||
/* Updated using finalize */
|
||||
settings->adler32 = 0;
|
||||
settings->total_uptime = 0;
|
||||
settings->language = ASSET_NX_SETTINGS_LANG_ENG;
|
||||
memset(
|
||||
settings->song_play_count,
|
||||
0,
|
||||
sizeof(uint32_t) * ASSET_NX_SETTINGS_MAX_SONGS);
|
||||
settings->game_option_default_station = ASSET_NX_SETTINGS_STATION_TRAIN;
|
||||
settings->game_mode = ASSET_NX_SETTINGS_GAME_MODE_NORMAL;
|
||||
settings->game_level = ASSET_NX_SETTINGS_LEVEL_NORMAL;
|
||||
settings->game_stage_break = ASSET_NX_SETTINGS_STAGE_BREAK_2ND;
|
||||
settings->game_demo_sound = 1;
|
||||
settings->game_show_help = 1;
|
||||
settings->game_mercy_ticket = 0;
|
||||
settings->game_score_per_ticket = 0;
|
||||
settings->coin_limit = 0;
|
||||
settings->coin1_setting = 1;
|
||||
settings->coin2_setting = 1;
|
||||
memset(settings->unknown_unlock_flags, 0, ASSET_NX_SETTINGS_NUM_UNLOCK_FLAGS);
|
||||
settings->unkn2 = 0x2A;
|
||||
settings->unkn3 = 0;
|
||||
settings->bookkeeping_coin1_total = 0;
|
||||
settings->bookkeeping_coin2_total = 0;
|
||||
settings->bookkeeping_service_total = 0;
|
||||
settings->bookkeeping_play_total = 0;
|
||||
settings->bookkeeping_faep21_play_count = 0;
|
||||
settings->bookkeeping_ticket_1 = 0;
|
||||
settings->bookkeeping_ticket_2 = 0;
|
||||
settings->region = 0xFF;
|
||||
memset(settings->censor_table, 0, ASSET_NX_SETTINGS_MAX_SONGS);
|
||||
|
||||
return settings;
|
||||
return settings;
|
||||
}
|
||||
|
||||
void asset_nx_settings_finalize(struct asset_nx_settings* settings)
|
||||
void asset_nx_settings_finalize(struct asset_nx_settings *settings)
|
||||
{
|
||||
/* Seems odd, but they just checksum the game settings part...*/
|
||||
settings->adler32 = util_adler32_calc(1, (const uint8_t*) &settings->game_mode, 8);
|
||||
/* Seems odd, but they just checksum the game settings part...*/
|
||||
settings->adler32 =
|
||||
util_adler32_calc(1, (const uint8_t *) &settings->game_mode, 8);
|
||||
}
|
||||
|
||||
void asset_nx_settings_unlock_all(struct asset_nx_settings* settings)
|
||||
void asset_nx_settings_unlock_all(struct asset_nx_settings *settings)
|
||||
{
|
||||
/* FAEP 2-1 must be played at least 100 times to unlock FAEP 2-2 */
|
||||
settings->bookkeeping_faep21_play_count = 100;
|
||||
/* FAEP 2-1 must be played at least 100 times to unlock FAEP 2-2 */
|
||||
settings->bookkeeping_faep21_play_count = 100;
|
||||
|
||||
/* To unlock all world tour missions and special zone songs, set this to 20k.
|
||||
The first 10k unlock only the first half of the missions while another 10k unlocks the second half (wtf) */
|
||||
settings->bookkeeping_play_total = 20000;
|
||||
/* To unlock all world tour missions and special zone songs, set this to 20k.
|
||||
The first 10k unlock only the first half of the missions while another 10k
|
||||
unlocks the second half (wtf) */
|
||||
settings->bookkeeping_play_total = 20000;
|
||||
}
|
||||
|
||||
char* asset_nx_settings_to_string(const struct asset_nx_settings* settings)
|
||||
char *asset_nx_settings_to_string(const struct asset_nx_settings *settings)
|
||||
{
|
||||
// TODO
|
||||
return "";
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
@@ -8,94 +8,96 @@
|
||||
#define ASSET_NX_SETTINGS_NUM_UNLOCK_FLAGS 59
|
||||
|
||||
enum asset_nx_settings_language {
|
||||
ASSET_NX_SETTINGS_LANG_KOR = 0,
|
||||
ASSET_NX_SETTINGS_LANG_ENG = 1,
|
||||
ASSET_NX_SETTINGS_LANG_SP = 2,
|
||||
ASSET_NX_SETTINGS_LANG_CH = 3,
|
||||
ASSET_NX_SETTINGS_LANG_KOR = 0,
|
||||
ASSET_NX_SETTINGS_LANG_ENG = 1,
|
||||
ASSET_NX_SETTINGS_LANG_SP = 2,
|
||||
ASSET_NX_SETTINGS_LANG_CH = 3,
|
||||
};
|
||||
|
||||
enum asset_nx_settings_station {
|
||||
ASSET_NX_SETTINGS_STATION_TRAIN = 0,
|
||||
ASSET_NX_SETTINGS_STATION_ARCADE = 1,
|
||||
ASSET_NX_SETTINGS_STATION_WORLD = 2,
|
||||
ASSET_NX_SETTINGS_STATION_SPECIAL = 3,
|
||||
ASSET_NX_SETTINGS_STATION_TRAIN = 0,
|
||||
ASSET_NX_SETTINGS_STATION_ARCADE = 1,
|
||||
ASSET_NX_SETTINGS_STATION_WORLD = 2,
|
||||
ASSET_NX_SETTINGS_STATION_SPECIAL = 3,
|
||||
};
|
||||
|
||||
enum asset_nx_settings_game_mode {
|
||||
ASSET_NX_SETTINGS_GAME_MODE_NORMAL = 0,
|
||||
ASSET_NX_SETTINGS_GAME_MODE_EVENT = 1,
|
||||
ASSET_NX_SETTINGS_GAME_MODE_NORMAL = 0,
|
||||
ASSET_NX_SETTINGS_GAME_MODE_EVENT = 1,
|
||||
};
|
||||
|
||||
enum asset_nx_settings_level {
|
||||
ASSET_NX_SETTINGS_LEVEL_EASY = 0,
|
||||
ASSET_NX_SETTINGS_LEVEL_NORMAL = 1,
|
||||
ASSET_NX_SETTINGS_LEVEL_HARD = 2,
|
||||
ASSET_NX_SETTINGS_LEVEL_EASY = 0,
|
||||
ASSET_NX_SETTINGS_LEVEL_NORMAL = 1,
|
||||
ASSET_NX_SETTINGS_LEVEL_HARD = 2,
|
||||
};
|
||||
|
||||
enum asset_nx_settings_stage_break {
|
||||
ASSET_NX_SETTINGS_STAGE_BREAK_OFF = 0,
|
||||
ASSET_NX_SETTINGS_STAGE_BREAK_1ST = 1,
|
||||
ASSET_NX_SETTINGS_STAGE_BREAK_2ND = 2,
|
||||
ASSET_NX_SETTINGS_STAGE_BREAK_3RD = 3,
|
||||
ASSET_NX_SETTINGS_STAGE_BREAK_4TH = 4,
|
||||
ASSET_NX_SETTINGS_STAGE_BREAK_OFF = 0,
|
||||
ASSET_NX_SETTINGS_STAGE_BREAK_1ST = 1,
|
||||
ASSET_NX_SETTINGS_STAGE_BREAK_2ND = 2,
|
||||
ASSET_NX_SETTINGS_STAGE_BREAK_3RD = 3,
|
||||
ASSET_NX_SETTINGS_STAGE_BREAK_4TH = 4,
|
||||
};
|
||||
|
||||
struct asset_nx_settings {
|
||||
/* Padding to fill up to 4k EEPROM legacy size */
|
||||
uint8_t ff_pad[0xB9D];
|
||||
/* NX10 */
|
||||
char ident[4];
|
||||
uint32_t adler32;
|
||||
uint32_t total_uptime;
|
||||
uint8_t language;
|
||||
uint32_t song_play_count[ASSET_NX_SETTINGS_MAX_SONGS];
|
||||
uint32_t game_option_default_station;
|
||||
uint8_t game_mode;
|
||||
uint8_t game_level;
|
||||
uint8_t game_stage_break;
|
||||
/* 0 off, 1 on */
|
||||
uint8_t game_demo_sound;
|
||||
/* 0 off, 1 on */
|
||||
uint8_t game_show_help;
|
||||
/* 0 off, 1 on */
|
||||
uint8_t game_mercy_ticket;
|
||||
/* 0 off, 1 - 6 for score */
|
||||
uint8_t game_score_per_ticket;
|
||||
/* 0 none */
|
||||
uint8_t coin_limit; // 0 none
|
||||
/* 0 freeplay */
|
||||
uint8_t coin1_setting;
|
||||
/* 0 freeplay */
|
||||
uint8_t coin2_setting;
|
||||
/* Unlock flags for world tour missions? setting them to 1 doesn't unlock anything.
|
||||
64 missions total, 55 unlock flags, 0 = locked, 1 = unlocked */
|
||||
uint8_t unknown_unlock_flags[ASSET_NX_SETTINGS_NUM_UNLOCK_FLAGS];
|
||||
/* Default value 0x2A */
|
||||
uint32_t unkn2;
|
||||
uint32_t unkn3;
|
||||
uint32_t bookkeeping_coin1_total;
|
||||
uint32_t bookkeeping_coin2_total;
|
||||
uint32_t bookkeeping_service_total;
|
||||
uint32_t bookkeeping_play_total;
|
||||
/* Separate counter for FAEP 2-1 play counts. Once this hits 100, FAEP 2-2 is unlocked in arcade station */
|
||||
uint32_t bookkeeping_faep21_play_count;
|
||||
uint32_t bookkeeping_ticket_1;
|
||||
uint32_t bookkeeping_ticket_2;
|
||||
/* FF -> not used, censoring globally disabled. unused feature though */
|
||||
uint8_t region;
|
||||
/* 0 = censoring of song off */
|
||||
uint8_t censor_table[ASSET_NX_SETTINGS_MAX_SONGS];
|
||||
/* Padding to fill up to 4k EEPROM legacy size */
|
||||
uint8_t ff_pad[0xB9D];
|
||||
/* NX10 */
|
||||
char ident[4];
|
||||
uint32_t adler32;
|
||||
uint32_t total_uptime;
|
||||
uint8_t language;
|
||||
uint32_t song_play_count[ASSET_NX_SETTINGS_MAX_SONGS];
|
||||
uint32_t game_option_default_station;
|
||||
uint8_t game_mode;
|
||||
uint8_t game_level;
|
||||
uint8_t game_stage_break;
|
||||
/* 0 off, 1 on */
|
||||
uint8_t game_demo_sound;
|
||||
/* 0 off, 1 on */
|
||||
uint8_t game_show_help;
|
||||
/* 0 off, 1 on */
|
||||
uint8_t game_mercy_ticket;
|
||||
/* 0 off, 1 - 6 for score */
|
||||
uint8_t game_score_per_ticket;
|
||||
/* 0 none */
|
||||
uint8_t coin_limit; // 0 none
|
||||
/* 0 freeplay */
|
||||
uint8_t coin1_setting;
|
||||
/* 0 freeplay */
|
||||
uint8_t coin2_setting;
|
||||
/* Unlock flags for world tour missions? setting them to 1 doesn't unlock
|
||||
anything. 64 missions total, 55 unlock flags, 0 = locked, 1 = unlocked */
|
||||
uint8_t unknown_unlock_flags[ASSET_NX_SETTINGS_NUM_UNLOCK_FLAGS];
|
||||
/* Default value 0x2A */
|
||||
uint32_t unkn2;
|
||||
uint32_t unkn3;
|
||||
uint32_t bookkeeping_coin1_total;
|
||||
uint32_t bookkeeping_coin2_total;
|
||||
uint32_t bookkeeping_service_total;
|
||||
uint32_t bookkeeping_play_total;
|
||||
/* Separate counter for FAEP 2-1 play counts. Once this hits 100, FAEP 2-2 is
|
||||
* unlocked in arcade station */
|
||||
uint32_t bookkeeping_faep21_play_count;
|
||||
uint32_t bookkeeping_ticket_1;
|
||||
uint32_t bookkeeping_ticket_2;
|
||||
/* FF -> not used, censoring globally disabled. unused feature though */
|
||||
uint8_t region;
|
||||
/* 0 = censoring of song off */
|
||||
uint8_t censor_table[ASSET_NX_SETTINGS_MAX_SONGS];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_nx_settings* asset_nx_settings_new(void);
|
||||
struct asset_nx_settings *asset_nx_settings_new(void);
|
||||
|
||||
// update checksum
|
||||
void asset_nx_settings_finalize(struct asset_nx_settings* settings);
|
||||
void asset_nx_settings_finalize(struct asset_nx_settings *settings);
|
||||
|
||||
// unlocks FAEP 2-2 by setting the play count to 100
|
||||
// and sets all missions cleared to unlock special stage songs and other missions
|
||||
void asset_nx_settings_unlock_all(struct asset_nx_settings* settings);
|
||||
// and sets all missions cleared to unlock special stage songs and other
|
||||
// missions
|
||||
void asset_nx_settings_unlock_all(struct asset_nx_settings *settings);
|
||||
|
||||
char* asset_nx_settings_to_string(const struct asset_nx_settings* settings);
|
||||
char *asset_nx_settings_to_string(const struct asset_nx_settings *settings);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,31 +5,38 @@
|
||||
#include "util/fs.h"
|
||||
#include "util/log.h"
|
||||
|
||||
struct asset_nx_settings* asset_nx_util_load_settings_from_file(const char* path)
|
||||
struct asset_nx_settings *
|
||||
asset_nx_util_load_settings_from_file(const char *path)
|
||||
{
|
||||
struct asset_nx_settings* settings;
|
||||
size_t size;
|
||||
struct asset_nx_settings *settings;
|
||||
size_t size;
|
||||
|
||||
if (!util_file_load(path, (void**) &settings, &size, false)) {
|
||||
log_error("Loading nx setting file %s failed", path);
|
||||
return NULL;
|
||||
}
|
||||
if (!util_file_load(path, (void **) &settings, &size, false)) {
|
||||
log_error("Loading nx setting file %s failed", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size != sizeof(struct asset_nx_settings)) {
|
||||
log_error("Invalid size of nx setting file %s: %d != %d", path, size, sizeof(struct asset_nx_settings));
|
||||
free(settings);
|
||||
return NULL;
|
||||
}
|
||||
if (size != sizeof(struct asset_nx_settings)) {
|
||||
log_error(
|
||||
"Invalid size of nx setting file %s: %d != %d",
|
||||
path,
|
||||
size,
|
||||
sizeof(struct asset_nx_settings));
|
||||
free(settings);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return settings;
|
||||
return settings;
|
||||
}
|
||||
|
||||
bool asset_nx_util_save_settings_to_file(const char* path, const struct asset_nx_settings* settings)
|
||||
bool asset_nx_util_save_settings_to_file(
|
||||
const char *path, const struct asset_nx_settings *settings)
|
||||
{
|
||||
if (!util_file_save(path, (void**) settings, sizeof(struct asset_nx_settings))) {
|
||||
log_error("Storing nx settings data to %s failed", path);
|
||||
return false;
|
||||
}
|
||||
if (!util_file_save(
|
||||
path, (void **) settings, sizeof(struct asset_nx_settings))) {
|
||||
log_error("Storing nx settings data to %s failed", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
@@ -5,8 +5,10 @@
|
||||
|
||||
#include "asset/nx/lib/settings.h"
|
||||
|
||||
struct asset_nx_settings* asset_nx_util_load_settings_from_file(const char* path);
|
||||
struct asset_nx_settings *
|
||||
asset_nx_util_load_settings_from_file(const char *path);
|
||||
|
||||
bool asset_nx_util_save_settings_to_file(const char* path, const struct asset_nx_settings* settings);
|
||||
bool asset_nx_util_save_settings_to_file(
|
||||
const char *path, const struct asset_nx_settings *settings);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,81 +8,84 @@
|
||||
#include "asset/nx/lib/settings.h"
|
||||
#include "asset/nx/lib/util.h"
|
||||
|
||||
static int main_settings(char* cmd, char* file);
|
||||
static int main_settings(char *cmd, char *file);
|
||||
|
||||
int main(int argc, char** argv)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
char* cmd;
|
||||
char* type;
|
||||
char* file;
|
||||
int ret;
|
||||
char *cmd;
|
||||
char *type;
|
||||
char *file;
|
||||
|
||||
if (argc < 4) {
|
||||
printf("Usage: %s [cmd: new, dump, unlock] [type: ini, mrank, rank] [file]\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
if (argc < 4) {
|
||||
printf(
|
||||
"Usage: %s [cmd: new, dump, unlock] [type: ini, mrank, rank] [file]\n",
|
||||
argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cmd = argv[1];
|
||||
type = argv[2];
|
||||
file = argv[3];
|
||||
cmd = argv[1];
|
||||
type = argv[2];
|
||||
file = argv[3];
|
||||
|
||||
if (!strcmp(type, "ini")) {
|
||||
ret = main_settings(cmd, file);
|
||||
} else {
|
||||
fprintf(stderr, "Unknown file type %s\n", type);
|
||||
ret = -1;
|
||||
}
|
||||
if (!strcmp(type, "ini")) {
|
||||
ret = main_settings(cmd, file);
|
||||
} else {
|
||||
fprintf(stderr, "Unknown file type %s\n", type);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int main_settings(char* cmd, char* file)
|
||||
static int main_settings(char *cmd, char *file)
|
||||
{
|
||||
int ret;
|
||||
int ret;
|
||||
|
||||
ret = 0;
|
||||
ret = 0;
|
||||
|
||||
if (!strcmp(cmd, "new")) {
|
||||
struct asset_nx_settings* settings = asset_nx_settings_new();
|
||||
if (!strcmp(cmd, "new")) {
|
||||
struct asset_nx_settings *settings = asset_nx_settings_new();
|
||||
|
||||
asset_nx_settings_finalize(settings);
|
||||
asset_nx_settings_finalize(settings);
|
||||
|
||||
if (!asset_nx_util_save_settings_to_file(file, settings)) {
|
||||
fprintf(stderr, "Creating nx settings file %s failed\n", file);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
free(settings);
|
||||
} else {
|
||||
struct asset_nx_settings* settings = asset_nx_util_load_settings_from_file(file);
|
||||
|
||||
if (!settings) {
|
||||
fprintf(stderr, "Loading %s failed", file);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (!strcmp(cmd, "dump")) {
|
||||
char* str = asset_nx_settings_to_string(settings);
|
||||
|
||||
printf("----------------- settings -----------------\n%s\n", str);
|
||||
|
||||
free(str);
|
||||
} else if (!strcmp(cmd, "unlock")) {
|
||||
asset_nx_settings_unlock_all(settings);
|
||||
|
||||
asset_nx_settings_finalize(settings);
|
||||
|
||||
if (!asset_nx_util_save_settings_to_file(file, settings)) {
|
||||
fprintf(stderr, "Saving nx settings file %s failed\n", file);
|
||||
ret = -1;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Unknown command %s\n", cmd);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
free(settings);
|
||||
if (!asset_nx_util_save_settings_to_file(file, settings)) {
|
||||
fprintf(stderr, "Creating nx settings file %s failed\n", file);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
free(settings);
|
||||
} else {
|
||||
struct asset_nx_settings *settings =
|
||||
asset_nx_util_load_settings_from_file(file);
|
||||
|
||||
if (!settings) {
|
||||
fprintf(stderr, "Loading %s failed", file);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (!strcmp(cmd, "dump")) {
|
||||
char *str = asset_nx_settings_to_string(settings);
|
||||
|
||||
printf("----------------- settings -----------------\n%s\n", str);
|
||||
|
||||
free(str);
|
||||
} else if (!strcmp(cmd, "unlock")) {
|
||||
asset_nx_settings_unlock_all(settings);
|
||||
|
||||
asset_nx_settings_finalize(settings);
|
||||
|
||||
if (!asset_nx_util_save_settings_to_file(file, settings)) {
|
||||
fprintf(stderr, "Saving nx settings file %s failed\n", file);
|
||||
ret = -1;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Unknown command %s\n", cmd);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
free(settings);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -6,88 +6,93 @@
|
||||
|
||||
#include "usb-rank.h"
|
||||
|
||||
struct asset_nx2_usb_rank* asset_nx2_usb_rank_new(void)
|
||||
struct asset_nx2_usb_rank *asset_nx2_usb_rank_new(void)
|
||||
{
|
||||
struct asset_nx2_usb_rank* rank;
|
||||
struct asset_nx2_usb_rank *rank;
|
||||
|
||||
rank = (struct asset_nx2_usb_rank*)
|
||||
util_xmalloc(sizeof(struct asset_nx2_usb_rank));
|
||||
rank = (struct asset_nx2_usb_rank *) util_xmalloc(
|
||||
sizeof(struct asset_nx2_usb_rank));
|
||||
|
||||
memset(rank, 0, sizeof(struct asset_nx2_usb_rank));
|
||||
memset(rank, 0, sizeof(struct asset_nx2_usb_rank));
|
||||
|
||||
return rank;
|
||||
return rank;
|
||||
}
|
||||
|
||||
void asset_nx2_usb_rank_finalize(struct asset_nx2_usb_rank* rank)
|
||||
void asset_nx2_usb_rank_finalize(struct asset_nx2_usb_rank *rank)
|
||||
{
|
||||
rank->adler32 = util_adler32_calc(1, ((const uint8_t*) rank) + 4,
|
||||
sizeof(struct asset_nx2_usb_rank) - 4);
|
||||
rank->adler32 = util_adler32_calc(
|
||||
1, ((const uint8_t *) rank) + 4, sizeof(struct asset_nx2_usb_rank) - 4);
|
||||
}
|
||||
|
||||
char* asset_nx2_usb_rank_to_string(const struct asset_nx2_usb_rank* rank)
|
||||
char *asset_nx2_usb_rank_to_string(const struct asset_nx2_usb_rank *rank)
|
||||
{
|
||||
char* buffer;
|
||||
char* buffer2;
|
||||
char* merged;
|
||||
char *buffer;
|
||||
char *buffer2;
|
||||
char *merged;
|
||||
|
||||
buffer = (char*) util_xmalloc(128);
|
||||
memset(buffer, 0, 128);
|
||||
buffer = (char *) util_xmalloc(128);
|
||||
memset(buffer, 0, 128);
|
||||
|
||||
util_str_format(buffer, 128,
|
||||
"adler32: 0x%X\n"
|
||||
"num_rankings: %d\n"
|
||||
"ranking entries:\n",
|
||||
rank->adler32,
|
||||
rank->num_rankings);
|
||||
util_str_format(
|
||||
buffer,
|
||||
128,
|
||||
"adler32: 0x%X\n"
|
||||
"num_rankings: %d\n"
|
||||
"ranking entries:\n",
|
||||
rank->adler32,
|
||||
rank->num_rankings);
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NX2_USB_RANK_MAX_RANK_ENTRIES; i++) {
|
||||
for (uint32_t i = 0; i < ASSET_NX2_USB_RANK_MAX_RANK_ENTRIES; i++) {
|
||||
|
||||
for (uint32_t j = 0; j < ASSET_NX2_USB_RANK_MAX_STAGES; j++) {
|
||||
buffer2 = (char*) util_xmalloc(512);
|
||||
memset(buffer2, 0, 512);
|
||||
for (uint32_t j = 0; j < ASSET_NX2_USB_RANK_MAX_STAGES; j++) {
|
||||
buffer2 = (char *) util_xmalloc(512);
|
||||
memset(buffer2, 0, 512);
|
||||
|
||||
util_str_format(buffer2, 512,
|
||||
"%d/%d:\n"
|
||||
"game_mode: %d\n"
|
||||
"play_order: %d\n"
|
||||
"play_score: %d\n"
|
||||
"grade: %d\n"
|
||||
"mileage: %d\n"
|
||||
"play_time: %f\n"
|
||||
"kcal: %f\n"
|
||||
"v02: %f\n",
|
||||
i, j,
|
||||
rank->entries[i][j].game_mode,
|
||||
rank->entries[i][j].play_order,
|
||||
rank->entries[i][j].play_score,
|
||||
rank->entries[i][j].grade,
|
||||
rank->entries[i][j].mileage,
|
||||
rank->entries[i][j].play_time,
|
||||
rank->entries[i][j].kcal,
|
||||
rank->entries[i][j].v02);
|
||||
util_str_format(
|
||||
buffer2,
|
||||
512,
|
||||
"%d/%d:\n"
|
||||
"game_mode: %d\n"
|
||||
"play_order: %d\n"
|
||||
"play_score: %d\n"
|
||||
"grade: %d\n"
|
||||
"mileage: %d\n"
|
||||
"play_time: %f\n"
|
||||
"kcal: %f\n"
|
||||
"v02: %f\n",
|
||||
i,
|
||||
j,
|
||||
rank->entries[i][j].game_mode,
|
||||
rank->entries[i][j].play_order,
|
||||
rank->entries[i][j].play_score,
|
||||
rank->entries[i][j].grade,
|
||||
rank->entries[i][j].mileage,
|
||||
rank->entries[i][j].play_time,
|
||||
rank->entries[i][j].kcal,
|
||||
rank->entries[i][j].v02);
|
||||
|
||||
merged = util_str_merge(buffer, buffer2);
|
||||
merged = util_str_merge(buffer, buffer2);
|
||||
|
||||
free(buffer);
|
||||
free(buffer2);
|
||||
free(buffer);
|
||||
free(buffer2);
|
||||
|
||||
buffer = merged;
|
||||
}
|
||||
buffer = merged;
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void asset_nx2_usb_rank_decrypt(uint8_t* buf, size_t len)
|
||||
void asset_nx2_usb_rank_decrypt(uint8_t *buf, size_t len)
|
||||
{
|
||||
for (size_t a = len - 1; a > 0; --a) {
|
||||
buf[a] = (buf[a] ^ buf[a - 1]) + ((a * 1234567) >> 8);
|
||||
}
|
||||
for (size_t a = len - 1; a > 0; --a) {
|
||||
buf[a] = (buf[a] ^ buf[a - 1]) + ((a * 1234567) >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
void asset_nx2_usb_rank_encrypt(uint8_t* buf, size_t len)
|
||||
void asset_nx2_usb_rank_encrypt(uint8_t *buf, size_t len)
|
||||
{
|
||||
for (size_t a = 1; a < len; ++a) {
|
||||
buf[a] = (buf[a] - ((a * 1234567) >> 8)) ^ buf[a - 1];
|
||||
}
|
||||
for (size_t a = 1; a < len; ++a) {
|
||||
buf[a] = (buf[a] - ((a * 1234567) >> 8)) ^ buf[a - 1];
|
||||
}
|
||||
}
|
||||
@@ -7,36 +7,37 @@
|
||||
#define ASSET_NX2_USB_RANK_SIZE 12296
|
||||
|
||||
enum asset_nx2_usb_rank_sizes {
|
||||
ASSET_NX2_USB_RANK_MAX_STAGES = 3,
|
||||
ASSET_NX2_USB_RANK_MAX_RANK_ENTRIES = 128,
|
||||
ASSET_NX2_USB_RANK_MAX_STAGES = 3,
|
||||
ASSET_NX2_USB_RANK_MAX_RANK_ENTRIES = 128,
|
||||
};
|
||||
|
||||
struct asset_nx2_usb_rank_entry {
|
||||
int32_t game_mode;
|
||||
int32_t play_order;
|
||||
int32_t play_score;
|
||||
int32_t grade;
|
||||
int32_t mileage;
|
||||
float play_time;
|
||||
float kcal;
|
||||
float v02;
|
||||
int32_t game_mode;
|
||||
int32_t play_order;
|
||||
int32_t play_score;
|
||||
int32_t grade;
|
||||
int32_t mileage;
|
||||
float play_time;
|
||||
float kcal;
|
||||
float v02;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_nx2_usb_rank {
|
||||
uint32_t adler32;
|
||||
uint32_t num_rankings;
|
||||
struct asset_nx2_usb_rank_entry entries[ASSET_NX2_USB_RANK_MAX_RANK_ENTRIES][ASSET_NX2_USB_RANK_MAX_STAGES];
|
||||
uint32_t adler32;
|
||||
uint32_t num_rankings;
|
||||
struct asset_nx2_usb_rank_entry entries[ASSET_NX2_USB_RANK_MAX_RANK_ENTRIES]
|
||||
[ASSET_NX2_USB_RANK_MAX_STAGES];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_nx2_usb_rank* asset_nx2_usb_rank_new(void);
|
||||
struct asset_nx2_usb_rank *asset_nx2_usb_rank_new(void);
|
||||
|
||||
// update checksum and prepare profile to get encrypted
|
||||
void asset_nx2_usb_rank_finalize(struct asset_nx2_usb_rank* rank);
|
||||
void asset_nx2_usb_rank_finalize(struct asset_nx2_usb_rank *rank);
|
||||
|
||||
char* asset_nx2_usb_rank_to_string(const struct asset_nx2_usb_rank* rank);
|
||||
char *asset_nx2_usb_rank_to_string(const struct asset_nx2_usb_rank *rank);
|
||||
|
||||
void asset_nx2_usb_rank_decrypt(uint8_t* buf, size_t len);
|
||||
void asset_nx2_usb_rank_decrypt(uint8_t *buf, size_t len);
|
||||
|
||||
void asset_nx2_usb_rank_encrypt(uint8_t* buf, size_t len);
|
||||
void asset_nx2_usb_rank_encrypt(uint8_t *buf, size_t len);
|
||||
|
||||
#endif
|
||||
+330
-301
@@ -8,363 +8,392 @@
|
||||
|
||||
#include "usb-save.h"
|
||||
|
||||
static char* asset_nx2_usb_save_time_to_string(
|
||||
const struct asset_nx2_usb_save_time* time)
|
||||
static char *
|
||||
asset_nx2_usb_save_time_to_string(const struct asset_nx2_usb_save_time *time)
|
||||
{
|
||||
char* buffer;
|
||||
char *buffer;
|
||||
|
||||
buffer = (char*) util_xmalloc(128);
|
||||
memset(buffer, 0, 128);
|
||||
buffer = (char *) util_xmalloc(128);
|
||||
memset(buffer, 0, 128);
|
||||
|
||||
util_str_format(buffer, 128,
|
||||
"year: %d\n"
|
||||
"month: %d\n"
|
||||
"day: %d\n"
|
||||
"hour: %d\n"
|
||||
"min: %d\n"
|
||||
"ms: %d\n",
|
||||
time->year,
|
||||
time->month,
|
||||
time->day,
|
||||
time->hour,
|
||||
time->min,
|
||||
time->ms);
|
||||
util_str_format(
|
||||
buffer,
|
||||
128,
|
||||
"year: %d\n"
|
||||
"month: %d\n"
|
||||
"day: %d\n"
|
||||
"hour: %d\n"
|
||||
"min: %d\n"
|
||||
"ms: %d\n",
|
||||
time->year,
|
||||
time->month,
|
||||
time->day,
|
||||
time->hour,
|
||||
time->min,
|
||||
time->ms);
|
||||
|
||||
return buffer;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static char* asset_nx2_usb_save_review_to_string(
|
||||
const struct asset_nx2_usb_save_review* review)
|
||||
static char *asset_nx2_usb_save_review_to_string(
|
||||
const struct asset_nx2_usb_save_review *review)
|
||||
{
|
||||
char* buffer;
|
||||
char* land;
|
||||
char* mission;
|
||||
char *buffer;
|
||||
char *land;
|
||||
char *mission;
|
||||
|
||||
buffer = (char*) util_xmalloc(1024);
|
||||
memset(buffer, 0, 1024);
|
||||
buffer = (char *) util_xmalloc(1024);
|
||||
memset(buffer, 0, 1024);
|
||||
|
||||
land = util_str_buffer((const uint8_t*) review->worldmax_current_land,
|
||||
ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX);
|
||||
mission = util_str_buffer((const uint8_t*) review->worldmax_current_mission,
|
||||
ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX);
|
||||
land = util_str_buffer(
|
||||
(const uint8_t *) review->worldmax_current_land,
|
||||
ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX);
|
||||
mission = util_str_buffer(
|
||||
(const uint8_t *) review->worldmax_current_mission,
|
||||
ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX);
|
||||
|
||||
util_str_format(buffer, 1024,
|
||||
">>> review:\n"
|
||||
"player_id: %s\n"
|
||||
"mileage: %d\n"
|
||||
"reward_count: %d\n"
|
||||
"worldmax_count: %d\n"
|
||||
"play_count: %d\n"
|
||||
"worldmax_current_land: %s\n"
|
||||
"worldmax_current_mission: %s\n"
|
||||
"kcal: %d\n"
|
||||
"v02: %d\n",
|
||||
review->player_id,
|
||||
review->mileage,
|
||||
review->reward_count,
|
||||
review->worldmax_count,
|
||||
review->play_count,
|
||||
land,
|
||||
mission,
|
||||
review->kcal,
|
||||
review->v02);
|
||||
util_str_format(
|
||||
buffer,
|
||||
1024,
|
||||
">>> review:\n"
|
||||
"player_id: %s\n"
|
||||
"mileage: %d\n"
|
||||
"reward_count: %d\n"
|
||||
"worldmax_count: %d\n"
|
||||
"play_count: %d\n"
|
||||
"worldmax_current_land: %s\n"
|
||||
"worldmax_current_mission: %s\n"
|
||||
"kcal: %d\n"
|
||||
"v02: %d\n",
|
||||
review->player_id,
|
||||
review->mileage,
|
||||
review->reward_count,
|
||||
review->worldmax_count,
|
||||
review->play_count,
|
||||
land,
|
||||
mission,
|
||||
review->kcal,
|
||||
review->v02);
|
||||
|
||||
free(land);
|
||||
free(mission);
|
||||
free(land);
|
||||
free(mission);
|
||||
|
||||
return buffer;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static char* asset_nx2_usb_save_stats_to_string(
|
||||
const struct asset_nx2_usb_save_stats* stats)
|
||||
static char *
|
||||
asset_nx2_usb_save_stats_to_string(const struct asset_nx2_usb_save_stats *stats)
|
||||
{
|
||||
char* merged;
|
||||
char* buffer;
|
||||
char* timestamp;
|
||||
char* tmp;
|
||||
const size_t buf_size = 512;
|
||||
char *merged;
|
||||
char *buffer;
|
||||
char *timestamp;
|
||||
char *tmp;
|
||||
const size_t buf_size = 512;
|
||||
|
||||
merged = (char*) util_xmalloc(buf_size);
|
||||
memset(merged, 0, buf_size);
|
||||
merged = (char *) util_xmalloc(buf_size);
|
||||
memset(merged, 0, buf_size);
|
||||
|
||||
buffer = (char*) util_xmalloc(buf_size);
|
||||
memset(buffer, 0, buf_size);
|
||||
buffer = (char *) util_xmalloc(buf_size);
|
||||
memset(buffer, 0, buf_size);
|
||||
|
||||
timestamp = asset_nx2_usb_save_time_to_string(&stats->timestamp);
|
||||
timestamp = asset_nx2_usb_save_time_to_string(&stats->timestamp);
|
||||
|
||||
util_str_format(merged, buf_size,
|
||||
">>> stats:\n"
|
||||
"adler32: 0x%X\n"
|
||||
"usb_serial: %s\n"
|
||||
"timestamp: %s"
|
||||
"avatar_id: %d\n"
|
||||
"rank: %d\n"
|
||||
"country_id: %d\n"
|
||||
"player_id: %s\n"
|
||||
"mileage: %d\n"
|
||||
"play_count: %d\n"
|
||||
"kcal: %d\n"
|
||||
"v02: %d\n"
|
||||
"worldmax_map_position: 0x%X\n"
|
||||
"reward_count: %d\n"
|
||||
"worldmax_count: %d\n",
|
||||
stats->adler32,
|
||||
stats->usb_serial,
|
||||
timestamp,
|
||||
stats->avatar_id,
|
||||
stats->rank,
|
||||
stats->country_id,
|
||||
stats->player_id,
|
||||
stats->mileage,
|
||||
stats->play_count,
|
||||
stats->kcal,
|
||||
stats->v02,
|
||||
stats->worldmax_map_position,
|
||||
stats->reward_count,
|
||||
stats->worldmax_count);
|
||||
util_str_format(
|
||||
merged,
|
||||
buf_size,
|
||||
">>> stats:\n"
|
||||
"adler32: 0x%X\n"
|
||||
"usb_serial: %s\n"
|
||||
"timestamp: %s"
|
||||
"avatar_id: %d\n"
|
||||
"rank: %d\n"
|
||||
"country_id: %d\n"
|
||||
"player_id: %s\n"
|
||||
"mileage: %d\n"
|
||||
"play_count: %d\n"
|
||||
"kcal: %d\n"
|
||||
"v02: %d\n"
|
||||
"worldmax_map_position: 0x%X\n"
|
||||
"reward_count: %d\n"
|
||||
"worldmax_count: %d\n",
|
||||
stats->adler32,
|
||||
stats->usb_serial,
|
||||
timestamp,
|
||||
stats->avatar_id,
|
||||
stats->rank,
|
||||
stats->country_id,
|
||||
stats->player_id,
|
||||
stats->mileage,
|
||||
stats->play_count,
|
||||
stats->kcal,
|
||||
stats->v02,
|
||||
stats->worldmax_map_position,
|
||||
stats->reward_count,
|
||||
stats->worldmax_count);
|
||||
|
||||
free(timestamp);
|
||||
free(timestamp);
|
||||
|
||||
tmp = util_str_merge(merged, "song_unlocks:\n");
|
||||
tmp = util_str_merge(merged, "song_unlocks:\n");
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_SONG_MAX; i++) {
|
||||
|
||||
util_str_format(
|
||||
buffer,
|
||||
buf_size,
|
||||
"song slot: %d\n"
|
||||
"mode: 0x%X\n"
|
||||
"unused: 0x%X\n"
|
||||
"song: %d\n"
|
||||
"reveal: %d\n",
|
||||
i,
|
||||
stats->song_unlocks[i].mode,
|
||||
stats->song_unlocks[i].unused,
|
||||
stats->song_unlocks[i].song,
|
||||
stats->song_unlocks[i].reveal);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_SONG_MAX; i++) {
|
||||
for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_MISSION_MAX; i++) {
|
||||
|
||||
util_str_format(buffer, buf_size,
|
||||
"song slot: %d\n"
|
||||
"mode: 0x%X\n"
|
||||
"unused: 0x%X\n"
|
||||
"song: %d\n"
|
||||
"reveal: %d\n",
|
||||
i,
|
||||
stats->song_unlocks[i].mode,
|
||||
stats->song_unlocks[i].unused,
|
||||
stats->song_unlocks[i].song,
|
||||
stats->song_unlocks[i].reveal);
|
||||
util_str_format(
|
||||
buffer,
|
||||
buf_size,
|
||||
"mission slot: %d\n"
|
||||
"clear_flags_directions: 0x%X\n"
|
||||
"clear_flag_mission: %d\n"
|
||||
"unused: 0x%X\n",
|
||||
i,
|
||||
stats->worldmax_mission_unlocks[i].clear_flags_directions,
|
||||
stats->worldmax_mission_unlocks[i].clear_flag_mission,
|
||||
stats->worldmax_mission_unlocks[i].unused);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_MISSION_MAX; i++) {
|
||||
|
||||
util_str_format(
|
||||
buffer,
|
||||
buf_size,
|
||||
"worldmax_high_score %d: %d\n",
|
||||
i,
|
||||
stats->worldmax_high_score[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_MISSION_MAX; i++) {
|
||||
|
||||
util_str_format(
|
||||
buffer,
|
||||
buf_size,
|
||||
"worldmax_challenge %d: %d\n",
|
||||
i,
|
||||
stats->worldmax_challenge[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_BARRICADE_MAX; i++) {
|
||||
|
||||
util_str_format(
|
||||
buffer,
|
||||
buf_size,
|
||||
"worldmax_barricade %d:\n"
|
||||
"flag_open: %d\n"
|
||||
"unused: 0x%X\n",
|
||||
i,
|
||||
stats->worldmax_barricade[i].flag_open,
|
||||
stats->worldmax_barricade[i].unused);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_EVENT_MAX; i++) {
|
||||
|
||||
util_str_format(
|
||||
buffer,
|
||||
buf_size,
|
||||
"worldmax_event %d:\n"
|
||||
"flag_cleared: %d\n"
|
||||
"unused: 0x%X\n",
|
||||
i,
|
||||
stats->worldmax_event[i].flag_cleared,
|
||||
stats->worldmax_event[i].unused);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_WARP_MAX; i++) {
|
||||
|
||||
util_str_format(
|
||||
buffer,
|
||||
buf_size,
|
||||
"worldmax_warp %d:\n"
|
||||
"direction_clear: 0x%X\n"
|
||||
"clear: %d\n",
|
||||
"unused: 0x%X\n",
|
||||
i,
|
||||
stats->worldmax_warp[i].direction_clear,
|
||||
stats->worldmax_warp[i].clear,
|
||||
stats->worldmax_warp[i].unused);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX; i++) {
|
||||
|
||||
util_str_format(
|
||||
buffer,
|
||||
buf_size,
|
||||
"worldmax_current_land %d: %d\n",
|
||||
i,
|
||||
stats->worldmax_current_land[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX; i++) {
|
||||
|
||||
util_str_format(
|
||||
buffer,
|
||||
buf_size,
|
||||
"worldmax_current_mission %d: %d\n",
|
||||
i,
|
||||
stats->worldmax_current_mission[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_SONG_MAX; i++) {
|
||||
|
||||
for (uint32_t j = 0; j < ASSET_NX2_USB_SAVE_NUM_MODES; j++) {
|
||||
util_str_format(
|
||||
buffer,
|
||||
buf_size,
|
||||
"song_scores %d/%d:\n"
|
||||
"score: %d\n"
|
||||
"player_id: %s\n",
|
||||
i,
|
||||
j,
|
||||
stats->song_scores[i][j].score,
|
||||
stats->song_scores[i][j].player_id);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_MISSION_MAX; i++) {
|
||||
free(buffer);
|
||||
|
||||
util_str_format(buffer, buf_size,
|
||||
"mission slot: %d\n"
|
||||
"clear_flags_directions: 0x%X\n"
|
||||
"clear_flag_mission: %d\n"
|
||||
"unused: 0x%X\n",
|
||||
i,
|
||||
stats->worldmax_mission_unlocks[i].clear_flags_directions,
|
||||
stats->worldmax_mission_unlocks[i].clear_flag_mission,
|
||||
stats->worldmax_mission_unlocks[i].unused);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_MISSION_MAX; i++) {
|
||||
|
||||
util_str_format(buffer, buf_size,
|
||||
"worldmax_high_score %d: %d\n",
|
||||
i,
|
||||
stats->worldmax_high_score[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_MISSION_MAX; i++) {
|
||||
|
||||
util_str_format(buffer, buf_size,
|
||||
"worldmax_challenge %d: %d\n",
|
||||
i,
|
||||
stats->worldmax_challenge[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_BARRICADE_MAX; i++) {
|
||||
|
||||
util_str_format(buffer, buf_size,
|
||||
"worldmax_barricade %d:\n"
|
||||
"flag_open: %d\n"
|
||||
"unused: 0x%X\n",
|
||||
i,
|
||||
stats->worldmax_barricade[i].flag_open,
|
||||
stats->worldmax_barricade[i].unused);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_EVENT_MAX; i++) {
|
||||
|
||||
util_str_format(buffer, buf_size,
|
||||
"worldmax_event %d:\n"
|
||||
"flag_cleared: %d\n"
|
||||
"unused: 0x%X\n",
|
||||
i,
|
||||
stats->worldmax_event[i].flag_cleared,
|
||||
stats->worldmax_event[i].unused);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_WARP_MAX; i++) {
|
||||
|
||||
util_str_format(buffer, buf_size,
|
||||
"worldmax_warp %d:\n"
|
||||
"direction_clear: 0x%X\n"
|
||||
"clear: %d\n",
|
||||
"unused: 0x%X\n",
|
||||
i,
|
||||
stats->worldmax_warp[i].direction_clear,
|
||||
stats->worldmax_warp[i].clear,
|
||||
stats->worldmax_warp[i].unused);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX; i++) {
|
||||
|
||||
util_str_format(buffer, buf_size,
|
||||
"worldmax_current_land %d: %d\n",
|
||||
i,
|
||||
stats->worldmax_current_land[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX; i++) {
|
||||
|
||||
util_str_format(buffer, buf_size,
|
||||
"worldmax_current_mission %d: %d\n",
|
||||
i,
|
||||
stats->worldmax_current_mission[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NX2_USB_SAVE_SONG_MAX; i++) {
|
||||
|
||||
for (uint32_t j = 0; j < ASSET_NX2_USB_SAVE_NUM_MODES; j++) {
|
||||
util_str_format(buffer, buf_size,
|
||||
"song_scores %d/%d:\n"
|
||||
"score: %d\n"
|
||||
"player_id: %s\n",
|
||||
i,
|
||||
j,
|
||||
stats->song_scores[i][j].score,
|
||||
stats->song_scores[i][j].player_id);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
|
||||
return merged;
|
||||
return merged;
|
||||
}
|
||||
|
||||
struct asset_nx2_usb_save* asset_nx2_usb_save_new(void)
|
||||
struct asset_nx2_usb_save *asset_nx2_usb_save_new(void)
|
||||
{
|
||||
struct asset_nx2_usb_save* save;
|
||||
char name[10];
|
||||
struct asset_nx2_usb_save *save;
|
||||
char name[10];
|
||||
|
||||
save = (struct asset_nx2_usb_save*) util_xmalloc(
|
||||
sizeof(struct asset_nx2_usb_save));
|
||||
save = (struct asset_nx2_usb_save *) util_xmalloc(
|
||||
sizeof(struct asset_nx2_usb_save));
|
||||
|
||||
memset(save, 0, sizeof(struct asset_nx2_usb_save));
|
||||
memset(save, 0, sizeof(struct asset_nx2_usb_save));
|
||||
|
||||
sprintf(name, "NX%06d", rand() % 1000000);
|
||||
strcpy(save->review.player_id, name);
|
||||
strcpy(save->stats.player_id, name);
|
||||
sprintf(name, "NX%06d", rand() % 1000000);
|
||||
strcpy(save->review.player_id, name);
|
||||
strcpy(save->stats.player_id, name);
|
||||
|
||||
/* default world map position */
|
||||
save->stats.worldmax_map_position = 0xEF001;
|
||||
/* default world map position */
|
||||
save->stats.worldmax_map_position = 0xEF001;
|
||||
|
||||
/* nx2 release date as default timestamp */
|
||||
save->stats.timestamp.year = 2008;
|
||||
save->stats.timestamp.month = 1;
|
||||
save->stats.timestamp.day = 21;
|
||||
save->stats.timestamp.hour = 0;
|
||||
save->stats.timestamp.min = 0;
|
||||
save->stats.timestamp.ms = 0;
|
||||
/* nx2 release date as default timestamp */
|
||||
save->stats.timestamp.year = 2008;
|
||||
save->stats.timestamp.month = 1;
|
||||
save->stats.timestamp.day = 21;
|
||||
save->stats.timestamp.hour = 0;
|
||||
save->stats.timestamp.min = 0;
|
||||
save->stats.timestamp.ms = 0;
|
||||
|
||||
return save;
|
||||
return save;
|
||||
}
|
||||
|
||||
void asset_nx2_usb_save_finalize(struct asset_nx2_usb_save* save)
|
||||
void asset_nx2_usb_save_finalize(struct asset_nx2_usb_save *save)
|
||||
{
|
||||
/* checksum update */
|
||||
save->stats.adler32 = util_adler32_calc(1,
|
||||
((const uint8_t*) &save->stats) + 4,
|
||||
sizeof(struct asset_nx2_usb_save_stats) - 4);
|
||||
/* checksum update */
|
||||
save->stats.adler32 = util_adler32_calc(
|
||||
1,
|
||||
((const uint8_t *) &save->stats) + 4,
|
||||
sizeof(struct asset_nx2_usb_save_stats) - 4);
|
||||
}
|
||||
|
||||
char* asset_nx2_usb_save_to_string(const struct asset_nx2_usb_save* save)
|
||||
char *asset_nx2_usb_save_to_string(const struct asset_nx2_usb_save *save)
|
||||
{
|
||||
char* review;
|
||||
char* stats;
|
||||
char* merged;
|
||||
char *review;
|
||||
char *stats;
|
||||
char *merged;
|
||||
|
||||
review = asset_nx2_usb_save_review_to_string(&save->review);
|
||||
stats = asset_nx2_usb_save_stats_to_string(&save->stats);
|
||||
review = asset_nx2_usb_save_review_to_string(&save->review);
|
||||
stats = asset_nx2_usb_save_stats_to_string(&save->stats);
|
||||
|
||||
merged = util_str_merge(review, stats);
|
||||
merged = util_str_merge(review, stats);
|
||||
|
||||
free(review);
|
||||
free(stats);
|
||||
free(review);
|
||||
free(stats);
|
||||
|
||||
return merged;
|
||||
return merged;
|
||||
}
|
||||
|
||||
void asset_nx2_usb_save_decrypt(uint8_t* buf, size_t len)
|
||||
void asset_nx2_usb_save_decrypt(uint8_t *buf, size_t len)
|
||||
{
|
||||
/* skip non encrypted review area */
|
||||
buf += sizeof(struct asset_nx2_usb_save_review);
|
||||
len -= sizeof(struct asset_nx2_usb_save_review);
|
||||
/* skip non encrypted review area */
|
||||
buf += sizeof(struct asset_nx2_usb_save_review);
|
||||
len -= sizeof(struct asset_nx2_usb_save_review);
|
||||
|
||||
for (size_t a = len - 1; a > 0; --a) {
|
||||
buf[a] = (buf[a] ^ buf[a - 1]) + ((a * 1234567) >> 8);
|
||||
}
|
||||
for (size_t a = len - 1; a > 0; --a) {
|
||||
buf[a] = (buf[a] ^ buf[a - 1]) + ((a * 1234567) >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
void asset_nx2_usb_save_encrypt(uint8_t* buf, size_t len)
|
||||
void asset_nx2_usb_save_encrypt(uint8_t *buf, size_t len)
|
||||
{
|
||||
/* skip non encrypted review area */
|
||||
buf += sizeof(struct asset_nx2_usb_save_review);
|
||||
len -= sizeof(struct asset_nx2_usb_save_review);
|
||||
/* skip non encrypted review area */
|
||||
buf += sizeof(struct asset_nx2_usb_save_review);
|
||||
len -= sizeof(struct asset_nx2_usb_save_review);
|
||||
|
||||
for (size_t a = 1; a < len; ++a) {
|
||||
buf[a] = (buf[a] - ((a * 1234567) >> 8)) ^ buf[a - 1];
|
||||
}
|
||||
for (size_t a = 1; a < len; ++a) {
|
||||
buf[a] = (buf[a] - ((a * 1234567) >> 8)) ^ buf[a - 1];
|
||||
}
|
||||
}
|
||||
@@ -7,116 +7,116 @@
|
||||
#define ASSET_NX2_USB_SAVE_SIZE 30780
|
||||
|
||||
enum asset_nx2_usb_save_limits {
|
||||
ASSET_NX2_USB_SAVE_SERIAL_ID_MAX = 64,
|
||||
ASSET_NX2_USB_SAVE_PLAYER_ID_MAX = 12,
|
||||
ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX = 128,
|
||||
ASSET_NX2_USB_SAVE_SONG_MAX = 256,
|
||||
ASSET_NX2_USB_SAVE_MISSION_MAX = 1024,
|
||||
ASSET_NX2_USB_SAVE_BARRICADE_MAX = 16,
|
||||
ASSET_NX2_USB_SAVE_EVENT_MAX = 128,
|
||||
ASSET_NX2_USB_SAVE_WARP_MAX = 8,
|
||||
ASSET_NX2_USB_SAVE_NUM_MODES = 5,
|
||||
ASSET_NX2_USB_SAVE_SERIAL_ID_MAX = 64,
|
||||
ASSET_NX2_USB_SAVE_PLAYER_ID_MAX = 12,
|
||||
ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX = 128,
|
||||
ASSET_NX2_USB_SAVE_SONG_MAX = 256,
|
||||
ASSET_NX2_USB_SAVE_MISSION_MAX = 1024,
|
||||
ASSET_NX2_USB_SAVE_BARRICADE_MAX = 16,
|
||||
ASSET_NX2_USB_SAVE_EVENT_MAX = 128,
|
||||
ASSET_NX2_USB_SAVE_WARP_MAX = 8,
|
||||
ASSET_NX2_USB_SAVE_NUM_MODES = 5,
|
||||
};
|
||||
|
||||
struct asset_nx2_usb_save_time {
|
||||
int16_t year;
|
||||
uint8_t month;
|
||||
uint8_t day;
|
||||
uint8_t hour;
|
||||
uint8_t min;
|
||||
uint16_t ms;
|
||||
int16_t year;
|
||||
uint8_t month;
|
||||
uint8_t day;
|
||||
uint8_t hour;
|
||||
uint8_t min;
|
||||
uint16_t ms;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_nx2_usb_save_review {
|
||||
char player_id[ASSET_NX2_USB_SAVE_PLAYER_ID_MAX];
|
||||
int32_t mileage;
|
||||
int32_t reward_count;
|
||||
int32_t worldmax_count;
|
||||
int32_t play_count;
|
||||
char worldmax_current_land[ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX];
|
||||
char worldmax_current_mission[ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX];
|
||||
int32_t kcal;
|
||||
int32_t v02;
|
||||
char player_id[ASSET_NX2_USB_SAVE_PLAYER_ID_MAX];
|
||||
int32_t mileage;
|
||||
int32_t reward_count;
|
||||
int32_t worldmax_count;
|
||||
int32_t play_count;
|
||||
char worldmax_current_land[ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX];
|
||||
char worldmax_current_mission[ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX];
|
||||
int32_t kcal;
|
||||
int32_t v02;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_nx2_usb_save_stats {
|
||||
uint32_t adler32;
|
||||
char usb_serial[ASSET_NX2_USB_SAVE_SERIAL_ID_MAX];
|
||||
struct asset_nx2_usb_save_time timestamp;
|
||||
int32_t avatar_id;
|
||||
int32_t rank;
|
||||
int32_t country_id;
|
||||
char player_id[ASSET_NX2_USB_SAVE_PLAYER_ID_MAX];
|
||||
int32_t mileage;
|
||||
int32_t play_count;
|
||||
int32_t kcal;
|
||||
int32_t v02;
|
||||
int32_t worldmax_map_position;
|
||||
int32_t reward_count;
|
||||
int32_t worldmax_count;
|
||||
uint32_t adler32;
|
||||
char usb_serial[ASSET_NX2_USB_SAVE_SERIAL_ID_MAX];
|
||||
struct asset_nx2_usb_save_time timestamp;
|
||||
int32_t avatar_id;
|
||||
int32_t rank;
|
||||
int32_t country_id;
|
||||
char player_id[ASSET_NX2_USB_SAVE_PLAYER_ID_MAX];
|
||||
int32_t mileage;
|
||||
int32_t play_count;
|
||||
int32_t kcal;
|
||||
int32_t v02;
|
||||
int32_t worldmax_map_position;
|
||||
int32_t reward_count;
|
||||
int32_t worldmax_count;
|
||||
|
||||
struct {
|
||||
/* bits 0-4 for modes/stepcharts */
|
||||
uint8_t mode : 5;
|
||||
/* unused bit */
|
||||
uint8_t unused : 1;
|
||||
/* bit 6 song itself */
|
||||
uint8_t song : 1;
|
||||
/* bit 7 reveal flag */
|
||||
uint8_t reveal : 1;
|
||||
} song_unlocks[ASSET_NX2_USB_SAVE_SONG_MAX] __attribute__((__packed__));
|
||||
struct {
|
||||
/* bits 0-4 for modes/stepcharts */
|
||||
uint8_t mode : 5;
|
||||
/* unused bit */
|
||||
uint8_t unused : 1;
|
||||
/* bit 6 song itself */
|
||||
uint8_t song : 1;
|
||||
/* bit 7 reveal flag */
|
||||
uint8_t reveal : 1;
|
||||
} song_unlocks[ASSET_NX2_USB_SAVE_SONG_MAX] __attribute__((__packed__));
|
||||
|
||||
struct {
|
||||
uint8_t clear_flags_directions : 4;
|
||||
uint8_t clear_flag_mission : 1;
|
||||
uint8_t unused : 3;
|
||||
} worldmax_mission_unlocks[ASSET_NX2_USB_SAVE_MISSION_MAX]
|
||||
__attribute__((__packed__));
|
||||
struct {
|
||||
uint8_t clear_flags_directions : 4;
|
||||
uint8_t clear_flag_mission : 1;
|
||||
uint8_t unused : 3;
|
||||
} worldmax_mission_unlocks[ASSET_NX2_USB_SAVE_MISSION_MAX]
|
||||
__attribute__((__packed__));
|
||||
|
||||
int32_t worldmax_high_score[ASSET_NX2_USB_SAVE_MISSION_MAX];
|
||||
int32_t worldmax_challenge[ASSET_NX2_USB_SAVE_MISSION_MAX];
|
||||
int32_t worldmax_high_score[ASSET_NX2_USB_SAVE_MISSION_MAX];
|
||||
int32_t worldmax_challenge[ASSET_NX2_USB_SAVE_MISSION_MAX];
|
||||
|
||||
struct {
|
||||
uint8_t flag_open : 1;
|
||||
uint8_t unused : 7;
|
||||
} worldmax_barricade[ASSET_NX2_USB_SAVE_BARRICADE_MAX]
|
||||
__attribute__((__packed__));
|
||||
struct {
|
||||
uint8_t flag_open : 1;
|
||||
uint8_t unused : 7;
|
||||
} worldmax_barricade[ASSET_NX2_USB_SAVE_BARRICADE_MAX]
|
||||
__attribute__((__packed__));
|
||||
|
||||
struct {
|
||||
uint8_t flag_cleared : 1;
|
||||
uint8_t unused : 7;
|
||||
} worldmax_event[ASSET_NX2_USB_SAVE_EVENT_MAX] __attribute__((__packed__));
|
||||
struct {
|
||||
uint8_t flag_cleared : 1;
|
||||
uint8_t unused : 7;
|
||||
} worldmax_event[ASSET_NX2_USB_SAVE_EVENT_MAX] __attribute__((__packed__));
|
||||
|
||||
struct {
|
||||
uint8_t direction_clear : 4;
|
||||
uint8_t clear : 1;
|
||||
uint8_t unused : 3;
|
||||
} worldmax_warp[ASSET_NX2_USB_SAVE_WARP_MAX] __attribute__((__packed__));
|
||||
struct {
|
||||
uint8_t direction_clear : 4;
|
||||
uint8_t clear : 1;
|
||||
uint8_t unused : 3;
|
||||
} worldmax_warp[ASSET_NX2_USB_SAVE_WARP_MAX] __attribute__((__packed__));
|
||||
|
||||
char worldmax_current_land[ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX];
|
||||
char worldmax_current_mission[ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX];
|
||||
char worldmax_current_land[ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX];
|
||||
char worldmax_current_mission[ASSET_NX2_USB_SAVE_WORLDMAX_LOC_MAX];
|
||||
|
||||
struct {
|
||||
int32_t score;
|
||||
char player_id[ASSET_NX2_USB_SAVE_PLAYER_ID_MAX];
|
||||
} song_scores[ASSET_NX2_USB_SAVE_SONG_MAX][ASSET_NX2_USB_SAVE_NUM_MODES]
|
||||
__attribute__((__packed__));
|
||||
struct {
|
||||
int32_t score;
|
||||
char player_id[ASSET_NX2_USB_SAVE_PLAYER_ID_MAX];
|
||||
} song_scores[ASSET_NX2_USB_SAVE_SONG_MAX][ASSET_NX2_USB_SAVE_NUM_MODES]
|
||||
__attribute__((__packed__));
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_nx2_usb_save {
|
||||
struct asset_nx2_usb_save_review review;
|
||||
struct asset_nx2_usb_save_stats stats;
|
||||
struct asset_nx2_usb_save_review review;
|
||||
struct asset_nx2_usb_save_stats stats;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_nx2_usb_save* asset_nx2_usb_save_new(void);
|
||||
struct asset_nx2_usb_save *asset_nx2_usb_save_new(void);
|
||||
|
||||
// update checksum and prepare profile to get encrypted
|
||||
void asset_nx2_usb_save_finalize(struct asset_nx2_usb_save* save);
|
||||
void asset_nx2_usb_save_finalize(struct asset_nx2_usb_save *save);
|
||||
|
||||
char* asset_nx2_usb_save_to_string(const struct asset_nx2_usb_save* save);
|
||||
char *asset_nx2_usb_save_to_string(const struct asset_nx2_usb_save *save);
|
||||
|
||||
void asset_nx2_usb_save_decrypt(uint8_t* buf, size_t len);
|
||||
void asset_nx2_usb_save_decrypt(uint8_t *buf, size_t len);
|
||||
|
||||
void asset_nx2_usb_save_encrypt(uint8_t* buf, size_t len);
|
||||
void asset_nx2_usb_save_encrypt(uint8_t *buf, size_t len);
|
||||
|
||||
#endif
|
||||
@@ -7,94 +7,100 @@
|
||||
|
||||
#include "util.h"
|
||||
|
||||
struct asset_nx2_usb_rank* asset_nx2_usb_rank_load_from_file(const char* path,
|
||||
bool encrypted)
|
||||
struct asset_nx2_usb_rank *
|
||||
asset_nx2_usb_rank_load_from_file(const char *path, bool encrypted)
|
||||
{
|
||||
struct asset_nx2_usb_rank* rank;
|
||||
size_t size;
|
||||
struct asset_nx2_usb_rank *rank;
|
||||
size_t size;
|
||||
|
||||
if (!util_file_load(path, (void**) &rank, &size, false)) {
|
||||
log_error("Loading nx2 rank file %s failed", path);
|
||||
return NULL;
|
||||
}
|
||||
if (!util_file_load(path, (void **) &rank, &size, false)) {
|
||||
log_error("Loading nx2 rank file %s failed", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size != sizeof(struct asset_nx2_usb_rank)) {
|
||||
log_error("Invalid size of nx2 rank file %s: %d != %d", path, size,
|
||||
sizeof(struct asset_nx2_usb_rank));
|
||||
free(rank);
|
||||
return NULL;
|
||||
}
|
||||
if (size != sizeof(struct asset_nx2_usb_rank)) {
|
||||
log_error(
|
||||
"Invalid size of nx2 rank file %s: %d != %d",
|
||||
path,
|
||||
size,
|
||||
sizeof(struct asset_nx2_usb_rank));
|
||||
free(rank);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (encrypted) {
|
||||
asset_nx2_usb_rank_decrypt((uint8_t*) rank, size);
|
||||
}
|
||||
if (encrypted) {
|
||||
asset_nx2_usb_rank_decrypt((uint8_t *) rank, size);
|
||||
}
|
||||
|
||||
return rank;
|
||||
return rank;
|
||||
}
|
||||
|
||||
bool asset_nx2_usb_rank_save_to_file(const char* path,
|
||||
const struct asset_nx2_usb_rank* rank, bool encrypt)
|
||||
bool asset_nx2_usb_rank_save_to_file(
|
||||
const char *path, const struct asset_nx2_usb_rank *rank, bool encrypt)
|
||||
{
|
||||
struct asset_nx2_usb_rank rank_enc;
|
||||
struct asset_nx2_usb_rank rank_enc;
|
||||
|
||||
memcpy(&rank_enc, rank, sizeof(struct asset_nx2_usb_rank));
|
||||
memcpy(&rank_enc, rank, sizeof(struct asset_nx2_usb_rank));
|
||||
|
||||
if (encrypt) {
|
||||
asset_nx2_usb_rank_encrypt((uint8_t*) &rank_enc,
|
||||
sizeof(struct asset_nx2_usb_rank));
|
||||
}
|
||||
if (encrypt) {
|
||||
asset_nx2_usb_rank_encrypt(
|
||||
(uint8_t *) &rank_enc, sizeof(struct asset_nx2_usb_rank));
|
||||
}
|
||||
|
||||
if (!util_file_save(path, (void**) &rank_enc,
|
||||
sizeof(struct asset_nx2_usb_rank))) {
|
||||
log_error("Storing nx2 rank data to %s failed", path);
|
||||
return false;
|
||||
}
|
||||
if (!util_file_save(
|
||||
path, (void **) &rank_enc, sizeof(struct asset_nx2_usb_rank))) {
|
||||
log_error("Storing nx2 rank data to %s failed", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct asset_nx2_usb_save* asset_nx2_usb_save_load_from_file(const char* path,
|
||||
bool encrypted)
|
||||
struct asset_nx2_usb_save *
|
||||
asset_nx2_usb_save_load_from_file(const char *path, bool encrypted)
|
||||
{
|
||||
struct asset_nx2_usb_save* save;
|
||||
size_t size;
|
||||
struct asset_nx2_usb_save *save;
|
||||
size_t size;
|
||||
|
||||
if (!util_file_load(path, (void**) &save, &size, false)) {
|
||||
log_error("Loading nx2 save file %s failed", path);
|
||||
return NULL;
|
||||
}
|
||||
if (!util_file_load(path, (void **) &save, &size, false)) {
|
||||
log_error("Loading nx2 save file %s failed", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size != sizeof(struct asset_nx2_usb_save)) {
|
||||
log_error("Invalid size of nx2 save file %s: %d != %d", path, size,
|
||||
sizeof(struct asset_nx2_usb_save));
|
||||
free(save);
|
||||
return NULL;
|
||||
}
|
||||
if (size != sizeof(struct asset_nx2_usb_save)) {
|
||||
log_error(
|
||||
"Invalid size of nx2 save file %s: %d != %d",
|
||||
path,
|
||||
size,
|
||||
sizeof(struct asset_nx2_usb_save));
|
||||
free(save);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (encrypted) {
|
||||
asset_nx2_usb_save_decrypt((uint8_t*) save, size);
|
||||
}
|
||||
if (encrypted) {
|
||||
asset_nx2_usb_save_decrypt((uint8_t *) save, size);
|
||||
}
|
||||
|
||||
return save;
|
||||
return save;
|
||||
}
|
||||
|
||||
bool asset_nx2_usb_save_save_to_file(const char* path,
|
||||
const struct asset_nx2_usb_save* save, bool encrypt)
|
||||
bool asset_nx2_usb_save_save_to_file(
|
||||
const char *path, const struct asset_nx2_usb_save *save, bool encrypt)
|
||||
{
|
||||
struct asset_nx2_usb_save save_enc;
|
||||
struct asset_nx2_usb_save save_enc;
|
||||
|
||||
memcpy(&save_enc, save, sizeof(struct asset_nx2_usb_save));
|
||||
memcpy(&save_enc, save, sizeof(struct asset_nx2_usb_save));
|
||||
|
||||
if (encrypt) {
|
||||
asset_nx2_usb_save_encrypt((uint8_t*) &save_enc,
|
||||
sizeof(struct asset_nx2_usb_save));
|
||||
}
|
||||
if (encrypt) {
|
||||
asset_nx2_usb_save_encrypt(
|
||||
(uint8_t *) &save_enc, sizeof(struct asset_nx2_usb_save));
|
||||
}
|
||||
|
||||
if (!util_file_save(path, (const void*) &save_enc,
|
||||
sizeof(struct asset_nx2_usb_save))) {
|
||||
log_error("Storing nx2 save data to %s failed", path);
|
||||
return false;
|
||||
}
|
||||
if (!util_file_save(
|
||||
path, (const void *) &save_enc, sizeof(struct asset_nx2_usb_save))) {
|
||||
log_error("Storing nx2 save data to %s failed", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
@@ -7,15 +7,19 @@
|
||||
#include "usb-save.h"
|
||||
|
||||
// load from file and decrypt, returns decrypted struct
|
||||
struct asset_nx2_usb_rank* asset_nx2_usb_rank_load_from_file(const char* path, bool encrypted);
|
||||
struct asset_nx2_usb_rank *
|
||||
asset_nx2_usb_rank_load_from_file(const char *path, bool encrypted);
|
||||
|
||||
// takes decrypted rank data, encrypts it and writes it to file
|
||||
bool asset_nx2_usb_rank_save_to_file(const char* path, const struct asset_nx2_usb_rank* rank, bool encrypt);
|
||||
bool asset_nx2_usb_rank_save_to_file(
|
||||
const char *path, const struct asset_nx2_usb_rank *rank, bool encrypt);
|
||||
|
||||
// load from file and decrypt, returns decrypted struct
|
||||
struct asset_nx2_usb_save* asset_nx2_usb_save_load_from_file(const char* path, bool encrypted);
|
||||
struct asset_nx2_usb_save *
|
||||
asset_nx2_usb_save_load_from_file(const char *path, bool encrypted);
|
||||
|
||||
// takes decrypted save data, encrypts it and writes it to file
|
||||
bool asset_nx2_usb_save_save_to_file(const char* path, const struct asset_nx2_usb_save* save, bool encrypt);
|
||||
bool asset_nx2_usb_save_save_to_file(
|
||||
const char *path, const struct asset_nx2_usb_save *save, bool encrypt);
|
||||
|
||||
#endif
|
||||
@@ -9,146 +9,150 @@
|
||||
|
||||
#include "util/str.h"
|
||||
|
||||
int main(int argc, char** argv)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
char* rank_path;
|
||||
char* save_path;
|
||||
int ret;
|
||||
char *rank_path;
|
||||
char *save_path;
|
||||
|
||||
if (argc < 3) {
|
||||
printf("Usage: %s [cmd: new, dec, enc, dump] "
|
||||
"[path containing nx2rank.bin nx2save.bin]\n", argv[0]);
|
||||
return -1;
|
||||
if (argc < 3) {
|
||||
printf(
|
||||
"Usage: %s [cmd: new, dec, enc, dump] "
|
||||
"[path containing nx2rank.bin nx2save.bin]\n",
|
||||
argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
rank_path = util_str_merge(argv[2], "nx2rank.bin");
|
||||
save_path = util_str_merge(argv[2], "nx2save.bin");
|
||||
|
||||
if (!strcmp(argv[1], "new")) {
|
||||
struct asset_nx2_usb_rank *rank = asset_nx2_usb_rank_new();
|
||||
struct asset_nx2_usb_save *save = asset_nx2_usb_save_new();
|
||||
|
||||
asset_nx2_usb_rank_finalize(rank);
|
||||
asset_nx2_usb_save_finalize(save);
|
||||
|
||||
if (!asset_nx2_usb_rank_save_to_file(rank_path, rank, true)) {
|
||||
fprintf(stderr, "Creating rank file %s failed\n", rank_path);
|
||||
ret = -2;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
if (!asset_nx2_usb_save_save_to_file(save_path, save, true)) {
|
||||
fprintf(stderr, "Creating save file %s failed\n", save_path);
|
||||
ret = -3;
|
||||
}
|
||||
|
||||
rank_path = util_str_merge(argv[2], "nx2rank.bin");
|
||||
save_path = util_str_merge(argv[2], "nx2save.bin");
|
||||
free(rank);
|
||||
free(save);
|
||||
} else {
|
||||
struct asset_nx2_usb_rank *rank;
|
||||
struct asset_nx2_usb_save *save;
|
||||
bool encrypted;
|
||||
|
||||
if (!strcmp(argv[1], "new")) {
|
||||
struct asset_nx2_usb_rank* rank = asset_nx2_usb_rank_new();
|
||||
struct asset_nx2_usb_save* save = asset_nx2_usb_save_new();
|
||||
if (!strcmp(argv[1], "enc")) {
|
||||
char *tmp;
|
||||
|
||||
asset_nx2_usb_rank_finalize(rank);
|
||||
asset_nx2_usb_save_finalize(save);
|
||||
encrypted = false;
|
||||
|
||||
if (!asset_nx2_usb_rank_save_to_file(rank_path, rank, true)) {
|
||||
fprintf(stderr, "Creating rank file %s failed\n", rank_path);
|
||||
ret = -2;
|
||||
}
|
||||
tmp = util_str_merge(rank_path, ".dec");
|
||||
free(rank_path);
|
||||
rank_path = tmp;
|
||||
|
||||
if (!asset_nx2_usb_save_save_to_file(save_path, save, true)) {
|
||||
fprintf(stderr, "Creating save file %s failed\n", save_path);
|
||||
ret = -3;
|
||||
}
|
||||
|
||||
free(rank);
|
||||
free(save);
|
||||
tmp = util_str_merge(save_path, ".dec");
|
||||
free(save_path);
|
||||
save_path = tmp;
|
||||
} else {
|
||||
struct asset_nx2_usb_rank* rank;
|
||||
struct asset_nx2_usb_save* save;
|
||||
bool encrypted;
|
||||
|
||||
if (!strcmp(argv[1], "enc")) {
|
||||
char* tmp;
|
||||
|
||||
encrypted = false;
|
||||
|
||||
tmp = util_str_merge(rank_path, ".dec");
|
||||
free(rank_path);
|
||||
rank_path = tmp;
|
||||
|
||||
tmp = util_str_merge(save_path, ".dec");
|
||||
free(save_path);
|
||||
save_path = tmp;
|
||||
} else {
|
||||
encrypted = true;
|
||||
}
|
||||
|
||||
rank = asset_nx2_usb_rank_load_from_file(rank_path, encrypted);
|
||||
save = asset_nx2_usb_save_load_from_file(save_path, encrypted);
|
||||
|
||||
if (!rank) {
|
||||
fprintf(stderr, "Loading %s failed", rank_path);
|
||||
ret = -4;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!save) {
|
||||
fprintf(stderr, "Loading %s failed", save_path);
|
||||
ret = -5;
|
||||
free(rank);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "dec")) {
|
||||
char* rank_path_dec;
|
||||
char* save_path_dec;
|
||||
|
||||
rank_path_dec = util_str_merge(rank_path, ".dec");
|
||||
save_path_dec = util_str_merge(save_path, ".dec");
|
||||
|
||||
if (!asset_nx2_usb_rank_save_to_file(rank_path_dec, rank, false)) {
|
||||
fprintf(stderr, "Saving decrypted rank file to %s failed\n",
|
||||
rank_path_dec);
|
||||
ret = -6;
|
||||
}
|
||||
|
||||
if (!asset_nx2_usb_save_save_to_file(save_path_dec, save, false)) {
|
||||
fprintf(stderr, "Saving decrypted save file to %s failed\n",
|
||||
save_path_dec);
|
||||
ret = -7;
|
||||
}
|
||||
|
||||
free(rank_path_dec);
|
||||
free(save_path_dec);
|
||||
} else if (!strcmp(argv[1], "enc")) {
|
||||
char* rank_path_enc;
|
||||
char* save_path_enc;
|
||||
|
||||
rank_path_enc = util_str_merge(rank_path, ".enc");
|
||||
save_path_enc = util_str_merge(save_path, ".enc");
|
||||
|
||||
if (!asset_nx2_usb_rank_save_to_file(rank_path_enc, rank, true)) {
|
||||
fprintf(stderr, "Saving encrypted rank file to %s failed\n",
|
||||
rank_path_enc);
|
||||
ret = -6;
|
||||
}
|
||||
|
||||
if (!asset_nx2_usb_save_save_to_file(save_path_enc, save, true)) {
|
||||
fprintf(stderr, "Saving encrypted save file to %s failed\n",
|
||||
save_path_enc);
|
||||
ret = -7;
|
||||
}
|
||||
|
||||
free(rank_path_enc);
|
||||
free(save_path_enc);
|
||||
} else if (!strcmp(argv[1], "dump")) {
|
||||
char* rank_str;
|
||||
char* save_str;
|
||||
|
||||
rank_str = asset_nx2_usb_rank_to_string(rank);
|
||||
save_str = asset_nx2_usb_save_to_string(save);
|
||||
|
||||
printf("----------------- rank -----------------\n"
|
||||
"%s----------------- save -----------------\n%s",
|
||||
rank_str, save_str);
|
||||
|
||||
free(rank_str);
|
||||
free(save_str);
|
||||
} else {
|
||||
fprintf(stderr, "Unknown command %s\n", argv[1]);
|
||||
ret = -4;
|
||||
}
|
||||
|
||||
free(rank);
|
||||
free(save);
|
||||
encrypted = true;
|
||||
}
|
||||
|
||||
rank = asset_nx2_usb_rank_load_from_file(rank_path, encrypted);
|
||||
save = asset_nx2_usb_save_load_from_file(save_path, encrypted);
|
||||
|
||||
if (!rank) {
|
||||
fprintf(stderr, "Loading %s failed", rank_path);
|
||||
ret = -4;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!save) {
|
||||
fprintf(stderr, "Loading %s failed", save_path);
|
||||
ret = -5;
|
||||
free(rank);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "dec")) {
|
||||
char *rank_path_dec;
|
||||
char *save_path_dec;
|
||||
|
||||
rank_path_dec = util_str_merge(rank_path, ".dec");
|
||||
save_path_dec = util_str_merge(save_path, ".dec");
|
||||
|
||||
if (!asset_nx2_usb_rank_save_to_file(rank_path_dec, rank, false)) {
|
||||
fprintf(
|
||||
stderr, "Saving decrypted rank file to %s failed\n", rank_path_dec);
|
||||
ret = -6;
|
||||
}
|
||||
|
||||
if (!asset_nx2_usb_save_save_to_file(save_path_dec, save, false)) {
|
||||
fprintf(
|
||||
stderr, "Saving decrypted save file to %s failed\n", save_path_dec);
|
||||
ret = -7;
|
||||
}
|
||||
|
||||
free(rank_path_dec);
|
||||
free(save_path_dec);
|
||||
} else if (!strcmp(argv[1], "enc")) {
|
||||
char *rank_path_enc;
|
||||
char *save_path_enc;
|
||||
|
||||
rank_path_enc = util_str_merge(rank_path, ".enc");
|
||||
save_path_enc = util_str_merge(save_path, ".enc");
|
||||
|
||||
if (!asset_nx2_usb_rank_save_to_file(rank_path_enc, rank, true)) {
|
||||
fprintf(
|
||||
stderr, "Saving encrypted rank file to %s failed\n", rank_path_enc);
|
||||
ret = -6;
|
||||
}
|
||||
|
||||
if (!asset_nx2_usb_save_save_to_file(save_path_enc, save, true)) {
|
||||
fprintf(
|
||||
stderr, "Saving encrypted save file to %s failed\n", save_path_enc);
|
||||
ret = -7;
|
||||
}
|
||||
|
||||
free(rank_path_enc);
|
||||
free(save_path_enc);
|
||||
} else if (!strcmp(argv[1], "dump")) {
|
||||
char *rank_str;
|
||||
char *save_str;
|
||||
|
||||
rank_str = asset_nx2_usb_rank_to_string(rank);
|
||||
save_str = asset_nx2_usb_save_to_string(save);
|
||||
|
||||
printf(
|
||||
"----------------- rank -----------------\n"
|
||||
"%s----------------- save -----------------\n%s",
|
||||
rank_str,
|
||||
save_str);
|
||||
|
||||
free(rank_str);
|
||||
free(save_str);
|
||||
} else {
|
||||
fprintf(stderr, "Unknown command %s\n", argv[1]);
|
||||
ret = -4;
|
||||
}
|
||||
|
||||
free(rank);
|
||||
free(save);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(rank_path);
|
||||
free(save_path);
|
||||
free(rank_path);
|
||||
free(save_path);
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
@@ -8,96 +8,101 @@
|
||||
|
||||
#include "usb-rank.h"
|
||||
|
||||
struct asset_nxa_usb_rank* asset_nxa_usb_rank_new(void)
|
||||
struct asset_nxa_usb_rank *asset_nxa_usb_rank_new(void)
|
||||
{
|
||||
struct asset_nxa_usb_rank* rank;
|
||||
struct asset_nxa_usb_rank *rank;
|
||||
|
||||
rank = (struct asset_nxa_usb_rank*)
|
||||
util_xmalloc(sizeof(struct asset_nxa_usb_rank));
|
||||
rank = (struct asset_nxa_usb_rank *) util_xmalloc(
|
||||
sizeof(struct asset_nxa_usb_rank));
|
||||
|
||||
memset(rank, 0, sizeof(struct asset_nxa_usb_rank));
|
||||
memset(rank, 0, sizeof(struct asset_nxa_usb_rank));
|
||||
|
||||
return rank;
|
||||
return rank;
|
||||
}
|
||||
|
||||
void asset_nxa_usb_rank_finalize(struct asset_nxa_usb_rank* rank)
|
||||
void asset_nxa_usb_rank_finalize(struct asset_nxa_usb_rank *rank)
|
||||
{
|
||||
rank->adler32 = util_adler32_calc(1, ((const uint8_t*) rank) + 4,
|
||||
sizeof(struct asset_nxa_usb_rank) - 4);
|
||||
rank->adler32 = util_adler32_calc(
|
||||
1, ((const uint8_t *) rank) + 4, sizeof(struct asset_nxa_usb_rank) - 4);
|
||||
}
|
||||
|
||||
char* asset_nxa_usb_rank_to_string(const struct asset_nxa_usb_rank* rank)
|
||||
char *asset_nxa_usb_rank_to_string(const struct asset_nxa_usb_rank *rank)
|
||||
{
|
||||
char* buffer;
|
||||
char* buffer2;
|
||||
char* merged;
|
||||
char* usb_ser;
|
||||
char *buffer;
|
||||
char *buffer2;
|
||||
char *merged;
|
||||
char *usb_ser;
|
||||
|
||||
buffer = (char*) util_xmalloc(512);
|
||||
memset(buffer, 0, 512);
|
||||
buffer = (char *) util_xmalloc(512);
|
||||
memset(buffer, 0, 512);
|
||||
|
||||
usb_ser = util_str_buffer((const uint8_t*) rank->usb_serial,
|
||||
ASSET_NXA_USB_RANK_USB_SERIAL_LEN);
|
||||
usb_ser = util_str_buffer(
|
||||
(const uint8_t *) rank->usb_serial, ASSET_NXA_USB_RANK_USB_SERIAL_LEN);
|
||||
|
||||
util_str_format(buffer, 512,
|
||||
"adler32: 0x%X\n"
|
||||
// "usb_serial: %s\n",
|
||||
"num_rankings: %d\n"
|
||||
"ranking entries:\n",
|
||||
rank->adler32,
|
||||
// usb_ser,
|
||||
rank->num_rankings);
|
||||
util_str_format(
|
||||
buffer,
|
||||
512,
|
||||
"adler32: 0x%X\n"
|
||||
// "usb_serial: %s\n",
|
||||
"num_rankings: %d\n"
|
||||
"ranking entries:\n",
|
||||
rank->adler32,
|
||||
// usb_ser,
|
||||
rank->num_rankings);
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NXA_USB_RANK_MAX_RANK_ENTRIES; i++) {
|
||||
for (uint32_t i = 0; i < ASSET_NXA_USB_RANK_MAX_RANK_ENTRIES; i++) {
|
||||
|
||||
for (uint32_t j = 0; j < ASSET_NXA_USB_RANK_MAX_STAGES; j++) {
|
||||
buffer2 = (char*) util_xmalloc(512);
|
||||
memset(buffer2, 0, 512);
|
||||
for (uint32_t j = 0; j < ASSET_NXA_USB_RANK_MAX_STAGES; j++) {
|
||||
buffer2 = (char *) util_xmalloc(512);
|
||||
memset(buffer2, 0, 512);
|
||||
|
||||
util_str_format(buffer2, 512,
|
||||
"%d/%d:\n"
|
||||
"game_mode: %d\n"
|
||||
"play_order: %d\n"
|
||||
"play_score: %d\n"
|
||||
"grade: %d\n"
|
||||
"mileage: %d\n"
|
||||
"play_time: %f\n"
|
||||
"kcal: %f\n"
|
||||
"v02: %f\n",
|
||||
i, j,
|
||||
rank->entries[i][j].game_mode,
|
||||
rank->entries[i][j].play_order,
|
||||
rank->entries[i][j].play_score,
|
||||
rank->entries[i][j].grade,
|
||||
rank->entries[i][j].mileage,
|
||||
rank->entries[i][j].play_time,
|
||||
rank->entries[i][j].kcal,
|
||||
rank->entries[i][j].v02);
|
||||
util_str_format(
|
||||
buffer2,
|
||||
512,
|
||||
"%d/%d:\n"
|
||||
"game_mode: %d\n"
|
||||
"play_order: %d\n"
|
||||
"play_score: %d\n"
|
||||
"grade: %d\n"
|
||||
"mileage: %d\n"
|
||||
"play_time: %f\n"
|
||||
"kcal: %f\n"
|
||||
"v02: %f\n",
|
||||
i,
|
||||
j,
|
||||
rank->entries[i][j].game_mode,
|
||||
rank->entries[i][j].play_order,
|
||||
rank->entries[i][j].play_score,
|
||||
rank->entries[i][j].grade,
|
||||
rank->entries[i][j].mileage,
|
||||
rank->entries[i][j].play_time,
|
||||
rank->entries[i][j].kcal,
|
||||
rank->entries[i][j].v02);
|
||||
|
||||
merged = util_str_merge(buffer, buffer2);
|
||||
merged = util_str_merge(buffer, buffer2);
|
||||
|
||||
free(buffer);
|
||||
free(buffer2);
|
||||
free(buffer);
|
||||
free(buffer2);
|
||||
|
||||
buffer = merged;
|
||||
}
|
||||
buffer = merged;
|
||||
}
|
||||
}
|
||||
|
||||
free(usb_ser);
|
||||
free(usb_ser);
|
||||
|
||||
return buffer;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void asset_nxa_usb_rank_decrypt(uint8_t* buf, size_t len)
|
||||
void asset_nxa_usb_rank_decrypt(uint8_t *buf, size_t len)
|
||||
{
|
||||
for (size_t a = len - 1; a > 0; --a) {
|
||||
buf[a] = (buf[a] ^ buf[a - 1]) + ((a * 1234567) >> 8);
|
||||
}
|
||||
for (size_t a = len - 1; a > 0; --a) {
|
||||
buf[a] = (buf[a] ^ buf[a - 1]) + ((a * 1234567) >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
void asset_nxa_usb_rank_encrypt(uint8_t* buf, size_t len)
|
||||
void asset_nxa_usb_rank_encrypt(uint8_t *buf, size_t len)
|
||||
{
|
||||
for (size_t a = 1; a < len; ++a) {
|
||||
buf[a] = (buf[a] - ((a * 1234567) >> 8)) ^ buf[a - 1];
|
||||
}
|
||||
for (size_t a = 1; a < len; ++a) {
|
||||
buf[a] = (buf[a] - ((a * 1234567) >> 8)) ^ buf[a - 1];
|
||||
}
|
||||
}
|
||||
@@ -5,39 +5,39 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
enum asset_nxa_usb_rank_sizes {
|
||||
ASSET_NXA_USB_RANK_MAX_STAGES = 3,
|
||||
ASSET_NXA_USB_RANK_MAX_RANK_ENTRIES = 256,
|
||||
ASSET_NXA_USB_RANK_USB_SERIAL_LEN = 64,
|
||||
ASSET_NXA_USB_RANK_MAX_STAGES = 3,
|
||||
ASSET_NXA_USB_RANK_MAX_RANK_ENTRIES = 256,
|
||||
ASSET_NXA_USB_RANK_USB_SERIAL_LEN = 64,
|
||||
};
|
||||
|
||||
struct asset_nxa_usb_rank_entry {
|
||||
int32_t game_mode;
|
||||
int32_t play_order;
|
||||
int32_t play_score;
|
||||
int32_t grade;
|
||||
int32_t mileage;
|
||||
float play_time;
|
||||
float kcal;
|
||||
float v02;
|
||||
int32_t game_mode;
|
||||
int32_t play_order;
|
||||
int32_t play_score;
|
||||
int32_t grade;
|
||||
int32_t mileage;
|
||||
float play_time;
|
||||
float kcal;
|
||||
float v02;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_nxa_usb_rank {
|
||||
uint32_t adler32;
|
||||
char usb_serial[ASSET_NXA_USB_RANK_USB_SERIAL_LEN];
|
||||
uint32_t num_rankings;
|
||||
struct asset_nxa_usb_rank_entry
|
||||
entries[ASSET_NXA_USB_RANK_MAX_RANK_ENTRIES][ASSET_NXA_USB_RANK_MAX_STAGES];
|
||||
uint32_t adler32;
|
||||
char usb_serial[ASSET_NXA_USB_RANK_USB_SERIAL_LEN];
|
||||
uint32_t num_rankings;
|
||||
struct asset_nxa_usb_rank_entry entries[ASSET_NXA_USB_RANK_MAX_RANK_ENTRIES]
|
||||
[ASSET_NXA_USB_RANK_MAX_STAGES];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_nxa_usb_rank* asset_nxa_usb_rank_new(void);
|
||||
struct asset_nxa_usb_rank *asset_nxa_usb_rank_new(void);
|
||||
|
||||
// update checksum and prepare profile to get encrypted
|
||||
void asset_nxa_usb_rank_finalize(struct asset_nxa_usb_rank* rank);
|
||||
void asset_nxa_usb_rank_finalize(struct asset_nxa_usb_rank *rank);
|
||||
|
||||
char* asset_nxa_usb_rank_to_string(const struct asset_nxa_usb_rank* rank);
|
||||
char *asset_nxa_usb_rank_to_string(const struct asset_nxa_usb_rank *rank);
|
||||
|
||||
void asset_nxa_usb_rank_decrypt(uint8_t* buf, size_t len);
|
||||
void asset_nxa_usb_rank_decrypt(uint8_t *buf, size_t len);
|
||||
|
||||
void asset_nxa_usb_rank_encrypt(uint8_t* buf, size_t len);
|
||||
void asset_nxa_usb_rank_encrypt(uint8_t *buf, size_t len);
|
||||
|
||||
#endif
|
||||
+410
-381
@@ -8,450 +8,479 @@
|
||||
|
||||
#include "usb-save.h"
|
||||
|
||||
static char* asset_nxa_usb_save_time_to_string(
|
||||
const struct asset_nxa_usb_save_time* time)
|
||||
static char *
|
||||
asset_nxa_usb_save_time_to_string(const struct asset_nxa_usb_save_time *time)
|
||||
{
|
||||
char* buffer;
|
||||
char *buffer;
|
||||
|
||||
buffer = (char*) util_xmalloc(128);
|
||||
memset(buffer, 0, 128);
|
||||
buffer = (char *) util_xmalloc(128);
|
||||
memset(buffer, 0, 128);
|
||||
|
||||
util_str_format(buffer, 128,
|
||||
"year: %d\n"
|
||||
"month: %d\n"
|
||||
"day: %d\n"
|
||||
"hour: %d\n"
|
||||
"min: %d\n"
|
||||
"ms: %d\n",
|
||||
time->year,
|
||||
time->month,
|
||||
time->day,
|
||||
time->hour,
|
||||
time->min,
|
||||
time->ms);
|
||||
util_str_format(
|
||||
buffer,
|
||||
128,
|
||||
"year: %d\n"
|
||||
"month: %d\n"
|
||||
"day: %d\n"
|
||||
"hour: %d\n"
|
||||
"min: %d\n"
|
||||
"ms: %d\n",
|
||||
time->year,
|
||||
time->month,
|
||||
time->day,
|
||||
time->hour,
|
||||
time->min,
|
||||
time->ms);
|
||||
|
||||
return buffer;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static char* asset_nxa_usb_save_review_to_string(
|
||||
const struct asset_nxa_usb_save_review* review)
|
||||
static char *asset_nxa_usb_save_review_to_string(
|
||||
const struct asset_nxa_usb_save_review *review)
|
||||
{
|
||||
char* buffer;
|
||||
char* land;
|
||||
char* mission;
|
||||
char* timestamp;
|
||||
char *buffer;
|
||||
char *land;
|
||||
char *mission;
|
||||
char *timestamp;
|
||||
|
||||
buffer = (char*) util_xmalloc(1024);
|
||||
memset(buffer, 0, 1024);
|
||||
buffer = (char *) util_xmalloc(1024);
|
||||
memset(buffer, 0, 1024);
|
||||
|
||||
land = util_str_buffer((const uint8_t*) review->worldmax_current_land,
|
||||
ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX);
|
||||
mission = util_str_buffer((const uint8_t*) review->worldmax_current_mission,
|
||||
ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX);
|
||||
timestamp = asset_nxa_usb_save_time_to_string(&review->timestamp);
|
||||
land = util_str_buffer(
|
||||
(const uint8_t *) review->worldmax_current_land,
|
||||
ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX);
|
||||
mission = util_str_buffer(
|
||||
(const uint8_t *) review->worldmax_current_mission,
|
||||
ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX);
|
||||
timestamp = asset_nxa_usb_save_time_to_string(&review->timestamp);
|
||||
|
||||
util_str_format(buffer, 1024,
|
||||
">>> review:\n"
|
||||
"player_id: %s\n"
|
||||
"mileage: %d\n"
|
||||
"reward_count: %d\n"
|
||||
"worldmax_count: %d\n"
|
||||
"play_count: %d\n"
|
||||
"worldmax_current_land: %s\n"
|
||||
"worldmax_current_mission: %s\n"
|
||||
"kcal: %d\n"
|
||||
"v02: %d\n",
|
||||
"timestamp: \n%s",
|
||||
"running_step: %d\n",
|
||||
"play_time_minutes: %f\n",
|
||||
"total_completion_percentage: %f\n",
|
||||
"arcade_percentage: %f\n",
|
||||
"brain_shower_percentage: %f\n",
|
||||
"special_percentage: %f\n",
|
||||
review->player_id,
|
||||
review->mileage,
|
||||
review->reward_count,
|
||||
review->worldmax_count,
|
||||
review->play_count,
|
||||
land,
|
||||
mission,
|
||||
review->kcal,
|
||||
review->v02,
|
||||
timestamp,
|
||||
review->running_step,
|
||||
review->play_time_minutes,
|
||||
review->total_completion_percentage,
|
||||
review->arcade_percentage,
|
||||
review->brain_shower_percentage,
|
||||
review->special_percentage);
|
||||
util_str_format(
|
||||
buffer,
|
||||
1024,
|
||||
">>> review:\n"
|
||||
"player_id: %s\n"
|
||||
"mileage: %d\n"
|
||||
"reward_count: %d\n"
|
||||
"worldmax_count: %d\n"
|
||||
"play_count: %d\n"
|
||||
"worldmax_current_land: %s\n"
|
||||
"worldmax_current_mission: %s\n"
|
||||
"kcal: %d\n"
|
||||
"v02: %d\n",
|
||||
"timestamp: \n%s",
|
||||
"running_step: %d\n",
|
||||
"play_time_minutes: %f\n",
|
||||
"total_completion_percentage: %f\n",
|
||||
"arcade_percentage: %f\n",
|
||||
"brain_shower_percentage: %f\n",
|
||||
"special_percentage: %f\n",
|
||||
review->player_id,
|
||||
review->mileage,
|
||||
review->reward_count,
|
||||
review->worldmax_count,
|
||||
review->play_count,
|
||||
land,
|
||||
mission,
|
||||
review->kcal,
|
||||
review->v02,
|
||||
timestamp,
|
||||
review->running_step,
|
||||
review->play_time_minutes,
|
||||
review->total_completion_percentage,
|
||||
review->arcade_percentage,
|
||||
review->brain_shower_percentage,
|
||||
review->special_percentage);
|
||||
|
||||
free(land);
|
||||
free(mission);
|
||||
free(timestamp);
|
||||
free(land);
|
||||
free(mission);
|
||||
free(timestamp);
|
||||
|
||||
return buffer;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static char* asset_nxa_usb_save_stats_to_string(
|
||||
const struct asset_nxa_usb_save_stats* stats)
|
||||
static char *
|
||||
asset_nxa_usb_save_stats_to_string(const struct asset_nxa_usb_save_stats *stats)
|
||||
{
|
||||
char* merged;
|
||||
char* buffer;
|
||||
char* timestamp;
|
||||
char* tmp;
|
||||
char* tmp2;
|
||||
const size_t buf_size = 16384;
|
||||
char *merged;
|
||||
char *buffer;
|
||||
char *timestamp;
|
||||
char *tmp;
|
||||
char *tmp2;
|
||||
const size_t buf_size = 16384;
|
||||
|
||||
merged = (char*) util_xmalloc(buf_size);
|
||||
memset(merged, 0, buf_size);
|
||||
merged = (char *) util_xmalloc(buf_size);
|
||||
memset(merged, 0, buf_size);
|
||||
|
||||
buffer = (char*) util_xmalloc(buf_size);
|
||||
memset(buffer, 0, buf_size);
|
||||
buffer = (char *) util_xmalloc(buf_size);
|
||||
memset(buffer, 0, buf_size);
|
||||
|
||||
timestamp = asset_nxa_usb_save_time_to_string(&stats->timestamp);
|
||||
timestamp = asset_nxa_usb_save_time_to_string(&stats->timestamp);
|
||||
|
||||
util_str_format(merged, buf_size,
|
||||
">>> stats:\n"
|
||||
"adler32: 0x%X\n"
|
||||
"usb_serial: %s\n"
|
||||
"timestamp: %s"
|
||||
"avatar_id: %d\n"
|
||||
"rank: %d\n"
|
||||
"country_id: %d\n"
|
||||
"player_id: %s\n"
|
||||
"mileage: %d\n"
|
||||
"play_count: %d\n"
|
||||
"kcal: %d\n"
|
||||
"v02: %d\n"
|
||||
"worldmax_map_position: 0x%X\n"
|
||||
"reward_count: %d\n"
|
||||
"worldmax_count: %d\n",
|
||||
stats->adler32,
|
||||
stats->usb_serial,
|
||||
timestamp,
|
||||
stats->avatar_id,
|
||||
stats->rank,
|
||||
stats->country_id,
|
||||
stats->player_id,
|
||||
stats->mileage,
|
||||
stats->play_count,
|
||||
stats->kcal,
|
||||
stats->v02,
|
||||
stats->worldmax_map_position,
|
||||
stats->reward_count,
|
||||
stats->worldmax_count);
|
||||
util_str_format(
|
||||
merged,
|
||||
buf_size,
|
||||
">>> stats:\n"
|
||||
"adler32: 0x%X\n"
|
||||
"usb_serial: %s\n"
|
||||
"timestamp: %s"
|
||||
"avatar_id: %d\n"
|
||||
"rank: %d\n"
|
||||
"country_id: %d\n"
|
||||
"player_id: %s\n"
|
||||
"mileage: %d\n"
|
||||
"play_count: %d\n"
|
||||
"kcal: %d\n"
|
||||
"v02: %d\n"
|
||||
"worldmax_map_position: 0x%X\n"
|
||||
"reward_count: %d\n"
|
||||
"worldmax_count: %d\n",
|
||||
stats->adler32,
|
||||
stats->usb_serial,
|
||||
timestamp,
|
||||
stats->avatar_id,
|
||||
stats->rank,
|
||||
stats->country_id,
|
||||
stats->player_id,
|
||||
stats->mileage,
|
||||
stats->play_count,
|
||||
stats->kcal,
|
||||
stats->v02,
|
||||
stats->worldmax_map_position,
|
||||
stats->reward_count,
|
||||
stats->worldmax_count);
|
||||
|
||||
free(timestamp);
|
||||
free(timestamp);
|
||||
|
||||
tmp = util_str_merge(merged, "song_unlocks:\n");
|
||||
tmp = util_str_merge(merged, "song_unlocks:\n");
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_SONG_MAX; i++) {
|
||||
for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_SONG_MAX; i++) {
|
||||
|
||||
util_str_format(buffer, buf_size,
|
||||
"song slot: %d\n"
|
||||
"mode: 0x%X\n"
|
||||
"unused: 0x%X\n"
|
||||
"song: %d\n"
|
||||
"reveal: %d\n",
|
||||
i,
|
||||
stats->song_unlocks[i].mode,
|
||||
stats->song_unlocks[i].unused,
|
||||
stats->song_unlocks[i].song,
|
||||
stats->song_unlocks[i].reveal);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_MISSION_MAX; i++) {
|
||||
|
||||
util_str_format(buffer, buf_size,
|
||||
"mission slot: %d\n"
|
||||
"clear_flags_directions: 0x%X\n"
|
||||
"clear_flag_mission: %d\n"
|
||||
"unused: 0x%X\n",
|
||||
i,
|
||||
stats->worldmax_mission_unlocks[i].clear_flags_directions,
|
||||
stats->worldmax_mission_unlocks[i].clear_flag_mission,
|
||||
stats->worldmax_mission_unlocks[i].unused);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_MISSION_MAX; i++) {
|
||||
|
||||
util_str_format(buffer, buf_size,
|
||||
"worldmax_high_score %d: %d\n",
|
||||
i,
|
||||
stats->worldmax_high_score[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_MISSION_MAX; i++) {
|
||||
|
||||
util_str_format(buffer, buf_size,
|
||||
"worldmax_challenge %d: %d\n",
|
||||
i,
|
||||
stats->worldmax_challenge[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_BARRICADE_MAX; i++) {
|
||||
|
||||
util_str_format(buffer, buf_size,
|
||||
"worldmax_barricade %d:\n"
|
||||
"flag_open: %d\n"
|
||||
"unused: 0x%X\n",
|
||||
i,
|
||||
stats->worldmax_barricade[i].flag_open,
|
||||
stats->worldmax_barricade[i].unused);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_EVENT_MAX; i++) {
|
||||
|
||||
util_str_format(buffer, buf_size,
|
||||
"worldmax_event %d:\n"
|
||||
"flag_cleared: %d\n"
|
||||
"unused: 0x%X\n",
|
||||
i,
|
||||
stats->worldmax_event[i].flag_cleared,
|
||||
stats->worldmax_event[i].unused);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_WARP_MAX; i++) {
|
||||
|
||||
util_str_format(buffer, buf_size,
|
||||
"worldmax_warp %d:\n"
|
||||
"direction_clear: 0x%X\n"
|
||||
"clear: %d\n",
|
||||
"unused: 0x%X\n",
|
||||
i,
|
||||
stats->worldmax_warp[i].direction_clear,
|
||||
stats->worldmax_warp[i].clear,
|
||||
stats->worldmax_warp[i].unused);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX; i++) {
|
||||
|
||||
util_str_format(buffer, buf_size,
|
||||
"worldmax_current_land %d: %d\n",
|
||||
i,
|
||||
stats->worldmax_current_land[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX; i++) {
|
||||
|
||||
util_str_format(buffer, buf_size,
|
||||
"worldmax_current_mission %d: %d\n",
|
||||
i,
|
||||
stats->worldmax_current_mission[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_SONG_MAX; i++) {
|
||||
|
||||
for (uint32_t j = 0; j < ASSET_NXA_USB_SAVE_NUM_MODES; j++) {
|
||||
util_str_format(buffer, buf_size,
|
||||
"song_scores %d/%d:\n"
|
||||
"score: %d\n"
|
||||
"player_id: %s\n",
|
||||
i,
|
||||
j,
|
||||
stats->song_scores[i][j].score,
|
||||
stats->song_scores[i][j].player_id);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------- */
|
||||
util_str_format(buffer, buf_size,
|
||||
"security_dongle_mfgid 0x%X\n"
|
||||
"unlock_signal: 0x%X\n"
|
||||
"running_steps: %d\n"
|
||||
"total_play_time_min: %f\n"
|
||||
"total_completion_percentage: %f\n"
|
||||
"arcade_completion_percentage: %f\n"
|
||||
"brain_shower_completion_percentage: %f\n"
|
||||
"special_stage_completion_percentage: %f\n",
|
||||
stats->security_dongle_mfgid,
|
||||
stats->unlock_signal,
|
||||
stats->running_steps,
|
||||
stats->total_play_time_min,
|
||||
stats->total_completion_percentage,
|
||||
stats->arcade_completion_percentage,
|
||||
stats->brain_shower_completion_percentage,
|
||||
stats->special_stage_completion_percentage);
|
||||
util_str_format(
|
||||
buffer,
|
||||
buf_size,
|
||||
"song slot: %d\n"
|
||||
"mode: 0x%X\n"
|
||||
"unused: 0x%X\n"
|
||||
"song: %d\n"
|
||||
"reveal: %d\n",
|
||||
i,
|
||||
stats->song_unlocks[i].mode,
|
||||
stats->song_unlocks[i].unused,
|
||||
stats->song_unlocks[i].song,
|
||||
stats->song_unlocks[i].reveal);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
/* ------------- */
|
||||
tmp2 = util_str_buffer(stats->unkn_some_map_scores_to_song_ids,
|
||||
4096);
|
||||
for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_MISSION_MAX; i++) {
|
||||
|
||||
util_str_format(buffer, buf_size,
|
||||
"unkn_some_map_scores_to_song_ids: %s\n",
|
||||
tmp2);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(tmp2);
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
|
||||
/* ------------- */
|
||||
tmp2 = util_str_buffer(stats->unkn2, sizeof(stats->unkn2));
|
||||
|
||||
util_str_format(buffer, buf_size,
|
||||
"unkn2: %s\n",
|
||||
tmp2);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(tmp2);
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
|
||||
/* ------------- */
|
||||
util_str_format(buffer, buf_size,
|
||||
"break_item_slot 0x%X\n"
|
||||
"func_item_slot: 0x%X\n"
|
||||
"bga_item_slot: 0x%X\n"
|
||||
"time_item_slot: 0x%X\n"
|
||||
"unknown: 0x%X\n",
|
||||
stats->break_item_slot,
|
||||
stats->func_item_slot,
|
||||
stats->bga_item_slot,
|
||||
stats->time_item_slot,
|
||||
stats->unknown);
|
||||
util_str_format(
|
||||
buffer,
|
||||
buf_size,
|
||||
"mission slot: %d\n"
|
||||
"clear_flags_directions: 0x%X\n"
|
||||
"clear_flag_mission: %d\n"
|
||||
"unused: 0x%X\n",
|
||||
i,
|
||||
stats->worldmax_mission_unlocks[i].clear_flags_directions,
|
||||
stats->worldmax_mission_unlocks[i].clear_flag_mission,
|
||||
stats->worldmax_mission_unlocks[i].unused);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_MISSION_MAX; i++) {
|
||||
|
||||
return merged;
|
||||
util_str_format(
|
||||
buffer,
|
||||
buf_size,
|
||||
"worldmax_high_score %d: %d\n",
|
||||
i,
|
||||
stats->worldmax_high_score[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_MISSION_MAX; i++) {
|
||||
|
||||
util_str_format(
|
||||
buffer,
|
||||
buf_size,
|
||||
"worldmax_challenge %d: %d\n",
|
||||
i,
|
||||
stats->worldmax_challenge[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_BARRICADE_MAX; i++) {
|
||||
|
||||
util_str_format(
|
||||
buffer,
|
||||
buf_size,
|
||||
"worldmax_barricade %d:\n"
|
||||
"flag_open: %d\n"
|
||||
"unused: 0x%X\n",
|
||||
i,
|
||||
stats->worldmax_barricade[i].flag_open,
|
||||
stats->worldmax_barricade[i].unused);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_EVENT_MAX; i++) {
|
||||
|
||||
util_str_format(
|
||||
buffer,
|
||||
buf_size,
|
||||
"worldmax_event %d:\n"
|
||||
"flag_cleared: %d\n"
|
||||
"unused: 0x%X\n",
|
||||
i,
|
||||
stats->worldmax_event[i].flag_cleared,
|
||||
stats->worldmax_event[i].unused);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_WARP_MAX; i++) {
|
||||
|
||||
util_str_format(
|
||||
buffer,
|
||||
buf_size,
|
||||
"worldmax_warp %d:\n"
|
||||
"direction_clear: 0x%X\n"
|
||||
"clear: %d\n",
|
||||
"unused: 0x%X\n",
|
||||
i,
|
||||
stats->worldmax_warp[i].direction_clear,
|
||||
stats->worldmax_warp[i].clear,
|
||||
stats->worldmax_warp[i].unused);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX; i++) {
|
||||
|
||||
util_str_format(
|
||||
buffer,
|
||||
buf_size,
|
||||
"worldmax_current_land %d: %d\n",
|
||||
i,
|
||||
stats->worldmax_current_land[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX; i++) {
|
||||
|
||||
util_str_format(
|
||||
buffer,
|
||||
buf_size,
|
||||
"worldmax_current_mission %d: %d\n",
|
||||
i,
|
||||
stats->worldmax_current_mission[i]);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ASSET_NXA_USB_SAVE_SONG_MAX; i++) {
|
||||
|
||||
for (uint32_t j = 0; j < ASSET_NXA_USB_SAVE_NUM_MODES; j++) {
|
||||
util_str_format(
|
||||
buffer,
|
||||
buf_size,
|
||||
"song_scores %d/%d:\n"
|
||||
"score: %d\n"
|
||||
"player_id: %s\n",
|
||||
i,
|
||||
j,
|
||||
stats->song_scores[i][j].score,
|
||||
stats->song_scores[i][j].player_id);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------- */
|
||||
util_str_format(
|
||||
buffer,
|
||||
buf_size,
|
||||
"security_dongle_mfgid 0x%X\n"
|
||||
"unlock_signal: 0x%X\n"
|
||||
"running_steps: %d\n"
|
||||
"total_play_time_min: %f\n"
|
||||
"total_completion_percentage: %f\n"
|
||||
"arcade_completion_percentage: %f\n"
|
||||
"brain_shower_completion_percentage: %f\n"
|
||||
"special_stage_completion_percentage: %f\n",
|
||||
stats->security_dongle_mfgid,
|
||||
stats->unlock_signal,
|
||||
stats->running_steps,
|
||||
stats->total_play_time_min,
|
||||
stats->total_completion_percentage,
|
||||
stats->arcade_completion_percentage,
|
||||
stats->brain_shower_completion_percentage,
|
||||
stats->special_stage_completion_percentage);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
|
||||
/* ------------- */
|
||||
tmp2 = util_str_buffer(stats->unkn_some_map_scores_to_song_ids, 4096);
|
||||
|
||||
util_str_format(
|
||||
buffer, buf_size, "unkn_some_map_scores_to_song_ids: %s\n", tmp2);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(tmp2);
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
|
||||
/* ------------- */
|
||||
tmp2 = util_str_buffer(stats->unkn2, sizeof(stats->unkn2));
|
||||
|
||||
util_str_format(buffer, buf_size, "unkn2: %s\n", tmp2);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(tmp2);
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
|
||||
/* ------------- */
|
||||
util_str_format(
|
||||
buffer,
|
||||
buf_size,
|
||||
"break_item_slot 0x%X\n"
|
||||
"func_item_slot: 0x%X\n"
|
||||
"bga_item_slot: 0x%X\n"
|
||||
"time_item_slot: 0x%X\n"
|
||||
"unknown: 0x%X\n",
|
||||
stats->break_item_slot,
|
||||
stats->func_item_slot,
|
||||
stats->bga_item_slot,
|
||||
stats->time_item_slot,
|
||||
stats->unknown);
|
||||
|
||||
tmp = util_str_merge(merged, buffer);
|
||||
|
||||
free(merged);
|
||||
merged = tmp;
|
||||
|
||||
free(buffer);
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
struct asset_nxa_usb_save* asset_nxa_usb_save_new(void)
|
||||
struct asset_nxa_usb_save *asset_nxa_usb_save_new(void)
|
||||
{
|
||||
struct asset_nxa_usb_save* save;
|
||||
char name[10];
|
||||
struct asset_nxa_usb_save *save;
|
||||
char name[10];
|
||||
|
||||
save = (struct asset_nxa_usb_save*) util_xmalloc(
|
||||
sizeof(struct asset_nxa_usb_save));
|
||||
save = (struct asset_nxa_usb_save *) util_xmalloc(
|
||||
sizeof(struct asset_nxa_usb_save));
|
||||
|
||||
memset(save, 0, sizeof(struct asset_nxa_usb_save));
|
||||
memset(save, 0, sizeof(struct asset_nxa_usb_save));
|
||||
|
||||
sprintf(name, "NX%06d", rand() % 1000000);
|
||||
strcpy(save->review.player_id, name);
|
||||
strcpy(save->stats.player_id, name);
|
||||
sprintf(name, "NX%06d", rand() % 1000000);
|
||||
strcpy(save->review.player_id, name);
|
||||
strcpy(save->stats.player_id, name);
|
||||
|
||||
/* default world map position */
|
||||
save->stats.worldmax_map_position = 0xEF001;
|
||||
/* default world map position */
|
||||
save->stats.worldmax_map_position = 0xEF001;
|
||||
|
||||
/* nxa release date as default timestamp */
|
||||
save->stats.timestamp.year = 2008;
|
||||
save->stats.timestamp.month = 12;
|
||||
save->stats.timestamp.day = 26;
|
||||
save->stats.timestamp.hour = 0;
|
||||
save->stats.timestamp.min = 0;
|
||||
save->stats.timestamp.ms = 0;
|
||||
/* nxa release date as default timestamp */
|
||||
save->stats.timestamp.year = 2008;
|
||||
save->stats.timestamp.month = 12;
|
||||
save->stats.timestamp.day = 26;
|
||||
save->stats.timestamp.hour = 0;
|
||||
save->stats.timestamp.min = 0;
|
||||
save->stats.timestamp.ms = 0;
|
||||
|
||||
return save;
|
||||
return save;
|
||||
}
|
||||
|
||||
void asset_nxa_usb_save_finalize(struct asset_nxa_usb_save* save)
|
||||
void asset_nxa_usb_save_finalize(struct asset_nxa_usb_save *save)
|
||||
{
|
||||
/* checksum update, expected size for area to checksum: 90540 */
|
||||
save->stats.adler32 = util_adler32_calc(1,
|
||||
((const uint8_t*) &save->stats) + 4,
|
||||
sizeof(struct asset_nxa_usb_save_stats) - 4);
|
||||
/* checksum update, expected size for area to checksum: 90540 */
|
||||
save->stats.adler32 = util_adler32_calc(
|
||||
1,
|
||||
((const uint8_t *) &save->stats) + 4,
|
||||
sizeof(struct asset_nxa_usb_save_stats) - 4);
|
||||
}
|
||||
|
||||
char* asset_nxa_usb_save_to_string(const struct asset_nxa_usb_save* save)
|
||||
char *asset_nxa_usb_save_to_string(const struct asset_nxa_usb_save *save)
|
||||
{
|
||||
char* review;
|
||||
char* stats;
|
||||
char* merged;
|
||||
char *review;
|
||||
char *stats;
|
||||
char *merged;
|
||||
|
||||
review = asset_nxa_usb_save_review_to_string(&save->review);
|
||||
stats = asset_nxa_usb_save_stats_to_string(&save->stats);
|
||||
review = asset_nxa_usb_save_review_to_string(&save->review);
|
||||
stats = asset_nxa_usb_save_stats_to_string(&save->stats);
|
||||
|
||||
merged = util_str_merge(review, stats);
|
||||
merged = util_str_merge(review, stats);
|
||||
|
||||
free(review);
|
||||
free(stats);
|
||||
free(review);
|
||||
free(stats);
|
||||
|
||||
return merged;
|
||||
return merged;
|
||||
}
|
||||
|
||||
void asset_nxa_usb_save_decrypt(uint8_t* buf, size_t len)
|
||||
void asset_nxa_usb_save_decrypt(uint8_t *buf, size_t len)
|
||||
{
|
||||
/* skip non encrypted review area */
|
||||
buf += sizeof(struct asset_nxa_usb_save_review);
|
||||
len -= sizeof(struct asset_nxa_usb_save_review);
|
||||
/* skip non encrypted review area */
|
||||
buf += sizeof(struct asset_nxa_usb_save_review);
|
||||
len -= sizeof(struct asset_nxa_usb_save_review);
|
||||
|
||||
for (size_t a = len - 1; a > 0; --a) {
|
||||
buf[a] = (buf[a] ^ buf[a - 1]) + ((a * 1234567) >> 8);
|
||||
}
|
||||
for (size_t a = len - 1; a > 0; --a) {
|
||||
buf[a] = (buf[a] ^ buf[a - 1]) + ((a * 1234567) >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
void asset_nxa_usb_save_encrypt(uint8_t* buf, size_t len)
|
||||
void asset_nxa_usb_save_encrypt(uint8_t *buf, size_t len)
|
||||
{
|
||||
/* skip non encrypted review area */
|
||||
buf += sizeof(struct asset_nxa_usb_save_review);
|
||||
len -= sizeof(struct asset_nxa_usb_save_review);
|
||||
/* skip non encrypted review area */
|
||||
buf += sizeof(struct asset_nxa_usb_save_review);
|
||||
len -= sizeof(struct asset_nxa_usb_save_review);
|
||||
|
||||
for (size_t a = 1; a < len; ++a) {
|
||||
buf[a] = (buf[a] - ((a * 1234567) >> 8)) ^ buf[a - 1];
|
||||
}
|
||||
for (size_t a = 1; a < len; ++a) {
|
||||
buf[a] = (buf[a] - ((a * 1234567) >> 8)) ^ buf[a - 1];
|
||||
}
|
||||
}
|
||||
+217
-216
@@ -5,271 +5,272 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
enum asset_nxa_usb_save_limits {
|
||||
ASSET_NXA_USB_SAVE_SERIAL_ID_MAX = 64,
|
||||
ASSET_NXA_USB_SAVE_PLAYER_ID_MAX = 12,
|
||||
ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX = 128,
|
||||
ASSET_NXA_USB_SAVE_SONG_MAX = 256,
|
||||
ASSET_NXA_USB_SAVE_MISSION_MAX = 1024,
|
||||
ASSET_NXA_USB_SAVE_BARRICADE_MAX = 16,
|
||||
ASSET_NXA_USB_SAVE_EVENT_MAX = 128,
|
||||
ASSET_NXA_USB_SAVE_WARP_MAX = 8,
|
||||
ASSET_NXA_USB_SAVE_NUM_MODES = 5,
|
||||
ASSET_NXA_USB_SAVE_SERIAL_ID_MAX = 64,
|
||||
ASSET_NXA_USB_SAVE_PLAYER_ID_MAX = 12,
|
||||
ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX = 128,
|
||||
ASSET_NXA_USB_SAVE_SONG_MAX = 256,
|
||||
ASSET_NXA_USB_SAVE_MISSION_MAX = 1024,
|
||||
ASSET_NXA_USB_SAVE_BARRICADE_MAX = 16,
|
||||
ASSET_NXA_USB_SAVE_EVENT_MAX = 128,
|
||||
ASSET_NXA_USB_SAVE_WARP_MAX = 8,
|
||||
ASSET_NXA_USB_SAVE_NUM_MODES = 5,
|
||||
};
|
||||
|
||||
struct asset_nxa_usb_save_time {
|
||||
int16_t year;
|
||||
uint8_t month;
|
||||
uint8_t day;
|
||||
uint8_t hour;
|
||||
uint8_t min;
|
||||
uint16_t ms;
|
||||
int16_t year;
|
||||
uint8_t month;
|
||||
uint8_t day;
|
||||
uint8_t hour;
|
||||
uint8_t min;
|
||||
uint16_t ms;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* Not encrypted and read only, offset 0x00 to 0x144 (excl) */
|
||||
struct asset_nxa_usb_save_review {
|
||||
/* 0x00, 12 byte char array: max char length is 8 which gets displayed
|
||||
ingame */
|
||||
char player_id[ASSET_NXA_USB_SAVE_PLAYER_ID_MAX];
|
||||
/* 0x0C, 4 byte int */
|
||||
uint32_t mileage;
|
||||
/* 0x10, 4 byte int: achieved reward count, max 65 */
|
||||
uint32_t reward_count;
|
||||
/* 0x14, 4 byte int: successful mission count, max 634 */
|
||||
uint32_t worldmax_count;
|
||||
/* 0x18, 4 byte int */
|
||||
uint32_t play_count;
|
||||
/* 0x1C, 128 byte char array */
|
||||
char worldmax_current_land[ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX];
|
||||
/* 0x9C, 128 byte char array */
|
||||
char worldmax_current_mission[ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX];
|
||||
/* 0x11C, 4 byte int */
|
||||
uint32_t kcal;
|
||||
/* 0x120, 4 byte int */
|
||||
uint32_t v02;
|
||||
/* 0x124, 8 byte */
|
||||
struct asset_nxa_usb_save_time timestamp;
|
||||
/* 0x12C, 4 byte int */
|
||||
uint32_t running_step;
|
||||
/* 0x130, 4 byte float */
|
||||
float play_time_minutes;
|
||||
/* 0x134, 4 byte float */
|
||||
float total_completion_percentage;
|
||||
/* 0x138, 4 byte float */
|
||||
float arcade_percentage;
|
||||
/* 0x13C, 4 byte float */
|
||||
float brain_shower_percentage;
|
||||
/* 0x140, 4 byte float */
|
||||
float special_percentage;
|
||||
/* 0x00, 12 byte char array: max char length is 8 which gets displayed
|
||||
ingame */
|
||||
char player_id[ASSET_NXA_USB_SAVE_PLAYER_ID_MAX];
|
||||
/* 0x0C, 4 byte int */
|
||||
uint32_t mileage;
|
||||
/* 0x10, 4 byte int: achieved reward count, max 65 */
|
||||
uint32_t reward_count;
|
||||
/* 0x14, 4 byte int: successful mission count, max 634 */
|
||||
uint32_t worldmax_count;
|
||||
/* 0x18, 4 byte int */
|
||||
uint32_t play_count;
|
||||
/* 0x1C, 128 byte char array */
|
||||
char worldmax_current_land[ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX];
|
||||
/* 0x9C, 128 byte char array */
|
||||
char worldmax_current_mission[ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX];
|
||||
/* 0x11C, 4 byte int */
|
||||
uint32_t kcal;
|
||||
/* 0x120, 4 byte int */
|
||||
uint32_t v02;
|
||||
/* 0x124, 8 byte */
|
||||
struct asset_nxa_usb_save_time timestamp;
|
||||
/* 0x12C, 4 byte int */
|
||||
uint32_t running_step;
|
||||
/* 0x130, 4 byte float */
|
||||
float play_time_minutes;
|
||||
/* 0x134, 4 byte float */
|
||||
float total_completion_percentage;
|
||||
/* 0x138, 4 byte float */
|
||||
float arcade_percentage;
|
||||
/* 0x13C, 4 byte float */
|
||||
float brain_shower_percentage;
|
||||
/* 0x140, 4 byte float */
|
||||
float special_percentage;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_nxa_usb_save_stats {
|
||||
/* 0x144, 4 byte int */
|
||||
uint32_t adler32;
|
||||
/* 0x148, 64 byte */
|
||||
char usb_serial[ASSET_NXA_USB_SAVE_SERIAL_ID_MAX];
|
||||
/* 0x188, 8 byte */
|
||||
struct asset_nxa_usb_save_time timestamp;
|
||||
/* 0x190, 4 byte int */
|
||||
int32_t avatar_id;
|
||||
/* 0x194, 4 byte int: setting this non null will give you a trophy */
|
||||
int32_t rank;
|
||||
/* 0x198, 4 byte int: seems unused */
|
||||
int32_t country_id;
|
||||
/* 0x19C, 12 byte char array */
|
||||
char player_id[ASSET_NXA_USB_SAVE_PLAYER_ID_MAX];
|
||||
/* 0x1A8, 4 byte int */
|
||||
int32_t mileage;
|
||||
/* 0x1AD, 4 byte int */
|
||||
int32_t play_count;
|
||||
/* 0x1B0, 4 byte int */
|
||||
int32_t kcal;
|
||||
/* 0x1B4, 4 byte int */
|
||||
int32_t v02;
|
||||
/* 0x1B8, 4 byte int */
|
||||
int32_t worldmax_map_position;
|
||||
/* 0x1BC, 4 byte int: achieved reward count, max 65 */
|
||||
int32_t reward_count;
|
||||
/* 0x1C0, 4 byte int: successful mission count, max 634 */
|
||||
int32_t worldmax_count;
|
||||
/* 0x144, 4 byte int */
|
||||
uint32_t adler32;
|
||||
/* 0x148, 64 byte */
|
||||
char usb_serial[ASSET_NXA_USB_SAVE_SERIAL_ID_MAX];
|
||||
/* 0x188, 8 byte */
|
||||
struct asset_nxa_usb_save_time timestamp;
|
||||
/* 0x190, 4 byte int */
|
||||
int32_t avatar_id;
|
||||
/* 0x194, 4 byte int: setting this non null will give you a trophy */
|
||||
int32_t rank;
|
||||
/* 0x198, 4 byte int: seems unused */
|
||||
int32_t country_id;
|
||||
/* 0x19C, 12 byte char array */
|
||||
char player_id[ASSET_NXA_USB_SAVE_PLAYER_ID_MAX];
|
||||
/* 0x1A8, 4 byte int */
|
||||
int32_t mileage;
|
||||
/* 0x1AD, 4 byte int */
|
||||
int32_t play_count;
|
||||
/* 0x1B0, 4 byte int */
|
||||
int32_t kcal;
|
||||
/* 0x1B4, 4 byte int */
|
||||
int32_t v02;
|
||||
/* 0x1B8, 4 byte int */
|
||||
int32_t worldmax_map_position;
|
||||
/* 0x1BC, 4 byte int: achieved reward count, max 65 */
|
||||
int32_t reward_count;
|
||||
/* 0x1C0, 4 byte int: successful mission count, max 634 */
|
||||
int32_t worldmax_count;
|
||||
|
||||
/* 0x1C4, 256 bytes */
|
||||
struct {
|
||||
/* bits 0-4 for modes/stepcharts */
|
||||
uint8_t mode : 5;
|
||||
/* unused bit */
|
||||
uint8_t unused : 1;
|
||||
/* bit 6 song itself */
|
||||
uint8_t song : 1;
|
||||
/* bit 7 reveal flag */
|
||||
uint8_t reveal : 1;
|
||||
} song_unlocks[ASSET_NXA_USB_SAVE_SONG_MAX] __attribute__((__packed__));
|
||||
/* 0x1C4, 256 bytes */
|
||||
struct {
|
||||
/* bits 0-4 for modes/stepcharts */
|
||||
uint8_t mode : 5;
|
||||
/* unused bit */
|
||||
uint8_t unused : 1;
|
||||
/* bit 6 song itself */
|
||||
uint8_t song : 1;
|
||||
/* bit 7 reveal flag */
|
||||
uint8_t reveal : 1;
|
||||
} song_unlocks[ASSET_NXA_USB_SAVE_SONG_MAX] __attribute__((__packed__));
|
||||
|
||||
/* 0x2C4, 1024 bytes */
|
||||
struct {
|
||||
uint8_t clear_flags_directions : 4;
|
||||
uint8_t clear_flag_mission : 1;
|
||||
uint8_t unused : 3;
|
||||
} worldmax_mission_unlocks[ASSET_NXA_USB_SAVE_MISSION_MAX]
|
||||
__attribute__((__packed__));
|
||||
/* 0x2C4, 1024 bytes */
|
||||
struct {
|
||||
uint8_t clear_flags_directions : 4;
|
||||
uint8_t clear_flag_mission : 1;
|
||||
uint8_t unused : 3;
|
||||
} worldmax_mission_unlocks[ASSET_NXA_USB_SAVE_MISSION_MAX]
|
||||
__attribute__((__packed__));
|
||||
|
||||
/* 0x6C4, 4 byte int * 1024: high score for each mission */
|
||||
int32_t worldmax_high_score[ASSET_NXA_USB_SAVE_MISSION_MAX];
|
||||
/* 0x6C4, 4 byte int * 1024: high score for each mission */
|
||||
int32_t worldmax_high_score[ASSET_NXA_USB_SAVE_MISSION_MAX];
|
||||
|
||||
/* 0x16C4, 4 byte int * 1024 */
|
||||
int32_t worldmax_challenge[ASSET_NXA_USB_SAVE_MISSION_MAX];
|
||||
/* 0x16C4, 4 byte int * 1024 */
|
||||
int32_t worldmax_challenge[ASSET_NXA_USB_SAVE_MISSION_MAX];
|
||||
|
||||
/* 0x26C4, 16 bytes
|
||||
0x00 for barricade clear and 0x01 for block */
|
||||
struct {
|
||||
uint8_t flag_open : 1;
|
||||
uint8_t unused : 7;
|
||||
} worldmax_barricade[ASSET_NXA_USB_SAVE_BARRICADE_MAX]
|
||||
__attribute__((__packed__));
|
||||
/* 0x26C4, 16 bytes
|
||||
0x00 for barricade clear and 0x01 for block */
|
||||
struct {
|
||||
uint8_t flag_open : 1;
|
||||
uint8_t unused : 7;
|
||||
} worldmax_barricade[ASSET_NXA_USB_SAVE_BARRICADE_MAX]
|
||||
__attribute__((__packed__));
|
||||
|
||||
/* 0x26D4, 128 bytes
|
||||
0x00 for event clear and 0x01 for not cleared */
|
||||
struct {
|
||||
uint8_t flag_cleared : 1;
|
||||
uint8_t unused : 7;
|
||||
} worldmax_event[ASSET_NXA_USB_SAVE_EVENT_MAX] __attribute__((__packed__));
|
||||
/* 0x26D4, 128 bytes
|
||||
0x00 for event clear and 0x01 for not cleared */
|
||||
struct {
|
||||
uint8_t flag_cleared : 1;
|
||||
uint8_t unused : 7;
|
||||
} worldmax_event[ASSET_NXA_USB_SAVE_EVENT_MAX] __attribute__((__packed__));
|
||||
|
||||
/* 0x2754, 8 bytes
|
||||
bit 0~3: clear bit for each direction bit:4 clear */
|
||||
struct {
|
||||
uint8_t direction_clear : 4;
|
||||
uint8_t clear : 1;
|
||||
uint8_t unused : 3;
|
||||
} worldmax_warp[ASSET_NXA_USB_SAVE_WARP_MAX] __attribute__((__packed__));
|
||||
/* 0x2754, 8 bytes
|
||||
bit 0~3: clear bit for each direction bit:4 clear */
|
||||
struct {
|
||||
uint8_t direction_clear : 4;
|
||||
uint8_t clear : 1;
|
||||
uint8_t unused : 3;
|
||||
} worldmax_warp[ASSET_NXA_USB_SAVE_WARP_MAX] __attribute__((__packed__));
|
||||
|
||||
/* 0x275C, 128 byte char array */
|
||||
char worldmax_current_land[ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX];
|
||||
/* 0x275C, 128 byte char array */
|
||||
char worldmax_current_land[ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX];
|
||||
|
||||
/* 0x27DC, 128 byte char array */
|
||||
char worldmax_current_mission[ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX];
|
||||
/* 0x27DC, 128 byte char array */
|
||||
char worldmax_current_mission[ASSET_NXA_USB_SAVE_WORLDMAX_LOC_MAX];
|
||||
|
||||
/* 0x285C */
|
||||
struct {
|
||||
int32_t score;
|
||||
char player_id[ASSET_NXA_USB_SAVE_PLAYER_ID_MAX];
|
||||
} song_scores[ASSET_NXA_USB_SAVE_SONG_MAX][ASSET_NXA_USB_SAVE_NUM_MODES]
|
||||
__attribute__((__packed__));
|
||||
/* 0x285C */
|
||||
struct {
|
||||
int32_t score;
|
||||
char player_id[ASSET_NXA_USB_SAVE_PLAYER_ID_MAX];
|
||||
} song_scores[ASSET_NXA_USB_SAVE_SONG_MAX][ASSET_NXA_USB_SAVE_NUM_MODES]
|
||||
__attribute__((__packed__));
|
||||
|
||||
/* 0x785C, 4 byte int */
|
||||
uint32_t security_dongle_mfgid;
|
||||
/* 0x785C, 4 byte int */
|
||||
uint32_t security_dongle_mfgid;
|
||||
|
||||
/* 0x7860, 4 byte int: <=3 Tells game to unlock new song */
|
||||
uint32_t unlock_signal;
|
||||
/* 0x7860, 4 byte int: <=3 Tells game to unlock new song */
|
||||
uint32_t unlock_signal;
|
||||
|
||||
/* 0x7864, 4 byte int */
|
||||
uint32_t running_steps;
|
||||
/* 0x7864, 4 byte int */
|
||||
uint32_t running_steps;
|
||||
|
||||
/* 0x7868, 4 byte float */
|
||||
float total_play_time_min;
|
||||
/* 0x7868, 4 byte float */
|
||||
float total_play_time_min;
|
||||
|
||||
/* 0x786C, 4 byte float */
|
||||
float total_completion_percentage;
|
||||
/* 0x786C, 4 byte float */
|
||||
float total_completion_percentage;
|
||||
|
||||
/* 0x7870, 4 byte float */
|
||||
float arcade_completion_percentage;
|
||||
/* 0x7870, 4 byte float */
|
||||
float arcade_completion_percentage;
|
||||
|
||||
/* 0x7874, 4 byte float */
|
||||
float brain_shower_completion_percentage;
|
||||
/* 0x7874, 4 byte float */
|
||||
float brain_shower_completion_percentage;
|
||||
|
||||
/* 0x7878, 4 byte float */
|
||||
float special_stage_completion_percentage;
|
||||
/* 0x7878, 4 byte float */
|
||||
float special_stage_completion_percentage;
|
||||
|
||||
/* 0x787C TODO unknown
|
||||
0x787C, 1 byte char * 4096 - Used by GetSongIndex -
|
||||
Assuming Maps Scores to Song IDs */
|
||||
uint8_t unkn_some_map_scores_to_song_ids[4096];
|
||||
/* 0x787C TODO unknown
|
||||
0x787C, 1 byte char * 4096 - Used by GetSongIndex -
|
||||
Assuming Maps Scores to Song IDs */
|
||||
uint8_t unkn_some_map_scores_to_song_ids[4096];
|
||||
|
||||
/* 0x887C TODO unknown
|
||||
0x887C, 1 byte char * 576 - Song Locks/Unlocks - 0x40 Unlocks (Special Zone, etc.)
|
||||
0x8A70 , 1 byte char * 36 - WorldMax Keys and various other events for completion
|
||||
0x8A9C, 8 byte char* - A Worldmax ID (Perhaps one to mark progress in Space)
|
||||
0x8AA4, 1 byte char * 24 - More WorldMax Event Switches */
|
||||
uint8_t unkn2[576];
|
||||
/* 0x887C TODO unknown
|
||||
0x887C, 1 byte char * 576 - Song Locks/Unlocks - 0x40 Unlocks (Special
|
||||
Zone, etc.) 0x8A70 , 1 byte char * 36 - WorldMax Keys and various other
|
||||
events for completion 0x8A9C, 8 byte char* - A Worldmax ID (Perhaps one to
|
||||
mark progress in Space) 0x8AA4, 1 byte char * 24 - More WorldMax Event
|
||||
Switches */
|
||||
uint8_t unkn2[576];
|
||||
|
||||
/* 0x8ABC, 4 byte int: possible values
|
||||
0x1 - grey
|
||||
0x2 - red
|
||||
0x3 - yellow
|
||||
0x4 - green
|
||||
0x5 - Dark Green
|
||||
0x6 - aqua
|
||||
0x7 - blue
|
||||
0x8 - purple
|
||||
0x9 - pink
|
||||
0xA - light grey
|
||||
0xB - Black
|
||||
0xC - Orange
|
||||
*/
|
||||
uint32_t break_item_slot;
|
||||
/* 0x8ABC, 4 byte int: possible values
|
||||
0x1 - grey
|
||||
0x2 - red
|
||||
0x3 - yellow
|
||||
0x4 - green
|
||||
0x5 - Dark Green
|
||||
0x6 - aqua
|
||||
0x7 - blue
|
||||
0x8 - purple
|
||||
0x9 - pink
|
||||
0xA - light grey
|
||||
0xB - Black
|
||||
0xC - Orange
|
||||
*/
|
||||
uint32_t break_item_slot;
|
||||
|
||||
/* 0x8AC0, 4 byte int
|
||||
0x1 - Shield
|
||||
0x2 - PermaShield
|
||||
0x3 - Line Searcher
|
||||
0x4 - Perma Line Searcher
|
||||
0x5 - Life Up
|
||||
0x6 - Perma Life Up
|
||||
0x7 - Lucky
|
||||
0x8 - Perma Lucky
|
||||
0x9 - Portal Pass
|
||||
*/
|
||||
uint32_t func_item_slot;
|
||||
/* 0x8AC0, 4 byte int
|
||||
0x1 - Shield
|
||||
0x2 - PermaShield
|
||||
0x3 - Line Searcher
|
||||
0x4 - Perma Line Searcher
|
||||
0x5 - Life Up
|
||||
0x6 - Perma Life Up
|
||||
0x7 - Lucky
|
||||
0x8 - Perma Lucky
|
||||
0x9 - Portal Pass
|
||||
*/
|
||||
uint32_t func_item_slot;
|
||||
|
||||
/* 0x8AC4, 4 byte int
|
||||
0x1 - BGA OFF
|
||||
0x2 - Perma BGA OFF
|
||||
*/
|
||||
uint32_t bga_item_slot;
|
||||
/* 0x8AC4, 4 byte int
|
||||
0x1 - BGA OFF
|
||||
0x2 - Perma BGA OFF
|
||||
*/
|
||||
uint32_t bga_item_slot;
|
||||
|
||||
/* 0x8AC4, 4 byte int
|
||||
0x1 - 10+
|
||||
0x2 - 20+
|
||||
0x3 - 30+
|
||||
*/
|
||||
uint32_t time_item_slot;
|
||||
/* 0x8AC4, 4 byte int
|
||||
0x1 - 10+
|
||||
0x2 - 20+
|
||||
0x3 - 30+
|
||||
*/
|
||||
uint32_t time_item_slot;
|
||||
|
||||
/* 0x8AC8, 4 byte int */
|
||||
uint32_t unknown;
|
||||
/* 0x8AC8, 4 byte int */
|
||||
uint32_t unknown;
|
||||
|
||||
/* 0x8ACC, unknown stuff: More WorldMax Event Switches (Unused)? */
|
||||
uint8_t unknown2[12];
|
||||
/* 0x8ACC, unknown stuff: More WorldMax Event Switches (Unused)? */
|
||||
uint8_t unknown2[12];
|
||||
|
||||
/* 0x8AD8, 4 byte float - Unknown What this Does (Unused) */
|
||||
float unknown3;
|
||||
/* 0x8AD8, 4 byte float - Unknown What this Does (Unused) */
|
||||
float unknown3;
|
||||
|
||||
/* 0x8ADC, totally unknown stuff, just nulls */
|
||||
uint8_t unknown4[0x7F8];
|
||||
/* 0x8ADC, totally unknown stuff, just nulls */
|
||||
uint8_t unknown4[0x7F8];
|
||||
|
||||
/* 0x92D4 */
|
||||
uint8_t unknown5[0xD01C];
|
||||
/* 0x92D4 */
|
||||
uint8_t unknown5[0xD01C];
|
||||
|
||||
/* TODO missing switches for dark/light world stuff
|
||||
0x8ACC, 1 byte char - More WorldMax Event Switches (Unused)
|
||||
0x8AD8 , 4 byte float - Unknown What this Does (Unused)
|
||||
0x92D4, High Score Table [See Below]
|
||||
0x132D0, 5216 bytes - Unknown Table (Unused)
|
||||
0x162D0, 24 bytes - Unknown Footer (Unused by Game - Most Likely PumBI)
|
||||
*/
|
||||
/* TODO missing switches for dark/light world stuff
|
||||
0x8ACC, 1 byte char - More WorldMax Event Switches (Unused)
|
||||
0x8AD8 , 4 byte float - Unknown What this Does (Unused)
|
||||
0x92D4, High Score Table [See Below]
|
||||
0x132D0, 5216 bytes - Unknown Table (Unused)
|
||||
0x162D0, 24 bytes - Unknown Footer (Unused by Game - Most Likely PumBI)
|
||||
*/
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_nxa_usb_save {
|
||||
struct asset_nxa_usb_save_review review;
|
||||
struct asset_nxa_usb_save_stats stats;
|
||||
struct asset_nxa_usb_save_review review;
|
||||
struct asset_nxa_usb_save_stats stats;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_nxa_usb_save* asset_nxa_usb_save_new(void);
|
||||
struct asset_nxa_usb_save *asset_nxa_usb_save_new(void);
|
||||
|
||||
/* update checksum and prepare profile to get encrypted */
|
||||
void asset_nxa_usb_save_finalize(struct asset_nxa_usb_save* save);
|
||||
void asset_nxa_usb_save_finalize(struct asset_nxa_usb_save *save);
|
||||
|
||||
char* asset_nxa_usb_save_to_string(const struct asset_nxa_usb_save* save);
|
||||
char *asset_nxa_usb_save_to_string(const struct asset_nxa_usb_save *save);
|
||||
|
||||
void asset_nxa_usb_save_decrypt(uint8_t* buf, size_t len);
|
||||
void asset_nxa_usb_save_decrypt(uint8_t *buf, size_t len);
|
||||
|
||||
void asset_nxa_usb_save_encrypt(uint8_t* buf, size_t len);
|
||||
void asset_nxa_usb_save_encrypt(uint8_t *buf, size_t len);
|
||||
|
||||
#endif
|
||||
@@ -7,94 +7,100 @@
|
||||
|
||||
#include "util.h"
|
||||
|
||||
struct asset_nxa_usb_rank* asset_nxa_usb_rank_load_from_file(const char* path,
|
||||
bool encrypted)
|
||||
struct asset_nxa_usb_rank *
|
||||
asset_nxa_usb_rank_load_from_file(const char *path, bool encrypted)
|
||||
{
|
||||
struct asset_nxa_usb_rank* rank;
|
||||
size_t size;
|
||||
struct asset_nxa_usb_rank *rank;
|
||||
size_t size;
|
||||
|
||||
if (!util_file_load(path, (void**) &rank, &size, false)) {
|
||||
log_error("Loading nxa rank file %s failed", path);
|
||||
return NULL;
|
||||
}
|
||||
if (!util_file_load(path, (void **) &rank, &size, false)) {
|
||||
log_error("Loading nxa rank file %s failed", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size != sizeof(struct asset_nxa_usb_rank)) {
|
||||
log_error("Invalid size of nxa rank file %s: %d != %d", path, size,
|
||||
sizeof(struct asset_nxa_usb_rank));
|
||||
free(rank);
|
||||
return NULL;
|
||||
}
|
||||
if (size != sizeof(struct asset_nxa_usb_rank)) {
|
||||
log_error(
|
||||
"Invalid size of nxa rank file %s: %d != %d",
|
||||
path,
|
||||
size,
|
||||
sizeof(struct asset_nxa_usb_rank));
|
||||
free(rank);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (encrypted) {
|
||||
asset_nxa_usb_rank_decrypt((uint8_t*) rank, size);
|
||||
}
|
||||
if (encrypted) {
|
||||
asset_nxa_usb_rank_decrypt((uint8_t *) rank, size);
|
||||
}
|
||||
|
||||
return rank;
|
||||
return rank;
|
||||
}
|
||||
|
||||
bool asset_nxa_usb_rank_save_to_file(const char* path,
|
||||
const struct asset_nxa_usb_rank* rank, bool encrypt)
|
||||
bool asset_nxa_usb_rank_save_to_file(
|
||||
const char *path, const struct asset_nxa_usb_rank *rank, bool encrypt)
|
||||
{
|
||||
struct asset_nxa_usb_rank rank_enc;
|
||||
struct asset_nxa_usb_rank rank_enc;
|
||||
|
||||
memcpy(&rank_enc, rank, sizeof(struct asset_nxa_usb_rank));
|
||||
memcpy(&rank_enc, rank, sizeof(struct asset_nxa_usb_rank));
|
||||
|
||||
if (encrypt) {
|
||||
asset_nxa_usb_rank_encrypt((uint8_t*) &rank_enc,
|
||||
sizeof(struct asset_nxa_usb_rank));
|
||||
}
|
||||
if (encrypt) {
|
||||
asset_nxa_usb_rank_encrypt(
|
||||
(uint8_t *) &rank_enc, sizeof(struct asset_nxa_usb_rank));
|
||||
}
|
||||
|
||||
if (!util_file_save(path, (void**) &rank_enc,
|
||||
sizeof(struct asset_nxa_usb_rank))) {
|
||||
log_error("Storing nxa rank data to %s failed", path);
|
||||
return false;
|
||||
}
|
||||
if (!util_file_save(
|
||||
path, (void **) &rank_enc, sizeof(struct asset_nxa_usb_rank))) {
|
||||
log_error("Storing nxa rank data to %s failed", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct asset_nxa_usb_save* asset_nxa_usb_save_load_from_file(const char* path,
|
||||
bool encrypted)
|
||||
struct asset_nxa_usb_save *
|
||||
asset_nxa_usb_save_load_from_file(const char *path, bool encrypted)
|
||||
{
|
||||
struct asset_nxa_usb_save* save;
|
||||
size_t size;
|
||||
struct asset_nxa_usb_save *save;
|
||||
size_t size;
|
||||
|
||||
if (!util_file_load(path, (void**) &save, &size, false)) {
|
||||
log_error("Loading nxa save file %s failed", path);
|
||||
return NULL;
|
||||
}
|
||||
if (!util_file_load(path, (void **) &save, &size, false)) {
|
||||
log_error("Loading nxa save file %s failed", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size != sizeof(struct asset_nxa_usb_save)) {
|
||||
log_error("Invalid size of nxa save file %s: %d != %d", path, size,
|
||||
sizeof(struct asset_nxa_usb_save));
|
||||
free(save);
|
||||
return NULL;
|
||||
}
|
||||
if (size != sizeof(struct asset_nxa_usb_save)) {
|
||||
log_error(
|
||||
"Invalid size of nxa save file %s: %d != %d",
|
||||
path,
|
||||
size,
|
||||
sizeof(struct asset_nxa_usb_save));
|
||||
free(save);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (encrypted) {
|
||||
asset_nxa_usb_save_decrypt((uint8_t*) save, size);
|
||||
}
|
||||
if (encrypted) {
|
||||
asset_nxa_usb_save_decrypt((uint8_t *) save, size);
|
||||
}
|
||||
|
||||
return save;
|
||||
return save;
|
||||
}
|
||||
|
||||
bool asset_nxa_usb_save_save_to_file(const char* path,
|
||||
const struct asset_nxa_usb_save* save, bool encrypt)
|
||||
bool asset_nxa_usb_save_save_to_file(
|
||||
const char *path, const struct asset_nxa_usb_save *save, bool encrypt)
|
||||
{
|
||||
struct asset_nxa_usb_save save_enc;
|
||||
struct asset_nxa_usb_save save_enc;
|
||||
|
||||
memcpy(&save_enc, save, sizeof(struct asset_nxa_usb_save));
|
||||
memcpy(&save_enc, save, sizeof(struct asset_nxa_usb_save));
|
||||
|
||||
if (encrypt) {
|
||||
asset_nxa_usb_save_encrypt((uint8_t*) &save_enc,
|
||||
sizeof(struct asset_nxa_usb_save));
|
||||
}
|
||||
if (encrypt) {
|
||||
asset_nxa_usb_save_encrypt(
|
||||
(uint8_t *) &save_enc, sizeof(struct asset_nxa_usb_save));
|
||||
}
|
||||
|
||||
if (!util_file_save(path, (const void*) &save_enc,
|
||||
sizeof(struct asset_nxa_usb_save))) {
|
||||
log_error("Storing nxa save data to %s failed", path);
|
||||
return false;
|
||||
}
|
||||
if (!util_file_save(
|
||||
path, (const void *) &save_enc, sizeof(struct asset_nxa_usb_save))) {
|
||||
log_error("Storing nxa save data to %s failed", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
@@ -7,15 +7,19 @@
|
||||
#include "usb-save.h"
|
||||
|
||||
// load from file and decrypt, returns decrypted struct
|
||||
struct asset_nxa_usb_rank* asset_nxa_usb_rank_load_from_file(const char* path, bool encrypted);
|
||||
struct asset_nxa_usb_rank *
|
||||
asset_nxa_usb_rank_load_from_file(const char *path, bool encrypted);
|
||||
|
||||
// takes decrypted rank data, encrypts it and writes it to file
|
||||
bool asset_nxa_usb_rank_save_to_file(const char* path, const struct asset_nxa_usb_rank* rank, bool encrypt);
|
||||
bool asset_nxa_usb_rank_save_to_file(
|
||||
const char *path, const struct asset_nxa_usb_rank *rank, bool encrypt);
|
||||
|
||||
// load from file and decrypt, returns decrypted struct
|
||||
struct asset_nxa_usb_save* asset_nxa_usb_save_load_from_file(const char* path, bool encrypted);
|
||||
struct asset_nxa_usb_save *
|
||||
asset_nxa_usb_save_load_from_file(const char *path, bool encrypted);
|
||||
|
||||
// takes decrypted save data, encrypts it and writes it to file
|
||||
bool asset_nxa_usb_save_save_to_file(const char* path, const struct asset_nxa_usb_save* save, bool encrypt);
|
||||
bool asset_nxa_usb_save_save_to_file(
|
||||
const char *path, const struct asset_nxa_usb_save *save, bool encrypt);
|
||||
|
||||
#endif
|
||||
@@ -9,146 +9,150 @@
|
||||
|
||||
#include "util/str.h"
|
||||
|
||||
int main(int argc, char** argv)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
char* rank_path;
|
||||
char* save_path;
|
||||
int ret;
|
||||
char *rank_path;
|
||||
char *save_path;
|
||||
|
||||
if (argc < 3) {
|
||||
printf("Usage: %s [cmd: new, dec, enc, dump] "
|
||||
"[path containing nxarank.bin nxasave.bin]\n", argv[0]);
|
||||
return -1;
|
||||
if (argc < 3) {
|
||||
printf(
|
||||
"Usage: %s [cmd: new, dec, enc, dump] "
|
||||
"[path containing nxarank.bin nxasave.bin]\n",
|
||||
argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
rank_path = util_str_merge(argv[2], "nxarank.bin");
|
||||
save_path = util_str_merge(argv[2], "nxasave.bin");
|
||||
|
||||
if (!strcmp(argv[1], "new")) {
|
||||
struct asset_nxa_usb_rank *rank = asset_nxa_usb_rank_new();
|
||||
struct asset_nxa_usb_save *save = asset_nxa_usb_save_new();
|
||||
|
||||
asset_nxa_usb_rank_finalize(rank);
|
||||
asset_nxa_usb_save_finalize(save);
|
||||
|
||||
if (!asset_nxa_usb_rank_save_to_file(rank_path, rank, true)) {
|
||||
fprintf(stderr, "Creating rank file %s failed\n", rank_path);
|
||||
ret = -2;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
if (!asset_nxa_usb_save_save_to_file(save_path, save, true)) {
|
||||
fprintf(stderr, "Creating save file %s failed\n", save_path);
|
||||
ret = -3;
|
||||
}
|
||||
|
||||
rank_path = util_str_merge(argv[2], "nxarank.bin");
|
||||
save_path = util_str_merge(argv[2], "nxasave.bin");
|
||||
free(rank);
|
||||
free(save);
|
||||
} else {
|
||||
struct asset_nxa_usb_rank *rank;
|
||||
struct asset_nxa_usb_save *save;
|
||||
bool encrypted;
|
||||
|
||||
if (!strcmp(argv[1], "new")) {
|
||||
struct asset_nxa_usb_rank* rank = asset_nxa_usb_rank_new();
|
||||
struct asset_nxa_usb_save* save = asset_nxa_usb_save_new();
|
||||
if (!strcmp(argv[1], "enc")) {
|
||||
char *tmp;
|
||||
|
||||
asset_nxa_usb_rank_finalize(rank);
|
||||
asset_nxa_usb_save_finalize(save);
|
||||
encrypted = false;
|
||||
|
||||
if (!asset_nxa_usb_rank_save_to_file(rank_path, rank, true)) {
|
||||
fprintf(stderr, "Creating rank file %s failed\n", rank_path);
|
||||
ret = -2;
|
||||
}
|
||||
tmp = util_str_merge(rank_path, ".dec");
|
||||
free(rank_path);
|
||||
rank_path = tmp;
|
||||
|
||||
if (!asset_nxa_usb_save_save_to_file(save_path, save, true)) {
|
||||
fprintf(stderr, "Creating save file %s failed\n", save_path);
|
||||
ret = -3;
|
||||
}
|
||||
|
||||
free(rank);
|
||||
free(save);
|
||||
tmp = util_str_merge(save_path, ".dec");
|
||||
free(save_path);
|
||||
save_path = tmp;
|
||||
} else {
|
||||
struct asset_nxa_usb_rank* rank;
|
||||
struct asset_nxa_usb_save* save;
|
||||
bool encrypted;
|
||||
|
||||
if (!strcmp(argv[1], "enc")) {
|
||||
char* tmp;
|
||||
|
||||
encrypted = false;
|
||||
|
||||
tmp = util_str_merge(rank_path, ".dec");
|
||||
free(rank_path);
|
||||
rank_path = tmp;
|
||||
|
||||
tmp = util_str_merge(save_path, ".dec");
|
||||
free(save_path);
|
||||
save_path = tmp;
|
||||
} else {
|
||||
encrypted = true;
|
||||
}
|
||||
|
||||
rank = asset_nxa_usb_rank_load_from_file(rank_path, encrypted);
|
||||
save = asset_nxa_usb_save_load_from_file(save_path, encrypted);
|
||||
|
||||
if (!rank) {
|
||||
fprintf(stderr, "Loading %s failed", rank_path);
|
||||
ret = -4;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!save) {
|
||||
fprintf(stderr, "Loading %s failed", save_path);
|
||||
ret = -5;
|
||||
free(rank);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "dec")) {
|
||||
char* rank_path_dec;
|
||||
char* save_path_dec;
|
||||
|
||||
rank_path_dec = util_str_merge(rank_path, ".dec");
|
||||
save_path_dec = util_str_merge(save_path, ".dec");
|
||||
|
||||
if (!asset_nxa_usb_rank_save_to_file(rank_path_dec, rank, false)) {
|
||||
fprintf(stderr, "Saving decrypted rank file to %s failed\n",
|
||||
rank_path_dec);
|
||||
ret = -6;
|
||||
}
|
||||
|
||||
if (!asset_nxa_usb_save_save_to_file(save_path_dec, save, false)) {
|
||||
fprintf(stderr, "Saving decrypted save file to %s failed\n",
|
||||
save_path_dec);
|
||||
ret = -7;
|
||||
}
|
||||
|
||||
free(rank_path_dec);
|
||||
free(save_path_dec);
|
||||
} else if (!strcmp(argv[1], "enc")) {
|
||||
char* rank_path_enc;
|
||||
char* save_path_enc;
|
||||
|
||||
rank_path_enc = util_str_merge(rank_path, ".enc");
|
||||
save_path_enc = util_str_merge(save_path, ".enc");
|
||||
|
||||
if (!asset_nxa_usb_rank_save_to_file(rank_path_enc, rank, true)) {
|
||||
fprintf(stderr, "Saving encrypted rank file to %s failed\n",
|
||||
rank_path_enc);
|
||||
ret = -6;
|
||||
}
|
||||
|
||||
if (!asset_nxa_usb_save_save_to_file(save_path_enc, save, true)) {
|
||||
fprintf(stderr, "Saving encrypted save file to %s failed\n",
|
||||
save_path_enc);
|
||||
ret = -7;
|
||||
}
|
||||
|
||||
free(rank_path_enc);
|
||||
free(save_path_enc);
|
||||
} else if (!strcmp(argv[1], "dump")) {
|
||||
char* rank_str;
|
||||
char* save_str;
|
||||
|
||||
rank_str = asset_nxa_usb_rank_to_string(rank);
|
||||
save_str = asset_nxa_usb_save_to_string(save);
|
||||
|
||||
printf("----------------- rank -----------------\n"
|
||||
"%s----------------- save -----------------\n%s",
|
||||
rank_str, save_str);
|
||||
|
||||
free(rank_str);
|
||||
free(save_str);
|
||||
} else {
|
||||
fprintf(stderr, "Unknown command %s\n", argv[1]);
|
||||
ret = -4;
|
||||
}
|
||||
|
||||
free(rank);
|
||||
free(save);
|
||||
encrypted = true;
|
||||
}
|
||||
|
||||
rank = asset_nxa_usb_rank_load_from_file(rank_path, encrypted);
|
||||
save = asset_nxa_usb_save_load_from_file(save_path, encrypted);
|
||||
|
||||
if (!rank) {
|
||||
fprintf(stderr, "Loading %s failed", rank_path);
|
||||
ret = -4;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!save) {
|
||||
fprintf(stderr, "Loading %s failed", save_path);
|
||||
ret = -5;
|
||||
free(rank);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "dec")) {
|
||||
char *rank_path_dec;
|
||||
char *save_path_dec;
|
||||
|
||||
rank_path_dec = util_str_merge(rank_path, ".dec");
|
||||
save_path_dec = util_str_merge(save_path, ".dec");
|
||||
|
||||
if (!asset_nxa_usb_rank_save_to_file(rank_path_dec, rank, false)) {
|
||||
fprintf(
|
||||
stderr, "Saving decrypted rank file to %s failed\n", rank_path_dec);
|
||||
ret = -6;
|
||||
}
|
||||
|
||||
if (!asset_nxa_usb_save_save_to_file(save_path_dec, save, false)) {
|
||||
fprintf(
|
||||
stderr, "Saving decrypted save file to %s failed\n", save_path_dec);
|
||||
ret = -7;
|
||||
}
|
||||
|
||||
free(rank_path_dec);
|
||||
free(save_path_dec);
|
||||
} else if (!strcmp(argv[1], "enc")) {
|
||||
char *rank_path_enc;
|
||||
char *save_path_enc;
|
||||
|
||||
rank_path_enc = util_str_merge(rank_path, ".enc");
|
||||
save_path_enc = util_str_merge(save_path, ".enc");
|
||||
|
||||
if (!asset_nxa_usb_rank_save_to_file(rank_path_enc, rank, true)) {
|
||||
fprintf(
|
||||
stderr, "Saving encrypted rank file to %s failed\n", rank_path_enc);
|
||||
ret = -6;
|
||||
}
|
||||
|
||||
if (!asset_nxa_usb_save_save_to_file(save_path_enc, save, true)) {
|
||||
fprintf(
|
||||
stderr, "Saving encrypted save file to %s failed\n", save_path_enc);
|
||||
ret = -7;
|
||||
}
|
||||
|
||||
free(rank_path_enc);
|
||||
free(save_path_enc);
|
||||
} else if (!strcmp(argv[1], "dump")) {
|
||||
char *rank_str;
|
||||
char *save_str;
|
||||
|
||||
rank_str = asset_nxa_usb_rank_to_string(rank);
|
||||
save_str = asset_nxa_usb_save_to_string(save);
|
||||
|
||||
printf(
|
||||
"----------------- rank -----------------\n"
|
||||
"%s----------------- save -----------------\n%s",
|
||||
rank_str,
|
||||
save_str);
|
||||
|
||||
free(rank_str);
|
||||
free(save_str);
|
||||
} else {
|
||||
fprintf(stderr, "Unknown command %s\n", argv[1]);
|
||||
ret = -4;
|
||||
}
|
||||
|
||||
free(rank);
|
||||
free(save);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(rank_path);
|
||||
free(save_path);
|
||||
free(rank_path);
|
||||
free(save_path);
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
@@ -5,83 +5,71 @@
|
||||
#include "util/adler32.h"
|
||||
#include "util/mem.h"
|
||||
|
||||
static const char* _asset_x2_settings_defaut_high_score_names[] = {
|
||||
"MKII",
|
||||
"YAHP",
|
||||
"KANN",
|
||||
"ZINY",
|
||||
"PIAH",
|
||||
"AHN ",
|
||||
"PIYO",
|
||||
"HIKO",
|
||||
"HALO",
|
||||
"BAJI",
|
||||
"YUTE",
|
||||
"SS ",
|
||||
"SIHO",
|
||||
"AZKI",
|
||||
"JUNE",
|
||||
"GOON",
|
||||
"ARI*",
|
||||
"TAMA",
|
||||
"YSMA",
|
||||
"PIU "
|
||||
};
|
||||
static const char *_asset_x2_settings_defaut_high_score_names[] = {
|
||||
"MKII", "YAHP", "KANN", "ZINY", "PIAH", "AHN ", "PIYO",
|
||||
"HIKO", "HALO", "BAJI", "YUTE", "SS ", "SIHO", "AZKI",
|
||||
"JUNE", "GOON", "ARI*", "TAMA", "YSMA", "PIU "};
|
||||
|
||||
struct asset_x2_settings* asset_x2_settings_new(void)
|
||||
struct asset_x2_settings *asset_x2_settings_new(void)
|
||||
{
|
||||
struct asset_x2_settings* settings;
|
||||
struct asset_x2_settings *settings;
|
||||
|
||||
settings = util_xmalloc(sizeof(struct asset_x2_settings));
|
||||
settings = util_xmalloc(sizeof(struct asset_x2_settings));
|
||||
|
||||
memset(settings->ff_pad, 0xFF, sizeof(settings->ff_pad));
|
||||
memset(settings->unkn, 0, sizeof(settings->unkn));
|
||||
settings->unlock_canond_full = 0;
|
||||
settings->total_uptime = 0;
|
||||
settings->unkn69 = 0x69;
|
||||
memset(settings->song_blacklist, 0, ASSET_X2_SETTINGS_MAX_SONGS);
|
||||
memset(settings->unkn3, 0, sizeof(settings->unkn3));
|
||||
memcpy(settings->ident, "EX02", 4);
|
||||
/* Updated using finalize */
|
||||
settings->adler32 = 0;
|
||||
memset(settings->song_play_count, 0, sizeof(uint16_t) * ASSET_X2_SETTINGS_MAX_SONGS);
|
||||
settings->padding = 0;
|
||||
memset(settings->ff_pad, 0xFF, sizeof(settings->ff_pad));
|
||||
memset(settings->unkn, 0, sizeof(settings->unkn));
|
||||
settings->unlock_canond_full = 0;
|
||||
settings->total_uptime = 0;
|
||||
settings->unkn69 = 0x69;
|
||||
memset(settings->song_blacklist, 0, ASSET_X2_SETTINGS_MAX_SONGS);
|
||||
memset(settings->unkn3, 0, sizeof(settings->unkn3));
|
||||
memcpy(settings->ident, "EX02", 4);
|
||||
/* Updated using finalize */
|
||||
settings->adler32 = 0;
|
||||
memset(
|
||||
settings->song_play_count,
|
||||
0,
|
||||
sizeof(uint16_t) * ASSET_X2_SETTINGS_MAX_SONGS);
|
||||
settings->padding = 0;
|
||||
|
||||
for (uint8_t i = 0; i < ASSET_X2_SETTINGS_HIGH_SCORE_COUNT; i++) {
|
||||
settings->high_score_scores[i] = 10000u - (500u * i);
|
||||
memcpy(&settings->high_score_names[i], &_asset_x2_settings_defaut_high_score_names[i],
|
||||
ASSET_X2_SETTINGS_HIGH_SCORE_NAME_LEN);
|
||||
}
|
||||
for (uint8_t i = 0; i < ASSET_X2_SETTINGS_HIGH_SCORE_COUNT; i++) {
|
||||
settings->high_score_scores[i] = 10000u - (500u * i);
|
||||
memcpy(
|
||||
&settings->high_score_names[i],
|
||||
&_asset_x2_settings_defaut_high_score_names[i],
|
||||
ASSET_X2_SETTINGS_HIGH_SCORE_NAME_LEN);
|
||||
}
|
||||
|
||||
settings->coin_limit = 0;
|
||||
settings->game_mode = ASSET_X2_SETTINGS_GAME_MODE_NORMAL;
|
||||
settings->game_level = ASSET_X2_SETTINGS_LEVEL_NORMAL;
|
||||
settings->game_stage_break = ASSET_X2_SETTINGS_STAGE_BREAK_2ND;
|
||||
settings->language = ASSET_X2_SETTINGS_LANG_ENG;
|
||||
settings->game_demo_sound = 1;
|
||||
settings->game_show_help = 1;
|
||||
settings->coin1_setting = 1;
|
||||
settings->coin2_setting = 1;
|
||||
settings->bookkeeping_coin1_total = 0;
|
||||
settings->bookkeeping_coin2_total = 0;
|
||||
settings->bookkeeping_service_total = 0;
|
||||
settings->coin_limit = 0;
|
||||
settings->game_mode = ASSET_X2_SETTINGS_GAME_MODE_NORMAL;
|
||||
settings->game_level = ASSET_X2_SETTINGS_LEVEL_NORMAL;
|
||||
settings->game_stage_break = ASSET_X2_SETTINGS_STAGE_BREAK_2ND;
|
||||
settings->language = ASSET_X2_SETTINGS_LANG_ENG;
|
||||
settings->game_demo_sound = 1;
|
||||
settings->game_show_help = 1;
|
||||
settings->coin1_setting = 1;
|
||||
settings->coin2_setting = 1;
|
||||
settings->bookkeeping_coin1_total = 0;
|
||||
settings->bookkeeping_coin2_total = 0;
|
||||
settings->bookkeeping_service_total = 0;
|
||||
|
||||
return settings;
|
||||
return settings;
|
||||
}
|
||||
|
||||
void asset_x2_settings_finalize(struct asset_x2_settings* settings)
|
||||
void asset_x2_settings_finalize(struct asset_x2_settings *settings)
|
||||
{
|
||||
/* Seems odd, but they just checksum the game settings part...*/
|
||||
settings->adler32 = util_adler32_calc(1, (const uint8_t*) &settings->game_mode, 8);
|
||||
/* Seems odd, but they just checksum the game settings part...*/
|
||||
settings->adler32 =
|
||||
util_adler32_calc(1, (const uint8_t *) &settings->game_mode, 8);
|
||||
}
|
||||
|
||||
void asset_x2_settings_unlock_all(struct asset_x2_settings* settings)
|
||||
void asset_x2_settings_unlock_all(struct asset_x2_settings *settings)
|
||||
{
|
||||
settings->unlock_canond_full = 1;
|
||||
settings->unlock_canond_full = 1;
|
||||
}
|
||||
|
||||
char* asset_x2_settings_to_string(const struct asset_x2_settings* settings)
|
||||
char *asset_x2_settings_to_string(const struct asset_x2_settings *settings)
|
||||
{
|
||||
// TODO
|
||||
return "";
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
@@ -9,74 +9,75 @@
|
||||
#define ASSET_X2_SETTINGS_HIGH_SCORE_NAME_LEN 4
|
||||
|
||||
enum asset_x2_settings_language {
|
||||
ASSET_X2_SETTINGS_LANG_KOR = 0,
|
||||
ASSET_X2_SETTINGS_LANG_ENG = 1,
|
||||
ASSET_X2_SETTINGS_LANG_SP = 2,
|
||||
ASSET_X2_SETTINGS_LANG_CH = 3,
|
||||
ASSET_X2_SETTINGS_LANG_KOR = 0,
|
||||
ASSET_X2_SETTINGS_LANG_ENG = 1,
|
||||
ASSET_X2_SETTINGS_LANG_SP = 2,
|
||||
ASSET_X2_SETTINGS_LANG_CH = 3,
|
||||
};
|
||||
|
||||
enum asset_x2_settings_game_mode {
|
||||
ASSET_X2_SETTINGS_GAME_MODE_NORMAL = 0,
|
||||
ASSET_X2_SETTINGS_GAME_MODE_EVENT = 1,
|
||||
ASSET_X2_SETTINGS_GAME_MODE_NORMAL = 0,
|
||||
ASSET_X2_SETTINGS_GAME_MODE_EVENT = 1,
|
||||
};
|
||||
|
||||
enum asset_x2_settings_level {
|
||||
ASSET_X2_SETTINGS_LEVEL_EASY = 0,
|
||||
ASSET_X2_SETTINGS_LEVEL_NORMAL = 1,
|
||||
ASSET_X2_SETTINGS_LEVEL_HARD = 2,
|
||||
ASSET_X2_SETTINGS_LEVEL_EASY = 0,
|
||||
ASSET_X2_SETTINGS_LEVEL_NORMAL = 1,
|
||||
ASSET_X2_SETTINGS_LEVEL_HARD = 2,
|
||||
};
|
||||
|
||||
enum asset_x2_settings_stage_break {
|
||||
ASSET_X2_SETTINGS_STAGE_BREAK_OFF = 0,
|
||||
ASSET_X2_SETTINGS_STAGE_BREAK_1ST = 1,
|
||||
ASSET_X2_SETTINGS_STAGE_BREAK_2ND = 2,
|
||||
ASSET_X2_SETTINGS_STAGE_BREAK_3RD = 3,
|
||||
ASSET_X2_SETTINGS_STAGE_BREAK_4TH = 4,
|
||||
ASSET_X2_SETTINGS_STAGE_BREAK_OFF = 0,
|
||||
ASSET_X2_SETTINGS_STAGE_BREAK_1ST = 1,
|
||||
ASSET_X2_SETTINGS_STAGE_BREAK_2ND = 2,
|
||||
ASSET_X2_SETTINGS_STAGE_BREAK_3RD = 3,
|
||||
ASSET_X2_SETTINGS_STAGE_BREAK_4TH = 4,
|
||||
};
|
||||
|
||||
struct asset_x2_settings {
|
||||
/* Padding to fill up to 4k EEPROM legacy size */
|
||||
uint8_t ff_pad[0x51B];
|
||||
uint8_t unkn[10];
|
||||
uint8_t unlock_canond_full;
|
||||
uint32_t total_uptime;
|
||||
uint8_t unkn69;
|
||||
uint8_t song_blacklist[ASSET_X2_SETTINGS_MAX_SONGS];
|
||||
uint8_t unkn3[0x75];
|
||||
/* EX02 */
|
||||
char ident[4];
|
||||
uint32_t adler32;
|
||||
uint16_t song_play_count[ASSET_X2_SETTINGS_MAX_SONGS];
|
||||
uint16_t padding;
|
||||
uint32_t high_score_scores[ASSET_X2_SETTINGS_HIGH_SCORE_COUNT];
|
||||
/* 20 names a 4 chars for the default high score list */
|
||||
char high_score_names[ASSET_X2_SETTINGS_HIGH_SCORE_COUNT][ASSET_X2_SETTINGS_HIGH_SCORE_NAME_LEN];
|
||||
/* 0 none */
|
||||
uint8_t coin_limit;
|
||||
uint8_t game_mode;
|
||||
uint8_t game_level;
|
||||
uint8_t game_stage_break;
|
||||
uint8_t language;
|
||||
/* 0 off, 1 on */
|
||||
uint8_t game_demo_sound;
|
||||
/* 0 off, 1 on */
|
||||
uint8_t game_show_help;
|
||||
/* 0 freeplay */
|
||||
uint8_t coin1_setting;
|
||||
/* 0 freeplay */
|
||||
uint8_t coin2_setting;
|
||||
uint32_t bookkeeping_coin1_total;
|
||||
uint32_t bookkeeping_coin2_total;
|
||||
uint32_t bookkeeping_service_total;
|
||||
/* Padding to fill up to 4k EEPROM legacy size */
|
||||
uint8_t ff_pad[0x51B];
|
||||
uint8_t unkn[10];
|
||||
uint8_t unlock_canond_full;
|
||||
uint32_t total_uptime;
|
||||
uint8_t unkn69;
|
||||
uint8_t song_blacklist[ASSET_X2_SETTINGS_MAX_SONGS];
|
||||
uint8_t unkn3[0x75];
|
||||
/* EX02 */
|
||||
char ident[4];
|
||||
uint32_t adler32;
|
||||
uint16_t song_play_count[ASSET_X2_SETTINGS_MAX_SONGS];
|
||||
uint16_t padding;
|
||||
uint32_t high_score_scores[ASSET_X2_SETTINGS_HIGH_SCORE_COUNT];
|
||||
/* 20 names a 4 chars for the default high score list */
|
||||
char high_score_names[ASSET_X2_SETTINGS_HIGH_SCORE_COUNT]
|
||||
[ASSET_X2_SETTINGS_HIGH_SCORE_NAME_LEN];
|
||||
/* 0 none */
|
||||
uint8_t coin_limit;
|
||||
uint8_t game_mode;
|
||||
uint8_t game_level;
|
||||
uint8_t game_stage_break;
|
||||
uint8_t language;
|
||||
/* 0 off, 1 on */
|
||||
uint8_t game_demo_sound;
|
||||
/* 0 off, 1 on */
|
||||
uint8_t game_show_help;
|
||||
/* 0 freeplay */
|
||||
uint8_t coin1_setting;
|
||||
/* 0 freeplay */
|
||||
uint8_t coin2_setting;
|
||||
uint32_t bookkeeping_coin1_total;
|
||||
uint32_t bookkeeping_coin2_total;
|
||||
uint32_t bookkeeping_service_total;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_x2_settings* asset_x2_settings_new(void);
|
||||
struct asset_x2_settings *asset_x2_settings_new(void);
|
||||
|
||||
// update checksum
|
||||
void asset_x2_settings_finalize(struct asset_x2_settings* settings);
|
||||
void asset_x2_settings_finalize(struct asset_x2_settings *settings);
|
||||
|
||||
void asset_x2_settings_unlock_all(struct asset_x2_settings* settings);
|
||||
void asset_x2_settings_unlock_all(struct asset_x2_settings *settings);
|
||||
|
||||
char* asset_x2_settings_to_string(const struct asset_x2_settings* settings);
|
||||
char *asset_x2_settings_to_string(const struct asset_x2_settings *settings);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,58 +5,65 @@
|
||||
#include "util/adler32.h"
|
||||
#include "util/mem.h"
|
||||
|
||||
struct asset_zero_settings* asset_zero_settings_new(void)
|
||||
struct asset_zero_settings *asset_zero_settings_new(void)
|
||||
{
|
||||
struct asset_zero_settings* settings;
|
||||
struct asset_zero_settings *settings;
|
||||
|
||||
settings = util_xmalloc(sizeof(struct asset_zero_settings));
|
||||
settings = util_xmalloc(sizeof(struct asset_zero_settings));
|
||||
|
||||
memset(settings->ff_pad, 0xFF, sizeof(settings->ff_pad));
|
||||
memcpy(settings->ident, "ZERO", 4);
|
||||
/* Updated using finalize */
|
||||
settings->adler32 = 0;
|
||||
settings->total_uptime = 0;
|
||||
settings->language = ASSET_ZERO_SETTINGS_LANG_ENG;
|
||||
memset(settings->song_play_count, 0, sizeof(uint32_t) * ASSET_ZERO_SETTINGS_MAX_SONGS);
|
||||
settings->game_option_default_station = ASSET_ZERO_SETTINGS_STATION_EASY;
|
||||
settings->game_mode = ASSET_ZERO_SETTINGS_GAME_MODE_NORMAL;
|
||||
settings->game_level = ASSET_ZERO_SETTINGS_LEVEL_NORMAL;
|
||||
settings->game_stage_break = ASSET_ZERO_SETTINGS_STAGE_BREAK_2ND;
|
||||
settings->game_demo_sound = 1;
|
||||
settings->game_show_help = 1;
|
||||
settings->game_mercy_ticket = 0;
|
||||
settings->game_score_per_ticket = 0;
|
||||
settings->coin_limit = 0;
|
||||
settings->coin1_setting = 1;
|
||||
settings->coin2_setting = 1;
|
||||
memset(settings->mission_unlock_flags, 0, ASSET_ZERO_SETTINGS_NUM_UNLOCK_FLAGS);
|
||||
settings->unkn2 = 0x2A;
|
||||
settings->unkn3 = 0;
|
||||
settings->bookkeeping_coin1_total = 0;
|
||||
settings->bookkeeping_coin2_total = 0;
|
||||
settings->bookkeeping_service_total = 0;
|
||||
settings->bookkeeping_ticket_1 = 0;
|
||||
settings->bookkeeping_ticket_2 = 0;
|
||||
settings->region = 0xFF;
|
||||
memset(settings->censor_table, 0, ASSET_ZERO_SETTINGS_MAX_SONGS);
|
||||
memset(settings->ff_pad, 0xFF, sizeof(settings->ff_pad));
|
||||
memcpy(settings->ident, "ZERO", 4);
|
||||
/* Updated using finalize */
|
||||
settings->adler32 = 0;
|
||||
settings->total_uptime = 0;
|
||||
settings->language = ASSET_ZERO_SETTINGS_LANG_ENG;
|
||||
memset(
|
||||
settings->song_play_count,
|
||||
0,
|
||||
sizeof(uint32_t) * ASSET_ZERO_SETTINGS_MAX_SONGS);
|
||||
settings->game_option_default_station = ASSET_ZERO_SETTINGS_STATION_EASY;
|
||||
settings->game_mode = ASSET_ZERO_SETTINGS_GAME_MODE_NORMAL;
|
||||
settings->game_level = ASSET_ZERO_SETTINGS_LEVEL_NORMAL;
|
||||
settings->game_stage_break = ASSET_ZERO_SETTINGS_STAGE_BREAK_2ND;
|
||||
settings->game_demo_sound = 1;
|
||||
settings->game_show_help = 1;
|
||||
settings->game_mercy_ticket = 0;
|
||||
settings->game_score_per_ticket = 0;
|
||||
settings->coin_limit = 0;
|
||||
settings->coin1_setting = 1;
|
||||
settings->coin2_setting = 1;
|
||||
memset(
|
||||
settings->mission_unlock_flags, 0, ASSET_ZERO_SETTINGS_NUM_UNLOCK_FLAGS);
|
||||
settings->unkn2 = 0x2A;
|
||||
settings->unkn3 = 0;
|
||||
settings->bookkeeping_coin1_total = 0;
|
||||
settings->bookkeeping_coin2_total = 0;
|
||||
settings->bookkeeping_service_total = 0;
|
||||
settings->bookkeeping_ticket_1 = 0;
|
||||
settings->bookkeeping_ticket_2 = 0;
|
||||
settings->region = 0xFF;
|
||||
memset(settings->censor_table, 0, ASSET_ZERO_SETTINGS_MAX_SONGS);
|
||||
|
||||
return settings;
|
||||
return settings;
|
||||
}
|
||||
|
||||
void asset_zero_settings_finalize(struct asset_zero_settings* settings)
|
||||
void asset_zero_settings_finalize(struct asset_zero_settings *settings)
|
||||
{
|
||||
/* Seems odd, but they just checksum the game settings part...*/
|
||||
settings->adler32 = util_adler32_calc(1, (const uint8_t*) &settings->game_mode, 8);
|
||||
/* Seems odd, but they just checksum the game settings part...*/
|
||||
settings->adler32 =
|
||||
util_adler32_calc(1, (const uint8_t *) &settings->game_mode, 8);
|
||||
}
|
||||
|
||||
void asset_zero_settings_unlock_all(struct asset_zero_settings* settings)
|
||||
void asset_zero_settings_unlock_all(struct asset_zero_settings *settings)
|
||||
{
|
||||
/* Mark all missions cleared to unlock all missions and content locked by some missions */
|
||||
memset(settings->mission_unlock_flags, 1, ASSET_ZERO_SETTINGS_NUM_UNLOCK_FLAGS);
|
||||
/* Mark all missions cleared to unlock all missions and content locked by some
|
||||
* missions */
|
||||
memset(
|
||||
settings->mission_unlock_flags, 1, ASSET_ZERO_SETTINGS_NUM_UNLOCK_FLAGS);
|
||||
}
|
||||
|
||||
char* asset_zero_settings_to_string(const struct asset_zero_settings* settings)
|
||||
char *asset_zero_settings_to_string(const struct asset_zero_settings *settings)
|
||||
{
|
||||
// TODO
|
||||
return "";
|
||||
// TODO
|
||||
return "";
|
||||
}
|
||||
@@ -8,88 +8,88 @@
|
||||
#define ASSET_ZERO_SETTINGS_NUM_UNLOCK_FLAGS 59
|
||||
|
||||
enum asset_zero_settings_language {
|
||||
ASSET_ZERO_SETTINGS_LANG_KOR = 0,
|
||||
ASSET_ZERO_SETTINGS_LANG_ENG = 1,
|
||||
ASSET_ZERO_SETTINGS_LANG_SP = 2,
|
||||
ASSET_ZERO_SETTINGS_LANG_CH = 3,
|
||||
ASSET_ZERO_SETTINGS_LANG_KOR = 0,
|
||||
ASSET_ZERO_SETTINGS_LANG_ENG = 1,
|
||||
ASSET_ZERO_SETTINGS_LANG_SP = 2,
|
||||
ASSET_ZERO_SETTINGS_LANG_CH = 3,
|
||||
};
|
||||
|
||||
enum asset_zero_settings_station {
|
||||
ASSET_ZERO_SETTINGS_STATION_EASY = 0,
|
||||
ASSET_ZERO_SETTINGS_STATION_ARCADE = 1,
|
||||
ASSET_ZERO_SETTINGS_STATION_REMIX = 2,
|
||||
ASSET_ZERO_SETTINGS_STATION_EASY = 0,
|
||||
ASSET_ZERO_SETTINGS_STATION_ARCADE = 1,
|
||||
ASSET_ZERO_SETTINGS_STATION_REMIX = 2,
|
||||
};
|
||||
|
||||
enum asset_zero_settings_game_mode {
|
||||
ASSET_ZERO_SETTINGS_GAME_MODE_NORMAL = 0,
|
||||
ASSET_ZERO_SETTINGS_GAME_MODE_EVENT = 1,
|
||||
ASSET_ZERO_SETTINGS_GAME_MODE_NORMAL = 0,
|
||||
ASSET_ZERO_SETTINGS_GAME_MODE_EVENT = 1,
|
||||
};
|
||||
|
||||
enum asset_zero_settings_level {
|
||||
ASSET_ZERO_SETTINGS_LEVEL_EASY = 0,
|
||||
ASSET_ZERO_SETTINGS_LEVEL_NORMAL = 1,
|
||||
ASSET_ZERO_SETTINGS_LEVEL_HARD = 2,
|
||||
ASSET_ZERO_SETTINGS_LEVEL_EASY = 0,
|
||||
ASSET_ZERO_SETTINGS_LEVEL_NORMAL = 1,
|
||||
ASSET_ZERO_SETTINGS_LEVEL_HARD = 2,
|
||||
};
|
||||
|
||||
enum asset_zero_settings_stage_break {
|
||||
ASSET_ZERO_SETTINGS_STAGE_BREAK_OFF = 0,
|
||||
ASSET_ZERO_SETTINGS_STAGE_BREAK_1ST = 1,
|
||||
ASSET_ZERO_SETTINGS_STAGE_BREAK_2ND = 2,
|
||||
ASSET_ZERO_SETTINGS_STAGE_BREAK_3RD = 3,
|
||||
ASSET_ZERO_SETTINGS_STAGE_BREAK_4TH = 4,
|
||||
ASSET_ZERO_SETTINGS_STAGE_BREAK_OFF = 0,
|
||||
ASSET_ZERO_SETTINGS_STAGE_BREAK_1ST = 1,
|
||||
ASSET_ZERO_SETTINGS_STAGE_BREAK_2ND = 2,
|
||||
ASSET_ZERO_SETTINGS_STAGE_BREAK_3RD = 3,
|
||||
ASSET_ZERO_SETTINGS_STAGE_BREAK_4TH = 4,
|
||||
};
|
||||
|
||||
struct asset_zero_settings {
|
||||
/* Padding to fill up to 4k EEPROM legacy size */
|
||||
uint8_t ff_pad[0xBA4];
|
||||
/* ZERO */
|
||||
char ident[4];
|
||||
uint32_t adler32;
|
||||
uint32_t total_uptime;
|
||||
uint8_t language;
|
||||
uint32_t song_play_count[ASSET_ZERO_SETTINGS_MAX_SONGS];
|
||||
uint32_t game_option_default_station;
|
||||
uint8_t game_mode;
|
||||
uint8_t game_level;
|
||||
uint8_t game_stage_break;
|
||||
/* 0 off, 1 on */
|
||||
uint8_t game_demo_sound;
|
||||
/* 0 off, 1 on */
|
||||
uint8_t game_show_help;
|
||||
/* 0 off, 1 on */
|
||||
uint8_t game_mercy_ticket;
|
||||
/* 0 off, 1 - 6 for score */
|
||||
uint8_t game_score_per_ticket;
|
||||
/* 0 none */
|
||||
uint8_t coin_limit; // 0 none
|
||||
/* 0 freeplay */
|
||||
uint8_t coin1_setting;
|
||||
/* 0 freeplay */
|
||||
uint8_t coin2_setting;
|
||||
/* Unlock flags for missions (total of 30) */
|
||||
uint8_t mission_unlock_flags[ASSET_ZERO_SETTINGS_NUM_UNLOCK_FLAGS];
|
||||
/* Default value 0x2A */
|
||||
uint32_t unkn2;
|
||||
uint32_t unkn3;
|
||||
uint32_t bookkeeping_coin1_total;
|
||||
uint32_t bookkeeping_coin2_total;
|
||||
uint32_t bookkeeping_service_total;
|
||||
uint32_t bookkeeping_ticket_1;
|
||||
uint32_t bookkeeping_ticket_2;
|
||||
/* FF -> not used, censoring globally disabled. unused feature though */
|
||||
uint8_t region;
|
||||
/* 0 = censoring of song off */
|
||||
uint8_t censor_table[ASSET_ZERO_SETTINGS_MAX_SONGS];
|
||||
/* Padding to fill up to 4k EEPROM legacy size */
|
||||
uint8_t ff_pad[0xBA4];
|
||||
/* ZERO */
|
||||
char ident[4];
|
||||
uint32_t adler32;
|
||||
uint32_t total_uptime;
|
||||
uint8_t language;
|
||||
uint32_t song_play_count[ASSET_ZERO_SETTINGS_MAX_SONGS];
|
||||
uint32_t game_option_default_station;
|
||||
uint8_t game_mode;
|
||||
uint8_t game_level;
|
||||
uint8_t game_stage_break;
|
||||
/* 0 off, 1 on */
|
||||
uint8_t game_demo_sound;
|
||||
/* 0 off, 1 on */
|
||||
uint8_t game_show_help;
|
||||
/* 0 off, 1 on */
|
||||
uint8_t game_mercy_ticket;
|
||||
/* 0 off, 1 - 6 for score */
|
||||
uint8_t game_score_per_ticket;
|
||||
/* 0 none */
|
||||
uint8_t coin_limit; // 0 none
|
||||
/* 0 freeplay */
|
||||
uint8_t coin1_setting;
|
||||
/* 0 freeplay */
|
||||
uint8_t coin2_setting;
|
||||
/* Unlock flags for missions (total of 30) */
|
||||
uint8_t mission_unlock_flags[ASSET_ZERO_SETTINGS_NUM_UNLOCK_FLAGS];
|
||||
/* Default value 0x2A */
|
||||
uint32_t unkn2;
|
||||
uint32_t unkn3;
|
||||
uint32_t bookkeeping_coin1_total;
|
||||
uint32_t bookkeeping_coin2_total;
|
||||
uint32_t bookkeeping_service_total;
|
||||
uint32_t bookkeeping_ticket_1;
|
||||
uint32_t bookkeeping_ticket_2;
|
||||
/* FF -> not used, censoring globally disabled. unused feature though */
|
||||
uint8_t region;
|
||||
/* 0 = censoring of song off */
|
||||
uint8_t censor_table[ASSET_ZERO_SETTINGS_MAX_SONGS];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct asset_zero_settings* asset_zero_settings_new(void);
|
||||
struct asset_zero_settings *asset_zero_settings_new(void);
|
||||
|
||||
// update checksum
|
||||
void asset_zero_settings_finalize(struct asset_zero_settings* settings);
|
||||
void asset_zero_settings_finalize(struct asset_zero_settings *settings);
|
||||
|
||||
// sets all missions cleared to unlock special stage songs and other missions
|
||||
void asset_zero_settings_unlock_all(struct asset_zero_settings* settings);
|
||||
void asset_zero_settings_unlock_all(struct asset_zero_settings *settings);
|
||||
|
||||
char* asset_zero_settings_to_string(const struct asset_zero_settings* settings);
|
||||
char *asset_zero_settings_to_string(const struct asset_zero_settings *settings);
|
||||
|
||||
#endif
|
||||
|
||||
+525
-464
File diff suppressed because it is too large
Load Diff
@@ -18,33 +18,33 @@
|
||||
* Available operations to hook
|
||||
*/
|
||||
enum cnh_filehook_irp_op {
|
||||
CNH_FILEHOOK_IRP_OP_OPEN = 0,
|
||||
CNH_FILEHOOK_IRP_OP_CLOSE = 1,
|
||||
CNH_FILEHOOK_IRP_OP_READ = 2,
|
||||
CNH_FILEHOOK_IRP_OP_WRITE = 3,
|
||||
CNH_FILEHOOK_IRP_OP_FGETS = 4,
|
||||
CNH_FILEHOOK_IRP_OP_SEEK = 5,
|
||||
CNH_FILEHOOK_IRP_OP_TELL = 6,
|
||||
CNH_FILEHOOK_IRP_OP_EOF = 7,
|
||||
CNH_FILEHOOK_IRP_OP_OPEN = 0,
|
||||
CNH_FILEHOOK_IRP_OP_CLOSE = 1,
|
||||
CNH_FILEHOOK_IRP_OP_READ = 2,
|
||||
CNH_FILEHOOK_IRP_OP_WRITE = 3,
|
||||
CNH_FILEHOOK_IRP_OP_FGETS = 4,
|
||||
CNH_FILEHOOK_IRP_OP_SEEK = 5,
|
||||
CNH_FILEHOOK_IRP_OP_TELL = 6,
|
||||
CNH_FILEHOOK_IRP_OP_EOF = 7,
|
||||
};
|
||||
|
||||
/**
|
||||
* I/O request packet
|
||||
*/
|
||||
struct cnh_filehook_irp {
|
||||
enum cnh_filehook_irp_op op;
|
||||
size_t next_handler;
|
||||
FILE* file;
|
||||
const char *open_filename;
|
||||
const char* open_mode;
|
||||
struct cnh_iobuf read;
|
||||
struct cnh_const_iobuf write;
|
||||
size_t orig_read_write_size;
|
||||
size_t orig_read_write_nmemb;
|
||||
int seek_origin;
|
||||
int64_t seek_offset;
|
||||
uint64_t tell_offset;
|
||||
bool eof;
|
||||
enum cnh_filehook_irp_op op;
|
||||
size_t next_handler;
|
||||
FILE *file;
|
||||
const char *open_filename;
|
||||
const char *open_mode;
|
||||
struct cnh_iobuf read;
|
||||
struct cnh_const_iobuf write;
|
||||
size_t orig_read_write_size;
|
||||
size_t orig_read_write_nmemb;
|
||||
int seek_origin;
|
||||
int64_t seek_offset;
|
||||
uint64_t tell_offset;
|
||||
bool eof;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -77,14 +77,15 @@ enum cnh_result cnh_filehook_invoke_next(struct cnh_filehook_irp *irp);
|
||||
*
|
||||
* @return Actual file handle instance pointing to a dummy endpoint.
|
||||
*/
|
||||
FILE* cnh_filehook_open_dummy_file_handle();
|
||||
FILE *cnh_filehook_open_dummy_file_handle();
|
||||
|
||||
/**
|
||||
* Close a dummy file handle. Make sure to free your previously allocated handles
|
||||
* to avoid resource leaks. Do not free them using the real close function.
|
||||
* Close a dummy file handle. Make sure to free your previously allocated
|
||||
* handles to avoid resource leaks. Do not free them using the real close
|
||||
* function.
|
||||
*
|
||||
* @param file Dummy file handle to free
|
||||
*/
|
||||
void cnh_filehook_close_dummy_file_handle(FILE* file);
|
||||
void cnh_filehook_close_dummy_file_handle(FILE *file);
|
||||
|
||||
#endif
|
||||
|
||||
+288
-253
@@ -3,8 +3,8 @@
|
||||
#include <pthread.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
@@ -14,34 +14,48 @@
|
||||
|
||||
#include "util/time.h"
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Real funcs typedefs */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
typedef DIR* (*cnh_fshook_opendir_t)(const char* name);
|
||||
typedef int (*cnh_fshook_lxstat_t)(int version, const char* file, struct stat* buf);
|
||||
typedef int (*cnh_fshook_xstat_t)(int version, const char* file, struct stat* buf);
|
||||
typedef int (*cnh_fshook_rename_t)(const char* old, const char* new);
|
||||
typedef int (*cnh_fshook_remove_t)(const char* pathname);
|
||||
typedef int (*cnh_fshook_access_t)(const char* path, int amode);
|
||||
typedef DIR *(*cnh_fshook_opendir_t)(const char *name);
|
||||
typedef int (*cnh_fshook_lxstat_t)(
|
||||
int version, const char *file, struct stat *buf);
|
||||
typedef int (*cnh_fshook_xstat_t)(
|
||||
int version, const char *file, struct stat *buf);
|
||||
typedef int (*cnh_fshook_rename_t)(const char *old, const char *new);
|
||||
typedef int (*cnh_fshook_remove_t)(const char *pathname);
|
||||
typedef int (*cnh_fshook_access_t)(const char *path, int amode);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Private helpers */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _cnh_fshook_init(void);
|
||||
|
||||
static enum cnh_result _cnh_fshook_invoke_real(struct cnh_fshook_irp *irp);
|
||||
static enum cnh_result _cnh_fshook_invoke_real_opendir(struct cnh_fshook_irp *irp);
|
||||
static enum cnh_result _cnh_fshook_invoke_real_lxstat(struct cnh_fshook_irp *irp);
|
||||
static enum cnh_result _cnh_fshook_invoke_real_xstat(struct cnh_fshook_irp *irp);
|
||||
static enum cnh_result _cnh_fshook_invoke_real_rename(struct cnh_fshook_irp *irp);
|
||||
static enum cnh_result _cnh_fshook_invoke_real_remove(struct cnh_fshook_irp *irp);
|
||||
static enum cnh_result _cnh_fshook_invoke_real_access(struct cnh_fshook_irp *irp);
|
||||
static enum cnh_result
|
||||
_cnh_fshook_invoke_real_opendir(struct cnh_fshook_irp *irp);
|
||||
static enum cnh_result
|
||||
_cnh_fshook_invoke_real_lxstat(struct cnh_fshook_irp *irp);
|
||||
static enum cnh_result
|
||||
_cnh_fshook_invoke_real_xstat(struct cnh_fshook_irp *irp);
|
||||
static enum cnh_result
|
||||
_cnh_fshook_invoke_real_rename(struct cnh_fshook_irp *irp);
|
||||
static enum cnh_result
|
||||
_cnh_fshook_invoke_real_remove(struct cnh_fshook_irp *irp);
|
||||
static enum cnh_result
|
||||
_cnh_fshook_invoke_real_access(struct cnh_fshook_irp *irp);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Private state */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static cnh_fshook_opendir_t _cnh_fshook_real_opendir;
|
||||
static cnh_fshook_lxstat_t _cnh_fshook_real_lxstat;
|
||||
@@ -65,383 +79,404 @@ static pthread_mutex_t _cnh_fshook_lock;
|
||||
static cnh_fshook_fn_t *_cnh_fshook_handlers;
|
||||
static size_t _cnh_fshook_nhandlers;
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Public module functions */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
enum cnh_result cnh_fshook_push_handler(cnh_fshook_fn_t fn)
|
||||
{
|
||||
cnh_fshook_fn_t *new_array;
|
||||
size_t new_size;
|
||||
enum cnh_result result;
|
||||
cnh_fshook_fn_t *new_array;
|
||||
size_t new_size;
|
||||
enum cnh_result result;
|
||||
|
||||
assert(fn != NULL);
|
||||
assert(fn != NULL);
|
||||
|
||||
_cnh_fshook_init();
|
||||
_cnh_fshook_init();
|
||||
|
||||
pthread_mutex_lock(&_cnh_fshook_lock);
|
||||
pthread_mutex_lock(&_cnh_fshook_lock);
|
||||
|
||||
new_size = _cnh_fshook_nhandlers + 1;
|
||||
new_array = realloc(_cnh_fshook_handlers, new_size * sizeof(cnh_fshook_fn_t));
|
||||
new_size = _cnh_fshook_nhandlers + 1;
|
||||
new_array = realloc(_cnh_fshook_handlers, new_size * sizeof(cnh_fshook_fn_t));
|
||||
|
||||
if (new_array != NULL) {
|
||||
_cnh_fshook_handlers = new_array;
|
||||
_cnh_fshook_handlers[_cnh_fshook_nhandlers++] = fn;
|
||||
result = CNH_RESULT_SUCCESS;
|
||||
} else {
|
||||
result = CNH_RESULT_OUT_OF_MEMORY;
|
||||
}
|
||||
if (new_array != NULL) {
|
||||
_cnh_fshook_handlers = new_array;
|
||||
_cnh_fshook_handlers[_cnh_fshook_nhandlers++] = fn;
|
||||
result = CNH_RESULT_SUCCESS;
|
||||
} else {
|
||||
result = CNH_RESULT_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_cnh_fshook_lock);
|
||||
pthread_mutex_unlock(&_cnh_fshook_lock);
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
enum cnh_result cnh_fshook_invoke_next(struct cnh_fshook_irp *irp)
|
||||
{
|
||||
cnh_fshook_fn_t handler;
|
||||
enum cnh_result result;
|
||||
cnh_fshook_fn_t handler;
|
||||
enum cnh_result result;
|
||||
|
||||
assert(irp != NULL);
|
||||
assert(_cnh_fshook_initted > 0);
|
||||
assert(irp != NULL);
|
||||
assert(_cnh_fshook_initted > 0);
|
||||
|
||||
pthread_mutex_lock(&_cnh_fshook_lock);
|
||||
pthread_mutex_lock(&_cnh_fshook_lock);
|
||||
|
||||
assert(irp->next_handler <= _cnh_fshook_nhandlers);
|
||||
assert(irp->next_handler <= _cnh_fshook_nhandlers);
|
||||
|
||||
if (irp->next_handler < _cnh_fshook_nhandlers) {
|
||||
handler = _cnh_fshook_handlers[irp->next_handler];
|
||||
irp->next_handler++;
|
||||
} else {
|
||||
handler = _cnh_fshook_invoke_real;
|
||||
irp->next_handler = (size_t) -1;
|
||||
}
|
||||
if (irp->next_handler < _cnh_fshook_nhandlers) {
|
||||
handler = _cnh_fshook_handlers[irp->next_handler];
|
||||
irp->next_handler++;
|
||||
} else {
|
||||
handler = _cnh_fshook_invoke_real;
|
||||
irp->next_handler = (size_t) -1;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_cnh_fshook_lock);
|
||||
pthread_mutex_unlock(&_cnh_fshook_lock);
|
||||
|
||||
result = handler(irp);
|
||||
result = handler(irp);
|
||||
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
irp->next_handler = (size_t) -1;
|
||||
}
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
irp->next_handler = (size_t) -1;
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Hooked functions */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
DIR* opendir(const char* name)
|
||||
DIR *opendir(const char *name)
|
||||
{
|
||||
struct cnh_fshook_irp irp;
|
||||
enum cnh_result result;
|
||||
struct cnh_fshook_irp irp;
|
||||
enum cnh_result result;
|
||||
|
||||
/* Ensure module is initialized */
|
||||
_cnh_fshook_init();
|
||||
/* Ensure module is initialized */
|
||||
_cnh_fshook_init();
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_FSHOOK_IRP_OP_DIR_OPEN;
|
||||
irp.opendir_name = name;
|
||||
irp.opendir_ret = NULL;
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_FSHOOK_IRP_OP_DIR_OPEN;
|
||||
irp.opendir_name = name;
|
||||
irp.opendir_ret = NULL;
|
||||
|
||||
result = cnh_fshook_invoke_next(&irp);
|
||||
result = cnh_fshook_invoke_next(&irp);
|
||||
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return NULL;
|
||||
}
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
errno = 0;
|
||||
|
||||
return irp.opendir_ret;
|
||||
return irp.opendir_ret;
|
||||
}
|
||||
|
||||
int __lxstat(int version, const char* file, struct stat* buf)
|
||||
int __lxstat(int version, const char *file, struct stat *buf)
|
||||
{
|
||||
struct cnh_fshook_irp irp;
|
||||
enum cnh_result result;
|
||||
struct cnh_fshook_irp irp;
|
||||
enum cnh_result result;
|
||||
|
||||
/* Ensure module is initialized */
|
||||
_cnh_fshook_init();
|
||||
/* Ensure module is initialized */
|
||||
_cnh_fshook_init();
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_FSHOOK_IRP_OP_LXSTAT;
|
||||
irp.xstat_version = version;
|
||||
irp.xstat_file = file;
|
||||
irp.xstat_buf = buf;
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_FSHOOK_IRP_OP_LXSTAT;
|
||||
irp.xstat_version = version;
|
||||
irp.xstat_file = file;
|
||||
irp.xstat_buf = buf;
|
||||
|
||||
result = cnh_fshook_invoke_next(&irp);
|
||||
result = cnh_fshook_invoke_next(&irp);
|
||||
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return -1;
|
||||
}
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
errno = 0;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __xstat(int version, const char* file, struct stat* buf)
|
||||
int __xstat(int version, const char *file, struct stat *buf)
|
||||
{
|
||||
struct cnh_fshook_irp irp;
|
||||
enum cnh_result result;
|
||||
struct cnh_fshook_irp irp;
|
||||
enum cnh_result result;
|
||||
|
||||
/* Ensure module is initialized */
|
||||
_cnh_fshook_init();
|
||||
/* Ensure module is initialized */
|
||||
_cnh_fshook_init();
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_FSHOOK_IRP_OP_XSTAT;
|
||||
irp.xstat_version = version;
|
||||
irp.xstat_file = file;
|
||||
irp.xstat_buf = buf;
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_FSHOOK_IRP_OP_XSTAT;
|
||||
irp.xstat_version = version;
|
||||
irp.xstat_file = file;
|
||||
irp.xstat_buf = buf;
|
||||
|
||||
result = cnh_fshook_invoke_next(&irp);
|
||||
result = cnh_fshook_invoke_next(&irp);
|
||||
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return -1;
|
||||
}
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
errno = 0;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rename(const char* old, const char* new)
|
||||
int rename(const char *old, const char *new)
|
||||
{
|
||||
struct cnh_fshook_irp irp;
|
||||
enum cnh_result result;
|
||||
struct cnh_fshook_irp irp;
|
||||
enum cnh_result result;
|
||||
|
||||
/* Ensure module is initialized */
|
||||
_cnh_fshook_init();
|
||||
/* Ensure module is initialized */
|
||||
_cnh_fshook_init();
|
||||
|
||||
if (old == NULL || new == NULL) {
|
||||
errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER);
|
||||
return -1;
|
||||
}
|
||||
if (old == NULL || new == NULL) {
|
||||
errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_FSHOOK_IRP_OP_RENAME;
|
||||
irp.rename_old = old;
|
||||
irp.rename_new = new;
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_FSHOOK_IRP_OP_RENAME;
|
||||
irp.rename_old = old;
|
||||
irp.rename_new = new;
|
||||
|
||||
result = cnh_fshook_invoke_next(&irp);
|
||||
result = cnh_fshook_invoke_next(&irp);
|
||||
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return -1;
|
||||
}
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
errno = 0;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int remove(const char* pathname)
|
||||
int remove(const char *pathname)
|
||||
{
|
||||
struct cnh_fshook_irp irp;
|
||||
enum cnh_result result;
|
||||
struct cnh_fshook_irp irp;
|
||||
enum cnh_result result;
|
||||
|
||||
/* Ensure module is initialized */
|
||||
_cnh_fshook_init();
|
||||
/* Ensure module is initialized */
|
||||
_cnh_fshook_init();
|
||||
|
||||
if (pathname == NULL) {
|
||||
errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER);
|
||||
return -1;
|
||||
}
|
||||
if (pathname == NULL) {
|
||||
errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_FSHOOK_IRP_OP_REMOVE;
|
||||
irp.remove_pathname = pathname;
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_FSHOOK_IRP_OP_REMOVE;
|
||||
irp.remove_pathname = pathname;
|
||||
|
||||
result = cnh_fshook_invoke_next(&irp);
|
||||
result = cnh_fshook_invoke_next(&irp);
|
||||
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return -1;
|
||||
}
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
errno = 0;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int access(const char* path, int amode)
|
||||
int access(const char *path, int amode)
|
||||
{
|
||||
struct cnh_fshook_irp irp;
|
||||
enum cnh_result result;
|
||||
struct cnh_fshook_irp irp;
|
||||
enum cnh_result result;
|
||||
|
||||
/* Ensure module is initialized */
|
||||
_cnh_fshook_init();
|
||||
/* Ensure module is initialized */
|
||||
_cnh_fshook_init();
|
||||
|
||||
if (path == NULL) {
|
||||
errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER);
|
||||
return -1;
|
||||
}
|
||||
if (path == NULL) {
|
||||
errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_FSHOOK_IRP_OP_ACCESS;
|
||||
irp.access_path = path;
|
||||
irp.access_amode = amode;
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_FSHOOK_IRP_OP_ACCESS;
|
||||
irp.access_path = path;
|
||||
irp.access_amode = amode;
|
||||
|
||||
result = cnh_fshook_invoke_next(&irp);
|
||||
result = cnh_fshook_invoke_next(&irp);
|
||||
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return -1;
|
||||
}
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
errno = 0;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Helper functions */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _cnh_fshook_init(void)
|
||||
{
|
||||
int expected;
|
||||
int expected;
|
||||
|
||||
if (atomic_load(&_cnh_fshook_initted) > 0) {
|
||||
return;
|
||||
if (atomic_load(&_cnh_fshook_initted) > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
expected = 0;
|
||||
|
||||
if (!atomic_compare_exchange_strong(
|
||||
&_cnh_fshook_init_in_progress, &expected, 1)) {
|
||||
while (atomic_load(&_cnh_fshook_init_in_progress) > 1) {
|
||||
util_time_sleep_us(100);
|
||||
}
|
||||
|
||||
expected = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!atomic_compare_exchange_strong(&_cnh_fshook_init_in_progress, &expected, 1)) {
|
||||
while (atomic_load(&_cnh_fshook_init_in_progress) > 1) {
|
||||
util_time_sleep_us(100);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check again to ensure the current thread yielded between the init'd check and setting init in progress */
|
||||
if (atomic_load(&_cnh_fshook_initted) > 0) {
|
||||
/* Revert init in progress, because nothing to do anymore */
|
||||
atomic_store(&_cnh_fshook_init_in_progress, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
_cnh_fshook_real_opendir = (cnh_fshook_opendir_t) cnh_lib_get_func_addr("opendir");
|
||||
_cnh_fshook_real_lxstat = (cnh_fshook_lxstat_t) cnh_lib_get_func_addr("__lxstat");
|
||||
_cnh_fshook_real_xstat = (cnh_fshook_xstat_t) cnh_lib_get_func_addr("__xstat");
|
||||
_cnh_fshook_real_rename = (cnh_fshook_rename_t) cnh_lib_get_func_addr("rename");
|
||||
_cnh_fshook_real_remove = (cnh_fshook_remove_t) cnh_lib_get_func_addr("remove");
|
||||
_cnh_fshook_real_access = (cnh_fshook_access_t) cnh_lib_get_func_addr("access");
|
||||
|
||||
pthread_mutex_init(&_cnh_fshook_lock, NULL);
|
||||
|
||||
atomic_store(&_cnh_fshook_initted, 1);
|
||||
/* Check again to ensure the current thread yielded between the init'd check
|
||||
* and setting init in progress */
|
||||
if (atomic_load(&_cnh_fshook_initted) > 0) {
|
||||
/* Revert init in progress, because nothing to do anymore */
|
||||
atomic_store(&_cnh_fshook_init_in_progress, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
_cnh_fshook_real_opendir =
|
||||
(cnh_fshook_opendir_t) cnh_lib_get_func_addr("opendir");
|
||||
_cnh_fshook_real_lxstat =
|
||||
(cnh_fshook_lxstat_t) cnh_lib_get_func_addr("__lxstat");
|
||||
_cnh_fshook_real_xstat =
|
||||
(cnh_fshook_xstat_t) cnh_lib_get_func_addr("__xstat");
|
||||
_cnh_fshook_real_rename =
|
||||
(cnh_fshook_rename_t) cnh_lib_get_func_addr("rename");
|
||||
_cnh_fshook_real_remove =
|
||||
(cnh_fshook_remove_t) cnh_lib_get_func_addr("remove");
|
||||
_cnh_fshook_real_access =
|
||||
(cnh_fshook_access_t) cnh_lib_get_func_addr("access");
|
||||
|
||||
pthread_mutex_init(&_cnh_fshook_lock, NULL);
|
||||
|
||||
atomic_store(&_cnh_fshook_initted, 1);
|
||||
atomic_store(&_cnh_fshook_init_in_progress, 0);
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_fshook_invoke_real(struct cnh_fshook_irp *irp)
|
||||
{
|
||||
cnh_fshook_fn_t handler;
|
||||
cnh_fshook_fn_t handler;
|
||||
|
||||
assert(irp != NULL);
|
||||
assert(irp->op < _countof(_cnh_fshook_real_handlers));
|
||||
assert(irp != NULL);
|
||||
assert(irp->op < _countof(_cnh_fshook_real_handlers));
|
||||
|
||||
handler = _cnh_fshook_real_handlers[irp->op];
|
||||
handler = _cnh_fshook_real_handlers[irp->op];
|
||||
|
||||
assert(handler != NULL);
|
||||
assert(handler != NULL);
|
||||
|
||||
return handler(irp);
|
||||
return handler(irp);
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_fshook_invoke_real_opendir(struct cnh_fshook_irp *irp)
|
||||
static enum cnh_result
|
||||
_cnh_fshook_invoke_real_opendir(struct cnh_fshook_irp *irp)
|
||||
{
|
||||
DIR* dir;
|
||||
DIR *dir;
|
||||
|
||||
assert(irp != NULL);
|
||||
assert(irp != NULL);
|
||||
|
||||
dir = _cnh_fshook_real_opendir(irp->opendir_name);
|
||||
dir = _cnh_fshook_real_opendir(irp->opendir_name);
|
||||
|
||||
if (dir == NULL) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
if (dir == NULL) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
|
||||
irp->opendir_ret = dir;
|
||||
irp->opendir_ret = dir;
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_fshook_invoke_real_lxstat(struct cnh_fshook_irp *irp)
|
||||
static enum cnh_result
|
||||
_cnh_fshook_invoke_real_lxstat(struct cnh_fshook_irp *irp)
|
||||
{
|
||||
int res;
|
||||
int res;
|
||||
|
||||
assert(irp != NULL);
|
||||
assert(irp != NULL);
|
||||
|
||||
res = _cnh_fshook_real_lxstat(irp->xstat_version, irp->xstat_file, irp->xstat_buf);
|
||||
res = _cnh_fshook_real_lxstat(
|
||||
irp->xstat_version, irp->xstat_file, irp->xstat_buf);
|
||||
|
||||
if (res != 0) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
if (res != 0) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_fshook_invoke_real_xstat(struct cnh_fshook_irp *irp)
|
||||
{
|
||||
int res;
|
||||
int res;
|
||||
|
||||
assert(irp != NULL);
|
||||
assert(irp != NULL);
|
||||
|
||||
res = _cnh_fshook_real_xstat(irp->xstat_version, irp->xstat_file, irp->xstat_buf);
|
||||
res = _cnh_fshook_real_xstat(
|
||||
irp->xstat_version, irp->xstat_file, irp->xstat_buf);
|
||||
|
||||
if (res != 0) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
if (res != 0) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_fshook_invoke_real_rename(struct cnh_fshook_irp *irp)
|
||||
static enum cnh_result
|
||||
_cnh_fshook_invoke_real_rename(struct cnh_fshook_irp *irp)
|
||||
{
|
||||
int res;
|
||||
int res;
|
||||
|
||||
assert(irp != NULL);
|
||||
assert(irp != NULL);
|
||||
|
||||
res = _cnh_fshook_real_rename(irp->rename_old, irp->rename_new);
|
||||
res = _cnh_fshook_real_rename(irp->rename_old, irp->rename_new);
|
||||
|
||||
if (res != 0) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
if (res != 0) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_fshook_invoke_real_remove(struct cnh_fshook_irp *irp)
|
||||
static enum cnh_result
|
||||
_cnh_fshook_invoke_real_remove(struct cnh_fshook_irp *irp)
|
||||
{
|
||||
int res;
|
||||
int res;
|
||||
|
||||
assert(irp != NULL);
|
||||
assert(irp != NULL);
|
||||
|
||||
res = _cnh_fshook_real_remove(irp->remove_pathname);
|
||||
res = _cnh_fshook_real_remove(irp->remove_pathname);
|
||||
|
||||
if (res != 0) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
if (res != 0) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_fshook_invoke_real_access(struct cnh_fshook_irp *irp)
|
||||
static enum cnh_result
|
||||
_cnh_fshook_invoke_real_access(struct cnh_fshook_irp *irp)
|
||||
{
|
||||
int res;
|
||||
int res;
|
||||
|
||||
assert(irp != NULL);
|
||||
assert(irp != NULL);
|
||||
|
||||
res = _cnh_fshook_real_access(irp->access_path, irp->access_amode);
|
||||
res = _cnh_fshook_real_access(irp->access_path, irp->access_amode);
|
||||
|
||||
if (res != 0) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
if (res != 0) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
@@ -19,30 +19,30 @@
|
||||
* Available operations to hook
|
||||
*/
|
||||
enum cnh_fshook_irp_op {
|
||||
CNH_FSHOOK_IRP_OP_DIR_OPEN = 0,
|
||||
CNH_FSHOOK_IRP_OP_LXSTAT = 1,
|
||||
CNH_FSHOOK_IRP_OP_XSTAT = 2,
|
||||
CNH_FSHOOK_IRP_OP_RENAME = 3,
|
||||
CNH_FSHOOK_IRP_OP_REMOVE = 4,
|
||||
CNH_FSHOOK_IRP_OP_ACCESS = 5,
|
||||
CNH_FSHOOK_IRP_OP_DIR_OPEN = 0,
|
||||
CNH_FSHOOK_IRP_OP_LXSTAT = 1,
|
||||
CNH_FSHOOK_IRP_OP_XSTAT = 2,
|
||||
CNH_FSHOOK_IRP_OP_RENAME = 3,
|
||||
CNH_FSHOOK_IRP_OP_REMOVE = 4,
|
||||
CNH_FSHOOK_IRP_OP_ACCESS = 5,
|
||||
};
|
||||
|
||||
/**
|
||||
* I/O request packet
|
||||
*/
|
||||
struct cnh_fshook_irp {
|
||||
enum cnh_fshook_irp_op op;
|
||||
size_t next_handler;
|
||||
const char* opendir_name;
|
||||
DIR* opendir_ret;
|
||||
int xstat_version;
|
||||
const char* xstat_file;
|
||||
struct stat* xstat_buf;
|
||||
const char* rename_old;
|
||||
const char* rename_new;
|
||||
const char* remove_pathname;
|
||||
const char* access_path;
|
||||
int access_amode;
|
||||
enum cnh_fshook_irp_op op;
|
||||
size_t next_handler;
|
||||
const char *opendir_name;
|
||||
DIR *opendir_ret;
|
||||
int xstat_version;
|
||||
const char *xstat_file;
|
||||
struct stat *xstat_buf;
|
||||
const char *rename_old;
|
||||
const char *rename_new;
|
||||
const char *remove_pathname;
|
||||
const char *access_path;
|
||||
int access_amode;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+138
-136
@@ -5,249 +5,251 @@
|
||||
|
||||
void cnh_iobuf_flip(struct cnh_const_iobuf *child, struct cnh_iobuf *parent)
|
||||
{
|
||||
assert(child != NULL);
|
||||
assert(parent != NULL);
|
||||
assert(child != NULL);
|
||||
assert(parent != NULL);
|
||||
|
||||
child->bytes = parent->bytes;
|
||||
child->pos = 0;
|
||||
child->nbytes = parent->pos;
|
||||
child->bytes = parent->bytes;
|
||||
child->pos = 0;
|
||||
child->nbytes = parent->pos;
|
||||
}
|
||||
|
||||
size_t cnh_iobuf_move(struct cnh_iobuf *dest, struct cnh_const_iobuf *src)
|
||||
{
|
||||
size_t dest_avail;
|
||||
size_t src_avail;
|
||||
size_t chunksz;
|
||||
size_t dest_avail;
|
||||
size_t src_avail;
|
||||
size_t chunksz;
|
||||
|
||||
assert(dest != NULL);
|
||||
assert(dest->bytes != NULL || dest->nbytes == 0);
|
||||
assert(dest->pos <= dest->nbytes);
|
||||
assert(dest != NULL);
|
||||
assert(dest->bytes != NULL || dest->nbytes == 0);
|
||||
assert(dest->pos <= dest->nbytes);
|
||||
|
||||
assert(src != NULL);
|
||||
assert(src->bytes != NULL || src->nbytes == 0);
|
||||
assert(src->pos <= src->nbytes);
|
||||
assert(src != NULL);
|
||||
assert(src->bytes != NULL || src->nbytes == 0);
|
||||
assert(src->pos <= src->nbytes);
|
||||
|
||||
dest_avail = dest->nbytes - dest->pos;
|
||||
src_avail = src->nbytes - src->pos;
|
||||
chunksz = dest_avail < src_avail ? dest_avail : src_avail;
|
||||
dest_avail = dest->nbytes - dest->pos;
|
||||
src_avail = src->nbytes - src->pos;
|
||||
chunksz = dest_avail < src_avail ? dest_avail : src_avail;
|
||||
|
||||
memcpy(&dest->bytes[dest->pos], &src->bytes[src->pos], chunksz);
|
||||
memcpy(&dest->bytes[dest->pos], &src->bytes[src->pos], chunksz);
|
||||
|
||||
dest->pos += chunksz;
|
||||
src->pos += chunksz;
|
||||
dest->pos += chunksz;
|
||||
src->pos += chunksz;
|
||||
|
||||
return chunksz;
|
||||
return chunksz;
|
||||
}
|
||||
|
||||
size_t cnh_iobuf_shift(struct cnh_iobuf *dest, struct cnh_iobuf *src)
|
||||
{
|
||||
struct cnh_const_iobuf span;
|
||||
struct cnh_const_iobuf span;
|
||||
|
||||
assert(dest != NULL);
|
||||
assert(src != NULL);
|
||||
assert(dest != NULL);
|
||||
assert(src != NULL);
|
||||
|
||||
cnh_iobuf_flip(&span, src);
|
||||
cnh_iobuf_move(dest, &span);
|
||||
cnh_iobuf_flip(&span, src);
|
||||
cnh_iobuf_move(dest, &span);
|
||||
|
||||
memmove(src->bytes, &src->bytes[span.pos], span.nbytes - span.pos);
|
||||
src->pos -= span.pos;
|
||||
memmove(src->bytes, &src->bytes[span.pos], span.nbytes - span.pos);
|
||||
src->pos -= span.pos;
|
||||
|
||||
return span.pos;
|
||||
return span.pos;
|
||||
}
|
||||
|
||||
enum cnh_result cnh_iobuf_read(struct cnh_const_iobuf *src, void *bytes, size_t nbytes)
|
||||
enum cnh_result
|
||||
cnh_iobuf_read(struct cnh_const_iobuf *src, void *bytes, size_t nbytes)
|
||||
{
|
||||
assert(src != NULL);
|
||||
assert(bytes != NULL || nbytes == 0);
|
||||
assert(src != NULL);
|
||||
assert(bytes != NULL || nbytes == 0);
|
||||
|
||||
if (src->pos + nbytes > src->nbytes) {
|
||||
return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
if (src->pos + nbytes > src->nbytes) {
|
||||
return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
memcpy(bytes, &src->bytes[src->pos], nbytes);
|
||||
src->pos += nbytes;
|
||||
memcpy(bytes, &src->bytes[src->pos], nbytes);
|
||||
src->pos += nbytes;
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
enum cnh_result cnh_iobuf_read_8(struct cnh_const_iobuf *src, uint8_t *out)
|
||||
{
|
||||
assert(src != NULL);
|
||||
assert(out != NULL);
|
||||
assert(src != NULL);
|
||||
assert(out != NULL);
|
||||
|
||||
if (src->pos + sizeof(uint8_t) > src->nbytes) {
|
||||
return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
if (src->pos + sizeof(uint8_t) > src->nbytes) {
|
||||
return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
*out = src->bytes[src->pos++];
|
||||
*out = src->bytes[src->pos++];
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
enum cnh_result cnh_iobuf_read_be16(struct cnh_const_iobuf *src, uint16_t *out)
|
||||
{
|
||||
uint16_t value;
|
||||
uint16_t value;
|
||||
|
||||
assert(src != NULL);
|
||||
assert(out != NULL);
|
||||
assert(src != NULL);
|
||||
assert(out != NULL);
|
||||
|
||||
if (src->pos + sizeof(uint16_t) > src->nbytes) {
|
||||
return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
if (src->pos + sizeof(uint16_t) > src->nbytes) {
|
||||
return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
value = src->bytes[src->pos++] << 8;
|
||||
value |= src->bytes[src->pos++];
|
||||
value = src->bytes[src->pos++] << 8;
|
||||
value |= src->bytes[src->pos++];
|
||||
|
||||
*out = value;
|
||||
*out = value;
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
enum cnh_result cnh_iobuf_read_be32(struct cnh_const_iobuf *src, uint32_t *out)
|
||||
{
|
||||
uint32_t value;
|
||||
uint32_t value;
|
||||
|
||||
assert(src != NULL);
|
||||
assert(out != NULL);
|
||||
assert(src != NULL);
|
||||
assert(out != NULL);
|
||||
|
||||
if (src->pos + sizeof(uint32_t) > src->nbytes) {
|
||||
return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
if (src->pos + sizeof(uint32_t) > src->nbytes) {
|
||||
return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
value = src->bytes[src->pos++] << 24;
|
||||
value |= src->bytes[src->pos++] << 16;
|
||||
value |= src->bytes[src->pos++] << 8;
|
||||
value |= src->bytes[src->pos++];
|
||||
value = src->bytes[src->pos++] << 24;
|
||||
value |= src->bytes[src->pos++] << 16;
|
||||
value |= src->bytes[src->pos++] << 8;
|
||||
value |= src->bytes[src->pos++];
|
||||
|
||||
*out = value;
|
||||
*out = value;
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
enum cnh_result cnh_iobuf_read_le16(struct cnh_const_iobuf *src, uint16_t *out)
|
||||
{
|
||||
uint16_t value;
|
||||
uint16_t value;
|
||||
|
||||
assert(src != NULL);
|
||||
assert(out != NULL);
|
||||
assert(src != NULL);
|
||||
assert(out != NULL);
|
||||
|
||||
if (src->pos + sizeof(uint16_t) > src->nbytes) {
|
||||
return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
if (src->pos + sizeof(uint16_t) > src->nbytes) {
|
||||
return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
value = src->bytes[src->pos++];
|
||||
value |= src->bytes[src->pos++] << 8;
|
||||
value = src->bytes[src->pos++];
|
||||
value |= src->bytes[src->pos++] << 8;
|
||||
|
||||
*out = value;
|
||||
*out = value;
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
enum cnh_result cnh_iobuf_read_le32(struct cnh_const_iobuf *src, uint32_t *out)
|
||||
{
|
||||
uint32_t value;
|
||||
uint32_t value;
|
||||
|
||||
assert(src != NULL);
|
||||
assert(out != NULL);
|
||||
assert(src != NULL);
|
||||
assert(out != NULL);
|
||||
|
||||
if (src->pos + sizeof(uint32_t) > src->nbytes) {
|
||||
return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
if (src->pos + sizeof(uint32_t) > src->nbytes) {
|
||||
return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
value = src->bytes[src->pos++];
|
||||
value |= src->bytes[src->pos++] << 8;
|
||||
value |= src->bytes[src->pos++] << 16;
|
||||
value |= src->bytes[src->pos++] << 24;
|
||||
value = src->bytes[src->pos++];
|
||||
value |= src->bytes[src->pos++] << 8;
|
||||
value |= src->bytes[src->pos++] << 16;
|
||||
value |= src->bytes[src->pos++] << 24;
|
||||
|
||||
*out = value;
|
||||
*out = value;
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
enum cnh_result cnh_iobuf_write(struct cnh_iobuf *dest, const void *bytes, size_t nbytes)
|
||||
enum cnh_result
|
||||
cnh_iobuf_write(struct cnh_iobuf *dest, const void *bytes, size_t nbytes)
|
||||
{
|
||||
assert(dest != NULL);
|
||||
assert(bytes != NULL || nbytes == 0);
|
||||
assert(dest != NULL);
|
||||
assert(bytes != NULL || nbytes == 0);
|
||||
|
||||
if (dest->pos + nbytes > dest->nbytes) {
|
||||
return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
if (dest->pos + nbytes > dest->nbytes) {
|
||||
return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
memcpy(&dest->bytes[dest->pos], bytes, nbytes);
|
||||
dest->pos += nbytes;
|
||||
memcpy(&dest->bytes[dest->pos], bytes, nbytes);
|
||||
dest->pos += nbytes;
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
enum cnh_result cnh_iobuf_write_8(struct cnh_iobuf *dest, uint8_t value)
|
||||
{
|
||||
assert(dest != NULL);
|
||||
assert(dest != NULL);
|
||||
|
||||
if (dest->pos + sizeof(uint8_t) > dest->nbytes) {
|
||||
return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
if (dest->pos + sizeof(uint8_t) > dest->nbytes) {
|
||||
return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
dest->bytes[dest->pos++] = value;
|
||||
dest->bytes[dest->pos++] = value;
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
enum cnh_result cnh_iobuf_write_be16(struct cnh_iobuf *dest, uint16_t value)
|
||||
{
|
||||
assert(dest != NULL);
|
||||
assert(dest != NULL);
|
||||
|
||||
if (dest->pos + sizeof(uint16_t) > dest->nbytes) {
|
||||
return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
if (dest->pos + sizeof(uint16_t) > dest->nbytes) {
|
||||
return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
dest->bytes[dest->pos++] = (uint8_t) (value >> 8);
|
||||
dest->bytes[dest->pos++] = (uint8_t) value;
|
||||
dest->bytes[dest->pos++] = (uint8_t)(value >> 8);
|
||||
dest->bytes[dest->pos++] = (uint8_t) value;
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
enum cnh_result cnh_iobuf_write_be32(struct cnh_iobuf *dest, uint32_t value)
|
||||
{
|
||||
assert(dest != NULL);
|
||||
assert(dest != NULL);
|
||||
|
||||
if (dest->pos + sizeof(uint32_t) > dest->nbytes) {
|
||||
return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
if (dest->pos + sizeof(uint32_t) > dest->nbytes) {
|
||||
return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
dest->bytes[dest->pos++] = (uint8_t) (value >> 24);
|
||||
dest->bytes[dest->pos++] = (uint8_t) (value >> 16);
|
||||
dest->bytes[dest->pos++] = (uint8_t) (value >> 8);
|
||||
dest->bytes[dest->pos++] = (uint8_t) value;
|
||||
dest->bytes[dest->pos++] = (uint8_t)(value >> 24);
|
||||
dest->bytes[dest->pos++] = (uint8_t)(value >> 16);
|
||||
dest->bytes[dest->pos++] = (uint8_t)(value >> 8);
|
||||
dest->bytes[dest->pos++] = (uint8_t) value;
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
enum cnh_result cnh_iobuf_write_le16(struct cnh_iobuf *dest, uint16_t value)
|
||||
{
|
||||
assert(dest != NULL);
|
||||
assert(dest != NULL);
|
||||
|
||||
if (dest->pos + sizeof(uint16_t) > dest->nbytes) {
|
||||
return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
if (dest->pos + sizeof(uint16_t) > dest->nbytes) {
|
||||
return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
dest->bytes[dest->pos++] = (uint8_t) value;
|
||||
dest->bytes[dest->pos++] = (uint8_t) (value >> 8);
|
||||
dest->bytes[dest->pos++] = (uint8_t) value;
|
||||
dest->bytes[dest->pos++] = (uint8_t)(value >> 8);
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
enum cnh_result cnh_iobuf_write_le32(struct cnh_iobuf *dest, uint32_t value)
|
||||
{
|
||||
assert(dest != NULL);
|
||||
assert(dest != NULL);
|
||||
|
||||
if (dest->pos + sizeof(uint32_t) > dest->nbytes) {
|
||||
return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
if (dest->pos + sizeof(uint32_t) > dest->nbytes) {
|
||||
return CNH_RESULT_ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
dest->bytes[dest->pos++] = (uint8_t) value;
|
||||
dest->bytes[dest->pos++] = (uint8_t) (value >> 8);
|
||||
dest->bytes[dest->pos++] = (uint8_t) (value >> 16);
|
||||
dest->bytes[dest->pos++] = (uint8_t) (value >> 24);
|
||||
dest->bytes[dest->pos++] = (uint8_t) value;
|
||||
dest->bytes[dest->pos++] = (uint8_t)(value >> 8);
|
||||
dest->bytes[dest->pos++] = (uint8_t)(value >> 16);
|
||||
dest->bytes[dest->pos++] = (uint8_t)(value >> 24);
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -16,18 +16,18 @@
|
||||
* I/O buffer
|
||||
*/
|
||||
struct cnh_iobuf {
|
||||
uint8_t *bytes;
|
||||
size_t nbytes;
|
||||
size_t pos;
|
||||
uint8_t *bytes;
|
||||
size_t nbytes;
|
||||
size_t pos;
|
||||
};
|
||||
|
||||
/**
|
||||
* I/O buffer
|
||||
*/
|
||||
struct cnh_const_iobuf {
|
||||
const uint8_t *bytes;
|
||||
size_t nbytes;
|
||||
size_t pos;
|
||||
const uint8_t *bytes;
|
||||
size_t nbytes;
|
||||
size_t pos;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -39,10 +39,12 @@ struct cnh_const_iobuf {
|
||||
void cnh_iobuf_flip(struct cnh_const_iobuf *child, struct cnh_iobuf *parent);
|
||||
|
||||
/**
|
||||
* Move the contents currently enclosed by pos and end of an I/O buffer to a destination.
|
||||
* Move the contents currently enclosed by pos and end of an I/O buffer to a
|
||||
* destination.
|
||||
*
|
||||
* @param dest Destination buffer to move the source to, starting at current pos
|
||||
* @param src Source to move to the destination, starting at current pos up to end of the buffer
|
||||
* @param src Source to move to the destination, starting at current pos up to
|
||||
* end of the buffer
|
||||
* @return Number of bytes copied to destination
|
||||
*/
|
||||
size_t cnh_iobuf_move(struct cnh_iobuf *dest, struct cnh_const_iobuf *src);
|
||||
@@ -57,7 +59,8 @@ size_t cnh_iobuf_shift(struct cnh_iobuf *dest, struct cnh_iobuf *src);
|
||||
* @param nbytes Number of bytes to read
|
||||
* @return Result of operation
|
||||
*/
|
||||
enum cnh_result cnh_iobuf_read(struct cnh_const_iobuf *src, void *bytes, size_t nbytes);
|
||||
enum cnh_result
|
||||
cnh_iobuf_read(struct cnh_const_iobuf *src, void *bytes, size_t nbytes);
|
||||
|
||||
/**
|
||||
* Read a byte from an I/O buffer
|
||||
@@ -75,7 +78,8 @@ enum cnh_result cnh_iobuf_read_8(struct cnh_const_iobuf *src, uint8_t *value);
|
||||
* @param value Pointer to variable to read the data into
|
||||
* @return Result of operation
|
||||
*/
|
||||
enum cnh_result cnh_iobuf_read_be16(struct cnh_const_iobuf *src, uint16_t *value);
|
||||
enum cnh_result
|
||||
cnh_iobuf_read_be16(struct cnh_const_iobuf *src, uint16_t *value);
|
||||
|
||||
/**
|
||||
* Read a 4 byte value, big endian byte order, from an I/O buffer
|
||||
@@ -84,7 +88,8 @@ enum cnh_result cnh_iobuf_read_be16(struct cnh_const_iobuf *src, uint16_t *value
|
||||
* @param value Pointer to variable to read the data into
|
||||
* @return Result of operation
|
||||
*/
|
||||
enum cnh_result cnh_iobuf_read_be32(struct cnh_const_iobuf *src, uint32_t *value);
|
||||
enum cnh_result
|
||||
cnh_iobuf_read_be32(struct cnh_const_iobuf *src, uint32_t *value);
|
||||
|
||||
/**
|
||||
* Read a 2 byte value, little endian byte order, from an I/O buffer
|
||||
@@ -93,7 +98,8 @@ enum cnh_result cnh_iobuf_read_be32(struct cnh_const_iobuf *src, uint32_t *value
|
||||
* @param value Pointer to variable to read the data into
|
||||
* @return Result of operation
|
||||
*/
|
||||
enum cnh_result cnh_iobuf_read_le16(struct cnh_const_iobuf *src, uint16_t *value);
|
||||
enum cnh_result
|
||||
cnh_iobuf_read_le16(struct cnh_const_iobuf *src, uint16_t *value);
|
||||
|
||||
/**
|
||||
* Read a 4 byte value, little endian byte order, from an I/O buffer
|
||||
@@ -102,7 +108,8 @@ enum cnh_result cnh_iobuf_read_le16(struct cnh_const_iobuf *src, uint16_t *value
|
||||
* @param value Pointer to variable to read the data into
|
||||
* @return Result of operation
|
||||
*/
|
||||
enum cnh_result cnh_iobuf_read_le32(struct cnh_const_iobuf *src, uint32_t *value);
|
||||
enum cnh_result
|
||||
cnh_iobuf_read_le32(struct cnh_const_iobuf *src, uint32_t *value);
|
||||
|
||||
/**
|
||||
* Write data to an I/O buffer
|
||||
@@ -112,7 +119,8 @@ enum cnh_result cnh_iobuf_read_le32(struct cnh_const_iobuf *src, uint32_t *value
|
||||
* @param nbytes Number of bytes to write
|
||||
* @return Result of operation
|
||||
*/
|
||||
enum cnh_result cnh_iobuf_write(struct cnh_iobuf *dest, const void *bytes, size_t nbytes);
|
||||
enum cnh_result
|
||||
cnh_iobuf_write(struct cnh_iobuf *dest, const void *bytes, size_t nbytes);
|
||||
|
||||
/**
|
||||
* Write a byte to an I/O buffer
|
||||
|
||||
+332
-305
@@ -15,36 +15,46 @@
|
||||
|
||||
#define INVALID_FILE_DEVICE (-1)
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Real funcs typedefs */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
typedef int (*cnh_iohook_open_t)(const char* path, int oflag);
|
||||
typedef FILE* (*cnh_iohook_fdopen_t)(int fd, const char* mode);
|
||||
typedef ssize_t (*cnh_iohook_write_t)(int fd, const void* buf, size_t count);
|
||||
typedef ssize_t (*cnh_iohook_read_t)(int fd, void* buf, size_t count);
|
||||
typedef int (*cnh_iohook_open_t)(const char *path, int oflag);
|
||||
typedef FILE *(*cnh_iohook_fdopen_t)(int fd, const char *mode);
|
||||
typedef ssize_t (*cnh_iohook_write_t)(int fd, const void *buf, size_t count);
|
||||
typedef ssize_t (*cnh_iohook_read_t)(int fd, void *buf, size_t count);
|
||||
typedef off_t (*cnh_iohook_lseek_t)(int fildes, off_t offset, int whence);
|
||||
typedef int (*cnh_iohook_ioctl_t)(int fd, int request, void* data);
|
||||
typedef int (*cnh_iohook_ioctl_t)(int fd, int request, void *data);
|
||||
typedef int (*cnh_iohook_close_t)(int fd);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Private helpers */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _cnh_iohook_init(void);
|
||||
|
||||
static enum cnh_result _cnh_iohook_invoke_real(struct cnh_iohook_irp *irp);
|
||||
static enum cnh_result _cnh_iohook_invoke_real_open(struct cnh_iohook_irp *irp);
|
||||
static enum cnh_result _cnh_iohook_invoke_real_fdopen(struct cnh_iohook_irp *irp);
|
||||
static enum cnh_result _cnh_iohook_invoke_real_close(struct cnh_iohook_irp *irp);
|
||||
static enum cnh_result
|
||||
_cnh_iohook_invoke_real_fdopen(struct cnh_iohook_irp *irp);
|
||||
static enum cnh_result
|
||||
_cnh_iohook_invoke_real_close(struct cnh_iohook_irp *irp);
|
||||
static enum cnh_result _cnh_iohook_invoke_real_read(struct cnh_iohook_irp *irp);
|
||||
static enum cnh_result _cnh_iohook_invoke_real_write(struct cnh_iohook_irp *irp);
|
||||
static enum cnh_result
|
||||
_cnh_iohook_invoke_real_write(struct cnh_iohook_irp *irp);
|
||||
static enum cnh_result _cnh_iohook_invoke_real_seek(struct cnh_iohook_irp *irp);
|
||||
static enum cnh_result _cnh_iohook_invoke_real_ioctl(struct cnh_iohook_irp *irp);
|
||||
static enum cnh_result
|
||||
_cnh_iohook_invoke_real_ioctl(struct cnh_iohook_irp *irp);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Private state */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static cnh_iohook_open_t _cnh_iohook_real_open;
|
||||
static cnh_iohook_fdopen_t _cnh_iohook_real_fdopen;
|
||||
@@ -70,483 +80,500 @@ static pthread_mutex_t _cnh_iohook_lock;
|
||||
static cnh_iohook_fn_t *_cnh_iohook_handlers;
|
||||
static size_t _cnh_iohook_nhandlers;
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Public module functions */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
enum cnh_result cnh_iohook_push_handler(cnh_iohook_fn_t fn)
|
||||
{
|
||||
cnh_iohook_fn_t *new_array;
|
||||
size_t new_size;
|
||||
enum cnh_result result;
|
||||
cnh_iohook_fn_t *new_array;
|
||||
size_t new_size;
|
||||
enum cnh_result result;
|
||||
|
||||
assert(fn != NULL);
|
||||
assert(fn != NULL);
|
||||
|
||||
_cnh_iohook_init();
|
||||
pthread_mutex_lock(&_cnh_iohook_lock);
|
||||
_cnh_iohook_init();
|
||||
pthread_mutex_lock(&_cnh_iohook_lock);
|
||||
|
||||
new_size = _cnh_iohook_nhandlers + 1;
|
||||
new_array = realloc(_cnh_iohook_handlers, new_size * sizeof(cnh_iohook_fn_t));
|
||||
new_size = _cnh_iohook_nhandlers + 1;
|
||||
new_array = realloc(_cnh_iohook_handlers, new_size * sizeof(cnh_iohook_fn_t));
|
||||
|
||||
if (new_array != NULL) {
|
||||
_cnh_iohook_handlers = new_array;
|
||||
_cnh_iohook_handlers[_cnh_iohook_nhandlers++] = fn;
|
||||
result = CNH_RESULT_SUCCESS;
|
||||
} else {
|
||||
result = CNH_RESULT_OUT_OF_MEMORY;
|
||||
}
|
||||
if (new_array != NULL) {
|
||||
_cnh_iohook_handlers = new_array;
|
||||
_cnh_iohook_handlers[_cnh_iohook_nhandlers++] = fn;
|
||||
result = CNH_RESULT_SUCCESS;
|
||||
} else {
|
||||
result = CNH_RESULT_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_cnh_iohook_lock);
|
||||
pthread_mutex_unlock(&_cnh_iohook_lock);
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
enum cnh_result cnh_iohook_invoke_next(struct cnh_iohook_irp *irp)
|
||||
{
|
||||
cnh_iohook_fn_t handler;
|
||||
enum cnh_result result;
|
||||
cnh_iohook_fn_t handler;
|
||||
enum cnh_result result;
|
||||
|
||||
assert(irp != NULL);
|
||||
assert(_cnh_iohook_initted > 0);
|
||||
assert(irp != NULL);
|
||||
assert(_cnh_iohook_initted > 0);
|
||||
|
||||
pthread_mutex_lock(&_cnh_iohook_lock);
|
||||
pthread_mutex_lock(&_cnh_iohook_lock);
|
||||
|
||||
assert(irp->next_handler <= _cnh_iohook_nhandlers);
|
||||
assert(irp->next_handler <= _cnh_iohook_nhandlers);
|
||||
|
||||
if (irp->next_handler < _cnh_iohook_nhandlers) {
|
||||
handler = _cnh_iohook_handlers[irp->next_handler];
|
||||
irp->next_handler++;
|
||||
} else {
|
||||
handler = _cnh_iohook_invoke_real;
|
||||
irp->next_handler = (size_t) -1;
|
||||
}
|
||||
if (irp->next_handler < _cnh_iohook_nhandlers) {
|
||||
handler = _cnh_iohook_handlers[irp->next_handler];
|
||||
irp->next_handler++;
|
||||
} else {
|
||||
handler = _cnh_iohook_invoke_real;
|
||||
irp->next_handler = (size_t) -1;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_cnh_iohook_lock);
|
||||
pthread_mutex_unlock(&_cnh_iohook_lock);
|
||||
|
||||
result = handler(irp);
|
||||
result = handler(irp);
|
||||
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
irp->next_handler = (size_t) -1;
|
||||
}
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
irp->next_handler = (size_t) -1;
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
int cnh_iohook_open_dummy_fd()
|
||||
{
|
||||
_cnh_iohook_init();
|
||||
_cnh_iohook_init();
|
||||
|
||||
/* We need to return some sort of valid FD to the
|
||||
caller, since we're simulating a device that
|
||||
doesn't exist. Open an FD on /dev/null. */
|
||||
/* We need to return some sort of valid FD to the
|
||||
caller, since we're simulating a device that
|
||||
doesn't exist. Open an FD on /dev/null. */
|
||||
|
||||
/* Open read only */
|
||||
return _cnh_iohook_real_open("/dev/null", 0);
|
||||
/* Open read only */
|
||||
return _cnh_iohook_real_open("/dev/null", 0);
|
||||
}
|
||||
|
||||
void cnh_iohook_close_dummy_fd(int fd)
|
||||
{
|
||||
_cnh_iohook_init();
|
||||
_cnh_iohook_init();
|
||||
|
||||
/* Avoid hooking pipeline when using dummy handles */
|
||||
_cnh_iohook_real_close(fd);
|
||||
/* Avoid hooking pipeline when using dummy handles */
|
||||
_cnh_iohook_real_close(fd);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Hooked functions */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int open(const char* path, int oflag)
|
||||
int open(const char *path, int oflag)
|
||||
{
|
||||
struct cnh_iohook_irp irp;
|
||||
enum cnh_result result;
|
||||
struct cnh_iohook_irp irp;
|
||||
enum cnh_result result;
|
||||
|
||||
/* Ensure module is initialized */
|
||||
_cnh_iohook_init();
|
||||
/* Ensure module is initialized */
|
||||
_cnh_iohook_init();
|
||||
|
||||
if (path == NULL) {
|
||||
errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER);
|
||||
return INVALID_FILE_DEVICE;
|
||||
}
|
||||
if (path == NULL) {
|
||||
errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER);
|
||||
return INVALID_FILE_DEVICE;
|
||||
}
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_IOHOOK_IRP_OP_OPEN;
|
||||
irp.fd = INVALID_FILE_DEVICE;
|
||||
irp.open_filename = path;
|
||||
irp.open_flags = oflag;
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_IOHOOK_IRP_OP_OPEN;
|
||||
irp.fd = INVALID_FILE_DEVICE;
|
||||
irp.open_filename = path;
|
||||
irp.open_flags = oflag;
|
||||
|
||||
result = cnh_iohook_invoke_next(&irp);
|
||||
result = cnh_iohook_invoke_next(&irp);
|
||||
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return INVALID_FILE_DEVICE;
|
||||
}
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return INVALID_FILE_DEVICE;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
errno = 0;
|
||||
|
||||
return irp.fd;
|
||||
return irp.fd;
|
||||
}
|
||||
|
||||
FILE* fdopen(int fd, const char* mode)
|
||||
FILE *fdopen(int fd, const char *mode)
|
||||
{
|
||||
struct cnh_iohook_irp irp;
|
||||
enum cnh_result result;
|
||||
struct cnh_iohook_irp irp;
|
||||
enum cnh_result result;
|
||||
|
||||
/* Ensure module is initialized */
|
||||
_cnh_iohook_init();
|
||||
/* Ensure module is initialized */
|
||||
_cnh_iohook_init();
|
||||
|
||||
if (fd == -1 || mode == NULL) {
|
||||
errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER);
|
||||
return NULL;
|
||||
}
|
||||
if (fd == -1 || mode == NULL) {
|
||||
errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_IOHOOK_IRP_OP_FDOPEN;
|
||||
irp.fdopen_fd = fd;
|
||||
irp.fdopen_mode = mode;
|
||||
irp.fdopen_res = NULL;
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_IOHOOK_IRP_OP_FDOPEN;
|
||||
irp.fdopen_fd = fd;
|
||||
irp.fdopen_mode = mode;
|
||||
irp.fdopen_res = NULL;
|
||||
|
||||
result = cnh_iohook_invoke_next(&irp);
|
||||
result = cnh_iohook_invoke_next(&irp);
|
||||
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return NULL;
|
||||
}
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
errno = 0;
|
||||
|
||||
return irp.fdopen_res;
|
||||
return irp.fdopen_res;
|
||||
}
|
||||
|
||||
int close(int fd)
|
||||
{
|
||||
struct cnh_iohook_irp irp;
|
||||
enum cnh_result result;
|
||||
struct cnh_iohook_irp irp;
|
||||
enum cnh_result result;
|
||||
|
||||
/* Ensure module is initialized */
|
||||
_cnh_iohook_init();
|
||||
/* Ensure module is initialized */
|
||||
_cnh_iohook_init();
|
||||
|
||||
if (fd == INVALID_FILE_DEVICE) {
|
||||
errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER);
|
||||
return -1;
|
||||
}
|
||||
if (fd == INVALID_FILE_DEVICE) {
|
||||
errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_IOHOOK_IRP_OP_CLOSE;
|
||||
irp.fd = fd;
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_IOHOOK_IRP_OP_CLOSE;
|
||||
irp.fd = fd;
|
||||
|
||||
result = cnh_iohook_invoke_next(&irp);
|
||||
result = cnh_iohook_invoke_next(&irp);
|
||||
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return -1;
|
||||
}
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
errno = 0;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t read(int fd, void* buf, size_t count)
|
||||
ssize_t read(int fd, void *buf, size_t count)
|
||||
{
|
||||
struct cnh_iohook_irp irp;
|
||||
enum cnh_result result;
|
||||
struct cnh_iohook_irp irp;
|
||||
enum cnh_result result;
|
||||
|
||||
/* Ensure module is initialized */
|
||||
_cnh_iohook_init();
|
||||
/* Ensure module is initialized */
|
||||
_cnh_iohook_init();
|
||||
|
||||
if (fd == INVALID_FILE_DEVICE || buf == NULL) {
|
||||
errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER);
|
||||
return -1;
|
||||
}
|
||||
if (fd == INVALID_FILE_DEVICE || buf == NULL) {
|
||||
errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_IOHOOK_IRP_OP_READ;
|
||||
irp.fd = fd;
|
||||
irp.read.bytes = buf;
|
||||
irp.read.nbytes = count;
|
||||
irp.read.pos = 0;
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_IOHOOK_IRP_OP_READ;
|
||||
irp.fd = fd;
|
||||
irp.read.bytes = buf;
|
||||
irp.read.nbytes = count;
|
||||
irp.read.pos = 0;
|
||||
|
||||
result = cnh_iohook_invoke_next(&irp);
|
||||
result = cnh_iohook_invoke_next(&irp);
|
||||
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return -1;
|
||||
}
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(irp.read.pos <= irp.read.nbytes);
|
||||
assert(irp.read.pos <= irp.read.nbytes);
|
||||
|
||||
errno = 0;
|
||||
errno = 0;
|
||||
|
||||
return irp.read.pos;
|
||||
return irp.read.pos;
|
||||
}
|
||||
|
||||
ssize_t write(int fd, const void* buf, size_t count)
|
||||
ssize_t write(int fd, const void *buf, size_t count)
|
||||
{
|
||||
struct cnh_iohook_irp irp;
|
||||
enum cnh_result result;
|
||||
struct cnh_iohook_irp irp;
|
||||
enum cnh_result result;
|
||||
|
||||
/* Ensure module is initialized */
|
||||
_cnh_iohook_init();
|
||||
/* Ensure module is initialized */
|
||||
_cnh_iohook_init();
|
||||
|
||||
if (fd == INVALID_FILE_DEVICE || buf == NULL) {
|
||||
errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER);
|
||||
return -1;
|
||||
}
|
||||
if (fd == INVALID_FILE_DEVICE || buf == NULL) {
|
||||
errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_IOHOOK_IRP_OP_WRITE;
|
||||
irp.fd = fd;
|
||||
irp.write.bytes = buf;
|
||||
irp.write.nbytes = count;
|
||||
irp.write.pos = 0;
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_IOHOOK_IRP_OP_WRITE;
|
||||
irp.fd = fd;
|
||||
irp.write.bytes = buf;
|
||||
irp.write.nbytes = count;
|
||||
irp.write.pos = 0;
|
||||
|
||||
result = cnh_iohook_invoke_next(&irp);
|
||||
result = cnh_iohook_invoke_next(&irp);
|
||||
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return -1;
|
||||
}
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(irp.write.pos <= irp.write.nbytes);
|
||||
assert(irp.write.pos <= irp.write.nbytes);
|
||||
|
||||
errno = 0;
|
||||
errno = 0;
|
||||
|
||||
return irp.write.pos;
|
||||
return irp.write.pos;
|
||||
}
|
||||
|
||||
off_t lseek(int fd, off_t offset, int whence)
|
||||
{
|
||||
struct cnh_iohook_irp irp;
|
||||
enum cnh_result result;
|
||||
struct cnh_iohook_irp irp;
|
||||
enum cnh_result result;
|
||||
|
||||
/* Ensure module is initialized */
|
||||
_cnh_iohook_init();
|
||||
/* Ensure module is initialized */
|
||||
_cnh_iohook_init();
|
||||
|
||||
if (fd == INVALID_FILE_DEVICE) {
|
||||
errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER);
|
||||
return -1;
|
||||
}
|
||||
if (fd == INVALID_FILE_DEVICE) {
|
||||
errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_IOHOOK_IRP_OP_SEEK;
|
||||
irp.fd = fd;
|
||||
irp.seek_origin = whence;
|
||||
irp.seek_offset = offset;
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_IOHOOK_IRP_OP_SEEK;
|
||||
irp.fd = fd;
|
||||
irp.seek_origin = whence;
|
||||
irp.seek_offset = offset;
|
||||
|
||||
result = cnh_iohook_invoke_next(&irp);
|
||||
result = cnh_iohook_invoke_next(&irp);
|
||||
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return -1;
|
||||
}
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
errno = 0;
|
||||
|
||||
return (off_t) irp.seek_pos;
|
||||
return (off_t) irp.seek_pos;
|
||||
}
|
||||
|
||||
int ioctl(int fd, int request, void* data)
|
||||
int ioctl(int fd, int request, void *data)
|
||||
{
|
||||
struct cnh_iohook_irp irp;
|
||||
enum cnh_result result;
|
||||
struct cnh_iohook_irp irp;
|
||||
enum cnh_result result;
|
||||
|
||||
/* Ensure module is initialized */
|
||||
_cnh_iohook_init();
|
||||
/* Ensure module is initialized */
|
||||
_cnh_iohook_init();
|
||||
|
||||
if (fd == INVALID_FILE_DEVICE) {
|
||||
errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER);
|
||||
return -1;
|
||||
}
|
||||
if (fd == INVALID_FILE_DEVICE) {
|
||||
errno = cnh_result_to_errno(CNH_RESULT_INVALID_PARAMETER);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_IOHOOK_IRP_OP_IOCTL;
|
||||
irp.fd = fd;
|
||||
irp.ioctl_req = request;
|
||||
irp.ioctl.bytes = data;
|
||||
memset(&irp, 0, sizeof(irp));
|
||||
irp.op = CNH_IOHOOK_IRP_OP_IOCTL;
|
||||
irp.fd = fd;
|
||||
irp.ioctl_req = request;
|
||||
irp.ioctl.bytes = data;
|
||||
|
||||
result = cnh_iohook_invoke_next(&irp);
|
||||
result = cnh_iohook_invoke_next(&irp);
|
||||
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return -1;
|
||||
}
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
errno = cnh_result_to_errno(result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
errno = 0;
|
||||
|
||||
return irp.ioctl.pos;
|
||||
return irp.ioctl.pos;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Helper functions */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _cnh_iohook_init(void)
|
||||
{
|
||||
int expected;
|
||||
int expected;
|
||||
|
||||
if (atomic_load(&_cnh_iohook_initted) > 0) {
|
||||
return;
|
||||
if (atomic_load(&_cnh_iohook_initted) > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
expected = 0;
|
||||
|
||||
if (!atomic_compare_exchange_strong(
|
||||
&_cnh_iohook_init_in_progress, &expected, 1)) {
|
||||
while (atomic_load(&_cnh_iohook_init_in_progress) > 1) {
|
||||
util_time_sleep_us(100);
|
||||
}
|
||||
|
||||
expected = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!atomic_compare_exchange_strong(&_cnh_iohook_init_in_progress, &expected, 1)) {
|
||||
while (atomic_load(&_cnh_iohook_init_in_progress) > 1) {
|
||||
util_time_sleep_us(100);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check again to ensure the current thread yielded between the init'd check and setting init in progress */
|
||||
if (atomic_load(&_cnh_iohook_initted) > 0) {
|
||||
/* Revert init in progress, because nothing to do anymore */
|
||||
atomic_store(&_cnh_iohook_init_in_progress, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
_cnh_iohook_real_open = (cnh_iohook_open_t) cnh_lib_get_func_addr("open");
|
||||
_cnh_iohook_real_fdopen = (cnh_iohook_fdopen_t) cnh_lib_get_func_addr("fdopen");
|
||||
_cnh_iohook_real_close = (cnh_iohook_close_t) cnh_lib_get_func_addr("close");
|
||||
_cnh_iohook_real_read = (cnh_iohook_read_t) cnh_lib_get_func_addr("read");
|
||||
_cnh_iohook_real_write = (cnh_iohook_write_t) cnh_lib_get_func_addr("write");
|
||||
_cnh_iohook_real_lseek = (cnh_iohook_lseek_t) cnh_lib_get_func_addr("lseek");
|
||||
_cnh_iohook_real_ioctl = (cnh_iohook_ioctl_t) cnh_lib_get_func_addr("ioctl");
|
||||
|
||||
pthread_mutex_init(&_cnh_iohook_lock, NULL);
|
||||
|
||||
atomic_store(&_cnh_iohook_initted, 1);
|
||||
/* Check again to ensure the current thread yielded between the init'd check
|
||||
* and setting init in progress */
|
||||
if (atomic_load(&_cnh_iohook_initted) > 0) {
|
||||
/* Revert init in progress, because nothing to do anymore */
|
||||
atomic_store(&_cnh_iohook_init_in_progress, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
_cnh_iohook_real_open = (cnh_iohook_open_t) cnh_lib_get_func_addr("open");
|
||||
_cnh_iohook_real_fdopen =
|
||||
(cnh_iohook_fdopen_t) cnh_lib_get_func_addr("fdopen");
|
||||
_cnh_iohook_real_close = (cnh_iohook_close_t) cnh_lib_get_func_addr("close");
|
||||
_cnh_iohook_real_read = (cnh_iohook_read_t) cnh_lib_get_func_addr("read");
|
||||
_cnh_iohook_real_write = (cnh_iohook_write_t) cnh_lib_get_func_addr("write");
|
||||
_cnh_iohook_real_lseek = (cnh_iohook_lseek_t) cnh_lib_get_func_addr("lseek");
|
||||
_cnh_iohook_real_ioctl = (cnh_iohook_ioctl_t) cnh_lib_get_func_addr("ioctl");
|
||||
|
||||
pthread_mutex_init(&_cnh_iohook_lock, NULL);
|
||||
|
||||
atomic_store(&_cnh_iohook_initted, 1);
|
||||
atomic_store(&_cnh_iohook_init_in_progress, 0);
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_iohook_invoke_real(struct cnh_iohook_irp *irp)
|
||||
{
|
||||
cnh_iohook_fn_t handler;
|
||||
cnh_iohook_fn_t handler;
|
||||
|
||||
assert(irp != NULL);
|
||||
assert(irp->op < _countof(_cnh_iohook_real_handlers));
|
||||
assert(irp != NULL);
|
||||
assert(irp->op < _countof(_cnh_iohook_real_handlers));
|
||||
|
||||
handler = _cnh_iohook_real_handlers[irp->op];
|
||||
handler = _cnh_iohook_real_handlers[irp->op];
|
||||
|
||||
assert(handler != NULL);
|
||||
assert(handler != NULL);
|
||||
|
||||
return handler(irp);
|
||||
return handler(irp);
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_iohook_invoke_real_open(struct cnh_iohook_irp *irp)
|
||||
{
|
||||
int fd;
|
||||
int fd;
|
||||
|
||||
assert(irp != NULL);
|
||||
assert(irp != NULL);
|
||||
|
||||
fd = _cnh_iohook_real_open(irp->open_filename, irp->open_flags);
|
||||
fd = _cnh_iohook_real_open(irp->open_filename, irp->open_flags);
|
||||
|
||||
if (fd == INVALID_FILE_DEVICE) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
if (fd == INVALID_FILE_DEVICE) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
|
||||
irp->fd = fd;
|
||||
irp->fd = fd;
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_iohook_invoke_real_fdopen(struct cnh_iohook_irp *irp)
|
||||
static enum cnh_result
|
||||
_cnh_iohook_invoke_real_fdopen(struct cnh_iohook_irp *irp)
|
||||
{
|
||||
FILE* file;
|
||||
FILE *file;
|
||||
|
||||
assert(irp != NULL);
|
||||
assert(irp != NULL);
|
||||
|
||||
file = _cnh_iohook_real_fdopen(irp->fdopen_fd, irp->fdopen_mode);
|
||||
file = _cnh_iohook_real_fdopen(irp->fdopen_fd, irp->fdopen_mode);
|
||||
|
||||
if (file == NULL) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
if (file == NULL) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
|
||||
irp->fdopen_res = file;
|
||||
irp->fdopen_res = file;
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_iohook_invoke_real_close(struct cnh_iohook_irp *irp)
|
||||
{
|
||||
int ok;
|
||||
int ok;
|
||||
|
||||
assert(irp != NULL);
|
||||
assert(irp != NULL);
|
||||
|
||||
ok = _cnh_iohook_real_close(irp->fd);
|
||||
ok = _cnh_iohook_real_close(irp->fd);
|
||||
|
||||
if (ok < 0) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
if (ok < 0) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_iohook_invoke_real_read(struct cnh_iohook_irp *irp)
|
||||
{
|
||||
ssize_t read;
|
||||
ssize_t read;
|
||||
|
||||
assert(irp != NULL);
|
||||
assert(irp != NULL);
|
||||
|
||||
read = _cnh_iohook_real_read(irp->fd, &irp->read.bytes[irp->read.pos], irp->read.nbytes - irp->read.pos);
|
||||
read = _cnh_iohook_real_read(
|
||||
irp->fd,
|
||||
&irp->read.bytes[irp->read.pos],
|
||||
irp->read.nbytes - irp->read.pos);
|
||||
|
||||
if (read < 0) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
if (read < 0) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
|
||||
irp->read.pos += read;
|
||||
irp->read.pos += read;
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_iohook_invoke_real_write(struct cnh_iohook_irp *irp)
|
||||
{
|
||||
ssize_t written;
|
||||
ssize_t written;
|
||||
|
||||
assert(irp != NULL);
|
||||
assert(irp != NULL);
|
||||
|
||||
written = _cnh_iohook_real_write(irp->fd, &irp->write.bytes[irp->write.pos], irp->write.nbytes - irp->write.pos);
|
||||
written = _cnh_iohook_real_write(
|
||||
irp->fd,
|
||||
&irp->write.bytes[irp->write.pos],
|
||||
irp->write.nbytes - irp->write.pos);
|
||||
|
||||
if (written < 0) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
if (written < 0) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
|
||||
irp->write.pos += written;
|
||||
irp->write.pos += written;
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_iohook_invoke_real_seek(struct cnh_iohook_irp *irp)
|
||||
{
|
||||
off_t result;
|
||||
off_t result;
|
||||
|
||||
assert(irp != NULL);
|
||||
assert(irp != NULL);
|
||||
|
||||
result = _cnh_iohook_real_lseek(irp->fd, (off_t) irp->seek_offset, irp->seek_origin);
|
||||
result = _cnh_iohook_real_lseek(
|
||||
irp->fd, (off_t) irp->seek_offset, irp->seek_origin);
|
||||
|
||||
if (result < 0) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
if (result < 0) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
|
||||
irp->seek_pos = result;
|
||||
irp->seek_pos = result;
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_iohook_invoke_real_ioctl(struct cnh_iohook_irp *irp)
|
||||
{
|
||||
int result;
|
||||
int result;
|
||||
|
||||
assert(irp != NULL);
|
||||
assert(irp != NULL);
|
||||
|
||||
result = _cnh_iohook_real_ioctl(irp->fd, irp->ioctl_req, irp->ioctl.bytes);
|
||||
result = _cnh_iohook_real_ioctl(irp->fd, irp->ioctl_req, irp->ioctl.bytes);
|
||||
|
||||
if (result < 0) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
if (result < 0) {
|
||||
return cnh_errno_to_result(errno);
|
||||
}
|
||||
|
||||
irp->ioctl.pos = (size_t) result;
|
||||
irp->ioctl.pos = (size_t) result;
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
@@ -17,34 +17,34 @@
|
||||
* Available operations to hook
|
||||
*/
|
||||
enum cnh_iohook_irp_op {
|
||||
CNH_IOHOOK_IRP_OP_OPEN = 0,
|
||||
CNH_IOHOOK_IRP_OP_FDOPEN = 1,
|
||||
CNH_IOHOOK_IRP_OP_CLOSE = 2,
|
||||
CNH_IOHOOK_IRP_OP_READ = 3,
|
||||
CNH_IOHOOK_IRP_OP_WRITE = 4,
|
||||
CNH_IOHOOK_IRP_OP_SEEK = 5,
|
||||
CNH_IOHOOK_IRP_OP_IOCTL = 6,
|
||||
CNH_IOHOOK_IRP_OP_OPEN = 0,
|
||||
CNH_IOHOOK_IRP_OP_FDOPEN = 1,
|
||||
CNH_IOHOOK_IRP_OP_CLOSE = 2,
|
||||
CNH_IOHOOK_IRP_OP_READ = 3,
|
||||
CNH_IOHOOK_IRP_OP_WRITE = 4,
|
||||
CNH_IOHOOK_IRP_OP_SEEK = 5,
|
||||
CNH_IOHOOK_IRP_OP_IOCTL = 6,
|
||||
};
|
||||
|
||||
/**
|
||||
* I/O request packet
|
||||
*/
|
||||
struct cnh_iohook_irp {
|
||||
enum cnh_iohook_irp_op op;
|
||||
size_t next_handler;
|
||||
int fd;
|
||||
const char *open_filename;
|
||||
int open_flags;
|
||||
int fdopen_fd;
|
||||
const char* fdopen_mode;
|
||||
FILE* fdopen_res;
|
||||
struct cnh_iobuf read;
|
||||
struct cnh_const_iobuf write;
|
||||
int seek_origin;
|
||||
int64_t seek_offset;
|
||||
uint64_t seek_pos;
|
||||
int ioctl_req;
|
||||
struct cnh_iobuf ioctl;
|
||||
enum cnh_iohook_irp_op op;
|
||||
size_t next_handler;
|
||||
int fd;
|
||||
const char *open_filename;
|
||||
int open_flags;
|
||||
int fdopen_fd;
|
||||
const char *fdopen_mode;
|
||||
FILE *fdopen_res;
|
||||
struct cnh_iobuf read;
|
||||
struct cnh_const_iobuf write;
|
||||
int seek_origin;
|
||||
int64_t seek_offset;
|
||||
uint64_t seek_pos;
|
||||
int ioctl_req;
|
||||
struct cnh_iobuf ioctl;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -80,8 +80,9 @@ enum cnh_result cnh_iohook_invoke_next(struct cnh_iohook_irp *irp);
|
||||
int cnh_iohook_open_dummy_fd();
|
||||
|
||||
/**
|
||||
* Close a dummy file handle. Make sure to free your previously allocated handles
|
||||
* to avoid resource leaks. Do not free them using the real close function.
|
||||
* Close a dummy file handle. Make sure to free your previously allocated
|
||||
* handles to avoid resource leaks. Do not free them using the real close
|
||||
* function.
|
||||
*
|
||||
* @param file Dummy file handle to free
|
||||
*/
|
||||
|
||||
@@ -6,52 +6,77 @@
|
||||
#define CNH_LIB_MAIN_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
#define LIB_MAIN_CONSTRUCTOR(func) __attribute__((constructor)) void lib_constructor() { func(); }
|
||||
#define LIB_MAIN_CONSTRUCTOR(func) \
|
||||
__attribute__((constructor)) void lib_constructor() \
|
||||
{ \
|
||||
func(); \
|
||||
}
|
||||
|
||||
#define LIB_MAIN_DESTRUCTOR(func) __attribute__((destructor)) void lib_destructor() { func(); }
|
||||
#define LIB_MAIN_DESTRUCTOR(func) \
|
||||
__attribute__((destructor)) void lib_destructor() \
|
||||
{ \
|
||||
func(); \
|
||||
}
|
||||
|
||||
#define LIB_MAIN_TRAP_MAIN(func_before_main, func_after_main) \
|
||||
typedef int (*func_libc_start_main_t)(int *(main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end)); \
|
||||
typedef int* (*func_main_t)(int, char**, char**); \
|
||||
typedef void (*func_init_t)(void); \
|
||||
static func_main_t orig_main; \
|
||||
static func_init_t orig_init; \
|
||||
static bool trapped; \
|
||||
\
|
||||
int* trap_main(int argc, char** argv, char** envp) \
|
||||
{ \
|
||||
log_debug("Trap before main (%s): argc %d", argv[0], argc); \
|
||||
func_before_main(argc, argv); \
|
||||
log_debug("Calling orig_init"); \
|
||||
orig_init(); \
|
||||
log_debug("Calling real main (%s): argc %d", argv[0], argc); \
|
||||
int* ret = orig_main(argc, argv, envp); \
|
||||
log_debug("Calling cleanup after main (%s): ret %d", argv[0], ret); \
|
||||
func_after_main(); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
void dummy_init(void) {} \
|
||||
\
|
||||
int __libc_start_main(int *(main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end)) \
|
||||
{ \
|
||||
func_libc_start_main_t start = (func_libc_start_main_t) dlsym(RTLD_NEXT, "__libc_start_main"); \
|
||||
if (start == NULL) { \
|
||||
printf("ERROR finding orig func __libc_start_main\n"); \
|
||||
} \
|
||||
orig_main = main; \
|
||||
main = trap_main; \
|
||||
orig_init = init; \
|
||||
init = dummy_init; \
|
||||
trapped = true; \
|
||||
return (*start)(main, argc, ubp_av, init, fini, rtld_fini, stack_end); \
|
||||
}
|
||||
#define LIB_MAIN_TRAP_MAIN(func_before_main, func_after_main) \
|
||||
typedef int (*func_libc_start_main_t)( \
|
||||
int *(main)(int, char **, char **), \
|
||||
int argc, \
|
||||
char **ubp_av, \
|
||||
void (*init)(void), \
|
||||
void (*fini)(void), \
|
||||
void (*rtld_fini)(void), \
|
||||
void(*stack_end)); \
|
||||
typedef int *(*func_main_t)(int, char **, char **); \
|
||||
typedef void (*func_init_t)(void); \
|
||||
static func_main_t orig_main; \
|
||||
static func_init_t orig_init; \
|
||||
static bool trapped; \
|
||||
\
|
||||
int *trap_main(int argc, char **argv, char **envp) \
|
||||
{ \
|
||||
log_debug("Trap before main (%s): argc %d", argv[0], argc); \
|
||||
func_before_main(argc, argv); \
|
||||
log_debug("Calling orig_init"); \
|
||||
orig_init(); \
|
||||
log_debug("Calling real main (%s): argc %d", argv[0], argc); \
|
||||
int *ret = orig_main(argc, argv, envp); \
|
||||
log_debug("Calling cleanup after main (%s): ret %d", argv[0], ret); \
|
||||
func_after_main(); \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
void dummy_init(void) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
int __libc_start_main( \
|
||||
int *(main)(int, char **, char **), \
|
||||
int argc, \
|
||||
char **ubp_av, \
|
||||
void (*init)(void), \
|
||||
void (*fini)(void), \
|
||||
void (*rtld_fini)(void), \
|
||||
void(*stack_end)) \
|
||||
{ \
|
||||
func_libc_start_main_t start = \
|
||||
(func_libc_start_main_t) dlsym(RTLD_NEXT, "__libc_start_main"); \
|
||||
if (start == NULL) { \
|
||||
printf("ERROR finding orig func __libc_start_main\n"); \
|
||||
} \
|
||||
orig_main = main; \
|
||||
main = trap_main; \
|
||||
orig_init = init; \
|
||||
init = dummy_init; \
|
||||
trapped = true; \
|
||||
return (*start)(main, argc, ubp_av, init, fini, rtld_fini, stack_end); \
|
||||
}
|
||||
|
||||
#endif
|
||||
+125
-118
@@ -8,172 +8,179 @@
|
||||
#include "util/mem.h"
|
||||
#include "util/rand.h"
|
||||
|
||||
typedef void* (*cnh_lib_load_t)(const char* lib);
|
||||
typedef void* (*cnh_lib_get_func_addr_handle_t)(void* lib_handle, const char* func_name);
|
||||
typedef void (*cnh_lib_unload_t)(void* handle);
|
||||
typedef void* (*cnh_lib_get_func_addr_t)(const char* func_name);
|
||||
typedef void *(*cnh_lib_load_t)(const char *lib);
|
||||
typedef void *(*cnh_lib_get_func_addr_handle_t)(
|
||||
void *lib_handle, const char *func_name);
|
||||
typedef void (*cnh_lib_unload_t)(void *handle);
|
||||
typedef void *(*cnh_lib_get_func_addr_t)(const char *func_name);
|
||||
|
||||
static void* _cnh_lib_load(const char* lib);
|
||||
static void* _cnh_lib_get_func_addr_handle(void* lib_handle, const char* func_name);
|
||||
static void _cnh_lib_unload(void* handle);
|
||||
static void* _cnh_lib_get_func_addr(const char* func_name);
|
||||
static void *_cnh_lib_load(const char *lib);
|
||||
static void *
|
||||
_cnh_lib_get_func_addr_handle(void *lib_handle, const char *func_name);
|
||||
static void _cnh_lib_unload(void *handle);
|
||||
static void *_cnh_lib_get_func_addr(const char *func_name);
|
||||
|
||||
static void* _cnh_lib_load_test(const char* lib);
|
||||
static void* _cnh_lib_get_func_addr_handle_test(void* lib_handle, const char* func_name);
|
||||
static void _cnh_lib_unload_test(void* handle);
|
||||
static void* _cnh_lib_get_func_addr_test(const char* func_name);
|
||||
static void *_cnh_lib_load_test(const char *lib);
|
||||
static void *
|
||||
_cnh_lib_get_func_addr_handle_test(void *lib_handle, const char *func_name);
|
||||
static void _cnh_lib_unload_test(void *handle);
|
||||
static void *_cnh_lib_get_func_addr_test(const char *func_name);
|
||||
|
||||
struct cnh_lib_interface {
|
||||
cnh_lib_load_t load;
|
||||
cnh_lib_get_func_addr_handle_t get_func_addr_handle;
|
||||
cnh_lib_unload_t unload;
|
||||
cnh_lib_get_func_addr_t get_func_addr;
|
||||
cnh_lib_load_t load;
|
||||
cnh_lib_get_func_addr_handle_t get_func_addr_handle;
|
||||
cnh_lib_unload_t unload;
|
||||
cnh_lib_get_func_addr_t get_func_addr;
|
||||
};
|
||||
|
||||
static struct cnh_lib_interface _cnh_lib_interface = {
|
||||
.load = _cnh_lib_load,
|
||||
.get_func_addr_handle = _cnh_lib_get_func_addr_handle,
|
||||
.unload = _cnh_lib_unload,
|
||||
.get_func_addr = _cnh_lib_get_func_addr,
|
||||
.load = _cnh_lib_load,
|
||||
.get_func_addr_handle = _cnh_lib_get_func_addr_handle,
|
||||
.unload = _cnh_lib_unload,
|
||||
.get_func_addr = _cnh_lib_get_func_addr,
|
||||
};
|
||||
|
||||
static struct cnh_lib_unit_test_func_mocks* _cnh_lib_func_mocks;
|
||||
static struct cnh_lib_unit_test_func_mocks *_cnh_lib_func_mocks;
|
||||
size_t _cnh_lib_func_mocks_cnt;
|
||||
|
||||
static void* _cnh_lib_load(const char* lib)
|
||||
static void *_cnh_lib_load(const char *lib)
|
||||
{
|
||||
void* so = dlopen(lib, RTLD_NOW);
|
||||
void *so = dlopen(lib, RTLD_NOW);
|
||||
|
||||
if (so == NULL) {
|
||||
log_warn("Failed to open library %s: %s", lib, dlerror());
|
||||
} else {
|
||||
log_debug("Opened lib %s, handle %p", lib, so);
|
||||
}
|
||||
if (so == NULL) {
|
||||
log_warn("Failed to open library %s: %s", lib, dlerror());
|
||||
} else {
|
||||
log_debug("Opened lib %s, handle %p", lib, so);
|
||||
}
|
||||
|
||||
return so;
|
||||
return so;
|
||||
}
|
||||
|
||||
static void* _cnh_lib_get_func_addr_handle(void* lib_handle, const char* func_name)
|
||||
static void *
|
||||
_cnh_lib_get_func_addr_handle(void *lib_handle, const char *func_name)
|
||||
{
|
||||
void* ret = dlsym(lib_handle, func_name);
|
||||
void *ret = dlsym(lib_handle, func_name);
|
||||
|
||||
if (ret == NULL) {
|
||||
log_warn("Could not find func %s in library %p", func_name, lib_handle);
|
||||
if (ret == NULL) {
|
||||
log_warn("Could not find func %s in library %p", func_name, lib_handle);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void _cnh_lib_unload(void *handle)
|
||||
{
|
||||
dlclose(handle);
|
||||
log_debug("Closed lib handle %p", handle);
|
||||
}
|
||||
|
||||
static void *_cnh_lib_get_func_addr(const char *func_name)
|
||||
{
|
||||
void *ret = dlsym(RTLD_NEXT, func_name);
|
||||
|
||||
if (ret == NULL) {
|
||||
log_warn("Could not find func %s", func_name);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *_cnh_lib_load_test(const char *lib)
|
||||
{
|
||||
log_warn("Loading lib %s not supported in test", lib);
|
||||
|
||||
if (sizeof(void *) == 4) {
|
||||
return (void *) util_rand_gen_32();
|
||||
} else {
|
||||
log_die_illegal_state();
|
||||
}
|
||||
}
|
||||
|
||||
static void *
|
||||
_cnh_lib_get_func_addr_handle_test(void *lib_handle, const char *func_name)
|
||||
{
|
||||
return _cnh_lib_get_func_addr_test(func_name);
|
||||
}
|
||||
|
||||
static void _cnh_lib_unload_test(void *handle)
|
||||
{
|
||||
log_warn("Unloading lib %p not supported in test", handle);
|
||||
}
|
||||
|
||||
static void *_cnh_lib_get_func_addr_test(const char *func_name)
|
||||
{
|
||||
for (size_t i = 0; i < _cnh_lib_func_mocks_cnt; i++) {
|
||||
if (!strcmp(_cnh_lib_func_mocks[i].name, func_name)) {
|
||||
return _cnh_lib_func_mocks->func;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
log_warn("Could not find func %s", func_name);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void _cnh_lib_unload(void* handle)
|
||||
struct cnh_lib_unit_test_func_mocks *cnh_lib_allocate_func_mocks(size_t count)
|
||||
{
|
||||
dlclose(handle);
|
||||
log_debug("Closed lib handle %p", handle);
|
||||
log_assert(count >= 0);
|
||||
|
||||
struct cnh_lib_unit_test_func_mocks *func_mocks;
|
||||
|
||||
func_mocks =
|
||||
util_xmalloc(sizeof(struct cnh_lib_unit_test_func_mocks) * count);
|
||||
|
||||
memset(func_mocks, 0, sizeof(struct cnh_lib_unit_test_func_mocks) * count);
|
||||
|
||||
return func_mocks;
|
||||
}
|
||||
|
||||
static void* _cnh_lib_get_func_addr(const char* func_name)
|
||||
void cnh_lib_init_unit_test(
|
||||
struct cnh_lib_unit_test_func_mocks *func_mocks, size_t func_mocks_cnt)
|
||||
{
|
||||
void* ret = dlsym(RTLD_NEXT, func_name);
|
||||
log_warn("Setting up %d unit test func mocks", func_mocks_cnt);
|
||||
|
||||
if (ret == NULL) {
|
||||
log_warn("Could not find func %s", func_name);
|
||||
}
|
||||
_cnh_lib_func_mocks = func_mocks;
|
||||
_cnh_lib_func_mocks_cnt = func_mocks_cnt;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void* _cnh_lib_load_test(const char* lib)
|
||||
{
|
||||
log_warn("Loading lib %s not supported in test", lib);
|
||||
|
||||
if (sizeof(void*) == 4) {
|
||||
return (void*) util_rand_gen_32();
|
||||
} else {
|
||||
log_die_illegal_state();
|
||||
}
|
||||
}
|
||||
|
||||
static void* _cnh_lib_get_func_addr_handle_test(void* lib_handle, const char* func_name)
|
||||
{
|
||||
return _cnh_lib_get_func_addr_test(func_name);
|
||||
}
|
||||
|
||||
static void _cnh_lib_unload_test(void* handle)
|
||||
{
|
||||
log_warn("Unloading lib %p not supported in test", handle);
|
||||
}
|
||||
|
||||
static void* _cnh_lib_get_func_addr_test(const char* func_name)
|
||||
{
|
||||
for (size_t i = 0; i < _cnh_lib_func_mocks_cnt; i++) {
|
||||
if (!strcmp(_cnh_lib_func_mocks[i].name, func_name)) {
|
||||
return _cnh_lib_func_mocks->func;
|
||||
}
|
||||
}
|
||||
|
||||
log_warn("Could not find func %s", func_name);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct cnh_lib_unit_test_func_mocks* cnh_lib_allocate_func_mocks(size_t count)
|
||||
{
|
||||
log_assert(count >= 0);
|
||||
|
||||
struct cnh_lib_unit_test_func_mocks* func_mocks;
|
||||
|
||||
func_mocks = util_xmalloc(sizeof(struct cnh_lib_unit_test_func_mocks) * count);
|
||||
|
||||
memset(func_mocks, 0, sizeof(struct cnh_lib_unit_test_func_mocks) * count);
|
||||
|
||||
return func_mocks;
|
||||
}
|
||||
|
||||
void cnh_lib_init_unit_test(struct cnh_lib_unit_test_func_mocks* func_mocks, size_t func_mocks_cnt)
|
||||
{
|
||||
log_warn("Setting up %d unit test func mocks", func_mocks_cnt);
|
||||
|
||||
_cnh_lib_func_mocks = func_mocks;
|
||||
_cnh_lib_func_mocks_cnt = func_mocks_cnt;
|
||||
|
||||
_cnh_lib_interface.load = _cnh_lib_load_test;
|
||||
_cnh_lib_interface.get_func_addr_handle = _cnh_lib_get_func_addr_handle_test;
|
||||
_cnh_lib_interface.unload = _cnh_lib_unload_test;
|
||||
_cnh_lib_interface.get_func_addr = _cnh_lib_get_func_addr_test;
|
||||
_cnh_lib_interface.load = _cnh_lib_load_test;
|
||||
_cnh_lib_interface.get_func_addr_handle = _cnh_lib_get_func_addr_handle_test;
|
||||
_cnh_lib_interface.unload = _cnh_lib_unload_test;
|
||||
_cnh_lib_interface.get_func_addr = _cnh_lib_get_func_addr_test;
|
||||
}
|
||||
|
||||
void cnh_lib_init()
|
||||
{
|
||||
log_warn("Setting up real interface");
|
||||
log_warn("Setting up real interface");
|
||||
|
||||
_cnh_lib_interface.load = _cnh_lib_load;
|
||||
_cnh_lib_interface.get_func_addr_handle = _cnh_lib_get_func_addr_handle;
|
||||
_cnh_lib_interface.unload = _cnh_lib_unload;
|
||||
_cnh_lib_interface.get_func_addr = _cnh_lib_get_func_addr;
|
||||
_cnh_lib_interface.load = _cnh_lib_load;
|
||||
_cnh_lib_interface.get_func_addr_handle = _cnh_lib_get_func_addr_handle;
|
||||
_cnh_lib_interface.unload = _cnh_lib_unload;
|
||||
_cnh_lib_interface.get_func_addr = _cnh_lib_get_func_addr;
|
||||
}
|
||||
|
||||
void cnh_lib_shutdown_unit_test()
|
||||
{
|
||||
log_assert(_cnh_lib_func_mocks);
|
||||
log_assert(_cnh_lib_func_mocks);
|
||||
|
||||
util_xfree((void**) &_cnh_lib_func_mocks);
|
||||
util_xfree((void **) &_cnh_lib_func_mocks);
|
||||
}
|
||||
|
||||
void* cnh_lib_load(const char* lib)
|
||||
void *cnh_lib_load(const char *lib)
|
||||
{
|
||||
return _cnh_lib_interface.load(lib);
|
||||
return _cnh_lib_interface.load(lib);
|
||||
}
|
||||
|
||||
void* cnh_lib_get_func_addr_handle(void* lib_handle, const char* func_name)
|
||||
void *cnh_lib_get_func_addr_handle(void *lib_handle, const char *func_name)
|
||||
{
|
||||
return _cnh_lib_interface.get_func_addr_handle(lib_handle, func_name);
|
||||
return _cnh_lib_interface.get_func_addr_handle(lib_handle, func_name);
|
||||
}
|
||||
|
||||
void cnh_lib_unload(void* handle)
|
||||
void cnh_lib_unload(void *handle)
|
||||
{
|
||||
_cnh_lib_interface.unload(handle);
|
||||
_cnh_lib_interface.unload(handle);
|
||||
}
|
||||
|
||||
void* cnh_lib_get_func_addr(const char* func_name)
|
||||
void *cnh_lib_get_func_addr(const char *func_name)
|
||||
{
|
||||
return _cnh_lib_interface.get_func_addr(func_name);
|
||||
return _cnh_lib_interface.get_func_addr(func_name);
|
||||
}
|
||||
@@ -7,38 +7,45 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* Provide a mock function key'd by it's name and pointing to your actual mock implementation.
|
||||
* Provide a mock function key'd by it's name and pointing to your actual mock
|
||||
* implementation.
|
||||
*/
|
||||
struct cnh_lib_unit_test_func_mocks {
|
||||
const char* name;
|
||||
void* func;
|
||||
const char *name;
|
||||
void *func;
|
||||
};
|
||||
|
||||
/**
|
||||
* Allocate memory for a list of mock functions to pass to cnh_lib_init_unit_test.
|
||||
* Allocate memory for a list of mock functions to pass to
|
||||
* cnh_lib_init_unit_test.
|
||||
*
|
||||
* @param count The size of the list.
|
||||
* @return Allocated memory with the specified number of entries.
|
||||
*/
|
||||
struct cnh_lib_unit_test_func_mocks* cnh_lib_allocate_func_mocks(size_t count);
|
||||
struct cnh_lib_unit_test_func_mocks *cnh_lib_allocate_func_mocks(size_t count);
|
||||
|
||||
/**
|
||||
* Initialize this module when using it in a unit-test. This allows you to add function mocks that are returned on the
|
||||
* various calls to get function pointers from real library functions. Use this to mock them to test various patching
|
||||
* modules.
|
||||
* Initialize this module when using it in a unit-test. This allows you to add
|
||||
* function mocks that are returned on the various calls to get function
|
||||
* pointers from real library functions. Use this to mock them to test various
|
||||
* patching modules.
|
||||
*
|
||||
* Use the cnh_lib_allocate_func_mocks function to allocate a list that you can fill in.
|
||||
* Use the cnh_lib_allocate_func_mocks function to allocate a list that you can
|
||||
* fill in.
|
||||
*
|
||||
* @param func_mocks A list of functions mocks with function names and pointers to the test mocks you set up. Ensure
|
||||
* that the function signatures match, otherwise things might crash when getting called. The module
|
||||
* will cleanup the memory allocated of this for you.
|
||||
* @param func_mocks A list of functions mocks with function names and pointers
|
||||
* to the test mocks you set up. Ensure that the function signatures match,
|
||||
* otherwise things might crash when getting called. The module will cleanup the
|
||||
* memory allocated of this for you.
|
||||
* @param func_mocks_cnt The length of the list of func_mocks.
|
||||
*/
|
||||
void cnh_lib_init_unit_test(struct cnh_lib_unit_test_func_mocks* func_mocks, size_t func_mocks_cnt);
|
||||
void cnh_lib_init_unit_test(
|
||||
struct cnh_lib_unit_test_func_mocks *func_mocks, size_t func_mocks_cnt);
|
||||
|
||||
/**
|
||||
* Optional, used for unit testing. Switch to the default backend that utilizes loading real libraries and getting real
|
||||
* function pointers from them. This is enabled by default.
|
||||
* Optional, used for unit testing. Switch to the default backend that utilizes
|
||||
* loading real libraries and getting real function pointers from them. This is
|
||||
* enabled by default.
|
||||
*/
|
||||
void cnh_lib_init();
|
||||
|
||||
@@ -53,7 +60,7 @@ void cnh_lib_shutdown_unit_test();
|
||||
* @param lib Path to library file to load
|
||||
* @return Pointer to a handle on success, NULL on failure
|
||||
*/
|
||||
void* cnh_lib_load(const char* lib);
|
||||
void *cnh_lib_load(const char *lib);
|
||||
|
||||
/**
|
||||
* Get the address of a function from a library
|
||||
@@ -62,14 +69,14 @@ void* cnh_lib_load(const char* lib);
|
||||
* @param func_name Name of the function to get
|
||||
* @return Function ptr on success, false on error (function not found)
|
||||
*/
|
||||
void*cnh_lib_get_func_addr_handle(void* lib_handle, const char* func_name);
|
||||
void *cnh_lib_get_func_addr_handle(void *lib_handle, const char *func_name);
|
||||
|
||||
/**
|
||||
* Unload a loaded dynamic library
|
||||
*
|
||||
* @param handle Handle of the loaded lib to unload
|
||||
*/
|
||||
void cnh_lib_unload(void* handle);
|
||||
void cnh_lib_unload(void *handle);
|
||||
|
||||
/**
|
||||
* Get the adress of a function (from a dynamic library)
|
||||
@@ -79,6 +86,6 @@ void cnh_lib_unload(void* handle);
|
||||
* @param func_name Name of the function
|
||||
* @return Valid ptr to function on success, false on error (not found)
|
||||
*/
|
||||
void* cnh_lib_get_func_addr(const char* func_name);
|
||||
void *cnh_lib_get_func_addr(const char *func_name);
|
||||
|
||||
#endif
|
||||
@@ -8,96 +8,100 @@
|
||||
|
||||
int cnh_result_to_errno(enum cnh_result result)
|
||||
{
|
||||
switch (result) {
|
||||
case CNH_RESULT_SUCCESS:
|
||||
return 0;
|
||||
case CNH_RESULT_ERROR_INSUFFICIENT_BUFFER:
|
||||
return EIO;
|
||||
case CNH_RESULT_INVALID_PARAMETER:
|
||||
return EINVAL;
|
||||
case CNH_RESULT_OUT_OF_MEMORY:
|
||||
return ENOMEM;
|
||||
case CNH_RESULT_REPEAT_OPERATION:
|
||||
return EAGAIN;
|
||||
case CNH_RESULT_NO_SUCH_FILE_OR_DIR:
|
||||
return ENOENT;
|
||||
case CNH_RESULT_NOT_TTY:
|
||||
return ENOTTY;
|
||||
case CNH_RESULT_BUSY:
|
||||
return EBUSY;
|
||||
case CNH_RESULT_IS_A_DIRECTORY:
|
||||
return EISDIR;
|
||||
case CNH_RESULT_PERMISSION_DENIED:
|
||||
return EACCES;
|
||||
case CNH_RESULT_DIRECTORY_NOT_EMPTY:
|
||||
return ENOTEMPTY;
|
||||
case CNH_RESULT_OPERATION_NOT_PERMITTED:
|
||||
return EPERM;
|
||||
case CNH_RESULT_NO_SUCH_DEVICE:
|
||||
return ENODEV;
|
||||
case CNH_RESULT_BAD_FILE_NUMBER:
|
||||
return EBADF;
|
||||
case CNH_RESULT_FILE_DESCRIPTOR_IN_BAD_STATE:
|
||||
return EBADFD;
|
||||
case CNH_RESULT_VALUE_TOO_LARGE_FOR_DEFINED_DATATYPE:
|
||||
return EOVERFLOW;
|
||||
case CNH_RESULT_NO_SUCH_DEVICE_OR_ADDRESS:
|
||||
return ENXIO;
|
||||
case CNH_RESULT_BROKEN_PIPE:
|
||||
return EPIPE;
|
||||
case CNH_RESULT_TIMER_EXPIRED:
|
||||
return ETIME;
|
||||
case CNH_RESULT_NO_DATA_AVAILABLE:
|
||||
return ENODATA;
|
||||
default:
|
||||
log_warn("Unhandled other error %d to errno convert might cause bugs", result);
|
||||
return EIO;
|
||||
}
|
||||
switch (result) {
|
||||
case CNH_RESULT_SUCCESS:
|
||||
return 0;
|
||||
case CNH_RESULT_ERROR_INSUFFICIENT_BUFFER:
|
||||
return EIO;
|
||||
case CNH_RESULT_INVALID_PARAMETER:
|
||||
return EINVAL;
|
||||
case CNH_RESULT_OUT_OF_MEMORY:
|
||||
return ENOMEM;
|
||||
case CNH_RESULT_REPEAT_OPERATION:
|
||||
return EAGAIN;
|
||||
case CNH_RESULT_NO_SUCH_FILE_OR_DIR:
|
||||
return ENOENT;
|
||||
case CNH_RESULT_NOT_TTY:
|
||||
return ENOTTY;
|
||||
case CNH_RESULT_BUSY:
|
||||
return EBUSY;
|
||||
case CNH_RESULT_IS_A_DIRECTORY:
|
||||
return EISDIR;
|
||||
case CNH_RESULT_PERMISSION_DENIED:
|
||||
return EACCES;
|
||||
case CNH_RESULT_DIRECTORY_NOT_EMPTY:
|
||||
return ENOTEMPTY;
|
||||
case CNH_RESULT_OPERATION_NOT_PERMITTED:
|
||||
return EPERM;
|
||||
case CNH_RESULT_NO_SUCH_DEVICE:
|
||||
return ENODEV;
|
||||
case CNH_RESULT_BAD_FILE_NUMBER:
|
||||
return EBADF;
|
||||
case CNH_RESULT_FILE_DESCRIPTOR_IN_BAD_STATE:
|
||||
return EBADFD;
|
||||
case CNH_RESULT_VALUE_TOO_LARGE_FOR_DEFINED_DATATYPE:
|
||||
return EOVERFLOW;
|
||||
case CNH_RESULT_NO_SUCH_DEVICE_OR_ADDRESS:
|
||||
return ENXIO;
|
||||
case CNH_RESULT_BROKEN_PIPE:
|
||||
return EPIPE;
|
||||
case CNH_RESULT_TIMER_EXPIRED:
|
||||
return ETIME;
|
||||
case CNH_RESULT_NO_DATA_AVAILABLE:
|
||||
return ENODATA;
|
||||
default:
|
||||
log_warn(
|
||||
"Unhandled other error %d to errno convert might cause bugs", result);
|
||||
return EIO;
|
||||
}
|
||||
}
|
||||
|
||||
enum cnh_result cnh_errno_to_result(int errn)
|
||||
{
|
||||
switch (errn) {
|
||||
case 0:
|
||||
return CNH_RESULT_SUCCESS;
|
||||
case EINVAL:
|
||||
return CNH_RESULT_INVALID_PARAMETER;
|
||||
case ENOMEM:
|
||||
return CNH_RESULT_OUT_OF_MEMORY;
|
||||
case EAGAIN:
|
||||
return CNH_RESULT_REPEAT_OPERATION;
|
||||
case ENOENT:
|
||||
return CNH_RESULT_NO_SUCH_FILE_OR_DIR;
|
||||
case ENOTTY:
|
||||
return CNH_RESULT_NOT_TTY;
|
||||
case EBUSY:
|
||||
return CNH_RESULT_BUSY;
|
||||
case EISDIR:
|
||||
return CNH_RESULT_IS_A_DIRECTORY;
|
||||
case EACCES:
|
||||
return CNH_RESULT_PERMISSION_DENIED;
|
||||
case ENOTEMPTY:
|
||||
return CNH_RESULT_DIRECTORY_NOT_EMPTY;
|
||||
case EPERM:
|
||||
return CNH_RESULT_OPERATION_NOT_PERMITTED;
|
||||
case ENODEV:
|
||||
return CNH_RESULT_NO_SUCH_DEVICE;
|
||||
case EBADF:
|
||||
return CNH_RESULT_BAD_FILE_NUMBER;
|
||||
case EBADFD:
|
||||
return CNH_RESULT_FILE_DESCRIPTOR_IN_BAD_STATE;
|
||||
case EOVERFLOW:
|
||||
return CNH_RESULT_VALUE_TOO_LARGE_FOR_DEFINED_DATATYPE;
|
||||
case ENXIO:
|
||||
return CNH_RESULT_NO_SUCH_DEVICE_OR_ADDRESS;
|
||||
case EPIPE:
|
||||
return CNH_RESULT_BROKEN_PIPE;
|
||||
case ETIME:
|
||||
return CNH_RESULT_TIMER_EXPIRED;
|
||||
case ENODATA:
|
||||
return CNH_RESULT_NO_DATA_AVAILABLE;
|
||||
default:
|
||||
log_warn("Unhandled errno to general error convert might cause bugs, errno: %d", errn);
|
||||
return CNH_RESULT_OTHER_ERROR;
|
||||
}
|
||||
switch (errn) {
|
||||
case 0:
|
||||
return CNH_RESULT_SUCCESS;
|
||||
case EINVAL:
|
||||
return CNH_RESULT_INVALID_PARAMETER;
|
||||
case ENOMEM:
|
||||
return CNH_RESULT_OUT_OF_MEMORY;
|
||||
case EAGAIN:
|
||||
return CNH_RESULT_REPEAT_OPERATION;
|
||||
case ENOENT:
|
||||
return CNH_RESULT_NO_SUCH_FILE_OR_DIR;
|
||||
case ENOTTY:
|
||||
return CNH_RESULT_NOT_TTY;
|
||||
case EBUSY:
|
||||
return CNH_RESULT_BUSY;
|
||||
case EISDIR:
|
||||
return CNH_RESULT_IS_A_DIRECTORY;
|
||||
case EACCES:
|
||||
return CNH_RESULT_PERMISSION_DENIED;
|
||||
case ENOTEMPTY:
|
||||
return CNH_RESULT_DIRECTORY_NOT_EMPTY;
|
||||
case EPERM:
|
||||
return CNH_RESULT_OPERATION_NOT_PERMITTED;
|
||||
case ENODEV:
|
||||
return CNH_RESULT_NO_SUCH_DEVICE;
|
||||
case EBADF:
|
||||
return CNH_RESULT_BAD_FILE_NUMBER;
|
||||
case EBADFD:
|
||||
return CNH_RESULT_FILE_DESCRIPTOR_IN_BAD_STATE;
|
||||
case EOVERFLOW:
|
||||
return CNH_RESULT_VALUE_TOO_LARGE_FOR_DEFINED_DATATYPE;
|
||||
case ENXIO:
|
||||
return CNH_RESULT_NO_SUCH_DEVICE_OR_ADDRESS;
|
||||
case EPIPE:
|
||||
return CNH_RESULT_BROKEN_PIPE;
|
||||
case ETIME:
|
||||
return CNH_RESULT_TIMER_EXPIRED;
|
||||
case ENODATA:
|
||||
return CNH_RESULT_NO_DATA_AVAILABLE;
|
||||
default:
|
||||
log_warn(
|
||||
"Unhandled errno to general error convert might cause bugs, errno: "
|
||||
"%d",
|
||||
errn);
|
||||
return CNH_RESULT_OTHER_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
/**
|
||||
* Results for returning errors on hook modules, converting them to errno and vice versa
|
||||
* Results for returning errors on hook modules, converting them to errno and
|
||||
* vice versa
|
||||
*
|
||||
* Based on original capnhook code for windows by decafcode:
|
||||
* https://github.com/decafcode/capnhook
|
||||
@@ -11,27 +12,27 @@
|
||||
* Result values for hook functions
|
||||
*/
|
||||
enum cnh_result {
|
||||
CNH_RESULT_SUCCESS = 0,
|
||||
CNH_RESULT_ERROR_INSUFFICIENT_BUFFER = 1,
|
||||
CNH_RESULT_INVALID_PARAMETER = 2,
|
||||
CNH_RESULT_OUT_OF_MEMORY = 3,
|
||||
CNH_RESULT_REPEAT_OPERATION = 4,
|
||||
CNH_RESULT_NO_SUCH_FILE_OR_DIR = 5,
|
||||
CNH_RESULT_OTHER_ERROR = 6,
|
||||
CNH_RESULT_NOT_TTY = 7,
|
||||
CNH_RESULT_BUSY = 8,
|
||||
CNH_RESULT_IS_A_DIRECTORY = 9,
|
||||
CNH_RESULT_PERMISSION_DENIED = 10,
|
||||
CNH_RESULT_DIRECTORY_NOT_EMPTY = 11,
|
||||
CNH_RESULT_OPERATION_NOT_PERMITTED = 12,
|
||||
CNH_RESULT_NO_SUCH_DEVICE = 13,
|
||||
CNH_RESULT_BAD_FILE_NUMBER = 14,
|
||||
CNH_RESULT_FILE_DESCRIPTOR_IN_BAD_STATE = 15,
|
||||
CNH_RESULT_VALUE_TOO_LARGE_FOR_DEFINED_DATATYPE = 16,
|
||||
CNH_RESULT_NO_SUCH_DEVICE_OR_ADDRESS = 17,
|
||||
CNH_RESULT_BROKEN_PIPE = 18,
|
||||
CNH_RESULT_TIMER_EXPIRED = 19,
|
||||
CNH_RESULT_NO_DATA_AVAILABLE = 20,
|
||||
CNH_RESULT_SUCCESS = 0,
|
||||
CNH_RESULT_ERROR_INSUFFICIENT_BUFFER = 1,
|
||||
CNH_RESULT_INVALID_PARAMETER = 2,
|
||||
CNH_RESULT_OUT_OF_MEMORY = 3,
|
||||
CNH_RESULT_REPEAT_OPERATION = 4,
|
||||
CNH_RESULT_NO_SUCH_FILE_OR_DIR = 5,
|
||||
CNH_RESULT_OTHER_ERROR = 6,
|
||||
CNH_RESULT_NOT_TTY = 7,
|
||||
CNH_RESULT_BUSY = 8,
|
||||
CNH_RESULT_IS_A_DIRECTORY = 9,
|
||||
CNH_RESULT_PERMISSION_DENIED = 10,
|
||||
CNH_RESULT_DIRECTORY_NOT_EMPTY = 11,
|
||||
CNH_RESULT_OPERATION_NOT_PERMITTED = 12,
|
||||
CNH_RESULT_NO_SUCH_DEVICE = 13,
|
||||
CNH_RESULT_BAD_FILE_NUMBER = 14,
|
||||
CNH_RESULT_FILE_DESCRIPTOR_IN_BAD_STATE = 15,
|
||||
CNH_RESULT_VALUE_TOO_LARGE_FOR_DEFINED_DATATYPE = 16,
|
||||
CNH_RESULT_NO_SUCH_DEVICE_OR_ADDRESS = 17,
|
||||
CNH_RESULT_BROKEN_PIPE = 18,
|
||||
CNH_RESULT_TIMER_EXPIRED = 19,
|
||||
CNH_RESULT_NO_DATA_AVAILABLE = 20,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#define LOG_MODULE "cnh-sig"
|
||||
|
||||
#include "capnhook/hook/lib.h"
|
||||
#include "capnhook/hook/sig.h"
|
||||
#include "capnhook/hook/lib.h"
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
typedef int (*cnh_sig_handler_sigaction_t) (int sig, const struct sigaction* act, struct sigaction* oact);
|
||||
typedef int (*cnh_sig_handler_sigaction_t)(
|
||||
int sig, const struct sigaction *act, struct sigaction *oact);
|
||||
|
||||
static void _cnh_signal_handler(int sig);
|
||||
|
||||
@@ -16,43 +17,48 @@ static __sighandler_t _cnh_signal_orig_handlers[32];
|
||||
|
||||
void cnh_sig_install(int sig, cnh_sig_handler_t handler)
|
||||
{
|
||||
if (sig < 0 || sig >= 32) {
|
||||
log_die("Can't register handler for invalid signal number %d", sig);
|
||||
}
|
||||
if (sig < 0 || sig >= 32) {
|
||||
log_die("Can't register handler for invalid signal number %d", sig);
|
||||
}
|
||||
|
||||
/* Ensure that the application does not install it's own handler */
|
||||
_cnh_signal_handlers[sig] = handler;
|
||||
/* Ensure that the application does not install it's own handler */
|
||||
_cnh_signal_handlers[sig] = handler;
|
||||
|
||||
/* Install a little detour as our signal handler */
|
||||
signal(sig, _cnh_signal_handler);
|
||||
/* Install a little detour as our signal handler */
|
||||
signal(sig, _cnh_signal_handler);
|
||||
|
||||
log_info("Installed signal handler %p for %d", handler, sig);
|
||||
log_info("Installed signal handler %p for %d", handler, sig);
|
||||
}
|
||||
|
||||
int sigaction(int sig, const struct sigaction* act, struct sigaction* oact)
|
||||
int sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
|
||||
{
|
||||
if (_cnh_signal_handlers[sig]) {
|
||||
log_info("Enforce own signal handler on signal: %d", sig);
|
||||
if (_cnh_signal_handlers[sig]) {
|
||||
log_info("Enforce own signal handler on signal: %d", sig);
|
||||
|
||||
/* save the original handler, we might need it */
|
||||
_cnh_signal_orig_handlers[sig] = ((struct sigaction*) act)->sa_handler;
|
||||
/* save the original handler, we might need it */
|
||||
_cnh_signal_orig_handlers[sig] = ((struct sigaction *) act)->sa_handler;
|
||||
|
||||
/* swap */
|
||||
((struct sigaction*) act)->sa_handler = (__sighandler_t) _cnh_signal_handler;
|
||||
/* swap */
|
||||
((struct sigaction *) act)->sa_handler =
|
||||
(__sighandler_t) _cnh_signal_handler;
|
||||
|
||||
log_debug("Original handler %p for signal %d", _cnh_signal_orig_handlers[sig], sig);
|
||||
}
|
||||
log_debug(
|
||||
"Original handler %p for signal %d",
|
||||
_cnh_signal_orig_handlers[sig],
|
||||
sig);
|
||||
}
|
||||
|
||||
if (!_cnh_sig_handler_real_sigaction) {
|
||||
_cnh_sig_handler_real_sigaction = (cnh_sig_handler_sigaction_t) cnh_lib_get_func_addr("sigaction");
|
||||
}
|
||||
if (!_cnh_sig_handler_real_sigaction) {
|
||||
_cnh_sig_handler_real_sigaction =
|
||||
(cnh_sig_handler_sigaction_t) cnh_lib_get_func_addr("sigaction");
|
||||
}
|
||||
|
||||
return _cnh_sig_handler_real_sigaction(sig, act, oact);
|
||||
return _cnh_sig_handler_real_sigaction(sig, act, oact);
|
||||
}
|
||||
|
||||
static void _cnh_signal_handler(int sig)
|
||||
{
|
||||
if (_cnh_signal_handlers[sig]) {
|
||||
_cnh_signal_handlers[sig](sig, _cnh_signal_orig_handlers[sig]);
|
||||
}
|
||||
if (_cnh_signal_handlers[sig]) {
|
||||
_cnh_signal_handlers[sig](sig, _cnh_signal_orig_handlers[sig]);
|
||||
}
|
||||
}
|
||||
+454
-377
File diff suppressed because it is too large
Load Diff
@@ -15,37 +15,37 @@
|
||||
* Available operations to hook
|
||||
*/
|
||||
enum cnh_usbhook_irp_op {
|
||||
CNH_USBHOOK_IRP_OP_INIT = 0,
|
||||
CNH_USBHOOK_IRP_OP_FIND_BUSSES = 1,
|
||||
CNH_USBHOOK_IRP_OP_FIND_DEVICES = 2,
|
||||
CNH_USBHOOK_IRP_OP_OPEN = 3,
|
||||
CNH_USBHOOK_IRP_OP_CLOSE = 4,
|
||||
CNH_USBHOOK_IRP_OP_RESET = 5,
|
||||
CNH_USBHOOK_IRP_OP_SET_ALTINTERFACE = 6,
|
||||
CNH_USBHOOK_IRP_OP_SET_CONFIGURATION = 7,
|
||||
CNH_USBHOOK_IRP_OP_CLAIM_INTERFACE = 8,
|
||||
CNH_USBHOOK_IRP_OP_CTRL_MSG = 9
|
||||
CNH_USBHOOK_IRP_OP_INIT = 0,
|
||||
CNH_USBHOOK_IRP_OP_FIND_BUSSES = 1,
|
||||
CNH_USBHOOK_IRP_OP_FIND_DEVICES = 2,
|
||||
CNH_USBHOOK_IRP_OP_OPEN = 3,
|
||||
CNH_USBHOOK_IRP_OP_CLOSE = 4,
|
||||
CNH_USBHOOK_IRP_OP_RESET = 5,
|
||||
CNH_USBHOOK_IRP_OP_SET_ALTINTERFACE = 6,
|
||||
CNH_USBHOOK_IRP_OP_SET_CONFIGURATION = 7,
|
||||
CNH_USBHOOK_IRP_OP_CLAIM_INTERFACE = 8,
|
||||
CNH_USBHOOK_IRP_OP_CTRL_MSG = 9
|
||||
};
|
||||
|
||||
/**
|
||||
* I/O request packet
|
||||
*/
|
||||
struct cnh_usbhook_irp {
|
||||
enum cnh_usbhook_irp_op op;
|
||||
size_t next_handler;
|
||||
int find_busses_res_num_busses;
|
||||
int find_devices_res_num_devices;
|
||||
struct usb_device* open_usb_dev;
|
||||
usb_dev_handle* handle;
|
||||
int set_altinterface;
|
||||
int set_configuration;
|
||||
int claim_interface;
|
||||
int ctrl_req_type;
|
||||
int ctrl_req;
|
||||
int ctrl_value;
|
||||
int ctrl_index;
|
||||
struct cnh_iobuf ctrl_buffer;
|
||||
int ctrl_timeout;
|
||||
enum cnh_usbhook_irp_op op;
|
||||
size_t next_handler;
|
||||
int find_busses_res_num_busses;
|
||||
int find_devices_res_num_devices;
|
||||
struct usb_device *open_usb_dev;
|
||||
usb_dev_handle *handle;
|
||||
int set_altinterface;
|
||||
int set_configuration;
|
||||
int claim_interface;
|
||||
int ctrl_req_type;
|
||||
int ctrl_req;
|
||||
int ctrl_value;
|
||||
int ctrl_index;
|
||||
struct cnh_iobuf ctrl_buffer;
|
||||
int ctrl_timeout;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -90,6 +90,7 @@ enum cnh_result cnh_usbhook_invoke_next(struct cnh_usbhook_irp *irp);
|
||||
* @param irp I/O request package to dispatch
|
||||
* @return Result of the following function dispatching the request package
|
||||
*/
|
||||
enum cnh_result cnh_usbhook_invoke_next_reset_advance(struct cnh_usbhook_irp *irp);
|
||||
enum cnh_result
|
||||
cnh_usbhook_invoke_next_reset_advance(struct cnh_usbhook_irp *irp);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,54 +4,96 @@
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
static const char* _cnh_filehook_mon_str_empty = "";
|
||||
static const char* _cnh_filehook_mon_irp_op_str[] = {
|
||||
"fopen",
|
||||
"fclose",
|
||||
"fread",
|
||||
"fwrite",
|
||||
"fgets",
|
||||
"fseek",
|
||||
"ftell",
|
||||
"feof"
|
||||
};
|
||||
static const char *_cnh_filehook_mon_str_empty = "";
|
||||
static const char *_cnh_filehook_mon_irp_op_str[] = {
|
||||
"fopen", "fclose", "fread", "fwrite", "fgets", "fseek", "ftell", "feof"};
|
||||
|
||||
enum cnh_result cnh_filehook_mon(struct cnh_filehook_irp *irp)
|
||||
{
|
||||
enum cnh_result result;
|
||||
enum cnh_result result;
|
||||
|
||||
/* Skip writes to log file because this results in infinite recursion */
|
||||
if (irp->file == util_log_get_file_handle()) {
|
||||
return cnh_filehook_invoke_next(irp);
|
||||
}
|
||||
/* Skip writes to log file because this results in infinite recursion */
|
||||
if (irp->file == util_log_get_file_handle()) {
|
||||
return cnh_filehook_invoke_next(irp);
|
||||
}
|
||||
|
||||
log_debug("[before][%s] next_handler %d, file %p, open_filename %s, open_mode %s, read(bytes %p, nbytes %d, pos %d)"
|
||||
", write(bytes %p, nbytes %d, pos %d), orig_read_write_size %d, orig_read_write_nmemb %d, seek_origin %d, "
|
||||
"seek_offset %d, tell_offset %llu, eof %d", _cnh_filehook_mon_irp_op_str[irp->op], irp->next_handler,
|
||||
irp->file, irp->open_filename ? irp->open_filename : _cnh_filehook_mon_str_empty,
|
||||
irp->open_mode ? irp->open_mode : _cnh_filehook_mon_str_empty, irp->read.bytes, irp->read.nbytes,
|
||||
irp->read.pos, irp->write.bytes, irp->write.nbytes, irp->write.pos, irp->orig_read_write_size,
|
||||
irp->orig_read_write_nmemb, irp->seek_origin, irp->seek_offset, irp->tell_offset, irp->eof);
|
||||
log_debug(
|
||||
"[before][%s] next_handler %d, file %p, open_filename %s, open_mode %s, "
|
||||
"read(bytes %p, nbytes %d, pos %d)"
|
||||
", write(bytes %p, nbytes %d, pos %d), orig_read_write_size %d, "
|
||||
"orig_read_write_nmemb %d, seek_origin %d, "
|
||||
"seek_offset %d, tell_offset %llu, eof %d",
|
||||
_cnh_filehook_mon_irp_op_str[irp->op],
|
||||
irp->next_handler,
|
||||
irp->file,
|
||||
irp->open_filename ? irp->open_filename : _cnh_filehook_mon_str_empty,
|
||||
irp->open_mode ? irp->open_mode : _cnh_filehook_mon_str_empty,
|
||||
irp->read.bytes,
|
||||
irp->read.nbytes,
|
||||
irp->read.pos,
|
||||
irp->write.bytes,
|
||||
irp->write.nbytes,
|
||||
irp->write.pos,
|
||||
irp->orig_read_write_size,
|
||||
irp->orig_read_write_nmemb,
|
||||
irp->seek_origin,
|
||||
irp->seek_offset,
|
||||
irp->tell_offset,
|
||||
irp->eof);
|
||||
|
||||
result = cnh_filehook_invoke_next(irp);
|
||||
result = cnh_filehook_invoke_next(irp);
|
||||
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
log_error("[after][%s] result %d, next_handler %d, file %p, open_filename %s, open_mode %s, read(bytes %p, "
|
||||
"nbytes %d, pos %d), write(bytes %p, nbytes %d, pos %d), orig_read_write_size %d, orig_read_write_nmemb %d,"
|
||||
" seek_origin %d, seek_offset %d, tell_offset %llu, eof %d", _cnh_filehook_mon_irp_op_str[irp->op],
|
||||
result, irp->next_handler, irp->file, irp->open_filename ? irp->open_filename : _cnh_filehook_mon_str_empty,
|
||||
irp->open_mode ? irp->open_mode : _cnh_filehook_mon_str_empty, irp->read.bytes, irp->read.nbytes,
|
||||
irp->read.pos, irp->write.bytes, irp->write.nbytes, irp->write.pos, irp->orig_read_write_size,
|
||||
irp->orig_read_write_nmemb, irp->seek_origin, irp->seek_offset, irp->tell_offset, irp->eof);
|
||||
} else {
|
||||
log_debug("[after][%s] result %d, next_handler %d, file %p, open_filename %s, open_mode %s, read(bytes %p, "
|
||||
"nbytes %d, pos %d), write(bytes %p, nbytes %d, pos %d), orig_read_write_size %d, orig_read_write_nmemb %d,"
|
||||
" seek_origin %d, seek_offset %d, tell_offset %llu, eof %d", _cnh_filehook_mon_irp_op_str[irp->op],
|
||||
result, irp->next_handler, irp->file, irp->open_filename ? irp->open_filename : _cnh_filehook_mon_str_empty,
|
||||
irp->open_mode ? irp->open_mode : _cnh_filehook_mon_str_empty, irp->read.bytes, irp->read.nbytes,
|
||||
irp->read.pos, irp->write.bytes, irp->write.nbytes, irp->write.pos, irp->orig_read_write_size,
|
||||
irp->orig_read_write_nmemb, irp->seek_origin, irp->seek_offset, irp->tell_offset, irp->eof);
|
||||
}
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
log_error(
|
||||
"[after][%s] result %d, next_handler %d, file %p, open_filename %s, "
|
||||
"open_mode %s, read(bytes %p, "
|
||||
"nbytes %d, pos %d), write(bytes %p, nbytes %d, pos %d), "
|
||||
"orig_read_write_size %d, orig_read_write_nmemb %d,"
|
||||
" seek_origin %d, seek_offset %d, tell_offset %llu, eof %d",
|
||||
_cnh_filehook_mon_irp_op_str[irp->op],
|
||||
result,
|
||||
irp->next_handler,
|
||||
irp->file,
|
||||
irp->open_filename ? irp->open_filename : _cnh_filehook_mon_str_empty,
|
||||
irp->open_mode ? irp->open_mode : _cnh_filehook_mon_str_empty,
|
||||
irp->read.bytes,
|
||||
irp->read.nbytes,
|
||||
irp->read.pos,
|
||||
irp->write.bytes,
|
||||
irp->write.nbytes,
|
||||
irp->write.pos,
|
||||
irp->orig_read_write_size,
|
||||
irp->orig_read_write_nmemb,
|
||||
irp->seek_origin,
|
||||
irp->seek_offset,
|
||||
irp->tell_offset,
|
||||
irp->eof);
|
||||
} else {
|
||||
log_debug(
|
||||
"[after][%s] result %d, next_handler %d, file %p, open_filename %s, "
|
||||
"open_mode %s, read(bytes %p, "
|
||||
"nbytes %d, pos %d), write(bytes %p, nbytes %d, pos %d), "
|
||||
"orig_read_write_size %d, orig_read_write_nmemb %d,"
|
||||
" seek_origin %d, seek_offset %d, tell_offset %llu, eof %d",
|
||||
_cnh_filehook_mon_irp_op_str[irp->op],
|
||||
result,
|
||||
irp->next_handler,
|
||||
irp->file,
|
||||
irp->open_filename ? irp->open_filename : _cnh_filehook_mon_str_empty,
|
||||
irp->open_mode ? irp->open_mode : _cnh_filehook_mon_str_empty,
|
||||
irp->read.bytes,
|
||||
irp->read.nbytes,
|
||||
irp->read.pos,
|
||||
irp->write.bytes,
|
||||
irp->write.nbytes,
|
||||
irp->write.pos,
|
||||
irp->orig_read_write_size,
|
||||
irp->orig_read_write_nmemb,
|
||||
irp->seek_origin,
|
||||
irp->seek_offset,
|
||||
irp->tell_offset,
|
||||
irp->eof);
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
/**
|
||||
* Hook implementation to monitor file related calls, e.g. fopen, fread, fwrite etc.
|
||||
* Hook implementation to monitor file related calls, e.g. fopen, fread, fwrite
|
||||
* etc.
|
||||
*/
|
||||
#ifndef CAPNHOOK_FILEHOOK_MON_H
|
||||
#define CAPNHOOK_FILEHOOK_MON_H
|
||||
|
||||
@@ -6,91 +6,105 @@
|
||||
|
||||
enum cnh_result cnh_fileopen_mon_filehook(struct cnh_filehook_irp *irp)
|
||||
{
|
||||
enum cnh_result result;
|
||||
enum cnh_result result;
|
||||
|
||||
if (irp->op == CNH_FILEHOOK_IRP_OP_OPEN) {
|
||||
log_debug("[before][fopen]: %s %s", irp->open_filename, irp->open_mode);
|
||||
if (irp->op == CNH_FILEHOOK_IRP_OP_OPEN) {
|
||||
log_debug("[before][fopen]: %s %s", irp->open_filename, irp->open_mode);
|
||||
|
||||
result = cnh_filehook_invoke_next(irp);
|
||||
result = cnh_filehook_invoke_next(irp);
|
||||
|
||||
log_debug("[after][fopen]: %s %s -> %d (%d)", irp->open_filename, irp->open_mode, irp->file, result);
|
||||
} else {
|
||||
result = cnh_filehook_invoke_next(irp);
|
||||
}
|
||||
log_debug(
|
||||
"[after][fopen]: %s %s -> %d (%d)",
|
||||
irp->open_filename,
|
||||
irp->open_mode,
|
||||
irp->file,
|
||||
result);
|
||||
} else {
|
||||
result = cnh_filehook_invoke_next(irp);
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
enum cnh_result cnh_fileopen_mon_fshook(struct cnh_fshook_irp *irp)
|
||||
{
|
||||
enum cnh_result result;
|
||||
enum cnh_result result;
|
||||
|
||||
switch (irp->op) {
|
||||
case CNH_FSHOOK_IRP_OP_DIR_OPEN:
|
||||
log_debug("[before][diropen]: %s", irp->opendir_name);
|
||||
break;
|
||||
case CNH_FSHOOK_IRP_OP_LXSTAT:
|
||||
log_debug("[before][lxstat]: %s", irp->xstat_file);
|
||||
break;
|
||||
case CNH_FSHOOK_IRP_OP_XSTAT:
|
||||
log_debug("[before][xstat]: %s", irp->xstat_file);
|
||||
break;
|
||||
case CNH_FSHOOK_IRP_OP_RENAME:
|
||||
log_debug("[before][rename]: %s %s", irp->rename_old, irp->rename_new);
|
||||
break;
|
||||
case CNH_FSHOOK_IRP_OP_REMOVE:
|
||||
log_debug("[before][remove]: %s", irp->remove_pathname);
|
||||
break;
|
||||
case CNH_FSHOOK_IRP_OP_ACCESS:
|
||||
log_debug("[before][access]: %s", irp->access_path);
|
||||
break;
|
||||
default:
|
||||
log_die("Unhandled case: %d", irp->op);
|
||||
break;
|
||||
}
|
||||
switch (irp->op) {
|
||||
case CNH_FSHOOK_IRP_OP_DIR_OPEN:
|
||||
log_debug("[before][diropen]: %s", irp->opendir_name);
|
||||
break;
|
||||
case CNH_FSHOOK_IRP_OP_LXSTAT:
|
||||
log_debug("[before][lxstat]: %s", irp->xstat_file);
|
||||
break;
|
||||
case CNH_FSHOOK_IRP_OP_XSTAT:
|
||||
log_debug("[before][xstat]: %s", irp->xstat_file);
|
||||
break;
|
||||
case CNH_FSHOOK_IRP_OP_RENAME:
|
||||
log_debug("[before][rename]: %s %s", irp->rename_old, irp->rename_new);
|
||||
break;
|
||||
case CNH_FSHOOK_IRP_OP_REMOVE:
|
||||
log_debug("[before][remove]: %s", irp->remove_pathname);
|
||||
break;
|
||||
case CNH_FSHOOK_IRP_OP_ACCESS:
|
||||
log_debug("[before][access]: %s", irp->access_path);
|
||||
break;
|
||||
default:
|
||||
log_die("Unhandled case: %d", irp->op);
|
||||
break;
|
||||
}
|
||||
|
||||
result = cnh_fshook_invoke_next(irp);
|
||||
result = cnh_fshook_invoke_next(irp);
|
||||
|
||||
switch (irp->op) {
|
||||
case CNH_FSHOOK_IRP_OP_DIR_OPEN:
|
||||
log_debug("[after][diropen]: %s -> %d", irp->opendir_name, result);
|
||||
break;
|
||||
case CNH_FSHOOK_IRP_OP_LXSTAT:
|
||||
log_debug("[after][lxstat]: %s -> %d", irp->xstat_file, result);
|
||||
break;
|
||||
case CNH_FSHOOK_IRP_OP_XSTAT:
|
||||
log_debug("[after][xstat]: %s -> %d", irp->xstat_file, result);
|
||||
break;
|
||||
case CNH_FSHOOK_IRP_OP_RENAME:
|
||||
log_debug("[after][rename]: %s %s -> %d", irp->rename_old, irp->rename_new, result);
|
||||
break;
|
||||
case CNH_FSHOOK_IRP_OP_REMOVE:
|
||||
log_debug("[after][remove]: %s -> %d", irp->remove_pathname, result);
|
||||
break;
|
||||
case CNH_FSHOOK_IRP_OP_ACCESS:
|
||||
log_debug("[after][access]: %s -> %d", irp->access_path, result);
|
||||
break;
|
||||
default:
|
||||
log_die("Unhandled case: %d", irp->op);
|
||||
break;
|
||||
}
|
||||
switch (irp->op) {
|
||||
case CNH_FSHOOK_IRP_OP_DIR_OPEN:
|
||||
log_debug("[after][diropen]: %s -> %d", irp->opendir_name, result);
|
||||
break;
|
||||
case CNH_FSHOOK_IRP_OP_LXSTAT:
|
||||
log_debug("[after][lxstat]: %s -> %d", irp->xstat_file, result);
|
||||
break;
|
||||
case CNH_FSHOOK_IRP_OP_XSTAT:
|
||||
log_debug("[after][xstat]: %s -> %d", irp->xstat_file, result);
|
||||
break;
|
||||
case CNH_FSHOOK_IRP_OP_RENAME:
|
||||
log_debug(
|
||||
"[after][rename]: %s %s -> %d",
|
||||
irp->rename_old,
|
||||
irp->rename_new,
|
||||
result);
|
||||
break;
|
||||
case CNH_FSHOOK_IRP_OP_REMOVE:
|
||||
log_debug("[after][remove]: %s -> %d", irp->remove_pathname, result);
|
||||
break;
|
||||
case CNH_FSHOOK_IRP_OP_ACCESS:
|
||||
log_debug("[after][access]: %s -> %d", irp->access_path, result);
|
||||
break;
|
||||
default:
|
||||
log_die("Unhandled case: %d", irp->op);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
enum cnh_result cnh_fileopen_mon_iohook(struct cnh_iohook_irp *irp)
|
||||
{
|
||||
enum cnh_result result;
|
||||
enum cnh_result result;
|
||||
|
||||
if (irp->op == CNH_IOHOOK_IRP_OP_OPEN) {
|
||||
log_debug("[before][open]: %s %d", irp->open_filename, irp->open_flags);
|
||||
if (irp->op == CNH_IOHOOK_IRP_OP_OPEN) {
|
||||
log_debug("[before][open]: %s %d", irp->open_filename, irp->open_flags);
|
||||
|
||||
result = cnh_iohook_invoke_next(irp);
|
||||
result = cnh_iohook_invoke_next(irp);
|
||||
|
||||
log_debug("[after][open]: %s %d -> %d (%d)", irp->open_filename, irp->open_flags, irp->fd, result);
|
||||
} else {
|
||||
result = cnh_iohook_invoke_next(irp);
|
||||
}
|
||||
log_debug(
|
||||
"[after][open]: %s %d -> %d (%d)",
|
||||
irp->open_filename,
|
||||
irp->open_flags,
|
||||
irp->fd,
|
||||
result);
|
||||
} else {
|
||||
result = cnh_iohook_invoke_next(irp);
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
@@ -9,7 +9,8 @@
|
||||
#include "capnhook/hook/iohook.h"
|
||||
|
||||
/**
|
||||
* Hook function to add to the hook module for monitoring open file calls on file operations
|
||||
* Hook function to add to the hook module for monitoring open file calls on
|
||||
* file operations
|
||||
*
|
||||
* @param irp I/O request package of hook module received
|
||||
* @return Result of operation
|
||||
@@ -17,7 +18,8 @@
|
||||
enum cnh_result cnh_fileopen_mon_filehook(struct cnh_filehook_irp *irp);
|
||||
|
||||
/**
|
||||
* Hook function to add to the hook module for monitoring open file calls on file system related operations
|
||||
* Hook function to add to the hook module for monitoring open file calls on
|
||||
* file system related operations
|
||||
*
|
||||
* @param irp I/O request package of hook module received
|
||||
* @return Result of operation
|
||||
@@ -25,7 +27,8 @@ enum cnh_result cnh_fileopen_mon_filehook(struct cnh_filehook_irp *irp);
|
||||
enum cnh_result cnh_fileopen_mon_fshook(struct cnh_fshook_irp *irp);
|
||||
|
||||
/**
|
||||
* Hook function to add to the hook module for monitoring open file/device calls on I/O operations
|
||||
* Hook function to add to the hook module for monitoring open file/device calls
|
||||
* on I/O operations
|
||||
*
|
||||
* @param irp I/O request package of hook module received
|
||||
* @return Result of operation
|
||||
|
||||
@@ -4,40 +4,74 @@
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
static const char* _cnh_fshook_mon_irp_op_str[] = {
|
||||
"diropen",
|
||||
"lxstat",
|
||||
"xstat",
|
||||
"rename",
|
||||
"remove",
|
||||
"access"
|
||||
};
|
||||
static const char *_cnh_fshook_mon_irp_op_str[] = {
|
||||
"diropen", "lxstat", "xstat", "rename", "remove", "access"};
|
||||
|
||||
enum cnh_result cnh_fshook_mon(struct cnh_fshook_irp *irp)
|
||||
{
|
||||
enum cnh_result result;
|
||||
enum cnh_result result;
|
||||
|
||||
log_debug("[before][%s] next_handler %d, opendir_name %s, opendir_ret %p, xstat_version %d, xstat_file %s, "
|
||||
"xstat_buf %p, rename_old %s, rename_new %s, remove_pathname %s, access_path %s, access_amode %d",
|
||||
_cnh_fshook_mon_irp_op_str[irp->op], irp->next_handler, irp->opendir_name, irp->opendir_ret,
|
||||
irp->xstat_version, irp->xstat_file, irp->xstat_buf, irp->rename_old, irp->rename_new, irp->remove_pathname,
|
||||
irp->access_path, irp->access_amode);
|
||||
log_debug(
|
||||
"[before][%s] next_handler %d, opendir_name %s, opendir_ret %p, "
|
||||
"xstat_version %d, xstat_file %s, "
|
||||
"xstat_buf %p, rename_old %s, rename_new %s, remove_pathname %s, "
|
||||
"access_path %s, access_amode %d",
|
||||
_cnh_fshook_mon_irp_op_str[irp->op],
|
||||
irp->next_handler,
|
||||
irp->opendir_name,
|
||||
irp->opendir_ret,
|
||||
irp->xstat_version,
|
||||
irp->xstat_file,
|
||||
irp->xstat_buf,
|
||||
irp->rename_old,
|
||||
irp->rename_new,
|
||||
irp->remove_pathname,
|
||||
irp->access_path,
|
||||
irp->access_amode);
|
||||
|
||||
result = cnh_fshook_invoke_next(irp);
|
||||
result = cnh_fshook_invoke_next(irp);
|
||||
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
log_error("[before][%s] result %d, next_handler %d, opendir_name %s, opendir_ret %p, xstat_version %d, "
|
||||
"xstat_file %s, xstat_buf %p, rename_old %s, rename_new %s, remove_pathname %s, access_path %s, "
|
||||
"access_amode %d", _cnh_fshook_mon_irp_op_str[irp->op], result, irp->next_handler, irp->opendir_name,
|
||||
irp->opendir_ret, irp->xstat_version, irp->xstat_file, irp->xstat_buf, irp->rename_old, irp->rename_new,
|
||||
irp->remove_pathname, irp->access_path, irp->access_amode);
|
||||
} else {
|
||||
log_debug("[before][%s] result %d, next_handler %d, opendir_name %s, opendir_ret %p, xstat_version %d, "
|
||||
"xstat_file %s, xstat_buf %p, rename_old %s, rename_new %s, remove_pathname %s, access_path %s, "
|
||||
"access_amode %d", _cnh_fshook_mon_irp_op_str[irp->op], result, irp->next_handler, irp->opendir_name,
|
||||
irp->opendir_ret, irp->xstat_version, irp->xstat_file, irp->xstat_buf, irp->rename_old, irp->rename_new,
|
||||
irp->remove_pathname, irp->access_path, irp->access_amode);
|
||||
}
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
log_error(
|
||||
"[before][%s] result %d, next_handler %d, opendir_name %s, opendir_ret "
|
||||
"%p, xstat_version %d, "
|
||||
"xstat_file %s, xstat_buf %p, rename_old %s, rename_new %s, "
|
||||
"remove_pathname %s, access_path %s, "
|
||||
"access_amode %d",
|
||||
_cnh_fshook_mon_irp_op_str[irp->op],
|
||||
result,
|
||||
irp->next_handler,
|
||||
irp->opendir_name,
|
||||
irp->opendir_ret,
|
||||
irp->xstat_version,
|
||||
irp->xstat_file,
|
||||
irp->xstat_buf,
|
||||
irp->rename_old,
|
||||
irp->rename_new,
|
||||
irp->remove_pathname,
|
||||
irp->access_path,
|
||||
irp->access_amode);
|
||||
} else {
|
||||
log_debug(
|
||||
"[before][%s] result %d, next_handler %d, opendir_name %s, opendir_ret "
|
||||
"%p, xstat_version %d, "
|
||||
"xstat_file %s, xstat_buf %p, rename_old %s, rename_new %s, "
|
||||
"remove_pathname %s, access_path %s, "
|
||||
"access_amode %d",
|
||||
_cnh_fshook_mon_irp_op_str[irp->op],
|
||||
result,
|
||||
irp->next_handler,
|
||||
irp->opendir_name,
|
||||
irp->opendir_ret,
|
||||
irp->xstat_version,
|
||||
irp->xstat_file,
|
||||
irp->xstat_buf,
|
||||
irp->rename_old,
|
||||
irp->rename_new,
|
||||
irp->remove_pathname,
|
||||
irp->access_path,
|
||||
irp->access_amode);
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
@@ -7,7 +7,8 @@
|
||||
#include "capnhook/hook/fshook.h"
|
||||
|
||||
/**
|
||||
* Hook function to add to the hook module for monitoring file system related calls
|
||||
* Hook function to add to the hook module for monitoring file system related
|
||||
* calls
|
||||
*
|
||||
* @param irp I/O request package of hook module received
|
||||
* @return Result of operation
|
||||
|
||||
@@ -4,51 +4,106 @@
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
static const char* _cnh_iohook_mon_str_empty = "";
|
||||
static const char* _cnh_iohook_mon_irp_op_str[] = {
|
||||
"open",
|
||||
"fdopen",
|
||||
"close",
|
||||
"read",
|
||||
"write",
|
||||
"seek",
|
||||
"ioctl"
|
||||
};
|
||||
static const char *_cnh_iohook_mon_str_empty = "";
|
||||
static const char *_cnh_iohook_mon_irp_op_str[] = {
|
||||
"open", "fdopen", "close", "read", "write", "seek", "ioctl"};
|
||||
|
||||
enum cnh_result cnh_iohook_mon(struct cnh_iohook_irp *irp)
|
||||
{
|
||||
enum cnh_result result;
|
||||
enum cnh_result result;
|
||||
|
||||
log_debug("[before][%s] next_handler %d, fd %d, open_filename %s, open_flags %d, fdopen_fd %d, fdopen_mode %s, "
|
||||
"fdopen_res %p, read(bytes %p, nbytes %d, pos %d), write(bytes %p, nbytes %d, pos %d), seek_origin %d, "
|
||||
"seek_offset %d, seek_pos %llu, ioctl_req %d, ioctl(bytes %p, nbytes %d, pos %d)",
|
||||
_cnh_iohook_mon_irp_op_str[irp->op], irp->next_handler, irp->fd,
|
||||
irp->open_filename ? irp->open_filename : _cnh_iohook_mon_str_empty, irp->open_flags, irp->fdopen_fd,
|
||||
irp->fdopen_mode ? irp->fdopen_mode : _cnh_iohook_mon_str_empty, irp->fdopen_res, irp->read.bytes,
|
||||
irp->read.nbytes, irp->read.pos, irp->write.bytes, irp->write.nbytes, irp->write.pos, irp->seek_origin,
|
||||
irp->seek_offset, irp->seek_pos, irp->ioctl_req, irp->ioctl.bytes, irp->ioctl.nbytes, irp->ioctl.pos);
|
||||
log_debug(
|
||||
"[before][%s] next_handler %d, fd %d, open_filename %s, open_flags %d, "
|
||||
"fdopen_fd %d, fdopen_mode %s, "
|
||||
"fdopen_res %p, read(bytes %p, nbytes %d, pos %d), write(bytes %p, "
|
||||
"nbytes %d, pos %d), seek_origin %d, "
|
||||
"seek_offset %d, seek_pos %llu, ioctl_req %d, ioctl(bytes %p, nbytes %d, "
|
||||
"pos %d)",
|
||||
_cnh_iohook_mon_irp_op_str[irp->op],
|
||||
irp->next_handler,
|
||||
irp->fd,
|
||||
irp->open_filename ? irp->open_filename : _cnh_iohook_mon_str_empty,
|
||||
irp->open_flags,
|
||||
irp->fdopen_fd,
|
||||
irp->fdopen_mode ? irp->fdopen_mode : _cnh_iohook_mon_str_empty,
|
||||
irp->fdopen_res,
|
||||
irp->read.bytes,
|
||||
irp->read.nbytes,
|
||||
irp->read.pos,
|
||||
irp->write.bytes,
|
||||
irp->write.nbytes,
|
||||
irp->write.pos,
|
||||
irp->seek_origin,
|
||||
irp->seek_offset,
|
||||
irp->seek_pos,
|
||||
irp->ioctl_req,
|
||||
irp->ioctl.bytes,
|
||||
irp->ioctl.nbytes,
|
||||
irp->ioctl.pos);
|
||||
|
||||
result = cnh_iohook_invoke_next(irp);
|
||||
result = cnh_iohook_invoke_next(irp);
|
||||
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
log_error("[after][%s] next_handler %d, res: %d, fd %d, open_filename %s, open_flags %d, fdopen_fd %d, "
|
||||
"fdopen_mode %s, fdopen_res %p, read(bytes %p, nbytes %d, pos %d), write(bytes %p, nbytes %d, pos %d), "
|
||||
"seek_origin %d, seek_offset %d, seek_pos %llu, ioctl_req %d, ioctl(bytes %p, nbytes %d, pos %d)",
|
||||
_cnh_iohook_mon_irp_op_str[irp->op], irp->next_handler, result, irp->fd,
|
||||
irp->open_filename ? irp->open_filename : _cnh_iohook_mon_str_empty, irp->open_flags, irp->fdopen_fd,
|
||||
irp->fdopen_mode ? irp->fdopen_mode : _cnh_iohook_mon_str_empty, irp->fdopen_res, irp->read.bytes,
|
||||
irp->read.nbytes, irp->read.pos, irp->write.bytes, irp->write.nbytes, irp->write.pos, irp->seek_origin,
|
||||
irp->seek_offset, irp->seek_pos, irp->ioctl_req, irp->ioctl.bytes, irp->ioctl.nbytes, irp->ioctl.pos);
|
||||
} else {
|
||||
log_debug("[after][%s] next_handler %d, res %d, fd %d, open_filename %s, open_flags %d, fdopen_fd %d, "
|
||||
"fdopen_mode %s, fdopen_res %p, read(bytes %p, nbytes %d, pos %d), write(bytes %p, nbytes %d, pos %d), "
|
||||
"seek_origin %d, seek_offset %d, seek_pos %llu, ioctl_req %d, ioctl(bytes %p, nbytes %d, pos %d)",
|
||||
_cnh_iohook_mon_irp_op_str[irp->op], irp->next_handler, result, irp->fd,
|
||||
irp->open_filename ? irp->open_filename : _cnh_iohook_mon_str_empty, irp->open_flags, irp->fdopen_fd,
|
||||
irp->fdopen_mode ? irp->fdopen_mode : _cnh_iohook_mon_str_empty, irp->fdopen_res, irp->read.bytes,
|
||||
irp->read.nbytes, irp->read.pos, irp->write.bytes, irp->write.nbytes, irp->write.pos, irp->seek_origin,
|
||||
irp->seek_offset, irp->seek_pos, irp->ioctl_req, irp->ioctl.bytes, irp->ioctl.nbytes, irp->ioctl.pos);
|
||||
}
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
log_error(
|
||||
"[after][%s] next_handler %d, res: %d, fd %d, open_filename %s, "
|
||||
"open_flags %d, fdopen_fd %d, "
|
||||
"fdopen_mode %s, fdopen_res %p, read(bytes %p, nbytes %d, pos %d), "
|
||||
"write(bytes %p, nbytes %d, pos %d), "
|
||||
"seek_origin %d, seek_offset %d, seek_pos %llu, ioctl_req %d, "
|
||||
"ioctl(bytes %p, nbytes %d, pos %d)",
|
||||
_cnh_iohook_mon_irp_op_str[irp->op],
|
||||
irp->next_handler,
|
||||
result,
|
||||
irp->fd,
|
||||
irp->open_filename ? irp->open_filename : _cnh_iohook_mon_str_empty,
|
||||
irp->open_flags,
|
||||
irp->fdopen_fd,
|
||||
irp->fdopen_mode ? irp->fdopen_mode : _cnh_iohook_mon_str_empty,
|
||||
irp->fdopen_res,
|
||||
irp->read.bytes,
|
||||
irp->read.nbytes,
|
||||
irp->read.pos,
|
||||
irp->write.bytes,
|
||||
irp->write.nbytes,
|
||||
irp->write.pos,
|
||||
irp->seek_origin,
|
||||
irp->seek_offset,
|
||||
irp->seek_pos,
|
||||
irp->ioctl_req,
|
||||
irp->ioctl.bytes,
|
||||
irp->ioctl.nbytes,
|
||||
irp->ioctl.pos);
|
||||
} else {
|
||||
log_debug(
|
||||
"[after][%s] next_handler %d, res %d, fd %d, open_filename %s, "
|
||||
"open_flags %d, fdopen_fd %d, "
|
||||
"fdopen_mode %s, fdopen_res %p, read(bytes %p, nbytes %d, pos %d), "
|
||||
"write(bytes %p, nbytes %d, pos %d), "
|
||||
"seek_origin %d, seek_offset %d, seek_pos %llu, ioctl_req %d, "
|
||||
"ioctl(bytes %p, nbytes %d, pos %d)",
|
||||
_cnh_iohook_mon_irp_op_str[irp->op],
|
||||
irp->next_handler,
|
||||
result,
|
||||
irp->fd,
|
||||
irp->open_filename ? irp->open_filename : _cnh_iohook_mon_str_empty,
|
||||
irp->open_flags,
|
||||
irp->fdopen_fd,
|
||||
irp->fdopen_mode ? irp->fdopen_mode : _cnh_iohook_mon_str_empty,
|
||||
irp->fdopen_res,
|
||||
irp->read.bytes,
|
||||
irp->read.nbytes,
|
||||
irp->read.pos,
|
||||
irp->write.bytes,
|
||||
irp->write.nbytes,
|
||||
irp->write.pos,
|
||||
irp->seek_origin,
|
||||
irp->seek_offset,
|
||||
irp->seek_pos,
|
||||
irp->ioctl_req,
|
||||
irp->ioctl.bytes,
|
||||
irp->ioctl.nbytes,
|
||||
irp->ioctl.pos);
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
+189
-167
@@ -4,17 +4,19 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "capnhook/hook/fshook.h"
|
||||
#include "capnhook/hook/filehook.h"
|
||||
#include "capnhook/hook/fshook.h"
|
||||
#include "capnhook/hook/iohook.h"
|
||||
|
||||
#include "util/log.h"
|
||||
#include "util/str.h"
|
||||
#include "util/time.h"
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Hooks to fshook module */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static enum cnh_result _cnh_redir_fshook_diropen(struct cnh_fshook_irp *irp);
|
||||
static enum cnh_result _cnh_redir_fshook_lxstat(struct cnh_fshook_irp *irp);
|
||||
@@ -32,11 +34,14 @@ static const cnh_fshook_fn_t _cnh_redir_fshook_handlers[6] = {
|
||||
[CNH_FSHOOK_IRP_OP_ACCESS] = _cnh_redir_fshook_access,
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Hooks to filehook module */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static enum cnh_result _cnh_redir_filehook_default(struct cnh_filehook_irp *irp);
|
||||
static enum cnh_result
|
||||
_cnh_redir_filehook_default(struct cnh_filehook_irp *irp);
|
||||
static enum cnh_result _cnh_redir_filehook_fopen(struct cnh_filehook_irp *irp);
|
||||
|
||||
static const cnh_filehook_fn_t _cnh_redir_filehook_handlers[8] = {
|
||||
@@ -50,9 +55,11 @@ static const cnh_filehook_fn_t _cnh_redir_filehook_handlers[8] = {
|
||||
[CNH_FILEHOOK_IRP_OP_EOF] = _cnh_redir_filehook_default,
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Hooks to iohook module */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static enum cnh_result _cnh_redir_iohook_default(struct cnh_iohook_irp *irp);
|
||||
static enum cnh_result _cnh_redir_iohook_open(struct cnh_iohook_irp *irp);
|
||||
@@ -67,305 +74,320 @@ static const cnh_iohook_fn_t _cnh_redir_iohook_handlers[7] = {
|
||||
[CNH_IOHOOK_IRP_OP_IOCTL] = _cnh_redir_iohook_default,
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Private state */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
struct cnh_redir_redir {
|
||||
char* src;
|
||||
char* dest;
|
||||
char *src;
|
||||
char *dest;
|
||||
};
|
||||
|
||||
static atomic_int _cnh_redir_initted = ATOMIC_VAR_INIT(0);
|
||||
static atomic_int _cnh_redir_init_in_progress = ATOMIC_VAR_INIT(0);
|
||||
static pthread_mutex_t _cnh_redir_lock;
|
||||
static struct cnh_redir_redir* _cnh_redir_redirs;
|
||||
static struct cnh_redir_redir *_cnh_redir_redirs;
|
||||
static size_t _cnh_redir_nredirs;
|
||||
|
||||
static void _cnh_redir_init();
|
||||
static char* _cnh_redir_check(const char* src);
|
||||
static char *_cnh_redir_check(const char *src);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Public module functions */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void cnh_redir_add(const char* src, const char* dest)
|
||||
void cnh_redir_add(const char *src, const char *dest)
|
||||
{
|
||||
struct cnh_redir_redir *new_array;
|
||||
size_t new_size;
|
||||
struct cnh_redir_redir *new_array;
|
||||
size_t new_size;
|
||||
|
||||
assert(src != NULL);
|
||||
assert(dest != NULL);
|
||||
assert(src != NULL);
|
||||
assert(dest != NULL);
|
||||
|
||||
/* Ensure module is initialized */
|
||||
_cnh_redir_init();
|
||||
/* Ensure module is initialized */
|
||||
_cnh_redir_init();
|
||||
|
||||
pthread_mutex_lock(&_cnh_redir_lock);
|
||||
pthread_mutex_lock(&_cnh_redir_lock);
|
||||
|
||||
new_size = _cnh_redir_nredirs + 1;
|
||||
new_array = realloc(_cnh_redir_redirs, new_size * sizeof(struct cnh_redir_redir));
|
||||
new_size = _cnh_redir_nredirs + 1;
|
||||
new_array =
|
||||
realloc(_cnh_redir_redirs, new_size * sizeof(struct cnh_redir_redir));
|
||||
|
||||
if (new_array != NULL) {
|
||||
_cnh_redir_redirs = new_array;
|
||||
}
|
||||
if (new_array != NULL) {
|
||||
_cnh_redir_redirs = new_array;
|
||||
}
|
||||
|
||||
_cnh_redir_redirs[_cnh_redir_nredirs].src = util_str_dup(src);
|
||||
_cnh_redir_redirs[_cnh_redir_nredirs].dest = util_str_dup(dest);
|
||||
_cnh_redir_redirs[_cnh_redir_nredirs].src = util_str_dup(src);
|
||||
_cnh_redir_redirs[_cnh_redir_nredirs].dest = util_str_dup(dest);
|
||||
|
||||
_cnh_redir_nredirs++;
|
||||
_cnh_redir_nredirs++;
|
||||
|
||||
pthread_mutex_unlock(&_cnh_redir_lock);
|
||||
pthread_mutex_unlock(&_cnh_redir_lock);
|
||||
|
||||
log_info("Added path redirect %s -> %s", src, dest);
|
||||
log_info("Added path redirect %s -> %s", src, dest);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Hooks to fshook module */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
enum cnh_result cnh_redir_fshook(struct cnh_fshook_irp* irp)
|
||||
enum cnh_result cnh_redir_fshook(struct cnh_fshook_irp *irp)
|
||||
{
|
||||
cnh_fshook_fn_t handler;
|
||||
cnh_fshook_fn_t handler;
|
||||
|
||||
handler = _cnh_redir_fshook_handlers[irp->op];
|
||||
handler = _cnh_redir_fshook_handlers[irp->op];
|
||||
|
||||
assert(handler != NULL);
|
||||
assert(handler != NULL);
|
||||
|
||||
return handler(irp);
|
||||
return handler(irp);
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_redir_fshook_diropen(struct cnh_fshook_irp *irp)
|
||||
{
|
||||
char* res;
|
||||
char *res;
|
||||
|
||||
/* Ensure module is initialized */
|
||||
_cnh_redir_init();
|
||||
/* Ensure module is initialized */
|
||||
_cnh_redir_init();
|
||||
|
||||
res = _cnh_redir_check(irp->opendir_name);
|
||||
res = _cnh_redir_check(irp->opendir_name);
|
||||
|
||||
if (res != NULL) {
|
||||
irp->opendir_name = res;
|
||||
}
|
||||
if (res != NULL) {
|
||||
irp->opendir_name = res;
|
||||
}
|
||||
|
||||
return cnh_fshook_invoke_next(irp);
|
||||
return cnh_fshook_invoke_next(irp);
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_redir_fshook_lxstat(struct cnh_fshook_irp *irp)
|
||||
{
|
||||
char* res;
|
||||
char *res;
|
||||
|
||||
/* Ensure module is initialized */
|
||||
_cnh_redir_init();
|
||||
/* Ensure module is initialized */
|
||||
_cnh_redir_init();
|
||||
|
||||
res = _cnh_redir_check(irp->xstat_file);
|
||||
res = _cnh_redir_check(irp->xstat_file);
|
||||
|
||||
if (res != NULL) {
|
||||
irp->xstat_file = res;
|
||||
}
|
||||
if (res != NULL) {
|
||||
irp->xstat_file = res;
|
||||
}
|
||||
|
||||
return cnh_fshook_invoke_next(irp);
|
||||
return cnh_fshook_invoke_next(irp);
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_redir_fshook_xstat(struct cnh_fshook_irp *irp)
|
||||
{
|
||||
char* res;
|
||||
char *res;
|
||||
|
||||
/* Ensure module is initialized */
|
||||
_cnh_redir_init();
|
||||
/* Ensure module is initialized */
|
||||
_cnh_redir_init();
|
||||
|
||||
res = _cnh_redir_check(irp->xstat_file);
|
||||
res = _cnh_redir_check(irp->xstat_file);
|
||||
|
||||
if (res != NULL) {
|
||||
irp->xstat_file = res;
|
||||
}
|
||||
if (res != NULL) {
|
||||
irp->xstat_file = res;
|
||||
}
|
||||
|
||||
return cnh_fshook_invoke_next(irp);
|
||||
return cnh_fshook_invoke_next(irp);
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_redir_fshook_rename(struct cnh_fshook_irp *irp)
|
||||
{
|
||||
char* res_old;
|
||||
char* res_new;
|
||||
char *res_old;
|
||||
char *res_new;
|
||||
|
||||
/* Ensure module is initialized */
|
||||
_cnh_redir_init();
|
||||
/* Ensure module is initialized */
|
||||
_cnh_redir_init();
|
||||
|
||||
res_old = _cnh_redir_check(irp->rename_old);
|
||||
res_new = _cnh_redir_check(irp->rename_old);
|
||||
res_old = _cnh_redir_check(irp->rename_old);
|
||||
res_new = _cnh_redir_check(irp->rename_old);
|
||||
|
||||
if (res_old != NULL) {
|
||||
irp->rename_old = res_old;
|
||||
}
|
||||
if (res_old != NULL) {
|
||||
irp->rename_old = res_old;
|
||||
}
|
||||
|
||||
if (res_new != NULL) {
|
||||
irp->rename_new = res_new;
|
||||
}
|
||||
if (res_new != NULL) {
|
||||
irp->rename_new = res_new;
|
||||
}
|
||||
|
||||
return cnh_fshook_invoke_next(irp);
|
||||
return cnh_fshook_invoke_next(irp);
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_redir_fshook_remove(struct cnh_fshook_irp *irp)
|
||||
{
|
||||
char* res;
|
||||
char *res;
|
||||
|
||||
/* Ensure module is initialized */
|
||||
_cnh_redir_init();
|
||||
/* Ensure module is initialized */
|
||||
_cnh_redir_init();
|
||||
|
||||
res = _cnh_redir_check(irp->remove_pathname);
|
||||
res = _cnh_redir_check(irp->remove_pathname);
|
||||
|
||||
if (res != NULL) {
|
||||
irp->remove_pathname = res;
|
||||
}
|
||||
if (res != NULL) {
|
||||
irp->remove_pathname = res;
|
||||
}
|
||||
|
||||
return cnh_fshook_invoke_next(irp);
|
||||
return cnh_fshook_invoke_next(irp);
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_redir_fshook_access(struct cnh_fshook_irp *irp)
|
||||
{
|
||||
char* res;
|
||||
char *res;
|
||||
|
||||
/* Ensure module is initialized */
|
||||
_cnh_redir_init();
|
||||
/* Ensure module is initialized */
|
||||
_cnh_redir_init();
|
||||
|
||||
res = _cnh_redir_check(irp->access_path);
|
||||
res = _cnh_redir_check(irp->access_path);
|
||||
|
||||
if (res != NULL) {
|
||||
irp->access_path = res;
|
||||
}
|
||||
if (res != NULL) {
|
||||
irp->access_path = res;
|
||||
}
|
||||
|
||||
return cnh_fshook_invoke_next(irp);
|
||||
return cnh_fshook_invoke_next(irp);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Hooks to iohook module */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
enum cnh_result cnh_redir_iohook(struct cnh_iohook_irp* irp)
|
||||
enum cnh_result cnh_redir_iohook(struct cnh_iohook_irp *irp)
|
||||
{
|
||||
cnh_iohook_fn_t handler;
|
||||
cnh_iohook_fn_t handler;
|
||||
|
||||
handler = _cnh_redir_iohook_handlers[irp->op];
|
||||
handler = _cnh_redir_iohook_handlers[irp->op];
|
||||
|
||||
assert(handler != NULL);
|
||||
assert(handler != NULL);
|
||||
|
||||
return handler(irp);
|
||||
return handler(irp);
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_redir_iohook_default(struct cnh_iohook_irp *irp)
|
||||
{
|
||||
return cnh_iohook_invoke_next(irp);
|
||||
return cnh_iohook_invoke_next(irp);
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_redir_iohook_open(struct cnh_iohook_irp *irp)
|
||||
{
|
||||
char* res;
|
||||
char *res;
|
||||
|
||||
/* Ensure module is initialized */
|
||||
_cnh_redir_init();
|
||||
/* Ensure module is initialized */
|
||||
_cnh_redir_init();
|
||||
|
||||
res = _cnh_redir_check(irp->open_filename);
|
||||
res = _cnh_redir_check(irp->open_filename);
|
||||
|
||||
if (res != NULL) {
|
||||
irp->open_filename = res;
|
||||
}
|
||||
if (res != NULL) {
|
||||
irp->open_filename = res;
|
||||
}
|
||||
|
||||
return cnh_iohook_invoke_next(irp);
|
||||
return cnh_iohook_invoke_next(irp);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Hooks to filehook module */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
enum cnh_result cnh_redir_filehook(struct cnh_filehook_irp* irp)
|
||||
enum cnh_result cnh_redir_filehook(struct cnh_filehook_irp *irp)
|
||||
{
|
||||
cnh_filehook_fn_t handler;
|
||||
cnh_filehook_fn_t handler;
|
||||
|
||||
handler = _cnh_redir_filehook_handlers[irp->op];
|
||||
handler = _cnh_redir_filehook_handlers[irp->op];
|
||||
|
||||
assert(handler != NULL);
|
||||
assert(handler != NULL);
|
||||
|
||||
return handler(irp);
|
||||
return handler(irp);
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_redir_filehook_default(struct cnh_filehook_irp *irp)
|
||||
{
|
||||
return cnh_filehook_invoke_next(irp);
|
||||
return cnh_filehook_invoke_next(irp);
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_redir_filehook_fopen(struct cnh_filehook_irp *irp)
|
||||
{
|
||||
char* res;
|
||||
char *res;
|
||||
|
||||
/* Ensure module is initialized */
|
||||
_cnh_redir_init();
|
||||
/* Ensure module is initialized */
|
||||
_cnh_redir_init();
|
||||
|
||||
res = _cnh_redir_check(irp->open_filename);
|
||||
res = _cnh_redir_check(irp->open_filename);
|
||||
|
||||
if (res != NULL) {
|
||||
irp->open_filename = res;
|
||||
}
|
||||
if (res != NULL) {
|
||||
irp->open_filename = res;
|
||||
}
|
||||
|
||||
return cnh_filehook_invoke_next(irp);
|
||||
return cnh_filehook_invoke_next(irp);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Helper functions */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _cnh_redir_init()
|
||||
{
|
||||
int expected;
|
||||
int expected;
|
||||
|
||||
if (atomic_load(&_cnh_redir_initted) > 0) {
|
||||
return;
|
||||
if (atomic_load(&_cnh_redir_initted) > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
expected = 0;
|
||||
|
||||
if (!atomic_compare_exchange_strong(
|
||||
&_cnh_redir_init_in_progress, &expected, 1)) {
|
||||
while (atomic_load(&_cnh_redir_init_in_progress) > 1) {
|
||||
util_time_sleep_us(100);
|
||||
}
|
||||
|
||||
expected = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!atomic_compare_exchange_strong(&_cnh_redir_init_in_progress, &expected, 1)) {
|
||||
while (atomic_load(&_cnh_redir_init_in_progress) > 1) {
|
||||
util_time_sleep_us(100);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check again to ensure the current thread yielded between the init'd check and setting init in progress */
|
||||
if (atomic_load(&_cnh_redir_initted) > 0) {
|
||||
/* Revert init in progress, because nothing to do anymore */
|
||||
atomic_store(&_cnh_redir_init_in_progress, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_init(&_cnh_redir_lock, NULL);
|
||||
|
||||
atomic_store(&_cnh_redir_initted, 1);
|
||||
/* Check again to ensure the current thread yielded between the init'd check
|
||||
* and setting init in progress */
|
||||
if (atomic_load(&_cnh_redir_initted) > 0) {
|
||||
/* Revert init in progress, because nothing to do anymore */
|
||||
atomic_store(&_cnh_redir_init_in_progress, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_init(&_cnh_redir_lock, NULL);
|
||||
|
||||
atomic_store(&_cnh_redir_initted, 1);
|
||||
atomic_store(&_cnh_redir_init_in_progress, 0);
|
||||
}
|
||||
|
||||
static char* _cnh_redir_check(const char* src)
|
||||
static char *_cnh_redir_check(const char *src)
|
||||
{
|
||||
const char* redir_src;
|
||||
const char* redir_dest;
|
||||
char* res;
|
||||
const char *redir_src;
|
||||
const char *redir_dest;
|
||||
char *res;
|
||||
|
||||
res = NULL;
|
||||
res = NULL;
|
||||
|
||||
pthread_mutex_lock(&_cnh_redir_lock);
|
||||
pthread_mutex_lock(&_cnh_redir_lock);
|
||||
|
||||
for (size_t i = 0; i < _cnh_redir_nredirs; i++) {
|
||||
redir_src = _cnh_redir_redirs[i].src;
|
||||
redir_dest = _cnh_redir_redirs[i].dest;
|
||||
for (size_t i = 0; i < _cnh_redir_nredirs; i++) {
|
||||
redir_src = _cnh_redir_redirs[i].src;
|
||||
redir_dest = _cnh_redir_redirs[i].dest;
|
||||
|
||||
if (strncmp(src, redir_src, strlen(redir_src)) == 0) {
|
||||
// FIXME memory leak
|
||||
res = util_str_merge(redir_dest, &src[strlen(redir_src)]);
|
||||
log_debug("Redirect %s -> %s", src, res);
|
||||
break;
|
||||
}
|
||||
if (strncmp(src, redir_src, strlen(redir_src)) == 0) {
|
||||
// FIXME memory leak
|
||||
res = util_str_merge(redir_dest, &src[strlen(redir_src)]);
|
||||
log_debug("Redirect %s -> %s", src, res);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_cnh_redir_lock);
|
||||
pthread_mutex_unlock(&_cnh_redir_lock);
|
||||
|
||||
return res;
|
||||
return res;
|
||||
}
|
||||
@@ -1,29 +1,32 @@
|
||||
/**
|
||||
* Hook implementation to redirect files/paths passed as parameters on various file, file system and I/O calls
|
||||
* Hook implementation to redirect files/paths passed as parameters on various
|
||||
* file, file system and I/O calls
|
||||
*/
|
||||
#ifndef CAPNHOOK_REDIR_H
|
||||
#define CAPNHOOK_REDIR_H
|
||||
|
||||
#include "capnhook/hook/fshook.h"
|
||||
#include "capnhook/hook/filehook.h"
|
||||
#include "capnhook/hook/fshook.h"
|
||||
#include "capnhook/hook/iohook.h"
|
||||
|
||||
/**
|
||||
* Add a new path/file redirect to the module
|
||||
*
|
||||
* @param src Source path/file to redirect. This does not have to match the full path.
|
||||
* Postfix, e.g. just the filename is sufficient as well
|
||||
* @param dest Destination to redirect the original path to. Recommended to use absolute paths here.
|
||||
* @param src Source path/file to redirect. This does not have to match the full
|
||||
* path. Postfix, e.g. just the filename is sufficient as well
|
||||
* @param dest Destination to redirect the original path to. Recommended to use
|
||||
* absolute paths here.
|
||||
*/
|
||||
void cnh_redir_add(const char* src, const char* dest);
|
||||
void cnh_redir_add(const char *src, const char *dest);
|
||||
|
||||
/**
|
||||
* Hook function to add to the hook module for redirecting file system related calls
|
||||
* Hook function to add to the hook module for redirecting file system related
|
||||
* calls
|
||||
*
|
||||
* @param irp I/O request package of hook module received
|
||||
* @return Result of operation
|
||||
*/
|
||||
enum cnh_result cnh_redir_fshook(struct cnh_fshook_irp* irp);
|
||||
enum cnh_result cnh_redir_fshook(struct cnh_fshook_irp *irp);
|
||||
|
||||
/**
|
||||
* Hook function to add to the hook module for redirecting I/O calls
|
||||
@@ -31,7 +34,7 @@ enum cnh_result cnh_redir_fshook(struct cnh_fshook_irp* irp);
|
||||
* @param irp I/O request package of hook module received
|
||||
* @return Result of operation
|
||||
*/
|
||||
enum cnh_result cnh_redir_iohook(struct cnh_iohook_irp* irp);
|
||||
enum cnh_result cnh_redir_iohook(struct cnh_iohook_irp *irp);
|
||||
|
||||
/**
|
||||
* Hook function to add to the hook module for redirecting file related calls
|
||||
@@ -39,6 +42,6 @@ enum cnh_result cnh_redir_iohook(struct cnh_iohook_irp* irp);
|
||||
* @param irp I/O request package of hook module received
|
||||
* @return Result of operation
|
||||
*/
|
||||
enum cnh_result cnh_redir_filehook(struct cnh_filehook_irp* irp);
|
||||
enum cnh_result cnh_redir_filehook(struct cnh_filehook_irp *irp);
|
||||
|
||||
#endif
|
||||
+353
-300
@@ -10,24 +10,32 @@
|
||||
#include "util/log.h"
|
||||
#include "util/time.h"
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Private helpers */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _cnh_usb_emu_init(void);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Hooks to usbhook module */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static enum cnh_result _cnh_usb_emu_usbhook_default(struct cnh_usbhook_irp *irp);
|
||||
static enum cnh_result
|
||||
_cnh_usb_emu_usbhook_default(struct cnh_usbhook_irp *irp);
|
||||
static enum cnh_result _cnh_usb_emu_usbhook_noop(struct cnh_usbhook_irp *irp);
|
||||
static enum cnh_result _cnh_usb_emu_usbhook_find_busses(struct cnh_usbhook_irp *irp);
|
||||
static enum cnh_result _cnh_usb_emu_usbhook_find_devices(struct cnh_usbhook_irp *irp);
|
||||
static enum cnh_result
|
||||
_cnh_usb_emu_usbhook_find_busses(struct cnh_usbhook_irp *irp);
|
||||
static enum cnh_result
|
||||
_cnh_usb_emu_usbhook_find_devices(struct cnh_usbhook_irp *irp);
|
||||
static enum cnh_result _cnh_usb_emu_usbhook_open(struct cnh_usbhook_irp *irp);
|
||||
static enum cnh_result _cnh_usb_emu_usbhook_close(struct cnh_usbhook_irp *irp);
|
||||
static enum cnh_result _cnh_usb_emu_usbhook_reset(struct cnh_usbhook_irp *irp);
|
||||
static enum cnh_result _cnh_usb_emu_usbhook_ctrl_msg(struct cnh_usbhook_irp *irp);
|
||||
static enum cnh_result
|
||||
_cnh_usb_emu_usbhook_ctrl_msg(struct cnh_usbhook_irp *irp);
|
||||
|
||||
static const cnh_usbhook_fn_t _cnh_usb_emu_usb_handlers[10] = {
|
||||
[CNH_USBHOOK_IRP_OP_INIT] = _cnh_usb_emu_usbhook_default,
|
||||
@@ -42,19 +50,21 @@ static const cnh_usbhook_fn_t _cnh_usb_emu_usb_handlers[10] = {
|
||||
[CNH_USBHOOK_IRP_OP_CTRL_MSG] = _cnh_usb_emu_usbhook_ctrl_msg,
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Private state */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
struct usb_dev_handle {
|
||||
struct cnh_usb_emu_virtdev* virtdev;
|
||||
struct cnh_usb_emu_virtdev *virtdev;
|
||||
};
|
||||
|
||||
struct cnh_usb_emu_virtdev {
|
||||
const struct cnh_usb_emu_virtdev_ep* ep;
|
||||
bool real_dev_avail;
|
||||
bool enumerated;
|
||||
struct usb_dev_handle usb_dev_handle;
|
||||
const struct cnh_usb_emu_virtdev_ep *ep;
|
||||
bool real_dev_avail;
|
||||
bool enumerated;
|
||||
struct usb_dev_handle usb_dev_handle;
|
||||
};
|
||||
|
||||
static atomic_int _cnh_usb_emu_initted = ATOMIC_VAR_INIT(0);
|
||||
@@ -63,432 +73,475 @@ static pthread_mutex_t _cnh_usb_emu_virtdevs_lock;
|
||||
static struct cnh_usb_emu_virtdev *_cnh_usb_emu_virtdevs;
|
||||
static size_t _cnh_usb_emu_nvirtdevs;
|
||||
|
||||
static struct cnh_usb_emu_virtdev* _cnh_usb_emu_get_virtdev(uint16_t vid, uint16_t pid);
|
||||
static struct cnh_usb_emu_virtdev* _cnh_usb_emu_get_virtdev_by_handle(usb_dev_handle* handle);
|
||||
static struct usb_device* _cnh_usb_emu_create_fakedev(uint16_t vid, uint16_t pid);
|
||||
static struct cnh_usb_emu_virtdev *
|
||||
_cnh_usb_emu_get_virtdev(uint16_t vid, uint16_t pid);
|
||||
static struct cnh_usb_emu_virtdev *
|
||||
_cnh_usb_emu_get_virtdev_by_handle(usb_dev_handle *handle);
|
||||
static struct usb_device *
|
||||
_cnh_usb_emu_create_fakedev(uint16_t vid, uint16_t pid);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Public module functions */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void cnh_usb_emu_add_virtdevep(const struct cnh_usb_emu_virtdev_ep* virtdevep)
|
||||
void cnh_usb_emu_add_virtdevep(const struct cnh_usb_emu_virtdev_ep *virtdevep)
|
||||
{
|
||||
struct cnh_usb_emu_virtdev *new_array;
|
||||
size_t new_size;
|
||||
struct cnh_usb_emu_virtdev *new_array;
|
||||
size_t new_size;
|
||||
|
||||
assert(virtdevep->enumerate);
|
||||
assert(virtdevep->open);
|
||||
assert(virtdevep->reset);
|
||||
assert(virtdevep->control_msg);
|
||||
assert(virtdevep->close);
|
||||
assert(virtdevep->enumerate);
|
||||
assert(virtdevep->open);
|
||||
assert(virtdevep->reset);
|
||||
assert(virtdevep->control_msg);
|
||||
assert(virtdevep->close);
|
||||
|
||||
/* Ensure initialized */
|
||||
_cnh_usb_emu_init();
|
||||
/* Ensure initialized */
|
||||
_cnh_usb_emu_init();
|
||||
|
||||
pthread_mutex_lock(&_cnh_usb_emu_virtdevs_lock);
|
||||
pthread_mutex_lock(&_cnh_usb_emu_virtdevs_lock);
|
||||
|
||||
new_size = _cnh_usb_emu_nvirtdevs + 1;
|
||||
new_array = realloc(_cnh_usb_emu_virtdevs, new_size * sizeof(struct cnh_usb_emu_virtdev));
|
||||
new_size = _cnh_usb_emu_nvirtdevs + 1;
|
||||
new_array = realloc(
|
||||
_cnh_usb_emu_virtdevs, new_size * sizeof(struct cnh_usb_emu_virtdev));
|
||||
|
||||
if (new_array != NULL) {
|
||||
_cnh_usb_emu_virtdevs = new_array;
|
||||
if (new_array != NULL) {
|
||||
_cnh_usb_emu_virtdevs = new_array;
|
||||
|
||||
_cnh_usb_emu_virtdevs[_cnh_usb_emu_nvirtdevs].enumerated = false;
|
||||
_cnh_usb_emu_virtdevs[_cnh_usb_emu_nvirtdevs].real_dev_avail = false;
|
||||
_cnh_usb_emu_virtdevs[_cnh_usb_emu_nvirtdevs].ep = virtdevep;
|
||||
_cnh_usb_emu_virtdevs[_cnh_usb_emu_nvirtdevs].usb_dev_handle.virtdev = &_cnh_usb_emu_virtdevs[_cnh_usb_emu_nvirtdevs];
|
||||
_cnh_usb_emu_nvirtdevs++;
|
||||
} else {
|
||||
log_die("Out of memory");
|
||||
}
|
||||
_cnh_usb_emu_virtdevs[_cnh_usb_emu_nvirtdevs].enumerated = false;
|
||||
_cnh_usb_emu_virtdevs[_cnh_usb_emu_nvirtdevs].real_dev_avail = false;
|
||||
_cnh_usb_emu_virtdevs[_cnh_usb_emu_nvirtdevs].ep = virtdevep;
|
||||
_cnh_usb_emu_virtdevs[_cnh_usb_emu_nvirtdevs].usb_dev_handle.virtdev =
|
||||
&_cnh_usb_emu_virtdevs[_cnh_usb_emu_nvirtdevs];
|
||||
_cnh_usb_emu_nvirtdevs++;
|
||||
} else {
|
||||
log_die("Out of memory");
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_cnh_usb_emu_virtdevs_lock);
|
||||
pthread_mutex_unlock(&_cnh_usb_emu_virtdevs_lock);
|
||||
}
|
||||
|
||||
enum cnh_result cnh_usb_emu(struct cnh_usbhook_irp *irp)
|
||||
{
|
||||
cnh_usbhook_fn_t handler;
|
||||
cnh_usbhook_fn_t handler;
|
||||
|
||||
/* Ensure initialized */
|
||||
_cnh_usb_emu_init();
|
||||
/* Ensure initialized */
|
||||
_cnh_usb_emu_init();
|
||||
|
||||
handler = _cnh_usb_emu_usb_handlers[irp->op];
|
||||
handler = _cnh_usb_emu_usb_handlers[irp->op];
|
||||
|
||||
assert(handler != NULL);
|
||||
assert(handler != NULL);
|
||||
|
||||
return handler(irp);
|
||||
return handler(irp);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Hooked functions to usbhook module */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static enum cnh_result _cnh_usb_emu_usbhook_default(struct cnh_usbhook_irp *irp)
|
||||
{
|
||||
return cnh_usbhook_invoke_next(irp);
|
||||
return cnh_usbhook_invoke_next(irp);
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_usb_emu_usbhook_noop(struct cnh_usbhook_irp *irp)
|
||||
{
|
||||
struct cnh_usb_emu_virtdev* virtdev;
|
||||
struct cnh_usb_emu_virtdev *virtdev;
|
||||
|
||||
assert(irp->handle);
|
||||
assert(irp->handle);
|
||||
|
||||
virtdev = _cnh_usb_emu_get_virtdev_by_handle(irp->handle);
|
||||
virtdev = _cnh_usb_emu_get_virtdev_by_handle(irp->handle);
|
||||
|
||||
/* Not a virtual device handle, probably real handle from libusb */
|
||||
if (virtdev == NULL) {
|
||||
return cnh_usbhook_invoke_next(irp);
|
||||
}
|
||||
/* Not a virtual device handle, probably real handle from libusb */
|
||||
if (virtdev == NULL) {
|
||||
return cnh_usbhook_invoke_next(irp);
|
||||
}
|
||||
|
||||
/* No-op */
|
||||
/* No-op */
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_usb_emu_usbhook_find_busses(struct cnh_usbhook_irp *irp)
|
||||
static enum cnh_result
|
||||
_cnh_usb_emu_usbhook_find_busses(struct cnh_usbhook_irp *irp)
|
||||
{
|
||||
enum cnh_result result;
|
||||
enum cnh_result result;
|
||||
|
||||
result = cnh_usbhook_invoke_next(irp);
|
||||
result = cnh_usbhook_invoke_next(irp);
|
||||
|
||||
// inject another custom bus for virtual devices
|
||||
if (result == CNH_RESULT_SUCCESS) {
|
||||
log_debug("Injecting usb bus for virtual devices");
|
||||
irp->find_busses_res_num_busses++;
|
||||
}
|
||||
// inject another custom bus for virtual devices
|
||||
if (result == CNH_RESULT_SUCCESS) {
|
||||
log_debug("Injecting usb bus for virtual devices");
|
||||
irp->find_busses_res_num_busses++;
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_usb_emu_usbhook_find_devices(struct cnh_usbhook_irp *irp)
|
||||
static enum cnh_result
|
||||
_cnh_usb_emu_usbhook_find_devices(struct cnh_usbhook_irp *irp)
|
||||
{
|
||||
enum cnh_result result;
|
||||
struct usb_bus* it;
|
||||
int fakedev_count;
|
||||
enum cnh_result result;
|
||||
struct usb_bus *it;
|
||||
int fakedev_count;
|
||||
|
||||
fakedev_count = 0;
|
||||
fakedev_count = 0;
|
||||
|
||||
/* first, populate the list with real devices */
|
||||
result = cnh_usbhook_invoke_next(irp);
|
||||
/* first, populate the list with real devices */
|
||||
result = cnh_usbhook_invoke_next(irp);
|
||||
|
||||
/* Iterate to the end of the list and add our stuff keeping real devices */
|
||||
it = usb_get_busses();
|
||||
/* Iterate to the end of the list and add our stuff keeping real devices */
|
||||
it = usb_get_busses();
|
||||
|
||||
/* Iterate all busses */
|
||||
do {
|
||||
/* First, iterate all devices on each bus and check for all real
|
||||
devices connected which are also part of our hook list */
|
||||
if (it != NULL) {
|
||||
/* Iterate devices on the current bus */
|
||||
struct usb_device* dev = it->devices;
|
||||
/* Iterate all busses */
|
||||
do {
|
||||
/* First, iterate all devices on each bus and check for all real
|
||||
devices connected which are also part of our hook list */
|
||||
if (it != NULL) {
|
||||
/* Iterate devices on the current bus */
|
||||
struct usb_device *dev = it->devices;
|
||||
|
||||
while (dev != NULL) {
|
||||
struct cnh_usb_emu_virtdev* virt_dev = _cnh_usb_emu_get_virtdev((uint16_t) dev->descriptor.idVendor,
|
||||
(uint16_t) dev->descriptor.idProduct);
|
||||
while (dev != NULL) {
|
||||
struct cnh_usb_emu_virtdev *virt_dev = _cnh_usb_emu_get_virtdev(
|
||||
(uint16_t) dev->descriptor.idVendor,
|
||||
(uint16_t) dev->descriptor.idProduct);
|
||||
|
||||
/* Real device connected for a hook */
|
||||
if (virt_dev) {
|
||||
log_debug("Detected real %04X:%04X device for virtual one", dev->descriptor.idVendor,
|
||||
dev->descriptor.idProduct);
|
||||
virt_dev->real_dev_avail = true;
|
||||
}
|
||||
/* Real device connected for a hook */
|
||||
if (virt_dev) {
|
||||
log_debug(
|
||||
"Detected real %04X:%04X device for virtual one",
|
||||
dev->descriptor.idVendor,
|
||||
dev->descriptor.idProduct);
|
||||
virt_dev->real_dev_avail = true;
|
||||
}
|
||||
|
||||
dev = dev->next;
|
||||
}
|
||||
}
|
||||
dev = dev->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* it == NULL, nothing found on current bus which is our last bus
|
||||
we added on usb_find_busses. We put our fakedevs on that bus */
|
||||
if (it == NULL || it->next == NULL) {
|
||||
struct usb_bus* fakebus;
|
||||
struct usb_device* fakebus_dev_tail;
|
||||
/* it == NULL, nothing found on current bus which is our last bus
|
||||
we added on usb_find_busses. We put our fakedevs on that bus */
|
||||
if (it == NULL || it->next == NULL) {
|
||||
struct usb_bus *fakebus;
|
||||
struct usb_device *fakebus_dev_tail;
|
||||
|
||||
/* Create an additional bus for our fakedevs */
|
||||
fakebus = (struct usb_bus*) util_xmalloc(sizeof(struct usb_bus));
|
||||
memset(fakebus, 0, sizeof(struct usb_bus));
|
||||
/* Create an additional bus for our fakedevs */
|
||||
fakebus = (struct usb_bus *) util_xmalloc(sizeof(struct usb_bus));
|
||||
memset(fakebus, 0, sizeof(struct usb_bus));
|
||||
|
||||
/* Make sure to modify the linked list correctly. If we fuck up,
|
||||
this works fine until Fiesta where they started to iterate
|
||||
everything in a different manner (-> crash) */
|
||||
if (it == NULL) {
|
||||
usb_busses = fakebus;
|
||||
/* Bus empty, no prev bus */
|
||||
fakebus->prev = NULL;
|
||||
} else {
|
||||
/* Append at end of bus chain */
|
||||
it->next = fakebus;
|
||||
/* Keep doubly linked list intact */
|
||||
fakebus->prev = it->next;
|
||||
}
|
||||
/* Make sure to modify the linked list correctly. If we fuck up,
|
||||
this works fine until Fiesta where they started to iterate
|
||||
everything in a different manner (-> crash) */
|
||||
if (it == NULL) {
|
||||
usb_busses = fakebus;
|
||||
/* Bus empty, no prev bus */
|
||||
fakebus->prev = NULL;
|
||||
} else {
|
||||
/* Append at end of bus chain */
|
||||
it->next = fakebus;
|
||||
/* Keep doubly linked list intact */
|
||||
fakebus->prev = it->next;
|
||||
}
|
||||
|
||||
fakebus_dev_tail = NULL;
|
||||
fakebus_dev_tail = NULL;
|
||||
|
||||
pthread_mutex_lock(&_cnh_usb_emu_virtdevs_lock);
|
||||
pthread_mutex_lock(&_cnh_usb_emu_virtdevs_lock);
|
||||
|
||||
for (size_t i = 0; i < _cnh_usb_emu_nvirtdevs; i++) {
|
||||
struct cnh_usb_emu_virtdev* virtdev = &_cnh_usb_emu_virtdevs[i];
|
||||
for (size_t i = 0; i < _cnh_usb_emu_nvirtdevs; i++) {
|
||||
struct cnh_usb_emu_virtdev *virtdev = &_cnh_usb_emu_virtdevs[i];
|
||||
|
||||
virtdev->enumerated = virtdev->ep->enumerate(virtdev->real_dev_avail);
|
||||
virtdev->enumerated = virtdev->ep->enumerate(virtdev->real_dev_avail);
|
||||
|
||||
if (virtdev->enumerated) {
|
||||
if (virtdev->real_dev_avail) {
|
||||
/* Suppress real device and detour everything to
|
||||
our hook */
|
||||
log_debug("Suppressing real device %04X:%04X", virtdev->ep->vid, virtdev->ep->pid);
|
||||
} else {
|
||||
/* Create a fakedev and add it to the bus */
|
||||
struct usb_device* fakedev;
|
||||
if (virtdev->enumerated) {
|
||||
if (virtdev->real_dev_avail) {
|
||||
/* Suppress real device and detour everything to
|
||||
our hook */
|
||||
log_debug(
|
||||
"Suppressing real device %04X:%04X",
|
||||
virtdev->ep->vid,
|
||||
virtdev->ep->pid);
|
||||
} else {
|
||||
/* Create a fakedev and add it to the bus */
|
||||
struct usb_device *fakedev;
|
||||
|
||||
{
|
||||
/* Print this once. Pump Pro calls this
|
||||
function every second */
|
||||
static int counter = 0;
|
||||
{
|
||||
/* Print this once. Pump Pro calls this
|
||||
function every second */
|
||||
static int counter = 0;
|
||||
|
||||
if (counter++ == 0) {
|
||||
log_info("Injecting fake usb device %04X:%04X into bus", virtdev->ep->vid,
|
||||
virtdev->ep->pid);
|
||||
} else {
|
||||
counter = 1;
|
||||
}
|
||||
}
|
||||
|
||||
fakedev = _cnh_usb_emu_create_fakedev(virtdev->ep->vid, virtdev->ep->pid);
|
||||
|
||||
/* Append to linked list */
|
||||
if (!fakebus->devices) {
|
||||
/* Set root on bus */
|
||||
fakebus->devices = fakedev;
|
||||
}
|
||||
|
||||
/* Cur element */
|
||||
fakedev->prev = fakebus_dev_tail;
|
||||
fakedev->next = NULL;
|
||||
|
||||
/* Update prev element's next */
|
||||
if (fakebus_dev_tail) {
|
||||
fakebus_dev_tail->next = fakedev;
|
||||
}
|
||||
|
||||
/* tail update */
|
||||
fakebus_dev_tail = fakedev;
|
||||
|
||||
fakedev_count++;
|
||||
}
|
||||
} else {
|
||||
log_debug("Reject enumerate hook for %04X:%04X", virtdev->ep->vid, virtdev->ep->pid);
|
||||
}
|
||||
if (counter++ == 0) {
|
||||
log_info(
|
||||
"Injecting fake usb device %04X:%04X into bus",
|
||||
virtdev->ep->vid,
|
||||
virtdev->ep->pid);
|
||||
} else {
|
||||
counter = 1;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_cnh_usb_emu_virtdevs_lock);
|
||||
fakedev =
|
||||
_cnh_usb_emu_create_fakedev(virtdev->ep->vid, virtdev->ep->pid);
|
||||
|
||||
break;
|
||||
}
|
||||
/* End of if block which handles fakedevs and hooking */
|
||||
/* Append to linked list */
|
||||
if (!fakebus->devices) {
|
||||
/* Set root on bus */
|
||||
fakebus->devices = fakedev;
|
||||
}
|
||||
|
||||
it = it->next;
|
||||
}
|
||||
while (it != NULL);
|
||||
/* Cur element */
|
||||
fakedev->prev = fakebus_dev_tail;
|
||||
fakedev->next = NULL;
|
||||
|
||||
{
|
||||
/* Print this once. Pump Pro calls this
|
||||
function every second */
|
||||
static int counter = 0;
|
||||
/* Update prev element's next */
|
||||
if (fakebus_dev_tail) {
|
||||
fakebus_dev_tail->next = fakedev;
|
||||
}
|
||||
|
||||
if (counter++ == 0) {
|
||||
log_info("Added %d fakedevs to usb bus", fakedev_count);
|
||||
/* tail update */
|
||||
fakebus_dev_tail = fakedev;
|
||||
|
||||
fakedev_count++;
|
||||
}
|
||||
} else {
|
||||
counter = 1;
|
||||
log_debug(
|
||||
"Reject enumerate hook for %04X:%04X",
|
||||
virtdev->ep->vid,
|
||||
virtdev->ep->pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* include our fakedev count as well */
|
||||
return result + fakedev_count;
|
||||
pthread_mutex_unlock(&_cnh_usb_emu_virtdevs_lock);
|
||||
|
||||
break;
|
||||
}
|
||||
/* End of if block which handles fakedevs and hooking */
|
||||
|
||||
it = it->next;
|
||||
} while (it != NULL);
|
||||
|
||||
{
|
||||
/* Print this once. Pump Pro calls this
|
||||
function every second */
|
||||
static int counter = 0;
|
||||
|
||||
if (counter++ == 0) {
|
||||
log_info("Added %d fakedevs to usb bus", fakedev_count);
|
||||
} else {
|
||||
counter = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* include our fakedev count as well */
|
||||
return result + fakedev_count;
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_usb_emu_usbhook_open(struct cnh_usbhook_irp *irp)
|
||||
{
|
||||
struct cnh_usb_emu_virtdev* virtdev;
|
||||
enum cnh_result result;
|
||||
struct cnh_usb_emu_virtdev *virtdev;
|
||||
enum cnh_result result;
|
||||
|
||||
virtdev = _cnh_usb_emu_get_virtdev((uint16_t) irp->open_usb_dev->descriptor.idVendor,
|
||||
(uint16_t) irp->open_usb_dev->descriptor.idProduct);
|
||||
virtdev = _cnh_usb_emu_get_virtdev(
|
||||
(uint16_t) irp->open_usb_dev->descriptor.idVendor,
|
||||
(uint16_t) irp->open_usb_dev->descriptor.idProduct);
|
||||
|
||||
if (virtdev == NULL) {
|
||||
return cnh_usbhook_invoke_next(irp);
|
||||
}
|
||||
if (virtdev == NULL) {
|
||||
return cnh_usbhook_invoke_next(irp);
|
||||
}
|
||||
|
||||
if (!virtdev->enumerated) {
|
||||
log_debug("Virtdev %04X:%04X not enumerated, skipping open", virtdev->ep->vid, virtdev->ep->pid);
|
||||
return cnh_usbhook_invoke_next(irp);
|
||||
}
|
||||
if (!virtdev->enumerated) {
|
||||
log_debug(
|
||||
"Virtdev %04X:%04X not enumerated, skipping open",
|
||||
virtdev->ep->vid,
|
||||
virtdev->ep->pid);
|
||||
return cnh_usbhook_invoke_next(irp);
|
||||
}
|
||||
|
||||
result = virtdev->ep->open();
|
||||
result = virtdev->ep->open();
|
||||
|
||||
if (result == CNH_RESULT_SUCCESS) {
|
||||
/* Return handle, use virtual device as fake handle */
|
||||
irp->handle = &virtdev->usb_dev_handle;
|
||||
}
|
||||
if (result == CNH_RESULT_SUCCESS) {
|
||||
/* Return handle, use virtual device as fake handle */
|
||||
irp->handle = &virtdev->usb_dev_handle;
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_usb_emu_usbhook_close(struct cnh_usbhook_irp *irp)
|
||||
{
|
||||
struct cnh_usb_emu_virtdev* virtdev;
|
||||
struct cnh_usb_emu_virtdev *virtdev;
|
||||
|
||||
assert(irp->handle);
|
||||
assert(irp->handle);
|
||||
|
||||
virtdev = _cnh_usb_emu_get_virtdev_by_handle(irp->handle);
|
||||
virtdev = _cnh_usb_emu_get_virtdev_by_handle(irp->handle);
|
||||
|
||||
/* Not a virtual device handle, probably real handle from libusb */
|
||||
if (virtdev == NULL) {
|
||||
return cnh_usbhook_invoke_next(irp);
|
||||
}
|
||||
/* Not a virtual device handle, probably real handle from libusb */
|
||||
if (virtdev == NULL) {
|
||||
return cnh_usbhook_invoke_next(irp);
|
||||
}
|
||||
|
||||
virtdev->ep->close();
|
||||
virtdev->ep->close();
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_usb_emu_usbhook_reset(struct cnh_usbhook_irp *irp)
|
||||
{
|
||||
struct cnh_usb_emu_virtdev* virtdev;
|
||||
struct cnh_usb_emu_virtdev *virtdev;
|
||||
|
||||
assert(irp->handle);
|
||||
assert(irp->handle);
|
||||
|
||||
virtdev = _cnh_usb_emu_get_virtdev_by_handle(irp->handle);
|
||||
virtdev = _cnh_usb_emu_get_virtdev_by_handle(irp->handle);
|
||||
|
||||
/* Not a virtual device handle, probably real handle from libusb */
|
||||
if (virtdev == NULL) {
|
||||
return cnh_usbhook_invoke_next(irp);
|
||||
}
|
||||
/* Not a virtual device handle, probably real handle from libusb */
|
||||
if (virtdev == NULL) {
|
||||
return cnh_usbhook_invoke_next(irp);
|
||||
}
|
||||
|
||||
return virtdev->ep->reset();
|
||||
return virtdev->ep->reset();
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_usb_emu_usbhook_ctrl_msg(struct cnh_usbhook_irp *irp)
|
||||
static enum cnh_result
|
||||
_cnh_usb_emu_usbhook_ctrl_msg(struct cnh_usbhook_irp *irp)
|
||||
{
|
||||
struct cnh_usb_emu_virtdev* virtdev;
|
||||
struct cnh_usb_emu_virtdev *virtdev;
|
||||
|
||||
assert(irp->handle);
|
||||
assert(irp->handle);
|
||||
|
||||
virtdev = _cnh_usb_emu_get_virtdev_by_handle(irp->handle);
|
||||
virtdev = _cnh_usb_emu_get_virtdev_by_handle(irp->handle);
|
||||
|
||||
/* Not a virtual device handle, probably real handle from libusb */
|
||||
if (virtdev == NULL) {
|
||||
return cnh_usbhook_invoke_next(irp);
|
||||
}
|
||||
/* Not a virtual device handle, probably real handle from libusb */
|
||||
if (virtdev == NULL) {
|
||||
return cnh_usbhook_invoke_next(irp);
|
||||
}
|
||||
|
||||
return virtdev->ep->control_msg(irp->ctrl_req_type, irp->ctrl_req, irp->ctrl_value, irp->ctrl_index,
|
||||
&irp->ctrl_buffer, irp->ctrl_timeout);
|
||||
return virtdev->ep->control_msg(
|
||||
irp->ctrl_req_type,
|
||||
irp->ctrl_req,
|
||||
irp->ctrl_value,
|
||||
irp->ctrl_index,
|
||||
&irp->ctrl_buffer,
|
||||
irp->ctrl_timeout);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
/* Helper functions */
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void _cnh_usb_emu_init(void)
|
||||
{
|
||||
int expected;
|
||||
int expected;
|
||||
|
||||
if (atomic_load(&_cnh_usb_emu_initted) > 0) {
|
||||
return;
|
||||
if (atomic_load(&_cnh_usb_emu_initted) > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
expected = 0;
|
||||
|
||||
if (!atomic_compare_exchange_strong(
|
||||
&_cnh_usb_emu_init_in_progress, &expected, 1)) {
|
||||
while (atomic_load(&_cnh_usb_emu_init_in_progress) > 1) {
|
||||
util_time_sleep_us(100);
|
||||
}
|
||||
|
||||
expected = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!atomic_compare_exchange_strong(&_cnh_usb_emu_init_in_progress, &expected, 1)) {
|
||||
while (atomic_load(&_cnh_usb_emu_init_in_progress) > 1) {
|
||||
util_time_sleep_us(100);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check again to ensure the current thread yielded between the init'd check and setting init in progress */
|
||||
if (atomic_load(&_cnh_usb_emu_initted) > 0) {
|
||||
/* Revert init in progress, because nothing to do anymore */
|
||||
atomic_store(&_cnh_usb_emu_init_in_progress, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_init(&_cnh_usb_emu_virtdevs_lock, NULL);
|
||||
|
||||
atomic_store(&_cnh_usb_emu_initted, 1);
|
||||
/* Check again to ensure the current thread yielded between the init'd check
|
||||
* and setting init in progress */
|
||||
if (atomic_load(&_cnh_usb_emu_initted) > 0) {
|
||||
/* Revert init in progress, because nothing to do anymore */
|
||||
atomic_store(&_cnh_usb_emu_init_in_progress, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_init(&_cnh_usb_emu_virtdevs_lock, NULL);
|
||||
|
||||
atomic_store(&_cnh_usb_emu_initted, 1);
|
||||
atomic_store(&_cnh_usb_emu_init_in_progress, 0);
|
||||
}
|
||||
|
||||
static struct cnh_usb_emu_virtdev* _cnh_usb_emu_get_virtdev(uint16_t vid, uint16_t pid)
|
||||
static struct cnh_usb_emu_virtdev *
|
||||
_cnh_usb_emu_get_virtdev(uint16_t vid, uint16_t pid)
|
||||
{
|
||||
struct cnh_usb_emu_virtdev* virtdev;
|
||||
struct cnh_usb_emu_virtdev* tmp;
|
||||
struct cnh_usb_emu_virtdev *virtdev;
|
||||
struct cnh_usb_emu_virtdev *tmp;
|
||||
|
||||
virtdev = NULL;
|
||||
virtdev = NULL;
|
||||
|
||||
pthread_mutex_lock(&_cnh_usb_emu_virtdevs_lock);
|
||||
pthread_mutex_lock(&_cnh_usb_emu_virtdevs_lock);
|
||||
|
||||
for (size_t i = 0; i < _cnh_usb_emu_nvirtdevs; i++) {
|
||||
tmp = &_cnh_usb_emu_virtdevs[i];
|
||||
for (size_t i = 0; i < _cnh_usb_emu_nvirtdevs; i++) {
|
||||
tmp = &_cnh_usb_emu_virtdevs[i];
|
||||
|
||||
if (tmp->ep->vid == vid && tmp->ep->pid == pid) {
|
||||
virtdev = tmp;
|
||||
break;
|
||||
}
|
||||
if (tmp->ep->vid == vid && tmp->ep->pid == pid) {
|
||||
virtdev = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_cnh_usb_emu_virtdevs_lock);
|
||||
pthread_mutex_unlock(&_cnh_usb_emu_virtdevs_lock);
|
||||
|
||||
return virtdev;
|
||||
return virtdev;
|
||||
}
|
||||
|
||||
static struct cnh_usb_emu_virtdev* _cnh_usb_emu_get_virtdev_by_handle(usb_dev_handle* handle)
|
||||
static struct cnh_usb_emu_virtdev *
|
||||
_cnh_usb_emu_get_virtdev_by_handle(usb_dev_handle *handle)
|
||||
{
|
||||
struct cnh_usb_emu_virtdev* virtdev;
|
||||
struct cnh_usb_emu_virtdev* tmp;
|
||||
struct cnh_usb_emu_virtdev *virtdev;
|
||||
struct cnh_usb_emu_virtdev *tmp;
|
||||
|
||||
virtdev = NULL;
|
||||
virtdev = NULL;
|
||||
|
||||
pthread_mutex_lock(&_cnh_usb_emu_virtdevs_lock);
|
||||
pthread_mutex_lock(&_cnh_usb_emu_virtdevs_lock);
|
||||
|
||||
for (size_t i = 0; i < _cnh_usb_emu_nvirtdevs; i++) {
|
||||
tmp = &_cnh_usb_emu_virtdevs[i];
|
||||
for (size_t i = 0; i < _cnh_usb_emu_nvirtdevs; i++) {
|
||||
tmp = &_cnh_usb_emu_virtdevs[i];
|
||||
|
||||
if (tmp == handle->virtdev) {
|
||||
virtdev = tmp;
|
||||
break;
|
||||
}
|
||||
if (tmp == handle->virtdev) {
|
||||
virtdev = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_cnh_usb_emu_virtdevs_lock);
|
||||
pthread_mutex_unlock(&_cnh_usb_emu_virtdevs_lock);
|
||||
|
||||
return virtdev;
|
||||
return virtdev;
|
||||
}
|
||||
|
||||
static struct usb_device* _cnh_usb_emu_create_fakedev(uint16_t vid, uint16_t pid)
|
||||
static struct usb_device *
|
||||
_cnh_usb_emu_create_fakedev(uint16_t vid, uint16_t pid)
|
||||
{
|
||||
struct usb_device* fakedev = (struct usb_device*) util_xmalloc(sizeof(struct usb_device));
|
||||
memset(fakedev, 0, sizeof(struct usb_device));
|
||||
struct usb_device *fakedev =
|
||||
(struct usb_device *) util_xmalloc(sizeof(struct usb_device));
|
||||
memset(fakedev, 0, sizeof(struct usb_device));
|
||||
|
||||
/* Populate fakedev */
|
||||
fakedev->descriptor.idVendor = vid;
|
||||
fakedev->descriptor.idProduct = pid;
|
||||
/* Populate fakedev */
|
||||
fakedev->descriptor.idVendor = vid;
|
||||
fakedev->descriptor.idProduct = pid;
|
||||
|
||||
/* Mark as fakedev */
|
||||
fakedev->descriptor.bcdDevice = 0xBEEF;
|
||||
/* Mark as fakedev */
|
||||
fakedev->descriptor.bcdDevice = 0xBEEF;
|
||||
|
||||
fakedev->config = (struct usb_config_descriptor*) util_xmalloc(
|
||||
sizeof(struct usb_config_descriptor));
|
||||
memset(fakedev->config, 0, sizeof(struct usb_config_descriptor));
|
||||
fakedev->config = (struct usb_config_descriptor *) util_xmalloc(
|
||||
sizeof(struct usb_config_descriptor));
|
||||
memset(fakedev->config, 0, sizeof(struct usb_config_descriptor));
|
||||
|
||||
fakedev->config->interface = (struct usb_interface*) util_xmalloc(
|
||||
sizeof(struct usb_interface));
|
||||
memset(fakedev->config->interface, 0, sizeof(struct usb_interface));
|
||||
fakedev->config->interface =
|
||||
(struct usb_interface *) util_xmalloc(sizeof(struct usb_interface));
|
||||
memset(fakedev->config->interface, 0, sizeof(struct usb_interface));
|
||||
|
||||
fakedev->config->interface->altsetting = (struct usb_interface_descriptor*)
|
||||
util_xmalloc(sizeof(struct usb_interface_descriptor));
|
||||
memset(fakedev->config->interface->altsetting, 0,
|
||||
sizeof(struct usb_interface_descriptor));
|
||||
fakedev->config->interface->altsetting =
|
||||
(struct usb_interface_descriptor *) util_xmalloc(
|
||||
sizeof(struct usb_interface_descriptor));
|
||||
memset(
|
||||
fakedev->config->interface->altsetting,
|
||||
0,
|
||||
sizeof(struct usb_interface_descriptor));
|
||||
|
||||
return fakedev;
|
||||
return fakedev;
|
||||
}
|
||||
@@ -14,14 +14,19 @@
|
||||
* Virtual device endpoint
|
||||
*/
|
||||
struct cnh_usb_emu_virtdev_ep {
|
||||
uint16_t pid;
|
||||
uint16_t vid;
|
||||
bool (*enumerate)(bool real_exists);
|
||||
enum cnh_result (*open)(void);
|
||||
enum cnh_result (*reset)(void);
|
||||
enum cnh_result (*control_msg)(int request_type, int request, int value, int index, struct cnh_iobuf* buffer,
|
||||
int timeout);
|
||||
void (*close)(void);
|
||||
uint16_t pid;
|
||||
uint16_t vid;
|
||||
bool (*enumerate)(bool real_exists);
|
||||
enum cnh_result (*open)(void);
|
||||
enum cnh_result (*reset)(void);
|
||||
enum cnh_result (*control_msg)(
|
||||
int request_type,
|
||||
int request,
|
||||
int value,
|
||||
int index,
|
||||
struct cnh_iobuf *buffer,
|
||||
int timeout);
|
||||
void (*close)(void);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -29,7 +34,7 @@ struct cnh_usb_emu_virtdev_ep {
|
||||
*
|
||||
* @param virtdevep Virtual device endpoint to add
|
||||
*/
|
||||
void cnh_usb_emu_add_virtdevep(const struct cnh_usb_emu_virtdev_ep* virtdevep);
|
||||
void cnh_usb_emu_add_virtdevep(const struct cnh_usb_emu_virtdev_ep *virtdevep);
|
||||
|
||||
/**
|
||||
* Hook function to add to the hook module for emulating usb devices
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
static enum cnh_result _cnh_usb_init_fix_default(struct cnh_usbhook_irp* irp);
|
||||
static enum cnh_result _cnh_usb_init_fix_init(struct cnh_usbhook_irp* irp);
|
||||
static enum cnh_result _cnh_usbio_emu_find_busses(struct cnh_usbhook_irp* irp);
|
||||
static enum cnh_result _cnh_usb_init_fix_default(struct cnh_usbhook_irp *irp);
|
||||
static enum cnh_result _cnh_usb_init_fix_init(struct cnh_usbhook_irp *irp);
|
||||
static enum cnh_result _cnh_usbio_emu_find_busses(struct cnh_usbhook_irp *irp);
|
||||
|
||||
static const cnh_usbhook_fn_t _hook_usb_init_fix_handlers[10] = {
|
||||
[CNH_USBHOOK_IRP_OP_INIT] = _cnh_usb_init_fix_init,
|
||||
@@ -25,56 +25,56 @@ static int _cnh_usb_init_fix_init_count = 0;
|
||||
|
||||
enum cnh_result cnh_usb_init_fix(struct cnh_usbhook_irp *irp)
|
||||
{
|
||||
cnh_usbhook_fn_t handler;
|
||||
cnh_usbhook_fn_t handler;
|
||||
|
||||
handler = _hook_usb_init_fix_handlers[irp->op];
|
||||
handler = _hook_usb_init_fix_handlers[irp->op];
|
||||
|
||||
assert(handler != NULL);
|
||||
assert(handler != NULL);
|
||||
|
||||
return handler(irp);
|
||||
return handler(irp);
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_usb_init_fix_default(struct cnh_usbhook_irp* irp)
|
||||
static enum cnh_result _cnh_usb_init_fix_default(struct cnh_usbhook_irp *irp)
|
||||
{
|
||||
return cnh_usbhook_invoke_next(irp);
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_usb_init_fix_init(struct cnh_usbhook_irp *irp)
|
||||
{
|
||||
/* On NXA, one programmer/multiple programmers had the bright idea to call
|
||||
usb_init twice for reasons...
|
||||
This breaks stuff in the usb-0.1 backend resulting in usb_find_busses
|
||||
not even finding native devices anymore.
|
||||
Make sure we call the real usb_init ONCE ONLY to fix that fuck up */
|
||||
_cnh_usb_init_fix_init_count++;
|
||||
|
||||
if (_cnh_usb_init_fix_init_count <= 1) {
|
||||
return cnh_usbhook_invoke_next(irp);
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_usb_init_fix_init(struct cnh_usbhook_irp* irp)
|
||||
{
|
||||
/* On NXA, one programmer/multiple programmers had the bright idea to call
|
||||
usb_init twice for reasons...
|
||||
This breaks stuff in the usb-0.1 backend resulting in usb_find_busses
|
||||
not even finding native devices anymore.
|
||||
Make sure we call the real usb_init ONCE ONLY to fix that fuck up */
|
||||
_cnh_usb_init_fix_init_count++;
|
||||
|
||||
if (_cnh_usb_init_fix_init_count <= 1) {
|
||||
return cnh_usbhook_invoke_next(irp);
|
||||
} else {
|
||||
/* Pump Pro is even worse and calls usb_init approx. every second...
|
||||
avoid overflow of counter if we really leave this running forever.
|
||||
Furthermore, this avoids printing the log message below with ever
|
||||
init call */
|
||||
if (_cnh_usb_init_fix_init_count > 2) {
|
||||
_cnh_usb_init_fix_init_count = 2;
|
||||
} else {
|
||||
/* Pump Pro is even worse and calls usb_init approx. every second...
|
||||
avoid overflow of counter if we really leave this running forever.
|
||||
Furthermore, this avoids printing the log message below with ever
|
||||
init call */
|
||||
if (_cnh_usb_init_fix_init_count > 2) {
|
||||
_cnh_usb_init_fix_init_count = 2;
|
||||
} else {
|
||||
log_info("usb_init called multiple times, blocking further calls...");
|
||||
}
|
||||
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_usbio_emu_find_busses(struct cnh_usbhook_irp* irp)
|
||||
{
|
||||
enum cnh_result result;
|
||||
|
||||
/* Fixes quirks with usb_init called multiple times on NXA */
|
||||
if (_cnh_usb_init_fix_init_count <= 1) {
|
||||
result = cnh_usbhook_invoke_next(irp);
|
||||
} else {
|
||||
result = CNH_RESULT_SUCCESS;
|
||||
log_info("usb_init called multiple times, blocking further calls...");
|
||||
}
|
||||
|
||||
return result;
|
||||
return CNH_RESULT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
static enum cnh_result _cnh_usbio_emu_find_busses(struct cnh_usbhook_irp *irp)
|
||||
{
|
||||
enum cnh_result result;
|
||||
|
||||
/* Fixes quirks with usb_init called multiple times on NXA */
|
||||
if (_cnh_usb_init_fix_init_count <= 1) {
|
||||
result = cnh_usbhook_invoke_next(irp);
|
||||
} else {
|
||||
result = CNH_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
static const char* _cnh_usbhook_mon_irp_op_str[] = {
|
||||
static const char *_cnh_usbhook_mon_irp_op_str[] = {
|
||||
"init",
|
||||
"find_busses",
|
||||
"find_devices",
|
||||
@@ -14,42 +14,94 @@ static const char* _cnh_usbhook_mon_irp_op_str[] = {
|
||||
"set_altinterface",
|
||||
"set_configuration",
|
||||
"claim_interface",
|
||||
"ctrl_msg"
|
||||
};
|
||||
"ctrl_msg"};
|
||||
|
||||
enum cnh_result cnh_usbhook_mon(struct cnh_usbhook_irp *irp)
|
||||
{
|
||||
enum cnh_result result;
|
||||
enum cnh_result result;
|
||||
|
||||
log_debug("[before][%s] next_handler %d, find_busses_res_num_busses %d, find_devices_res_num_devices %d, "
|
||||
"open_usb_dev %p, handle %p, set_altinterface %d, set_configuration %d, claim_interface %d, ctrl_req_type %d, "
|
||||
"ctrl_req %d, ctrl_value %d, ctrl_index %d, ctrl_buffer(bytes %p, nbytes %d, pos %d), ctrl_timeout %d",
|
||||
_cnh_usbhook_mon_irp_op_str[irp->op], irp->next_handler, irp->find_busses_res_num_busses,
|
||||
irp->find_devices_res_num_devices, irp->open_usb_dev, irp->handle, irp->set_altinterface,
|
||||
irp->set_configuration, irp->claim_interface, irp->ctrl_req_type, irp->ctrl_req, irp->ctrl_value,
|
||||
irp->ctrl_index, irp->ctrl_buffer.bytes, irp->ctrl_buffer.nbytes, irp->ctrl_buffer.pos, irp->ctrl_timeout);
|
||||
log_debug(
|
||||
"[before][%s] next_handler %d, find_busses_res_num_busses %d, "
|
||||
"find_devices_res_num_devices %d, "
|
||||
"open_usb_dev %p, handle %p, set_altinterface %d, set_configuration %d, "
|
||||
"claim_interface %d, ctrl_req_type %d, "
|
||||
"ctrl_req %d, ctrl_value %d, ctrl_index %d, ctrl_buffer(bytes %p, nbytes "
|
||||
"%d, pos %d), ctrl_timeout %d",
|
||||
_cnh_usbhook_mon_irp_op_str[irp->op],
|
||||
irp->next_handler,
|
||||
irp->find_busses_res_num_busses,
|
||||
irp->find_devices_res_num_devices,
|
||||
irp->open_usb_dev,
|
||||
irp->handle,
|
||||
irp->set_altinterface,
|
||||
irp->set_configuration,
|
||||
irp->claim_interface,
|
||||
irp->ctrl_req_type,
|
||||
irp->ctrl_req,
|
||||
irp->ctrl_value,
|
||||
irp->ctrl_index,
|
||||
irp->ctrl_buffer.bytes,
|
||||
irp->ctrl_buffer.nbytes,
|
||||
irp->ctrl_buffer.pos,
|
||||
irp->ctrl_timeout);
|
||||
|
||||
result = cnh_usbhook_invoke_next(irp);
|
||||
result = cnh_usbhook_invoke_next(irp);
|
||||
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
log_error("[after][%s] result %d, next_handler %d, find_busses_res_num_busses %d, "
|
||||
"find_devices_res_num_devices %d, open_usb_dev %p, handle %p, set_altinterface %d, set_configuration %d, "
|
||||
"claim_interface %d, ctrl_req_type %d, ctrl_req %d, ctrl_value %d, ctrl_index %d, ctrl_buffer(bytes %p, "
|
||||
"nbytes %d, pos %d), ctrl_timeout %d", _cnh_usbhook_mon_irp_op_str[irp->op], result, irp->next_handler,
|
||||
irp->find_busses_res_num_busses, irp->find_devices_res_num_devices, irp->open_usb_dev, irp->handle,
|
||||
irp->set_altinterface, irp->set_configuration, irp->claim_interface, irp->ctrl_req_type, irp->ctrl_req,
|
||||
irp->ctrl_value, irp->ctrl_index, irp->ctrl_buffer.bytes, irp->ctrl_buffer.nbytes, irp->ctrl_buffer.pos,
|
||||
irp->ctrl_timeout);
|
||||
} else {
|
||||
log_debug("[after][%s] result %d, next_handler %d, find_busses_res_num_busses %d, "
|
||||
"find_devices_res_num_devices %d, open_usb_dev %p, handle %p, set_altinterface %d, set_configuration %d, "
|
||||
"claim_interface %d, ctrl_req_type %d, ctrl_req %d, ctrl_value %d, ctrl_index %d, ctrl_buffer(bytes %p, "
|
||||
"nbytes %d, pos %d), ctrl_timeout %d", _cnh_usbhook_mon_irp_op_str[irp->op], result, irp->next_handler,
|
||||
irp->find_busses_res_num_busses, irp->find_devices_res_num_devices, irp->open_usb_dev, irp->handle,
|
||||
irp->set_altinterface, irp->set_configuration, irp->claim_interface, irp->ctrl_req_type, irp->ctrl_req,
|
||||
irp->ctrl_value, irp->ctrl_index, irp->ctrl_buffer.bytes, irp->ctrl_buffer.nbytes, irp->ctrl_buffer.pos,
|
||||
irp->ctrl_timeout);
|
||||
}
|
||||
if (result != CNH_RESULT_SUCCESS) {
|
||||
log_error(
|
||||
"[after][%s] result %d, next_handler %d, find_busses_res_num_busses "
|
||||
"%d, "
|
||||
"find_devices_res_num_devices %d, open_usb_dev %p, handle %p, "
|
||||
"set_altinterface %d, set_configuration %d, "
|
||||
"claim_interface %d, ctrl_req_type %d, ctrl_req %d, ctrl_value %d, "
|
||||
"ctrl_index %d, ctrl_buffer(bytes %p, "
|
||||
"nbytes %d, pos %d), ctrl_timeout %d",
|
||||
_cnh_usbhook_mon_irp_op_str[irp->op],
|
||||
result,
|
||||
irp->next_handler,
|
||||
irp->find_busses_res_num_busses,
|
||||
irp->find_devices_res_num_devices,
|
||||
irp->open_usb_dev,
|
||||
irp->handle,
|
||||
irp->set_altinterface,
|
||||
irp->set_configuration,
|
||||
irp->claim_interface,
|
||||
irp->ctrl_req_type,
|
||||
irp->ctrl_req,
|
||||
irp->ctrl_value,
|
||||
irp->ctrl_index,
|
||||
irp->ctrl_buffer.bytes,
|
||||
irp->ctrl_buffer.nbytes,
|
||||
irp->ctrl_buffer.pos,
|
||||
irp->ctrl_timeout);
|
||||
} else {
|
||||
log_debug(
|
||||
"[after][%s] result %d, next_handler %d, find_busses_res_num_busses "
|
||||
"%d, "
|
||||
"find_devices_res_num_devices %d, open_usb_dev %p, handle %p, "
|
||||
"set_altinterface %d, set_configuration %d, "
|
||||
"claim_interface %d, ctrl_req_type %d, ctrl_req %d, ctrl_value %d, "
|
||||
"ctrl_index %d, ctrl_buffer(bytes %p, "
|
||||
"nbytes %d, pos %d), ctrl_timeout %d",
|
||||
_cnh_usbhook_mon_irp_op_str[irp->op],
|
||||
result,
|
||||
irp->next_handler,
|
||||
irp->find_busses_res_num_busses,
|
||||
irp->find_devices_res_num_devices,
|
||||
irp->open_usb_dev,
|
||||
irp->handle,
|
||||
irp->set_altinterface,
|
||||
irp->set_configuration,
|
||||
irp->claim_interface,
|
||||
irp->ctrl_req_type,
|
||||
irp->ctrl_req,
|
||||
irp->ctrl_value,
|
||||
irp->ctrl_index,
|
||||
irp->ctrl_buffer.bytes,
|
||||
irp->ctrl_buffer.nbytes,
|
||||
irp->ctrl_buffer.pos,
|
||||
irp->ctrl_timeout);
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
+24
-16
@@ -4,26 +4,34 @@
|
||||
|
||||
#include "aes.h"
|
||||
|
||||
void crypt_aes_enc(uint8_t* key, enum crypt_aes_key_length key_len,
|
||||
uint8_t* out, const uint8_t* in, size_t nbytes)
|
||||
void crypt_aes_enc(
|
||||
uint8_t *key,
|
||||
enum crypt_aes_key_length key_len,
|
||||
uint8_t *out,
|
||||
const uint8_t *in,
|
||||
size_t nbytes)
|
||||
{
|
||||
unsigned long rk[RKLENGTH(128)];
|
||||
int nrounds;
|
||||
unsigned long rk[RKLENGTH(128)];
|
||||
int nrounds;
|
||||
|
||||
nrounds = rijndaelSetupEncrypt(rk, key, key_len * 8);
|
||||
for (size_t i = 0; i < nbytes / key_len; i++) {
|
||||
rijndaelEncrypt(rk, nrounds, &in[i * key_len], &out[i * key_len]);
|
||||
}
|
||||
nrounds = rijndaelSetupEncrypt(rk, key, key_len * 8);
|
||||
for (size_t i = 0; i < nbytes / key_len; i++) {
|
||||
rijndaelEncrypt(rk, nrounds, &in[i * key_len], &out[i * key_len]);
|
||||
}
|
||||
}
|
||||
|
||||
void crypt_aes_dec(uint8_t* key, enum crypt_aes_key_length key_len,
|
||||
uint8_t* out, const uint8_t* in, size_t nbytes)
|
||||
void crypt_aes_dec(
|
||||
uint8_t *key,
|
||||
enum crypt_aes_key_length key_len,
|
||||
uint8_t *out,
|
||||
const uint8_t *in,
|
||||
size_t nbytes)
|
||||
{
|
||||
unsigned long rk[RKLENGTH(128)];
|
||||
int nrounds;
|
||||
unsigned long rk[RKLENGTH(128)];
|
||||
int nrounds;
|
||||
|
||||
nrounds = rijndaelSetupDecrypt(rk, key, key_len * 8);
|
||||
for (size_t i = 0; i < nbytes / key_len; i++) {
|
||||
rijndaelDecrypt(rk, nrounds, &in[i * key_len], &out[i * key_len]);
|
||||
}
|
||||
nrounds = rijndaelSetupDecrypt(rk, key, key_len * 8);
|
||||
for (size_t i = 0; i < nbytes / key_len; i++) {
|
||||
rijndaelDecrypt(rk, nrounds, &in[i * key_len], &out[i * key_len]);
|
||||
}
|
||||
}
|
||||
+18
-10
@@ -8,12 +8,12 @@
|
||||
* AES enc/dec key lengths
|
||||
*/
|
||||
enum crypt_aes_key_length {
|
||||
/* 128 bit */
|
||||
CRYPT_AES_KEY_LENGTH_16_BYTES = 16,
|
||||
/* 192 bit */
|
||||
CRYPT_AES_KEY_LENGTH_24_BYTES = 24,
|
||||
/* 256 bit */
|
||||
CRYPT_AES_KEY_LENGTH_32_BYTES = 32,
|
||||
/* 128 bit */
|
||||
CRYPT_AES_KEY_LENGTH_16_BYTES = 16,
|
||||
/* 192 bit */
|
||||
CRYPT_AES_KEY_LENGTH_24_BYTES = 24,
|
||||
/* 256 bit */
|
||||
CRYPT_AES_KEY_LENGTH_32_BYTES = 32,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -25,8 +25,12 @@ enum crypt_aes_key_length {
|
||||
* @param in Input buffer to encrypt
|
||||
* @param nbytes Number of bytes of input buffer to encrypt
|
||||
*/
|
||||
void crypt_aes_enc(uint8_t* key, enum crypt_aes_key_length key_len,
|
||||
uint8_t* out, const uint8_t* in, size_t nbytes);
|
||||
void crypt_aes_enc(
|
||||
uint8_t *key,
|
||||
enum crypt_aes_key_length key_len,
|
||||
uint8_t *out,
|
||||
const uint8_t *in,
|
||||
size_t nbytes);
|
||||
|
||||
/**
|
||||
* Decrypt data
|
||||
@@ -37,7 +41,11 @@ void crypt_aes_enc(uint8_t* key, enum crypt_aes_key_length key_len,
|
||||
* @param in Input buffer to decrypt
|
||||
* @param nbytes Number of bytes of input buffer to decrypt
|
||||
*/
|
||||
void crypt_aes_dec(uint8_t* key, enum crypt_aes_key_length key_len,
|
||||
uint8_t* out, const uint8_t* in, size_t nbytes);
|
||||
void crypt_aes_dec(
|
||||
uint8_t *key,
|
||||
enum crypt_aes_key_length key_len,
|
||||
uint8_t *out,
|
||||
const uint8_t *in,
|
||||
size_t nbytes);
|
||||
|
||||
#endif
|
||||
+136
-144
@@ -42,17 +42,16 @@ documentation and/or software.
|
||||
#define S43 15
|
||||
#define S44 21
|
||||
|
||||
static void MD5Transform (uint32_t [4], unsigned char [64]);
|
||||
static void MD5Transform(uint32_t[4], unsigned char[64]);
|
||||
static void Encode(unsigned char *, uint32_t *, unsigned int);
|
||||
static void Decode(uint32_t *, unsigned char *, unsigned int);
|
||||
static void MD5_memcpy(uint8_t *, uint8_t *, unsigned int);
|
||||
static void MD5_memset(uint8_t *, int, unsigned int);
|
||||
|
||||
static unsigned char PADDING[64] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
/* F, G, H and I are basic MD5 functions.
|
||||
*/
|
||||
@@ -63,40 +62,43 @@ static unsigned char PADDING[64] = {
|
||||
|
||||
/* ROTATE_LEFT rotates x left n bits.
|
||||
*/
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
||||
|
||||
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
|
||||
Rotation is separate from addition to prevent recomputation.
|
||||
*/
|
||||
#define FF(a, b, c, d, x, s, ac) { \
|
||||
(a) += F ((b), (c), (d)) + (x) + (uint32_t)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
#define FF(a, b, c, d, x, s, ac) \
|
||||
{ \
|
||||
(a) += F((b), (c), (d)) + (x) + (uint32_t)(ac); \
|
||||
(a) = ROTATE_LEFT((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define GG(a, b, c, d, x, s, ac) { \
|
||||
(a) += G ((b), (c), (d)) + (x) + (uint32_t)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
#define GG(a, b, c, d, x, s, ac) \
|
||||
{ \
|
||||
(a) += G((b), (c), (d)) + (x) + (uint32_t)(ac); \
|
||||
(a) = ROTATE_LEFT((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define HH(a, b, c, d, x, s, ac) { \
|
||||
(a) += H ((b), (c), (d)) + (x) + (uint32_t)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
#define HH(a, b, c, d, x, s, ac) \
|
||||
{ \
|
||||
(a) += H((b), (c), (d)) + (x) + (uint32_t)(ac); \
|
||||
(a) = ROTATE_LEFT((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define II(a, b, c, d, x, s, ac) { \
|
||||
(a) += I ((b), (c), (d)) + (x) + (uint32_t)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
#define II(a, b, c, d, x, s, ac) \
|
||||
{ \
|
||||
(a) += I((b), (c), (d)) + (x) + (uint32_t)(ac); \
|
||||
(a) = ROTATE_LEFT((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
|
||||
/* MD5 initialization. Begins an MD5 operation, writing a new context.
|
||||
*/
|
||||
void MD5Init (context)
|
||||
MD5_CTX *context; /* context */
|
||||
void MD5Init(context) MD5_CTX *context; /* context */
|
||||
{
|
||||
context->count[0] = context->count[1] = 0;
|
||||
/* Load magic initialization constants.
|
||||
*/
|
||||
*/
|
||||
context->state[0] = 0x67452301;
|
||||
context->state[1] = 0xefcdab89;
|
||||
context->state[2] = 0x98badcfe;
|
||||
@@ -107,158 +109,152 @@ MD5_CTX *context; /* context */
|
||||
operation, processing another message block, and updating the
|
||||
context.
|
||||
*/
|
||||
void MD5Update (context, input, inputLen)
|
||||
MD5_CTX *context; /* context */
|
||||
unsigned char *input; /* input block */
|
||||
unsigned int inputLen; /* length of input block */
|
||||
void MD5Update(context, input, inputLen) MD5_CTX *context; /* context */
|
||||
unsigned char *input; /* input block */
|
||||
unsigned int inputLen; /* length of input block */
|
||||
{
|
||||
unsigned int i, index, partLen;
|
||||
|
||||
/* Compute number of bytes mod 64 */
|
||||
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
|
||||
index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
|
||||
|
||||
/* Update number of bits */
|
||||
if ((context->count[0] += ((uint32_t)inputLen << 3))
|
||||
if ((context->count[0] += ((uint32_t) inputLen << 3))
|
||||
|
||||
< ((uint32_t)inputLen << 3))
|
||||
context->count[1]++;
|
||||
context->count[1] += ((uint32_t)inputLen >> 29);
|
||||
< ((uint32_t) inputLen << 3))
|
||||
context->count[1]++;
|
||||
context->count[1] += ((uint32_t) inputLen >> 29);
|
||||
|
||||
partLen = 64 - index;
|
||||
|
||||
/* Transform as many times as possible.
|
||||
*/
|
||||
*/
|
||||
if (inputLen >= partLen) {
|
||||
MD5_memcpy
|
||||
((uint8_t *)&context->buffer[index], (uint8_t *)input, partLen);
|
||||
MD5Transform (context->state, context->buffer);
|
||||
MD5_memcpy((uint8_t *) &context->buffer[index], (uint8_t *) input, partLen);
|
||||
MD5Transform(context->state, context->buffer);
|
||||
|
||||
for (i = partLen; i + 63 < inputLen; i += 64)
|
||||
MD5Transform (context->state, &input[i]);
|
||||
for (i = partLen; i + 63 < inputLen; i += 64)
|
||||
MD5Transform(context->state, &input[i]);
|
||||
|
||||
index = 0;
|
||||
}
|
||||
else
|
||||
i = 0;
|
||||
index = 0;
|
||||
} else
|
||||
i = 0;
|
||||
|
||||
/* Buffer remaining input */
|
||||
MD5_memcpy
|
||||
((uint8_t *)&context->buffer[index], (uint8_t *)&input[i],
|
||||
inputLen-i);
|
||||
MD5_memcpy(
|
||||
(uint8_t *) &context->buffer[index], (uint8_t *) &input[i], inputLen - i);
|
||||
}
|
||||
|
||||
/* MD5 finalization. Ends an MD5 message-digest operation, writing the
|
||||
the message digest and zeroizing the context.
|
||||
*/
|
||||
void MD5Final (digest, context)
|
||||
unsigned char digest[16]; /* message digest */
|
||||
MD5_CTX *context; /* context */
|
||||
void MD5Final(digest, context) unsigned char digest[16]; /* message digest */
|
||||
MD5_CTX *context; /* context */
|
||||
{
|
||||
unsigned char bits[8];
|
||||
unsigned int index, padLen;
|
||||
|
||||
/* Save number of bits */
|
||||
Encode (bits, context->count, 8);
|
||||
Encode(bits, context->count, 8);
|
||||
|
||||
/* Pad out to 56 mod 64.
|
||||
*/
|
||||
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
|
||||
*/
|
||||
index = (unsigned int) ((context->count[0] >> 3) & 0x3f);
|
||||
padLen = (index < 56) ? (56 - index) : (120 - index);
|
||||
MD5Update (context, PADDING, padLen);
|
||||
MD5Update(context, PADDING, padLen);
|
||||
|
||||
/* Append length (before padding) */
|
||||
MD5Update (context, bits, 8);
|
||||
MD5Update(context, bits, 8);
|
||||
|
||||
/* Store state in digest */
|
||||
Encode (digest, context->state, 16);
|
||||
Encode(digest, context->state, 16);
|
||||
|
||||
/* Zeroize sensitive information.
|
||||
*/
|
||||
MD5_memset ((uint8_t *)context, 0, sizeof (*context));
|
||||
*/
|
||||
MD5_memset((uint8_t *) context, 0, sizeof(*context));
|
||||
}
|
||||
|
||||
/* MD5 basic transformation. Transforms state based on block.
|
||||
*/
|
||||
static void MD5Transform (state, block)
|
||||
uint32_t state[4];
|
||||
static void MD5Transform(state, block) uint32_t state[4];
|
||||
unsigned char block[64];
|
||||
{
|
||||
uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
|
||||
|
||||
Decode (x, block, 64);
|
||||
Decode(x, block, 64);
|
||||
|
||||
/* Round 1 */
|
||||
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
|
||||
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
|
||||
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
|
||||
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
|
||||
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
|
||||
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
|
||||
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
|
||||
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
|
||||
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
|
||||
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
|
||||
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
|
||||
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
|
||||
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
|
||||
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
|
||||
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
|
||||
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
|
||||
FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
|
||||
FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
|
||||
FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
|
||||
FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
|
||||
FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
|
||||
FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
|
||||
FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
|
||||
FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
|
||||
FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
|
||||
FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
|
||||
FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
|
||||
FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
|
||||
FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
|
||||
FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
|
||||
FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
|
||||
FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
|
||||
|
||||
/* Round 2 */
|
||||
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
|
||||
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
|
||||
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
|
||||
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
|
||||
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
|
||||
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
|
||||
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
|
||||
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
|
||||
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
|
||||
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
|
||||
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
|
||||
/* Round 2 */
|
||||
GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
|
||||
GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
|
||||
GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
|
||||
GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
|
||||
GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
|
||||
GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
|
||||
GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
|
||||
GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
|
||||
GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
|
||||
GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
|
||||
GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
|
||||
|
||||
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
|
||||
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
|
||||
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
|
||||
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
|
||||
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
|
||||
GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
|
||||
GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
|
||||
GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
|
||||
GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
|
||||
GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
|
||||
|
||||
/* Round 3 */
|
||||
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
|
||||
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
|
||||
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
|
||||
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
|
||||
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
|
||||
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
|
||||
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
|
||||
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
|
||||
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
|
||||
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
|
||||
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
|
||||
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
|
||||
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
|
||||
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
|
||||
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
|
||||
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
|
||||
HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
|
||||
HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
|
||||
HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
|
||||
HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
|
||||
HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
|
||||
HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
|
||||
HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
|
||||
HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
|
||||
HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
|
||||
HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
|
||||
HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
|
||||
HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
|
||||
HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
|
||||
HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
|
||||
HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
|
||||
HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
|
||||
|
||||
/* Round 4 */
|
||||
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
|
||||
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
|
||||
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
|
||||
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
|
||||
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
|
||||
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
|
||||
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
|
||||
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
|
||||
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
|
||||
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
|
||||
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
|
||||
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
|
||||
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
|
||||
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
|
||||
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
|
||||
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
|
||||
II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
|
||||
II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
|
||||
II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
|
||||
II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
|
||||
II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
|
||||
II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
|
||||
II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
|
||||
II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
|
||||
II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
|
||||
II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
|
||||
II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
|
||||
II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
|
||||
II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
|
||||
II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
|
||||
II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
|
||||
II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
|
||||
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
@@ -268,66 +264,62 @@ unsigned char block[64];
|
||||
/* Zeroize sensitive information.
|
||||
|
||||
*/
|
||||
MD5_memset ((uint8_t *)x, 0, sizeof (x));
|
||||
MD5_memset((uint8_t *) x, 0, sizeof(x));
|
||||
}
|
||||
|
||||
/* Encodes input (uint32_t) into output (unsigned char). Assumes len is
|
||||
a multiple of 4.
|
||||
*/
|
||||
static void Encode (output, input, len)
|
||||
unsigned char *output;
|
||||
static void Encode(output, input, len) unsigned char *output;
|
||||
uint32_t *input;
|
||||
unsigned int len;
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4) {
|
||||
output[j] = (unsigned char)(input[i] & 0xff);
|
||||
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
|
||||
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
|
||||
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
|
||||
output[j] = (unsigned char) (input[i] & 0xff);
|
||||
output[j + 1] = (unsigned char) ((input[i] >> 8) & 0xff);
|
||||
output[j + 2] = (unsigned char) ((input[i] >> 16) & 0xff);
|
||||
output[j + 3] = (unsigned char) ((input[i] >> 24) & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
/* Decodes input (unsigned char) into output (uint32_t). Assumes len is
|
||||
a multiple of 4.
|
||||
*/
|
||||
static void Decode (output, input, len)
|
||||
uint32_t *output;
|
||||
static void Decode(output, input, len) uint32_t *output;
|
||||
unsigned char *input;
|
||||
unsigned int len;
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4)
|
||||
output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j+1]) << 8) |
|
||||
(((uint32_t)input[j+2]) << 16) | (((uint32_t)input[j+3]) << 24);
|
||||
output[i] = ((uint32_t) input[j]) | (((uint32_t) input[j + 1]) << 8) |
|
||||
(((uint32_t) input[j + 2]) << 16) | (((uint32_t) input[j + 3]) << 24);
|
||||
}
|
||||
|
||||
/* Note: Replace "for loop" with standard memcpy if possible.
|
||||
*/
|
||||
|
||||
static void MD5_memcpy (output, input, len)
|
||||
uint8_t * output;
|
||||
uint8_t * input;
|
||||
static void MD5_memcpy(output, input, len) uint8_t *output;
|
||||
uint8_t *input;
|
||||
unsigned int len;
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
|
||||
output[i] = input[i];
|
||||
output[i] = input[i];
|
||||
}
|
||||
|
||||
/* Note: Replace "for loop" with standard memset if possible.
|
||||
*/
|
||||
static void MD5_memset (output, value, len)
|
||||
uint8_t * output;
|
||||
static void MD5_memset(output, value, len) uint8_t *output;
|
||||
int value;
|
||||
unsigned int len;
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
((char *)output)[i] = (char)value;
|
||||
((char *) output)[i] = (char) value;
|
||||
}
|
||||
@@ -24,12 +24,11 @@ documentation and/or software.
|
||||
|
||||
/* MD5 context. */
|
||||
typedef struct {
|
||||
uint32_t state[4]; /* state (ABCD) */
|
||||
uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */
|
||||
unsigned char buffer[64]; /* input buffer */
|
||||
uint32_t state[4]; /* state (ABCD) */
|
||||
uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */
|
||||
unsigned char buffer[64]; /* input buffer */
|
||||
} MD5_CTX;
|
||||
|
||||
void MD5Init(MD5_CTX *);
|
||||
void MD5Update(MD5_CTX *, unsigned char *, unsigned int);
|
||||
void MD5Final(unsigned char [16], MD5_CTX *);
|
||||
|
||||
void MD5Final(unsigned char[16], MD5_CTX *);
|
||||
|
||||
+974
-1102
File diff suppressed because it is too large
Load Diff
@@ -1,17 +1,23 @@
|
||||
#ifndef H__RIJNDAEL
|
||||
#define H__RIJNDAEL
|
||||
|
||||
int rijndaelSetupEncrypt(unsigned long *rk, const unsigned char *key,
|
||||
int keybits);
|
||||
int rijndaelSetupDecrypt(unsigned long *rk, const unsigned char *key,
|
||||
int keybits);
|
||||
void rijndaelEncrypt(const unsigned long *rk, int nrounds,
|
||||
const unsigned char plaintext[16], unsigned char ciphertext[16]);
|
||||
void rijndaelDecrypt(const unsigned long *rk, int nrounds,
|
||||
const unsigned char ciphertext[16], unsigned char plaintext[16]);
|
||||
int rijndaelSetupEncrypt(
|
||||
unsigned long *rk, const unsigned char *key, int keybits);
|
||||
int rijndaelSetupDecrypt(
|
||||
unsigned long *rk, const unsigned char *key, int keybits);
|
||||
void rijndaelEncrypt(
|
||||
const unsigned long *rk,
|
||||
int nrounds,
|
||||
const unsigned char plaintext[16],
|
||||
unsigned char ciphertext[16]);
|
||||
void rijndaelDecrypt(
|
||||
const unsigned long *rk,
|
||||
int nrounds,
|
||||
const unsigned char ciphertext[16],
|
||||
unsigned char plaintext[16]);
|
||||
|
||||
#define KEYLENGTH(keybits) ((keybits)/8)
|
||||
#define RKLENGTH(keybits) ((keybits)/8+28)
|
||||
#define NROUNDS(keybits) ((keybits)/32+6)
|
||||
#define KEYLENGTH(keybits) ((keybits) / 8)
|
||||
#define RKLENGTH(keybits) ((keybits) / 8 + 28)
|
||||
#define NROUNDS(keybits) ((keybits) / 32 + 6)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
|
||||
#include "md5.h"
|
||||
|
||||
void crypt_md5_hash(uint8_t* out, const uint8_t* in, size_t nbytes)
|
||||
void crypt_md5_hash(uint8_t *out, const uint8_t *in, size_t nbytes)
|
||||
{
|
||||
MD5_CTX ctx;
|
||||
MD5_CTX ctx;
|
||||
|
||||
MD5Init(&ctx);
|
||||
MD5Update(&ctx, (unsigned char*) in, (unsigned int) nbytes);
|
||||
MD5Final(out, &ctx);
|
||||
MD5Init(&ctx);
|
||||
MD5Update(&ctx, (unsigned char *) in, (unsigned int) nbytes);
|
||||
MD5Final(out, &ctx);
|
||||
}
|
||||
@@ -11,6 +11,6 @@
|
||||
* @param in Input buffer to hash
|
||||
* @param nbytes Number of bytes of input buffer to process
|
||||
*/
|
||||
void crypt_md5_hash(uint8_t* out, const uint8_t* in, size_t nbytes);
|
||||
void crypt_md5_hash(uint8_t *out, const uint8_t *in, size_t nbytes);
|
||||
|
||||
#endif
|
||||
@@ -27,24 +27,25 @@ const struct util_options_defs hook_core_options_defs = {
|
||||
// Just use something because this is not relevant/required here
|
||||
.usage_param = '\r',
|
||||
.defs = hook_core_options_def,
|
||||
.ndefs = lengthof(hook_core_options_def)
|
||||
};
|
||||
.ndefs = lengthof(hook_core_options_def)};
|
||||
|
||||
void hook_core_options_init(int argc, char** argv, struct hook_core_options* options)
|
||||
void hook_core_options_init(
|
||||
int argc, char **argv, struct hook_core_options *options)
|
||||
{
|
||||
log_assert(argv);
|
||||
log_assert(options);
|
||||
log_assert(argv);
|
||||
log_assert(options);
|
||||
|
||||
struct util_options_opts* options_opt;
|
||||
struct util_options_opts *options_opt;
|
||||
|
||||
util_options_init(argc, argv);
|
||||
options_opt = util_options_get(&hook_core_options_defs);
|
||||
util_options_init(argc, argv);
|
||||
options_opt = util_options_get(&hook_core_options_defs);
|
||||
|
||||
if (!options_opt) {
|
||||
return;
|
||||
}
|
||||
if (!options_opt) {
|
||||
return;
|
||||
}
|
||||
|
||||
options->log.file = util_options_get_str(options_opt, HOOK_CORE_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
|
||||
options->log.level =
|
||||
(enum util_log_level) util_options_get_int(options_opt, HOOK_CORE_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
|
||||
options->log.file = util_options_get_str(
|
||||
options_opt, HOOK_CORE_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
|
||||
options->log.level = (enum util_log_level) util_options_get_int(
|
||||
options_opt, HOOK_CORE_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
|
||||
}
|
||||
@@ -4,12 +4,13 @@
|
||||
#include "util/log.h"
|
||||
|
||||
struct hook_core_options {
|
||||
struct log {
|
||||
const char* file;
|
||||
enum util_log_level level;
|
||||
} log;
|
||||
struct log {
|
||||
const char *file;
|
||||
enum util_log_level level;
|
||||
} log;
|
||||
};
|
||||
|
||||
void hook_core_options_init(int argc, char** argv, struct hook_core_options* options);
|
||||
void hook_core_options_init(
|
||||
int argc, char **argv, struct hook_core_options *options);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -13,121 +13,131 @@
|
||||
#include "util/str.h"
|
||||
#include "util/sys-info.h"
|
||||
|
||||
static void hook_core_piu_log_application_args(int argc, char** argv)
|
||||
static void hook_core_piu_log_application_args(int argc, char **argv)
|
||||
{
|
||||
const char* sep = "\n";
|
||||
char* str = util_str_dup("");
|
||||
char* tmp;
|
||||
const char *sep = "\n";
|
||||
char *str = util_str_dup("");
|
||||
char *tmp;
|
||||
|
||||
for (int i = 0; i < argc; i++) {
|
||||
if (strlen(str) > 0) {
|
||||
tmp = util_str_merge(str, sep);
|
||||
free(str);
|
||||
str = tmp;
|
||||
}
|
||||
|
||||
tmp = util_str_merge(str, argv[i]);
|
||||
free(str);
|
||||
str = tmp;
|
||||
for (int i = 0; i < argc; i++) {
|
||||
if (strlen(str) > 0) {
|
||||
tmp = util_str_merge(str, sep);
|
||||
free(str);
|
||||
str = tmp;
|
||||
}
|
||||
|
||||
log_info("Application arguments (%d):\n%s", argc, str);
|
||||
tmp = util_str_merge(str, argv[i]);
|
||||
free(str);
|
||||
str = tmp;
|
||||
}
|
||||
|
||||
log_info("Application arguments (%d):\n%s", argc, str);
|
||||
free(str);
|
||||
}
|
||||
|
||||
void hook_core_piu_log_init(int argc, char** argv)
|
||||
void hook_core_piu_log_init(int argc, char **argv)
|
||||
{
|
||||
struct hook_core_options options;
|
||||
struct hook_core_options options;
|
||||
|
||||
hook_core_options_init(argc, argv, &options);
|
||||
hook_core_options_init(argc, argv, &options);
|
||||
|
||||
util_log_set_file(options.log.file, false);
|
||||
util_log_set_level(options.log.level);
|
||||
util_log_set_file(options.log.file, false);
|
||||
util_log_set_level(options.log.level);
|
||||
}
|
||||
|
||||
void hook_core_piu_log_info(int argc, char** argv)
|
||||
void hook_core_piu_log_info(int argc, char **argv)
|
||||
{
|
||||
log_info("\n"
|
||||
" _ _ \n"
|
||||
" _ __ _ _ _ __ ___ _ __ | |_ ___ ___ | |___ \n"
|
||||
" | '_ \\| | | | '_ ` _ \\| '_ \\| __/ _ \\ / _ \\| / __|\n"
|
||||
" | |_) | |_| | | | | | | |_) | || (_) | (_) | \\__ \\\n"
|
||||
" | .__/ \\__,_|_| |_| |_| .__/ \\__\\___/ \\___/|_|___/\n"
|
||||
" |_| |_| ");
|
||||
log_info(
|
||||
"\n"
|
||||
" _ _ \n"
|
||||
" _ __ _ _ _ __ ___ _ __ | |_ ___ ___ | |___ \n"
|
||||
" | '_ \\| | | | '_ ` _ \\| '_ \\| __/ _ \\ / _ \\| / __|\n"
|
||||
" | |_) | |_| | | | | | | |_) | || (_) | (_) | \\__ \\\n"
|
||||
" | .__/ \\__,_|_| |_| |_| .__/ \\__\\___/ \\___/|_|___/\n"
|
||||
" |_| |_| ");
|
||||
|
||||
log_info("Pumptools build " __DATE__ " " __TIME__ " gitrev %s", STRINGIFY(GITREV));
|
||||
log_info(
|
||||
"Pumptools build " __DATE__ " " __TIME__ " gitrev %s", STRINGIFY(GITREV));
|
||||
|
||||
util_sys_info_log();
|
||||
util_proc_log_info();
|
||||
util_glibc_info_log();
|
||||
hook_core_piu_log_application_args(argc, argv);
|
||||
util_sys_info_log();
|
||||
util_proc_log_info();
|
||||
util_glibc_info_log();
|
||||
hook_core_piu_log_application_args(argc, argv);
|
||||
}
|
||||
|
||||
char* hook_core_piu_utils_get_and_verify_game_data_path(int argc, char** argv)
|
||||
char *hook_core_piu_utils_get_and_verify_game_data_path(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
log_error("Missing game data path, usage for piu (stock args): piu <game folder> (e.g. piu ./game)");
|
||||
exit(0);
|
||||
}
|
||||
if (argc < 2) {
|
||||
log_error(
|
||||
"Missing game data path, usage for piu (stock args): piu <game folder> "
|
||||
"(e.g. piu ./game)");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
char* game_data_path = util_str_dup(argv[1]);
|
||||
char *game_data_path = util_str_dup(argv[1]);
|
||||
|
||||
log_info("Game data path: %s", game_data_path);
|
||||
log_info("Game data path: %s", game_data_path);
|
||||
|
||||
/* remove trailing / for the hook. however, the game crashes without it */
|
||||
if (util_str_ends_with(game_data_path, "/")) {
|
||||
game_data_path[strlen(game_data_path) - 1] = '\0';
|
||||
} else {
|
||||
log_error("Game data path '%s' does not end with a trailing /, exiting because the game is going to "
|
||||
"crash anyway!", game_data_path);
|
||||
exit(0);
|
||||
}
|
||||
/* remove trailing / for the hook. however, the game crashes without it */
|
||||
if (util_str_ends_with(game_data_path, "/")) {
|
||||
game_data_path[strlen(game_data_path) - 1] = '\0';
|
||||
} else {
|
||||
log_error(
|
||||
"Game data path '%s' does not end with a trailing /, exiting because "
|
||||
"the game is going to "
|
||||
"crash anyway!",
|
||||
game_data_path);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* depending on the version, the game also just crashes if the game folder or files within it were not found */
|
||||
if (!util_fs_path_exists(game_data_path)) {
|
||||
log_error("Game data path '%s' does not exist, exiting", game_data_path);
|
||||
exit(0);
|
||||
}
|
||||
/* depending on the version, the game also just crashes if the game folder or
|
||||
* files within it were not found */
|
||||
if (!util_fs_path_exists(game_data_path)) {
|
||||
log_error("Game data path '%s' does not exist, exiting", game_data_path);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
return game_data_path;
|
||||
return game_data_path;
|
||||
}
|
||||
|
||||
void hook_core_piu_utils_verify_root_user()
|
||||
{
|
||||
log_info("Verifying process is running as root user.");
|
||||
log_info("Verifying process is running as root user.");
|
||||
|
||||
if (!util_proc_is_running_as_root()) {
|
||||
log_error("Process not running as root which is required for the game to work correctly.");
|
||||
//exit(0);
|
||||
}
|
||||
if (!util_proc_is_running_as_root()) {
|
||||
log_error(
|
||||
"Process not running as root which is required for the game to work "
|
||||
"correctly.");
|
||||
// exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
void hook_core_piu_utils_fix_locale()
|
||||
{
|
||||
log_info("Fixing locale settings.");
|
||||
log_info("Fixing locale settings.");
|
||||
|
||||
if (setenv("LC_ALL", "C", 1) != 0) {
|
||||
log_warn("Setting locale LC_ALL failed.");
|
||||
}
|
||||
if (setenv("LC_ALL", "C", 1) != 0) {
|
||||
log_warn("Setting locale LC_ALL failed.");
|
||||
}
|
||||
|
||||
if (unsetenv("LANGUAGE") != 0) {
|
||||
log_warn("Unsetting LANGUAGE env var failed.");
|
||||
}
|
||||
if (unsetenv("LANGUAGE") != 0) {
|
||||
log_warn("Unsetting LANGUAGE env var failed.");
|
||||
}
|
||||
}
|
||||
|
||||
bool hook_core_piu_block_non_piu_process_recursion(int argc, char** argv)
|
||||
bool hook_core_piu_block_non_piu_process_recursion(int argc, char **argv)
|
||||
{
|
||||
/* Sanity check for arguments. If further child processes are started
|
||||
from the current process, and using LD_PRELOAD on the current process,
|
||||
all children are also getting the preloaded library. This causes
|
||||
multiple calls to the trap main function and just crashes our
|
||||
application at some point.
|
||||
The executable file is required to contain the "piu" substring to make
|
||||
this work properly */
|
||||
if (!strstr(argv[0], "piu")) {
|
||||
log_warn("Not attaching to non piu process %s", argv[0]);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
/* Sanity check for arguments. If further child processes are started
|
||||
from the current process, and using LD_PRELOAD on the current process,
|
||||
all children are also getting the preloaded library. This causes
|
||||
multiple calls to the trap main function and just crashes our
|
||||
application at some point.
|
||||
The executable file is required to contain the "piu" substring to make
|
||||
this work properly */
|
||||
if (!strstr(argv[0], "piu")) {
|
||||
log_warn("Not attaching to non piu process %s", argv[0]);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,15 @@
|
||||
#define HOOK_CORE_PIU_UTILS_H
|
||||
|
||||
/**
|
||||
* Initialize the logging system as early as possible to allow recording everything to a log file as well.
|
||||
* Initialize the logging system as early as possible to allow recording
|
||||
* everything to a log file as well.
|
||||
*/
|
||||
void hook_core_piu_log_init(int argc, char** argv);
|
||||
void hook_core_piu_log_init(int argc, char **argv);
|
||||
|
||||
/**
|
||||
* Log process and system relevant information.
|
||||
*/
|
||||
void hook_core_piu_log_info(int argc, char** argv);
|
||||
void hook_core_piu_log_info(int argc, char **argv);
|
||||
|
||||
/**
|
||||
* Check and verify the game data path argument passed to the game via argv
|
||||
@@ -19,9 +20,10 @@ void hook_core_piu_log_info(int argc, char** argv);
|
||||
*
|
||||
* @param argc Argc from piu main
|
||||
* @param argv Argv from piu main
|
||||
* @return New string with game data path extracted from argv (caller has to free)
|
||||
* @return New string with game data path extracted from argv (caller has to
|
||||
* free)
|
||||
*/
|
||||
char* hook_core_piu_utils_get_and_verify_game_data_path(int argc, char** argv);
|
||||
char *hook_core_piu_utils_get_and_verify_game_data_path(int argc, char **argv);
|
||||
|
||||
/**
|
||||
* Verify that the current process is running as root user because the game
|
||||
@@ -38,16 +40,16 @@ void hook_core_piu_utils_fix_locale();
|
||||
|
||||
/**
|
||||
* If further child processes are started from the current process, and using
|
||||
* LD_PRELOAD on the current process, all children are also getting the preloaded
|
||||
* library. This causes multiple calls to the trap main function and just crashes our
|
||||
* application at some point. The executable file is required to contain the "piu"
|
||||
* substring to make this work properly.
|
||||
* LD_PRELOAD on the current process, all children are also getting the
|
||||
* preloaded library. This causes multiple calls to the trap main function and
|
||||
* just crashes our application at some point. The executable file is required
|
||||
* to contain the "piu" substring to make this work properly.
|
||||
*
|
||||
* @param argc Argc from piu main
|
||||
* @param argv Argv from piu main
|
||||
* @return True if we have to block this call by another process,
|
||||
* false if the process calling this is the piu process.
|
||||
*/
|
||||
bool hook_core_piu_block_non_piu_process_recursion(int argc, char** argv);
|
||||
bool hook_core_piu_block_non_piu_process_recursion(int argc, char **argv);
|
||||
|
||||
#endif
|
||||
|
||||
+74
-62
@@ -10,89 +10,101 @@
|
||||
#include "util/log.h"
|
||||
#include "util/patch.h"
|
||||
|
||||
static int32_t exchook_eeprom_read(uint8_t* buffer, int32_t len);
|
||||
static int32_t exchook_eeprom_write(const uint8_t* buffer, int32_t len);
|
||||
static int32_t exchook_eeprom_read(uint8_t *buffer, int32_t len);
|
||||
static int32_t exchook_eeprom_write(const uint8_t *buffer, int32_t len);
|
||||
|
||||
static char* exchook_eeprom_file;
|
||||
static char *exchook_eeprom_file;
|
||||
static uint8_t exchook_eeprom_buffer[8192];
|
||||
|
||||
void exchook_eeprom_init(const struct exchook_mempatch_table* patch_table, const char* eeprom_file)
|
||||
void exchook_eeprom_init(
|
||||
const struct exchook_mempatch_table *patch_table, const char *eeprom_file)
|
||||
{
|
||||
void* buffer;
|
||||
size_t len;
|
||||
void *buffer;
|
||||
size_t len;
|
||||
|
||||
exchook_eeprom_file = util_fs_get_abs_path(eeprom_file);
|
||||
|
||||
/* EEPROM file does not exist, create new */
|
||||
if (!exchook_eeprom_file) {
|
||||
memset(exchook_eeprom_buffer, 0xFF, sizeof(exchook_eeprom_buffer));
|
||||
|
||||
FILE *file = fopen(eeprom_file, "wb+");
|
||||
|
||||
if (file == NULL) {
|
||||
log_error(
|
||||
"Creating new eeprom file %s failed: %s",
|
||||
eeprom_file,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
fwrite(exchook_eeprom_buffer, sizeof(exchook_eeprom_buffer), 1, file);
|
||||
fclose(file);
|
||||
|
||||
exchook_eeprom_file = util_fs_get_abs_path(eeprom_file);
|
||||
len = (size_t) -1;
|
||||
} else {
|
||||
if (util_file_load(exchook_eeprom_file, &buffer, &len, false)) {
|
||||
if (len > sizeof(exchook_eeprom_buffer)) {
|
||||
log_error(
|
||||
"Contents of %s eeprom file exceed the max eeprom buffer "
|
||||
" size of %d bytes",
|
||||
eeprom_file,
|
||||
sizeof(exchook_eeprom_buffer));
|
||||
free(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
/* EEPROM file does not exist, create new */
|
||||
if (!exchook_eeprom_file) {
|
||||
memset(exchook_eeprom_buffer, 0xFF, sizeof(exchook_eeprom_buffer));
|
||||
|
||||
FILE* file = fopen(eeprom_file, "wb+");
|
||||
|
||||
if (file == NULL) {
|
||||
log_error("Creating new eeprom file %s failed: %s", eeprom_file, strerror(errno));
|
||||
}
|
||||
|
||||
fwrite(exchook_eeprom_buffer, sizeof(exchook_eeprom_buffer), 1, file);
|
||||
fclose(file);
|
||||
|
||||
exchook_eeprom_file = util_fs_get_abs_path(eeprom_file);
|
||||
len = (size_t) -1;
|
||||
/* copy read contents */
|
||||
memcpy(exchook_eeprom_buffer, buffer, len);
|
||||
free(buffer);
|
||||
} else {
|
||||
if (util_file_load(exchook_eeprom_file, &buffer, &len, false)) {
|
||||
if (len > sizeof(exchook_eeprom_buffer)) {
|
||||
log_error("Contents of %s eeprom file exceed the max eeprom buffer "
|
||||
" size of %d bytes", eeprom_file,
|
||||
sizeof(exchook_eeprom_buffer));
|
||||
free(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
/* copy read contents */
|
||||
memcpy(exchook_eeprom_buffer, buffer, len);
|
||||
free(buffer);
|
||||
} else {
|
||||
log_error("Loading eeprom file %s failed", exchook_eeprom_file);
|
||||
}
|
||||
log_error("Loading eeprom file %s failed", exchook_eeprom_file);
|
||||
}
|
||||
}
|
||||
|
||||
log_assert(exchook_eeprom_file);
|
||||
log_assert(exchook_eeprom_file);
|
||||
|
||||
/* Hook eeprom */
|
||||
util_patch_function(patch_table->addr_eeprom_read, exchook_eeprom_read);
|
||||
util_patch_function(patch_table->addr_eeprom_write, exchook_eeprom_write);
|
||||
/* Hook eeprom */
|
||||
util_patch_function(patch_table->addr_eeprom_read, exchook_eeprom_read);
|
||||
util_patch_function(patch_table->addr_eeprom_write, exchook_eeprom_write);
|
||||
|
||||
log_info("Initizlied (%s), eeprom file %s", len == -1 ? "new" : "loaded", eeprom_file);
|
||||
log_info(
|
||||
"Initizlied (%s), eeprom file %s",
|
||||
len == -1 ? "new" : "loaded",
|
||||
eeprom_file);
|
||||
}
|
||||
|
||||
static int32_t exchook_eeprom_read(uint8_t* buffer, int32_t len)
|
||||
static int32_t exchook_eeprom_read(uint8_t *buffer, int32_t len)
|
||||
{
|
||||
if (len > sizeof(exchook_eeprom_buffer)) {
|
||||
log_error("Eeprom read %d exceeds buffer size %d", len,
|
||||
sizeof(exchook_eeprom_buffer));
|
||||
return 0;
|
||||
}
|
||||
if (len > sizeof(exchook_eeprom_buffer)) {
|
||||
log_error(
|
||||
"Eeprom read %d exceeds buffer size %d",
|
||||
len,
|
||||
sizeof(exchook_eeprom_buffer));
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(buffer, exchook_eeprom_buffer, len);
|
||||
memcpy(buffer, exchook_eeprom_buffer, len);
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
|
||||
static int32_t exchook_eeprom_write(const uint8_t* buffer, int32_t len)
|
||||
static int32_t exchook_eeprom_write(const uint8_t *buffer, int32_t len)
|
||||
{
|
||||
if (len > sizeof(exchook_eeprom_buffer)) {
|
||||
log_error("Eeprom write %d exceeds buffer size %d", len,
|
||||
sizeof(exchook_eeprom_buffer));
|
||||
return 0;
|
||||
}
|
||||
if (len > sizeof(exchook_eeprom_buffer)) {
|
||||
log_error(
|
||||
"Eeprom write %d exceeds buffer size %d",
|
||||
len,
|
||||
sizeof(exchook_eeprom_buffer));
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(exchook_eeprom_buffer, buffer, len);
|
||||
memcpy(exchook_eeprom_buffer, buffer, len);
|
||||
|
||||
/* Write back to file */
|
||||
if (!util_file_save(exchook_eeprom_file, exchook_eeprom_buffer, len)) {
|
||||
log_error("Storing eeprom contents to file %s failed",
|
||||
exchook_eeprom_file);
|
||||
}
|
||||
/* Write back to file */
|
||||
if (!util_file_save(exchook_eeprom_file, exchook_eeprom_buffer, len)) {
|
||||
log_error("Storing eeprom contents to file %s failed", exchook_eeprom_file);
|
||||
}
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
@@ -14,6 +14,7 @@
|
||||
* @param eeprom_file Path to existing eeprom file to read from and new eeprom
|
||||
* file to store to
|
||||
*/
|
||||
void exchook_eeprom_init(const struct exchook_mempatch_table* patch_table, const char* eeprom_file);
|
||||
void exchook_eeprom_init(
|
||||
const struct exchook_mempatch_table *patch_table, const char *eeprom_file);
|
||||
|
||||
#endif
|
||||
+413
-405
@@ -11,54 +11,53 @@
|
||||
#include "util/patch.h"
|
||||
|
||||
/* Taken from ioarcade.hpp nx2 src dump */
|
||||
#define GI_P1_1 0x00000001
|
||||
#define GI_P1_3 0x00000002
|
||||
#define GI_P1_5 0x00000004
|
||||
#define GI_P1_7 0x00000008
|
||||
#define GI_P1_9 0x00000010
|
||||
#define GI_P1_1 0x00000001
|
||||
#define GI_P1_3 0x00000002
|
||||
#define GI_P1_5 0x00000004
|
||||
#define GI_P1_7 0x00000008
|
||||
#define GI_P1_9 0x00000010
|
||||
|
||||
#define GI_P2_1 0x00000100
|
||||
#define GI_P2_3 0x00000200
|
||||
#define GI_P2_5 0x00000400
|
||||
#define GI_P2_7 0x00000800
|
||||
#define GI_P2_9 0x00001000
|
||||
#define GI_P2_1 0x00000100
|
||||
#define GI_P2_3 0x00000200
|
||||
#define GI_P2_5 0x00000400
|
||||
#define GI_P2_7 0x00000800
|
||||
#define GI_P2_9 0x00001000
|
||||
|
||||
#define GI_TEST 0x00010000
|
||||
#define GI_SERVICE 0x00020000
|
||||
#define GI_CLEAR 0x00040000
|
||||
#define GI_TEST 0x00010000
|
||||
#define GI_SERVICE 0x00020000
|
||||
#define GI_CLEAR 0x00040000
|
||||
|
||||
#define GI_COIN 0x00100000
|
||||
#define GI_COIN2 0x00200000
|
||||
#define GI_COIN 0x00100000
|
||||
#define GI_COIN2 0x00200000
|
||||
|
||||
struct exchook_io_sensores {
|
||||
uint32_t lu : 4;
|
||||
uint32_t ru : 4;
|
||||
uint32_t cn : 4;
|
||||
uint32_t ld : 4;
|
||||
uint32_t rd : 4;
|
||||
uint32_t padding : 12;
|
||||
uint32_t lu : 4;
|
||||
uint32_t ru : 4;
|
||||
uint32_t cn : 4;
|
||||
uint32_t ld : 4;
|
||||
uint32_t rd : 4;
|
||||
uint32_t padding : 12;
|
||||
};
|
||||
|
||||
static const uint8_t exchook_io_sensor_mappings[] = {
|
||||
1, 2, 3, 0
|
||||
};
|
||||
static const uint8_t exchook_io_sensor_mappings[] = {1, 2, 3, 0};
|
||||
|
||||
static struct ptapi_io_piuio_api exchook_piuio_api;
|
||||
|
||||
static uint16_t exchook_io_check(void* obj);
|
||||
static int32_t exchook_io_light_all(void* obj, uint8_t on);
|
||||
static int32_t exchook_io_light_neon(void* obj, uint8_t on);
|
||||
static int32_t exchook_io_light_halogan(void* obj, uint8_t on, uint16_t light_id);
|
||||
static int32_t exchook_io_light_p1_ccfl(void* obj, uint8_t on, uint16_t cmd);
|
||||
static int32_t exchook_io_light_p2_ccfl(void* obj, uint8_t on, uint16_t cmd);
|
||||
static int32_t exchook_io_input(void* obj);
|
||||
static int32_t exchook_io_coin_input(void* obj);
|
||||
static int32_t exchook_io_coin_input_2(void* obj);
|
||||
static int32_t exchook_io_coin_counter_2(void* obj);
|
||||
static uint16_t exchook_io_check(void *obj);
|
||||
static int32_t exchook_io_light_all(void *obj, uint8_t on);
|
||||
static int32_t exchook_io_light_neon(void *obj, uint8_t on);
|
||||
static int32_t
|
||||
exchook_io_light_halogan(void *obj, uint8_t on, uint16_t light_id);
|
||||
static int32_t exchook_io_light_p1_ccfl(void *obj, uint8_t on, uint16_t cmd);
|
||||
static int32_t exchook_io_light_p2_ccfl(void *obj, uint8_t on, uint16_t cmd);
|
||||
static int32_t exchook_io_input(void *obj);
|
||||
static int32_t exchook_io_coin_input(void *obj);
|
||||
static int32_t exchook_io_coin_input_2(void *obj);
|
||||
static int32_t exchook_io_coin_counter_2(void *obj);
|
||||
|
||||
static uint32_t* exchook_io_game_input_stat;
|
||||
static uint32_t* exchook_io_game_input_down;
|
||||
static uint32_t* exchook_io_game_input_up;
|
||||
static uint32_t *exchook_io_game_input_stat;
|
||||
static uint32_t *exchook_io_game_input_down;
|
||||
static uint32_t *exchook_io_game_input_up;
|
||||
|
||||
static uint32_t exchook_io_game_input_stat_prev;
|
||||
|
||||
@@ -72,434 +71,443 @@ static struct ptapi_io_piuio_cab_outputs exchook_io_out_cab;
|
||||
|
||||
static bool exchook_io_exit_on_service_test;
|
||||
|
||||
void exchook_io_init(const struct exchook_mempatch_table* patch_table, const char* piuio_lib_path,
|
||||
bool exit_on_service_test)
|
||||
void exchook_io_init(
|
||||
const struct exchook_mempatch_table *patch_table,
|
||||
const char *piuio_lib_path,
|
||||
bool exit_on_service_test)
|
||||
{
|
||||
if (!piuio_lib_path) {
|
||||
log_error("NULL piuio (emu) lib path. Check that you have set-up and configured a piuio API implementation "
|
||||
"correctly.");
|
||||
return;
|
||||
}
|
||||
if (!piuio_lib_path) {
|
||||
log_error(
|
||||
"NULL piuio (emu) lib path. Check that you have set-up and configured "
|
||||
"a piuio API implementation "
|
||||
"correctly.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Load piuio library funcs */
|
||||
log_info("Loading piuio api implementation %s", piuio_lib_path);
|
||||
/* Load piuio library funcs */
|
||||
log_info("Loading piuio api implementation %s", piuio_lib_path);
|
||||
|
||||
if (!ptapi_io_piuio_util_lib_load(piuio_lib_path, &exchook_piuio_api)) {
|
||||
log_error("Loading piuio API from file %s failed", piuio_lib_path);
|
||||
return;
|
||||
}
|
||||
if (!ptapi_io_piuio_util_lib_load(piuio_lib_path, &exchook_piuio_api)) {
|
||||
log_error("Loading piuio API from file %s failed", piuio_lib_path);
|
||||
return;
|
||||
}
|
||||
|
||||
exchook_io_exit_on_service_test = exit_on_service_test;
|
||||
exchook_io_exit_on_service_test = exit_on_service_test;
|
||||
|
||||
log_info("Service + Test exit %d", exchook_io_exit_on_service_test);
|
||||
log_info("Service + Test exit %d", exchook_io_exit_on_service_test);
|
||||
|
||||
/* Hook MK5IO engine calls */
|
||||
/* Why so many functions you might ask? Because the MK5 IO code is a pile
|
||||
of shit created by a monkey */
|
||||
/* Hook MK5IO engine calls */
|
||||
/* Why so many functions you might ask? Because the MK5 IO code is a pile
|
||||
of shit created by a monkey */
|
||||
|
||||
util_patch_function(patch_table->addr_io_check, exchook_io_check);
|
||||
util_patch_function(patch_table->addr_io_light_all, exchook_io_light_all);
|
||||
util_patch_function(patch_table->addr_io_light_neon, exchook_io_light_neon);
|
||||
util_patch_function(patch_table->addr_io_light_halogan, exchook_io_light_halogan);
|
||||
util_patch_function(patch_table->addr_io_light_p1_ccfl, exchook_io_light_p1_ccfl);
|
||||
util_patch_function(patch_table->addr_io_light_p2_ccfl, exchook_io_light_p2_ccfl);
|
||||
util_patch_function(patch_table->addr_io_input, exchook_io_input);
|
||||
util_patch_function(patch_table->addr_io_coin_input, exchook_io_coin_input);
|
||||
util_patch_function(patch_table->addr_io_coin_input_2, exchook_io_coin_input_2);
|
||||
util_patch_function(patch_table->addr_io_coin_counter_2, exchook_io_coin_counter_2);
|
||||
util_patch_function(patch_table->addr_io_check, exchook_io_check);
|
||||
util_patch_function(patch_table->addr_io_light_all, exchook_io_light_all);
|
||||
util_patch_function(patch_table->addr_io_light_neon, exchook_io_light_neon);
|
||||
util_patch_function(
|
||||
patch_table->addr_io_light_halogan, exchook_io_light_halogan);
|
||||
util_patch_function(
|
||||
patch_table->addr_io_light_p1_ccfl, exchook_io_light_p1_ccfl);
|
||||
util_patch_function(
|
||||
patch_table->addr_io_light_p2_ccfl, exchook_io_light_p2_ccfl);
|
||||
util_patch_function(patch_table->addr_io_input, exchook_io_input);
|
||||
util_patch_function(patch_table->addr_io_coin_input, exchook_io_coin_input);
|
||||
util_patch_function(
|
||||
patch_table->addr_io_coin_input_2, exchook_io_coin_input_2);
|
||||
util_patch_function(
|
||||
patch_table->addr_io_coin_counter_2, exchook_io_coin_counter_2);
|
||||
|
||||
exchook_io_game_input_stat = ((uint32_t*) patch_table->addr_io_game_input_stat);
|
||||
exchook_io_game_input_down = ((uint32_t*) patch_table->addr_io_game_input_down);
|
||||
exchook_io_game_input_up = ((uint32_t*) patch_table->addr_io_game_input_up);
|
||||
exchook_io_game_input_stat =
|
||||
((uint32_t *) patch_table->addr_io_game_input_stat);
|
||||
exchook_io_game_input_down =
|
||||
((uint32_t *) patch_table->addr_io_game_input_down);
|
||||
exchook_io_game_input_up = ((uint32_t *) patch_table->addr_io_game_input_up);
|
||||
|
||||
/* there is an io init method but obviously requires another address to be
|
||||
hooked...just init our backend here */
|
||||
if (!exchook_piuio_api.open()) {
|
||||
log_error("Opening io failed");
|
||||
return;
|
||||
}
|
||||
/* there is an io init method but obviously requires another address to be
|
||||
hooked...just init our backend here */
|
||||
if (!exchook_piuio_api.open()) {
|
||||
log_error("Opening io failed");
|
||||
return;
|
||||
}
|
||||
|
||||
log_info("Initialized");
|
||||
log_info("Initialized");
|
||||
}
|
||||
|
||||
void exchook_io_shutdown(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/* check? why can't you just call it get_fucking_inputs... */
|
||||
static uint16_t exchook_io_check(void* obj)
|
||||
static uint16_t exchook_io_check(void *obj)
|
||||
{
|
||||
struct ptapi_io_piuio_pad_inputs p1_pad_in;
|
||||
struct ptapi_io_piuio_pad_inputs p2_pad_in;
|
||||
struct ptapi_io_piuio_pad_inputs p1_pad_in;
|
||||
struct ptapi_io_piuio_pad_inputs p2_pad_in;
|
||||
|
||||
/* Sensor states are expected to be returned using the object */
|
||||
struct exchook_io_sensores* sensores_p1 =
|
||||
(struct exchook_io_sensores*) obj;
|
||||
struct exchook_io_sensores* sensores_p2 =
|
||||
(struct exchook_io_sensores*) (((uint32_t*) obj) + 1);
|
||||
/* Sensor states are expected to be returned using the object */
|
||||
struct exchook_io_sensores *sensores_p1 = (struct exchook_io_sensores *) obj;
|
||||
struct exchook_io_sensores *sensores_p2 =
|
||||
(struct exchook_io_sensores *) (((uint32_t *) obj) + 1);
|
||||
|
||||
/* execute polling here */
|
||||
/* execute polling here */
|
||||
|
||||
/* might delay output for a frame but whatever */
|
||||
if (!exchook_piuio_api.send()) {
|
||||
log_error("Piuio send failed");
|
||||
}
|
||||
/* might delay output for a frame but whatever */
|
||||
if (!exchook_piuio_api.send()) {
|
||||
log_error("Piuio send failed");
|
||||
}
|
||||
|
||||
if (!exchook_piuio_api.recv()) {
|
||||
log_error("Piuio receive failed");
|
||||
}
|
||||
if (!exchook_piuio_api.recv()) {
|
||||
log_error("Piuio receive failed");
|
||||
}
|
||||
|
||||
/* MK5 inputs state reset */
|
||||
exchook_io_sensores_p1.lu = 0;
|
||||
exchook_io_sensores_p1.ru = 0;
|
||||
exchook_io_sensores_p1.cn = 0;
|
||||
exchook_io_sensores_p1.ld = 0;
|
||||
exchook_io_sensores_p1.rd = 0;
|
||||
/* MK5 inputs state reset */
|
||||
exchook_io_sensores_p1.lu = 0;
|
||||
exchook_io_sensores_p1.ru = 0;
|
||||
exchook_io_sensores_p1.cn = 0;
|
||||
exchook_io_sensores_p1.ld = 0;
|
||||
exchook_io_sensores_p1.rd = 0;
|
||||
|
||||
exchook_io_sensores_p2.lu = 0;
|
||||
exchook_io_sensores_p2.ru = 0;
|
||||
exchook_io_sensores_p2.cn = 0;
|
||||
exchook_io_sensores_p2.ld = 0;
|
||||
exchook_io_sensores_p2.rd = 0;
|
||||
exchook_io_sensores_p2.lu = 0;
|
||||
exchook_io_sensores_p2.ru = 0;
|
||||
exchook_io_sensores_p2.cn = 0;
|
||||
exchook_io_sensores_p2.ld = 0;
|
||||
exchook_io_sensores_p2.rd = 0;
|
||||
|
||||
// State reset
|
||||
memset(&p1_pad_in, 0, sizeof(struct ptapi_io_piuio_pad_inputs));
|
||||
memset(&p2_pad_in, 0, sizeof(struct ptapi_io_piuio_pad_inputs));
|
||||
// State reset
|
||||
memset(&p1_pad_in, 0, sizeof(struct ptapi_io_piuio_pad_inputs));
|
||||
memset(&p2_pad_in, 0, sizeof(struct ptapi_io_piuio_pad_inputs));
|
||||
|
||||
/* cycle all sensores */
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
exchook_piuio_api.get_input_pad(0, i, &p1_pad_in);
|
||||
exchook_piuio_api.get_input_pad(1, i, &p2_pad_in);
|
||||
/* cycle all sensores */
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
exchook_piuio_api.get_input_pad(0, i, &p1_pad_in);
|
||||
exchook_piuio_api.get_input_pad(1, i, &p2_pad_in);
|
||||
|
||||
/* process inputs */
|
||||
|
||||
/* Player 1 */
|
||||
if (p1_pad_in.lu) {
|
||||
exchook_io_sensores_p1.lu |= (1 << exchook_io_sensor_mappings[i]);
|
||||
}
|
||||
|
||||
if (p1_pad_in.ru) {
|
||||
exchook_io_sensores_p1.ru |= (1 << exchook_io_sensor_mappings[i]);
|
||||
}
|
||||
|
||||
if (p1_pad_in.cn) {
|
||||
exchook_io_sensores_p1.cn |= (1 << exchook_io_sensor_mappings[i]);
|
||||
}
|
||||
|
||||
if (p1_pad_in.ld) {
|
||||
exchook_io_sensores_p1.ld |= (1 << exchook_io_sensor_mappings[i]);
|
||||
}
|
||||
|
||||
if (p1_pad_in.rd) {
|
||||
exchook_io_sensores_p1.rd |= (1 << exchook_io_sensor_mappings[i]);
|
||||
}
|
||||
|
||||
/* Player 2 */
|
||||
if (p2_pad_in.lu) {
|
||||
exchook_io_sensores_p2.lu |= (1 << exchook_io_sensor_mappings[i]);
|
||||
}
|
||||
|
||||
if (p2_pad_in.ru) {
|
||||
exchook_io_sensores_p2.ru |= (1 << exchook_io_sensor_mappings[i]);
|
||||
}
|
||||
|
||||
if (p2_pad_in.cn) {
|
||||
exchook_io_sensores_p2.cn |= (1 << exchook_io_sensor_mappings[i]);
|
||||
}
|
||||
|
||||
if (p2_pad_in.ld) {
|
||||
exchook_io_sensores_p2.ld |= (1 << exchook_io_sensor_mappings[i]);
|
||||
}
|
||||
|
||||
if (p2_pad_in.rd) {
|
||||
exchook_io_sensores_p2.rd |= (1 << exchook_io_sensor_mappings[i]);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(sensores_p1, &exchook_io_sensores_p1, sizeof(exchook_io_sensores_p1));
|
||||
memcpy(sensores_p2, &exchook_io_sensores_p2, sizeof(exchook_io_sensores_p2));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t exchook_io_light_all(void* obj, uint8_t on)
|
||||
{
|
||||
if (on) {
|
||||
memset(&exchook_io_out_pad_p1, 1, sizeof(exchook_io_out_pad_p1));
|
||||
memset(&exchook_io_out_pad_p2, 1, sizeof(exchook_io_out_pad_p2));
|
||||
memset(&exchook_io_out_cab, 1, sizeof(exchook_io_out_cab));
|
||||
} else {
|
||||
memset(&exchook_io_out_pad_p1, 0, sizeof(exchook_io_out_pad_p1));
|
||||
memset(&exchook_io_out_pad_p2, 0, sizeof(exchook_io_out_pad_p2));
|
||||
memset(&exchook_io_out_cab, 0, sizeof(exchook_io_out_cab));
|
||||
}
|
||||
|
||||
exchook_piuio_api.set_output_pad(0, &exchook_io_out_pad_p1);
|
||||
exchook_piuio_api.set_output_pad(1, &exchook_io_out_pad_p2);
|
||||
exchook_piuio_api.set_output_cab(&exchook_io_out_cab);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t exchook_io_light_neon(void* obj, uint8_t on)
|
||||
{
|
||||
if (on) {
|
||||
exchook_io_out_cab.bass = true;
|
||||
} else {
|
||||
exchook_io_out_cab.bass = false;
|
||||
}
|
||||
|
||||
exchook_piuio_api.set_output_cab(&exchook_io_out_cab);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t exchook_io_light_halogan(void* obj, uint8_t on, uint16_t light_id)
|
||||
{
|
||||
if (light_id & 0x0400) {
|
||||
exchook_io_out_cab.halo_l1 = on;
|
||||
}
|
||||
|
||||
if (light_id & 0x0200) {
|
||||
exchook_io_out_cab.halo_l2 = on;
|
||||
}
|
||||
|
||||
if (light_id & 0x0100) {
|
||||
exchook_io_out_cab.halo_r1 = on;
|
||||
}
|
||||
|
||||
if (light_id & 0x0080) {
|
||||
exchook_io_out_cab.halo_r2 = on;
|
||||
}
|
||||
|
||||
exchook_piuio_api.set_output_cab(&exchook_io_out_cab);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t exchook_io_light_p1_ccfl(void* obj, uint8_t on, uint16_t cmd)
|
||||
{
|
||||
if (cmd & 0x0004) {
|
||||
exchook_io_out_pad_p1.lu = on;
|
||||
}
|
||||
|
||||
if (cmd & 0x0008) {
|
||||
exchook_io_out_pad_p1.ru = on;
|
||||
}
|
||||
|
||||
if (cmd & 0x0010) {
|
||||
exchook_io_out_pad_p1.cn = on;
|
||||
}
|
||||
|
||||
if (cmd & 0x0020) {
|
||||
exchook_io_out_pad_p1.ld = on;
|
||||
}
|
||||
|
||||
if (cmd & 0x040) {
|
||||
exchook_io_out_pad_p1.rd = on;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t exchook_io_light_p2_ccfl(void* obj, uint8_t on, uint16_t cmd)
|
||||
{
|
||||
if (cmd & 0x0004) {
|
||||
exchook_io_out_pad_p2.lu = on;
|
||||
}
|
||||
|
||||
if (cmd & 0x0008) {
|
||||
exchook_io_out_pad_p2.ru = on;
|
||||
}
|
||||
|
||||
if (cmd & 0x0010) {
|
||||
exchook_io_out_pad_p2.cn = on;
|
||||
}
|
||||
|
||||
if (cmd & 0x0020) {
|
||||
exchook_io_out_pad_p2.ld = on;
|
||||
}
|
||||
|
||||
if (cmd & 0x040) {
|
||||
exchook_io_out_pad_p2.rd = on;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t exchook_io_input(void* obj)
|
||||
{
|
||||
uint32_t stat;
|
||||
uint32_t stat_down;
|
||||
uint32_t stat_up;
|
||||
|
||||
struct ptapi_io_piuio_sys_inputs sys_in;
|
||||
|
||||
memset(&sys_in, 0, sizeof(struct ptapi_io_piuio_sys_inputs));
|
||||
|
||||
exchook_piuio_api.get_input_sys(&sys_in);
|
||||
|
||||
/* For game loaders and stuff */
|
||||
if (exchook_io_exit_on_service_test) {
|
||||
if (sys_in.test && sys_in.service) {
|
||||
log_info("Exit on service + test enabled and hit, bye");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* process final input states for the game as well as service, test, clear
|
||||
and coin which can't be handled in the check function */
|
||||
|
||||
stat = 0;
|
||||
stat_down = 0;
|
||||
stat_up = 0;
|
||||
/* process inputs */
|
||||
|
||||
/* Player 1 */
|
||||
if (exchook_io_sensores_p1.lu) {
|
||||
stat |= GI_P1_7;
|
||||
if (p1_pad_in.lu) {
|
||||
exchook_io_sensores_p1.lu |= (1 << exchook_io_sensor_mappings[i]);
|
||||
}
|
||||
|
||||
if (exchook_io_sensores_p1.ru) {
|
||||
stat |= GI_P1_9;
|
||||
if (p1_pad_in.ru) {
|
||||
exchook_io_sensores_p1.ru |= (1 << exchook_io_sensor_mappings[i]);
|
||||
}
|
||||
|
||||
if (exchook_io_sensores_p1.cn) {
|
||||
stat |= GI_P1_5;
|
||||
if (p1_pad_in.cn) {
|
||||
exchook_io_sensores_p1.cn |= (1 << exchook_io_sensor_mappings[i]);
|
||||
}
|
||||
|
||||
if (exchook_io_sensores_p1.ld) {
|
||||
stat |= GI_P1_1;
|
||||
if (p1_pad_in.ld) {
|
||||
exchook_io_sensores_p1.ld |= (1 << exchook_io_sensor_mappings[i]);
|
||||
}
|
||||
|
||||
if (exchook_io_sensores_p1.rd) {
|
||||
stat |= GI_P1_3;
|
||||
if (p1_pad_in.rd) {
|
||||
exchook_io_sensores_p1.rd |= (1 << exchook_io_sensor_mappings[i]);
|
||||
}
|
||||
|
||||
/* Player 2 */
|
||||
if (exchook_io_sensores_p2.lu) {
|
||||
stat |= GI_P2_7;
|
||||
/* Player 2 */
|
||||
if (p2_pad_in.lu) {
|
||||
exchook_io_sensores_p2.lu |= (1 << exchook_io_sensor_mappings[i]);
|
||||
}
|
||||
|
||||
if (exchook_io_sensores_p2.ru) {
|
||||
stat |= GI_P2_9;
|
||||
if (p2_pad_in.ru) {
|
||||
exchook_io_sensores_p2.ru |= (1 << exchook_io_sensor_mappings[i]);
|
||||
}
|
||||
|
||||
if (exchook_io_sensores_p2.cn) {
|
||||
stat |= GI_P2_5;
|
||||
if (p2_pad_in.cn) {
|
||||
exchook_io_sensores_p2.cn |= (1 << exchook_io_sensor_mappings[i]);
|
||||
}
|
||||
|
||||
if (exchook_io_sensores_p2.ld) {
|
||||
stat |= GI_P2_1;
|
||||
if (p2_pad_in.ld) {
|
||||
exchook_io_sensores_p2.ld |= (1 << exchook_io_sensor_mappings[i]);
|
||||
}
|
||||
|
||||
if (exchook_io_sensores_p2.rd) {
|
||||
stat |= GI_P2_3;
|
||||
if (p2_pad_in.rd) {
|
||||
exchook_io_sensores_p2.rd |= (1 << exchook_io_sensor_mappings[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sys */
|
||||
if (sys_in.test) {
|
||||
stat |= GI_TEST;
|
||||
}
|
||||
memcpy(sensores_p1, &exchook_io_sensores_p1, sizeof(exchook_io_sensores_p1));
|
||||
memcpy(sensores_p2, &exchook_io_sensores_p2, sizeof(exchook_io_sensores_p2));
|
||||
|
||||
if (sys_in.service) {
|
||||
stat |= GI_SERVICE;
|
||||
}
|
||||
|
||||
/* Taken from source but doesn't seem to work (on some versions?) */
|
||||
if (sys_in.clear) {
|
||||
stat |= GI_CLEAR;
|
||||
}
|
||||
|
||||
if (sys_in.coin) {
|
||||
stat |= GI_COIN;
|
||||
}
|
||||
|
||||
if (sys_in.coin2) {
|
||||
stat |= GI_COIN2;
|
||||
}
|
||||
|
||||
/* iterate bits for up and down events */
|
||||
for (uint8_t i = 0; i < 32; i++) {
|
||||
|
||||
if (!(exchook_io_game_input_stat_prev & (1 << i)) &&
|
||||
(stat & (1 << i))) {
|
||||
/* New push down */
|
||||
stat_down |= (1 << i);
|
||||
} else if ((exchook_io_game_input_stat_prev & (1 << i)) &&
|
||||
!(stat & (1 << i))) {
|
||||
/* New release */
|
||||
stat_up |= (1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
/* Extremely bad IO subsystem design */
|
||||
*exchook_io_game_input_stat |= stat;
|
||||
*exchook_io_game_input_down |= stat_down;
|
||||
*exchook_io_game_input_up = stat_up;
|
||||
|
||||
/* swap for next iterateion */
|
||||
exchook_io_game_input_stat_prev = *exchook_io_game_input_stat;
|
||||
|
||||
/* Welp, the game expects us to do output setting if a button is pressed
|
||||
here...fuck that mess. Merge (i.e. |= not =) with other states set
|
||||
by the game */
|
||||
|
||||
memset(&exchook_io_out_pad_press_p1, 0, sizeof(exchook_io_out_pad_press_p1));
|
||||
memset(&exchook_io_out_pad_press_p2, 0, sizeof(exchook_io_out_pad_press_p2));
|
||||
|
||||
/* Player 1 */
|
||||
exchook_io_out_pad_press_p1.lu |= exchook_io_sensores_p1.lu;
|
||||
exchook_io_out_pad_press_p1.ru |= exchook_io_sensores_p1.ru;
|
||||
exchook_io_out_pad_press_p1.cn |= exchook_io_sensores_p1.cn;
|
||||
exchook_io_out_pad_press_p1.ld |= exchook_io_sensores_p1.ld;
|
||||
exchook_io_out_pad_press_p1.rd |= exchook_io_sensores_p1.rd;
|
||||
|
||||
/* Player 2 */
|
||||
exchook_io_out_pad_press_p2.lu |= exchook_io_sensores_p2.lu;
|
||||
exchook_io_out_pad_press_p2.ru |= exchook_io_sensores_p2.ru;
|
||||
exchook_io_out_pad_press_p2.cn |= exchook_io_sensores_p2.cn;
|
||||
exchook_io_out_pad_press_p2.ld |= exchook_io_sensores_p2.ld;
|
||||
exchook_io_out_pad_press_p2.rd |= exchook_io_sensores_p2.rd;
|
||||
|
||||
/* merge */
|
||||
/* Player 1 */
|
||||
exchook_io_out_pad_press_p1.lu |= exchook_io_out_pad_p1.lu;
|
||||
exchook_io_out_pad_press_p1.ru |= exchook_io_out_pad_p1.ru;
|
||||
exchook_io_out_pad_press_p1.cn |= exchook_io_out_pad_p1.cn;
|
||||
exchook_io_out_pad_press_p1.ld |= exchook_io_out_pad_p1.ld;
|
||||
exchook_io_out_pad_press_p1.rd |= exchook_io_out_pad_p1.rd;
|
||||
|
||||
/* Player 2 */
|
||||
exchook_io_out_pad_press_p2.lu |= exchook_io_out_pad_p2.lu;
|
||||
exchook_io_out_pad_press_p2.ru |= exchook_io_out_pad_p2.ru;
|
||||
exchook_io_out_pad_press_p2.cn |= exchook_io_out_pad_p2.cn;
|
||||
exchook_io_out_pad_press_p2.ld |= exchook_io_out_pad_p2.ld;
|
||||
exchook_io_out_pad_press_p2.rd |= exchook_io_out_pad_p2.rd;
|
||||
|
||||
exchook_piuio_api.set_output_pad(0, &exchook_io_out_pad_press_p1);
|
||||
exchook_piuio_api.set_output_pad(1, &exchook_io_out_pad_press_p2);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t exchook_io_coin_input(void* obj)
|
||||
static int32_t exchook_io_light_all(void *obj, uint8_t on)
|
||||
{
|
||||
/* Stub */
|
||||
if (on) {
|
||||
memset(&exchook_io_out_pad_p1, 1, sizeof(exchook_io_out_pad_p1));
|
||||
memset(&exchook_io_out_pad_p2, 1, sizeof(exchook_io_out_pad_p2));
|
||||
memset(&exchook_io_out_cab, 1, sizeof(exchook_io_out_cab));
|
||||
} else {
|
||||
memset(&exchook_io_out_pad_p1, 0, sizeof(exchook_io_out_pad_p1));
|
||||
memset(&exchook_io_out_pad_p2, 0, sizeof(exchook_io_out_pad_p2));
|
||||
memset(&exchook_io_out_cab, 0, sizeof(exchook_io_out_cab));
|
||||
}
|
||||
|
||||
return 0;
|
||||
exchook_piuio_api.set_output_pad(0, &exchook_io_out_pad_p1);
|
||||
exchook_piuio_api.set_output_pad(1, &exchook_io_out_pad_p2);
|
||||
exchook_piuio_api.set_output_cab(&exchook_io_out_cab);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t exchook_io_coin_input_2(void* obj)
|
||||
static int32_t exchook_io_light_neon(void *obj, uint8_t on)
|
||||
{
|
||||
/* Stub */
|
||||
if (on) {
|
||||
exchook_io_out_cab.bass = true;
|
||||
} else {
|
||||
exchook_io_out_cab.bass = false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
exchook_piuio_api.set_output_cab(&exchook_io_out_cab);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t exchook_io_coin_counter_2(void* obj)
|
||||
static int32_t
|
||||
exchook_io_light_halogan(void *obj, uint8_t on, uint16_t light_id)
|
||||
{
|
||||
/* Stub */
|
||||
if (light_id & 0x0400) {
|
||||
exchook_io_out_cab.halo_l1 = on;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (light_id & 0x0200) {
|
||||
exchook_io_out_cab.halo_l2 = on;
|
||||
}
|
||||
|
||||
if (light_id & 0x0100) {
|
||||
exchook_io_out_cab.halo_r1 = on;
|
||||
}
|
||||
|
||||
if (light_id & 0x0080) {
|
||||
exchook_io_out_cab.halo_r2 = on;
|
||||
}
|
||||
|
||||
exchook_piuio_api.set_output_cab(&exchook_io_out_cab);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t exchook_io_light_p1_ccfl(void *obj, uint8_t on, uint16_t cmd)
|
||||
{
|
||||
if (cmd & 0x0004) {
|
||||
exchook_io_out_pad_p1.lu = on;
|
||||
}
|
||||
|
||||
if (cmd & 0x0008) {
|
||||
exchook_io_out_pad_p1.ru = on;
|
||||
}
|
||||
|
||||
if (cmd & 0x0010) {
|
||||
exchook_io_out_pad_p1.cn = on;
|
||||
}
|
||||
|
||||
if (cmd & 0x0020) {
|
||||
exchook_io_out_pad_p1.ld = on;
|
||||
}
|
||||
|
||||
if (cmd & 0x040) {
|
||||
exchook_io_out_pad_p1.rd = on;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t exchook_io_light_p2_ccfl(void *obj, uint8_t on, uint16_t cmd)
|
||||
{
|
||||
if (cmd & 0x0004) {
|
||||
exchook_io_out_pad_p2.lu = on;
|
||||
}
|
||||
|
||||
if (cmd & 0x0008) {
|
||||
exchook_io_out_pad_p2.ru = on;
|
||||
}
|
||||
|
||||
if (cmd & 0x0010) {
|
||||
exchook_io_out_pad_p2.cn = on;
|
||||
}
|
||||
|
||||
if (cmd & 0x0020) {
|
||||
exchook_io_out_pad_p2.ld = on;
|
||||
}
|
||||
|
||||
if (cmd & 0x040) {
|
||||
exchook_io_out_pad_p2.rd = on;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t exchook_io_input(void *obj)
|
||||
{
|
||||
uint32_t stat;
|
||||
uint32_t stat_down;
|
||||
uint32_t stat_up;
|
||||
|
||||
struct ptapi_io_piuio_sys_inputs sys_in;
|
||||
|
||||
memset(&sys_in, 0, sizeof(struct ptapi_io_piuio_sys_inputs));
|
||||
|
||||
exchook_piuio_api.get_input_sys(&sys_in);
|
||||
|
||||
/* For game loaders and stuff */
|
||||
if (exchook_io_exit_on_service_test) {
|
||||
if (sys_in.test && sys_in.service) {
|
||||
log_info("Exit on service + test enabled and hit, bye");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* process final input states for the game as well as service, test, clear
|
||||
and coin which can't be handled in the check function */
|
||||
|
||||
stat = 0;
|
||||
stat_down = 0;
|
||||
stat_up = 0;
|
||||
|
||||
/* Player 1 */
|
||||
if (exchook_io_sensores_p1.lu) {
|
||||
stat |= GI_P1_7;
|
||||
}
|
||||
|
||||
if (exchook_io_sensores_p1.ru) {
|
||||
stat |= GI_P1_9;
|
||||
}
|
||||
|
||||
if (exchook_io_sensores_p1.cn) {
|
||||
stat |= GI_P1_5;
|
||||
}
|
||||
|
||||
if (exchook_io_sensores_p1.ld) {
|
||||
stat |= GI_P1_1;
|
||||
}
|
||||
|
||||
if (exchook_io_sensores_p1.rd) {
|
||||
stat |= GI_P1_3;
|
||||
}
|
||||
|
||||
/* Player 2 */
|
||||
if (exchook_io_sensores_p2.lu) {
|
||||
stat |= GI_P2_7;
|
||||
}
|
||||
|
||||
if (exchook_io_sensores_p2.ru) {
|
||||
stat |= GI_P2_9;
|
||||
}
|
||||
|
||||
if (exchook_io_sensores_p2.cn) {
|
||||
stat |= GI_P2_5;
|
||||
}
|
||||
|
||||
if (exchook_io_sensores_p2.ld) {
|
||||
stat |= GI_P2_1;
|
||||
}
|
||||
|
||||
if (exchook_io_sensores_p2.rd) {
|
||||
stat |= GI_P2_3;
|
||||
}
|
||||
|
||||
/* Sys */
|
||||
if (sys_in.test) {
|
||||
stat |= GI_TEST;
|
||||
}
|
||||
|
||||
if (sys_in.service) {
|
||||
stat |= GI_SERVICE;
|
||||
}
|
||||
|
||||
/* Taken from source but doesn't seem to work (on some versions?) */
|
||||
if (sys_in.clear) {
|
||||
stat |= GI_CLEAR;
|
||||
}
|
||||
|
||||
if (sys_in.coin) {
|
||||
stat |= GI_COIN;
|
||||
}
|
||||
|
||||
if (sys_in.coin2) {
|
||||
stat |= GI_COIN2;
|
||||
}
|
||||
|
||||
/* iterate bits for up and down events */
|
||||
for (uint8_t i = 0; i < 32; i++) {
|
||||
|
||||
if (!(exchook_io_game_input_stat_prev & (1 << i)) && (stat & (1 << i))) {
|
||||
/* New push down */
|
||||
stat_down |= (1 << i);
|
||||
} else if (
|
||||
(exchook_io_game_input_stat_prev & (1 << i)) && !(stat & (1 << i))) {
|
||||
/* New release */
|
||||
stat_up |= (1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
/* Extremely bad IO subsystem design */
|
||||
*exchook_io_game_input_stat |= stat;
|
||||
*exchook_io_game_input_down |= stat_down;
|
||||
*exchook_io_game_input_up = stat_up;
|
||||
|
||||
/* swap for next iterateion */
|
||||
exchook_io_game_input_stat_prev = *exchook_io_game_input_stat;
|
||||
|
||||
/* Welp, the game expects us to do output setting if a button is pressed
|
||||
here...fuck that mess. Merge (i.e. |= not =) with other states set
|
||||
by the game */
|
||||
|
||||
memset(&exchook_io_out_pad_press_p1, 0, sizeof(exchook_io_out_pad_press_p1));
|
||||
memset(&exchook_io_out_pad_press_p2, 0, sizeof(exchook_io_out_pad_press_p2));
|
||||
|
||||
/* Player 1 */
|
||||
exchook_io_out_pad_press_p1.lu |= exchook_io_sensores_p1.lu;
|
||||
exchook_io_out_pad_press_p1.ru |= exchook_io_sensores_p1.ru;
|
||||
exchook_io_out_pad_press_p1.cn |= exchook_io_sensores_p1.cn;
|
||||
exchook_io_out_pad_press_p1.ld |= exchook_io_sensores_p1.ld;
|
||||
exchook_io_out_pad_press_p1.rd |= exchook_io_sensores_p1.rd;
|
||||
|
||||
/* Player 2 */
|
||||
exchook_io_out_pad_press_p2.lu |= exchook_io_sensores_p2.lu;
|
||||
exchook_io_out_pad_press_p2.ru |= exchook_io_sensores_p2.ru;
|
||||
exchook_io_out_pad_press_p2.cn |= exchook_io_sensores_p2.cn;
|
||||
exchook_io_out_pad_press_p2.ld |= exchook_io_sensores_p2.ld;
|
||||
exchook_io_out_pad_press_p2.rd |= exchook_io_sensores_p2.rd;
|
||||
|
||||
/* merge */
|
||||
/* Player 1 */
|
||||
exchook_io_out_pad_press_p1.lu |= exchook_io_out_pad_p1.lu;
|
||||
exchook_io_out_pad_press_p1.ru |= exchook_io_out_pad_p1.ru;
|
||||
exchook_io_out_pad_press_p1.cn |= exchook_io_out_pad_p1.cn;
|
||||
exchook_io_out_pad_press_p1.ld |= exchook_io_out_pad_p1.ld;
|
||||
exchook_io_out_pad_press_p1.rd |= exchook_io_out_pad_p1.rd;
|
||||
|
||||
/* Player 2 */
|
||||
exchook_io_out_pad_press_p2.lu |= exchook_io_out_pad_p2.lu;
|
||||
exchook_io_out_pad_press_p2.ru |= exchook_io_out_pad_p2.ru;
|
||||
exchook_io_out_pad_press_p2.cn |= exchook_io_out_pad_p2.cn;
|
||||
exchook_io_out_pad_press_p2.ld |= exchook_io_out_pad_p2.ld;
|
||||
exchook_io_out_pad_press_p2.rd |= exchook_io_out_pad_p2.rd;
|
||||
|
||||
exchook_piuio_api.set_output_pad(0, &exchook_io_out_pad_press_p1);
|
||||
exchook_piuio_api.set_output_pad(1, &exchook_io_out_pad_press_p2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t exchook_io_coin_input(void *obj)
|
||||
{
|
||||
/* Stub */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t exchook_io_coin_input_2(void *obj)
|
||||
{
|
||||
/* Stub */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t exchook_io_coin_counter_2(void *obj)
|
||||
{
|
||||
/* Stub */
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -15,7 +15,9 @@
|
||||
* @param piuio_lib_path Path to piuio lib to use for emulation
|
||||
* @parma exit_on_service_test Exit the game when pressing service + test
|
||||
*/
|
||||
void exchook_io_init(const struct exchook_mempatch_table* patch_table, const char* piuio_lib_path,
|
||||
void exchook_io_init(
|
||||
const struct exchook_mempatch_table *patch_table,
|
||||
const char *piuio_lib_path,
|
||||
bool exit_on_service_test);
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,42 +2,42 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "sec/lockchip/lockchip.h"
|
||||
#include "sec/lockchip/lockchip-defs.h"
|
||||
#include "sec/lockchip/lockchip.h"
|
||||
|
||||
#include "util/log.h"
|
||||
#include "util/patch.h"
|
||||
|
||||
#include "lockchip.h"
|
||||
|
||||
static void exchook_lockchip_dec_chunk(uint8_t len, const uint8_t* src,
|
||||
uint8_t* dest);
|
||||
static void
|
||||
exchook_lockchip_dec_chunk(uint8_t len, const uint8_t *src, uint8_t *dest);
|
||||
|
||||
void exchook_lockchip_init(const struct exchook_mempatch_table* patch_table)
|
||||
void exchook_lockchip_init(const struct exchook_mempatch_table *patch_table)
|
||||
{
|
||||
sec_lockchip_init(
|
||||
sec_lockchip_defs_transforms[SEC_LOCK_CHIP_DEFS_GAME_EXCEED]);
|
||||
sec_lockchip_init(
|
||||
sec_lockchip_defs_transforms[SEC_LOCK_CHIP_DEFS_GAME_EXCEED]);
|
||||
|
||||
/* Hook lockchip */
|
||||
util_patch_function(patch_table->addr_lockchip_dec_chunk, exchook_lockchip_dec_chunk);
|
||||
/* Hook lockchip */
|
||||
util_patch_function(
|
||||
patch_table->addr_lockchip_dec_chunk, exchook_lockchip_dec_chunk);
|
||||
|
||||
log_info("Initialized");
|
||||
log_info("Initialized");
|
||||
}
|
||||
|
||||
static void exchook_lockchip_dec_chunk(uint8_t len, const uint8_t* src,
|
||||
uint8_t* dest)
|
||||
static void
|
||||
exchook_lockchip_dec_chunk(uint8_t len, const uint8_t *src, uint8_t *dest)
|
||||
{
|
||||
sec_lockchip_start();
|
||||
sec_lockchip_start();
|
||||
|
||||
uint8_t last_res = sec_lockchip_step(src[0] ^ 0xFF);
|
||||
uint8_t last_res = sec_lockchip_step(src[0] ^ 0xFF);
|
||||
|
||||
for (size_t i = 1; i < len; i++)
|
||||
{
|
||||
uint8_t result = sec_lockchip_step(src[i] ^ 0xFF);
|
||||
dest[i - 1] = (uint8_t)((last_res >> 3) ^ (result << 5));
|
||||
last_res = result;
|
||||
}
|
||||
for (size_t i = 1; i < len; i++) {
|
||||
uint8_t result = sec_lockchip_step(src[i] ^ 0xFF);
|
||||
dest[i - 1] = (uint8_t)((last_res >> 3) ^ (result << 5));
|
||||
last_res = result;
|
||||
}
|
||||
|
||||
uint8_t last_byte = sec_lockchip_step(0);
|
||||
dest[len - 1] = (uint8_t)((last_res >> 3) ^ (last_byte << 5));
|
||||
uint8_t last_byte = sec_lockchip_step(0);
|
||||
dest[len - 1] = (uint8_t)((last_res >> 3) ^ (last_byte << 5));
|
||||
}
|
||||
@@ -14,6 +14,6 @@
|
||||
*
|
||||
* @param patch_table Patch table with memory addresses
|
||||
*/
|
||||
void exchook_lockchip_init(const struct exchook_mempatch_table* patch_table);
|
||||
void exchook_lockchip_init(const struct exchook_mempatch_table *patch_table);
|
||||
|
||||
#endif
|
||||
+153
-133
@@ -30,225 +30,245 @@
|
||||
#include "mempatch.h"
|
||||
#include "options.h"
|
||||
|
||||
static void exchook_bootstrapping(int argc, char** argv, struct exchook_options* options, char** game_data_path)
|
||||
static void exchook_bootstrapping(
|
||||
int argc,
|
||||
char **argv,
|
||||
struct exchook_options *options,
|
||||
char **game_data_path)
|
||||
{
|
||||
log_assert(argc >= 0);
|
||||
log_assert(argv);
|
||||
log_assert(options);
|
||||
log_assert(game_data_path);
|
||||
log_assert(argc >= 0);
|
||||
log_assert(argv);
|
||||
log_assert(options);
|
||||
log_assert(game_data_path);
|
||||
|
||||
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
|
||||
return;
|
||||
}
|
||||
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
hook_core_piu_log_init(argc, argv);
|
||||
hook_core_piu_log_init(argc, argv);
|
||||
|
||||
if (!exchook_options_init(argc, argv, options)) {
|
||||
exit(0);
|
||||
}
|
||||
if (!exchook_options_init(argc, argv, options)) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
hook_core_piu_log_info(argc, argv);
|
||||
hook_core_piu_log_info(argc, argv);
|
||||
|
||||
*game_data_path = hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
|
||||
*game_data_path =
|
||||
hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
|
||||
|
||||
hook_core_piu_utils_verify_root_user();
|
||||
hook_core_piu_utils_verify_root_user();
|
||||
|
||||
log_info("Initializing, piu game data path: %s", *game_data_path);
|
||||
log_info("Initializing, piu game data path: %s", *game_data_path);
|
||||
}
|
||||
|
||||
static void exchook_game_version_mempatch_table_init(
|
||||
struct exchook_options* options,
|
||||
const struct exchook_mempatch_table** patch_table)
|
||||
struct exchook_options *options,
|
||||
const struct exchook_mempatch_table **patch_table)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(patch_table);
|
||||
log_assert(options);
|
||||
log_assert(patch_table);
|
||||
|
||||
if (!options->game.version) {
|
||||
log_die("No game version specified");
|
||||
} else {
|
||||
log_info("Game version configured: %s", options->game.version);
|
||||
}
|
||||
if (!options->game.version) {
|
||||
log_die("No game version specified");
|
||||
} else {
|
||||
log_info("Game version configured: %s", options->game.version);
|
||||
}
|
||||
|
||||
*patch_table = exchook_mempatch_get_table(options->game.version);
|
||||
*patch_table = exchook_mempatch_get_table(options->game.version);
|
||||
|
||||
if (*patch_table == NULL) {
|
||||
log_die("Unsupported game version %s", options->game.version);
|
||||
}
|
||||
if (*patch_table == NULL) {
|
||||
log_die("Unsupported game version %s", options->game.version);
|
||||
}
|
||||
}
|
||||
|
||||
static void exchook_patch_fs_init(struct exchook_options* options)
|
||||
static void exchook_patch_fs_init(struct exchook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
patch_hook_mon_init(
|
||||
options->patch.hook_mon.io,
|
||||
options->patch.hook_mon.file,
|
||||
options->patch.hook_mon.fs,
|
||||
options->patch.hook_mon.usb,
|
||||
options->patch.hook_mon.open);
|
||||
patch_hook_mon_init(
|
||||
options->patch.hook_mon.io,
|
||||
options->patch.hook_mon.file,
|
||||
options->patch.hook_mon.fs,
|
||||
options->patch.hook_mon.usb,
|
||||
options->patch.hook_mon.open);
|
||||
|
||||
patch_redir_init();
|
||||
patch_redir_init();
|
||||
}
|
||||
|
||||
static void exchook_fs_redir_settings(struct exchook_options* options)
|
||||
static void exchook_fs_redir_settings(struct exchook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
if (options->game.settings) {
|
||||
if (!util_fs_path_exists(options->game.settings)) {
|
||||
log_info("Settings path %s does not exist, creating", options->game.settings);
|
||||
if (options->game.settings) {
|
||||
if (!util_fs_path_exists(options->game.settings)) {
|
||||
log_info(
|
||||
"Settings path %s does not exist, creating", options->game.settings);
|
||||
|
||||
if (!util_fs_mkdir(options->game.settings)) {
|
||||
log_error("Creating directory %s failed", options->game.settings);
|
||||
}
|
||||
}
|
||||
|
||||
char* abs_path = util_fs_get_abs_path(options->game.settings);
|
||||
|
||||
cnh_redir_add("/SETTINGS", abs_path);
|
||||
free(abs_path);
|
||||
} else {
|
||||
log_warn("No settings path specified");
|
||||
if (!util_fs_mkdir(options->game.settings)) {
|
||||
log_error("Creating directory %s failed", options->game.settings);
|
||||
}
|
||||
}
|
||||
|
||||
char *abs_path = util_fs_get_abs_path(options->game.settings);
|
||||
|
||||
cnh_redir_add("/SETTINGS", abs_path);
|
||||
free(abs_path);
|
||||
} else {
|
||||
log_warn("No settings path specified");
|
||||
}
|
||||
}
|
||||
|
||||
static void exchook_fs_redir_usb()
|
||||
{
|
||||
/* Needed on newer kernels */
|
||||
cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices");
|
||||
/* Needed on newer kernels */
|
||||
cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices");
|
||||
}
|
||||
|
||||
static void exchook_patch_gfx_init(struct exchook_options* options)
|
||||
static void exchook_patch_gfx_init(struct exchook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
patch_gfx_init();
|
||||
patch_gfx_init();
|
||||
|
||||
if (options->patch.gfx.windowed) {
|
||||
patch_gfx_force_window_mode();
|
||||
}
|
||||
if (options->patch.gfx.windowed) {
|
||||
patch_gfx_force_window_mode();
|
||||
}
|
||||
}
|
||||
|
||||
static void exchook_patch_main_loop_init(struct exchook_options* options)
|
||||
static void exchook_patch_main_loop_init(struct exchook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
patch_main_loop_init(true, options->patch.main_loop.disable_built_in_inputs, false);
|
||||
patch_main_loop_init(
|
||||
true, options->patch.main_loop.disable_built_in_inputs, false);
|
||||
|
||||
if (options->patch.main_loop.x11_input_handler_api_lib) {
|
||||
char* abs_path_x11_input_hook_lib = util_fs_get_abs_path(options->patch.main_loop.x11_input_handler_api_lib);
|
||||
if (options->patch.main_loop.x11_input_handler_api_lib) {
|
||||
char *abs_path_x11_input_hook_lib = util_fs_get_abs_path(
|
||||
options->patch.main_loop.x11_input_handler_api_lib);
|
||||
|
||||
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
|
||||
free(abs_path_x11_input_hook_lib);
|
||||
}
|
||||
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
|
||||
free(abs_path_x11_input_hook_lib);
|
||||
}
|
||||
}
|
||||
|
||||
static void exchook_patch_sound_init(struct exchook_options* options, const struct exchook_mempatch_table* patch_table)
|
||||
static void exchook_patch_sound_init(
|
||||
struct exchook_options *options,
|
||||
const struct exchook_mempatch_table *patch_table)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(patch_table);
|
||||
log_assert(options);
|
||||
log_assert(patch_table);
|
||||
|
||||
/* exceed crashes with its default device hw:0. use dmix instead */
|
||||
if (strcmp(options->patch.sound.device, "dmix") != 0) {
|
||||
log_warn("Game might crash with selected sound device %s, use 'dmix' instead if that happens",
|
||||
options->patch.sound.device);
|
||||
}
|
||||
/* exceed crashes with its default device hw:0. use dmix instead */
|
||||
if (strcmp(options->patch.sound.device, "dmix") != 0) {
|
||||
log_warn(
|
||||
"Game might crash with selected sound device %s, use 'dmix' instead if "
|
||||
"that happens",
|
||||
options->patch.sound.device);
|
||||
}
|
||||
|
||||
patch_sound_init(options->patch.sound.device);
|
||||
patch_asound_fix_init();
|
||||
patch_sound_init(options->patch.sound.device);
|
||||
patch_asound_fix_init();
|
||||
|
||||
/* return from StopAllEffects to avoid killing the sound thread */
|
||||
util_patch_write_memory_byte(patch_table->addr_stop_all_effects_return, 0xC3);
|
||||
/* return from StopAllEffects to avoid killing the sound thread */
|
||||
util_patch_write_memory_byte(patch_table->addr_stop_all_effects_return, 0xC3);
|
||||
}
|
||||
|
||||
static void exchook_patch_sigsegv_init(struct exchook_options* options)
|
||||
static void exchook_patch_sigsegv_init(struct exchook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
|
||||
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
|
||||
}
|
||||
|
||||
static void exchook_patch_lockchip_init(const struct exchook_mempatch_table* patch_table)
|
||||
static void
|
||||
exchook_patch_lockchip_init(const struct exchook_mempatch_table *patch_table)
|
||||
{
|
||||
log_assert(patch_table);
|
||||
log_assert(patch_table);
|
||||
|
||||
exchook_lockchip_init(patch_table);
|
||||
exchook_lockchip_init(patch_table);
|
||||
}
|
||||
|
||||
static void exchook_patch_eeprom_init(struct exchook_options* options, const struct exchook_mempatch_table* patch_table)
|
||||
static void exchook_patch_eeprom_init(
|
||||
struct exchook_options *options,
|
||||
const struct exchook_mempatch_table *patch_table)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(patch_table);
|
||||
log_assert(options);
|
||||
log_assert(patch_table);
|
||||
|
||||
char* eeprom_path;
|
||||
char *eeprom_path;
|
||||
|
||||
if (options->game.settings) {
|
||||
char* abs_path = util_fs_get_abs_path(options->game.settings);
|
||||
if (options->game.settings) {
|
||||
char *abs_path = util_fs_get_abs_path(options->game.settings);
|
||||
|
||||
eeprom_path = util_str_merge(abs_path, "/eeprom.bin");
|
||||
free(abs_path);
|
||||
} else {
|
||||
eeprom_path = util_str_dup("/tmp/eeprom.bin");
|
||||
log_warn("No settings path specified to store eeprom data, defaulting to %s", eeprom_path);
|
||||
}
|
||||
eeprom_path = util_str_merge(abs_path, "/eeprom.bin");
|
||||
free(abs_path);
|
||||
} else {
|
||||
eeprom_path = util_str_dup("/tmp/eeprom.bin");
|
||||
log_warn(
|
||||
"No settings path specified to store eeprom data, defaulting to %s",
|
||||
eeprom_path);
|
||||
}
|
||||
|
||||
exchook_eeprom_init(patch_table, eeprom_path);
|
||||
free(eeprom_path);
|
||||
exchook_eeprom_init(patch_table, eeprom_path);
|
||||
free(eeprom_path);
|
||||
}
|
||||
|
||||
static void exchook_patch_piuio_init(struct exchook_options* options, const struct exchook_mempatch_table* patch_table)
|
||||
static void exchook_patch_piuio_init(
|
||||
struct exchook_options *options,
|
||||
const struct exchook_mempatch_table *patch_table)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(patch_table);
|
||||
log_assert(options);
|
||||
log_assert(patch_table);
|
||||
|
||||
if (options->patch.piuio.api_lib) {
|
||||
char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
|
||||
if (options->patch.piuio.api_lib) {
|
||||
char *abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
|
||||
|
||||
exchook_io_init(patch_table, abs_path_iolib, options->patch.piuio.exit_test_serv);
|
||||
free(abs_path_iolib);
|
||||
}
|
||||
exchook_io_init(
|
||||
patch_table, abs_path_iolib, options->patch.piuio.exit_test_serv);
|
||||
free(abs_path_iolib);
|
||||
}
|
||||
}
|
||||
|
||||
void exchook_constructor(void)
|
||||
{
|
||||
/* Nothing here */
|
||||
/* Nothing here */
|
||||
}
|
||||
|
||||
void exchook_destructor(void)
|
||||
{
|
||||
/* Nothing here */
|
||||
/* Nothing here */
|
||||
}
|
||||
|
||||
void exchook_trap_before_main(int argc, char** argv)
|
||||
void exchook_trap_before_main(int argc, char **argv)
|
||||
{
|
||||
log_assert(argc >= 0);
|
||||
log_assert(argv);
|
||||
log_assert(argc >= 0);
|
||||
log_assert(argv);
|
||||
|
||||
char* game_data_path;
|
||||
struct exchook_options options;
|
||||
const struct exchook_mempatch_table* mempatch_table;
|
||||
char *game_data_path;
|
||||
struct exchook_options options;
|
||||
const struct exchook_mempatch_table *mempatch_table;
|
||||
|
||||
exchook_bootstrapping(argc, argv, &options, &game_data_path);
|
||||
exchook_game_version_mempatch_table_init(&options, &mempatch_table);
|
||||
exchook_patch_fs_init(&options);
|
||||
exchook_fs_redir_settings(&options);
|
||||
exchook_fs_redir_usb();
|
||||
exchook_patch_gfx_init(&options);
|
||||
exchook_patch_main_loop_init(&options);
|
||||
exchook_patch_sound_init(&options, mempatch_table);
|
||||
exchook_patch_sigsegv_init(&options);
|
||||
exchook_patch_lockchip_init(mempatch_table);
|
||||
exchook_patch_eeprom_init(&options, mempatch_table);
|
||||
exchook_patch_piuio_init(&options, mempatch_table);
|
||||
exchook_bootstrapping(argc, argv, &options, &game_data_path);
|
||||
exchook_game_version_mempatch_table_init(&options, &mempatch_table);
|
||||
exchook_patch_fs_init(&options);
|
||||
exchook_fs_redir_settings(&options);
|
||||
exchook_fs_redir_usb();
|
||||
exchook_patch_gfx_init(&options);
|
||||
exchook_patch_main_loop_init(&options);
|
||||
exchook_patch_sound_init(&options, mempatch_table);
|
||||
exchook_patch_sigsegv_init(&options);
|
||||
exchook_patch_lockchip_init(mempatch_table);
|
||||
exchook_patch_eeprom_init(&options, mempatch_table);
|
||||
exchook_patch_piuio_init(&options, mempatch_table);
|
||||
|
||||
free(game_data_path);
|
||||
free(game_data_path);
|
||||
|
||||
log_info("Hooking finished");
|
||||
log_info("Hooking finished");
|
||||
}
|
||||
|
||||
void exchook_trap_after_main(void)
|
||||
{
|
||||
exchook_io_shutdown();
|
||||
exchook_io_shutdown();
|
||||
}
|
||||
|
||||
LIB_MAIN_CONSTRUCTOR(exchook_constructor);
|
||||
|
||||
@@ -48,15 +48,16 @@ static const struct exchook_mempatch_table _exchook_mempatch_table[] = {
|
||||
},
|
||||
};
|
||||
|
||||
const struct exchook_mempatch_table* exchook_mempatch_get_table(const char* version)
|
||||
const struct exchook_mempatch_table *
|
||||
exchook_mempatch_get_table(const char *version)
|
||||
{
|
||||
size_t entries = lengthof(_exchook_mempatch_table);
|
||||
size_t entries = lengthof(_exchook_mempatch_table);
|
||||
|
||||
for (uint32_t i = 0; i < entries; i++) {
|
||||
if (!strcmp(_exchook_mempatch_table[i].version, version)) {
|
||||
return &_exchook_mempatch_table[i];
|
||||
}
|
||||
for (uint32_t i = 0; i < entries; i++) {
|
||||
if (!strcmp(_exchook_mempatch_table[i].version, version)) {
|
||||
return &_exchook_mempatch_table[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
@@ -4,26 +4,27 @@
|
||||
#include <stdint.h>
|
||||
|
||||
struct exchook_mempatch_table {
|
||||
const char* version;
|
||||
uintptr_t addr_eeprom_read;
|
||||
uintptr_t addr_eeprom_write;
|
||||
uintptr_t addr_io_check;
|
||||
uintptr_t addr_io_light_all;
|
||||
uintptr_t addr_io_light_neon;
|
||||
uintptr_t addr_io_light_halogan;
|
||||
uintptr_t addr_io_light_p1_ccfl;
|
||||
uintptr_t addr_io_light_p2_ccfl;
|
||||
uintptr_t addr_io_input;
|
||||
uintptr_t addr_io_coin_input;
|
||||
uintptr_t addr_io_coin_input_2;
|
||||
uintptr_t addr_io_coin_counter_2;
|
||||
uintptr_t addr_io_game_input_stat;
|
||||
uintptr_t addr_io_game_input_down;
|
||||
uintptr_t addr_io_game_input_up;
|
||||
uintptr_t addr_lockchip_dec_chunk;
|
||||
uintptr_t addr_stop_all_effects_return;
|
||||
const char *version;
|
||||
uintptr_t addr_eeprom_read;
|
||||
uintptr_t addr_eeprom_write;
|
||||
uintptr_t addr_io_check;
|
||||
uintptr_t addr_io_light_all;
|
||||
uintptr_t addr_io_light_neon;
|
||||
uintptr_t addr_io_light_halogan;
|
||||
uintptr_t addr_io_light_p1_ccfl;
|
||||
uintptr_t addr_io_light_p2_ccfl;
|
||||
uintptr_t addr_io_input;
|
||||
uintptr_t addr_io_coin_input;
|
||||
uintptr_t addr_io_coin_input_2;
|
||||
uintptr_t addr_io_coin_counter_2;
|
||||
uintptr_t addr_io_game_input_stat;
|
||||
uintptr_t addr_io_game_input_down;
|
||||
uintptr_t addr_io_game_input_up;
|
||||
uintptr_t addr_lockchip_dec_chunk;
|
||||
uintptr_t addr_stop_all_effects_return;
|
||||
};
|
||||
|
||||
const struct exchook_mempatch_table* exchook_mempatch_get_table(const char* version);
|
||||
const struct exchook_mempatch_table *
|
||||
exchook_mempatch_get_table(const char *version);
|
||||
|
||||
#endif
|
||||
+63
-40
@@ -10,12 +10,16 @@
|
||||
#define EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO "patch.hook_mon.io"
|
||||
#define EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN "patch.hook_mon.open"
|
||||
#define EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb"
|
||||
#define EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS "patch.hook_main_loop.disable_built_in_inputs"
|
||||
#define EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER "patch_hook_main_loop.x11_input_handler"
|
||||
#define EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS \
|
||||
"patch.hook_main_loop.disable_built_in_inputs"
|
||||
#define EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER \
|
||||
"patch_hook_main_loop.x11_input_handler"
|
||||
#define EXCHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib"
|
||||
#define EXCHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv"
|
||||
#define EXCHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV \
|
||||
"patch.piuio_exit.test_serv"
|
||||
#define EXCHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE "patch.sound.device"
|
||||
#define EXCHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV "patch.sigsegv.halt_on_segv"
|
||||
#define EXCHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV \
|
||||
"patch.sigsegv.halt_on_segv"
|
||||
#define EXCHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file"
|
||||
#define EXCHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level"
|
||||
|
||||
@@ -29,7 +33,9 @@ static const struct util_options_def exchook_options_def[] = {
|
||||
},
|
||||
{
|
||||
.name = EXCHOOK_OPTIONS_STR_GAME_VERSION,
|
||||
.description = "Version of the game (format YYYYMMDD). Make sure this matches exactly the version you are"
|
||||
.description =
|
||||
"Version of the game (format YYYYMMDD). Make sure this matches "
|
||||
"exactly the version you are"
|
||||
" running because the hook lib has to apply memory patches.",
|
||||
.param = 'v',
|
||||
.type = UTIL_OPTIONS_TYPE_STR,
|
||||
@@ -78,22 +84,26 @@ static const struct util_options_def exchook_options_def[] = {
|
||||
.default_value.b = false,
|
||||
},
|
||||
{
|
||||
.name = EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS,
|
||||
.description = "Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3)",
|
||||
.name =
|
||||
EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS,
|
||||
.description = "Disable the built in keyboard inputs for test (F1), "
|
||||
"service (F2) and clear (F3)",
|
||||
.param = 'k',
|
||||
.type = UTIL_OPTIONS_TYPE_BOOL,
|
||||
.default_value.b = false,
|
||||
},
|
||||
{
|
||||
.name = EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER,
|
||||
.description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs",
|
||||
.description = "Path to a library implementing the x11-input-handler "
|
||||
"api to capture X11 keyboard inputs",
|
||||
.param = 'q',
|
||||
.type = UTIL_OPTIONS_TYPE_STR,
|
||||
.default_value.str = NULL,
|
||||
},
|
||||
{
|
||||
.name = EXCHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB,
|
||||
.description = "Path to library implementing the piuio api for piuio emulation",
|
||||
.description =
|
||||
"Path to library implementing the piuio api for piuio emulation",
|
||||
.param = 'p',
|
||||
.type = UTIL_OPTIONS_TYPE_STR,
|
||||
.default_value.str = NULL,
|
||||
@@ -144,41 +154,54 @@ static const struct util_options_defs exchook_options_defs = {
|
||||
.ndefs = lengthof(exchook_options_def)
|
||||
};
|
||||
|
||||
bool exchook_options_init(int argc, char** argv, struct exchook_options* options)
|
||||
bool exchook_options_init(
|
||||
int argc, char **argv, struct exchook_options *options)
|
||||
{
|
||||
log_assert(argv);
|
||||
log_assert(options);
|
||||
log_assert(argv);
|
||||
log_assert(options);
|
||||
|
||||
struct util_options_opts* options_opt;
|
||||
struct util_options_opts *options_opt;
|
||||
|
||||
util_options_init(argc, argv);
|
||||
options_opt = util_options_get(&exchook_options_defs);
|
||||
util_options_init(argc, argv);
|
||||
options_opt = util_options_get(&exchook_options_defs);
|
||||
|
||||
if (!options_opt) {
|
||||
return false;
|
||||
}
|
||||
if (!options_opt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
options->game.settings = util_options_get_str(options_opt, EXCHOOK_OPTIONS_STR_GAME_SETTINGS);
|
||||
options->game.version = util_options_get_str(options_opt, EXCHOOK_OPTIONS_STR_GAME_VERSION);
|
||||
options->patch.gfx.windowed = util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
|
||||
options->patch.hook_mon.file = util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
|
||||
options->patch.hook_mon.fs = util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
|
||||
options->patch.hook_mon.io = util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
|
||||
options->patch.hook_mon.open = util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
|
||||
options->patch.hook_mon.usb = util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
|
||||
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(options_opt,
|
||||
EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
|
||||
options->patch.main_loop.x11_input_handler_api_lib =
|
||||
util_options_get_str(options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
|
||||
options->patch.piuio.api_lib = util_options_get_str(options_opt, EXCHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
|
||||
options->patch.piuio.exit_test_serv =
|
||||
util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
|
||||
options->patch.sound.device = util_options_get_str(options_opt, EXCHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
|
||||
options->patch.sigsegv.halt_on_segv =
|
||||
util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
|
||||
options->log.file = util_options_get_str(options_opt, EXCHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
|
||||
options->log.level =
|
||||
(enum util_log_level) util_options_get_int(options_opt, EXCHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
|
||||
options->game.settings =
|
||||
util_options_get_str(options_opt, EXCHOOK_OPTIONS_STR_GAME_SETTINGS);
|
||||
options->game.version =
|
||||
util_options_get_str(options_opt, EXCHOOK_OPTIONS_STR_GAME_VERSION);
|
||||
options->patch.gfx.windowed = util_options_get_bool(
|
||||
options_opt, EXCHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
|
||||
options->patch.hook_mon.file = util_options_get_bool(
|
||||
options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
|
||||
options->patch.hook_mon.fs =
|
||||
util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
|
||||
options->patch.hook_mon.io =
|
||||
util_options_get_bool(options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
|
||||
options->patch.hook_mon.open = util_options_get_bool(
|
||||
options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
|
||||
options->patch.hook_mon.usb = util_options_get_bool(
|
||||
options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
|
||||
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(
|
||||
options_opt,
|
||||
EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
|
||||
options->patch.main_loop.x11_input_handler_api_lib = util_options_get_str(
|
||||
options_opt, EXCHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
|
||||
options->patch.piuio.api_lib = util_options_get_str(
|
||||
options_opt, EXCHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
|
||||
options->patch.piuio.exit_test_serv = util_options_get_bool(
|
||||
options_opt, EXCHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
|
||||
options->patch.sound.device =
|
||||
util_options_get_str(options_opt, EXCHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
|
||||
options->patch.sigsegv.halt_on_segv = util_options_get_bool(
|
||||
options_opt, EXCHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
|
||||
options->log.file = util_options_get_str(
|
||||
options_opt, EXCHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
|
||||
options->log.level = (enum util_log_level) util_options_get_int(
|
||||
options_opt, EXCHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
+36
-35
@@ -7,49 +7,50 @@
|
||||
#include "util/log.h"
|
||||
|
||||
struct exchook_options {
|
||||
struct game {
|
||||
const char* settings;
|
||||
const char* version;
|
||||
} game;
|
||||
struct game {
|
||||
const char *settings;
|
||||
const char *version;
|
||||
} game;
|
||||
|
||||
struct patch {
|
||||
struct gfx {
|
||||
bool windowed;
|
||||
} gfx;
|
||||
struct patch {
|
||||
struct gfx {
|
||||
bool windowed;
|
||||
} gfx;
|
||||
|
||||
struct hook_mon {
|
||||
bool file;
|
||||
bool fs;
|
||||
bool io;
|
||||
bool open;
|
||||
bool usb;
|
||||
} hook_mon;
|
||||
struct hook_mon {
|
||||
bool file;
|
||||
bool fs;
|
||||
bool io;
|
||||
bool open;
|
||||
bool usb;
|
||||
} hook_mon;
|
||||
|
||||
struct main_loop {
|
||||
bool disable_built_in_inputs;
|
||||
const char* x11_input_handler_api_lib;
|
||||
} main_loop;
|
||||
struct main_loop {
|
||||
bool disable_built_in_inputs;
|
||||
const char *x11_input_handler_api_lib;
|
||||
} main_loop;
|
||||
|
||||
struct piuio {
|
||||
const char* api_lib;
|
||||
bool exit_test_serv;
|
||||
} piuio;
|
||||
struct piuio {
|
||||
const char *api_lib;
|
||||
bool exit_test_serv;
|
||||
} piuio;
|
||||
|
||||
struct sound {
|
||||
const char* device;
|
||||
} sound;
|
||||
struct sound {
|
||||
const char *device;
|
||||
} sound;
|
||||
|
||||
struct sigsegv {
|
||||
bool halt_on_segv;
|
||||
} sigsegv;
|
||||
} patch;
|
||||
struct sigsegv {
|
||||
bool halt_on_segv;
|
||||
} sigsegv;
|
||||
} patch;
|
||||
|
||||
struct log {
|
||||
const char* file;
|
||||
enum util_log_level level;
|
||||
} log;
|
||||
struct log {
|
||||
const char *file;
|
||||
enum util_log_level level;
|
||||
} log;
|
||||
};
|
||||
|
||||
bool exchook_options_init(int argc, char** argv, struct exchook_options* options);
|
||||
bool exchook_options_init(
|
||||
int argc, char **argv, struct exchook_options *options);
|
||||
|
||||
#endif
|
||||
|
||||
+125
-112
@@ -17,8 +17,8 @@
|
||||
#include "hook/patch/hook-mon.h"
|
||||
#include "hook/patch/main-loop.h"
|
||||
#include "hook/patch/mounts.h"
|
||||
#include "hook/patch/piuio.h"
|
||||
#include "hook/patch/piuio-exit.h"
|
||||
#include "hook/patch/piuio.h"
|
||||
#include "hook/patch/redir.h"
|
||||
#include "hook/patch/sigsegv.h"
|
||||
#include "hook/patch/sound.h"
|
||||
@@ -39,204 +39,217 @@ extern const uint8_t _binary_f2hook_hdd_raw_end[];
|
||||
extern const uint8_t _binary_f2hook_hasp_key_start[];
|
||||
extern const uint8_t _binary_f2hook_hasp_key_end[];
|
||||
|
||||
static void f2hook_bootstrapping(int argc, char** argv, struct f2hook_options* options, char** game_data_path)
|
||||
static void f2hook_bootstrapping(
|
||||
int argc,
|
||||
char **argv,
|
||||
struct f2hook_options *options,
|
||||
char **game_data_path)
|
||||
{
|
||||
log_assert(argc >= 0);
|
||||
log_assert(argv);
|
||||
log_assert(options);
|
||||
log_assert(game_data_path);
|
||||
log_assert(argc >= 0);
|
||||
log_assert(argv);
|
||||
log_assert(options);
|
||||
log_assert(game_data_path);
|
||||
|
||||
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
|
||||
return;
|
||||
}
|
||||
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
hook_core_piu_log_init(argc, argv);
|
||||
hook_core_piu_log_init(argc, argv);
|
||||
|
||||
if (!f2hook_options_init(argc, argv, options)) {
|
||||
exit(0);
|
||||
}
|
||||
if (!f2hook_options_init(argc, argv, options)) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
hook_core_piu_log_info(argc, argv);
|
||||
hook_core_piu_log_info(argc, argv);
|
||||
|
||||
*game_data_path = hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
|
||||
*game_data_path =
|
||||
hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
|
||||
|
||||
hook_core_piu_utils_verify_root_user();
|
||||
hook_core_piu_utils_verify_root_user();
|
||||
|
||||
hook_core_piu_utils_fix_locale();
|
||||
hook_core_piu_utils_fix_locale();
|
||||
|
||||
log_info("Initializing, piu game data path: %s", *game_data_path);
|
||||
log_info("Initializing, piu game data path: %s", *game_data_path);
|
||||
}
|
||||
|
||||
static void f2hook_patch_fs_init(struct f2hook_options* options)
|
||||
static void f2hook_patch_fs_init(struct f2hook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
patch_hook_mon_init(
|
||||
options->patch.hook_mon.io,
|
||||
options->patch.hook_mon.file,
|
||||
options->patch.hook_mon.fs,
|
||||
options->patch.hook_mon.usb,
|
||||
options->patch.hook_mon.open);
|
||||
patch_hook_mon_init(
|
||||
options->patch.hook_mon.io,
|
||||
options->patch.hook_mon.file,
|
||||
options->patch.hook_mon.fs,
|
||||
options->patch.hook_mon.usb,
|
||||
options->patch.hook_mon.open);
|
||||
|
||||
patch_redir_init();
|
||||
patch_redir_init();
|
||||
}
|
||||
|
||||
static void f2hook_fs_redir_settings(struct f2hook_options* options)
|
||||
static void f2hook_fs_redir_settings(struct f2hook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
if (options->game.settings) {
|
||||
if (!util_fs_path_exists(options->game.settings)) {
|
||||
log_info("Settings path %s does not exist, creating", options->game.settings);
|
||||
if (options->game.settings) {
|
||||
if (!util_fs_path_exists(options->game.settings)) {
|
||||
log_info(
|
||||
"Settings path %s does not exist, creating", options->game.settings);
|
||||
|
||||
if (!util_fs_mkdir(options->game.settings)) {
|
||||
log_error("Creating directory %s failed", options->game.settings);
|
||||
}
|
||||
}
|
||||
|
||||
char* abs_path = util_fs_get_abs_path(options->game.settings);
|
||||
|
||||
cnh_redir_add("/SETTINGS", abs_path);
|
||||
free(abs_path);
|
||||
} else {
|
||||
log_warn("No settings path specified");
|
||||
if (!util_fs_mkdir(options->game.settings)) {
|
||||
log_error("Creating directory %s failed", options->game.settings);
|
||||
}
|
||||
}
|
||||
|
||||
char *abs_path = util_fs_get_abs_path(options->game.settings);
|
||||
|
||||
cnh_redir_add("/SETTINGS", abs_path);
|
||||
free(abs_path);
|
||||
} else {
|
||||
log_warn("No settings path specified");
|
||||
}
|
||||
}
|
||||
|
||||
static void f2hook_fs_redir_usb()
|
||||
{
|
||||
/* Needed on newer kernels */
|
||||
cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices");
|
||||
patch_usbfs_init();
|
||||
/* Needed on newer kernels */
|
||||
cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices");
|
||||
patch_usbfs_init();
|
||||
}
|
||||
|
||||
static void f2hook_fs_redirs_init(struct f2hook_options* options, const char* game_data_path)
|
||||
static void f2hook_fs_redirs_init(
|
||||
struct f2hook_options *options, const char *game_data_path)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(game_data_path);
|
||||
log_assert(options);
|
||||
log_assert(game_data_path);
|
||||
|
||||
f2hook_fs_redir_settings(options);
|
||||
f2hook_fs_redir_settings(options);
|
||||
|
||||
f2hook_fs_redir_usb();
|
||||
f2hook_fs_redir_usb();
|
||||
}
|
||||
|
||||
static void f2hook_patch_fs_mounting_init()
|
||||
{
|
||||
patch_mounts_init();
|
||||
patch_mounts_init();
|
||||
|
||||
patch_usb_mnt_init();
|
||||
patch_usb_mnt_init();
|
||||
}
|
||||
|
||||
static void f2hook_patch_gfx_init(struct f2hook_options* options)
|
||||
static void f2hook_patch_gfx_init(struct f2hook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
patch_gfx_init();
|
||||
patch_gfx_init();
|
||||
|
||||
if (options->patch.gfx.windowed) {
|
||||
patch_gfx_force_window_mode();
|
||||
}
|
||||
if (options->patch.gfx.windowed) {
|
||||
patch_gfx_force_window_mode();
|
||||
}
|
||||
}
|
||||
|
||||
static void f2hook_patch_main_loop_init(struct f2hook_options* options)
|
||||
static void f2hook_patch_main_loop_init(struct f2hook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
patch_main_loop_init(false, options->patch.main_loop.disable_built_in_inputs, false);
|
||||
patch_main_loop_init(
|
||||
false, options->patch.main_loop.disable_built_in_inputs, false);
|
||||
|
||||
if (options->patch.main_loop.x11_input_handler_api_lib) {
|
||||
char* abs_path_x11_input_hook_lib = util_fs_get_abs_path(options->patch.main_loop.x11_input_handler_api_lib);
|
||||
if (options->patch.main_loop.x11_input_handler_api_lib) {
|
||||
char *abs_path_x11_input_hook_lib = util_fs_get_abs_path(
|
||||
options->patch.main_loop.x11_input_handler_api_lib);
|
||||
|
||||
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
|
||||
free(abs_path_x11_input_hook_lib);
|
||||
}
|
||||
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
|
||||
free(abs_path_x11_input_hook_lib);
|
||||
}
|
||||
}
|
||||
|
||||
static void f2hook_patch_sound_init(struct f2hook_options* options)
|
||||
static void f2hook_patch_sound_init(struct f2hook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
patch_sound_init(options->patch.sound.device);
|
||||
patch_axmier_block_init();
|
||||
patch_sound_init(options->patch.sound.device);
|
||||
patch_axmier_block_init();
|
||||
}
|
||||
|
||||
static void f2hook_patch_sigsegv_init(struct f2hook_options* options)
|
||||
static void f2hook_patch_sigsegv_init(struct f2hook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
|
||||
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
|
||||
}
|
||||
|
||||
static void f2hook_patch_dongle_init()
|
||||
{
|
||||
patch_hasp_init((const uint8_t*) _binary_f2hook_hasp_key_start,
|
||||
((uintptr_t) &_binary_f2hook_hasp_key_end - (uintptr_t) &_binary_f2hook_hasp_key_start));
|
||||
patch_hasp_init(
|
||||
(const uint8_t *) _binary_f2hook_hasp_key_start,
|
||||
((uintptr_t) &_binary_f2hook_hasp_key_end -
|
||||
(uintptr_t) &_binary_f2hook_hasp_key_start));
|
||||
}
|
||||
|
||||
static void f2hook_patch_hdd_check_init()
|
||||
{
|
||||
patch_hdd_check_init((const uint8_t*) _binary_f2hook_hdd_raw_start,
|
||||
((uintptr_t) &_binary_f2hook_hdd_raw_end - (uintptr_t) &_binary_f2hook_hdd_raw_start));
|
||||
patch_hdd_check_init(
|
||||
(const uint8_t *) _binary_f2hook_hdd_raw_start,
|
||||
((uintptr_t) &_binary_f2hook_hdd_raw_end -
|
||||
(uintptr_t) &_binary_f2hook_hdd_raw_start));
|
||||
}
|
||||
|
||||
static void f2hook_patch_piuio_init(struct f2hook_options* options)
|
||||
static void f2hook_patch_piuio_init(struct f2hook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
/* Hook before IO emulation */
|
||||
if (options->patch.piuio.exit_test_serv) {
|
||||
patch_piuio_exit_init();
|
||||
}
|
||||
/* Hook before IO emulation */
|
||||
if (options->patch.piuio.exit_test_serv) {
|
||||
patch_piuio_exit_init();
|
||||
}
|
||||
|
||||
patch_usb_init_fix_init();
|
||||
patch_usb_emu_init();
|
||||
patch_usb_init_fix_init();
|
||||
patch_usb_emu_init();
|
||||
|
||||
if (options->patch.piuio.api_lib) {
|
||||
char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
|
||||
if (options->patch.piuio.api_lib) {
|
||||
char *abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
|
||||
|
||||
patch_piuio_init(abs_path_iolib);
|
||||
free(abs_path_iolib);
|
||||
}
|
||||
patch_piuio_init(abs_path_iolib);
|
||||
free(abs_path_iolib);
|
||||
}
|
||||
}
|
||||
|
||||
void f2hook_constructor(void)
|
||||
{
|
||||
/* Nothing here */
|
||||
/* Nothing here */
|
||||
}
|
||||
|
||||
void f2hook_destructor(void)
|
||||
{
|
||||
/* Nothing here */
|
||||
/* Nothing here */
|
||||
}
|
||||
|
||||
void f2hook_trap_before_main(int argc, char** argv)
|
||||
void f2hook_trap_before_main(int argc, char **argv)
|
||||
{
|
||||
log_assert(argc >= 0);
|
||||
log_assert(argv);
|
||||
log_assert(argc >= 0);
|
||||
log_assert(argv);
|
||||
|
||||
char* game_data_path;
|
||||
struct f2hook_options options;
|
||||
char *game_data_path;
|
||||
struct f2hook_options options;
|
||||
|
||||
f2hook_bootstrapping(argc, argv, &options, &game_data_path);
|
||||
f2hook_patch_fs_init(&options);
|
||||
f2hook_fs_redirs_init(&options, game_data_path);
|
||||
f2hook_patch_fs_mounting_init();
|
||||
f2hook_patch_gfx_init(&options);
|
||||
f2hook_patch_main_loop_init(&options);
|
||||
f2hook_patch_sound_init(&options);
|
||||
f2hook_patch_sigsegv_init(&options);
|
||||
f2hook_patch_dongle_init();
|
||||
f2hook_patch_hdd_check_init();
|
||||
f2hook_patch_piuio_init(&options);
|
||||
f2hook_bootstrapping(argc, argv, &options, &game_data_path);
|
||||
f2hook_patch_fs_init(&options);
|
||||
f2hook_fs_redirs_init(&options, game_data_path);
|
||||
f2hook_patch_fs_mounting_init();
|
||||
f2hook_patch_gfx_init(&options);
|
||||
f2hook_patch_main_loop_init(&options);
|
||||
f2hook_patch_sound_init(&options);
|
||||
f2hook_patch_sigsegv_init(&options);
|
||||
f2hook_patch_dongle_init();
|
||||
f2hook_patch_hdd_check_init();
|
||||
f2hook_patch_piuio_init(&options);
|
||||
|
||||
free(game_data_path);
|
||||
free(game_data_path);
|
||||
|
||||
log_info("Hooking finished");
|
||||
log_info("Hooking finished");
|
||||
}
|
||||
|
||||
void f2hook_trap_after_main(void)
|
||||
{
|
||||
patch_piuio_shutdown();
|
||||
patch_piuio_shutdown();
|
||||
}
|
||||
|
||||
LIB_MAIN_CONSTRUCTOR(f2hook_constructor);
|
||||
|
||||
+66
-44
@@ -9,14 +9,19 @@
|
||||
#define F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_IO "patch.hook_mon.io"
|
||||
#define F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN "patch.hook_mon.open"
|
||||
#define F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb"
|
||||
#define F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS "patch.hook_main_loop.disable_built_in_inputs"
|
||||
#define F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER "patch_hook_main_loop.x11_input_handler"
|
||||
#define F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS \
|
||||
"patch.hook_main_loop.disable_built_in_inputs"
|
||||
#define F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER \
|
||||
"patch_hook_main_loop.x11_input_handler"
|
||||
#define F2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER "patch.net_profile.server"
|
||||
#define F2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID "patch.net_profile.machine_id"
|
||||
#define F2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID \
|
||||
"patch.net_profile.machine_id"
|
||||
#define F2HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib"
|
||||
#define F2HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv"
|
||||
#define F2HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV \
|
||||
"patch.piuio_exit.test_serv"
|
||||
#define F2HOOK_OPTIONS_STR_PATCH_SOUND_DEVICE "patch.sound.device"
|
||||
#define F2HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV "patch.sigsegv.halt_on_segv"
|
||||
#define F2HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV \
|
||||
"patch.sigsegv.halt_on_segv"
|
||||
#define F2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file"
|
||||
#define F2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level"
|
||||
|
||||
@@ -72,21 +77,24 @@ const struct util_options_def f2hook_options_def[] = {
|
||||
},
|
||||
{
|
||||
.name = F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS,
|
||||
.description = "Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3)",
|
||||
.description = "Disable the built in keyboard inputs for test (F1), "
|
||||
"service (F2) and clear (F3)",
|
||||
.param = 'k',
|
||||
.type = UTIL_OPTIONS_TYPE_BOOL,
|
||||
.default_value.b = false,
|
||||
},
|
||||
{
|
||||
.name = F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER,
|
||||
.description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs",
|
||||
.description = "Path to a library implementing the x11-input-handler "
|
||||
"api to capture X11 keyboard inputs",
|
||||
.param = 'q',
|
||||
.type = UTIL_OPTIONS_TYPE_STR,
|
||||
.default_value.str = NULL,
|
||||
},
|
||||
{
|
||||
.name = F2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER,
|
||||
.description = "Address and port of pumpnet server (e.g. 127.0.0.1:1234)",
|
||||
.description =
|
||||
"Address and port of pumpnet server (e.g. 127.0.0.1:1234)",
|
||||
.param = 'n',
|
||||
.type = UTIL_OPTIONS_TYPE_STR,
|
||||
.default_value.str = NULL,
|
||||
@@ -100,7 +108,8 @@ const struct util_options_def f2hook_options_def[] = {
|
||||
},
|
||||
{
|
||||
.name = F2HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB,
|
||||
.description = "Path to library implementing the piuio api for piuio emulation",
|
||||
.description =
|
||||
"Path to library implementing the piuio api for piuio emulation",
|
||||
.param = 'p',
|
||||
.type = UTIL_OPTIONS_TYPE_STR,
|
||||
.default_value.str = NULL,
|
||||
@@ -151,45 +160,58 @@ const struct util_options_defs f2hook_options_defs = {
|
||||
.ndefs = lengthof(f2hook_options_def)
|
||||
};
|
||||
|
||||
bool f2hook_options_init(int argc, char** argv, struct f2hook_options* options)
|
||||
bool f2hook_options_init(int argc, char **argv, struct f2hook_options *options)
|
||||
{
|
||||
log_assert(argv);
|
||||
log_assert(options);
|
||||
log_assert(argv);
|
||||
log_assert(options);
|
||||
|
||||
struct util_options_opts* options_opt;
|
||||
struct util_options_opts *options_opt;
|
||||
|
||||
util_options_init(argc, argv);
|
||||
options_opt = util_options_get(&f2hook_options_defs);
|
||||
util_options_init(argc, argv);
|
||||
options_opt = util_options_get(&f2hook_options_defs);
|
||||
|
||||
if (!options_opt) {
|
||||
return false;
|
||||
}
|
||||
if (!options_opt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
options->game.settings = util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_GAME_SETTINGS);
|
||||
options->patch.gfx.windowed = util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
|
||||
options->patch.hook_mon.file = util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
|
||||
options->patch.hook_mon.fs = util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
|
||||
options->patch.hook_mon.io = util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
|
||||
options->patch.hook_mon.open = util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
|
||||
options->patch.hook_mon.usb = util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
|
||||
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(options_opt,
|
||||
F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
|
||||
options->patch.main_loop.x11_input_handler_api_lib =
|
||||
util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
|
||||
options->patch.net.server = util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER);
|
||||
options->patch.net.machine_id = strtoul(
|
||||
util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID),
|
||||
NULL,
|
||||
16);
|
||||
options->patch.piuio.api_lib = util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
|
||||
options->patch.piuio.exit_test_serv =
|
||||
util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
|
||||
options->patch.sound.device = util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
|
||||
options->patch.sigsegv.halt_on_segv =
|
||||
util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
|
||||
options->log.file = util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
|
||||
options->log.level =
|
||||
(enum util_log_level) util_options_get_int(options_opt, F2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
|
||||
options->game.settings =
|
||||
util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_GAME_SETTINGS);
|
||||
options->patch.gfx.windowed =
|
||||
util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
|
||||
options->patch.hook_mon.file = util_options_get_bool(
|
||||
options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
|
||||
options->patch.hook_mon.fs =
|
||||
util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
|
||||
options->patch.hook_mon.io =
|
||||
util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
|
||||
options->patch.hook_mon.open = util_options_get_bool(
|
||||
options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
|
||||
options->patch.hook_mon.usb =
|
||||
util_options_get_bool(options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
|
||||
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(
|
||||
options_opt,
|
||||
F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
|
||||
options->patch.main_loop.x11_input_handler_api_lib = util_options_get_str(
|
||||
options_opt, F2HOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
|
||||
options->patch.net.server = util_options_get_str(
|
||||
options_opt, F2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER);
|
||||
options->patch.net.machine_id = strtoul(
|
||||
util_options_get_str(
|
||||
options_opt, F2HOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID),
|
||||
NULL,
|
||||
16);
|
||||
options->patch.piuio.api_lib =
|
||||
util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
|
||||
options->patch.piuio.exit_test_serv = util_options_get_bool(
|
||||
options_opt, F2HOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
|
||||
options->patch.sound.device =
|
||||
util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
|
||||
options->patch.sigsegv.halt_on_segv = util_options_get_bool(
|
||||
options_opt, F2HOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
|
||||
options->log.file =
|
||||
util_options_get_str(options_opt, F2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
|
||||
options->log.level = (enum util_log_level) util_options_get_int(
|
||||
options_opt, F2HOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
+38
-38
@@ -7,53 +7,53 @@
|
||||
#include "util/log.h"
|
||||
|
||||
struct f2hook_options {
|
||||
struct game {
|
||||
const char* settings;
|
||||
} game;
|
||||
struct game {
|
||||
const char *settings;
|
||||
} game;
|
||||
|
||||
struct patch {
|
||||
struct gfx {
|
||||
bool windowed;
|
||||
} gfx;
|
||||
struct patch {
|
||||
struct gfx {
|
||||
bool windowed;
|
||||
} gfx;
|
||||
|
||||
struct hook_mon {
|
||||
bool file;
|
||||
bool fs;
|
||||
bool io;
|
||||
bool open;
|
||||
bool usb;
|
||||
} hook_mon;
|
||||
struct hook_mon {
|
||||
bool file;
|
||||
bool fs;
|
||||
bool io;
|
||||
bool open;
|
||||
bool usb;
|
||||
} hook_mon;
|
||||
|
||||
struct main_loop {
|
||||
bool disable_built_in_inputs;
|
||||
const char* x11_input_handler_api_lib;
|
||||
} main_loop;
|
||||
struct main_loop {
|
||||
bool disable_built_in_inputs;
|
||||
const char *x11_input_handler_api_lib;
|
||||
} main_loop;
|
||||
|
||||
struct net {
|
||||
const char* server;
|
||||
uint32_t machine_id;
|
||||
} net;
|
||||
struct net {
|
||||
const char *server;
|
||||
uint32_t machine_id;
|
||||
} net;
|
||||
|
||||
struct piuio {
|
||||
const char* api_lib;
|
||||
bool exit_test_serv;
|
||||
} piuio;
|
||||
struct piuio {
|
||||
const char *api_lib;
|
||||
bool exit_test_serv;
|
||||
} piuio;
|
||||
|
||||
struct sound {
|
||||
const char* device;
|
||||
} sound;
|
||||
struct sound {
|
||||
const char *device;
|
||||
} sound;
|
||||
|
||||
struct sigsegv {
|
||||
bool halt_on_segv;
|
||||
} sigsegv;
|
||||
} patch;
|
||||
struct sigsegv {
|
||||
bool halt_on_segv;
|
||||
} sigsegv;
|
||||
} patch;
|
||||
|
||||
struct log {
|
||||
const char* file;
|
||||
enum util_log_level level;
|
||||
} log;
|
||||
struct log {
|
||||
const char *file;
|
||||
enum util_log_level level;
|
||||
} log;
|
||||
};
|
||||
|
||||
bool f2hook_options_init(int argc, char** argv, struct f2hook_options* options);
|
||||
bool f2hook_options_init(int argc, char **argv, struct f2hook_options *options);
|
||||
|
||||
#endif
|
||||
|
||||
+124
-111
@@ -17,8 +17,8 @@
|
||||
#include "hook/patch/main-loop.h"
|
||||
#include "hook/patch/microdog40.h"
|
||||
#include "hook/patch/mounts.h"
|
||||
#include "hook/patch/piuio.h"
|
||||
#include "hook/patch/piuio-exit.h"
|
||||
#include "hook/patch/piuio.h"
|
||||
#include "hook/patch/redir.h"
|
||||
#include "hook/patch/sigsegv.h"
|
||||
#include "hook/patch/sound.h"
|
||||
@@ -39,202 +39,215 @@ extern const uint8_t _binary_fexhook_hdd_raw_end[];
|
||||
extern const uint8_t _binary_fexhook_dog_key_start[];
|
||||
extern const uint8_t _binary_fexhook_dog_key_end[];
|
||||
|
||||
static void fexhook_bootstrapping(int argc, char** argv, struct fexhook_options* options, char** game_data_path)
|
||||
static void fexhook_bootstrapping(
|
||||
int argc,
|
||||
char **argv,
|
||||
struct fexhook_options *options,
|
||||
char **game_data_path)
|
||||
{
|
||||
log_assert(argc >= 0);
|
||||
log_assert(argv);
|
||||
log_assert(options);
|
||||
log_assert(game_data_path);
|
||||
log_assert(argc >= 0);
|
||||
log_assert(argv);
|
||||
log_assert(options);
|
||||
log_assert(game_data_path);
|
||||
|
||||
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
|
||||
return;
|
||||
}
|
||||
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
hook_core_piu_log_init(argc, argv);
|
||||
hook_core_piu_log_init(argc, argv);
|
||||
|
||||
if (!fexhook_options_init(argc, argv, options)) {
|
||||
exit(0);
|
||||
}
|
||||
if (!fexhook_options_init(argc, argv, options)) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
hook_core_piu_log_info(argc, argv);
|
||||
hook_core_piu_log_info(argc, argv);
|
||||
|
||||
*game_data_path = hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
|
||||
*game_data_path =
|
||||
hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
|
||||
|
||||
hook_core_piu_utils_verify_root_user();
|
||||
hook_core_piu_utils_verify_root_user();
|
||||
|
||||
log_info("Initializing, piu game data path: %s", *game_data_path);
|
||||
log_info("Initializing, piu game data path: %s", *game_data_path);
|
||||
}
|
||||
|
||||
static void fexhook_patch_fs_init(struct fexhook_options* options)
|
||||
static void fexhook_patch_fs_init(struct fexhook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
patch_hook_mon_init(
|
||||
options->patch.hook_mon.io,
|
||||
options->patch.hook_mon.file,
|
||||
options->patch.hook_mon.fs,
|
||||
options->patch.hook_mon.usb,
|
||||
options->patch.hook_mon.open);
|
||||
patch_hook_mon_init(
|
||||
options->patch.hook_mon.io,
|
||||
options->patch.hook_mon.file,
|
||||
options->patch.hook_mon.fs,
|
||||
options->patch.hook_mon.usb,
|
||||
options->patch.hook_mon.open);
|
||||
|
||||
patch_redir_init();
|
||||
patch_redir_init();
|
||||
}
|
||||
|
||||
static void fexhook_fs_redir_settings(struct fexhook_options* options)
|
||||
static void fexhook_fs_redir_settings(struct fexhook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
if (options->game.settings) {
|
||||
if (!util_fs_path_exists(options->game.settings)) {
|
||||
log_info("Settings path %s does not exist, creating", options->game.settings);
|
||||
if (options->game.settings) {
|
||||
if (!util_fs_path_exists(options->game.settings)) {
|
||||
log_info(
|
||||
"Settings path %s does not exist, creating", options->game.settings);
|
||||
|
||||
if (!util_fs_mkdir(options->game.settings)) {
|
||||
log_error("Creating directory %s failed", options->game.settings);
|
||||
}
|
||||
}
|
||||
|
||||
char* abs_path = util_fs_get_abs_path(options->game.settings);
|
||||
|
||||
cnh_redir_add("/SETTINGS", abs_path);
|
||||
free(abs_path);
|
||||
} else {
|
||||
log_warn("No settings path specified");
|
||||
if (!util_fs_mkdir(options->game.settings)) {
|
||||
log_error("Creating directory %s failed", options->game.settings);
|
||||
}
|
||||
}
|
||||
|
||||
char *abs_path = util_fs_get_abs_path(options->game.settings);
|
||||
|
||||
cnh_redir_add("/SETTINGS", abs_path);
|
||||
free(abs_path);
|
||||
} else {
|
||||
log_warn("No settings path specified");
|
||||
}
|
||||
}
|
||||
|
||||
static void fexhook_fs_redir_usb()
|
||||
{
|
||||
/* Needed on newer kernels */
|
||||
cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices");
|
||||
patch_usbfs_init();
|
||||
/* Needed on newer kernels */
|
||||
cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices");
|
||||
patch_usbfs_init();
|
||||
}
|
||||
|
||||
static void fexhook_fs_redirs_init(struct fexhook_options* options, const char* game_data_path)
|
||||
static void fexhook_fs_redirs_init(
|
||||
struct fexhook_options *options, const char *game_data_path)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(game_data_path);
|
||||
log_assert(options);
|
||||
log_assert(game_data_path);
|
||||
|
||||
fexhook_fs_redir_settings(options);
|
||||
fexhook_fs_redir_settings(options);
|
||||
|
||||
fexhook_fs_redir_usb();
|
||||
fexhook_fs_redir_usb();
|
||||
}
|
||||
|
||||
static void fexhook_patch_fs_mounting_init()
|
||||
{
|
||||
patch_mounts_init();
|
||||
patch_mounts_init();
|
||||
|
||||
patch_usb_mnt_init();
|
||||
patch_usb_mnt_init();
|
||||
}
|
||||
|
||||
static void fexhook_patch_gfx_init(struct fexhook_options* options)
|
||||
static void fexhook_patch_gfx_init(struct fexhook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
patch_gfx_init();
|
||||
patch_gfx_init();
|
||||
|
||||
if (options->patch.gfx.windowed) {
|
||||
patch_gfx_force_window_mode();
|
||||
}
|
||||
if (options->patch.gfx.windowed) {
|
||||
patch_gfx_force_window_mode();
|
||||
}
|
||||
}
|
||||
|
||||
static void fexhook_patch_main_loop_init(struct fexhook_options* options)
|
||||
static void fexhook_patch_main_loop_init(struct fexhook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
patch_main_loop_init(false, options->patch.main_loop.disable_built_in_inputs, false);
|
||||
patch_main_loop_init(
|
||||
false, options->patch.main_loop.disable_built_in_inputs, false);
|
||||
|
||||
if (options->patch.main_loop.x11_input_handler_api_lib) {
|
||||
char* abs_path_x11_input_hook_lib = util_fs_get_abs_path(options->patch.main_loop.x11_input_handler_api_lib);
|
||||
if (options->patch.main_loop.x11_input_handler_api_lib) {
|
||||
char *abs_path_x11_input_hook_lib = util_fs_get_abs_path(
|
||||
options->patch.main_loop.x11_input_handler_api_lib);
|
||||
|
||||
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
|
||||
free(abs_path_x11_input_hook_lib);
|
||||
}
|
||||
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
|
||||
free(abs_path_x11_input_hook_lib);
|
||||
}
|
||||
}
|
||||
|
||||
static void fexhook_patch_sound_init(struct fexhook_options* options)
|
||||
static void fexhook_patch_sound_init(struct fexhook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
patch_sound_init(options->patch.sound.device);
|
||||
patch_axmier_block_init();
|
||||
patch_sound_init(options->patch.sound.device);
|
||||
patch_axmier_block_init();
|
||||
}
|
||||
|
||||
static void fexhook_patch_sigsegv_init(struct fexhook_options* options)
|
||||
static void fexhook_patch_sigsegv_init(struct fexhook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
|
||||
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
|
||||
}
|
||||
|
||||
static void fexhook_patch_dongle_init()
|
||||
{
|
||||
patch_microdog40_init((const uint8_t*) _binary_fexhook_dog_key_start,
|
||||
((uintptr_t) &_binary_fexhook_dog_key_end - (uintptr_t) &_binary_fexhook_dog_key_start));
|
||||
patch_microdog40_init(
|
||||
(const uint8_t *) _binary_fexhook_dog_key_start,
|
||||
((uintptr_t) &_binary_fexhook_dog_key_end -
|
||||
(uintptr_t) &_binary_fexhook_dog_key_start));
|
||||
}
|
||||
|
||||
static void fexhook_patch_hdd_check_init()
|
||||
{
|
||||
patch_hdd_check_init((const uint8_t*) _binary_fexhook_hdd_raw_start,
|
||||
((uintptr_t) &_binary_fexhook_hdd_raw_end - (uintptr_t) &_binary_fexhook_hdd_raw_start));
|
||||
patch_hdd_check_init(
|
||||
(const uint8_t *) _binary_fexhook_hdd_raw_start,
|
||||
((uintptr_t) &_binary_fexhook_hdd_raw_end -
|
||||
(uintptr_t) &_binary_fexhook_hdd_raw_start));
|
||||
}
|
||||
|
||||
static void fexhook_patch_piuio_init(struct fexhook_options* options)
|
||||
static void fexhook_patch_piuio_init(struct fexhook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
/* Hook before IO emulation */
|
||||
if (options->patch.piuio.exit_test_serv) {
|
||||
patch_piuio_exit_init();
|
||||
}
|
||||
/* Hook before IO emulation */
|
||||
if (options->patch.piuio.exit_test_serv) {
|
||||
patch_piuio_exit_init();
|
||||
}
|
||||
|
||||
patch_usb_init_fix_init();
|
||||
patch_usb_emu_init();
|
||||
patch_usb_init_fix_init();
|
||||
patch_usb_emu_init();
|
||||
|
||||
if (options->patch.piuio.api_lib) {
|
||||
char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
|
||||
if (options->patch.piuio.api_lib) {
|
||||
char *abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
|
||||
|
||||
patch_piuio_init(abs_path_iolib);
|
||||
free(abs_path_iolib);
|
||||
}
|
||||
patch_piuio_init(abs_path_iolib);
|
||||
free(abs_path_iolib);
|
||||
}
|
||||
}
|
||||
|
||||
void fexhook_constructor(void)
|
||||
{
|
||||
/* Nothing here */
|
||||
/* Nothing here */
|
||||
}
|
||||
|
||||
void fexhook_destructor(void)
|
||||
{
|
||||
/* Nothing here */
|
||||
/* Nothing here */
|
||||
}
|
||||
|
||||
void fexhook_trap_before_main(int argc, char** argv)
|
||||
void fexhook_trap_before_main(int argc, char **argv)
|
||||
{
|
||||
log_assert(argc >= 0);
|
||||
log_assert(argv);
|
||||
log_assert(argc >= 0);
|
||||
log_assert(argv);
|
||||
|
||||
char* game_data_path;
|
||||
struct fexhook_options options;
|
||||
char *game_data_path;
|
||||
struct fexhook_options options;
|
||||
|
||||
fexhook_bootstrapping(argc, argv, &options, &game_data_path);
|
||||
fexhook_patch_fs_init(&options);
|
||||
fexhook_fs_redirs_init(&options, game_data_path);
|
||||
fexhook_patch_fs_mounting_init();
|
||||
fexhook_patch_gfx_init(&options);
|
||||
fexhook_patch_main_loop_init(&options);
|
||||
fexhook_patch_sound_init(&options);
|
||||
fexhook_patch_sigsegv_init(&options);
|
||||
fexhook_patch_dongle_init();
|
||||
fexhook_patch_hdd_check_init();
|
||||
fexhook_patch_piuio_init(&options);
|
||||
fexhook_bootstrapping(argc, argv, &options, &game_data_path);
|
||||
fexhook_patch_fs_init(&options);
|
||||
fexhook_fs_redirs_init(&options, game_data_path);
|
||||
fexhook_patch_fs_mounting_init();
|
||||
fexhook_patch_gfx_init(&options);
|
||||
fexhook_patch_main_loop_init(&options);
|
||||
fexhook_patch_sound_init(&options);
|
||||
fexhook_patch_sigsegv_init(&options);
|
||||
fexhook_patch_dongle_init();
|
||||
fexhook_patch_hdd_check_init();
|
||||
fexhook_patch_piuio_init(&options);
|
||||
|
||||
free(game_data_path);
|
||||
free(game_data_path);
|
||||
|
||||
log_info("Hooking finished");
|
||||
log_info("Hooking finished");
|
||||
}
|
||||
|
||||
void fexhook_trap_after_main(void)
|
||||
{
|
||||
patch_piuio_shutdown();
|
||||
patch_piuio_shutdown();
|
||||
}
|
||||
|
||||
LIB_MAIN_CONSTRUCTOR(fexhook_constructor);
|
||||
|
||||
+69
-45
@@ -9,14 +9,19 @@
|
||||
#define FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO "patch.hook_mon.io"
|
||||
#define FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN "patch.hook_mon.open"
|
||||
#define FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb"
|
||||
#define FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS "patch.hook_main_loop.disable_built_in_inputs"
|
||||
#define FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER "patch_hook_main_loop.x11_input_handler"
|
||||
#define FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS \
|
||||
"patch.hook_main_loop.disable_built_in_inputs"
|
||||
#define FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER \
|
||||
"patch_hook_main_loop.x11_input_handler"
|
||||
#define FEXHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER "patch.net_profile.server"
|
||||
#define FEXHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID "patch.net_profile.machine_id"
|
||||
#define FEXHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID \
|
||||
"patch.net_profile.machine_id"
|
||||
#define FEXHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib"
|
||||
#define FEXHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv"
|
||||
#define FEXHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV \
|
||||
"patch.piuio_exit.test_serv"
|
||||
#define FEXHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE "patch.sound.device"
|
||||
#define FEXHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV "patch.sigsegv.halt_on_segv"
|
||||
#define FEXHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV \
|
||||
"patch.sigsegv.halt_on_segv"
|
||||
#define FEXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file"
|
||||
#define FEXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level"
|
||||
|
||||
@@ -71,22 +76,26 @@ const struct util_options_def fexhook_options_def[] = {
|
||||
.default_value.b = false,
|
||||
},
|
||||
{
|
||||
.name = FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS,
|
||||
.description = "Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3)",
|
||||
.name =
|
||||
FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS,
|
||||
.description = "Disable the built in keyboard inputs for test (F1), "
|
||||
"service (F2) and clear (F3)",
|
||||
.param = 'k',
|
||||
.type = UTIL_OPTIONS_TYPE_BOOL,
|
||||
.default_value.b = false,
|
||||
},
|
||||
{
|
||||
.name = FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER,
|
||||
.description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs",
|
||||
.description = "Path to a library implementing the x11-input-handler "
|
||||
"api to capture X11 keyboard inputs",
|
||||
.param = 'q',
|
||||
.type = UTIL_OPTIONS_TYPE_STR,
|
||||
.default_value.str = NULL,
|
||||
},
|
||||
{
|
||||
.name = FEXHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER,
|
||||
.description = "Address and port of pumpnet server (e.g. 127.0.0.1:1234)",
|
||||
.description =
|
||||
"Address and port of pumpnet server (e.g. 127.0.0.1:1234)",
|
||||
.param = 'n',
|
||||
.type = UTIL_OPTIONS_TYPE_STR,
|
||||
.default_value.str = NULL,
|
||||
@@ -100,7 +109,8 @@ const struct util_options_def fexhook_options_def[] = {
|
||||
},
|
||||
{
|
||||
.name = FEXHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB,
|
||||
.description = "Path to library implementing the piuio api for piuio emulation",
|
||||
.description =
|
||||
"Path to library implementing the piuio api for piuio emulation",
|
||||
.param = 'p',
|
||||
.type = UTIL_OPTIONS_TYPE_STR,
|
||||
.default_value.str = NULL,
|
||||
@@ -151,45 +161,59 @@ const struct util_options_defs fexhook_options_defs = {
|
||||
.ndefs = lengthof(fexhook_options_def)
|
||||
};
|
||||
|
||||
bool fexhook_options_init(int argc, char** argv, struct fexhook_options* options)
|
||||
bool fexhook_options_init(
|
||||
int argc, char **argv, struct fexhook_options *options)
|
||||
{
|
||||
log_assert(argv);
|
||||
log_assert(options);
|
||||
log_assert(argv);
|
||||
log_assert(options);
|
||||
|
||||
struct util_options_opts* options_opt;
|
||||
struct util_options_opts *options_opt;
|
||||
|
||||
util_options_init(argc, argv);
|
||||
options_opt = util_options_get(&fexhook_options_defs);
|
||||
util_options_init(argc, argv);
|
||||
options_opt = util_options_get(&fexhook_options_defs);
|
||||
|
||||
if (!options_opt) {
|
||||
return false;
|
||||
}
|
||||
if (!options_opt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
options->game.settings = util_options_get_str(options_opt, FEXHOOK_OPTIONS_STR_GAME_SETTINGS);
|
||||
options->patch.gfx.windowed = util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
|
||||
options->patch.hook_mon.file = util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
|
||||
options->patch.hook_mon.fs = util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
|
||||
options->patch.hook_mon.io = util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
|
||||
options->patch.hook_mon.open = util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
|
||||
options->patch.hook_mon.usb = util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
|
||||
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(options_opt,
|
||||
FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
|
||||
options->patch.main_loop.x11_input_handler_api_lib =
|
||||
util_options_get_str(options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
|
||||
options->patch.net.server = util_options_get_str(options_opt, FEXHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER);
|
||||
options->patch.net.machine_id = strtoul(
|
||||
util_options_get_str(options_opt, FEXHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID),
|
||||
NULL,
|
||||
16);
|
||||
options->patch.piuio.api_lib = util_options_get_str(options_opt, FEXHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
|
||||
options->patch.piuio.exit_test_serv =
|
||||
util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
|
||||
options->patch.sound.device = util_options_get_str(options_opt, FEXHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
|
||||
options->patch.sigsegv.halt_on_segv =
|
||||
util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
|
||||
options->log.file = util_options_get_str(options_opt, FEXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
|
||||
options->log.level =
|
||||
(enum util_log_level) util_options_get_int(options_opt, FEXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
|
||||
options->game.settings =
|
||||
util_options_get_str(options_opt, FEXHOOK_OPTIONS_STR_GAME_SETTINGS);
|
||||
options->patch.gfx.windowed = util_options_get_bool(
|
||||
options_opt, FEXHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
|
||||
options->patch.hook_mon.file = util_options_get_bool(
|
||||
options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
|
||||
options->patch.hook_mon.fs =
|
||||
util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
|
||||
options->patch.hook_mon.io =
|
||||
util_options_get_bool(options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
|
||||
options->patch.hook_mon.open = util_options_get_bool(
|
||||
options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
|
||||
options->patch.hook_mon.usb = util_options_get_bool(
|
||||
options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
|
||||
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(
|
||||
options_opt,
|
||||
FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
|
||||
options->patch.main_loop.x11_input_handler_api_lib = util_options_get_str(
|
||||
options_opt, FEXHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
|
||||
options->patch.net.server = util_options_get_str(
|
||||
options_opt, FEXHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER);
|
||||
options->patch.net.machine_id = strtoul(
|
||||
util_options_get_str(
|
||||
options_opt, FEXHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID),
|
||||
NULL,
|
||||
16);
|
||||
options->patch.piuio.api_lib = util_options_get_str(
|
||||
options_opt, FEXHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
|
||||
options->patch.piuio.exit_test_serv = util_options_get_bool(
|
||||
options_opt, FEXHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
|
||||
options->patch.sound.device =
|
||||
util_options_get_str(options_opt, FEXHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
|
||||
options->patch.sigsegv.halt_on_segv = util_options_get_bool(
|
||||
options_opt, FEXHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
|
||||
options->log.file = util_options_get_str(
|
||||
options_opt, FEXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
|
||||
options->log.level = (enum util_log_level) util_options_get_int(
|
||||
options_opt, FEXHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
+39
-38
@@ -7,53 +7,54 @@
|
||||
#include "util/log.h"
|
||||
|
||||
struct fexhook_options {
|
||||
struct game {
|
||||
const char* settings;
|
||||
} game;
|
||||
struct game {
|
||||
const char *settings;
|
||||
} game;
|
||||
|
||||
struct patch {
|
||||
struct gfx {
|
||||
bool windowed;
|
||||
} gfx;
|
||||
struct patch {
|
||||
struct gfx {
|
||||
bool windowed;
|
||||
} gfx;
|
||||
|
||||
struct hook_mon {
|
||||
bool file;
|
||||
bool fs;
|
||||
bool io;
|
||||
bool open;
|
||||
bool usb;
|
||||
} hook_mon;
|
||||
struct hook_mon {
|
||||
bool file;
|
||||
bool fs;
|
||||
bool io;
|
||||
bool open;
|
||||
bool usb;
|
||||
} hook_mon;
|
||||
|
||||
struct main_loop {
|
||||
bool disable_built_in_inputs;
|
||||
const char* x11_input_handler_api_lib;
|
||||
} main_loop;
|
||||
struct main_loop {
|
||||
bool disable_built_in_inputs;
|
||||
const char *x11_input_handler_api_lib;
|
||||
} main_loop;
|
||||
|
||||
struct net {
|
||||
const char* server;
|
||||
uint32_t machine_id;
|
||||
} net;
|
||||
struct net {
|
||||
const char *server;
|
||||
uint32_t machine_id;
|
||||
} net;
|
||||
|
||||
struct piuio {
|
||||
const char* api_lib;
|
||||
bool exit_test_serv;
|
||||
} piuio;
|
||||
struct piuio {
|
||||
const char *api_lib;
|
||||
bool exit_test_serv;
|
||||
} piuio;
|
||||
|
||||
struct sound {
|
||||
const char* device;
|
||||
} sound;
|
||||
struct sound {
|
||||
const char *device;
|
||||
} sound;
|
||||
|
||||
struct sigsegv {
|
||||
bool halt_on_segv;
|
||||
} sigsegv;
|
||||
} patch;
|
||||
struct sigsegv {
|
||||
bool halt_on_segv;
|
||||
} sigsegv;
|
||||
} patch;
|
||||
|
||||
struct log {
|
||||
const char* file;
|
||||
enum util_log_level level;
|
||||
} log;
|
||||
struct log {
|
||||
const char *file;
|
||||
enum util_log_level level;
|
||||
} log;
|
||||
};
|
||||
|
||||
bool fexhook_options_init(int argc, char** argv, struct fexhook_options* options);
|
||||
bool fexhook_options_init(
|
||||
int argc, char **argv, struct fexhook_options *options);
|
||||
|
||||
#endif
|
||||
|
||||
+124
-111
@@ -17,8 +17,8 @@
|
||||
#include "hook/patch/main-loop.h"
|
||||
#include "hook/patch/microdog40.h"
|
||||
#include "hook/patch/mounts.h"
|
||||
#include "hook/patch/piuio.h"
|
||||
#include "hook/patch/piuio-exit.h"
|
||||
#include "hook/patch/piuio.h"
|
||||
#include "hook/patch/redir.h"
|
||||
#include "hook/patch/sigsegv.h"
|
||||
#include "hook/patch/sound.h"
|
||||
@@ -39,202 +39,215 @@ extern const uint8_t _binary_fsthook_hdd_raw_end[];
|
||||
extern const uint8_t _binary_fsthook_dog_key_start[];
|
||||
extern const uint8_t _binary_fsthook_dog_key_end[];
|
||||
|
||||
static void fsthook_bootstrapping(int argc, char** argv, struct fsthook_options* options, char** game_data_path)
|
||||
static void fsthook_bootstrapping(
|
||||
int argc,
|
||||
char **argv,
|
||||
struct fsthook_options *options,
|
||||
char **game_data_path)
|
||||
{
|
||||
log_assert(argc >= 0);
|
||||
log_assert(argv);
|
||||
log_assert(options);
|
||||
log_assert(game_data_path);
|
||||
log_assert(argc >= 0);
|
||||
log_assert(argv);
|
||||
log_assert(options);
|
||||
log_assert(game_data_path);
|
||||
|
||||
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
|
||||
return;
|
||||
}
|
||||
if (hook_core_piu_block_non_piu_process_recursion(argc, argv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
hook_core_piu_log_init(argc, argv);
|
||||
hook_core_piu_log_init(argc, argv);
|
||||
|
||||
if (!fsthook_options_init(argc, argv, options)) {
|
||||
exit(0);
|
||||
}
|
||||
if (!fsthook_options_init(argc, argv, options)) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
hook_core_piu_log_info(argc, argv);
|
||||
hook_core_piu_log_info(argc, argv);
|
||||
|
||||
*game_data_path = hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
|
||||
*game_data_path =
|
||||
hook_core_piu_utils_get_and_verify_game_data_path(argc, argv);
|
||||
|
||||
hook_core_piu_utils_verify_root_user();
|
||||
hook_core_piu_utils_verify_root_user();
|
||||
|
||||
log_info("Initializing, piu game data path: %s", *game_data_path);
|
||||
log_info("Initializing, piu game data path: %s", *game_data_path);
|
||||
}
|
||||
|
||||
static void fsthook_patch_fs_init(struct fsthook_options* options)
|
||||
static void fsthook_patch_fs_init(struct fsthook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
patch_hook_mon_init(
|
||||
options->patch.hook_mon.io,
|
||||
options->patch.hook_mon.file,
|
||||
options->patch.hook_mon.fs,
|
||||
options->patch.hook_mon.usb,
|
||||
options->patch.hook_mon.open);
|
||||
patch_hook_mon_init(
|
||||
options->patch.hook_mon.io,
|
||||
options->patch.hook_mon.file,
|
||||
options->patch.hook_mon.fs,
|
||||
options->patch.hook_mon.usb,
|
||||
options->patch.hook_mon.open);
|
||||
|
||||
patch_redir_init();
|
||||
patch_redir_init();
|
||||
}
|
||||
|
||||
static void fsthook_fs_redir_settings(struct fsthook_options* options)
|
||||
static void fsthook_fs_redir_settings(struct fsthook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
if (options->game.settings) {
|
||||
if (!util_fs_path_exists(options->game.settings)) {
|
||||
log_info("Settings path %s does not exist, creating", options->game.settings);
|
||||
if (options->game.settings) {
|
||||
if (!util_fs_path_exists(options->game.settings)) {
|
||||
log_info(
|
||||
"Settings path %s does not exist, creating", options->game.settings);
|
||||
|
||||
if (!util_fs_mkdir(options->game.settings)) {
|
||||
log_error("Creating directory %s failed", options->game.settings);
|
||||
}
|
||||
}
|
||||
|
||||
char* abs_path = util_fs_get_abs_path(options->game.settings);
|
||||
|
||||
cnh_redir_add("/SETTINGS", abs_path);
|
||||
free(abs_path);
|
||||
} else {
|
||||
log_warn("No settings path specified");
|
||||
if (!util_fs_mkdir(options->game.settings)) {
|
||||
log_error("Creating directory %s failed", options->game.settings);
|
||||
}
|
||||
}
|
||||
|
||||
char *abs_path = util_fs_get_abs_path(options->game.settings);
|
||||
|
||||
cnh_redir_add("/SETTINGS", abs_path);
|
||||
free(abs_path);
|
||||
} else {
|
||||
log_warn("No settings path specified");
|
||||
}
|
||||
}
|
||||
|
||||
static void fsthook_fs_redir_usb()
|
||||
{
|
||||
/* Needed on newer kernels */
|
||||
cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices");
|
||||
patch_usbfs_init();
|
||||
/* Needed on newer kernels */
|
||||
cnh_redir_add("/proc/bus/usb/devices", "/sys/kernel/debug/usb/devices");
|
||||
patch_usbfs_init();
|
||||
}
|
||||
|
||||
static void fsthook_fs_redirs_init(struct fsthook_options* options, const char* game_data_path)
|
||||
static void fsthook_fs_redirs_init(
|
||||
struct fsthook_options *options, const char *game_data_path)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(game_data_path);
|
||||
log_assert(options);
|
||||
log_assert(game_data_path);
|
||||
|
||||
fsthook_fs_redir_settings(options);
|
||||
fsthook_fs_redir_settings(options);
|
||||
|
||||
fsthook_fs_redir_usb();
|
||||
fsthook_fs_redir_usb();
|
||||
}
|
||||
|
||||
static void fsthook_patch_fs_mounting_init()
|
||||
{
|
||||
patch_mounts_init();
|
||||
patch_mounts_init();
|
||||
|
||||
patch_usb_mnt_init();
|
||||
patch_usb_mnt_init();
|
||||
}
|
||||
|
||||
static void fsthook_patch_gfx_init(struct fsthook_options* options)
|
||||
static void fsthook_patch_gfx_init(struct fsthook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
patch_gfx_init();
|
||||
patch_gfx_init();
|
||||
|
||||
if (options->patch.gfx.windowed) {
|
||||
patch_gfx_force_window_mode();
|
||||
}
|
||||
if (options->patch.gfx.windowed) {
|
||||
patch_gfx_force_window_mode();
|
||||
}
|
||||
}
|
||||
|
||||
static void fsthook_patch_main_loop_init(struct fsthook_options* options)
|
||||
static void fsthook_patch_main_loop_init(struct fsthook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
patch_main_loop_init(false, options->patch.main_loop.disable_built_in_inputs, false);
|
||||
patch_main_loop_init(
|
||||
false, options->patch.main_loop.disable_built_in_inputs, false);
|
||||
|
||||
if (options->patch.main_loop.x11_input_handler_api_lib) {
|
||||
char* abs_path_x11_input_hook_lib = util_fs_get_abs_path(options->patch.main_loop.x11_input_handler_api_lib);
|
||||
if (options->patch.main_loop.x11_input_handler_api_lib) {
|
||||
char *abs_path_x11_input_hook_lib = util_fs_get_abs_path(
|
||||
options->patch.main_loop.x11_input_handler_api_lib);
|
||||
|
||||
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
|
||||
free(abs_path_x11_input_hook_lib);
|
||||
}
|
||||
patch_main_loop_add_x11_input_handler(abs_path_x11_input_hook_lib);
|
||||
free(abs_path_x11_input_hook_lib);
|
||||
}
|
||||
}
|
||||
|
||||
static void fsthook_patch_sound_init(struct fsthook_options* options)
|
||||
static void fsthook_patch_sound_init(struct fsthook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
patch_sound_init(options->patch.sound.device);
|
||||
patch_axmier_block_init();
|
||||
patch_sound_init(options->patch.sound.device);
|
||||
patch_axmier_block_init();
|
||||
}
|
||||
|
||||
static void fsthook_patch_sigsegv_init(struct fsthook_options* options)
|
||||
static void fsthook_patch_sigsegv_init(struct fsthook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
|
||||
patch_sigsegv_init(options->patch.sigsegv.halt_on_segv);
|
||||
}
|
||||
|
||||
static void fsthook_patch_dongle_init()
|
||||
{
|
||||
patch_microdog40_init((const uint8_t*) _binary_fsthook_dog_key_start,
|
||||
((uintptr_t) &_binary_fsthook_dog_key_end - (uintptr_t) &_binary_fsthook_dog_key_start));
|
||||
patch_microdog40_init(
|
||||
(const uint8_t *) _binary_fsthook_dog_key_start,
|
||||
((uintptr_t) &_binary_fsthook_dog_key_end -
|
||||
(uintptr_t) &_binary_fsthook_dog_key_start));
|
||||
}
|
||||
|
||||
static void fsthook_patch_hdd_check_init()
|
||||
{
|
||||
patch_hdd_check_init((const uint8_t*) _binary_fsthook_hdd_raw_start,
|
||||
((uintptr_t) &_binary_fsthook_hdd_raw_end - (uintptr_t) &_binary_fsthook_hdd_raw_start));
|
||||
patch_hdd_check_init(
|
||||
(const uint8_t *) _binary_fsthook_hdd_raw_start,
|
||||
((uintptr_t) &_binary_fsthook_hdd_raw_end -
|
||||
(uintptr_t) &_binary_fsthook_hdd_raw_start));
|
||||
}
|
||||
|
||||
static void fsthook_patch_piuio_init(struct fsthook_options* options)
|
||||
static void fsthook_patch_piuio_init(struct fsthook_options *options)
|
||||
{
|
||||
log_assert(options);
|
||||
log_assert(options);
|
||||
|
||||
/* Hook before IO emulation */
|
||||
if (options->patch.piuio.exit_test_serv) {
|
||||
patch_piuio_exit_init();
|
||||
}
|
||||
/* Hook before IO emulation */
|
||||
if (options->patch.piuio.exit_test_serv) {
|
||||
patch_piuio_exit_init();
|
||||
}
|
||||
|
||||
patch_usb_init_fix_init();
|
||||
patch_usb_emu_init();
|
||||
patch_usb_init_fix_init();
|
||||
patch_usb_emu_init();
|
||||
|
||||
if (options->patch.piuio.api_lib) {
|
||||
char* abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
|
||||
if (options->patch.piuio.api_lib) {
|
||||
char *abs_path_iolib = util_fs_get_abs_path(options->patch.piuio.api_lib);
|
||||
|
||||
patch_piuio_init(abs_path_iolib);
|
||||
free(abs_path_iolib);
|
||||
}
|
||||
patch_piuio_init(abs_path_iolib);
|
||||
free(abs_path_iolib);
|
||||
}
|
||||
}
|
||||
|
||||
void fsthook_constructor(void)
|
||||
{
|
||||
/* Nothing here */
|
||||
/* Nothing here */
|
||||
}
|
||||
|
||||
void fsthook_destructor(void)
|
||||
{
|
||||
/* Nothing here */
|
||||
/* Nothing here */
|
||||
}
|
||||
|
||||
void fsthook_trap_before_main(int argc, char** argv)
|
||||
void fsthook_trap_before_main(int argc, char **argv)
|
||||
{
|
||||
log_assert(argc >= 0);
|
||||
log_assert(argv);
|
||||
log_assert(argc >= 0);
|
||||
log_assert(argv);
|
||||
|
||||
char* game_data_path;
|
||||
struct fsthook_options options;
|
||||
char *game_data_path;
|
||||
struct fsthook_options options;
|
||||
|
||||
fsthook_bootstrapping(argc, argv, &options, &game_data_path);
|
||||
fsthook_patch_fs_init(&options);
|
||||
fsthook_fs_redirs_init(&options, game_data_path);
|
||||
fsthook_patch_fs_mounting_init();
|
||||
fsthook_patch_gfx_init(&options);
|
||||
fsthook_patch_main_loop_init(&options);
|
||||
fsthook_patch_sound_init(&options);
|
||||
fsthook_patch_sigsegv_init(&options);
|
||||
fsthook_patch_dongle_init();
|
||||
fsthook_patch_hdd_check_init();
|
||||
fsthook_patch_piuio_init(&options);
|
||||
fsthook_bootstrapping(argc, argv, &options, &game_data_path);
|
||||
fsthook_patch_fs_init(&options);
|
||||
fsthook_fs_redirs_init(&options, game_data_path);
|
||||
fsthook_patch_fs_mounting_init();
|
||||
fsthook_patch_gfx_init(&options);
|
||||
fsthook_patch_main_loop_init(&options);
|
||||
fsthook_patch_sound_init(&options);
|
||||
fsthook_patch_sigsegv_init(&options);
|
||||
fsthook_patch_dongle_init();
|
||||
fsthook_patch_hdd_check_init();
|
||||
fsthook_patch_piuio_init(&options);
|
||||
|
||||
free(game_data_path);
|
||||
free(game_data_path);
|
||||
|
||||
log_info("Hooking finished");
|
||||
log_info("Hooking finished");
|
||||
}
|
||||
|
||||
void fsthook_trap_after_main(void)
|
||||
{
|
||||
patch_piuio_shutdown();
|
||||
patch_piuio_shutdown();
|
||||
}
|
||||
|
||||
LIB_MAIN_CONSTRUCTOR(fsthook_constructor);
|
||||
|
||||
+70
-46
@@ -9,14 +9,19 @@
|
||||
#define FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO "patch.hook_mon.io"
|
||||
#define FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN "patch.hook_mon.open"
|
||||
#define FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB "patch.hook_mon.usb"
|
||||
#define FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS "patch.hook_main_loop.disable_built_in_inputs"
|
||||
#define FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER "patch_hook_main_loop.x11_input_handler"
|
||||
#define FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS \
|
||||
"patch.hook_main_loop.disable_built_in_inputs"
|
||||
#define FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER \
|
||||
"patch_hook_main_loop.x11_input_handler"
|
||||
#define FSTHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER "patch.net_profile.server"
|
||||
#define FSTHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID "patch.net_profile.machine_id"
|
||||
#define FSTHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID \
|
||||
"patch.net_profile.machine_id"
|
||||
#define FSTHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB "patch.piuio.emu_lib"
|
||||
#define FSTHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV "patch.piuio_exit.test_serv"
|
||||
#define FSTHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV \
|
||||
"patch.piuio_exit.test_serv"
|
||||
#define FSTHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE "patch.sound.device"
|
||||
#define FSTHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV "patch.sigsegv.halt_on_segv"
|
||||
#define FSTHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV \
|
||||
"patch.sigsegv.halt_on_segv"
|
||||
#define FSTHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE "util.log.file"
|
||||
#define FSTHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL "util.log.level"
|
||||
|
||||
@@ -26,7 +31,7 @@ const struct util_options_def fsthook_options_def[] = {
|
||||
.description = "Path to game settings (SETTINGS) folder",
|
||||
.param = 's',
|
||||
.type = UTIL_OPTIONS_TYPE_STR,
|
||||
.default_value.str = "./save",
|
||||
.default_value.str = "./save",
|
||||
},
|
||||
{
|
||||
.name = FSTHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED,
|
||||
@@ -71,22 +76,26 @@ const struct util_options_def fsthook_options_def[] = {
|
||||
.default_value.b = false,
|
||||
},
|
||||
{
|
||||
.name = FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS,
|
||||
.description = "Disable the built in keyboard inputs for test (F1), service (F2) and clear (F3)",
|
||||
.name =
|
||||
FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS,
|
||||
.description = "Disable the built in keyboard inputs for test (F1), "
|
||||
"service (F2) and clear (F3)",
|
||||
.param = 'k',
|
||||
.type = UTIL_OPTIONS_TYPE_BOOL,
|
||||
.default_value.b = false,
|
||||
},
|
||||
{
|
||||
.name = FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER,
|
||||
.description = "Path to a library implementing the x11-input-handler api to capture X11 keyboard inputs",
|
||||
.description = "Path to a library implementing the x11-input-handler "
|
||||
"api to capture X11 keyboard inputs",
|
||||
.param = 'q',
|
||||
.type = UTIL_OPTIONS_TYPE_STR,
|
||||
.default_value.str = NULL,
|
||||
},
|
||||
{
|
||||
.name = FSTHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER,
|
||||
.description = "Address and port of pumpnet server (e.g. 127.0.0.1:1234)",
|
||||
.description =
|
||||
"Address and port of pumpnet server (e.g. 127.0.0.1:1234)",
|
||||
.param = 'n',
|
||||
.type = UTIL_OPTIONS_TYPE_STR,
|
||||
.default_value.str = NULL,
|
||||
@@ -100,7 +109,8 @@ const struct util_options_def fsthook_options_def[] = {
|
||||
},
|
||||
{
|
||||
.name = FSTHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB,
|
||||
.description = "Path to library implementing the piuio api for piuio emulation",
|
||||
.description =
|
||||
"Path to library implementing the piuio api for piuio emulation",
|
||||
.param = 'p',
|
||||
.type = UTIL_OPTIONS_TYPE_STR,
|
||||
.default_value.str = NULL,
|
||||
@@ -151,45 +161,59 @@ const struct util_options_defs fsthook_options_defs = {
|
||||
.ndefs = lengthof(fsthook_options_def)
|
||||
};
|
||||
|
||||
bool fsthook_options_init(int argc, char** argv, struct fsthook_options* options)
|
||||
bool fsthook_options_init(
|
||||
int argc, char **argv, struct fsthook_options *options)
|
||||
{
|
||||
log_assert(argv);
|
||||
log_assert(options);
|
||||
log_assert(argv);
|
||||
log_assert(options);
|
||||
|
||||
struct util_options_opts* options_opt;
|
||||
struct util_options_opts *options_opt;
|
||||
|
||||
util_options_init(argc, argv);
|
||||
options_opt = util_options_get(&fsthook_options_defs);
|
||||
util_options_init(argc, argv);
|
||||
options_opt = util_options_get(&fsthook_options_defs);
|
||||
|
||||
if (!options_opt) {
|
||||
return false;
|
||||
}
|
||||
if (!options_opt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
options->game.settings = util_options_get_str(options_opt, FSTHOOK_OPTIONS_STR_GAME_SETTINGS);
|
||||
options->patch.gfx.windowed = util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
|
||||
options->patch.hook_mon.file = util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
|
||||
options->patch.hook_mon.fs = util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
|
||||
options->patch.hook_mon.io = util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
|
||||
options->patch.hook_mon.open = util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
|
||||
options->patch.hook_mon.usb = util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
|
||||
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(options_opt,
|
||||
FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
|
||||
options->patch.main_loop.x11_input_handler_api_lib =
|
||||
util_options_get_str(options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
|
||||
options->patch.net.server = util_options_get_str(options_opt, FSTHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER);
|
||||
options->patch.net.machine_id = strtoul(
|
||||
util_options_get_str(options_opt, FSTHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID),
|
||||
NULL,
|
||||
16);
|
||||
options->patch.piuio.api_lib = util_options_get_str(options_opt, FSTHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
|
||||
options->patch.piuio.exit_test_serv =
|
||||
util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
|
||||
options->patch.sound.device = util_options_get_str(options_opt, FSTHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
|
||||
options->patch.sigsegv.halt_on_segv =
|
||||
util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
|
||||
options->log.file = util_options_get_str(options_opt, FSTHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
|
||||
options->log.level =
|
||||
(enum util_log_level) util_options_get_int(options_opt, FSTHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
|
||||
options->game.settings =
|
||||
util_options_get_str(options_opt, FSTHOOK_OPTIONS_STR_GAME_SETTINGS);
|
||||
options->patch.gfx.windowed = util_options_get_bool(
|
||||
options_opt, FSTHOOK_OPTIONS_STR_PATCH_GFX_WINDOWED);
|
||||
options->patch.hook_mon.file = util_options_get_bool(
|
||||
options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_FILE);
|
||||
options->patch.hook_mon.fs =
|
||||
util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_FS);
|
||||
options->patch.hook_mon.io =
|
||||
util_options_get_bool(options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_IO);
|
||||
options->patch.hook_mon.open = util_options_get_bool(
|
||||
options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_OPEN);
|
||||
options->patch.hook_mon.usb = util_options_get_bool(
|
||||
options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MON_USB);
|
||||
options->patch.main_loop.disable_built_in_inputs = util_options_get_bool(
|
||||
options_opt,
|
||||
FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_DISABLE_BUILT_IN_INPUTS);
|
||||
options->patch.main_loop.x11_input_handler_api_lib = util_options_get_str(
|
||||
options_opt, FSTHOOK_OPTIONS_STR_PATCH_HOOK_MAIN_LOOP_X11_INPUT_HANDLER);
|
||||
options->patch.net.server = util_options_get_str(
|
||||
options_opt, FSTHOOK_OPTIONS_STR_PATCH_NET_PROFILE_SERVER);
|
||||
options->patch.net.machine_id = strtoul(
|
||||
util_options_get_str(
|
||||
options_opt, FSTHOOK_OPTIONS_STR_PATCH_NET_PROFILE_MACHINE_ID),
|
||||
NULL,
|
||||
16);
|
||||
options->patch.piuio.api_lib = util_options_get_str(
|
||||
options_opt, FSTHOOK_OPTIONS_STR_PATCH_PIUIO_EMU_LIB);
|
||||
options->patch.piuio.exit_test_serv = util_options_get_bool(
|
||||
options_opt, FSTHOOK_OPTIONS_STR_PATCH_PIUIO_EXIT_TEST_SERV);
|
||||
options->patch.sound.device =
|
||||
util_options_get_str(options_opt, FSTHOOK_OPTIONS_STR_PATCH_SOUND_DEVICE);
|
||||
options->patch.sigsegv.halt_on_segv = util_options_get_bool(
|
||||
options_opt, FSTHOOK_OPTIONS_STR_PATCH_SIGSEGV_HALT_ON_SEGV);
|
||||
options->log.file = util_options_get_str(
|
||||
options_opt, FSTHOOK_OPTIONS_STR_PATCH_UTIL_LOG_FILE);
|
||||
options->log.level = (enum util_log_level) util_options_get_int(
|
||||
options_opt, FSTHOOK_OPTIONS_STR_PATCH_UTIL_LOG_LEVEL);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
+39
-38
@@ -7,53 +7,54 @@
|
||||
#include "util/log.h"
|
||||
|
||||
struct fsthook_options {
|
||||
struct game {
|
||||
const char* settings;
|
||||
} game;
|
||||
struct game {
|
||||
const char *settings;
|
||||
} game;
|
||||
|
||||
struct patch {
|
||||
struct gfx {
|
||||
bool windowed;
|
||||
} gfx;
|
||||
struct patch {
|
||||
struct gfx {
|
||||
bool windowed;
|
||||
} gfx;
|
||||
|
||||
struct hook_mon {
|
||||
bool file;
|
||||
bool fs;
|
||||
bool io;
|
||||
bool open;
|
||||
bool usb;
|
||||
} hook_mon;
|
||||
struct hook_mon {
|
||||
bool file;
|
||||
bool fs;
|
||||
bool io;
|
||||
bool open;
|
||||
bool usb;
|
||||
} hook_mon;
|
||||
|
||||
struct main_loop {
|
||||
bool disable_built_in_inputs;
|
||||
const char* x11_input_handler_api_lib;
|
||||
} main_loop;
|
||||
struct main_loop {
|
||||
bool disable_built_in_inputs;
|
||||
const char *x11_input_handler_api_lib;
|
||||
} main_loop;
|
||||
|
||||
struct net {
|
||||
const char* server;
|
||||
uint32_t machine_id;
|
||||
} net;
|
||||
struct net {
|
||||
const char *server;
|
||||
uint32_t machine_id;
|
||||
} net;
|
||||
|
||||
struct piuio {
|
||||
const char* api_lib;
|
||||
bool exit_test_serv;
|
||||
} piuio;
|
||||
struct piuio {
|
||||
const char *api_lib;
|
||||
bool exit_test_serv;
|
||||
} piuio;
|
||||
|
||||
struct sound {
|
||||
const char* device;
|
||||
} sound;
|
||||
struct sound {
|
||||
const char *device;
|
||||
} sound;
|
||||
|
||||
struct sigsegv {
|
||||
bool halt_on_segv;
|
||||
} sigsegv;
|
||||
} patch;
|
||||
struct sigsegv {
|
||||
bool halt_on_segv;
|
||||
} sigsegv;
|
||||
} patch;
|
||||
|
||||
struct log {
|
||||
const char* file;
|
||||
enum util_log_level level;
|
||||
} log;
|
||||
struct log {
|
||||
const char *file;
|
||||
enum util_log_level level;
|
||||
} log;
|
||||
};
|
||||
|
||||
bool fsthook_options_init(int argc, char** argv, struct fsthook_options* options);
|
||||
bool fsthook_options_init(
|
||||
int argc, char **argv, struct fsthook_options *options);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -10,32 +10,39 @@
|
||||
typedef int (*cnh_fshook_chdir_t)(const char *path);
|
||||
static cnh_fshook_chdir_t mk3hook_1st_2nd_fs_fix_real_chdir;
|
||||
|
||||
static char* mk3hook_1st_2nd_fs_fix_path_game_dir_abs;
|
||||
static char *mk3hook_1st_2nd_fs_fix_path_game_dir_abs;
|
||||
|
||||
int chdir(const char *path)
|
||||
{
|
||||
if (!mk3hook_1st_2nd_fs_fix_real_chdir) {
|
||||
mk3hook_1st_2nd_fs_fix_real_chdir = (cnh_fshook_chdir_t) cnh_lib_get_func_addr("chdir");
|
||||
}
|
||||
if (!mk3hook_1st_2nd_fs_fix_real_chdir) {
|
||||
mk3hook_1st_2nd_fs_fix_real_chdir =
|
||||
(cnh_fshook_chdir_t) cnh_lib_get_func_addr("chdir");
|
||||
}
|
||||
|
||||
// This seems to be some kind of probe the game is doing to determine something...I assume which folder layout to
|
||||
// use? When we change directory to our "game" dir which contains all stuff at that point, everything's fine.
|
||||
// If we do not do that, the game will error not being able to find any files. When loading files, the code also
|
||||
// does some odd iterating the file system starting at / at that point. I assume that this is some sort of search
|
||||
// trying to look for the file on the filesystem. However, that breaks a lot of other stuf with the hooking code
|
||||
// and therefore should not be triggered.
|
||||
if (mk3hook_1st_2nd_fs_fix_path_game_dir_abs && !strcmp(path, "/datas/bga")) {
|
||||
log_debug("Trapping /datas/bga chdir, chdir to %s", mk3hook_1st_2nd_fs_fix_path_game_dir_abs);
|
||||
// This seems to be some kind of probe the game is doing to determine
|
||||
// something...I assume which folder layout to use? When we change directory
|
||||
// to our "game" dir which contains all stuff at that point, everything's
|
||||
// fine. If we do not do that, the game will error not being able to find any
|
||||
// files. When loading files, the code also does some odd iterating the file
|
||||
// system starting at / at that point. I assume that this is some sort of
|
||||
// search trying to look for the file on the filesystem. However, that breaks
|
||||
// a lot of other stuf with the hooking code and therefore should not be
|
||||
// triggered.
|
||||
if (mk3hook_1st_2nd_fs_fix_path_game_dir_abs && !strcmp(path, "/datas/bga")) {
|
||||
log_debug(
|
||||
"Trapping /datas/bga chdir, chdir to %s",
|
||||
mk3hook_1st_2nd_fs_fix_path_game_dir_abs);
|
||||
|
||||
return mk3hook_1st_2nd_fs_fix_real_chdir(mk3hook_1st_2nd_fs_fix_path_game_dir_abs);
|
||||
} else {
|
||||
return mk3hook_1st_2nd_fs_fix_real_chdir(path);
|
||||
}
|
||||
return mk3hook_1st_2nd_fs_fix_real_chdir(
|
||||
mk3hook_1st_2nd_fs_fix_path_game_dir_abs);
|
||||
} else {
|
||||
return mk3hook_1st_2nd_fs_fix_real_chdir(path);
|
||||
}
|
||||
}
|
||||
|
||||
void mk3hook_1st_2nd_fs_fix_init(const char* path_game_dir_abs)
|
||||
void mk3hook_1st_2nd_fs_fix_init(const char *path_game_dir_abs)
|
||||
{
|
||||
mk3hook_1st_2nd_fs_fix_path_game_dir_abs = util_str_dup(path_game_dir_abs);
|
||||
mk3hook_1st_2nd_fs_fix_path_game_dir_abs = util_str_dup(path_game_dir_abs);
|
||||
|
||||
log_info("Initialized");
|
||||
log_info("Initialized");
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
/**
|
||||
* Fixes an issue with the engine of 1st and 2nd when redirecting all game data to one game folder, e.g. ./game/.
|
||||
* Fixes an issue with the engine of 1st and 2nd when redirecting all game data
|
||||
* to one game folder, e.g. ./game/.
|
||||
*/
|
||||
#ifndef MK3HOOK_1ST_2ND_FS_FIX_H
|
||||
#define MK3HOOK_1ST_2ND_FS_FIX_H
|
||||
@@ -7,8 +8,9 @@
|
||||
/**
|
||||
* Initialize the module.
|
||||
*
|
||||
* @param path_game_dir_abs The absolute path to the "game" dir containing all game assets.
|
||||
* @param path_game_dir_abs The absolute path to the "game" dir containing all
|
||||
* game assets.
|
||||
*/
|
||||
void mk3hook_1st_2nd_fs_fix_init(const char* path_game_dir_abs);
|
||||
void mk3hook_1st_2nd_fs_fix_init(const char *path_game_dir_abs);
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user