mirror of
https://github.com/pumpitupdev/pumptools.git
synced 2026-09-26 16:38:29 +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:
+34
-27
@@ -12,41 +12,44 @@
|
||||
* Button inputs of a single player
|
||||
*/
|
||||
struct ptapi_io_piubtn_inputs {
|
||||
bool start;
|
||||
bool back;
|
||||
bool left;
|
||||
bool right;
|
||||
bool start;
|
||||
bool back;
|
||||
bool left;
|
||||
bool right;
|
||||
};
|
||||
|
||||
/**
|
||||
* Button light outputs of a single player
|
||||
*/
|
||||
struct ptapi_io_piubtn_outputs {
|
||||
bool start;
|
||||
bool back;
|
||||
bool left;
|
||||
bool right;
|
||||
bool start;
|
||||
bool back;
|
||||
bool left;
|
||||
bool right;
|
||||
};
|
||||
|
||||
typedef const char* (*ptapi_io_piubtn_ident_t)(void);
|
||||
typedef const char *(*ptapi_io_piubtn_ident_t)(void);
|
||||
typedef bool (*ptapi_io_piubtn_open_t)(void);
|
||||
typedef void (*ptapi_io_piubtn_close_t)(void);
|
||||
typedef bool (*ptapi_io_piubtn_recv_t)(void);
|
||||
typedef bool (*ptapi_io_piubtn_send_t)(void);
|
||||
typedef void (*ptapi_io_piubtn_get_input_t)(uint8_t player, struct ptapi_io_piubtn_inputs* inputs);
|
||||
typedef void (*ptapi_io_piubtn_set_output_t)(uint8_t player, const struct ptapi_io_piubtn_outputs* outputs);
|
||||
typedef void (*ptapi_io_piubtn_get_input_t)(
|
||||
uint8_t player, struct ptapi_io_piubtn_inputs *inputs);
|
||||
typedef void (*ptapi_io_piubtn_set_output_t)(
|
||||
uint8_t player, const struct ptapi_io_piubtn_outputs *outputs);
|
||||
|
||||
/**
|
||||
* API functions in a struct to make them easier to handle and have less boilerplate
|
||||
* API functions in a struct to make them easier to handle and have less
|
||||
* boilerplate
|
||||
*/
|
||||
struct ptapi_io_piubtn_api {
|
||||
ptapi_io_piubtn_ident_t ident;
|
||||
ptapi_io_piubtn_open_t open;
|
||||
ptapi_io_piubtn_close_t close;
|
||||
ptapi_io_piubtn_recv_t recv;
|
||||
ptapi_io_piubtn_send_t send;
|
||||
ptapi_io_piubtn_get_input_t get_input;
|
||||
ptapi_io_piubtn_set_output_t set_output;
|
||||
ptapi_io_piubtn_ident_t ident;
|
||||
ptapi_io_piubtn_open_t open;
|
||||
ptapi_io_piubtn_close_t close;
|
||||
ptapi_io_piubtn_recv_t recv;
|
||||
ptapi_io_piubtn_send_t send;
|
||||
ptapi_io_piubtn_get_input_t get_input;
|
||||
ptapi_io_piubtn_set_output_t set_output;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -54,15 +57,16 @@ struct ptapi_io_piubtn_api {
|
||||
*
|
||||
* @return Identifier string for your implementation (e.g. "my-custom-btnio")
|
||||
*/
|
||||
const char* ptapi_io_piubtn_ident(void);
|
||||
const char *ptapi_io_piubtn_ident(void);
|
||||
|
||||
/**
|
||||
* Open the piubtn device
|
||||
*
|
||||
* Open any file handles, spawn threads and/or initialize your device or emulation code to be ready to accept further
|
||||
* commands.
|
||||
* Open any file handles, spawn threads and/or initialize your device or
|
||||
* emulation code to be ready to accept further commands.
|
||||
*
|
||||
* @return True if opening/initializing your implementation was sucessful, false on failure
|
||||
* @return True if opening/initializing your implementation was sucessful, false
|
||||
* on failure
|
||||
*/
|
||||
bool ptapi_io_piubtn_open(void);
|
||||
|
||||
@@ -89,10 +93,12 @@ bool ptapi_io_piubtn_send(void);
|
||||
* Get buffered button input data
|
||||
*
|
||||
* @param player Player id (0, 1)
|
||||
* @param inputs Pointer to buffer to copy inputs to. Every time this is invoked, this buffer is nulled. If you do not
|
||||
* write any data to this, all inputs remain un-triggered.
|
||||
* @param inputs Pointer to buffer to copy inputs to. Every time this is
|
||||
* invoked, this buffer is nulled. If you do not write any data to this, all
|
||||
* inputs remain un-triggered.
|
||||
*/
|
||||
void ptapi_io_piubtn_get_input(uint8_t player, struct ptapi_io_piubtn_inputs* inputs);
|
||||
void ptapi_io_piubtn_get_input(
|
||||
uint8_t player, struct ptapi_io_piubtn_inputs *inputs);
|
||||
|
||||
/**
|
||||
* Set button light outputs (i.e. buffer them)
|
||||
@@ -100,6 +106,7 @@ void ptapi_io_piubtn_get_input(uint8_t player, struct ptapi_io_piubtn_inputs* in
|
||||
* @param player Player id (0, 1)
|
||||
* @param outputs Pointer to output data to copy to your private buffers.
|
||||
*/
|
||||
void ptapi_io_piubtn_set_output(uint8_t player, const struct ptapi_io_piubtn_outputs* outputs);
|
||||
void ptapi_io_piubtn_set_output(
|
||||
uint8_t player, const struct ptapi_io_piubtn_outputs *outputs);
|
||||
|
||||
#endif
|
||||
+70
-56
@@ -12,81 +12,87 @@
|
||||
* Enum for pad input sensor groups (four sensors per button/panel)
|
||||
*/
|
||||
enum ptapi_io_piuio_sensor_group {
|
||||
PTAPI_IO_PIUIO_SENSOR_GROUP_RIGHT = 0,
|
||||
PTAPI_IO_PIUIO_SENSOR_GROUP_LEFT = 1,
|
||||
PTAPI_IO_PIUIO_SENSOR_GROUP_DOWN = 2,
|
||||
PTAPI_IO_PIUIO_SENSOR_GROUP_UP = 3,
|
||||
PTAPI_IO_PIUIO_SENSOR_GROUP_NUM = 4,
|
||||
PTAPI_IO_PIUIO_SENSOR_GROUP_RIGHT = 0,
|
||||
PTAPI_IO_PIUIO_SENSOR_GROUP_LEFT = 1,
|
||||
PTAPI_IO_PIUIO_SENSOR_GROUP_DOWN = 2,
|
||||
PTAPI_IO_PIUIO_SENSOR_GROUP_UP = 3,
|
||||
PTAPI_IO_PIUIO_SENSOR_GROUP_NUM = 4,
|
||||
};
|
||||
|
||||
/**
|
||||
* Inputs of all arrows of a single pad (per sensor group)
|
||||
*/
|
||||
struct ptapi_io_piuio_pad_inputs {
|
||||
bool lu;
|
||||
bool ru;
|
||||
bool cn;
|
||||
bool ld;
|
||||
bool rd;
|
||||
bool lu;
|
||||
bool ru;
|
||||
bool cn;
|
||||
bool ld;
|
||||
bool rd;
|
||||
};
|
||||
|
||||
/**
|
||||
* System/operator inputs
|
||||
*/
|
||||
struct ptapi_io_piuio_sys_inputs {
|
||||
bool test;
|
||||
bool service;
|
||||
bool clear;
|
||||
bool coin;
|
||||
bool coin2;
|
||||
bool test;
|
||||
bool service;
|
||||
bool clear;
|
||||
bool coin;
|
||||
bool coin2;
|
||||
};
|
||||
|
||||
/**
|
||||
* Pad light outputs
|
||||
*/
|
||||
struct ptapi_io_piuio_pad_outputs {
|
||||
bool lu;
|
||||
bool ru;
|
||||
bool cn;
|
||||
bool ld;
|
||||
bool rd;
|
||||
bool lu;
|
||||
bool ru;
|
||||
bool cn;
|
||||
bool ld;
|
||||
bool rd;
|
||||
};
|
||||
|
||||
/**
|
||||
* Cabinet light outputs
|
||||
*/
|
||||
struct ptapi_io_piuio_cab_outputs {
|
||||
bool bass;
|
||||
bool halo_r2;
|
||||
bool halo_r1;
|
||||
bool halo_l2;
|
||||
bool halo_l1;
|
||||
bool bass;
|
||||
bool halo_r2;
|
||||
bool halo_r1;
|
||||
bool halo_l2;
|
||||
bool halo_l1;
|
||||
};
|
||||
|
||||
typedef const char* (*ptapi_io_piuio_ident_t)(void);
|
||||
typedef const char *(*ptapi_io_piuio_ident_t)(void);
|
||||
typedef bool (*ptapi_io_piuio_open_t)(void);
|
||||
typedef void (*ptapi_io_piuio_close_t)(void);
|
||||
typedef bool (*ptapi_io_piuio_recv_t)(void);
|
||||
typedef bool (*ptapi_io_piuio_send_t)(void);
|
||||
typedef void (*ptapi_io_piuio_get_input_pad_t)(uint8_t player, enum ptapi_io_piuio_sensor_group sensor_group,
|
||||
struct ptapi_io_piuio_pad_inputs* inputs);
|
||||
typedef void (*ptapi_io_piuio_get_input_sys_t)(struct ptapi_io_piuio_sys_inputs* inputs);
|
||||
typedef void (*ptapi_io_piuio_set_output_pad_t)(uint8_t player, struct ptapi_io_piuio_pad_outputs* outputs);
|
||||
typedef void (*ptapi_io_piuio_set_output_cab_t)(const struct ptapi_io_piuio_cab_outputs* outputs);
|
||||
typedef void (*ptapi_io_piuio_get_input_pad_t)(
|
||||
uint8_t player,
|
||||
enum ptapi_io_piuio_sensor_group sensor_group,
|
||||
struct ptapi_io_piuio_pad_inputs *inputs);
|
||||
typedef void (*ptapi_io_piuio_get_input_sys_t)(
|
||||
struct ptapi_io_piuio_sys_inputs *inputs);
|
||||
typedef void (*ptapi_io_piuio_set_output_pad_t)(
|
||||
uint8_t player, struct ptapi_io_piuio_pad_outputs *outputs);
|
||||
typedef void (*ptapi_io_piuio_set_output_cab_t)(
|
||||
const struct ptapi_io_piuio_cab_outputs *outputs);
|
||||
|
||||
/**
|
||||
* API functions in a struct to make them easier to handle and have less boilerplate
|
||||
* API functions in a struct to make them easier to handle and have less
|
||||
* boilerplate
|
||||
*/
|
||||
struct ptapi_io_piuio_api {
|
||||
ptapi_io_piuio_ident_t ident;
|
||||
ptapi_io_piuio_open_t open;
|
||||
ptapi_io_piuio_close_t close;
|
||||
ptapi_io_piuio_recv_t recv;
|
||||
ptapi_io_piuio_send_t send;
|
||||
ptapi_io_piuio_get_input_pad_t get_input_pad;
|
||||
ptapi_io_piuio_get_input_sys_t get_input_sys;
|
||||
ptapi_io_piuio_set_output_pad_t set_output_pad;
|
||||
ptapi_io_piuio_set_output_cab_t set_output_cab;
|
||||
ptapi_io_piuio_ident_t ident;
|
||||
ptapi_io_piuio_open_t open;
|
||||
ptapi_io_piuio_close_t close;
|
||||
ptapi_io_piuio_recv_t recv;
|
||||
ptapi_io_piuio_send_t send;
|
||||
ptapi_io_piuio_get_input_pad_t get_input_pad;
|
||||
ptapi_io_piuio_get_input_sys_t get_input_sys;
|
||||
ptapi_io_piuio_set_output_pad_t set_output_pad;
|
||||
ptapi_io_piuio_set_output_cab_t set_output_cab;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -94,15 +100,16 @@ struct ptapi_io_piuio_api {
|
||||
*
|
||||
* @return Identifier string for your implementation (e.g. "my-custom-io")
|
||||
*/
|
||||
const char* ptapi_io_piuio_ident(void);
|
||||
const char *ptapi_io_piuio_ident(void);
|
||||
|
||||
/**
|
||||
* Open the piuio device
|
||||
*
|
||||
* Open any file handles, spawn threads and/or initialize your device or emulation code to be ready to accept further
|
||||
* commands.
|
||||
* Open any file handles, spawn threads and/or initialize your device or
|
||||
* emulation code to be ready to accept further commands.
|
||||
*
|
||||
* @return True if opening/initializing your implementation was sucessful, false on failure
|
||||
* @return True if opening/initializing your implementation was sucessful, false
|
||||
* on failure
|
||||
*/
|
||||
bool ptapi_io_piuio_open(void);
|
||||
|
||||
@@ -112,8 +119,9 @@ bool ptapi_io_piuio_open(void);
|
||||
void ptapi_io_piuio_close(void);
|
||||
|
||||
/**
|
||||
* Get _ALL_ readable data from your device in this single recv call. If you have to address single sensores like the
|
||||
* real piuio, you have to do this on a single call to this function.
|
||||
* Get _ALL_ readable data from your device in this single recv call. If you
|
||||
* have to address single sensores like the real piuio, you have to do this on a
|
||||
* single call to this function.
|
||||
*
|
||||
* @return True on success, false on error
|
||||
*/
|
||||
@@ -131,19 +139,23 @@ bool ptapi_io_piuio_send(void);
|
||||
*
|
||||
* @param player Player id (0, 1)
|
||||
* @param sensor_group Sensor group states to get
|
||||
* @param inputs Pointer to buffer to copy inputs of the selected sensor group to. Every time this is invoked, this
|
||||
* buffer is nulled. If you do not write any data to this, all inputs remain un-triggered.
|
||||
* @param inputs Pointer to buffer to copy inputs of the selected sensor group
|
||||
* to. Every time this is invoked, this buffer is nulled. If you do not write
|
||||
* any data to this, all inputs remain un-triggered.
|
||||
*/
|
||||
void ptapi_io_piuio_get_input_pad(uint8_t player, enum ptapi_io_piuio_sensor_group sensor_group,
|
||||
struct ptapi_io_piuio_pad_inputs* inputs);
|
||||
void ptapi_io_piuio_get_input_pad(
|
||||
uint8_t player,
|
||||
enum ptapi_io_piuio_sensor_group sensor_group,
|
||||
struct ptapi_io_piuio_pad_inputs *inputs);
|
||||
|
||||
/**
|
||||
* Get buffered system (test, service, clear, coin) inputs
|
||||
*
|
||||
* @param inputs Pointer to buffer to copy inputs to. Every time this is invoked, this buffer is nulled. If you do not
|
||||
* write any data to this, all inputs remain un-triggered.
|
||||
* @param inputs Pointer to buffer to copy inputs to. Every time this is
|
||||
* invoked, this buffer is nulled. If you do not write any data to this, all
|
||||
* inputs remain un-triggered.
|
||||
*/
|
||||
void ptapi_io_piuio_get_input_sys(struct ptapi_io_piuio_sys_inputs* inputs);
|
||||
void ptapi_io_piuio_get_input_sys(struct ptapi_io_piuio_sys_inputs *inputs);
|
||||
|
||||
/**
|
||||
* Set pad light outputs (i.e. buffer them)
|
||||
@@ -151,13 +163,15 @@ void ptapi_io_piuio_get_input_sys(struct ptapi_io_piuio_sys_inputs* inputs);
|
||||
* @param player Player id (0, 1)
|
||||
* @param outputs Pointer to output data to copy to your private buffers.
|
||||
*/
|
||||
void ptapi_io_piuio_set_output_pad(uint8_t player, const struct ptapi_io_piuio_pad_outputs* outputs);
|
||||
void ptapi_io_piuio_set_output_pad(
|
||||
uint8_t player, const struct ptapi_io_piuio_pad_outputs *outputs);
|
||||
|
||||
/**
|
||||
* Set cabinet light outputs (i.e. buffer them)
|
||||
*
|
||||
* @param outputs Pointer to output data to copy to your private buffers.
|
||||
*/
|
||||
void ptapi_io_piuio_set_output_cab(const struct ptapi_io_piuio_cab_outputs* outputs);
|
||||
void ptapi_io_piuio_set_output_cab(
|
||||
const struct ptapi_io_piuio_cab_outputs *outputs);
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,7 @@
|
||||
/**
|
||||
* Pumptools hooks into the X11 event dispatch loop to grab different events and exposes
|
||||
* keyboard input events. This allows external modules to react to these inputs.
|
||||
* Pumptools hooks into the X11 event dispatch loop to grab different events and
|
||||
* exposes keyboard input events. This allows external modules to react to these
|
||||
* inputs.
|
||||
*/
|
||||
#ifndef PTAPI_IO_X11_INPUT_HOOK_H
|
||||
#define PTAPI_IO_X11_INPUT_HOOK_H
|
||||
@@ -12,28 +13,31 @@
|
||||
* Set functions you do not use to NULL.
|
||||
*/
|
||||
struct ptapi_io_x11_input_hook_handler {
|
||||
/**
|
||||
* Dispatch the key press event
|
||||
*
|
||||
* @param key Key pressed
|
||||
*/
|
||||
void (*dispatch_key_press)(KeySym key);
|
||||
/**
|
||||
* Dispatch the key press event
|
||||
*
|
||||
* @param key Key pressed
|
||||
*/
|
||||
void (*dispatch_key_press)(KeySym key);
|
||||
|
||||
/**
|
||||
* Dispatch the key release event
|
||||
*
|
||||
* @param key Key released
|
||||
*/
|
||||
void (*dispatch_key_release)(KeySym key);
|
||||
/**
|
||||
* Dispatch the key release event
|
||||
*
|
||||
* @param key Key released
|
||||
*/
|
||||
void (*dispatch_key_release)(KeySym key);
|
||||
};
|
||||
|
||||
typedef const struct ptapi_io_x11_input_hook_handler* (*ptapi_io_x11_input_handler_hook_t)(void);
|
||||
typedef const struct ptapi_io_x11_input_hook_handler *(
|
||||
*ptapi_io_x11_input_handler_hook_t)(void);
|
||||
|
||||
/**
|
||||
* Get an input hook handler to receive keyboard inputs from the X11 event loop.
|
||||
*
|
||||
* @return Either a valid handler structure with dispatch functions or NULL if unused.
|
||||
* @return Either a valid handler structure with dispatch functions or NULL if
|
||||
* unused.
|
||||
*/
|
||||
const struct ptapi_io_x11_input_hook_handler* ptapi_io_x11_input_handler_hook(void);
|
||||
const struct ptapi_io_x11_input_hook_handler *
|
||||
ptapi_io_x11_input_handler_hook(void);
|
||||
|
||||
#endif
|
||||
|
||||
+2710
-2440
File diff suppressed because it is too large
Load Diff
+645
-407
File diff suppressed because it is too large
Load Diff
@@ -26,47 +26,47 @@
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
|
||||
# ifdef _MSC_VER
|
||||
# include <stdio.h> /* _snprintf */
|
||||
#ifdef _MSC_VER
|
||||
#include <stdio.h> /* _snprintf */
|
||||
|
||||
# undef inline
|
||||
# define inline __inline
|
||||
#undef inline
|
||||
#define inline __inline
|
||||
|
||||
# ifndef va_copy
|
||||
# define va_copy(dest, src) (dest = src)
|
||||
# endif
|
||||
#ifndef va_copy
|
||||
#define va_copy(dest, src) (dest = src)
|
||||
#endif
|
||||
|
||||
# define strcasecmp _stricmp
|
||||
# define strncasecmp _strnicmp
|
||||
#define strcasecmp _stricmp
|
||||
#define strncasecmp _strnicmp
|
||||
|
||||
# if defined(HAVE__SNPRINTF_S)
|
||||
# undef snprintf
|
||||
# define snprintf(d, n, ...) _snprintf_s((d), (n), _TRUNCATE, __VA_ARGS__)
|
||||
# else /* HAVE__SNPRINTF_S */
|
||||
# if defined(HAVE__SNPRINTF)
|
||||
# undef snprintf
|
||||
# define snprintf _snprintf
|
||||
# else /* HAVE__SNPRINTF */
|
||||
# if !defined(HAVE_SNPRINTF)
|
||||
# error "no snprintf compatible function found"
|
||||
# endif /* HAVE_SNPRINTF */
|
||||
# endif /* HAVE__SNPRINTF */
|
||||
# endif /* HAVE__SNPRINTF_S */
|
||||
#if defined(HAVE__SNPRINTF_S)
|
||||
#undef snprintf
|
||||
#define snprintf(d, n, ...) _snprintf_s((d), (n), _TRUNCATE, __VA_ARGS__)
|
||||
#else /* HAVE__SNPRINTF_S */
|
||||
#if defined(HAVE__SNPRINTF)
|
||||
#undef snprintf
|
||||
#define snprintf _snprintf
|
||||
#else /* HAVE__SNPRINTF */
|
||||
#if !defined(HAVE_SNPRINTF)
|
||||
#error "no snprintf compatible function found"
|
||||
#endif /* HAVE_SNPRINTF */
|
||||
#endif /* HAVE__SNPRINTF */
|
||||
#endif /* HAVE__SNPRINTF_S */
|
||||
|
||||
# if defined(HAVE__VSNPRINTF_S)
|
||||
# undef vsnprintf
|
||||
# define vsnprintf(s, n, f, v) _vsnprintf_s((s), (n), _TRUNCATE, (f), (v))
|
||||
# else /* HAVE__VSNPRINTF_S */
|
||||
# if defined(HAVE__VSNPRINTF)
|
||||
# undef vsnprintf
|
||||
# define vsnprintf _vsnprintf
|
||||
# else
|
||||
# if !defined(HAVE_VSNPRINTF)
|
||||
# error "No vsnprintf compatible function found"
|
||||
# endif /* HAVE_VSNPRINTF */
|
||||
# endif /* HAVE__VSNPRINTF */
|
||||
# endif /* HAVE__VSNPRINTF_S */
|
||||
# endif /* _MSC_VER */
|
||||
#if defined(HAVE__VSNPRINTF_S)
|
||||
#undef vsnprintf
|
||||
#define vsnprintf(s, n, f, v) _vsnprintf_s((s), (n), _TRUNCATE, (f), (v))
|
||||
#else /* HAVE__VSNPRINTF_S */
|
||||
#if defined(HAVE__VSNPRINTF)
|
||||
#undef vsnprintf
|
||||
#define vsnprintf _vsnprintf
|
||||
#else
|
||||
#if !defined(HAVE_VSNPRINTF)
|
||||
#error "No vsnprintf compatible function found"
|
||||
#endif /* HAVE_VSNPRINTF */
|
||||
#endif /* HAVE__VSNPRINTF */
|
||||
#endif /* HAVE__VSNPRINTF_S */
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
/*
|
||||
* Backwards compatibility with headers shipped with Visual Studio 2005 and
|
||||
@@ -75,15 +75,15 @@
|
||||
WINBASEAPI BOOL WINAPI IsDebuggerPresent(VOID);
|
||||
|
||||
#ifndef PRIdS
|
||||
# define PRIdS "Id"
|
||||
#define PRIdS "Id"
|
||||
#endif
|
||||
|
||||
#ifndef PRIu64
|
||||
# define PRIu64 "I64u"
|
||||
#define PRIu64 "I64u"
|
||||
#endif
|
||||
|
||||
#ifndef PRIuMAX
|
||||
# define PRIuMAX PRIu64
|
||||
#define PRIuMAX PRIu64
|
||||
#endif
|
||||
|
||||
#ifndef PRIxMAX
|
||||
@@ -97,23 +97,23 @@ WINBASEAPI BOOL WINAPI IsDebuggerPresent(VOID);
|
||||
#else /* _WIN32 */
|
||||
|
||||
#ifndef __PRI64_PREFIX
|
||||
# if __WORDSIZE == 64
|
||||
# define __PRI64_PREFIX "l"
|
||||
# else
|
||||
# define __PRI64_PREFIX "ll"
|
||||
# endif
|
||||
#if __WORDSIZE == 64
|
||||
#define __PRI64_PREFIX "l"
|
||||
#else
|
||||
#define __PRI64_PREFIX "ll"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef PRIdS
|
||||
# define PRIdS "zd"
|
||||
#define PRIdS "zd"
|
||||
#endif
|
||||
|
||||
#ifndef PRIu64
|
||||
# define PRIu64 __PRI64_PREFIX "u"
|
||||
#define PRIu64 __PRI64_PREFIX "u"
|
||||
#endif
|
||||
|
||||
#ifndef PRIuMAX
|
||||
# define PRIuMAX __PRI64_PREFIX "u"
|
||||
#define PRIuMAX __PRI64_PREFIX "u"
|
||||
#endif
|
||||
|
||||
#ifndef PRIxMAX
|
||||
@@ -127,19 +127,33 @@ WINBASEAPI BOOL WINAPI IsDebuggerPresent(VOID);
|
||||
#endif /* _WIN32 */
|
||||
|
||||
/** Free memory space */
|
||||
#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
|
||||
#define SAFE_FREE(x) \
|
||||
do { \
|
||||
if ((x) != NULL) { \
|
||||
free(x); \
|
||||
x = NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/** Zero a structure */
|
||||
#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
|
||||
#define ZERO_STRUCT(x) memset((char *) &(x), 0, sizeof(x))
|
||||
|
||||
/** Zero a structure given a pointer to the structure */
|
||||
#define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } while(0)
|
||||
#define ZERO_STRUCTP(x) \
|
||||
do { \
|
||||
if ((x) != NULL) \
|
||||
memset((char *) (x), 0, sizeof(*(x))); \
|
||||
} while (0)
|
||||
|
||||
/** Get the size of an array */
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
||||
|
||||
/** Overwrite the complete string with 'X' */
|
||||
#define BURN_STRING(x) do { if ((x) != NULL) memset((x), 'X', strlen((x))); } while(0)
|
||||
#define BURN_STRING(x) \
|
||||
do { \
|
||||
if ((x) != NULL) \
|
||||
memset((x), 'X', strlen((x))); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* This is a hack to fix warnings. The idea is to use this everywhere that we
|
||||
@@ -153,11 +167,11 @@ WINBASEAPI BOOL WINAPI IsDebuggerPresent(VOID);
|
||||
* Also, please call this via the discard_const_p() macro interface, as that
|
||||
* makes the return type safe.
|
||||
*/
|
||||
#define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
|
||||
#define discard_const(ptr) ((void *) ((uintptr_t)(ptr)))
|
||||
|
||||
/**
|
||||
* Type-safe version of discard_const
|
||||
*/
|
||||
#define discard_const_p(type, ptr) ((type *)discard_const(ptr))
|
||||
#define discard_const_p(type, ptr) ((type *) discard_const(ptr))
|
||||
|
||||
#endif /* CMOCKA_PRIVATE_H_ */
|
||||
|
||||
+3111
-1487
File diff suppressed because it is too large
Load Diff
+219
-97
@@ -1,11 +1,17 @@
|
||||
/* ==================================================================================================== */
|
||||
/* FMOD Ex - codec development header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2016. */
|
||||
/* ====================================================================================================
|
||||
*/
|
||||
/* FMOD Ex - codec development header file. Copyright (c), Firelight
|
||||
* Technologies Pty, Ltd. 2004-2016. */
|
||||
/* */
|
||||
/* Use this header if you are wanting to develop your own file format plugin to use with */
|
||||
/* FMOD's codec system. With this header you can make your own fileformat plugin that FMOD */
|
||||
/* can register and use. See the documentation and examples on how to make a working plugin. */
|
||||
/* Use this header if you are wanting to develop your own file format plugin to
|
||||
* use with */
|
||||
/* FMOD's codec system. With this header you can make your own fileformat
|
||||
* plugin that FMOD */
|
||||
/* can register and use. See the documentation and examples on how to make a
|
||||
* working plugin. */
|
||||
/* */
|
||||
/* ==================================================================================================== */
|
||||
/* ====================================================================================================
|
||||
*/
|
||||
|
||||
#ifndef _FMOD_CODEC_H
|
||||
#define _FMOD_CODEC_H
|
||||
@@ -15,145 +21,261 @@ typedef struct FMOD_CODEC_WAVEFORMAT FMOD_CODEC_WAVEFORMAT;
|
||||
|
||||
/*
|
||||
Codec callbacks
|
||||
*/
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_OPENCALLBACK) (FMOD_CODEC_STATE *codec_state, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_CLOSECALLBACK) (FMOD_CODEC_STATE *codec_state);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_READCALLBACK) (FMOD_CODEC_STATE *codec_state, void *buffer, unsigned int sizebytes, unsigned int *bytesread);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_GETLENGTHCALLBACK) (FMOD_CODEC_STATE *codec_state, unsigned int *length, FMOD_TIMEUNIT lengthtype);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_SETPOSITIONCALLBACK) (FMOD_CODEC_STATE *codec_state, int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_GETPOSITIONCALLBACK) (FMOD_CODEC_STATE *codec_state, unsigned int *position, FMOD_TIMEUNIT postype);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_SOUNDCREATECALLBACK) (FMOD_CODEC_STATE *codec_state, int subsound, FMOD_SOUND *sound);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_METADATACALLBACK) (FMOD_CODEC_STATE *codec_state, FMOD_TAGTYPE tagtype, char *name, void *data, unsigned int datalen, FMOD_TAGDATATYPE datatype, int unique);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_GETWAVEFORMAT) (FMOD_CODEC_STATE *codec_state, int index, FMOD_CODEC_WAVEFORMAT *waveformat);
|
||||
|
||||
*/
|
||||
typedef FMOD_RESULT(F_CALLBACK *FMOD_CODEC_OPENCALLBACK)(
|
||||
FMOD_CODEC_STATE *codec_state,
|
||||
FMOD_MODE usermode,
|
||||
FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
typedef FMOD_RESULT(F_CALLBACK *FMOD_CODEC_CLOSECALLBACK)(
|
||||
FMOD_CODEC_STATE *codec_state);
|
||||
typedef FMOD_RESULT(F_CALLBACK *FMOD_CODEC_READCALLBACK)(
|
||||
FMOD_CODEC_STATE *codec_state,
|
||||
void *buffer,
|
||||
unsigned int sizebytes,
|
||||
unsigned int *bytesread);
|
||||
typedef FMOD_RESULT(F_CALLBACK *FMOD_CODEC_GETLENGTHCALLBACK)(
|
||||
FMOD_CODEC_STATE *codec_state,
|
||||
unsigned int *length,
|
||||
FMOD_TIMEUNIT lengthtype);
|
||||
typedef FMOD_RESULT(F_CALLBACK *FMOD_CODEC_SETPOSITIONCALLBACK)(
|
||||
FMOD_CODEC_STATE *codec_state,
|
||||
int subsound,
|
||||
unsigned int position,
|
||||
FMOD_TIMEUNIT postype);
|
||||
typedef FMOD_RESULT(F_CALLBACK *FMOD_CODEC_GETPOSITIONCALLBACK)(
|
||||
FMOD_CODEC_STATE *codec_state,
|
||||
unsigned int *position,
|
||||
FMOD_TIMEUNIT postype);
|
||||
typedef FMOD_RESULT(F_CALLBACK *FMOD_CODEC_SOUNDCREATECALLBACK)(
|
||||
FMOD_CODEC_STATE *codec_state, int subsound, FMOD_SOUND *sound);
|
||||
typedef FMOD_RESULT(F_CALLBACK *FMOD_CODEC_METADATACALLBACK)(
|
||||
FMOD_CODEC_STATE *codec_state,
|
||||
FMOD_TAGTYPE tagtype,
|
||||
char *name,
|
||||
void *data,
|
||||
unsigned int datalen,
|
||||
FMOD_TAGDATATYPE datatype,
|
||||
int unique);
|
||||
typedef FMOD_RESULT(F_CALLBACK *FMOD_CODEC_GETWAVEFORMAT)(
|
||||
FMOD_CODEC_STATE *codec_state,
|
||||
int index,
|
||||
FMOD_CODEC_WAVEFORMAT *waveformat);
|
||||
|
||||
/*
|
||||
[STRUCTURE]
|
||||
[STRUCTURE]
|
||||
[
|
||||
[DESCRIPTION]
|
||||
When creating a codec, declare one of these and provide the relevant callbacks and name for FMOD to use when it opens and reads a file.
|
||||
When creating a codec, declare one of these and provide the relevant
|
||||
callbacks and name for FMOD to use when it opens and reads a file.
|
||||
|
||||
[REMARKS]
|
||||
Members marked with [in] mean the variable can be written to. The user can set the value.<br>
|
||||
Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.<br>
|
||||
Members marked with [in] mean the variable can be written to. The user can
|
||||
set the value.<br> Members marked with [out] mean the variable is modified by
|
||||
FMOD and is for reading purposes only. Do not change this value.<br>
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable,
|
||||
PlayStation 3, Wii, iPhone, 3GS, NGP, Android
|
||||
|
||||
[SEE_ALSO]
|
||||
FMOD_CODEC_STATE
|
||||
]
|
||||
*/
|
||||
typedef struct FMOD_CODEC_DESCRIPTION
|
||||
{
|
||||
const char *name; /* [in] Name of the codec. */
|
||||
unsigned int version; /* [in] Plugin writer's version number. */
|
||||
int defaultasstream; /* [in] Tells FMOD to open the file as a stream when calling System::createSound, and not a static sample. Should normally be 0 (FALSE), because generally the user wants to decode the file into memory when using System::createSound. Mainly used for formats that decode for a very long time, or could use large amounts of memory when decoded. Usually sequenced formats such as mod/s3m/xm/it/midi fall into this category. It is mainly to stop users that don't know what they're doing from getting FMOD_ERR_MEMORY returned from createSound when they should have in fact called System::createStream or used FMOD_CREATESTREAM in System::createSound. */
|
||||
FMOD_TIMEUNIT timeunits; /* [in] When setposition codec is called, only these time formats will be passed to the codec. Use bitwise OR to accumulate different types. */
|
||||
FMOD_CODEC_OPENCALLBACK open; /* [in] Open callback for the codec for when FMOD tries to open a sound using this codec. */
|
||||
FMOD_CODEC_CLOSECALLBACK close; /* [in] Close callback for the codec for when FMOD tries to close a sound using this codec. */
|
||||
FMOD_CODEC_READCALLBACK read; /* [in] Read callback for the codec for when FMOD tries to read some data from the file to the destination format (specified in the open callback). */
|
||||
FMOD_CODEC_GETLENGTHCALLBACK getlength; /* [in] Callback to return the length of the song in whatever format required when Sound::getLength is called. */
|
||||
FMOD_CODEC_SETPOSITIONCALLBACK setposition; /* [in] Seek callback for the codec for when FMOD tries to seek within the file with Channel::setPosition. */
|
||||
FMOD_CODEC_GETPOSITIONCALLBACK getposition; /* [in] Tell callback for the codec for when FMOD tries to get the current position within the with Channel::getPosition. */
|
||||
FMOD_CODEC_SOUNDCREATECALLBACK soundcreate; /* [in] Sound creation callback for the codec when FMOD finishes creating the sound. (So the codec can set more parameters for the related created sound, ie loop points/mode or 3D attributes etc). */
|
||||
FMOD_CODEC_GETWAVEFORMAT getwaveformat; /* [in] Callback to tell FMOD about the waveformat of a particular subsound. This is to save memory, rather than saving 1000 FMOD_CODEC_WAVEFORMAT structures in the codec, the codec might have a more optimal way of storing this information. */
|
||||
typedef struct FMOD_CODEC_DESCRIPTION {
|
||||
const char *name; /* [in] Name of the codec. */
|
||||
unsigned int version; /* [in] Plugin writer's version number. */
|
||||
int defaultasstream; /* [in] Tells FMOD to open the file as a stream when
|
||||
calling System::createSound, and not a static sample.
|
||||
Should normally be 0 (FALSE), because generally the
|
||||
user wants to decode the file into memory when using
|
||||
System::createSound. Mainly used for formats that
|
||||
decode for a very long time, or could use large
|
||||
amounts of memory when decoded. Usually sequenced
|
||||
formats such as mod/s3m/xm/it/midi fall into this
|
||||
category. It is mainly to stop users that don't know
|
||||
what they're doing from getting FMOD_ERR_MEMORY
|
||||
returned from createSound when they should have in
|
||||
fact called System::createStream or used
|
||||
FMOD_CREATESTREAM in System::createSound. */
|
||||
FMOD_TIMEUNIT timeunits; /* [in] When setposition codec is called, only these
|
||||
time formats will be passed to the codec. Use
|
||||
bitwise OR to accumulate different types. */
|
||||
FMOD_CODEC_OPENCALLBACK
|
||||
open; /* [in] Open callback for the codec for when FMOD tries to open a
|
||||
sound using this codec. */
|
||||
FMOD_CODEC_CLOSECALLBACK
|
||||
close; /* [in] Close callback for the codec for when FMOD tries to close a
|
||||
sound using this codec. */
|
||||
FMOD_CODEC_READCALLBACK
|
||||
read; /* [in] Read callback for the codec for when FMOD tries to read some
|
||||
data from the file to the destination format (specified in the
|
||||
open callback). */
|
||||
FMOD_CODEC_GETLENGTHCALLBACK
|
||||
getlength; /* [in] Callback to return the length of the song in whatever
|
||||
format required when Sound::getLength is called. */
|
||||
FMOD_CODEC_SETPOSITIONCALLBACK
|
||||
setposition; /* [in] Seek callback for the codec for when FMOD tries to
|
||||
seek within the file with Channel::setPosition. */
|
||||
FMOD_CODEC_GETPOSITIONCALLBACK
|
||||
getposition; /* [in] Tell callback for the codec for when FMOD tries to
|
||||
get the current position within the with
|
||||
Channel::getPosition. */
|
||||
FMOD_CODEC_SOUNDCREATECALLBACK
|
||||
soundcreate; /* [in] Sound creation callback for the codec when FMOD
|
||||
finishes creating the sound. (So the codec can set more
|
||||
parameters for the related created sound, ie loop
|
||||
points/mode or 3D attributes etc). */
|
||||
FMOD_CODEC_GETWAVEFORMAT
|
||||
getwaveformat; /* [in] Callback to tell FMOD about the waveformat of a
|
||||
particular subsound. This is to save memory, rather
|
||||
than saving 1000 FMOD_CODEC_WAVEFORMAT structures in the
|
||||
codec, the codec might have a more optimal way of
|
||||
storing this information. */
|
||||
} FMOD_CODEC_DESCRIPTION;
|
||||
|
||||
|
||||
/*
|
||||
[STRUCTURE]
|
||||
[STRUCTURE]
|
||||
[
|
||||
[DESCRIPTION]
|
||||
Set these values marked 'in' to tell fmod what sort of sound to create.<br>
|
||||
The format, channels and frequency tell FMOD what sort of hardware buffer to create when you initialize your code. So if you wrote an MP3 codec that decoded to stereo 16bit integer PCM, you would specify FMOD_SOUND_FORMAT_PCM16, and channels would be equal to 2.<br>
|
||||
Members marked as 'out' are set by fmod. Do not modify these. Simply specify 0 for these values when declaring the structure, FMOD will fill in the values for you after creation with the correct function pointers.<br>
|
||||
The format, channels and frequency tell FMOD what sort of hardware buffer to
|
||||
create when you initialize your code. So if you wrote an MP3 codec that decoded
|
||||
to stereo 16bit integer PCM, you would specify FMOD_SOUND_FORMAT_PCM16, and
|
||||
channels would be equal to 2.<br> Members marked as 'out' are set by fmod. Do
|
||||
not modify these. Simply specify 0 for these values when declaring the
|
||||
structure, FMOD will fill in the values for you after creation with the correct
|
||||
function pointers.<br>
|
||||
|
||||
[REMARKS]
|
||||
Members marked with [in] mean the variable can be written to. The user can set the value.<br>
|
||||
Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.<br>
|
||||
<br>
|
||||
An FMOD file might be from disk, memory or network, however the file may be opened by the user.<br>
|
||||
<br>
|
||||
'numsubsounds' should be 0 if the file is a normal single sound stream or sound. Examples of this would be .WAV, .WMA, .MP3, .AIFF.<br>
|
||||
'numsubsounds' should be 1+ if the file is a container format, and does not contain wav data itself. Examples of these types would be CDDA (multiple CD tracks), FSB (contains multiple sounds), MIDI/MOD/S3M/XM/IT (contain instruments).<br>
|
||||
The arrays of format, channel, frequency, length and blockalign should point to arrays of information based on how many subsounds are in the format. If the number of subsounds is 0 then it should point to 1 of each attribute, the same as if the number of subsounds was 1. If subsounds was 100 for example, each pointer should point to an array of 100 of each attribute.<br>
|
||||
When a sound has 1 or more subsounds, you must play the individual sounds specified by first obtaining the subsound with Sound::getSubSound.
|
||||
|
||||
Members marked with [in] mean the variable can be written to. The user can
|
||||
set the value.<br> Members marked with [out] mean the variable is modified by
|
||||
FMOD and is for reading purposes only. Do not change this value.<br> <br> An
|
||||
FMOD file might be from disk, memory or network, however the file may be opened
|
||||
by the user.<br> <br> 'numsubsounds' should be 0 if the file is a normal single
|
||||
sound stream or sound. Examples of this would be .WAV, .WMA, .MP3, .AIFF.<br>
|
||||
'numsubsounds' should be 1+ if the file is a container format, and does not
|
||||
contain wav data itself. Examples of these types would be CDDA (multiple CD
|
||||
tracks), FSB (contains multiple sounds), MIDI/MOD/S3M/XM/IT (contain
|
||||
instruments).<br> The arrays of format, channel, frequency, length and
|
||||
blockalign should point to arrays of information based on how many subsounds are
|
||||
in the format. If the number of subsounds is 0 then it should point to 1 of
|
||||
each attribute, the same as if the number of subsounds was 1. If subsounds was
|
||||
100 for example, each pointer should point to an array of 100 of each
|
||||
attribute.<br> When a sound has 1 or more subsounds, you must play the
|
||||
individual sounds specified by first obtaining the subsound with
|
||||
Sound::getSubSound.
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable,
|
||||
PlayStation 3, Wii, iPhone, 3GS, NGP, Android
|
||||
|
||||
[SEE_ALSO]
|
||||
FMOD_SOUND_FORMAT
|
||||
FMOD_FILE_READCALLBACK
|
||||
FMOD_FILE_SEEKCALLBACK
|
||||
FMOD_FILE_READCALLBACK
|
||||
FMOD_FILE_SEEKCALLBACK
|
||||
FMOD_CODEC_METADATACALLBACK
|
||||
Sound::getSubSound
|
||||
Sound::getNumSubSounds
|
||||
]
|
||||
*/
|
||||
struct FMOD_CODEC_WAVEFORMAT
|
||||
{
|
||||
char name[256]; /* [in] Name of sound.*/
|
||||
FMOD_SOUND_FORMAT format; /* [in] Format for (decompressed) codec output, ie FMOD_SOUND_FORMAT_PCM8, FMOD_SOUND_FORMAT_PCM16.*/
|
||||
int channels; /* [in] Number of channels used by codec, ie mono = 1, stereo = 2. */
|
||||
int frequency; /* [in] Default frequency in hz of the codec, ie 44100. */
|
||||
unsigned int lengthbytes; /* [in] Length in bytes of the source data. */
|
||||
unsigned int lengthpcm; /* [in] Length in decompressed, PCM samples of the file, ie length in seconds * frequency. Used for Sound::getLength and for memory allocation of static decompressed sample data. */
|
||||
int blockalign; /* [in] Blockalign in decompressed, PCM samples of the optimal decode chunk size for this format. The codec read callback will be called in multiples of this value. */
|
||||
int loopstart; /* [in] Loopstart in decompressed, PCM samples of file. */
|
||||
int loopend; /* [in] Loopend in decompressed, PCM samples of file. */
|
||||
FMOD_MODE mode; /* [in] Mode to determine whether the sound should by default load as looping, non looping, 2d or 3d. */
|
||||
unsigned int channelmask; /* [in] Microsoft speaker channel mask, as defined for WAVEFORMATEXTENSIBLE and is found in ksmedia.h. Leave at 0 to play in natural speaker order. */
|
||||
struct FMOD_CODEC_WAVEFORMAT {
|
||||
char name[256]; /* [in] Name of sound.*/
|
||||
FMOD_SOUND_FORMAT
|
||||
format; /* [in] Format for (decompressed) codec output, ie
|
||||
FMOD_SOUND_FORMAT_PCM8, FMOD_SOUND_FORMAT_PCM16.*/
|
||||
int channels; /* [in] Number of channels used by codec, ie mono = 1, stereo
|
||||
= 2. */
|
||||
int frequency; /* [in] Default frequency in hz of the codec, ie 44100. */
|
||||
unsigned int lengthbytes; /* [in] Length in bytes of the source data. */
|
||||
unsigned int lengthpcm; /* [in] Length in decompressed, PCM samples of the
|
||||
file, ie length in seconds * frequency. Used for
|
||||
Sound::getLength and for memory allocation of
|
||||
static decompressed sample data. */
|
||||
int blockalign; /* [in] Blockalign in decompressed, PCM samples of the optimal
|
||||
decode chunk size for this format. The codec read callback
|
||||
will be called in multiples of this value. */
|
||||
int loopstart; /* [in] Loopstart in decompressed, PCM samples of file. */
|
||||
int loopend; /* [in] Loopend in decompressed, PCM samples of file. */
|
||||
FMOD_MODE mode; /* [in] Mode to determine whether the sound should by default
|
||||
load as looping, non looping, 2d or 3d. */
|
||||
unsigned int
|
||||
channelmask; /* [in] Microsoft speaker channel mask, as defined for
|
||||
WAVEFORMATEXTENSIBLE and is found in ksmedia.h. Leave at
|
||||
0 to play in natural speaker order. */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
[STRUCTURE]
|
||||
[STRUCTURE]
|
||||
[
|
||||
[DESCRIPTION]
|
||||
Codec plugin structure that is passed into each callback.<br>
|
||||
<br>
|
||||
Set these numsubsounds and waveformat members when called in FMOD_CODEC_OPENCALLBACK to tell fmod what sort of sound to create.<br>
|
||||
<br>
|
||||
The format, channels and frequency tell FMOD what sort of hardware buffer to create when you initialize your code. So if you wrote an MP3 codec that decoded to stereo 16bit integer PCM, you would specify FMOD_SOUND_FORMAT_PCM16, and channels would be equal to 2.<br>
|
||||
Set these numsubsounds and waveformat members when called in
|
||||
FMOD_CODEC_OPENCALLBACK to tell fmod what sort of sound to create.<br> <br> The
|
||||
format, channels and frequency tell FMOD what sort of hardware buffer to create
|
||||
when you initialize your code. So if you wrote an MP3 codec that decoded to
|
||||
stereo 16bit integer PCM, you would specify FMOD_SOUND_FORMAT_PCM16, and
|
||||
channels would be equal to 2.<br>
|
||||
|
||||
[REMARKS]
|
||||
Members marked with [in] mean the variable can be written to. The user can set the value.<br>
|
||||
Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.<br>
|
||||
<br>
|
||||
An FMOD file might be from disk, memory or internet, however the file may be opened by the user.<br>
|
||||
<br>
|
||||
'numsubsounds' should be 0 if the file is a normal single sound stream or sound. Examples of this would be .WAV, .WMA, .MP3, .AIFF.<br>
|
||||
'numsubsounds' should be 1+ if the file is a container format, and does not contain wav data itself. Examples of these types would be CDDA (multiple CD tracks), FSB (contains multiple sounds), DLS (contain instruments).<br>
|
||||
The arrays of format, channel, frequency, length and blockalign should point to arrays of information based on how many subsounds are in the format. If the number of subsounds is 0 then it should point to 1 of each attribute, the same as if the number of subsounds was 1. If subsounds was 100 for example, each pointer should point to an array of 100 of each attribute.<br>
|
||||
When a sound has 1 or more subsounds, you must play the individual sounds specified by first obtaining the subsound with Sound::getSubSound.
|
||||
|
||||
Members marked with [in] mean the variable can be written to. The user can
|
||||
set the value.<br> Members marked with [out] mean the variable is modified by
|
||||
FMOD and is for reading purposes only. Do not change this value.<br> <br> An
|
||||
FMOD file might be from disk, memory or internet, however the file may be opened
|
||||
by the user.<br> <br> 'numsubsounds' should be 0 if the file is a normal single
|
||||
sound stream or sound. Examples of this would be .WAV, .WMA, .MP3, .AIFF.<br>
|
||||
'numsubsounds' should be 1+ if the file is a container format, and does not
|
||||
contain wav data itself. Examples of these types would be CDDA (multiple CD
|
||||
tracks), FSB (contains multiple sounds), DLS (contain instruments).<br> The
|
||||
arrays of format, channel, frequency, length and blockalign should point to
|
||||
arrays of information based on how many subsounds are in the format. If the
|
||||
number of subsounds is 0 then it should point to 1 of each attribute, the same
|
||||
as if the number of subsounds was 1. If subsounds was 100 for example, each
|
||||
pointer should point to an array of 100 of each attribute.<br> When a sound has
|
||||
1 or more subsounds, you must play the individual sounds specified by first
|
||||
obtaining the subsound with Sound::getSubSound.
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable,
|
||||
PlayStation 3, Wii, iPhone, 3GS, NGP, Android
|
||||
|
||||
[SEE_ALSO]
|
||||
FMOD_SOUND_FORMAT
|
||||
FMOD_FILE_READCALLBACK
|
||||
FMOD_FILE_SEEKCALLBACK
|
||||
FMOD_FILE_READCALLBACK
|
||||
FMOD_FILE_SEEKCALLBACK
|
||||
FMOD_CODEC_METADATACALLBACK
|
||||
Sound::getSubSound
|
||||
Sound::getNumSubSounds
|
||||
]
|
||||
*/
|
||||
struct FMOD_CODEC_STATE
|
||||
{
|
||||
int numsubsounds; /* [in] Number of 'subsounds' in this sound. Anything other than 0 makes it a 'container' format (ie CDDA/DLS/FSB etc which contain 1 or more su bsounds). For most normal, single sound codec such as WAV/AIFF/MP3, this should be 0 as they are not a container for subsounds, they are the sound by itself. */
|
||||
FMOD_CODEC_WAVEFORMAT *waveformat; /* [in] Pointer to an array of format structures containing information about each sample. Can be 0 or NULL if FMOD_CODEC_GETWAVEFORMAT callback is preferred. The number of entries here must equal the number of subsounds defined in the subsound parameter. If numsubsounds = 0 then there should be 1 instance of this structure. */
|
||||
void *plugindata; /* [in] Plugin writer created data the codec author wants to attach to this object. */
|
||||
|
||||
void *filehandle; /* [out] This will return an internal FMOD file handle to use with the callbacks provided. */
|
||||
unsigned int filesize; /* [out] This will contain the size of the file in bytes. */
|
||||
FMOD_FILE_READCALLBACK fileread; /* [out] This will return a callable FMOD file function to use from codec. */
|
||||
FMOD_FILE_SEEKCALLBACK fileseek; /* [out] This will return a callable FMOD file function to use from codec. */
|
||||
FMOD_CODEC_METADATACALLBACK metadata; /* [out] This will return a callable FMOD metadata function to use from codec. */
|
||||
struct FMOD_CODEC_STATE {
|
||||
int numsubsounds; /* [in] Number of 'subsounds' in this sound. Anything other
|
||||
than 0 makes it a 'container' format (ie CDDA/DLS/FSB etc
|
||||
which contain 1 or more su bsounds). For most normal,
|
||||
single sound codec such as WAV/AIFF/MP3, this should be 0
|
||||
as they are not a container for subsounds, they are the
|
||||
sound by itself. */
|
||||
FMOD_CODEC_WAVEFORMAT
|
||||
*waveformat; /* [in] Pointer to an array of format structures containing
|
||||
information about each sample. Can be 0 or NULL if
|
||||
FMOD_CODEC_GETWAVEFORMAT callback is preferred. The
|
||||
number of entries here must equal the number of subsounds
|
||||
defined in the subsound parameter. If numsubsounds = 0
|
||||
then there should be 1 instance of this structure. */
|
||||
void *plugindata; /* [in] Plugin writer created data the codec author wants to
|
||||
attach to this object. */
|
||||
|
||||
void *filehandle; /* [out] This will return an internal FMOD file handle to
|
||||
use with the callbacks provided. */
|
||||
unsigned int
|
||||
filesize; /* [out] This will contain the size of the file in bytes. */
|
||||
FMOD_FILE_READCALLBACK fileread; /* [out] This will return a callable FMOD
|
||||
file function to use from codec. */
|
||||
FMOD_FILE_SEEKCALLBACK fileseek; /* [out] This will return a callable FMOD
|
||||
file function to use from codec. */
|
||||
FMOD_CODEC_METADATACALLBACK
|
||||
metadata; /* [out] This will return a callable FMOD metadata function to
|
||||
use from codec. */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
+611
-387
File diff suppressed because it is too large
Load Diff
+273
-109
@@ -1,126 +1,290 @@
|
||||
/*$ preserve start $*/
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* FMOD Ex - Error string header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2016. */
|
||||
/* ==============================================================================================
|
||||
*/
|
||||
/* FMOD Ex - Error string header file. Copyright (c), Firelight Technologies
|
||||
* Pty, Ltd. 2004-2016. */
|
||||
/* */
|
||||
/* Use this header if you want to store or display a string version / english explanation of */
|
||||
/* the FMOD error codes. */
|
||||
/* Use this header if you want to store or display a string version / english
|
||||
* explanation of */
|
||||
/* the FMOD error codes. */
|
||||
/* */
|
||||
/* ============================================================================================== */
|
||||
/* ==============================================================================================
|
||||
*/
|
||||
|
||||
#ifndef _FMOD_ERRORS_H
|
||||
#define _FMOD_ERRORS_H
|
||||
|
||||
#include "fmod.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
static const char *FMOD_ErrorString(FMOD_RESULT errcode) __attribute__((unused));
|
||||
#ifdef __GNUC__
|
||||
static const char *FMOD_ErrorString(FMOD_RESULT errcode)
|
||||
__attribute__((unused));
|
||||
#endif
|
||||
|
||||
static const char *FMOD_ErrorString(FMOD_RESULT errcode)
|
||||
{
|
||||
switch (errcode)
|
||||
{
|
||||
/*$ preserve end $*/
|
||||
case FMOD_ERR_ALREADYLOCKED: return "Tried to call lock a second time before unlock was called. ";
|
||||
case FMOD_ERR_BADCOMMAND: return "Tried to call a function on a data type that does not allow this type of functionality (ie calling Sound::lock on a streaming sound). ";
|
||||
case FMOD_ERR_CDDA_DRIVERS: return "Neither NTSCSI nor ASPI could be initialised. ";
|
||||
case FMOD_ERR_CDDA_INIT: return "An error occurred while initialising the CDDA subsystem. ";
|
||||
case FMOD_ERR_CDDA_INVALID_DEVICE: return "Couldn't find the specified device. ";
|
||||
case FMOD_ERR_CDDA_NOAUDIO: return "No audio tracks on the specified disc. ";
|
||||
case FMOD_ERR_CDDA_NODEVICES: return "No CD/DVD devices were found. ";
|
||||
case FMOD_ERR_CDDA_NODISC: return "No disc present in the specified drive. ";
|
||||
case FMOD_ERR_CDDA_READ: return "A CDDA read error occurred. ";
|
||||
case FMOD_ERR_CHANNEL_ALLOC: return "Error trying to allocate a channel. ";
|
||||
case FMOD_ERR_CHANNEL_STOLEN: return "The specified channel has been reused to play another sound. ";
|
||||
case FMOD_ERR_COM: return "A Win32 COM related error occured. COM failed to initialize or a QueryInterface failed meaning a Windows codec or driver was not installed properly. ";
|
||||
case FMOD_ERR_DMA: return "DMA Failure. See debug output for more information. ";
|
||||
case FMOD_ERR_DSP_CONNECTION: return "DSP connection error. Connection possibly caused a cyclic dependancy. Or tried to connect a tree too many units deep (more than 128). ";
|
||||
case FMOD_ERR_DSP_FORMAT: return "DSP Format error. A DSP unit may have attempted to connect to this network with the wrong format. ";
|
||||
case FMOD_ERR_DSP_NOTFOUND: return "DSP connection error. Couldn't find the DSP unit specified. ";
|
||||
case FMOD_ERR_DSP_RUNNING: return "DSP error. Cannot perform this operation while the network is in the middle of running. This will most likely happen if a connection or disconnection is attempted in a DSP callback. ";
|
||||
case FMOD_ERR_DSP_TOOMANYCONNECTIONS: return "DSP connection error. The unit being connected to or disconnected should only have 1 input or output. ";
|
||||
case FMOD_ERR_EVENT_ALREADY_LOADED: return "The specified project or bank has already been loaded. Having multiple copies of the same project loaded simultaneously is forbidden. ";
|
||||
case FMOD_ERR_EVENT_FAILED: return "An Event failed to be retrieved, most likely due to 'just fail' being specified as the max playbacks behavior. ";
|
||||
case FMOD_ERR_EVENT_GUIDCONFLICT: return "An event with the same GUID already exists. ";
|
||||
case FMOD_ERR_EVENT_INFOONLY: return "Can't execute this command on an EVENT_INFOONLY event. ";
|
||||
case FMOD_ERR_EVENT_INTERNAL: return "An error occured that wasn't supposed to. See debug log for reason. ";
|
||||
case FMOD_ERR_EVENT_MAXSTREAMS: return "Event failed because 'Max streams' was hit when FMOD_EVENT_INIT_FAIL_ON_MAXSTREAMS was specified. ";
|
||||
case FMOD_ERR_EVENT_MISMATCH: return "FSB mismatches the FEV it was compiled with, the stream/sample mode it was meant to be created with was different, or the FEV was built for a different platform. ";
|
||||
case FMOD_ERR_EVENT_NAMECONFLICT: return "A category with the same name already exists. ";
|
||||
case FMOD_ERR_EVENT_NEEDSSIMPLE: return "Tried to call a function on a complex event that's only supported by simple events. ";
|
||||
case FMOD_ERR_EVENT_NOTFOUND: return "The requested event, event group, event category or event property could not be found. ";
|
||||
case FMOD_ERR_FILE_BAD: return "Error loading file. ";
|
||||
case FMOD_ERR_FILE_COULDNOTSEEK: return "Couldn't perform seek operation. This is a limitation of the medium (ie netstreams) or the file format. ";
|
||||
case FMOD_ERR_FILE_DISKEJECTED: return "Media was ejected while reading. ";
|
||||
case FMOD_ERR_FILE_EOF: return "End of file unexpectedly reached while trying to read essential data (truncated data?). ";
|
||||
case FMOD_ERR_FILE_NOTFOUND: return "File not found. ";
|
||||
case FMOD_ERR_FILE_UNWANTED: return "Unwanted file access occured. ";
|
||||
case FMOD_ERR_FORMAT: return "Unsupported file or audio format. ";
|
||||
case FMOD_ERR_HTTP: return "A HTTP error occurred. This is a catch-all for HTTP errors not listed elsewhere. ";
|
||||
case FMOD_ERR_HTTP_ACCESS: return "The specified resource requires authentication or is forbidden. ";
|
||||
case FMOD_ERR_HTTP_PROXY_AUTH: return "Proxy authentication is required to access the specified resource. ";
|
||||
case FMOD_ERR_HTTP_SERVER_ERROR: return "A HTTP server error occurred. ";
|
||||
case FMOD_ERR_HTTP_TIMEOUT: return "The HTTP request timed out. ";
|
||||
case FMOD_ERR_INITIALIZATION: return "FMOD was not initialized correctly to support this function. ";
|
||||
case FMOD_ERR_INITIALIZED: return "Cannot call this command after System::init. ";
|
||||
case FMOD_ERR_INTERNAL: return "An error occured that wasn't supposed to. Contact support. ";
|
||||
case FMOD_ERR_INVALID_ADDRESS: return "On Xbox 360, this memory address passed to FMOD must be physical, (ie allocated with XPhysicalAlloc.) ";
|
||||
case FMOD_ERR_INVALID_FLOAT: return "Value passed in was a NaN, Inf or denormalized float. ";
|
||||
case FMOD_ERR_INVALID_HANDLE: return "An invalid object handle was used. ";
|
||||
case FMOD_ERR_INVALID_PARAM: return "An invalid parameter was passed to this function. ";
|
||||
case FMOD_ERR_INVALID_POSITION: return "An invalid seek position was passed to this function. ";
|
||||
case FMOD_ERR_INVALID_SPEAKER: return "An invalid speaker was passed to this function based on the current speaker mode. ";
|
||||
case FMOD_ERR_INVALID_SYNCPOINT: return "The syncpoint did not come from this sound handle. ";
|
||||
case FMOD_ERR_INVALID_VECTOR: return "The vectors passed in are not unit length, or perpendicular. ";
|
||||
case FMOD_ERR_MAXAUDIBLE: return "Reached maximum audible playback count for this sound's soundgroup. ";
|
||||
case FMOD_ERR_MEMORY: return "Not enough memory or resources. ";
|
||||
case FMOD_ERR_MEMORY_CANTPOINT: return "Can't use FMOD_OPENMEMORY_POINT on non PCM source data, or non mp3/xma/adpcm data if FMOD_CREATECOMPRESSEDSAMPLE was used. ";
|
||||
case FMOD_ERR_MEMORY_SRAM: return "Not enough memory or resources on console sound ram. ";
|
||||
case FMOD_ERR_MUSIC_NOCALLBACK: return "The music callback is required, but it has not been set. ";
|
||||
case FMOD_ERR_MUSIC_NOTFOUND: return "The requested music entity could not be found. ";
|
||||
case FMOD_ERR_MUSIC_UNINITIALIZED: return "Music system is not initialized probably because no music data is loaded. ";
|
||||
case FMOD_ERR_NEEDS2D: return "Tried to call a command on a 3d sound when the command was meant for 2d sound. ";
|
||||
case FMOD_ERR_NEEDS3D: return "Tried to call a command on a 2d sound when the command was meant for 3d sound. ";
|
||||
case FMOD_ERR_NEEDSHARDWARE: return "Tried to use a feature that requires hardware support. (ie trying to play a GCADPCM compressed sound in software on Wii). ";
|
||||
case FMOD_ERR_NEEDSSOFTWARE: return "Tried to use a feature that requires the software engine. Software engine has either been turned off, or command was executed on a hardware channel which does not support this feature. ";
|
||||
case FMOD_ERR_NET_CONNECT: return "Couldn't connect to the specified host. ";
|
||||
case FMOD_ERR_NET_SOCKET_ERROR: return "A socket error occurred. This is a catch-all for socket-related errors not listed elsewhere. ";
|
||||
case FMOD_ERR_NET_URL: return "The specified URL couldn't be resolved. ";
|
||||
case FMOD_ERR_NET_WOULD_BLOCK: return "Operation on a non-blocking socket could not complete immediately. ";
|
||||
case FMOD_ERR_NOTREADY: return "Operation could not be performed because specified sound/DSP connection is not ready. ";
|
||||
case FMOD_ERR_OUTPUT_ALLOCATED: return "Error initializing output device, but more specifically, the output device is already in use and cannot be reused. ";
|
||||
case FMOD_ERR_OUTPUT_CREATEBUFFER: return "Error creating hardware sound buffer. ";
|
||||
case FMOD_ERR_OUTPUT_DRIVERCALL: return "A call to a standard soundcard driver failed, which could possibly mean a bug in the driver or resources were missing or exhausted. ";
|
||||
case FMOD_ERR_OUTPUT_ENUMERATION: return "Error enumerating the available driver list. List may be inconsistent due to a recent device addition or removal. ";
|
||||
case FMOD_ERR_OUTPUT_FORMAT: return "Soundcard does not support the minimum features needed for this soundsystem (16bit stereo output). ";
|
||||
case FMOD_ERR_OUTPUT_INIT: return "Error initializing output device. ";
|
||||
case FMOD_ERR_OUTPUT_NOHARDWARE: return "FMOD_HARDWARE was specified but the sound card does not have the resources necessary to play it. ";
|
||||
case FMOD_ERR_OUTPUT_NOSOFTWARE: return "Attempted to create a software sound but no software channels were specified in System::init. ";
|
||||
case FMOD_ERR_PAN: return "Panning only works with mono or stereo sound sources. ";
|
||||
case FMOD_ERR_PLUGIN: return "An unspecified error has been returned from a 3rd party plugin. ";
|
||||
case FMOD_ERR_PLUGIN_INSTANCES: return "The number of allowed instances of a plugin has been exceeded. ";
|
||||
case FMOD_ERR_PLUGIN_MISSING: return "A requested output, dsp unit type or codec was not available. ";
|
||||
case FMOD_ERR_PLUGIN_RESOURCE: return "A resource that the plugin requires cannot be found. (ie the DLS file for MIDI playback or other DLLs that it needs to load) ";
|
||||
case FMOD_ERR_PRELOADED: return "The specified sound is still in use by the event system, call EventSystem::unloadFSB before trying to release it. ";
|
||||
case FMOD_ERR_PROGRAMMERSOUND: return "The specified sound is still in use by the event system, wait for the event which is using it finish with it. ";
|
||||
case FMOD_ERR_RECORD: return "An error occured trying to initialize the recording device. ";
|
||||
case FMOD_ERR_REVERB_INSTANCE: return "Specified instance in FMOD_REVERB_PROPERTIES couldn't be set. Most likely because it is an invalid instance number or the reverb doesnt exist. ";
|
||||
case FMOD_ERR_SUBSOUNDS: return "The error occured because the sound referenced contains subsounds when it shouldn't have, or it doesn't contain subsounds when it should have. The operation may also not be able to be performed on a parent sound, or a parent sound was played without setting up a sentence first. ";
|
||||
case FMOD_ERR_SUBSOUND_ALLOCATED: return "This subsound is already being used by another sound, you cannot have more than one parent to a sound. Null out the other parent's entry first. ";
|
||||
case FMOD_ERR_SUBSOUND_CANTMOVE: return "Shared subsounds cannot be replaced or moved from their parent stream, such as when the parent stream is an FSB file. ";
|
||||
case FMOD_ERR_SUBSOUND_MODE: return "The subsound's mode bits do not match with the parent sound's mode bits. See documentation for function that it was called with. ";
|
||||
case FMOD_ERR_TAGNOTFOUND: return "The specified tag could not be found or there are no tags. ";
|
||||
case FMOD_ERR_TOOMANYCHANNELS: return "The sound created exceeds the allowable input channel count. This can be increased using the maxinputchannels parameter in System::setSoftwareFormat. ";
|
||||
case FMOD_ERR_UNIMPLEMENTED: return "Something in FMOD hasn't been implemented when it should be! contact support! ";
|
||||
case FMOD_ERR_UNINITIALIZED: return "This command failed because System::init or System::setDriver was not called. ";
|
||||
case FMOD_ERR_UNSUPPORTED: return "A command issued was not supported by this object. Possibly a plugin without certain callbacks specified. ";
|
||||
case FMOD_ERR_UPDATE: return "An error caused by System::update occured. ";
|
||||
case FMOD_ERR_VERSION: return "The version number of this file format is not supported. ";
|
||||
case FMOD_OK: return "No errors.";
|
||||
default : return "Unknown error.";
|
||||
/*$ preserve start $*/
|
||||
};
|
||||
switch (errcode) {
|
||||
/*$ preserve end $*/
|
||||
case FMOD_ERR_ALREADYLOCKED:
|
||||
return "Tried to call lock a second time before unlock was called. ";
|
||||
case FMOD_ERR_BADCOMMAND:
|
||||
return "Tried to call a function on a data type that does not allow this "
|
||||
"type of functionality (ie calling Sound::lock on a streaming "
|
||||
"sound). ";
|
||||
case FMOD_ERR_CDDA_DRIVERS:
|
||||
return "Neither NTSCSI nor ASPI could be initialised. ";
|
||||
case FMOD_ERR_CDDA_INIT:
|
||||
return "An error occurred while initialising the CDDA subsystem. ";
|
||||
case FMOD_ERR_CDDA_INVALID_DEVICE:
|
||||
return "Couldn't find the specified device. ";
|
||||
case FMOD_ERR_CDDA_NOAUDIO:
|
||||
return "No audio tracks on the specified disc. ";
|
||||
case FMOD_ERR_CDDA_NODEVICES:
|
||||
return "No CD/DVD devices were found. ";
|
||||
case FMOD_ERR_CDDA_NODISC:
|
||||
return "No disc present in the specified drive. ";
|
||||
case FMOD_ERR_CDDA_READ:
|
||||
return "A CDDA read error occurred. ";
|
||||
case FMOD_ERR_CHANNEL_ALLOC:
|
||||
return "Error trying to allocate a channel. ";
|
||||
case FMOD_ERR_CHANNEL_STOLEN:
|
||||
return "The specified channel has been reused to play another sound. ";
|
||||
case FMOD_ERR_COM:
|
||||
return "A Win32 COM related error occured. COM failed to initialize or a "
|
||||
"QueryInterface failed meaning a Windows codec or driver was not "
|
||||
"installed properly. ";
|
||||
case FMOD_ERR_DMA:
|
||||
return "DMA Failure. See debug output for more information. ";
|
||||
case FMOD_ERR_DSP_CONNECTION:
|
||||
return "DSP connection error. Connection possibly caused a cyclic "
|
||||
"dependancy. Or tried to connect a tree too many units deep "
|
||||
"(more than 128). ";
|
||||
case FMOD_ERR_DSP_FORMAT:
|
||||
return "DSP Format error. A DSP unit may have attempted to connect to "
|
||||
"this network with the wrong format. ";
|
||||
case FMOD_ERR_DSP_NOTFOUND:
|
||||
return "DSP connection error. Couldn't find the DSP unit specified. ";
|
||||
case FMOD_ERR_DSP_RUNNING:
|
||||
return "DSP error. Cannot perform this operation while the network is "
|
||||
"in the middle of running. This will most likely happen if a "
|
||||
"connection or disconnection is attempted in a DSP callback. ";
|
||||
case FMOD_ERR_DSP_TOOMANYCONNECTIONS:
|
||||
return "DSP connection error. The unit being connected to or "
|
||||
"disconnected should only have 1 input or output. ";
|
||||
case FMOD_ERR_EVENT_ALREADY_LOADED:
|
||||
return "The specified project or bank has already been loaded. Having "
|
||||
"multiple copies of the same project loaded simultaneously is "
|
||||
"forbidden. ";
|
||||
case FMOD_ERR_EVENT_FAILED:
|
||||
return "An Event failed to be retrieved, most likely due to 'just fail' "
|
||||
"being specified as the max playbacks behavior. ";
|
||||
case FMOD_ERR_EVENT_GUIDCONFLICT:
|
||||
return "An event with the same GUID already exists. ";
|
||||
case FMOD_ERR_EVENT_INFOONLY:
|
||||
return "Can't execute this command on an EVENT_INFOONLY event. ";
|
||||
case FMOD_ERR_EVENT_INTERNAL:
|
||||
return "An error occured that wasn't supposed to. See debug log for "
|
||||
"reason. ";
|
||||
case FMOD_ERR_EVENT_MAXSTREAMS:
|
||||
return "Event failed because 'Max streams' was hit when "
|
||||
"FMOD_EVENT_INIT_FAIL_ON_MAXSTREAMS was specified. ";
|
||||
case FMOD_ERR_EVENT_MISMATCH:
|
||||
return "FSB mismatches the FEV it was compiled with, the stream/sample "
|
||||
"mode it was meant to be created with was different, or the FEV "
|
||||
"was built for a different platform. ";
|
||||
case FMOD_ERR_EVENT_NAMECONFLICT:
|
||||
return "A category with the same name already exists. ";
|
||||
case FMOD_ERR_EVENT_NEEDSSIMPLE:
|
||||
return "Tried to call a function on a complex event that's only "
|
||||
"supported by simple events. ";
|
||||
case FMOD_ERR_EVENT_NOTFOUND:
|
||||
return "The requested event, event group, event category or event "
|
||||
"property could not be found. ";
|
||||
case FMOD_ERR_FILE_BAD:
|
||||
return "Error loading file. ";
|
||||
case FMOD_ERR_FILE_COULDNOTSEEK:
|
||||
return "Couldn't perform seek operation. This is a limitation of the "
|
||||
"medium (ie netstreams) or the file format. ";
|
||||
case FMOD_ERR_FILE_DISKEJECTED:
|
||||
return "Media was ejected while reading. ";
|
||||
case FMOD_ERR_FILE_EOF:
|
||||
return "End of file unexpectedly reached while trying to read essential "
|
||||
"data (truncated data?). ";
|
||||
case FMOD_ERR_FILE_NOTFOUND:
|
||||
return "File not found. ";
|
||||
case FMOD_ERR_FILE_UNWANTED:
|
||||
return "Unwanted file access occured. ";
|
||||
case FMOD_ERR_FORMAT:
|
||||
return "Unsupported file or audio format. ";
|
||||
case FMOD_ERR_HTTP:
|
||||
return "A HTTP error occurred. This is a catch-all for HTTP errors not "
|
||||
"listed elsewhere. ";
|
||||
case FMOD_ERR_HTTP_ACCESS:
|
||||
return "The specified resource requires authentication or is forbidden. ";
|
||||
case FMOD_ERR_HTTP_PROXY_AUTH:
|
||||
return "Proxy authentication is required to access the specified "
|
||||
"resource. ";
|
||||
case FMOD_ERR_HTTP_SERVER_ERROR:
|
||||
return "A HTTP server error occurred. ";
|
||||
case FMOD_ERR_HTTP_TIMEOUT:
|
||||
return "The HTTP request timed out. ";
|
||||
case FMOD_ERR_INITIALIZATION:
|
||||
return "FMOD was not initialized correctly to support this function. ";
|
||||
case FMOD_ERR_INITIALIZED:
|
||||
return "Cannot call this command after System::init. ";
|
||||
case FMOD_ERR_INTERNAL:
|
||||
return "An error occured that wasn't supposed to. Contact support. ";
|
||||
case FMOD_ERR_INVALID_ADDRESS:
|
||||
return "On Xbox 360, this memory address passed to FMOD must be "
|
||||
"physical, (ie allocated with XPhysicalAlloc.) ";
|
||||
case FMOD_ERR_INVALID_FLOAT:
|
||||
return "Value passed in was a NaN, Inf or denormalized float. ";
|
||||
case FMOD_ERR_INVALID_HANDLE:
|
||||
return "An invalid object handle was used. ";
|
||||
case FMOD_ERR_INVALID_PARAM:
|
||||
return "An invalid parameter was passed to this function. ";
|
||||
case FMOD_ERR_INVALID_POSITION:
|
||||
return "An invalid seek position was passed to this function. ";
|
||||
case FMOD_ERR_INVALID_SPEAKER:
|
||||
return "An invalid speaker was passed to this function based on the "
|
||||
"current speaker mode. ";
|
||||
case FMOD_ERR_INVALID_SYNCPOINT:
|
||||
return "The syncpoint did not come from this sound handle. ";
|
||||
case FMOD_ERR_INVALID_VECTOR:
|
||||
return "The vectors passed in are not unit length, or perpendicular. ";
|
||||
case FMOD_ERR_MAXAUDIBLE:
|
||||
return "Reached maximum audible playback count for this sound's "
|
||||
"soundgroup. ";
|
||||
case FMOD_ERR_MEMORY:
|
||||
return "Not enough memory or resources. ";
|
||||
case FMOD_ERR_MEMORY_CANTPOINT:
|
||||
return "Can't use FMOD_OPENMEMORY_POINT on non PCM source data, or non "
|
||||
"mp3/xma/adpcm data if FMOD_CREATECOMPRESSEDSAMPLE was used. ";
|
||||
case FMOD_ERR_MEMORY_SRAM:
|
||||
return "Not enough memory or resources on console sound ram. ";
|
||||
case FMOD_ERR_MUSIC_NOCALLBACK:
|
||||
return "The music callback is required, but it has not been set. ";
|
||||
case FMOD_ERR_MUSIC_NOTFOUND:
|
||||
return "The requested music entity could not be found. ";
|
||||
case FMOD_ERR_MUSIC_UNINITIALIZED:
|
||||
return "Music system is not initialized probably because no music data "
|
||||
"is loaded. ";
|
||||
case FMOD_ERR_NEEDS2D:
|
||||
return "Tried to call a command on a 3d sound when the command was meant "
|
||||
"for 2d sound. ";
|
||||
case FMOD_ERR_NEEDS3D:
|
||||
return "Tried to call a command on a 2d sound when the command was meant "
|
||||
"for 3d sound. ";
|
||||
case FMOD_ERR_NEEDSHARDWARE:
|
||||
return "Tried to use a feature that requires hardware support. (ie "
|
||||
"trying to play a GCADPCM compressed sound in software on Wii). ";
|
||||
case FMOD_ERR_NEEDSSOFTWARE:
|
||||
return "Tried to use a feature that requires the software engine. "
|
||||
"Software engine has either been turned off, or command was "
|
||||
"executed on a hardware channel which does not support this "
|
||||
"feature. ";
|
||||
case FMOD_ERR_NET_CONNECT:
|
||||
return "Couldn't connect to the specified host. ";
|
||||
case FMOD_ERR_NET_SOCKET_ERROR:
|
||||
return "A socket error occurred. This is a catch-all for socket-related "
|
||||
"errors not listed elsewhere. ";
|
||||
case FMOD_ERR_NET_URL:
|
||||
return "The specified URL couldn't be resolved. ";
|
||||
case FMOD_ERR_NET_WOULD_BLOCK:
|
||||
return "Operation on a non-blocking socket could not complete "
|
||||
"immediately. ";
|
||||
case FMOD_ERR_NOTREADY:
|
||||
return "Operation could not be performed because specified sound/DSP "
|
||||
"connection is not ready. ";
|
||||
case FMOD_ERR_OUTPUT_ALLOCATED:
|
||||
return "Error initializing output device, but more specifically, the "
|
||||
"output device is already in use and cannot be reused. ";
|
||||
case FMOD_ERR_OUTPUT_CREATEBUFFER:
|
||||
return "Error creating hardware sound buffer. ";
|
||||
case FMOD_ERR_OUTPUT_DRIVERCALL:
|
||||
return "A call to a standard soundcard driver failed, which could "
|
||||
"possibly mean a bug in the driver or resources were missing or "
|
||||
"exhausted. ";
|
||||
case FMOD_ERR_OUTPUT_ENUMERATION:
|
||||
return "Error enumerating the available driver list. List may be "
|
||||
"inconsistent due to a recent device addition or removal. ";
|
||||
case FMOD_ERR_OUTPUT_FORMAT:
|
||||
return "Soundcard does not support the minimum features needed for this "
|
||||
"soundsystem (16bit stereo output). ";
|
||||
case FMOD_ERR_OUTPUT_INIT:
|
||||
return "Error initializing output device. ";
|
||||
case FMOD_ERR_OUTPUT_NOHARDWARE:
|
||||
return "FMOD_HARDWARE was specified but the sound card does not have the "
|
||||
"resources necessary to play it. ";
|
||||
case FMOD_ERR_OUTPUT_NOSOFTWARE:
|
||||
return "Attempted to create a software sound but no software channels "
|
||||
"were specified in System::init. ";
|
||||
case FMOD_ERR_PAN:
|
||||
return "Panning only works with mono or stereo sound sources. ";
|
||||
case FMOD_ERR_PLUGIN:
|
||||
return "An unspecified error has been returned from a 3rd party plugin. ";
|
||||
case FMOD_ERR_PLUGIN_INSTANCES:
|
||||
return "The number of allowed instances of a plugin has been exceeded. ";
|
||||
case FMOD_ERR_PLUGIN_MISSING:
|
||||
return "A requested output, dsp unit type or codec was not available. ";
|
||||
case FMOD_ERR_PLUGIN_RESOURCE:
|
||||
return "A resource that the plugin requires cannot be found. (ie the DLS "
|
||||
"file for MIDI playback or other DLLs that it needs to load) ";
|
||||
case FMOD_ERR_PRELOADED:
|
||||
return "The specified sound is still in use by the event system, call "
|
||||
"EventSystem::unloadFSB before trying to release it. ";
|
||||
case FMOD_ERR_PROGRAMMERSOUND:
|
||||
return "The specified sound is still in use by the event system, wait "
|
||||
"for the event which is using it finish with it. ";
|
||||
case FMOD_ERR_RECORD:
|
||||
return "An error occured trying to initialize the recording device. ";
|
||||
case FMOD_ERR_REVERB_INSTANCE:
|
||||
return "Specified instance in FMOD_REVERB_PROPERTIES couldn't be set. "
|
||||
"Most likely because it is an invalid instance number or the "
|
||||
"reverb doesnt exist. ";
|
||||
case FMOD_ERR_SUBSOUNDS:
|
||||
return "The error occured because the sound referenced contains "
|
||||
"subsounds when it shouldn't have, or it doesn't contain "
|
||||
"subsounds when it should have. The operation may also not be "
|
||||
"able to be performed on a parent sound, or a parent sound was "
|
||||
"played without setting up a sentence first. ";
|
||||
case FMOD_ERR_SUBSOUND_ALLOCATED:
|
||||
return "This subsound is already being used by another sound, you cannot "
|
||||
"have more than one parent to a sound. Null out the other "
|
||||
"parent's entry first. ";
|
||||
case FMOD_ERR_SUBSOUND_CANTMOVE:
|
||||
return "Shared subsounds cannot be replaced or moved from their parent "
|
||||
"stream, such as when the parent stream is an FSB file. ";
|
||||
case FMOD_ERR_SUBSOUND_MODE:
|
||||
return "The subsound's mode bits do not match with the parent sound's "
|
||||
"mode bits. See documentation for function that it was called "
|
||||
"with. ";
|
||||
case FMOD_ERR_TAGNOTFOUND:
|
||||
return "The specified tag could not be found or there are no tags. ";
|
||||
case FMOD_ERR_TOOMANYCHANNELS:
|
||||
return "The sound created exceeds the allowable input channel count. "
|
||||
"This can be increased using the maxinputchannels parameter in "
|
||||
"System::setSoftwareFormat. ";
|
||||
case FMOD_ERR_UNIMPLEMENTED:
|
||||
return "Something in FMOD hasn't been implemented when it should be! "
|
||||
"contact support! ";
|
||||
case FMOD_ERR_UNINITIALIZED:
|
||||
return "This command failed because System::init or System::setDriver "
|
||||
"was not called. ";
|
||||
case FMOD_ERR_UNSUPPORTED:
|
||||
return "A command issued was not supported by this object. Possibly a "
|
||||
"plugin without certain callbacks specified. ";
|
||||
case FMOD_ERR_UPDATE:
|
||||
return "An error caused by System::update occured. ";
|
||||
case FMOD_ERR_VERSION:
|
||||
return "The version number of this file format is not supported. ";
|
||||
case FMOD_OK:
|
||||
return "No errors.";
|
||||
default:
|
||||
return "Unknown error.";
|
||||
/*$ preserve start $*/
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
/* ============================================================================================= */
|
||||
/* FMOD Ex - Memory info header file. Copyright (c), Firelight Technologies Pty, Ltd. 2008-2016. */
|
||||
/* =============================================================================================
|
||||
*/
|
||||
/* FMOD Ex - Memory info header file. Copyright (c), Firelight Technologies Pty,
|
||||
* Ltd. 2008-2016. */
|
||||
/* */
|
||||
/* Use this header if you are interested in getting detailed information on FMOD's memory */
|
||||
/* usage. See the documentation for more details. */
|
||||
/* Use this header if you are interested in getting detailed information on
|
||||
* FMOD's memory */
|
||||
/* usage. See the documentation for more details. */
|
||||
/* */
|
||||
/* ============================================================================================= */
|
||||
/* =============================================================================================
|
||||
*/
|
||||
|
||||
#ifndef _FMOD_MEMORYINFO_H
|
||||
#define _FMOD_MEMORYINFO_H
|
||||
@@ -13,79 +17,85 @@
|
||||
[STRUCTURE]
|
||||
[
|
||||
[DESCRIPTION]
|
||||
Structure to be filled with detailed memory usage information of an FMOD object
|
||||
Structure to be filled with detailed memory usage information of an FMOD
|
||||
object
|
||||
|
||||
[REMARKS]
|
||||
Every public FMOD class has a getMemoryInfo function which can be used to get detailed information on what memory resources are associated with the object in question.
|
||||
On return from getMemoryInfo, each member of this structure will hold the amount of memory used for its type in bytes.<br>
|
||||
<br>
|
||||
Members marked with [in] mean the user sets the value before passing it to the function.<br>
|
||||
Members marked with [out] mean FMOD sets the value to be used after the function exits.<br>
|
||||
Every public FMOD class has a getMemoryInfo function which can be used to
|
||||
get detailed information on what memory resources are associated with the object
|
||||
in question. On return from getMemoryInfo, each member of this structure will
|
||||
hold the amount of memory used for its type in bytes.<br> <br> Members marked
|
||||
with [in] mean the user sets the value before passing it to the function.<br>
|
||||
Members marked with [out] mean FMOD sets the value to be used after the
|
||||
function exits.<br>
|
||||
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable,
|
||||
PlayStation 3, Wii, iPhone, 3GS, NGP, Android
|
||||
|
||||
[SEE_ALSO]
|
||||
System::getMemoryInfo
|
||||
EventSystem::getMemoryInfo
|
||||
FMOD_MEMBITS
|
||||
FMOD_MEMBITS
|
||||
FMOD_EVENT_MEMBITS
|
||||
]
|
||||
*/
|
||||
typedef struct FMOD_MEMORY_USAGE_DETAILS
|
||||
{
|
||||
unsigned int other; /* [out] Memory not accounted for by other types */
|
||||
unsigned int string; /* [out] String data */
|
||||
unsigned int system; /* [out] System object and various internals */
|
||||
unsigned int plugins; /* [out] Plugin objects and internals */
|
||||
unsigned int output; /* [out] Output module object and internals */
|
||||
unsigned int channel; /* [out] Channel related memory */
|
||||
unsigned int channelgroup; /* [out] ChannelGroup objects and internals */
|
||||
unsigned int codec; /* [out] Codecs allocated for streaming */
|
||||
unsigned int file; /* [out] File buffers and structures */
|
||||
unsigned int sound; /* [out] Sound objects and internals */
|
||||
unsigned int secondaryram; /* [out] Sound data stored in secondary RAM */
|
||||
unsigned int soundgroup; /* [out] SoundGroup objects and internals */
|
||||
unsigned int streambuffer; /* [out] Stream buffer memory */
|
||||
unsigned int dspconnection; /* [out] DSPConnection objects and internals */
|
||||
unsigned int dsp; /* [out] DSP implementation objects */
|
||||
unsigned int dspcodec; /* [out] Realtime file format decoding DSP objects */
|
||||
unsigned int profile; /* [out] Profiler memory footprint. */
|
||||
unsigned int recordbuffer; /* [out] Buffer used to store recorded data from microphone */
|
||||
unsigned int reverb; /* [out] Reverb implementation objects */
|
||||
unsigned int reverbchannelprops; /* [out] Reverb channel properties structs */
|
||||
unsigned int geometry; /* [out] Geometry objects and internals */
|
||||
unsigned int syncpoint; /* [out] Sync point memory. */
|
||||
unsigned int eventsystem; /* [out] EventSystem and various internals */
|
||||
unsigned int musicsystem; /* [out] MusicSystem and various internals */
|
||||
unsigned int fev; /* [out] Definition of objects contained in all loaded projects e.g. events, groups, categories */
|
||||
unsigned int memoryfsb; /* [out] Data loaded with preloadFSB */
|
||||
unsigned int eventproject; /* [out] EventProject objects and internals */
|
||||
unsigned int eventgroupi; /* [out] EventGroup objects and internals */
|
||||
unsigned int soundbankclass; /* [out] Objects used to manage wave banks */
|
||||
unsigned int soundbanklist; /* [out] Data used to manage lists of wave bank usage */
|
||||
unsigned int streaminstance; /* [out] Stream objects and internals */
|
||||
unsigned int sounddefclass; /* [out] Sound definition objects */
|
||||
unsigned int sounddefdefclass; /* [out] Sound definition static data objects */
|
||||
unsigned int sounddefpool; /* [out] Sound definition pool data */
|
||||
unsigned int reverbdef; /* [out] Reverb definition objects */
|
||||
unsigned int eventreverb; /* [out] Reverb objects */
|
||||
unsigned int userproperty; /* [out] User property objects */
|
||||
unsigned int eventinstance; /* [out] Event instance base objects */
|
||||
unsigned int eventinstance_complex; /* [out] Complex event instance objects */
|
||||
unsigned int eventinstance_simple; /* [out] Simple event instance objects */
|
||||
unsigned int eventinstance_layer; /* [out] Event layer instance objects */
|
||||
unsigned int eventinstance_sound; /* [out] Event sound instance objects */
|
||||
unsigned int eventenvelope; /* [out] Event envelope objects */
|
||||
unsigned int eventenvelopedef; /* [out] Event envelope definition objects */
|
||||
unsigned int eventparameter; /* [out] Event parameter objects */
|
||||
unsigned int eventcategory; /* [out] Event category objects */
|
||||
unsigned int eventenvelopepoint; /* [out] Event envelope point objects */
|
||||
unsigned int eventinstancepool; /* [out] Event instance pool memory */
|
||||
typedef struct FMOD_MEMORY_USAGE_DETAILS {
|
||||
unsigned int other; /* [out] Memory not accounted for by other types */
|
||||
unsigned int string; /* [out] String data */
|
||||
unsigned int system; /* [out] System object and various internals */
|
||||
unsigned int plugins; /* [out] Plugin objects and internals */
|
||||
unsigned int output; /* [out] Output module object and internals */
|
||||
unsigned int channel; /* [out] Channel related memory */
|
||||
unsigned int channelgroup; /* [out] ChannelGroup objects and internals */
|
||||
unsigned int codec; /* [out] Codecs allocated for streaming */
|
||||
unsigned int file; /* [out] File buffers and structures */
|
||||
unsigned int sound; /* [out] Sound objects and internals */
|
||||
unsigned int secondaryram; /* [out] Sound data stored in secondary RAM */
|
||||
unsigned int soundgroup; /* [out] SoundGroup objects and internals */
|
||||
unsigned int streambuffer; /* [out] Stream buffer memory */
|
||||
unsigned int dspconnection; /* [out] DSPConnection objects and internals */
|
||||
unsigned int dsp; /* [out] DSP implementation objects */
|
||||
unsigned int dspcodec; /* [out] Realtime file format decoding DSP objects */
|
||||
unsigned int profile; /* [out] Profiler memory footprint. */
|
||||
unsigned int recordbuffer; /* [out] Buffer used to store recorded data from
|
||||
microphone */
|
||||
unsigned int reverb; /* [out] Reverb implementation objects */
|
||||
unsigned int reverbchannelprops; /* [out] Reverb channel properties structs */
|
||||
unsigned int geometry; /* [out] Geometry objects and internals */
|
||||
unsigned int syncpoint; /* [out] Sync point memory. */
|
||||
unsigned int eventsystem; /* [out] EventSystem and various internals */
|
||||
unsigned int musicsystem; /* [out] MusicSystem and various internals */
|
||||
unsigned int fev; /* [out] Definition of objects contained in all loaded
|
||||
projects e.g. events, groups, categories */
|
||||
unsigned int memoryfsb; /* [out] Data loaded with preloadFSB */
|
||||
unsigned int eventproject; /* [out] EventProject objects and internals */
|
||||
unsigned int eventgroupi; /* [out] EventGroup objects and internals */
|
||||
unsigned int soundbankclass; /* [out] Objects used to manage wave banks */
|
||||
unsigned int
|
||||
soundbanklist; /* [out] Data used to manage lists of wave bank usage */
|
||||
unsigned int streaminstance; /* [out] Stream objects and internals */
|
||||
unsigned int sounddefclass; /* [out] Sound definition objects */
|
||||
unsigned int
|
||||
sounddefdefclass; /* [out] Sound definition static data objects */
|
||||
unsigned int sounddefpool; /* [out] Sound definition pool data */
|
||||
unsigned int reverbdef; /* [out] Reverb definition objects */
|
||||
unsigned int eventreverb; /* [out] Reverb objects */
|
||||
unsigned int userproperty; /* [out] User property objects */
|
||||
unsigned int eventinstance; /* [out] Event instance base objects */
|
||||
unsigned int eventinstance_complex; /* [out] Complex event instance objects */
|
||||
unsigned int eventinstance_simple; /* [out] Simple event instance objects */
|
||||
unsigned int eventinstance_layer; /* [out] Event layer instance objects */
|
||||
unsigned int eventinstance_sound; /* [out] Event sound instance objects */
|
||||
unsigned int eventenvelope; /* [out] Event envelope objects */
|
||||
unsigned int eventenvelopedef; /* [out] Event envelope definition objects */
|
||||
unsigned int eventparameter; /* [out] Event parameter objects */
|
||||
unsigned int eventcategory; /* [out] Event category objects */
|
||||
unsigned int eventenvelopepoint; /* [out] Event envelope point objects */
|
||||
unsigned int eventinstancepool; /* [out] Event instance pool memory */
|
||||
} FMOD_MEMORY_USAGE_DETAILS;
|
||||
|
||||
|
||||
/*
|
||||
[DEFINE]
|
||||
[
|
||||
@@ -93,48 +103,62 @@ typedef struct FMOD_MEMORY_USAGE_DETAILS
|
||||
FMOD_MEMBITS
|
||||
|
||||
[DESCRIPTION]
|
||||
Bitfield used to request specific memory usage information from the getMemoryInfo function of every public FMOD Ex class.
|
||||
Use with the "memorybits" parameter of getMemoryInfo to get information on FMOD Ex memory usage.
|
||||
Bitfield used to request specific memory usage information from the
|
||||
getMemoryInfo function of every public FMOD Ex class. Use with the "memorybits"
|
||||
parameter of getMemoryInfo to get information on FMOD Ex memory usage.
|
||||
|
||||
[REMARKS]
|
||||
Every public FMOD class has a getMemoryInfo function which can be used to get detailed information on what memory resources are associated with the object in question.
|
||||
The FMOD_MEMBITS defines can be OR'd together to specify precisely what memory usage you'd like to get information on. See System::getMemoryInfo for an example.
|
||||
Every public FMOD class has a getMemoryInfo function which can be used to
|
||||
get detailed information on what memory resources are associated with the object
|
||||
in question. The FMOD_MEMBITS defines can be OR'd together to specify precisely
|
||||
what memory usage you'd like to get information on. See System::getMemoryInfo
|
||||
for an example.
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable,
|
||||
PlayStation 3, Wii, iPhone, 3GS, NGP, Android
|
||||
|
||||
[SEE_ALSO]
|
||||
FMOD_EVENT_MEMBITS
|
||||
System::getMemoryInfo
|
||||
]
|
||||
*/
|
||||
#define FMOD_MEMBITS_OTHER 0x00000001 /* Memory not accounted for by other types */
|
||||
#define FMOD_MEMBITS_STRING 0x00000002 /* String data */
|
||||
#define FMOD_MEMBITS_OTHER \
|
||||
0x00000001 /* Memory not accounted for by other types */
|
||||
#define FMOD_MEMBITS_STRING 0x00000002 /* String data */
|
||||
|
||||
#define FMOD_MEMBITS_SYSTEM 0x00000004 /* System object and various internals */
|
||||
#define FMOD_MEMBITS_PLUGINS 0x00000008 /* Plugin objects and internals */
|
||||
#define FMOD_MEMBITS_OUTPUT 0x00000010 /* Output module object and internals */
|
||||
#define FMOD_MEMBITS_CHANNEL 0x00000020 /* Channel related memory */
|
||||
#define FMOD_MEMBITS_CHANNELGROUP 0x00000040 /* ChannelGroup objects and internals */
|
||||
#define FMOD_MEMBITS_CODEC 0x00000080 /* Codecs allocated for streaming */
|
||||
#define FMOD_MEMBITS_FILE 0x00000100 /* Codecs allocated for streaming */
|
||||
#define FMOD_MEMBITS_SOUND 0x00000200 /* Sound objects and internals */
|
||||
#define FMOD_MEMBITS_SOUND_SECONDARYRAM 0x00000400 /* Sound data stored in secondary RAM */
|
||||
#define FMOD_MEMBITS_SOUNDGROUP 0x00000800 /* SoundGroup objects and internals */
|
||||
#define FMOD_MEMBITS_STREAMBUFFER 0x00001000 /* Stream buffer memory */
|
||||
#define FMOD_MEMBITS_DSPCONNECTION 0x00002000 /* DSPConnection objects and internals */
|
||||
#define FMOD_MEMBITS_DSP 0x00004000 /* DSP implementation objects */
|
||||
#define FMOD_MEMBITS_DSPCODEC 0x00008000 /* Realtime file format decoding DSP objects */
|
||||
#define FMOD_MEMBITS_PROFILE 0x00010000 /* Profiler memory footprint. */
|
||||
#define FMOD_MEMBITS_RECORDBUFFER 0x00020000 /* Buffer used to store recorded data from microphone */
|
||||
#define FMOD_MEMBITS_REVERB 0x00040000 /* Reverb implementation objects */
|
||||
#define FMOD_MEMBITS_REVERBCHANNELPROPS 0x00080000 /* Reverb channel properties structs */
|
||||
#define FMOD_MEMBITS_GEOMETRY 0x00100000 /* Geometry objects and internals */
|
||||
#define FMOD_MEMBITS_SYNCPOINT 0x00200000 /* Sync point memory. */
|
||||
#define FMOD_MEMBITS_ALL 0xffffffff /* All memory used by FMOD Ex */
|
||||
#define FMOD_MEMBITS_SYSTEM 0x00000004 /* System object and various internals \
|
||||
*/
|
||||
#define FMOD_MEMBITS_PLUGINS 0x00000008 /* Plugin objects and internals */
|
||||
#define FMOD_MEMBITS_OUTPUT 0x00000010 /* Output module object and internals \
|
||||
*/
|
||||
#define FMOD_MEMBITS_CHANNEL 0x00000020 /* Channel related memory */
|
||||
#define FMOD_MEMBITS_CHANNELGROUP \
|
||||
0x00000040 /* ChannelGroup objects and internals */
|
||||
#define FMOD_MEMBITS_CODEC 0x00000080 /* Codecs allocated for streaming */
|
||||
#define FMOD_MEMBITS_FILE 0x00000100 /* Codecs allocated for streaming */
|
||||
#define FMOD_MEMBITS_SOUND 0x00000200 /* Sound objects and internals */
|
||||
#define FMOD_MEMBITS_SOUND_SECONDARYRAM \
|
||||
0x00000400 /* Sound data stored in secondary RAM */
|
||||
#define FMOD_MEMBITS_SOUNDGROUP \
|
||||
0x00000800 /* SoundGroup objects and internals */
|
||||
#define FMOD_MEMBITS_STREAMBUFFER 0x00001000 /* Stream buffer memory */
|
||||
#define FMOD_MEMBITS_DSPCONNECTION \
|
||||
0x00002000 /* DSPConnection objects and internals */
|
||||
#define FMOD_MEMBITS_DSP 0x00004000 /* DSP implementation objects */
|
||||
#define FMOD_MEMBITS_DSPCODEC \
|
||||
0x00008000 /* Realtime file format decoding DSP objects */
|
||||
#define FMOD_MEMBITS_PROFILE 0x00010000 /* Profiler memory footprint. */
|
||||
#define FMOD_MEMBITS_RECORDBUFFER \
|
||||
0x00020000 /* Buffer used to store recorded data from microphone */
|
||||
#define FMOD_MEMBITS_REVERB 0x00040000 /* Reverb implementation objects */
|
||||
#define FMOD_MEMBITS_REVERBCHANNELPROPS \
|
||||
0x00080000 /* Reverb channel properties structs */
|
||||
#define FMOD_MEMBITS_GEOMETRY 0x00100000 /* Geometry objects and internals */
|
||||
#define FMOD_MEMBITS_SYNCPOINT 0x00200000 /* Sync point memory. */
|
||||
#define FMOD_MEMBITS_ALL 0xffffffff /* All memory used by FMOD Ex */
|
||||
/* [DEFINE_END] */
|
||||
|
||||
|
||||
/*
|
||||
[DEFINE]
|
||||
[
|
||||
@@ -142,60 +166,93 @@ typedef struct FMOD_MEMORY_USAGE_DETAILS
|
||||
FMOD_EVENT_MEMBITS
|
||||
|
||||
[DESCRIPTION]
|
||||
Bitfield used to request specific memory usage information from the getMemoryInfo function of every public FMOD Event System class.
|
||||
Use with the "event_memorybits" parameter of getMemoryInfo to get information on FMOD Event System memory usage.
|
||||
Bitfield used to request specific memory usage information from the
|
||||
getMemoryInfo function of every public FMOD Event System class. Use with the
|
||||
"event_memorybits" parameter of getMemoryInfo to get information on FMOD Event
|
||||
System memory usage.
|
||||
|
||||
[REMARKS]
|
||||
Every public FMOD Event System class has a getMemoryInfo function which can be used to get detailed information on what memory resources are associated with the object in question.
|
||||
The FMOD_EVENT_MEMBITS defines can be OR'd together to specify precisely what memory usage you'd like to get information on. See EventSystem::getMemoryInfo for an example.
|
||||
Every public FMOD Event System class has a getMemoryInfo function which can
|
||||
be used to get detailed information on what memory resources are associated with
|
||||
the object in question. The FMOD_EVENT_MEMBITS defines can be OR'd together to
|
||||
specify precisely what memory usage you'd like to get information on. See
|
||||
EventSystem::getMemoryInfo for an example.
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable,
|
||||
PlayStation 3, Wii, iPhone, 3GS, NGP, Android
|
||||
|
||||
[SEE_ALSO]
|
||||
FMOD_MEMBITS
|
||||
System::getMemoryInfo
|
||||
]
|
||||
*/
|
||||
#define FMOD_EVENT_MEMBITS_EVENTSYSTEM 0x00000001 /* EventSystem and various internals */
|
||||
#define FMOD_EVENT_MEMBITS_MUSICSYSTEM 0x00000002 /* MusicSystem and various internals */
|
||||
#define FMOD_EVENT_MEMBITS_FEV 0x00000004 /* Definition of objects contained in all loaded projects e.g. events, groups, categories */
|
||||
#define FMOD_EVENT_MEMBITS_MEMORYFSB 0x00000008 /* Data loaded with preloadFSB */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTPROJECT 0x00000010 /* EventProject objects and internals */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTGROUPI 0x00000020 /* EventGroup objects and internals */
|
||||
#define FMOD_EVENT_MEMBITS_SOUNDBANKCLASS 0x00000040 /* Objects used to manage wave banks */
|
||||
#define FMOD_EVENT_MEMBITS_SOUNDBANKLIST 0x00000080 /* Data used to manage lists of wave bank usage */
|
||||
#define FMOD_EVENT_MEMBITS_STREAMINSTANCE 0x00000100 /* Stream objects and internals */
|
||||
#define FMOD_EVENT_MEMBITS_SOUNDDEFCLASS 0x00000200 /* Sound definition objects */
|
||||
#define FMOD_EVENT_MEMBITS_SOUNDDEFDEFCLASS 0x00000400 /* Sound definition static data objects */
|
||||
#define FMOD_EVENT_MEMBITS_SOUNDDEFPOOL 0x00000800 /* Sound definition pool data */
|
||||
#define FMOD_EVENT_MEMBITS_REVERBDEF 0x00001000 /* Reverb definition objects */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTREVERB 0x00002000 /* Reverb objects */
|
||||
#define FMOD_EVENT_MEMBITS_USERPROPERTY 0x00004000 /* User property objects */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTINSTANCE 0x00008000 /* Event instance base objects */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_COMPLEX 0x00010000 /* Complex event instance objects */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_SIMPLE 0x00020000 /* Simple event instance objects */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_LAYER 0x00040000 /* Event layer instance objects */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_SOUND 0x00080000 /* Event sound instance objects */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTENVELOPE 0x00100000 /* Event envelope objects */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTENVELOPEDEF 0x00200000 /* Event envelope definition objects */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTPARAMETER 0x00400000 /* Event parameter objects */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTCATEGORY 0x00800000 /* Event category objects */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTENVELOPEPOINT 0x01000000 /* Event envelope point object+s */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTINSTANCEPOOL 0x02000000 /* Event instance pool data */
|
||||
#define FMOD_EVENT_MEMBITS_ALL 0xffffffff /* All memory used by FMOD Event System */
|
||||
*/
|
||||
#define FMOD_EVENT_MEMBITS_EVENTSYSTEM \
|
||||
0x00000001 /* EventSystem and various internals */
|
||||
#define FMOD_EVENT_MEMBITS_MUSICSYSTEM \
|
||||
0x00000002 /* MusicSystem and various internals */
|
||||
#define FMOD_EVENT_MEMBITS_FEV \
|
||||
0x00000004 /* Definition of objects contained in all loaded projects e.g. \
|
||||
events, groups, categories */
|
||||
#define FMOD_EVENT_MEMBITS_MEMORYFSB \
|
||||
0x00000008 /* Data loaded with preloadFSB */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTPROJECT \
|
||||
0x00000010 /* EventProject objects and internals */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTGROUPI \
|
||||
0x00000020 /* EventGroup objects and internals */
|
||||
#define FMOD_EVENT_MEMBITS_SOUNDBANKCLASS \
|
||||
0x00000040 /* Objects used to manage wave banks */
|
||||
#define FMOD_EVENT_MEMBITS_SOUNDBANKLIST \
|
||||
0x00000080 /* Data used to manage lists of wave bank usage */
|
||||
#define FMOD_EVENT_MEMBITS_STREAMINSTANCE \
|
||||
0x00000100 /* Stream objects and internals */
|
||||
#define FMOD_EVENT_MEMBITS_SOUNDDEFCLASS \
|
||||
0x00000200 /* Sound definition objects */
|
||||
#define FMOD_EVENT_MEMBITS_SOUNDDEFDEFCLASS \
|
||||
0x00000400 /* Sound definition static data objects */
|
||||
#define FMOD_EVENT_MEMBITS_SOUNDDEFPOOL \
|
||||
0x00000800 /* Sound definition pool data */
|
||||
#define FMOD_EVENT_MEMBITS_REVERBDEF 0x00001000 /* Reverb definition objects \
|
||||
*/
|
||||
#define FMOD_EVENT_MEMBITS_EVENTREVERB 0x00002000 /* Reverb objects */
|
||||
#define FMOD_EVENT_MEMBITS_USERPROPERTY 0x00004000 /* User property objects */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTINSTANCE \
|
||||
0x00008000 /* Event instance base objects */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_COMPLEX \
|
||||
0x00010000 /* Complex event instance objects */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_SIMPLE \
|
||||
0x00020000 /* Simple event instance objects */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_LAYER \
|
||||
0x00040000 /* Event layer instance objects */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_SOUND \
|
||||
0x00080000 /* Event sound instance objects */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTENVELOPE 0x00100000 /* Event envelope objects \
|
||||
*/
|
||||
#define FMOD_EVENT_MEMBITS_EVENTENVELOPEDEF \
|
||||
0x00200000 /* Event envelope definition objects */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTPARAMETER \
|
||||
0x00400000 /* Event parameter objects */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTCATEGORY 0x00800000 /* Event category objects \
|
||||
*/
|
||||
#define FMOD_EVENT_MEMBITS_EVENTENVELOPEPOINT \
|
||||
0x01000000 /* Event envelope point object+s */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTINSTANCEPOOL \
|
||||
0x02000000 /* Event instance pool data */
|
||||
#define FMOD_EVENT_MEMBITS_ALL \
|
||||
0xffffffff /* All memory used by FMOD Event System */
|
||||
|
||||
/* All event instance memory */
|
||||
#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_GROUP (FMOD_EVENT_MEMBITS_EVENTINSTANCE | \
|
||||
FMOD_EVENT_MEMBITS_EVENTINSTANCE_COMPLEX | \
|
||||
FMOD_EVENT_MEMBITS_EVENTINSTANCE_SIMPLE | \
|
||||
FMOD_EVENT_MEMBITS_EVENTINSTANCE_LAYER | \
|
||||
FMOD_EVENT_MEMBITS_EVENTINSTANCE_SOUND)
|
||||
#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_GROUP \
|
||||
(FMOD_EVENT_MEMBITS_EVENTINSTANCE | \
|
||||
FMOD_EVENT_MEMBITS_EVENTINSTANCE_COMPLEX | \
|
||||
FMOD_EVENT_MEMBITS_EVENTINSTANCE_SIMPLE | \
|
||||
FMOD_EVENT_MEMBITS_EVENTINSTANCE_LAYER | \
|
||||
FMOD_EVENT_MEMBITS_EVENTINSTANCE_SOUND)
|
||||
|
||||
/* All sound definition memory */
|
||||
#define FMOD_EVENT_MEMBITS_SOUNDDEF_GROUP (FMOD_EVENT_MEMBITS_SOUNDDEFCLASS | \
|
||||
FMOD_EVENT_MEMBITS_SOUNDDEFDEFCLASS | \
|
||||
FMOD_EVENT_MEMBITS_SOUNDDEFPOOL)
|
||||
#define FMOD_EVENT_MEMBITS_SOUNDDEF_GROUP \
|
||||
(FMOD_EVENT_MEMBITS_SOUNDDEFCLASS | FMOD_EVENT_MEMBITS_SOUNDDEFDEFCLASS | \
|
||||
FMOD_EVENT_MEMBITS_SOUNDDEFPOOL)
|
||||
/* [DEFINE_END] */
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
/* ==================================================================================================== */
|
||||
/* FMOD Ex - output development header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2016. */
|
||||
/* ====================================================================================================
|
||||
*/
|
||||
/* FMOD Ex - output development header file. Copyright (c), Firelight
|
||||
* Technologies Pty, Ltd. 2004-2016. */
|
||||
/* */
|
||||
/* Use this header if you are wanting to develop your own output plugin to use with */
|
||||
/* FMOD's output system. With this header you can make your own output plugin that FMOD */
|
||||
/* can register and use. See the documentation and examples on how to make a working plugin. */
|
||||
/* Use this header if you are wanting to develop your own output plugin to use
|
||||
* with */
|
||||
/* FMOD's output system. With this header you can make your own output plugin
|
||||
* that FMOD */
|
||||
/* can register and use. See the documentation and examples on how to make a
|
||||
* working plugin. */
|
||||
/* */
|
||||
/* ==================================================================================================== */
|
||||
/* ====================================================================================================
|
||||
*/
|
||||
|
||||
#ifndef _FMOD_OUTPUT_H
|
||||
#define _FMOD_OUTPUT_H
|
||||
@@ -16,78 +22,140 @@ typedef struct FMOD_OUTPUT_STATE FMOD_OUTPUT_STATE;
|
||||
|
||||
/*
|
||||
Output callbacks
|
||||
*/
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETNUMDRIVERSCALLBACK)(FMOD_OUTPUT_STATE *output_state, int *numdrivers);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETDRIVERNAMECALLBACK)(FMOD_OUTPUT_STATE *output_state, int id, char *name, int namelen);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETDRIVERCAPSCALLBACK)(FMOD_OUTPUT_STATE *output_state, int id, FMOD_CAPS *caps);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_INITCALLBACK) (FMOD_OUTPUT_STATE *output_state, int selecteddriver, FMOD_INITFLAGS flags, int *outputrate, int outputchannels, FMOD_SOUND_FORMAT *outputformat, int dspbufferlength, int dspnumbuffers, void *extradriverdata);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_CLOSECALLBACK) (FMOD_OUTPUT_STATE *output_state);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_UPDATECALLBACK) (FMOD_OUTPUT_STATE *output_state);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETHANDLECALLBACK) (FMOD_OUTPUT_STATE *output_state, void **handle);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETPOSITIONCALLBACK) (FMOD_OUTPUT_STATE *output_state, unsigned int *pcm);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_LOCKCALLBACK) (FMOD_OUTPUT_STATE *output_state, unsigned int offset, unsigned int length, void **ptr1, void **ptr2, unsigned int *len1, unsigned int *len2);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_UNLOCKCALLBACK) (FMOD_OUTPUT_STATE *output_state, void *ptr1, void *ptr2, unsigned int len1, unsigned int len2);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_READFROMMIXER) (FMOD_OUTPUT_STATE *output_state, void *buffer, unsigned int length);
|
||||
|
||||
*/
|
||||
typedef FMOD_RESULT(F_CALLBACK *FMOD_OUTPUT_GETNUMDRIVERSCALLBACK)(
|
||||
FMOD_OUTPUT_STATE *output_state, int *numdrivers);
|
||||
typedef FMOD_RESULT(F_CALLBACK *FMOD_OUTPUT_GETDRIVERNAMECALLBACK)(
|
||||
FMOD_OUTPUT_STATE *output_state, int id, char *name, int namelen);
|
||||
typedef FMOD_RESULT(F_CALLBACK *FMOD_OUTPUT_GETDRIVERCAPSCALLBACK)(
|
||||
FMOD_OUTPUT_STATE *output_state, int id, FMOD_CAPS *caps);
|
||||
typedef FMOD_RESULT(F_CALLBACK *FMOD_OUTPUT_INITCALLBACK)(
|
||||
FMOD_OUTPUT_STATE *output_state,
|
||||
int selecteddriver,
|
||||
FMOD_INITFLAGS flags,
|
||||
int *outputrate,
|
||||
int outputchannels,
|
||||
FMOD_SOUND_FORMAT *outputformat,
|
||||
int dspbufferlength,
|
||||
int dspnumbuffers,
|
||||
void *extradriverdata);
|
||||
typedef FMOD_RESULT(F_CALLBACK *FMOD_OUTPUT_CLOSECALLBACK)(
|
||||
FMOD_OUTPUT_STATE *output_state);
|
||||
typedef FMOD_RESULT(F_CALLBACK *FMOD_OUTPUT_UPDATECALLBACK)(
|
||||
FMOD_OUTPUT_STATE *output_state);
|
||||
typedef FMOD_RESULT(F_CALLBACK *FMOD_OUTPUT_GETHANDLECALLBACK)(
|
||||
FMOD_OUTPUT_STATE *output_state, void **handle);
|
||||
typedef FMOD_RESULT(F_CALLBACK *FMOD_OUTPUT_GETPOSITIONCALLBACK)(
|
||||
FMOD_OUTPUT_STATE *output_state, unsigned int *pcm);
|
||||
typedef FMOD_RESULT(F_CALLBACK *FMOD_OUTPUT_LOCKCALLBACK)(
|
||||
FMOD_OUTPUT_STATE *output_state,
|
||||
unsigned int offset,
|
||||
unsigned int length,
|
||||
void **ptr1,
|
||||
void **ptr2,
|
||||
unsigned int *len1,
|
||||
unsigned int *len2);
|
||||
typedef FMOD_RESULT(F_CALLBACK *FMOD_OUTPUT_UNLOCKCALLBACK)(
|
||||
FMOD_OUTPUT_STATE *output_state,
|
||||
void *ptr1,
|
||||
void *ptr2,
|
||||
unsigned int len1,
|
||||
unsigned int len2);
|
||||
typedef FMOD_RESULT(F_CALLBACK *FMOD_OUTPUT_READFROMMIXER)(
|
||||
FMOD_OUTPUT_STATE *output_state, void *buffer, unsigned int length);
|
||||
|
||||
/*
|
||||
[STRUCTURE]
|
||||
[STRUCTURE]
|
||||
[
|
||||
[DESCRIPTION]
|
||||
When creating an output, declare one of these and provide the relevant callbacks and name for FMOD to use when it opens and reads a file of this type.
|
||||
When creating an output, declare one of these and provide the relevant
|
||||
callbacks and name for FMOD to use when it opens and reads a file of this type.
|
||||
|
||||
[REMARKS]
|
||||
Members marked with [in] mean the variable can be written to. The user can set the value.<br>
|
||||
Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.<br>
|
||||
Members marked with [in] mean the variable can be written to. The user can
|
||||
set the value.<br> Members marked with [out] mean the variable is modified by
|
||||
FMOD and is for reading purposes only. Do not change this value.<br>
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable,
|
||||
PlayStation 3, Wii, iPhone, 3GS, NGP, Android
|
||||
|
||||
[SEE_ALSO]
|
||||
FMOD_OUTPUT_STATE
|
||||
]
|
||||
*/
|
||||
typedef struct FMOD_OUTPUT_DESCRIPTION
|
||||
{
|
||||
const char *name; /* [in] Name of the output. */
|
||||
unsigned int version; /* [in] Plugin writer's version number. */
|
||||
int polling; /* [in] If TRUE (non zero), this tells FMOD to start a thread and call getposition / lock / unlock for feeding data. If 0, the output is probably callback based, so all the plugin needs to do is call readfrommixer to the appropriate pointer. */
|
||||
FMOD_OUTPUT_GETNUMDRIVERSCALLBACK getnumdrivers; /* [in] For sound device enumeration. This callback is to give System::getNumDrivers somthing to return. */
|
||||
FMOD_OUTPUT_GETDRIVERNAMECALLBACK getdrivername; /* [in] For sound device enumeration. This callback is to give System::getDriverName somthing to return. */
|
||||
FMOD_OUTPUT_GETDRIVERCAPSCALLBACK getdrivercaps; /* [in] For sound device enumeration. This callback is to give System::getDriverCaps somthing to return. */
|
||||
FMOD_OUTPUT_INITCALLBACK init; /* [in] Initialization function for the output device. This is called from System::init. */
|
||||
FMOD_OUTPUT_CLOSECALLBACK close; /* [in] Cleanup / close down function for the output device. This is called from System::close. */
|
||||
FMOD_OUTPUT_UPDATECALLBACK update; /* [in] Update function that is called once a frame by the user. This is called from System::update. */
|
||||
FMOD_OUTPUT_GETHANDLECALLBACK gethandle; /* [in] This is called from System::getOutputHandle. This is just to return a pointer to the internal system device object that the system may be using.*/
|
||||
FMOD_OUTPUT_GETPOSITIONCALLBACK getposition; /* [in] This is called from the FMOD software mixer thread if 'polling' = true. This returns a position value in samples so that FMOD knows where and when to fill its buffer. */
|
||||
FMOD_OUTPUT_LOCKCALLBACK lock; /* [in] This is called from the FMOD software mixer thread if 'polling' = true. This function provides a pointer to data that FMOD can write to when software mixing. */
|
||||
FMOD_OUTPUT_UNLOCKCALLBACK unlock; /* [in] This is called from the FMOD software mixer thread if 'polling' = true. This optional function accepts the data that has been mixed and copies it or does whatever it needs to before sending it to the hardware. */
|
||||
typedef struct FMOD_OUTPUT_DESCRIPTION {
|
||||
const char *name; /* [in] Name of the output. */
|
||||
unsigned int version; /* [in] Plugin writer's version number. */
|
||||
int polling; /* [in] If TRUE (non zero), this tells FMOD to start a thread and
|
||||
call getposition / lock / unlock for feeding data. If 0, the
|
||||
output is probably callback based, so all the plugin needs to
|
||||
do is call readfrommixer to the appropriate pointer. */
|
||||
FMOD_OUTPUT_GETNUMDRIVERSCALLBACK
|
||||
getnumdrivers; /* [in] For sound device enumeration. This callback is to
|
||||
give System::getNumDrivers somthing to return. */
|
||||
FMOD_OUTPUT_GETDRIVERNAMECALLBACK
|
||||
getdrivername; /* [in] For sound device enumeration. This callback is to
|
||||
give System::getDriverName somthing to return. */
|
||||
FMOD_OUTPUT_GETDRIVERCAPSCALLBACK
|
||||
getdrivercaps; /* [in] For sound device enumeration. This callback is to
|
||||
give System::getDriverCaps somthing to return. */
|
||||
FMOD_OUTPUT_INITCALLBACK
|
||||
init; /* [in] Initialization function for the output device. This is
|
||||
called from System::init. */
|
||||
FMOD_OUTPUT_CLOSECALLBACK
|
||||
close; /* [in] Cleanup / close down function for the output device. This
|
||||
is called from System::close. */
|
||||
FMOD_OUTPUT_UPDATECALLBACK
|
||||
update; /* [in] Update function that is called once a frame by the user.
|
||||
This is called from System::update. */
|
||||
FMOD_OUTPUT_GETHANDLECALLBACK
|
||||
gethandle; /* [in] This is called from System::getOutputHandle. This is
|
||||
just to return a pointer to the internal system device
|
||||
object that the system may be using.*/
|
||||
FMOD_OUTPUT_GETPOSITIONCALLBACK
|
||||
getposition; /* [in] This is called from the FMOD software mixer thread if
|
||||
'polling' = true. This returns a position value in
|
||||
samples so that FMOD knows where and when to fill its
|
||||
buffer. */
|
||||
FMOD_OUTPUT_LOCKCALLBACK
|
||||
lock; /* [in] This is called from the FMOD software mixer thread if
|
||||
'polling' = true. This function provides a pointer to data that
|
||||
FMOD can write to when software mixing. */
|
||||
FMOD_OUTPUT_UNLOCKCALLBACK
|
||||
unlock; /* [in] This is called from the FMOD software mixer thread if
|
||||
'polling' = true. This optional function accepts the data that
|
||||
has been mixed and copies it or does whatever it needs to
|
||||
before sending it to the hardware. */
|
||||
} FMOD_OUTPUT_DESCRIPTION;
|
||||
|
||||
|
||||
/*
|
||||
[STRUCTURE]
|
||||
[STRUCTURE]
|
||||
[
|
||||
[DESCRIPTION]
|
||||
Output plugin structure that is passed into each callback.
|
||||
|
||||
[REMARKS]
|
||||
Members marked with [in] mean the variable can be written to. The user can set the value.<br>
|
||||
Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.<br>
|
||||
Members marked with [in] mean the variable can be written to. The user can
|
||||
set the value.<br> Members marked with [out] mean the variable is modified by
|
||||
FMOD and is for reading purposes only. Do not change this value.<br>
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable,
|
||||
PlayStation 3, Wii, iPhone, 3GS, NGP, Android
|
||||
|
||||
[SEE_ALSO]
|
||||
FMOD_OUTPUT_DESCRIPTION
|
||||
]
|
||||
*/
|
||||
struct FMOD_OUTPUT_STATE
|
||||
{
|
||||
void *plugindata; /* [in] Plugin writer created data the output author wants to attach to this object. */
|
||||
FMOD_OUTPUT_READFROMMIXER readfrommixer; /* [out] Function to update mixer and write the result to the provided pointer. Used from callback based output only. Polling based output uses lock/unlock/getposition. */
|
||||
struct FMOD_OUTPUT_STATE {
|
||||
void *plugindata; /* [in] Plugin writer created data the output author wants
|
||||
to attach to this object. */
|
||||
FMOD_OUTPUT_READFROMMIXER
|
||||
readfrommixer; /* [out] Function to update mixer and write the result to
|
||||
the provided pointer. Used from callback based output
|
||||
only. Polling based output uses
|
||||
lock/unlock/getposition. */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
/* =========================================================================================== */
|
||||
/* FMOD Linux Specific header file. Copyright (c), Firelight Technologies Pty, Ltd. 2005-2016. */
|
||||
/* =========================================================================================== */
|
||||
/* ===========================================================================================
|
||||
*/
|
||||
/* FMOD Linux Specific header file. Copyright (c), Firelight Technologies Pty,
|
||||
* Ltd. 2005-2016. */
|
||||
/* ===========================================================================================
|
||||
*/
|
||||
|
||||
#ifndef _FMODLINUX_H
|
||||
#define _FMODLINUX_H
|
||||
|
||||
#include "fmod.h"
|
||||
|
||||
|
||||
/*
|
||||
[STRUCTURE]
|
||||
[STRUCTURE]
|
||||
[
|
||||
[DESCRIPTION]
|
||||
Use this structure with System::init to set the information required for linux
|
||||
initialisation.
|
||||
Use this structure with System::init to set the information required for
|
||||
linux initialisation.
|
||||
|
||||
Pass this structure in as the "extradriverdata" parameter in System::init.
|
||||
|
||||
@@ -26,11 +28,11 @@
|
||||
System::init
|
||||
]
|
||||
*/
|
||||
typedef struct FMOD_LINUX_EXTRADRIVERDATA
|
||||
{
|
||||
const char *output_driver_arguments; /* ALSA Only - Arguments to apply to the selected output driver */
|
||||
const char *record_driver_arguments; /* ALSA Only - Arguments to apply to the selected input (record) driver */
|
||||
typedef struct FMOD_LINUX_EXTRADRIVERDATA {
|
||||
const char *output_driver_arguments; /* ALSA Only - Arguments to apply to the
|
||||
selected output driver */
|
||||
const char *record_driver_arguments; /* ALSA Only - Arguments to apply to the
|
||||
selected input (record) driver */
|
||||
} FMOD_LINUX_EXTRADRIVERDATA;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user