move code from segatools

This commit is contained in:
Kevin
2026-09-18 19:03:01 -04:00
parent 7f23821a42
commit 5ea5922dcc
16 changed files with 1263 additions and 106 deletions
+200 -21
View File
@@ -12,6 +12,7 @@
#include "util/crc.h"
#include "util/dprintf.h"
#include "util/env.h"
struct aime_io_config {
wchar_t aime_path[MAX_PATH];
@@ -26,6 +27,8 @@ static uint8_t aime_io_aime_id[10];
static uint8_t aime_io_felica_id[8];
static bool aime_io_aime_id_present;
static bool aime_io_felica_id_present;
static bool aime_io_radio_on = true;
static bool aime_io_update_mode;
static void aime_io_config_read(
struct aime_io_config *cfg,
@@ -217,12 +220,12 @@ static HRESULT aime_io_generate_aime(
uint16_t aime_io_get_api_version(void)
{
return 0x0100;
return 0x0101;
}
HRESULT aime_io_init(void)
{
aime_io_config_read(&aime_io_cfg, L".\\bananatools.ini");
aime_io_config_read(&aime_io_cfg, get_config_path());
return S_OK;
}
@@ -232,10 +235,6 @@ HRESULT aime_io_nfc_poll(uint8_t unit_no)
bool sense;
HRESULT hr;
if (unit_no != 0) {
return S_OK;
}
/* Reset presence flags */
aime_io_aime_id_present = false;
@@ -243,6 +242,10 @@ HRESULT aime_io_nfc_poll(uint8_t unit_no)
/* Don't do anything more if the scan key is not held */
if (!aime_io_radio_on) {
return S_OK;
}
sense = GetAsyncKeyState(aime_io_cfg.vk_scan) & 0x8000;
if (!sense) {
@@ -262,6 +265,20 @@ HRESULT aime_io_nfc_poll(uint8_t unit_no)
return S_OK;
}
/* Try FeliCa IC */
hr = aime_io_read_id_file(
aime_io_cfg.felica_path,
aime_io_felica_id,
sizeof(aime_io_felica_id));
if (SUCCEEDED(hr) && hr != S_FALSE) {
aime_io_felica_id_present = true;
return S_OK;
}
// 2026-08-24 Hay1tsme: Skipping Generating aime before checking for felica was incredibly annoying.
/* Try generating AiMe IC (if enabled) */
if (aime_io_cfg.aime_gen) {
@@ -278,19 +295,6 @@ HRESULT aime_io_nfc_poll(uint8_t unit_no)
return S_OK;
}
/* Try FeliCa IC */
hr = aime_io_read_id_file(
aime_io_cfg.felica_path,
aime_io_felica_id,
sizeof(aime_io_felica_id));
if (SUCCEEDED(hr) && hr != S_FALSE) {
aime_io_felica_id_present = true;
return S_OK;
}
/* Try generating FeliCa IC (if enabled) */
if (aime_io_cfg.felica_gen) {
@@ -317,7 +321,7 @@ HRESULT aime_io_nfc_get_aime_id(
assert(luid != NULL);
assert(luid_size == sizeof(aime_io_aime_id));
if (unit_no != 0 || !aime_io_aime_id_present) {
if (!aime_io_aime_id_present) {
return S_FALSE;
}
@@ -333,7 +337,7 @@ HRESULT aime_io_nfc_get_felica_id(uint8_t unit_no, uint64_t *IDm)
assert(IDm != NULL);
if (unit_no != 0 || !aime_io_felica_id_present) {
if (!aime_io_felica_id_present) {
return S_FALSE;
}
@@ -348,5 +352,180 @@ HRESULT aime_io_nfc_get_felica_id(uint8_t unit_no, uint64_t *IDm)
return S_OK;
}
HRESULT aime_io_nfc_get_mifare_uid(
uint8_t unit_no,
uint8_t *uid,
size_t uid_size)
{
(void) uid;
(void) uid_size;
if (unit_no != 0 || !aime_io_aime_id_present) {
return S_FALSE;
}
return S_FALSE;
}
HRESULT aime_io_nfc_mifare_select(
uint8_t unit_no,
const uint8_t *uid,
size_t uid_size)
{
(void) uid;
(void) uid_size;
if (unit_no != 0) {
return S_FALSE;
}
return S_FALSE;
}
HRESULT aime_io_nfc_mifare_set_key(
uint8_t unit_no,
uint8_t key_type,
const uint8_t *key,
size_t key_size)
{
(void) key_type;
(void) key;
(void) key_size;
if (unit_no != 0) {
return S_FALSE;
}
return S_FALSE;
}
HRESULT aime_io_nfc_mifare_authenticate(
uint8_t unit_no,
uint8_t key_type,
const uint8_t *payload,
size_t payload_size)
{
(void) key_type;
(void) payload;
(void) payload_size;
if (unit_no != 0) {
return S_FALSE;
}
return S_FALSE;
}
HRESULT aime_io_nfc_mifare_read_block(
uint8_t unit_no,
const uint8_t *uid,
size_t uid_size,
uint8_t block_no,
uint8_t *block,
size_t block_size)
{
(void) uid;
(void) uid_size;
(void) block_no;
(void) block;
(void) block_size;
if (unit_no != 0) {
return S_FALSE;
}
return S_FALSE;
}
HRESULT aime_io_nfc_felica_transact(
uint8_t unit_no,
const uint8_t *req,
size_t req_size,
uint8_t *res,
size_t res_size,
size_t *res_size_written)
{
(void) req;
(void) req_size;
(void) res;
(void) res_size;
(void) res_size_written;
if (unit_no != 0) {
return S_FALSE;
}
return S_FALSE;
}
HRESULT aime_io_nfc_radio_on(uint8_t unit_no)
{
if (unit_no != 0) {
return S_FALSE;
}
aime_io_radio_on = true;
aime_io_update_mode = false;
return S_OK;
}
HRESULT aime_io_nfc_radio_off(uint8_t unit_no)
{
if (unit_no != 0) {
return S_FALSE;
}
aime_io_radio_on = false;
return S_OK;
}
HRESULT aime_io_nfc_to_update_mode(uint8_t unit_no)
{
if (unit_no != 0) {
return S_FALSE;
}
aime_io_update_mode = true;
return S_OK;
}
HRESULT aime_io_nfc_send_hex_data(
uint8_t unit_no,
const uint8_t *payload,
size_t payload_size,
uint8_t *status_out)
{
(void) payload;
(void) payload_size;
if (unit_no != 0) {
return S_FALSE;
}
if (status_out != NULL) {
*status_out = (payload_size == 0x2b) ? 0x20 : 0x00;
}
return S_OK;
}
void aime_io_led_set_color(uint8_t unit_no, uint8_t r, uint8_t g, uint8_t b)
{}
void aime_io_vfd_set_text(
const uint8_t *text,
size_t text_len,
const struct aime_io_vfd_state *state)
{
(void) text;
(void) text_len;
(void) state;
}
void aime_io_vfd_set_state(const struct aime_io_vfd_state *state)
{
(void) state;
}
+183 -5
View File
@@ -11,7 +11,7 @@
version and the low byte is the minor version (as defined by the Semantic
Versioning standard).
The latest API version as of this writing is 0x0100.
The latest API version as of this writing is 0x0101.
*/
uint16_t aime_io_get_api_version(void);
@@ -27,7 +27,7 @@ HRESULT aime_io_init(void);
/*
Poll for IC cards in the vicinity.
- unit_no: Always 0 as of the current API version
- unit_no: 0 on the primary Aime reader (most games), may be 1 on Sangokushi Taisen for the queue reader
Minimum API version: 0x0100
*/
@@ -36,7 +36,7 @@ HRESULT aime_io_nfc_poll(uint8_t unit_no);
/*
Attempt to read out a classic Aime card ID
- unit_no: Always 0 as of the current API version
- unit_no: 0 on the primary Aime reader (most games), may be 1 on Sangokushi Taisen for the queue reader
- luid: Pointer to a ten-byte buffer that will receive the ID
- luid_size: Size of the buffer at *luid. Always 10.
@@ -63,7 +63,7 @@ HRESULT aime_io_nfc_get_aime_id(
Parameters:
- unit_no: Always 0 as of the current API version
- unit_no: 0 on the primary Aime reader (most games), may be 1 on Sangokushi Taisen for the queue reader
- IDm: Output parameter that will receive the card ID
Returns:
@@ -77,11 +77,189 @@ HRESULT aime_io_nfc_get_aime_id(
HRESULT aime_io_nfc_get_felica_id(uint8_t unit_no, uint64_t *IDm);
/*
Change the color and brightness of the card reader's RGB lighting
MIFARE key selector values used by the set key/authenticate functions.
Minimum API version: 0x0101
*/
enum {
AIME_IO_MIFARE_KEY_AIME = 0,
AIME_IO_MIFARE_KEY_BANA = 1,
};
/*
Attempt to read the 4-byte MIFARE UID of the currently present card.
Parameters:
- unit_no: Always 0 as of the current API version
- uid: Pointer to a four-byte buffer that will receive the UID
- uid_size: Size of the buffer at *uid. Always 4.
Returns:
- S_OK if a MIFARE card is present and the UID was read successfully
- S_FALSE if no MIFARE card is present (*uid will be ignored)
- Any HRESULT error if an error occured.
Minimum API version: 0x0101
*/
HRESULT aime_io_nfc_get_mifare_uid(
uint8_t unit_no,
uint8_t *uid,
size_t uid_size);
/*
Select a MIFARE card by UID (optional for real readers).
Minimum API version: 0x0101
*/
HRESULT aime_io_nfc_mifare_select(
uint8_t unit_no,
const uint8_t *uid,
size_t uid_size);
/*
Supply a MIFARE authentication key to the reader.
Minimum API version: 0x0101
*/
HRESULT aime_io_nfc_mifare_set_key(
uint8_t unit_no,
uint8_t key_type,
const uint8_t *key,
size_t key_size);
/*
Perform a MIFARE authentication sequence.
Minimum API version: 0x0101
*/
HRESULT aime_io_nfc_mifare_authenticate(
uint8_t unit_no,
uint8_t key_type,
const uint8_t *payload,
size_t payload_size);
/*
Read a 16-byte MIFARE block from the card.
Minimum API version: 0x0101
*/
HRESULT aime_io_nfc_mifare_read_block(
uint8_t unit_no,
const uint8_t *uid,
size_t uid_size,
uint8_t block_no,
uint8_t *block,
size_t block_size);
/*
Forward a raw FeliCa request to a real reader.
Parameters:
- req: FeliCa request buffer, including the length byte
- res: FeliCa response buffer, including the length byte
- res_size_written: Output size of the response (bytes written to *res)
Minimum API version: 0x0101
*/
HRESULT aime_io_nfc_felica_transact(
uint8_t unit_no,
const uint8_t *req,
size_t req_size,
uint8_t *res,
size_t res_size,
size_t *res_size_written);
/*
Enable the reader's RF field.
Minimum API version: 0x0101
*/
HRESULT aime_io_nfc_radio_on(uint8_t unit_no);
/*
Disable the reader's RF field.
Minimum API version: 0x0101
*/
HRESULT aime_io_nfc_radio_off(uint8_t unit_no);
/*
Put the reader into firmware update mode.
Minimum API version: 0x0101
*/
HRESULT aime_io_nfc_to_update_mode(uint8_t unit_no);
/*
Forward a raw hex-data command to the reader.
Parameters:
- payload: Command payload bytes
- payload_size: Size of the payload
- status_out: Optional pointer to receive the SG status byte
Minimum API version: 0x0101
*/
HRESULT aime_io_nfc_send_hex_data(
uint8_t unit_no,
const uint8_t *payload,
size_t payload_size,
uint8_t *status_out);
/*
Change the color and brightness of the card reader's RGB lighting
- unit_no: 0 on the primary Aime reader (most games), may be 1 on Sangokushi Taisen for the queue reader
- r, g, b: Primary color intensity, from 0 to 255 inclusive.
Minimum API version: 0x0100
*/
void aime_io_led_set_color(uint8_t unit_no, uint8_t r, uint8_t g, uint8_t b);
/*
VFD text forwarding. This is intended to pass through the text payload
plus the most recent VFD state so external handlers can emulate scrolling
or layout if desired.
- text: Pointer to raw text bytes (not null-terminated)
- text_len: Length of the text buffer
- state: Current VFD state at the time of rendering
The encoding field uses VFD encoding values (0=GB2312, 1=Big5,
2=Shift-JIS, 3=KSC5601).
Minimum API version: 0x0101
*/
struct aime_io_vfd_state {
uint8_t encoding;
uint8_t text_speed;
uint8_t scroll_enabled;
uint16_t h_scroll;
uint16_t cursor_x;
uint8_t cursor_y;
uint16_t wnd_x0;
uint8_t wnd_y0;
uint16_t wnd_x1;
uint8_t wnd_y1;
uint8_t rotate;
uint8_t brightness;
uint8_t screen_on;
uint32_t clear_seq;
};
void aime_io_vfd_set_text(
const uint8_t *text,
size_t text_len,
const struct aime_io_vfd_state *state);
/*
VFD state change notification. Called when the VFD state changes even
when no text is written.
Minimum API version: 0x0101
*/
void aime_io_vfd_set_state(const struct aime_io_vfd_state *state);
+47 -2
View File
@@ -8,6 +8,11 @@
#include "util/dll-bind.h"
#include "util/dprintf.h"
enum {
AIME_DLL_SYM_COUNT_V100 = 5,
AIME_DLL_SYM_COUNT_V101 = 17,
};
const struct dll_bind_sym aime_dll_syms[] = {
{
.sym = "aime_io_init",
@@ -24,7 +29,43 @@ const struct dll_bind_sym aime_dll_syms[] = {
}, {
.sym = "aime_io_led_set_color",
.off = offsetof(struct aime_dll, led_set_color),
}
}, {
.sym = "aime_io_vfd_set_text",
.off = offsetof(struct aime_dll, vfd_set_text),
}, {
.sym = "aime_io_vfd_set_state",
.off = offsetof(struct aime_dll, vfd_set_state),
}, {
.sym = "aime_io_nfc_get_mifare_uid",
.off = offsetof(struct aime_dll, nfc_get_mifare_uid),
}, {
.sym = "aime_io_nfc_mifare_select",
.off = offsetof(struct aime_dll, nfc_mifare_select),
}, {
.sym = "aime_io_nfc_mifare_set_key",
.off = offsetof(struct aime_dll, nfc_mifare_set_key),
}, {
.sym = "aime_io_nfc_mifare_authenticate",
.off = offsetof(struct aime_dll, nfc_mifare_authenticate),
}, {
.sym = "aime_io_nfc_mifare_read_block",
.off = offsetof(struct aime_dll, nfc_mifare_read_block),
}, {
.sym = "aime_io_nfc_felica_transact",
.off = offsetof(struct aime_dll, nfc_felica_transact),
}, {
.sym = "aime_io_nfc_radio_on",
.off = offsetof(struct aime_dll, nfc_radio_on),
}, {
.sym = "aime_io_nfc_radio_off",
.off = offsetof(struct aime_dll, nfc_radio_off),
}, {
.sym = "aime_io_nfc_to_update_mode",
.off = offsetof(struct aime_dll, nfc_to_update_mode),
}, {
.sym = "aime_io_nfc_send_hex_data",
.off = offsetof(struct aime_dll, nfc_send_hex_data),
},
};
struct aime_dll aime_dll;
@@ -42,6 +83,7 @@ HRESULT aime_dll_init(const struct aime_dll_config *cfg, HINSTANCE self)
HINSTANCE owned;
HINSTANCE src;
HRESULT hr;
size_t sym_count;
assert(cfg != NULL);
assert(self != NULL);
@@ -86,7 +128,10 @@ HRESULT aime_dll_init(const struct aime_dll_config *cfg, HINSTANCE self)
}
sym = aime_dll_syms;
hr = dll_bind(&aime_dll, src, &sym, _countof(aime_dll_syms));
sym_count = (aime_dll.api_version < 0x0101)
? AIME_DLL_SYM_COUNT_V100
: AIME_DLL_SYM_COUNT_V101;
hr = dll_bind(&aime_dll, src, &sym, sym_count);
if (FAILED(hr)) {
if (src != self) {
+47
View File
@@ -1,6 +1,7 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
#include "aimeio/aimeio.h"
@@ -13,11 +14,57 @@ struct aime_dll {
uint8_t *luid,
size_t luid_size);
HRESULT (*nfc_get_felica_id)(uint8_t unit_no, uint64_t *IDm);
HRESULT (*nfc_get_mifare_uid)(
uint8_t unit_no,
uint8_t *uid,
size_t uid_size);
HRESULT (*nfc_mifare_select)(
uint8_t unit_no,
const uint8_t *uid,
size_t uid_size);
HRESULT (*nfc_mifare_set_key)(
uint8_t unit_no,
uint8_t key_type,
const uint8_t *key,
size_t key_size);
HRESULT (*nfc_mifare_authenticate)(
uint8_t unit_no,
uint8_t key_type,
const uint8_t *payload,
size_t payload_size);
HRESULT (*nfc_mifare_read_block)(
uint8_t unit_no,
const uint8_t *uid,
size_t uid_size,
uint8_t block_no,
uint8_t *block,
size_t block_size);
HRESULT (*nfc_felica_transact)(
uint8_t unit_no,
const uint8_t *req,
size_t req_size,
uint8_t *res,
size_t res_size,
size_t *res_size_written);
HRESULT (*nfc_radio_on)(uint8_t unit_no);
HRESULT (*nfc_radio_off)(uint8_t unit_no);
HRESULT (*nfc_to_update_mode)(uint8_t unit_no);
HRESULT (*nfc_send_hex_data)(
uint8_t unit_no,
const uint8_t *payload,
size_t payload_size,
uint8_t *status_out);
void (*led_set_color)(uint8_t unit_no, uint8_t r, uint8_t g, uint8_t b);
void (*vfd_set_text)(
const uint8_t *text,
size_t text_len,
const struct aime_io_vfd_state *state);
void (*vfd_set_state)(const struct aime_io_vfd_state *state);
};
struct aime_dll_config {
wchar_t path[MAX_PATH];
bool path64;
};
extern struct aime_dll aime_dll;
+15 -15
View File
@@ -5,21 +5,21 @@
#pragma pack(push, 1)
enum {
SG_NFC_CMD_GET_FW_VERSION = 0x30,
SG_NFC_CMD_GET_HW_VERSION = 0x32,
SG_NFC_CMD_RADIO_ON = 0x40,
SG_NFC_CMD_RADIO_OFF = 0x41,
SG_NFC_CMD_POLL = 0x42,
SG_NFC_CMD_MIFARE_SELECT_TAG = 0x43,
SG_NFC_CMD_MIFARE_SET_KEY_AIME = 0x50,
SG_NFC_CMD_MIFARE_AUTHENTICATE_A = 0x51,
SG_NFC_CMD_MIFARE_READ_BLOCK = 0x52,
SG_NFC_CMD_MIFARE_SET_KEY_BANA = 0x54,
SG_NFC_CMD_MIFARE_AUTHENTICATE_B = 0x55,
SG_NFC_CMD_TO_UPDATE_MODE = 0x60,
SG_NFC_CMD_SEND_HEX_DATA = 0x61,
SG_NFC_CMD_RESET = 0x62,
SG_NFC_CMD_FELICA_ENCAP = 0x71,
SG_NFC_CMD_GET_FW_VERSION = 0x30,
SG_NFC_CMD_GET_HW_VERSION = 0x32,
SG_NFC_CMD_RADIO_ON = 0x40,
SG_NFC_CMD_RADIO_OFF = 0x41,
SG_NFC_CMD_POLL = 0x42,
SG_NFC_CMD_MIFARE_SELECT_TAG = 0x43,
SG_NFC_CMD_MIFARE_SET_KEY_AIME = 0x50,
SG_NFC_CMD_MIFARE_AUTHENTICATE_AIME = 0x51,
SG_NFC_CMD_MIFARE_READ_BLOCK = 0x52,
SG_NFC_CMD_MIFARE_SET_KEY_BANA = 0x54,
SG_NFC_CMD_MIFARE_AUTHENTICATE_BANA = 0x55,
SG_NFC_CMD_TO_UPDATE_MODE = 0x60,
SG_NFC_CMD_SEND_HEX_DATA = 0x61,
SG_NFC_CMD_RESET = 0x62,
SG_NFC_CMD_FELICA_ENCAP = 0x71,
};
struct sg_nfc_res_get_fw_version {
+417 -28
View File
@@ -2,6 +2,7 @@
#include <assert.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
@@ -11,11 +12,14 @@
#include "board/sg-nfc.h"
#include "board/sg-nfc-cmd.h"
#include "aimeio/aimeio.h"
#include "iccard/aime.h"
#include "iccard/felica.h"
#include "util/dprintf.h"
#include "util/dump.h"
#include "util/slurp.h"
static HRESULT sg_nfc_dispatch(
void *ctx,
@@ -55,6 +59,38 @@ static HRESULT sg_nfc_cmd_mifare_read_block(
const struct sg_nfc_req_mifare_read_block *req,
struct sg_nfc_res_mifare_read_block *res);
static HRESULT sg_nfc_cmd_mifare_select(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_res_header *res);
static HRESULT sg_nfc_cmd_mifare_set_key(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_res_header *res,
uint8_t key_type);
static HRESULT sg_nfc_cmd_mifare_authenticate(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_res_header *res,
uint8_t key_type);
static HRESULT sg_nfc_cmd_radio_on(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_res_header *res);
static HRESULT sg_nfc_cmd_radio_off(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_res_header *res);
static HRESULT sg_nfc_cmd_to_update_mode(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_res_header *res);
static HRESULT sg_nfc_cmd_felica_encap(
struct sg_nfc *nfc,
const struct sg_nfc_req_felica_encap *req,
@@ -87,6 +123,9 @@ void sg_nfc_init(
uint8_t addr,
const struct sg_nfc_ops *ops,
unsigned int gen,
unsigned int proxy_flag,
const wchar_t* authdata_path,
bool mobile_felica,
void *ops_ctx)
{
assert(nfc != NULL);
@@ -96,6 +135,9 @@ void sg_nfc_init(
nfc->ops_ctx = ops_ctx;
nfc->addr = addr;
nfc->gen = gen;
nfc->proxy_flag = proxy_flag;
nfc->authdata_path = authdata_path;
nfc->felica.is_mobile = mobile_felica;
}
#ifdef NDEBUG
@@ -189,19 +231,49 @@ static HRESULT sg_nfc_dispatch(
&req->felica_encap,
&res->felica_encap);
case SG_NFC_CMD_MIFARE_AUTHENTICATE_A:
case SG_NFC_CMD_MIFARE_AUTHENTICATE_B:
case SG_NFC_CMD_MIFARE_SELECT_TAG:
return sg_nfc_cmd_mifare_select(nfc, &req->simple, &res->simple);
case SG_NFC_CMD_MIFARE_SET_KEY_AIME:
return sg_nfc_cmd_mifare_set_key(
nfc,
&req->simple,
&res->simple,
AIME_IO_MIFARE_KEY_AIME);
case SG_NFC_CMD_MIFARE_SET_KEY_BANA:
return sg_nfc_cmd_mifare_set_key(
nfc,
&req->simple,
&res->simple,
AIME_IO_MIFARE_KEY_BANA);
case SG_NFC_CMD_MIFARE_AUTHENTICATE_AIME:
return sg_nfc_cmd_mifare_authenticate(
nfc,
&req->simple,
&res->simple,
AIME_IO_MIFARE_KEY_AIME);
case SG_NFC_CMD_MIFARE_AUTHENTICATE_BANA:
return sg_nfc_cmd_mifare_authenticate(
nfc,
&req->simple,
&res->simple,
AIME_IO_MIFARE_KEY_BANA);
case SG_NFC_CMD_RADIO_ON:
return sg_nfc_cmd_radio_on(nfc, &req->simple, &res->simple);
case SG_NFC_CMD_RADIO_OFF:
return sg_nfc_cmd_radio_off(nfc, &req->simple, &res->simple);
case SG_NFC_CMD_TO_UPDATE_MODE:
return sg_nfc_cmd_to_update_mode(nfc, &req->simple, &res->simple);
case SG_NFC_CMD_SEND_HEX_DATA:
return sg_nfc_cmd_send_hex_data(nfc, &req->simple, &res->simple);
case SG_NFC_CMD_MIFARE_SELECT_TAG:
case SG_NFC_CMD_MIFARE_SET_KEY_AIME:
case SG_NFC_CMD_MIFARE_SET_KEY_BANA:
case SG_NFC_CMD_RADIO_ON:
case SG_NFC_CMD_RADIO_OFF:
case SG_NFC_CMD_TO_UPDATE_MODE:
return sg_nfc_cmd_dummy(nfc, &req->simple, &res->simple);
default:
sg_nfc_dprintf(nfc, "Unimpl command %02x\n", req->simple.hdr.cmd);
@@ -294,7 +366,9 @@ static HRESULT sg_nfc_poll_aime(
struct sg_nfc *nfc,
struct sg_nfc_poll_mifare *mifare)
{
bool has_uid;
uint8_t luid[10];
uint8_t uid[4];
HRESULT hr;
/* Call backend */
@@ -311,11 +385,30 @@ static HRESULT sg_nfc_poll_aime(
sg_nfc_dprintf(nfc, "AiMe card is present\n");
/* Construct response (use an arbitrary UID) */
has_uid = false;
if (nfc->ops->get_mifare_uid != NULL) {
hr = nfc->ops->get_mifare_uid(nfc->ops_ctx, uid, sizeof(uid));
if (FAILED(hr)) {
return hr;
}
if (hr == S_OK) {
has_uid = true;
}
}
/* Construct response */
mifare->type = 0x10;
mifare->id_len = sizeof(mifare->uid);
mifare->uid = _byteswap_ulong(0x01020304);
if (has_uid) {
memcpy(&mifare->uid, uid, sizeof(uid));
} else {
// mifare->uid = _byteswap_ulong(0x8FBECBFF);
mifare->uid = _byteswap_ulong(0x01020304);
}
/* Initialize MIFARE IC emulator */
@@ -354,22 +447,193 @@ static HRESULT sg_nfc_poll_felica(
felica->type = 0x20;
felica->id_len = sizeof(felica->IDm) + sizeof(felica->PMm);
felica->IDm = _byteswap_uint64(IDm);
felica->PMm = _byteswap_uint64(felica_get_amusement_ic_PMm());
felica->PMm = _byteswap_uint64(felica_get_amusement_ic_PMm(nfc->felica.is_mobile));
/* Initialize FeliCa IC emulator */
nfc->felica.IDm = IDm;
nfc->felica.PMm = felica_get_amusement_ic_PMm();
nfc->felica.PMm = felica_get_amusement_ic_PMm(nfc->felica.is_mobile);
nfc->felica.system_code = 0x88b4;
return S_OK;
}
static HRESULT sg_nfc_cmd_mifare_select(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_res_header *res)
{
const uint8_t *payload;
HRESULT hr;
if (req->payload_len != sizeof(uint32_t)) {
sg_nfc_dprintf(nfc, "%s: Payload size is incorrect\n", __func__);
return E_FAIL;
}
payload = (const uint8_t *) req + sizeof(*req);
if (nfc->ops->mifare_select != NULL) {
hr = nfc->ops->mifare_select(nfc->ops_ctx, payload, req->payload_len);
if (FAILED(hr)) {
return hr;
}
}
sg_res_init(res, req, 0);
return S_OK;
}
static HRESULT sg_nfc_cmd_mifare_set_key(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_res_header *res,
uint8_t key_type)
{
const uint8_t *payload;
HRESULT hr;
payload = (const uint8_t *) req + sizeof(*req);
if (nfc->ops->mifare_set_key != NULL) {
hr = nfc->ops->mifare_set_key(
nfc->ops_ctx,
key_type,
payload,
req->payload_len);
if (FAILED(hr)) {
return hr;
}
}
sg_res_init(res, req, 0);
return S_OK;
}
static HRESULT sg_nfc_cmd_mifare_authenticate(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_res_header *res,
uint8_t key_type)
{
const uint8_t *payload;
HRESULT hr;
payload = (const uint8_t *) req + sizeof(*req);
if (nfc->ops->mifare_authenticate != NULL) {
hr = nfc->ops->mifare_authenticate(
nfc->ops_ctx,
key_type,
payload,
req->payload_len);
if (FAILED(hr)) {
return hr;
}
}
sg_res_init(res, req, 0);
return S_OK;
}
static HRESULT sg_nfc_cmd_radio_on(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_res_header *res)
{
HRESULT hr;
if (nfc->ops->radio_on == NULL) {
sg_res_init(res, req, 0);
return S_OK;
}
hr = nfc->ops->radio_on(nfc->ops_ctx);
if (FAILED(hr)) {
return hr;
}
if (hr == S_FALSE) {
sg_res_init(res, req, 0);
return S_OK;
}
sg_res_init(res, req, 0);
return S_OK;
}
static HRESULT sg_nfc_cmd_radio_off(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_res_header *res)
{
HRESULT hr;
if (nfc->ops->radio_off == NULL) {
sg_res_init(res, req, 0);
return S_OK;
}
hr = nfc->ops->radio_off(nfc->ops_ctx);
if (FAILED(hr)) {
return hr;
}
if (hr == S_FALSE) {
sg_res_init(res, req, 0);
return S_OK;
}
sg_res_init(res, req, 0);
return S_OK;
}
static HRESULT sg_nfc_cmd_to_update_mode(
struct sg_nfc *nfc,
const struct sg_req_header *req,
struct sg_res_header *res)
{
HRESULT hr;
if (nfc->ops->to_update_mode == NULL) {
sg_res_init(res, req, 0);
return S_OK;
}
hr = nfc->ops->to_update_mode(nfc->ops_ctx);
if (FAILED(hr)) {
return hr;
}
if (hr == S_FALSE) {
sg_res_init(res, req, 0);
return S_OK;
}
sg_res_init(res, req, 0);
return S_OK;
}
static HRESULT sg_nfc_cmd_mifare_read_block(
struct sg_nfc *nfc,
const struct sg_nfc_req_mifare_read_block *req,
struct sg_nfc_res_mifare_read_block *res)
{
const uint8_t *uid_bytes;
HRESULT hr;
uint32_t uid;
if (req->req.payload_len != sizeof(req->payload)) {
@@ -378,22 +642,86 @@ static HRESULT sg_nfc_cmd_mifare_read_block(
return E_FAIL;
}
uid_bytes = (const uint8_t *) &req->payload.uid;
uid = _byteswap_ulong(req->payload.uid);
sg_nfc_dprintf(nfc, "Read uid %08x block %i\n", uid, req->payload.block_no);
if (req->payload.block_no > 3) {
if (nfc->ops->mifare_read_block != NULL) {
hr = nfc->ops->mifare_read_block(
nfc->ops_ctx,
uid_bytes,
sizeof(req->payload.uid),
req->payload.block_no,
res->block,
sizeof(res->block));
if (FAILED(hr)) {
return hr;
}
if (hr == S_OK) {
sg_res_init(&res->res, &req->req, sizeof(res->block));
return S_OK;
}
}
if (req->payload.block_no > 14) {
sg_nfc_dprintf(nfc, "MIFARE block number out of range\n");
return E_FAIL;
} else if (req->payload.block_no >= 5){ // emoney auth encrypted
sg_res_init(&res->res, &req->req, sizeof(res->block));
char* auth;
long size = wslurp(nfc->authdata_path, &auth, false);
if (size < 0){
sg_nfc_dprintf(nfc, "Failed to read %ls: %lx!\n", nfc->authdata_path, GetLastError());
return E_FAIL;
}
int offset = 0;
if (req->payload.block_no == 6){
offset = 16;
} else if (req->payload.block_no == 8){
offset = 32;
} else if (req->payload.block_no == 9){
offset = 48;
} else if (req->payload.block_no == 10){
offset = 64;
} else if (req->payload.block_no == 12){
offset = 82;
} else if (req->payload.block_no == 13){
offset = 98;
} else if (req->payload.block_no == 14){
offset = 114;
}
for (int i = 0; i < 16 && offset + i < size; i++){
res->block[i] = auth[offset + i];
}
free(auth);
} else if (req->payload.block_no == 4){ // emoney auth plain
sg_res_init(&res->res, &req->req, sizeof(res->block));
res->block[0] = 0x54; // header
res->block[1] = 0x43;
res->block[2] = nfc->proxy_flag; // 2 or 3 depending on game (useProxy in env.json)
res->block[3] = 0x01; // unknown flag
} else { // read all other blocks normally
sg_res_init(&res->res, &req->req, sizeof(res->block));
memcpy( res->block,
nfc->mifare.sectors[0].blocks[req->payload.block_no].bytes,
sizeof(res->block));
}
sg_res_init(&res->res, &req->req, sizeof(res->block));
memcpy( res->block,
nfc->mifare.sectors[0].blocks[req->payload.block_no].bytes,
sizeof(res->block));
return S_OK;
}
@@ -404,6 +732,7 @@ static HRESULT sg_nfc_cmd_felica_encap(
{
struct const_iobuf f_req;
struct iobuf f_res;
size_t res_size_written;
HRESULT hr;
/* First byte of encapsulated request and response is a length byte
@@ -421,6 +750,32 @@ static HRESULT sg_nfc_cmd_felica_encap(
return E_FAIL;
}
if (nfc->ops->felica_transact != NULL) {
res_size_written = 0;
hr = nfc->ops->felica_transact(
nfc->ops_ctx,
req->payload,
req->payload[0],
res->payload,
sizeof(res->payload),
&res_size_written);
if (FAILED(hr)) {
return hr;
}
if (hr == S_OK) {
if (res_size_written == 0 ||
res_size_written > sizeof(res->payload)) {
return E_FAIL;
}
sg_res_init(&res->res, &req->req, res_size_written);
return S_OK;
}
}
f_req.bytes = req->payload;
f_req.nbytes = req->payload[0];
f_req.pos = 1;
@@ -429,7 +784,7 @@ static HRESULT sg_nfc_cmd_felica_encap(
f_res.nbytes = sizeof(res->payload);
f_res.pos = 1;
#if 0
#if defined(LOG_NFC)
dprintf("FELICA OUTBOUND:\n");
dump_const_iobuf(&f_req);
#endif
@@ -443,7 +798,7 @@ static HRESULT sg_nfc_cmd_felica_encap(
sg_res_init(&res->res, &req->req, f_res.pos);
res->payload[0] = f_res.pos;
#if 0
#if defined(LOG_NFC)
dprintf("FELICA INBOUND:\n");
dump_iobuf(&f_res);
#endif
@@ -456,14 +811,48 @@ static HRESULT sg_nfc_cmd_send_hex_data(
const struct sg_req_header *req,
struct sg_res_header *res)
{
sg_res_init(res, req, 0);
const uint8_t *payload;
HRESULT hr;
uint8_t status;
/* Firmware checksum length? */
if (req->payload_len == 0x2b) {
/* The firmware is identical flag? */
res->status = 0x20;
if (nfc->ops->send_hex_data == NULL) {
sg_res_init(res, req, 0);
/* Firmware checksum length? */
if (req->payload_len == 0x2b) {
/* The firmware is identical flag? */
res->status = 0x20;
}
return S_OK;
}
payload = (const uint8_t *) req + sizeof(*req);
status = 0;
hr = nfc->ops->send_hex_data(
nfc->ops_ctx,
payload,
req->payload_len,
&status);
if (FAILED(hr)) {
return hr;
}
if (hr == S_FALSE) {
sg_res_init(res, req, 0);
if (req->payload_len == 0x2b) {
res->status = 0x20;
}
return S_OK;
}
sg_res_init(res, req, 0);
res->status = status;
return S_OK;
}
+39
View File
@@ -14,6 +14,40 @@ struct sg_nfc_ops {
HRESULT (*poll)(void *ctx);
HRESULT (*get_aime_id)(void *ctx, uint8_t *luid, size_t nbytes);
HRESULT (*get_felica_id)(void *ctx, uint64_t *IDm);
HRESULT (*get_mifare_uid)(void *ctx, uint8_t *uid, size_t nbytes);
HRESULT (*mifare_select)(void *ctx, const uint8_t *uid, size_t nbytes);
HRESULT (*mifare_set_key)(
void *ctx,
uint8_t key_type,
const uint8_t *key,
size_t nbytes);
HRESULT (*mifare_authenticate)(
void *ctx,
uint8_t key_type,
const uint8_t *payload,
size_t nbytes);
HRESULT (*mifare_read_block)(
void *ctx,
const uint8_t *uid,
size_t uid_size,
uint8_t block_no,
uint8_t *block,
size_t block_size);
HRESULT (*felica_transact)(
void *ctx,
const uint8_t *req,
size_t req_size,
uint8_t *res,
size_t res_size,
size_t *res_size_written);
HRESULT (*radio_on)(void *ctx);
HRESULT (*radio_off)(void *ctx);
HRESULT (*to_update_mode)(void *ctx);
HRESULT (*send_hex_data)(
void *ctx,
const uint8_t *payload,
size_t payload_size,
uint8_t *status_out);
// TODO Banapass, AmuseIC
};
@@ -23,8 +57,10 @@ struct sg_nfc {
void *ops_ctx;
uint8_t addr;
unsigned int gen;
unsigned int proxy_flag;
struct felica felica;
struct mifare mifare;
const wchar_t* authdata_path;
};
void sg_nfc_init(
@@ -32,6 +68,9 @@ void sg_nfc_init(
uint8_t addr,
const struct sg_nfc_ops *ops,
unsigned int gen,
unsigned int proxy_flag,
const wchar_t* authdata_path,
bool mobile_felica,
void *ops_ctx);
void sg_nfc_transact(
+196 -4
View File
@@ -24,12 +24,62 @@ static HRESULT sg_reader_nfc_get_aime_id(
uint8_t *luid,
size_t luid_size);
static HRESULT sg_reader_nfc_get_felica_id(void *ctx, uint64_t *IDm);
static HRESULT sg_reader_nfc_get_mifare_uid(
void *ctx,
uint8_t *uid,
size_t uid_size);
static HRESULT sg_reader_nfc_mifare_select(
void *ctx,
const uint8_t *uid,
size_t uid_size);
static HRESULT sg_reader_nfc_mifare_set_key(
void *ctx,
uint8_t key_type,
const uint8_t *key,
size_t key_size);
static HRESULT sg_reader_nfc_mifare_authenticate(
void *ctx,
uint8_t key_type,
const uint8_t *payload,
size_t payload_size);
static HRESULT sg_reader_nfc_mifare_read_block(
void *ctx,
const uint8_t *uid,
size_t uid_size,
uint8_t block_no,
uint8_t *block,
size_t block_size);
static HRESULT sg_reader_nfc_felica_transact(
void *ctx,
const uint8_t *req,
size_t req_size,
uint8_t *res,
size_t res_size,
size_t *res_size_written);
static HRESULT sg_reader_nfc_radio_on(void *ctx);
static HRESULT sg_reader_nfc_radio_off(void *ctx);
static HRESULT sg_reader_nfc_to_update_mode(void *ctx);
static HRESULT sg_reader_nfc_send_hex_data(
void *ctx,
const uint8_t *payload,
size_t payload_size,
uint8_t *status_out);
static void sg_reader_led_set_color(void *ctx, uint8_t r, uint8_t g, uint8_t b);
static const struct sg_nfc_ops sg_reader_nfc_ops = {
.poll = sg_reader_nfc_poll,
.get_aime_id = sg_reader_nfc_get_aime_id,
.get_felica_id = sg_reader_nfc_get_felica_id,
.get_mifare_uid = sg_reader_nfc_get_mifare_uid,
.mifare_select = sg_reader_nfc_mifare_select,
.mifare_set_key = sg_reader_nfc_mifare_set_key,
.mifare_authenticate = sg_reader_nfc_mifare_authenticate,
.mifare_read_block = sg_reader_nfc_mifare_read_block,
.felica_transact = sg_reader_nfc_felica_transact,
.radio_on = sg_reader_nfc_radio_on,
.radio_off = sg_reader_nfc_radio_off,
.to_update_mode = sg_reader_nfc_to_update_mode,
.send_hex_data = sg_reader_nfc_send_hex_data,
};
static const struct sg_led_ops sg_reader_led_ops = {
@@ -47,7 +97,7 @@ static struct sg_led sg_reader_led;
HRESULT sg_reader_hook_init(
const struct aime_config *cfg,
unsigned int port_no,
unsigned int default_port_no,
unsigned int gen,
HINSTANCE self)
{
@@ -66,6 +116,11 @@ HRESULT sg_reader_hook_init(
return hr;
}
unsigned int port_no = cfg->port_no;
if (port_no == 0){
port_no = default_port_no;
}
if (cfg->gen != 0) {
gen = cfg->gen;
}
@@ -76,7 +131,7 @@ HRESULT sg_reader_hook_init(
return E_INVALIDARG;
}
sg_nfc_init(&sg_reader_nfc, 0x00, &sg_reader_nfc_ops, gen, NULL);
sg_nfc_init(&sg_reader_nfc, 0x00, &sg_reader_nfc_ops, gen, cfg->proxy_flag, cfg->authdata_path, cfg->mobile_felica, NULL);
sg_led_init(&sg_reader_led, 0x08, &sg_reader_led_ops, gen, NULL);
InitializeCriticalSection(&sg_reader_lock);
@@ -85,6 +140,7 @@ HRESULT sg_reader_hook_init(
sg_reader_uart.baud.BaudRate = 38400;
}
dprintf("NFC Assembly: enabling (port=%d)\n", port_no);
uart_init(&sg_reader_uart, port_no);
sg_reader_uart.written.bytes = sg_reader_written_bytes;
sg_reader_uart.written.nbytes = sizeof(sg_reader_written_bytes);
@@ -115,14 +171,14 @@ static HRESULT sg_reader_handle_irp_locked(struct irp *irp)
{
HRESULT hr;
#if 0
#if defined(LOG_NFC)
if (irp->op == IRP_OP_WRITE) {
dprintf("WRITE:\n");
dump_const_iobuf(&irp->write);
}
#endif
#if 0
#if defined(LOG_NFC)
if (irp->op == IRP_OP_READ) {
dprintf("READ:\n");
dump_iobuf(&sg_reader_uart.readable);
@@ -195,6 +251,142 @@ static HRESULT sg_reader_nfc_get_felica_id(void *ctx, uint64_t *IDm)
return aime_dll.nfc_get_felica_id(0, IDm);
}
static HRESULT sg_reader_nfc_get_mifare_uid(
void *ctx,
uint8_t *uid,
size_t uid_size)
{
if (aime_dll.nfc_get_mifare_uid == NULL) {
return S_FALSE;
}
return aime_dll.nfc_get_mifare_uid(0, uid, uid_size);
}
static HRESULT sg_reader_nfc_mifare_select(
void *ctx,
const uint8_t *uid,
size_t uid_size)
{
if (aime_dll.nfc_mifare_select == NULL) {
return S_FALSE;
}
return aime_dll.nfc_mifare_select(0, uid, uid_size);
}
static HRESULT sg_reader_nfc_mifare_set_key(
void *ctx,
uint8_t key_type,
const uint8_t *key,
size_t key_size)
{
if (aime_dll.nfc_mifare_set_key == NULL) {
return S_FALSE;
}
return aime_dll.nfc_mifare_set_key(0, key_type, key, key_size);
}
static HRESULT sg_reader_nfc_mifare_authenticate(
void *ctx,
uint8_t key_type,
const uint8_t *payload,
size_t payload_size)
{
if (aime_dll.nfc_mifare_authenticate == NULL) {
return S_FALSE;
}
return aime_dll.nfc_mifare_authenticate(
0,
key_type,
payload,
payload_size);
}
static HRESULT sg_reader_nfc_mifare_read_block(
void *ctx,
const uint8_t *uid,
size_t uid_size,
uint8_t block_no,
uint8_t *block,
size_t block_size)
{
if (aime_dll.nfc_mifare_read_block == NULL) {
return S_FALSE;
}
return aime_dll.nfc_mifare_read_block(
0,
uid,
uid_size,
block_no,
block,
block_size);
}
static HRESULT sg_reader_nfc_felica_transact(
void *ctx,
const uint8_t *req,
size_t req_size,
uint8_t *res,
size_t res_size,
size_t *res_size_written)
{
if (aime_dll.nfc_felica_transact == NULL) {
return S_FALSE;
}
return aime_dll.nfc_felica_transact(
0,
req,
req_size,
res,
res_size,
res_size_written);
}
static HRESULT sg_reader_nfc_radio_on(void *ctx)
{
if (aime_dll.nfc_radio_on == NULL) {
return S_FALSE;
}
return aime_dll.nfc_radio_on(0);
}
static HRESULT sg_reader_nfc_radio_off(void *ctx)
{
if (aime_dll.nfc_radio_off == NULL) {
return S_FALSE;
}
return aime_dll.nfc_radio_off(0);
}
static HRESULT sg_reader_nfc_to_update_mode(void *ctx)
{
if (aime_dll.nfc_to_update_mode == NULL) {
return S_FALSE;
}
return aime_dll.nfc_to_update_mode(0);
}
static HRESULT sg_reader_nfc_send_hex_data(
void *ctx,
const uint8_t *payload,
size_t payload_size,
uint8_t *status_out)
{
if (aime_dll.nfc_send_hex_data == NULL) {
return S_FALSE;
}
return aime_dll.nfc_send_hex_data(0, payload, payload_size, status_out);
}
static void sg_reader_led_set_color(void *ctx, uint8_t r, uint8_t g, uint8_t b)
{
aime_dll.led_set_color(0, r, g, b);
+5 -1
View File
@@ -9,12 +9,16 @@
struct aime_config {
struct aime_dll_config dll;
bool enable;
unsigned int port_no;
bool high_baudrate;
unsigned int gen;
unsigned int proxy_flag;
wchar_t authdata_path[MAX_PATH];
bool mobile_felica;
};
HRESULT sg_reader_hook_init(
const struct aime_config *cfg,
unsigned int port_no,
unsigned int default_port_no,
unsigned int gen,
HINSTANCE self);
+14 -28
View File
@@ -1,9 +1,9 @@
#include <windows.h>
#include <stdlib.h>
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include "hook/iobuf.h"
@@ -37,28 +37,14 @@ static HRESULT felica_cmd_write_without_encryption(
struct const_iobuf* req,
struct iobuf* res);
uint64_t felica_get_generic_PMm(void)
{
/* A FeliCa PMm contains low-level protocol timing information for
communicating with a particular IC card. The exact values are not
particularly important for our purposes, so we'll just return a hard-
coded PMm. This current value has been taken from an iPhone, emulating
a Suica pass via Apple Wallet, which seems to be one of the few
universally accepted FeliCa types for these games. Certain older
Suica passes and other payment and transportation cards
do not seem to be supported anymore. */
return 0x01168B868FBECBFFULL;
}
uint64_t felica_get_amusement_ic_PMm(void)
uint64_t felica_get_amusement_ic_PMm(bool is_mobile)
{
/*
* AIC Card PMm, if this is returned from the card,
* the aimelib will access the actual blocks for authentication.
*/
return 0x00F1000000014300;
return is_mobile ? 0x0018000000014300 : 0x00F1000000014300;
}
HRESULT felica_transact(
@@ -211,17 +197,6 @@ static HRESULT felica_cmd_get_system_code(
return S_OK;
}
static HRESULT felica_cmd_active(
struct felica *f,
struct const_iobuf *req,
struct iobuf *res)
{
/* The specification for this command is probably only available under NDA.
Returning what the driver seems to want. */
return iobuf_write_8(res, 0);
}
static HRESULT felica_cmd_read_without_encryption(
struct felica *f,
struct const_iobuf *req,
@@ -345,3 +320,14 @@ static HRESULT felica_cmd_write_without_encryption(
{
return iobuf_write_be16(res, 0);
}
static HRESULT felica_cmd_active(
struct felica *f,
struct const_iobuf *req,
struct iobuf *res)
{
/* The specification for this command is probably only available under NDA.
Returning what the driver seems to want. */
return iobuf_write_8(res, 0);
}
+3 -2
View File
@@ -1,5 +1,6 @@
#pragma once
#include <stdbool.h>
#include <windows.h>
#include <stddef.h>
@@ -19,6 +20,7 @@ struct felica {
uint64_t IDm;
uint64_t PMm;
uint16_t system_code;
bool is_mobile;
};
HRESULT felica_transact(
@@ -26,5 +28,4 @@ HRESULT felica_transact(
struct const_iobuf *req,
struct iobuf *res);
uint64_t felica_get_generic_PMm(void);
uint64_t felica_get_amusement_ic_PMm(void);
uint64_t felica_get_amusement_ic_PMm(bool is_mobile);
+10
View File
@@ -0,0 +1,10 @@
#include "env.h"
const wchar_t* get_config_path() {
static wchar_t path[MAX_PATH];
if (!GetEnvironmentVariableW(L"BANANATOOLS_CONFIG_PATH", path, MAX_PATH)) {
return L".\\bananatools.ini";
}
return path;
}
+4
View File
@@ -0,0 +1,4 @@
#pragma once
#include <windows.h>
const wchar_t* get_config_path();
+4
View File
@@ -10,6 +10,8 @@ util_lib = static_library(
'async.h',
'crc.c',
'crc.h',
'env.c',
'env.h',
'dll-bind.c',
'dll-bind.h',
'dprintf.c',
@@ -20,6 +22,8 @@ util_lib = static_library(
'lib.h',
'str.c',
'str.h',
'slurp.c',
'slurp.h',
'hexstr.c',
'hexstr.h',
],
+67
View File
@@ -0,0 +1,67 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
/*
* 'slurp' reads the file identified by 'path' into a character buffer
* pointed at by 'buf', optionally adding a terminating NUL if
* 'add_nul' is true. On success, the size of the file is returned; on
* failure, -1 is returned and ERRNO is set by the underlying system
* or library call that failed.
*
* WARNING: 'slurp' malloc()s memory to '*buf' which must be freed by
* the caller.
*/
long wslurp(const wchar_t* path, char **buf, bool add_nul)
{
FILE *fp;
size_t fsz;
long off_end;
int rc;
/* Open the file */
fp = _wfopen(path, L"rb");
if( NULL == fp ) {
return -1L;
}
/* Seek to the end of the file */
rc = fseek(fp, 0L, SEEK_END);
if( 0 != rc ) {
return -1L;
}
/* Byte offset to the end of the file (size) */
if( 0 > (off_end = ftell(fp)) ) {
return -1L;
}
fsz = (size_t)off_end;
/* Allocate a buffer to hold the whole file */
*buf = malloc( fsz+(int)add_nul );
if( NULL == *buf ) {
return -1L;
}
/* Rewind file pointer to start of file */
rewind(fp);
/* Slurp file into buffer */
if( fsz != fread(*buf, 1, fsz, fp) ) {
free(*buf);
return -1L;
}
/* Close the file */
if( EOF == fclose(fp) ) {
free(*buf);
return -1L;
}
if( add_nul ) {
/* Make sure the buffer is NUL-terminated, just in case */
buf[fsz] = '\0';
}
/* Return the file size */
return (long)fsz;
}
+12
View File
@@ -0,0 +1,12 @@
#include <stdbool.h>
/*
* 'slurp' reads the file identified by 'path' into a character buffer
* pointed at by 'buf', optionally adding a terminating NUL if
* 'add_nul' is true. On success, the size of the file is returned; on
* failure, -1 is returned and ERRNO is set by the underlying system
* or library call that failed.
*
* WARNING: 'slurp' malloc()s memory to '*buf' which must be freed by
* the caller.
*/
long wslurp(const wchar_t* path, char **buf, bool add_nul);