mirror of
https://gitea.tendokyu.moe/Hay1tsme/segatools.git
synced 2026-05-06 05:15:42 -05:00
Merge branch 'develop'
This commit is contained in:
commit
aaf823594d
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -18,6 +18,7 @@ build/
|
|||
|
||||
# External dependencies
|
||||
subprojects/capnhook
|
||||
subprojects/cwinwebsocket
|
||||
|
||||
# For enabling debug logging on local builds
|
||||
MesonLocalOptions.mk
|
||||
|
|
|
|||
54
Package.mk
54
Package.mk
|
|
@ -179,6 +179,7 @@ $(BUILD_DIR_ZIP)/mai2.zip:
|
|||
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
||||
$(BUILD_DIR_GAMES_64)/mai2hook/mai2hook.dll \
|
||||
$(DIST_DIR)/mai2/segatools.ini \
|
||||
$(DIST_DIR)/mai2/config_hook.json \
|
||||
$(DIST_DIR)/mai2/launch.bat \
|
||||
$(BUILD_DIR_ZIP)/mai2
|
||||
$(V)cp pki/billing.pub \
|
||||
|
|
@ -256,6 +257,57 @@ $(BUILD_DIR_ZIP)/apm3.zip:
|
|||
$(V)strip $(BUILD_DIR_ZIP)/apm3/*.{exe,dll}
|
||||
$(V)cd $(BUILD_DIR_ZIP)/apm3 ; zip -r ../apm3.zip *
|
||||
|
||||
$(BUILD_DIR_ZIP)/ekt.zip:
|
||||
$(V)echo ... $@
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/ekt
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/ekt/DEVICE
|
||||
$(V)cp $(DIST_DIR)/ekt/segatools_terminal.ini \
|
||||
$(DIST_DIR)/ekt/segatools_satellite.ini \
|
||||
$(DIST_DIR)/ekt/launch_terminal.bat \
|
||||
$(DIST_DIR)/ekt/launch_satellite.bat \
|
||||
$(DIST_DIR)/ekt/card_player.html \
|
||||
$(DIST_DIR)/ekt/config_hook.json \
|
||||
$(BUILD_DIR_ZIP)/ekt
|
||||
$(V)cp pki/billing.pub \
|
||||
pki/ca.crt \
|
||||
$(BUILD_DIR_ZIP)/ekt/DEVICE
|
||||
$(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \
|
||||
$(BUILD_DIR_ZIP)/ekt/inject_x86.exe
|
||||
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
||||
$(BUILD_DIR_ZIP)/ekt/inject_x64.exe
|
||||
$(V)cp $(BUILD_DIR_GAMES_32)/ekthook/ekthook.dll \
|
||||
$(BUILD_DIR_ZIP)/ekt/ekthook_x86.dll
|
||||
$(V)cp $(BUILD_DIR_GAMES_64)/ekthook/ekthook.dll \
|
||||
$(BUILD_DIR_ZIP)/ekt/ekthook_x64.dll
|
||||
$(V)strip $(BUILD_DIR_ZIP)/ekt/*.{exe,dll}
|
||||
$(V)cd $(BUILD_DIR_ZIP)/ekt ; zip -r ../ekt.zip *
|
||||
|
||||
$(BUILD_DIR_ZIP)/sekito.zip:
|
||||
$(V)echo ... $@
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/sekito
|
||||
$(V)mkdir -p $(BUILD_DIR_ZIP)/sekito/DEVICE
|
||||
$(V)cp $(DIST_DIR)/sekito/segatools_terminal.ini \
|
||||
$(DIST_DIR)/sekito/segatools_satellite.ini \
|
||||
$(DIST_DIR)/sekito/launch_terminal.bat \
|
||||
$(DIST_DIR)/sekito/launch_satellite.bat \
|
||||
$(DIST_DIR)/sekito/card_player.html \
|
||||
$(DIST_DIR)/sekito/config_hook_satellite.json \
|
||||
$(DIST_DIR)/sekito/config_hook_terminal.json \
|
||||
$(BUILD_DIR_ZIP)/sekito
|
||||
$(V)cp pki/billing.pub \
|
||||
pki/ca.crt \
|
||||
$(BUILD_DIR_ZIP)/sekito/DEVICE
|
||||
$(V)cp $(BUILD_DIR_32)/subprojects/capnhook/inject/inject.exe \
|
||||
$(BUILD_DIR_ZIP)/sekito/inject_x86.exe
|
||||
$(V)cp $(BUILD_DIR_64)/subprojects/capnhook/inject/inject.exe \
|
||||
$(BUILD_DIR_ZIP)/sekito/inject_x64.exe
|
||||
$(V)cp $(BUILD_DIR_GAMES_32)/sekitohook/sekitohook.dll \
|
||||
$(BUILD_DIR_ZIP)/sekito/sekitohook_x86.dll
|
||||
$(V)cp $(BUILD_DIR_GAMES_64)/sekitohook/sekitohook.dll \
|
||||
$(BUILD_DIR_ZIP)/sekito/sekitohook_x64.dll
|
||||
$(V)strip $(BUILD_DIR_ZIP)/sekito/*.{exe,dll}
|
||||
$(V)cd $(BUILD_DIR_ZIP)/sekito ; zip -r ../sekito.zip *
|
||||
|
||||
$(BUILD_DIR_ZIP)/doc.zip: \
|
||||
$(DOC_DIR)/config \
|
||||
$(DOC_DIR)/chunihook.md \
|
||||
|
|
@ -282,6 +334,8 @@ $(BUILD_DIR_ZIP)/segatools.zip: \
|
|||
$(BUILD_DIR_ZIP)/fgo.zip \
|
||||
$(BUILD_DIR_ZIP)/kemono.zip \
|
||||
$(BUILD_DIR_ZIP)/apm3.zip \
|
||||
$(BUILD_DIR_ZIP)/ekt.zip \
|
||||
$(BUILD_DIR_ZIP)/sekito.zip \
|
||||
CHANGELOG.md \
|
||||
README.md \
|
||||
|
||||
|
|
|
|||
16
README.md
16
README.md
|
|
@ -1,11 +1,13 @@
|
|||
# Segatools
|
||||
|
||||
Version: `2025-11-04`
|
||||
Version: `2026-04-06`
|
||||
|
||||
Loaders and hardware emulators for SEGA games that run on the Nu and ALLS platforms.
|
||||
|
||||
## List of supported games
|
||||
|
||||
* ALL.Net P-ras MULTI Version 3
|
||||
* starting from ALL.Net P-ras MULTI Version 3 1.01
|
||||
* Card Maker
|
||||
* starting from Card Maker
|
||||
* CHUNITHM
|
||||
|
|
@ -13,27 +15,29 @@ Loaders and hardware emulators for SEGA games that run on the Nu and ALLS platfo
|
|||
* starting from CHUNITHM NEW!!
|
||||
* crossbeats REV.
|
||||
* up to crossbeats REV. SUNRISE
|
||||
* Eiketsu Taisen (英傑大戦)
|
||||
* starting from Sanzensekai no Hadou (三千世界の波動)
|
||||
* Fate/Grand Order
|
||||
* Fate/Grand Order Arcade
|
||||
* Hatsune Miku: Project DIVA Arcade
|
||||
* up to Future Tone
|
||||
* Initial D
|
||||
* [Initial D Arcade Stage Zero](doc/idzhook.md)
|
||||
* Initial D THE ARCADE
|
||||
* Initial D THE ARCADE (up to Season 3)
|
||||
* Kemono Friends
|
||||
* Kemono Friends 3: Planet Tours
|
||||
* maimai DX
|
||||
* starting from maimai DX
|
||||
* Mario & Sonic
|
||||
* Mario & Sonic at the Tokyo 2020 Olympics Arcade
|
||||
* O.N.G.E.K.I.
|
||||
* starting from O.N.G.E.K.I.
|
||||
* Sangokushi Taisen (三国志大戦)
|
||||
* starting from 1.01
|
||||
* SEGA World Drivers Championship
|
||||
* SEGA World Drivers Championship 2019
|
||||
* WACCA
|
||||
* starting from WACCA
|
||||
* Kemono Friends
|
||||
* Kemono Friends 3: Planet Tours
|
||||
* ALL.Net P-ras MULTI Version 3
|
||||
* starting from ALL.Net P-ras MULTI Version 3 1.01
|
||||
|
||||
## End-users
|
||||
|
||||
|
|
|
|||
|
|
@ -27,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,
|
||||
|
|
@ -218,7 +220,7 @@ static HRESULT aime_io_generate_aime(
|
|||
|
||||
uint16_t aime_io_get_api_version(void)
|
||||
{
|
||||
return 0x0100;
|
||||
return 0x0101;
|
||||
}
|
||||
|
||||
HRESULT aime_io_init(void)
|
||||
|
|
@ -233,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;
|
||||
|
|
@ -244,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) {
|
||||
|
|
@ -318,7 +320,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;
|
||||
}
|
||||
|
||||
|
|
@ -334,7 +336,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;
|
||||
}
|
||||
|
||||
|
|
@ -349,5 +351,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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ void jvs_config_load(struct jvs_config *cfg, const wchar_t *filename)
|
|||
assert(filename != NULL);
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"jvs", L"enable", 1, filename);
|
||||
cfg->foreground = GetPrivateProfileIntW(L"jvs", L"foreground", 0, filename);
|
||||
}
|
||||
|
||||
void sram_config_load(struct sram_config *cfg, const wchar_t *filename)
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ DEFINE_GUID(
|
|||
|
||||
struct jvs_config {
|
||||
bool enable;
|
||||
bool foreground;
|
||||
};
|
||||
|
||||
typedef HRESULT (*jvs_provider_t)(struct jvs_node **root);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,52 @@ 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 {
|
||||
|
|
|
|||
|
|
@ -65,20 +65,24 @@ static void aime_dll_config_load(struct aime_dll_config *cfg, const wchar_t *fil
|
|||
}
|
||||
}
|
||||
|
||||
void aime_config_load(struct aime_config *cfg, const wchar_t *filename)
|
||||
void aime_config_load(struct aime_config *cfg, const wchar_t *filename) {
|
||||
aime_config_load_bykey(cfg, filename, L"aime");
|
||||
}
|
||||
|
||||
void aime_config_load_bykey(struct aime_config *cfg, const wchar_t *filename, const wchar_t* config_key)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
aime_dll_config_load(&cfg->dll, filename);
|
||||
cfg->enable = GetPrivateProfileIntW(L"aime", L"enable", 1, filename);
|
||||
cfg->port_no = GetPrivateProfileIntW(L"aime", L"portNo", 0, filename);
|
||||
cfg->high_baudrate = GetPrivateProfileIntW(L"aime", L"highBaud", 1, filename);
|
||||
cfg->gen = GetPrivateProfileIntW(L"aime", L"gen", 0, filename);
|
||||
cfg->proxy_flag = GetPrivateProfileIntW(L"aime", L"proxyFlag", 2, filename);
|
||||
cfg->enable = GetPrivateProfileIntW(config_key, L"enable", 1, filename);
|
||||
cfg->port_no = GetPrivateProfileIntW(config_key, L"portNo", 0, filename);
|
||||
cfg->high_baudrate = GetPrivateProfileIntW(config_key, L"highBaud", 1, filename);
|
||||
cfg->gen = GetPrivateProfileIntW(config_key, L"gen", 0, filename);
|
||||
cfg->proxy_flag = GetPrivateProfileIntW(config_key, L"proxyFlag", 2, filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"aime",
|
||||
config_key,
|
||||
L"authdataPath",
|
||||
L"DEVICE\\authdata.bin",
|
||||
cfg->authdata_path,
|
||||
|
|
@ -92,6 +96,7 @@ void io4_config_load(struct io4_config *cfg, const wchar_t *filename)
|
|||
assert(filename != NULL);
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"io4", L"enable", 1, filename);
|
||||
cfg->foreground_only = GetPrivateProfileIntW(L"io4", L"foreground", 1, filename);
|
||||
}
|
||||
|
||||
void vfd_config_load(struct vfd_config *cfg, const wchar_t *filename)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include "board/ffb.h"
|
||||
|
||||
void aime_config_load(struct aime_config *cfg, const wchar_t *filename);
|
||||
void aime_config_load_bykey(struct aime_config *cfg, const wchar_t *filename, const wchar_t *config_key);
|
||||
void io4_config_load(struct io4_config *cfg, const wchar_t *filename);
|
||||
void vfd_config_load(struct vfd_config *cfg, const wchar_t *filename);
|
||||
void ffb_config_load(struct ffb_config *cfg, const wchar_t *filename);
|
||||
|
|
|
|||
77
common/board/elo-cmd.h
Normal file
77
common/board/elo-cmd.h
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#pragma once
|
||||
|
||||
#include "board/elo-frame.h"
|
||||
|
||||
enum {
|
||||
ELO_CMD_TOUCH = 'T',
|
||||
ELO_CMD_QUERY_ACKNOWLEDGE = 'a',
|
||||
ELO_CMD_ACKNOWLEDGE = 'A',
|
||||
ELO_CMD_SET_RESET = 'R',
|
||||
ELO_CMD_QUERY_PARAMETER = 'p',
|
||||
ELO_CMD_SET_PARAMETER = 'P'
|
||||
};
|
||||
|
||||
enum {
|
||||
ELO_ERR_NONE = '0',
|
||||
ELO_ERR_DIVIDE_BY_ZERO = '1',
|
||||
ELO_ERR_BAD_INPUT_PACKET = '2',
|
||||
ELO_ERR_BAD_INPUT_CHECKSUM = '3',
|
||||
ELO_ERR_INPUT_PACKET_OVERRUN = '4',
|
||||
ELO_ERR_ILLEGAL_COMMAND = '5',
|
||||
ELO_ERR_CALIBRATION_CANCELLED = '6',
|
||||
ELO_ERR_BAD_SERIAL_SETUP = '8',
|
||||
ELO_ERR_INVALID_NVRAM = '9',
|
||||
ELO_ERR_SET_UNAVAILABLE = 'A',
|
||||
ELO_ERR_UNSUPPORTED_IN_FIRM = 'B',
|
||||
ELO_ERR_ILLEGAL_SUBCOMMAND = 'C',
|
||||
ELO_ERR_OPERAND_OUT_OF_RANGE = 'D',
|
||||
ELO_ERR_INVALID_TYPE = 'E',
|
||||
ELO_ERR_FATAL_ERROR = 'F',
|
||||
ELO_ERR_QUERY_UNAVAILABLE = 'G',
|
||||
ELO_ERR_INVALID_INTERRUPT = 'H',
|
||||
ELO_ERR_NVRAM_FAILURE = 'I',
|
||||
ELO_ERR_INVALID_ADDRESS = 'J',
|
||||
ELO_ERR_FAILED_POWER_ON = 'K',
|
||||
};
|
||||
|
||||
/* Touch report packet (IntelliTouch format) */
|
||||
struct elo_packet_touch {
|
||||
struct elo_packet_hdr hdr;
|
||||
uint8_t status; /* Touch status flags */
|
||||
uint8_t x_low; /* X coordinate low byte */
|
||||
uint8_t x_high; /* X coordinate high byte */
|
||||
uint8_t y_low; /* Y coordinate low byte */
|
||||
uint8_t y_high; /* Y coordinate high byte */
|
||||
uint8_t z_low; /* Z coordinate (pressure) low byte */
|
||||
uint8_t z_high; /* Z coordinate (pressure) high byte */
|
||||
};
|
||||
|
||||
/* Acknowledge packet */
|
||||
struct elo_packet_acknowledge {
|
||||
struct elo_packet_hdr hdr;
|
||||
uint8_t error_code[4]; /* Up to 4 error codes */
|
||||
};
|
||||
|
||||
/* Reset packet */
|
||||
struct elo_packet_reset {
|
||||
struct elo_packet_hdr hdr;
|
||||
uint8_t r_type; /* '0' = hard reset, '1' = soft reset, '2' = NVRAM reset */
|
||||
};
|
||||
|
||||
/* Parameter packet */
|
||||
struct elo_packet_parameter {
|
||||
struct elo_packet_hdr hdr;
|
||||
uint8_t io; /* I/O type: '0' = serial */
|
||||
uint8_t ser1; /* Serial parameter 1 (baud rate, parity, etc.) */
|
||||
uint8_t ser2; /* Serial parameter 2 (handshaking, etc.) */
|
||||
};
|
||||
|
||||
/* Union of all packet types for easier handling */
|
||||
union elo_packet_any {
|
||||
struct elo_packet_hdr hdr;
|
||||
struct elo_packet_touch touch;
|
||||
struct elo_packet_acknowledge ack;
|
||||
struct elo_packet_reset reset;
|
||||
struct elo_packet_parameter param;
|
||||
uint8_t bytes[10];
|
||||
};
|
||||
161
common/board/elo-frame.c
Normal file
161
common/board/elo-frame.c
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
SmartSet protocol framing implementation
|
||||
|
||||
The SmartSet protocol uses the following frame format:
|
||||
[0x55] [CMD] [DATA...] [CHECKSUM]
|
||||
|
||||
- Lead byte: 0x55 (alternating bit pattern 01010101)
|
||||
- Command byte: ASCII command character
|
||||
- Data: Variable length based on command
|
||||
- Checksum: Sum of all bytes (including lead) + 0xAA, low byte only
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "board/elo-cmd.h"
|
||||
#include "board/elo-frame.h"
|
||||
|
||||
#include "hook/iobuf.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static void elo_frame_sync(struct iobuf *src);
|
||||
static HRESULT elo_frame_accept(const struct iobuf *dest);
|
||||
|
||||
/* Checksum offset to cancel out the lead byte */
|
||||
#define ELO_CHECKSUM_OFFSET 0xAA
|
||||
|
||||
/* SmartSet frame length */
|
||||
#define ELO_FRAME_LENGTH 10
|
||||
|
||||
static void elo_frame_sync(struct iobuf *src)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < src->pos && src->bytes[i] != ELO_FRAME_LEAD; i++);
|
||||
|
||||
src->pos -= i;
|
||||
memmove(&src->bytes[0], &src->bytes[i], i);
|
||||
}
|
||||
|
||||
static HRESULT elo_frame_accept(const struct iobuf *dest)
|
||||
{
|
||||
uint8_t checksum;
|
||||
uint8_t calc_checksum;
|
||||
size_t i;
|
||||
|
||||
if (dest->pos < ELO_FRAME_LENGTH) {
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
/* Try to validate checksum with current buffer length
|
||||
Calculate checksum (sum of all bytes including lead + 0xAA) */
|
||||
calc_checksum = ELO_CHECKSUM_OFFSET;
|
||||
|
||||
for (i = 0; i < dest->pos - 1; i++) {
|
||||
calc_checksum += dest->bytes[i];
|
||||
}
|
||||
|
||||
calc_checksum &= 0xFF;
|
||||
|
||||
/* Check if last byte matches calculated checksum */
|
||||
checksum = dest->bytes[dest->pos - 1];
|
||||
|
||||
if (checksum != calc_checksum) {
|
||||
dprintf("Checksum missmatch: %d != %d\n", checksum, calc_checksum);
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT elo_frame_decode(struct iobuf *dest, struct iobuf *src)
|
||||
{
|
||||
uint8_t byte;
|
||||
size_t i;
|
||||
HRESULT hr;
|
||||
|
||||
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);
|
||||
|
||||
elo_frame_sync(src);
|
||||
|
||||
dest->pos = 0;
|
||||
|
||||
for (i = 0, hr = S_FALSE; i < src->pos && hr == S_FALSE; i++) {
|
||||
byte = src->bytes[i];
|
||||
|
||||
if (dest->pos >= dest->nbytes) {
|
||||
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
} else if (i == 0 && byte != ELO_FRAME_LEAD) {
|
||||
/* Invalid lead byte */
|
||||
hr = E_FAIL;
|
||||
} else {
|
||||
dest->bytes[dest->pos++] = byte;
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = elo_frame_accept(dest);
|
||||
}
|
||||
}
|
||||
|
||||
if (hr != S_FALSE) {
|
||||
memmove(&src->bytes[0], &src->bytes[i], src->pos - i);
|
||||
src->pos -= i;
|
||||
|
||||
/* If accepted, remove checksum from destination */
|
||||
if (hr == S_OK) {
|
||||
dest->pos--;
|
||||
}
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT elo_frame_encode(
|
||||
struct iobuf *dest,
|
||||
const void *ptr,
|
||||
size_t nbytes)
|
||||
{
|
||||
const uint8_t *src;
|
||||
uint8_t checksum;
|
||||
size_t i;
|
||||
|
||||
assert(dest != NULL);
|
||||
assert(dest->bytes != NULL || dest->nbytes == 0);
|
||||
assert(dest->pos <= dest->nbytes);
|
||||
assert(ptr != NULL);
|
||||
|
||||
src = ptr;
|
||||
|
||||
/* Requires exactly 10 bytes */
|
||||
if (dest->pos + ELO_FRAME_LENGTH > dest->nbytes) {
|
||||
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
}
|
||||
|
||||
/* First byte must be lead-in */
|
||||
assert(nbytes >= 1 && src[0] == ELO_FRAME_LEAD);
|
||||
|
||||
checksum = ELO_CHECKSUM_OFFSET;
|
||||
|
||||
/* Write exactly 9 bytes (lead-in + 8 data bytes) */
|
||||
for (i = 0; i < ELO_FRAME_LENGTH-1; i++) {
|
||||
uint8_t b = (i < nbytes) ? src[i] : 0x00;
|
||||
dest->bytes[dest->pos++] = b;
|
||||
checksum += b;
|
||||
}
|
||||
|
||||
/* Append checksum as 10th byte */
|
||||
dest->bytes[dest->pos++] = checksum;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
21
common/board/elo-frame.h
Normal file
21
common/board/elo-frame.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hook/iobuf.h"
|
||||
|
||||
/* SmartSet Protocol Lead-in byte */
|
||||
enum {
|
||||
ELO_FRAME_LEAD = 0x55
|
||||
};
|
||||
|
||||
struct elo_packet_hdr {
|
||||
uint8_t lead;
|
||||
uint8_t cmd;
|
||||
};
|
||||
|
||||
HRESULT elo_frame_decode(struct iobuf *dest, struct iobuf *src);
|
||||
|
||||
HRESULT elo_frame_encode(struct iobuf *dest, const void *src, size_t nbytes);
|
||||
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "util/dprintf.h"
|
||||
#include "util/dump.h"
|
||||
#include "util/fg-detect.h"
|
||||
|
||||
static void io3_transact(
|
||||
struct jvs_node *node,
|
||||
|
|
@ -146,6 +147,8 @@ static uint8_t io3_features[] = {
|
|||
0x00,
|
||||
};
|
||||
|
||||
static struct io3_switch_state prev_state = {0};
|
||||
|
||||
void io3_init(
|
||||
struct io3 *io3,
|
||||
struct jvs_node *next,
|
||||
|
|
@ -423,7 +426,13 @@ static HRESULT io3_cmd_read_switches(
|
|||
memset(&state, 0, sizeof(state));
|
||||
|
||||
if (io3->ops != NULL) {
|
||||
io3->ops->read_switches(io3->ops_ctx, &state);
|
||||
fgdet_poll();
|
||||
if (fgdet_in_foreground()) { // returns true if fgdet is not enabled
|
||||
io3->ops->read_switches(io3->ops_ctx, &state);
|
||||
memcpy(&prev_state, &state, sizeof(state));
|
||||
} else {
|
||||
state = prev_state;
|
||||
}
|
||||
}
|
||||
|
||||
hr = iobuf_write_8(resp_buf, state.system); /* Test, Tilt lines */
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "util/async.h"
|
||||
#include "util/dprintf.h"
|
||||
#include "util/fg-detect.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
|
|
@ -99,12 +100,14 @@ static struct async io4_async;
|
|||
static uint8_t io4_system_status;
|
||||
static const struct io4_ops *io4_ops;
|
||||
static void *io4_ops_ctx;
|
||||
static struct io4_state prev_state;
|
||||
|
||||
HRESULT io4_hook_init(
|
||||
const struct io4_config *cfg,
|
||||
const struct io4_ops *ops,
|
||||
void *ctx)
|
||||
{
|
||||
const struct io4_config *cfg,
|
||||
const struct io4_ops *ops,
|
||||
void *ctx,
|
||||
const wchar_t* window_name,
|
||||
const bool window_name_is_partial_match) {
|
||||
HRESULT hr;
|
||||
|
||||
assert(cfg != NULL);
|
||||
|
|
@ -122,9 +125,14 @@ HRESULT io4_hook_init(
|
|||
return hr;
|
||||
}
|
||||
|
||||
if (window_name != NULL && cfg->foreground_only) {
|
||||
fgdet_init(window_name, window_name_is_partial_match);
|
||||
}
|
||||
|
||||
io4_ops = ops;
|
||||
io4_ops_ctx = ctx;
|
||||
io4_system_status = 0x02; /* idk */
|
||||
memset(&prev_state, 0, sizeof(prev_state));
|
||||
iohook_push_handler(io4_handle_irp);
|
||||
|
||||
hr = setupapi_add_phantom_dev(&hid_guid, io4_path);
|
||||
|
|
@ -233,13 +241,21 @@ static HRESULT io4_handle_write(struct irp *irp)
|
|||
return S_OK;
|
||||
|
||||
case IO4_CMD_SET_PWM_OUTPUT:
|
||||
dprintf("USB I/O: PWM Out\n");
|
||||
// dprintf("USB I/O: PWM Out\n");
|
||||
|
||||
if (io4_ops->write_pwm != NULL) {
|
||||
return io4_ops->write_pwm(out.payload, IO4_REPORT_OUT_PAYLOAD_LEN);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
|
||||
case IO4_CMD_SET_UNIQUE_OUTPUT:
|
||||
// dprintf("USB I/O: Unique Out\n");
|
||||
|
||||
if (io4_ops->write_unique != NULL) {
|
||||
return io4_ops->write_unique(out.payload, IO4_REPORT_OUT_PAYLOAD_LEN);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
|
||||
case IO4_CMD_UPDATE_FIRMWARE:
|
||||
|
|
@ -325,11 +341,18 @@ static HRESULT io4_async_poll(void *ctx, struct irp *irp)
|
|||
|
||||
/* Call into ops to poll the underlying inputs */
|
||||
|
||||
memset(&state, 0, sizeof(state));
|
||||
hr = io4_ops->poll(io4_ops_ctx, &state);
|
||||
fgdet_poll();
|
||||
if (fgdet_in_foreground()) { // returns true if fgdet is not enabled
|
||||
memset(&state, 0, sizeof(state));
|
||||
hr = io4_ops->poll(io4_ops_ctx, &state);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
memcpy(&prev_state, &state, sizeof(state));
|
||||
} else {
|
||||
state = prev_state; // if we're unfocused, freeze the current input
|
||||
}
|
||||
|
||||
/* Construct IN report. Values are all little-endian, unlike JVS. */
|
||||
|
|
|
|||
|
|
@ -10,12 +10,13 @@
|
|||
enum {
|
||||
/* System buttons in button[0] */
|
||||
|
||||
IO4_BUTTON_TEST = 1 << 9,
|
||||
IO4_BUTTON_SERVICE = 1 << 6,
|
||||
IO4_BUTTON_TEST = 1 << 9,
|
||||
IO4_BUTTON_SERVICE = 1 << 6,
|
||||
};
|
||||
|
||||
struct io4_config {
|
||||
bool enable;
|
||||
bool foreground_only;
|
||||
};
|
||||
|
||||
struct io4_state {
|
||||
|
|
@ -26,11 +27,16 @@ struct io4_state {
|
|||
};
|
||||
|
||||
struct io4_ops {
|
||||
HRESULT (*poll)(void *ctx, struct io4_state *state);
|
||||
HRESULT (*poll)(void* ctx, struct io4_state* state);
|
||||
|
||||
HRESULT (*write_gpio)(uint8_t* payload, size_t len);
|
||||
HRESULT (*write_pwm)(uint8_t* payload, size_t len);
|
||||
HRESULT (*write_unique)(uint8_t* payload, size_t len);
|
||||
};
|
||||
|
||||
HRESULT io4_hook_init(
|
||||
const struct io4_config *cfg,
|
||||
const struct io4_ops *ops,
|
||||
void *ctx);
|
||||
const struct io4_config* cfg,
|
||||
const struct io4_ops* ops,
|
||||
void* ctx,
|
||||
const wchar_t* window_name,
|
||||
const bool window_name_is_partial_match);
|
||||
|
|
@ -71,6 +71,7 @@ static uint16_t led15070_fw_sum;
|
|||
static uint8_t led15070_host_adr = 0x01;
|
||||
|
||||
#define led15070_nboards 2
|
||||
#define led15070_nleds 32
|
||||
|
||||
typedef struct {
|
||||
CRITICAL_SECTION lock;
|
||||
|
|
@ -79,8 +80,10 @@ typedef struct {
|
|||
struct uart boarduart;
|
||||
uint8_t written_bytes[520];
|
||||
uint8_t readable_bytes[520];
|
||||
uint8_t gs[32][4];
|
||||
uint8_t dc[32][3];
|
||||
uint8_t gs[led15070_nleds][4];
|
||||
uint8_t gs_fade[led15070_nleds][4];
|
||||
bool gs_fade_pending[led15070_nleds];
|
||||
uint8_t dc[led15070_nleds][3];
|
||||
uint8_t fet[3];
|
||||
uint8_t gs_palette[8][3];
|
||||
wchar_t eeprom_path[MAX_PATH];
|
||||
|
|
@ -150,6 +153,8 @@ HRESULT led15070_hook_init(
|
|||
v->boarduart.readable.nbytes = sizeof(v->readable_bytes);
|
||||
|
||||
memset(v->gs, 0, sizeof(v->gs));
|
||||
memset(v->gs_fade, 0, sizeof(v->gs_fade));
|
||||
memset(v->gs_fade_pending, 0, sizeof(v->gs_fade_pending));
|
||||
memset(v->dc, 0, sizeof(v->dc));
|
||||
memset(v->fet, 0, sizeof(v->fet));
|
||||
memset(v->gs_palette, 0, sizeof(v->gs_palette));
|
||||
|
|
@ -239,6 +244,12 @@ static HRESULT led15070_handle_irp_locked(int board, struct irp *irp)
|
|||
}
|
||||
}
|
||||
|
||||
if (irp->op == IRP_OP_READ) {
|
||||
if (irp->ovl != NULL && boarduart->readable.pos == 0) {
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
hr = uart_handle_irp(boarduart, irp);
|
||||
|
||||
if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
|
||||
|
|
@ -454,6 +465,8 @@ static HRESULT led15070_req_set_normal_8bit(int board, const struct led15070_req
|
|||
led15070_per_board_vars[board].gs[idx][0] = req->payload[1]; // R
|
||||
led15070_per_board_vars[board].gs[idx][1] = req->payload[2]; // G
|
||||
led15070_per_board_vars[board].gs[idx][2] = req->payload[3]; // B
|
||||
led15070_per_board_vars[board].gs[idx][3] = 0;
|
||||
led15070_per_board_vars[board].gs_fade_pending[idx] = false;
|
||||
|
||||
if (!led15070_per_board_vars[board].enable_response)
|
||||
return S_OK;
|
||||
|
|
@ -473,31 +486,65 @@ static HRESULT led15070_req_set_normal_8bit(int board, const struct led15070_req
|
|||
return led15070_frame_encode(&led15070_per_board_vars[board].boarduart.readable, &resp, sizeof(resp.hdr) + resp.hdr.nbytes);
|
||||
}
|
||||
|
||||
static void led15070_calc_range(
|
||||
uint8_t start,
|
||||
uint8_t count,
|
||||
uint8_t skip,
|
||||
uint8_t *out_start,
|
||||
uint8_t *out_end)
|
||||
{
|
||||
uint16_t s = start;
|
||||
uint16_t c = count;
|
||||
|
||||
if (c == 0) {
|
||||
*out_start = 0;
|
||||
*out_end = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (c >= led15070_nleds) {
|
||||
c = led15070_nleds;
|
||||
}
|
||||
|
||||
if (skip > 0 && skip <= c) {
|
||||
s += skip;
|
||||
c -= skip;
|
||||
}
|
||||
|
||||
if (s >= led15070_nleds || c == 0) {
|
||||
*out_start = led15070_nleds;
|
||||
*out_end = led15070_nleds;
|
||||
return;
|
||||
}
|
||||
|
||||
*out_start = (uint8_t) s;
|
||||
*out_end = (s + c > led15070_nleds) ? led15070_nleds : (uint8_t) (s + c);
|
||||
}
|
||||
|
||||
static HRESULT led15070_req_set_multi_flash_8bit(int board, const struct led15070_req_any *req)
|
||||
{
|
||||
uint8_t idx_start = req->payload[0];
|
||||
uint8_t idx_end = req->payload[1];
|
||||
uint8_t idx_count = req->payload[1];
|
||||
uint8_t idx_skip = req->payload[2];
|
||||
uint8_t start;
|
||||
uint8_t end;
|
||||
|
||||
// TODO: useful?
|
||||
#if defined(LOG_LED15070)
|
||||
dprintf("LED 15070: Set LED - Multi flash 8bit (board %u, start %u, end %u, skip %u)\n",
|
||||
board, idx_start, idx_end, idx_skip);
|
||||
dprintf("LED 15070: Set LED - Multi flash 8bit (board %u, start %u, count %u, skip %u)\n",
|
||||
board, idx_start, idx_count, idx_skip);
|
||||
#endif
|
||||
|
||||
if (idx_skip > 0 && idx_skip <= (idx_end - idx_start + 1)) {
|
||||
idx_start += idx_skip;
|
||||
}
|
||||
led15070_calc_range(idx_start, idx_count, idx_skip, &start, &end);
|
||||
|
||||
int i = idx_start;
|
||||
do {
|
||||
for (int i = start; i < end; i++) {
|
||||
led15070_per_board_vars[board].gs[i][0] = req->payload[3]; // R
|
||||
led15070_per_board_vars[board].gs[i][1] = req->payload[4]; // G
|
||||
led15070_per_board_vars[board].gs[i][2] = req->payload[5]; // B
|
||||
/* Always 0, tells the controller to immediately change to this color */
|
||||
led15070_per_board_vars[board].gs[i][3] = req->payload[6]; // Speed
|
||||
i++;
|
||||
} while (i < idx_end);
|
||||
led15070_per_board_vars[board].gs_fade_pending[i] = false;
|
||||
}
|
||||
|
||||
if (!led15070_per_board_vars[board].enable_response)
|
||||
return S_OK;
|
||||
|
|
@ -520,25 +567,24 @@ static HRESULT led15070_req_set_multi_flash_8bit(int board, const struct led1507
|
|||
static HRESULT led15070_req_set_multi_fade_8bit(int board, const struct led15070_req_any *req)
|
||||
{
|
||||
uint8_t idx_start = req->payload[0];
|
||||
uint8_t idx_end = req->payload[1];
|
||||
uint8_t idx_count = req->payload[1];
|
||||
uint8_t idx_skip = req->payload[2];
|
||||
uint8_t start;
|
||||
uint8_t end;
|
||||
#if defined(LOG_LED15070)
|
||||
dprintf("LED 15070: Set LED - Multi fade 8bit (board %u, start %u, end %u, skip %u)\n",
|
||||
board, idx_start, idx_end, idx_skip);
|
||||
dprintf("LED 15070: Set LED - Multi fade 8bit (board %u, start %u, count %u, skip %u)\n",
|
||||
board, idx_start, idx_count, idx_skip);
|
||||
#endif
|
||||
|
||||
if (idx_skip > 0 && idx_skip <= (idx_end - idx_start + 1)) {
|
||||
idx_start += idx_skip;
|
||||
}
|
||||
led15070_calc_range(idx_start, idx_count, idx_skip, &start, &end);
|
||||
|
||||
int i = idx_start;
|
||||
do {
|
||||
led15070_per_board_vars[board].gs[i][0] = req->payload[3]; // R
|
||||
led15070_per_board_vars[board].gs[i][1] = req->payload[4]; // G
|
||||
led15070_per_board_vars[board].gs[i][2] = req->payload[5]; // B
|
||||
led15070_per_board_vars[board].gs[i][3] = req->payload[6]; // Speed
|
||||
i++;
|
||||
} while (i < idx_end);
|
||||
for (int i = start; i < end; i++) {
|
||||
led15070_per_board_vars[board].gs_fade[i][0] = req->payload[3]; // R
|
||||
led15070_per_board_vars[board].gs_fade[i][1] = req->payload[4]; // G
|
||||
led15070_per_board_vars[board].gs_fade[i][2] = req->payload[5]; // B
|
||||
led15070_per_board_vars[board].gs_fade[i][3] = req->payload[6]; // Speed
|
||||
led15070_per_board_vars[board].gs_fade_pending[i] = true;
|
||||
}
|
||||
|
||||
if (!led15070_per_board_vars[board].enable_response)
|
||||
return S_OK;
|
||||
|
|
@ -767,12 +813,56 @@ static HRESULT led15070_req_dc_update(int board, const struct led15070_req_any *
|
|||
|
||||
static HRESULT led15070_req_gs_update(int board, const struct led15070_req_any *req)
|
||||
{
|
||||
_led15070_per_board_vars *v = &led15070_per_board_vars[board];
|
||||
#if defined(LOG_LED15070)
|
||||
dprintf("LED 15070: GS update (board %u)\n", board);
|
||||
#endif
|
||||
|
||||
if (led_gs_update)
|
||||
led_gs_update(board, (const uint8_t*)led15070_per_board_vars[board].gs);
|
||||
if (led_gs_update) {
|
||||
bool has_fade = false;
|
||||
uint8_t payload[led15070_nleds][4];
|
||||
|
||||
for (int i = 0; i < led15070_nleds; i++) {
|
||||
if (v->gs_fade_pending[i]) {
|
||||
has_fade = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_fade) {
|
||||
for (int i = 0; i < led15070_nleds; i++) {
|
||||
payload[i][0] = v->gs[i][0];
|
||||
payload[i][1] = v->gs[i][1];
|
||||
payload[i][2] = v->gs[i][2];
|
||||
payload[i][3] = 0;
|
||||
}
|
||||
|
||||
led_gs_update(board, (const uint8_t*)payload);
|
||||
|
||||
for (int i = 0; i < led15070_nleds; i++) {
|
||||
if (v->gs_fade_pending[i]) {
|
||||
payload[i][0] = v->gs_fade[i][0];
|
||||
payload[i][1] = v->gs_fade[i][1];
|
||||
payload[i][2] = v->gs_fade[i][2];
|
||||
payload[i][3] = v->gs_fade[i][3];
|
||||
v->gs_fade_pending[i] = false;
|
||||
} else {
|
||||
payload[i][0] = v->gs[i][0];
|
||||
payload[i][1] = v->gs[i][1];
|
||||
payload[i][2] = v->gs[i][2];
|
||||
payload[i][3] = v->gs[i][3];
|
||||
}
|
||||
}
|
||||
|
||||
led_gs_update(board, (const uint8_t*)payload);
|
||||
} else {
|
||||
led_gs_update(board, (const uint8_t*)v->gs);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < led15070_nleds; i++) {
|
||||
v->gs_fade_pending[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!led15070_per_board_vars[board].enable_response)
|
||||
return S_OK;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@ board_lib = static_library(
|
|||
'aime-dll.h',
|
||||
'config.c',
|
||||
'config.h',
|
||||
'elo-cmd.h',
|
||||
'elo-frame.c',
|
||||
'elo-frame.h',
|
||||
'guid.c',
|
||||
'guid.h',
|
||||
'io3.c',
|
||||
|
|
@ -41,6 +44,8 @@ board_lib = static_library(
|
|||
'sg-nfc-cmd.h',
|
||||
'sg-reader.c',
|
||||
'sg-reader.h',
|
||||
'sg-reader-queue.c',
|
||||
'sg-reader-queue.h',
|
||||
'slider-cmd.h',
|
||||
'slider-frame.c',
|
||||
'slider-frame.h',
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
#include "board/sg-nfc.h"
|
||||
#include "board/sg-nfc-cmd.h"
|
||||
|
||||
#include "aimeio/aimeio.h"
|
||||
|
||||
#include "iccard/aime.h"
|
||||
#include "iccard/felica.h"
|
||||
|
||||
|
|
@ -57,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,
|
||||
|
|
@ -195,19 +229,49 @@ static HRESULT sg_nfc_dispatch(
|
|||
&req->felica_encap,
|
||||
&res->felica_encap);
|
||||
|
||||
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);
|
||||
|
||||
|
|
@ -300,7 +364,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 */
|
||||
|
|
@ -317,12 +383,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(0x8FBECBFF);
|
||||
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 */
|
||||
|
||||
|
|
@ -372,11 +456,182 @@ static HRESULT sg_nfc_poll_felica(
|
|||
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)) {
|
||||
|
|
@ -385,10 +640,30 @@ 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 (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");
|
||||
|
||||
|
|
@ -455,6 +730,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
|
||||
|
|
@ -472,6 +748,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;
|
||||
|
|
@ -507,14 +809,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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
208
common/board/sg-reader-queue.c
Normal file
208
common/board/sg-reader-queue.c
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "board/aime-dll.h"
|
||||
#include "board/sg-led.h"
|
||||
#include "board/sg-nfc.h"
|
||||
#include "board/sg-reader.h"
|
||||
#include "board/sg-reader-queue.h"
|
||||
|
||||
#include "hook/iohook.h"
|
||||
|
||||
#include "hooklib/uart.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
#include "util/dump.h"
|
||||
|
||||
static HRESULT sg_reader_handle_irp(struct irp *irp);
|
||||
static HRESULT sg_reader_handle_irp_locked(struct irp *irp);
|
||||
static HRESULT sg_reader_nfc_poll(void *ctx);
|
||||
static HRESULT sg_reader_nfc_get_aime_id(
|
||||
void *ctx,
|
||||
uint8_t *luid,
|
||||
size_t luid_size);
|
||||
static HRESULT sg_reader_nfc_get_felica_id(void *ctx, uint64_t *IDm);
|
||||
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,
|
||||
};
|
||||
|
||||
static const struct sg_led_ops sg_reader_led_ops = {
|
||||
.set_color = sg_reader_led_set_color,
|
||||
};
|
||||
|
||||
static CRITICAL_SECTION sg_reader_lock;
|
||||
static bool sg_reader_started;
|
||||
static HRESULT sg_reader_start_hr;
|
||||
static struct uart sg_reader_uart;
|
||||
static uint8_t sg_reader_written_bytes[520];
|
||||
static uint8_t sg_reader_readable_bytes[520];
|
||||
static struct sg_nfc sg_reader_nfc;
|
||||
static struct sg_led sg_reader_led;
|
||||
|
||||
HRESULT sg_reader_queue_hook_init(
|
||||
const struct aime_config *cfg,
|
||||
unsigned int default_port_no,
|
||||
unsigned int gen,
|
||||
HINSTANCE self)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
assert(cfg != NULL);
|
||||
assert(self != NULL);
|
||||
|
||||
if (!cfg->enable) {
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
hr = aime_dll_init(&cfg->dll, self);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (gen < 1 || gen > 3) {
|
||||
dprintf("NFC Assembly (Queue): Invalid reader generation: %u\n", gen);
|
||||
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
sg_nfc_init(&sg_reader_nfc, 0x01, &sg_reader_nfc_ops, gen, cfg->proxy_flag, cfg->authdata_path, NULL);
|
||||
sg_led_init(&sg_reader_led, 0x08, &sg_reader_led_ops, gen, NULL);
|
||||
|
||||
InitializeCriticalSection(&sg_reader_lock);
|
||||
|
||||
if (!cfg->high_baudrate) {
|
||||
sg_reader_uart.baud.BaudRate = 38400;
|
||||
}
|
||||
|
||||
dprintf("NFC Assembly (Queue): 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);
|
||||
sg_reader_uart.readable.bytes = sg_reader_readable_bytes;
|
||||
sg_reader_uart.readable.nbytes = sizeof(sg_reader_readable_bytes);
|
||||
|
||||
return iohook_push_handler(sg_reader_handle_irp);
|
||||
}
|
||||
|
||||
static HRESULT sg_reader_handle_irp(struct irp *irp)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
assert(irp != NULL);
|
||||
|
||||
if (!uart_match_irp(&sg_reader_uart, irp)) {
|
||||
return iohook_invoke_next(irp);
|
||||
}
|
||||
|
||||
EnterCriticalSection(&sg_reader_lock);
|
||||
hr = sg_reader_handle_irp_locked(irp);
|
||||
LeaveCriticalSection(&sg_reader_lock);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT sg_reader_handle_irp_locked(struct irp *irp)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
#if defined(LOG_NFC)
|
||||
if (irp->op == IRP_OP_WRITE) {
|
||||
dprintf("WRITE:\n");
|
||||
dump_const_iobuf(&irp->write);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(LOG_NFC)
|
||||
if (irp->op == IRP_OP_READ) {
|
||||
dprintf("READ:\n");
|
||||
dump_iobuf(&sg_reader_uart.readable);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (irp->op == IRP_OP_OPEN) {
|
||||
/* Unfortunately the card reader UART gets opened and closed
|
||||
repeatedly */
|
||||
|
||||
if (!sg_reader_started) {
|
||||
dprintf("NFC Assembly (Queue): Starting backend DLL\n");
|
||||
hr = aime_dll.init();
|
||||
|
||||
sg_reader_started = true;
|
||||
sg_reader_start_hr = hr;
|
||||
|
||||
if (FAILED(hr)) {
|
||||
dprintf("NFC Assembly (Queue): Backend error: %x\n", (int) hr);
|
||||
|
||||
return hr;
|
||||
}
|
||||
} else {
|
||||
hr = sg_reader_start_hr;
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hr = uart_handle_irp(&sg_reader_uart, irp);
|
||||
|
||||
if (FAILED(hr) || irp->op != IRP_OP_WRITE) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
sg_nfc_transact(
|
||||
&sg_reader_nfc,
|
||||
&sg_reader_uart.readable,
|
||||
sg_reader_uart.written.bytes,
|
||||
sg_reader_uart.written.pos);
|
||||
|
||||
sg_led_transact(
|
||||
&sg_reader_led,
|
||||
&sg_reader_uart.readable,
|
||||
sg_reader_uart.written.bytes,
|
||||
sg_reader_uart.written.pos);
|
||||
|
||||
sg_reader_uart.written.pos = 0;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT sg_reader_nfc_poll(void *ctx)
|
||||
{
|
||||
return aime_dll.nfc_poll(1);
|
||||
}
|
||||
|
||||
static HRESULT sg_reader_nfc_get_aime_id(
|
||||
void *ctx,
|
||||
uint8_t *luid,
|
||||
size_t luid_size)
|
||||
{
|
||||
return aime_dll.nfc_get_aime_id(1, luid, luid_size);
|
||||
}
|
||||
|
||||
static HRESULT sg_reader_nfc_get_felica_id(void *ctx, uint64_t *IDm)
|
||||
{
|
||||
return aime_dll.nfc_get_felica_id(1, IDm);
|
||||
}
|
||||
|
||||
static void sg_reader_led_set_color(void *ctx, uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
aime_dll.led_set_color(1, r, g, b);
|
||||
}
|
||||
14
common/board/sg-reader-queue.h
Normal file
14
common/board/sg-reader-queue.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "board/aime-dll.h"
|
||||
#include "board/sg-reader.h"
|
||||
|
||||
HRESULT sg_reader_queue_hook_init(
|
||||
const struct aime_config *cfg,
|
||||
unsigned int default_port_no,
|
||||
unsigned int gen,
|
||||
HINSTANCE self);
|
||||
|
|
@ -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 = {
|
||||
|
|
@ -201,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);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "board/vfd-frame.h"
|
||||
|
||||
enum {
|
||||
VFD_CMD_WRITE_STATIC = 0x00,
|
||||
VFD_CMD_GET_VERSION = 0x5B,
|
||||
VFD_CMD_RESET = 0x0B,
|
||||
VFD_CMD_CLEAR_SCREEN = 0x0C,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "board/config.h"
|
||||
#include "board/aime-dll.h"
|
||||
#include "board/vfd.h"
|
||||
#include "board/vfd-cmd.h"
|
||||
|
||||
|
|
@ -22,6 +23,7 @@
|
|||
#include "util/dump.h"
|
||||
|
||||
#define SUPER_VERBOSE 0
|
||||
#define VFD_BRIGHTNESS_MAX 4
|
||||
|
||||
static HRESULT vfd_handle_irp(struct irp *irp);
|
||||
|
||||
|
|
@ -29,7 +31,7 @@ static struct uart vfd_uart;
|
|||
static uint8_t vfd_written[4096];
|
||||
static uint8_t vfd_readable[4096];
|
||||
|
||||
static int encoding = VFD_ENC_SHIFT_JIS;
|
||||
static struct aime_io_vfd_state vfd_state;
|
||||
|
||||
HRESULT vfd_handle_get_version(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
|
||||
HRESULT vfd_handle_reset(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart);
|
||||
|
|
@ -51,6 +53,13 @@ HRESULT vfd_handle_create_char2(struct const_iobuf* reader, struct iobuf* writer
|
|||
|
||||
static bool utf_enabled;
|
||||
|
||||
static void vfd_publish_state(void)
|
||||
{
|
||||
if (aime_dll.vfd_set_state != NULL) {
|
||||
aime_dll.vfd_set_state(&vfd_state);
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT vfd_hook_init(struct vfd_config *cfg, unsigned int default_port_no)
|
||||
{
|
||||
if (!cfg->enable){
|
||||
|
|
@ -58,6 +67,9 @@ HRESULT vfd_hook_init(struct vfd_config *cfg, unsigned int default_port_no)
|
|||
}
|
||||
|
||||
utf_enabled = cfg->utf_conversion;
|
||||
memset(&vfd_state, 0, sizeof(vfd_state));
|
||||
vfd_state.encoding = VFD_ENC_SHIFT_JIS;
|
||||
vfd_publish_state();
|
||||
|
||||
unsigned int port_no = cfg->port_no;
|
||||
if (port_no == 0){
|
||||
|
|
@ -93,13 +105,13 @@ void print_vfd_text(const char* str, int len){
|
|||
memset(encoded, 0, 1024 * sizeof(wchar_t));
|
||||
|
||||
int codepage = 0;
|
||||
if (encoding == VFD_ENC_GB2312){
|
||||
if (vfd_state.encoding == VFD_ENC_GB2312){
|
||||
codepage = 936;
|
||||
} else if (encoding == VFD_ENC_BIG5){
|
||||
} else if (vfd_state.encoding == VFD_ENC_BIG5){
|
||||
codepage = 950;
|
||||
} else if (encoding == VFD_ENC_SHIFT_JIS){
|
||||
} else if (vfd_state.encoding == VFD_ENC_SHIFT_JIS){
|
||||
codepage = 932;
|
||||
} else if (encoding == VFD_ENC_KSC5601) {
|
||||
} else if (vfd_state.encoding == VFD_ENC_KSC5601) {
|
||||
codepage = 949;
|
||||
}
|
||||
|
||||
|
|
@ -114,6 +126,37 @@ void print_vfd_text(const char* str, int len){
|
|||
dprintf("VFD: Text: %s\n", str);
|
||||
|
||||
}
|
||||
|
||||
if (aime_dll.vfd_set_text != NULL) {
|
||||
aime_dll.vfd_set_text((const uint8_t *) str, len, &vfd_state);
|
||||
}
|
||||
}
|
||||
|
||||
static void vfd_read_text_until_sync(struct const_iobuf *reader)
|
||||
{
|
||||
int len;
|
||||
|
||||
if (reader->pos >= reader->nbytes) {
|
||||
return;
|
||||
}
|
||||
|
||||
len = 0;
|
||||
while (reader->pos + len < reader->nbytes &&
|
||||
reader->bytes[reader->pos + len] != VFD_SYNC_BYTE &&
|
||||
reader->bytes[reader->pos + len] != VFD_SYNC_BYTE2) {
|
||||
len++;
|
||||
}
|
||||
|
||||
if (len <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
char *str = malloc((size_t) len + 1);
|
||||
memset(str, 0, (size_t) len + 1);
|
||||
iobuf_read(reader, str, len);
|
||||
str[len] = '\0';
|
||||
print_vfd_text(str, len);
|
||||
free(str);
|
||||
}
|
||||
|
||||
static HRESULT vfd_handle_irp(struct irp *irp)
|
||||
|
|
@ -178,6 +221,10 @@ static HRESULT vfd_handle_irp(struct irp *irp)
|
|||
hr = vfd_handle_set_text_wnd(&reader, writer, &vfd_uart);
|
||||
} else if (cmd == VFD_CMD_SET_TEXT_SPEED) {
|
||||
hr = vfd_handle_set_text_speed(&reader, writer, &vfd_uart);
|
||||
} else if (cmd == VFD_CMD_WRITE_STATIC) {
|
||||
dprintf("VFD: Write Static Text\n");
|
||||
vfd_read_text_until_sync(&reader);
|
||||
hr = S_FALSE;
|
||||
} else if (cmd == VFD_CMD_WRITE_TEXT) {
|
||||
hr = vfd_handle_write_text(&reader, writer, &vfd_uart);
|
||||
} else if (cmd == VFD_CMD_ENABLE_SCROLL) {
|
||||
|
|
@ -199,22 +246,7 @@ static HRESULT vfd_handle_irp(struct irp *irp)
|
|||
|
||||
// if no sync byte is sent, we are just getting plain text...
|
||||
|
||||
if (reader.pos < reader.nbytes){
|
||||
int len = 0;
|
||||
|
||||
// read chars until we hit a new sync byte or the data ends
|
||||
while (reader.pos + len + 1 < reader.nbytes && reader.bytes[reader.pos + len] != VFD_SYNC_BYTE && reader.bytes[reader.pos + len] != VFD_SYNC_BYTE2){
|
||||
len++;
|
||||
}
|
||||
|
||||
char* str = malloc(len);
|
||||
memset(str, 0, len);
|
||||
iobuf_read(&reader, str, len);
|
||||
print_vfd_text(str, len);
|
||||
free(str);
|
||||
|
||||
reader.pos += len;
|
||||
}
|
||||
vfd_read_text_until_sync(&reader);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -230,7 +262,16 @@ static HRESULT vfd_handle_irp(struct irp *irp)
|
|||
}
|
||||
|
||||
HRESULT vfd_handle_get_version(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
|
||||
dprintf("VFD: Get Version\n");
|
||||
uint8_t subcmd;
|
||||
|
||||
if (reader->pos < reader->nbytes &&
|
||||
reader->bytes[reader->pos] != VFD_SYNC_BYTE &&
|
||||
reader->bytes[reader->pos] != VFD_SYNC_BYTE2) {
|
||||
iobuf_read_8(reader, &subcmd);
|
||||
dprintf("VFD: Get Version (0x%02x)\n", subcmd);
|
||||
} else {
|
||||
dprintf("VFD: Get Version\n");
|
||||
}
|
||||
|
||||
struct vfd_resp_board_info resp;
|
||||
|
||||
|
|
@ -244,12 +285,39 @@ HRESULT vfd_handle_get_version(struct const_iobuf* reader, struct iobuf* writer,
|
|||
HRESULT vfd_handle_reset(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
|
||||
dprintf("VFD: Reset\n");
|
||||
|
||||
encoding = VFD_ENC_SHIFT_JIS;
|
||||
memset(&vfd_state, 0, sizeof(vfd_state));
|
||||
vfd_state.encoding = VFD_ENC_SHIFT_JIS;
|
||||
vfd_publish_state();
|
||||
|
||||
return S_FALSE;
|
||||
}
|
||||
HRESULT vfd_handle_clear_screen(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
|
||||
if (reader->pos + 1 <= reader->nbytes) {
|
||||
uint8_t next = reader->bytes[reader->pos];
|
||||
bool next_is_sync = (next == VFD_SYNC_BYTE || next == VFD_SYNC_BYTE2);
|
||||
|
||||
if (!next_is_sync && next <= VFD_BRIGHTNESS_MAX) {
|
||||
bool end_or_sync = (reader->pos + 1 >= reader->nbytes);
|
||||
|
||||
if (!end_or_sync) {
|
||||
uint8_t follow = reader->bytes[reader->pos + 1];
|
||||
end_or_sync = (follow == VFD_SYNC_BYTE || follow == VFD_SYNC_BYTE2);
|
||||
}
|
||||
|
||||
if (end_or_sync) {
|
||||
uint8_t b;
|
||||
iobuf_read_8(reader, &b);
|
||||
dprintf("VFD: Brightness (compat), %d\n", b);
|
||||
vfd_state.brightness = b;
|
||||
vfd_publish_state();
|
||||
return S_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dprintf("VFD: Clear Screen\n");
|
||||
vfd_state.clear_seq++;
|
||||
vfd_publish_state();
|
||||
|
||||
return S_FALSE;
|
||||
}
|
||||
|
|
@ -257,12 +325,14 @@ HRESULT vfd_handle_set_brightness(struct const_iobuf* reader, struct iobuf* writ
|
|||
uint8_t b;
|
||||
iobuf_read_8(reader, &b);
|
||||
|
||||
if (b > 4){
|
||||
if (b > VFD_BRIGHTNESS_MAX){
|
||||
dprintf("VFD: Brightness, invalid argument\n");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
dprintf("VFD: Brightness, %d\n", b);
|
||||
vfd_state.brightness = b;
|
||||
vfd_publish_state();
|
||||
|
||||
return S_FALSE;
|
||||
}
|
||||
|
|
@ -276,30 +346,49 @@ HRESULT vfd_handle_set_screen_on(struct const_iobuf* reader, struct iobuf* write
|
|||
}
|
||||
|
||||
dprintf("VFD: Screen Power, %d\n", b);
|
||||
vfd_state.screen_on = b;
|
||||
vfd_publish_state();
|
||||
return S_FALSE;
|
||||
}
|
||||
HRESULT vfd_handle_set_h_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
|
||||
uint8_t x;
|
||||
iobuf_read_8(reader, &x);
|
||||
uint16_t x;
|
||||
iobuf_read_be16(reader, &x);
|
||||
|
||||
dprintf("VFD: Horizontal Scroll, X=%d\n", x);
|
||||
vfd_state.h_scroll = x;
|
||||
vfd_publish_state();
|
||||
return S_FALSE;
|
||||
}
|
||||
HRESULT vfd_handle_draw_image(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
|
||||
int w, h;
|
||||
uint16_t x0, x1;
|
||||
uint16_t x0;
|
||||
uint16_t w;
|
||||
uint16_t h_lines;
|
||||
uint16_t h_pixels;
|
||||
uint8_t y0, y1;
|
||||
uint8_t image[2048];
|
||||
size_t payload;
|
||||
size_t remaining;
|
||||
|
||||
iobuf_read_be16(reader, &x0);
|
||||
iobuf_read_8(reader, &y0);
|
||||
iobuf_read_be16(reader, &x1);
|
||||
iobuf_read_be16(reader, &w);
|
||||
iobuf_read_8(reader, &y1);
|
||||
w = x1 - x0;
|
||||
h = y1 - y0;
|
||||
iobuf_read(reader, image, w*h);
|
||||
|
||||
dprintf("VFD: Draw image, %dx%d\n", w, h);
|
||||
if (y1 >= y0) {
|
||||
h_lines = (uint16_t) (y1 - y0 + 1);
|
||||
} else {
|
||||
h_lines = 0;
|
||||
}
|
||||
|
||||
h_pixels = (uint16_t) (h_lines * 8);
|
||||
dprintf("VFD: Draw image, %dx%d @%d,%d\n", w, h_pixels, x0, y0);
|
||||
|
||||
payload = (size_t) w * (size_t) h_pixels;
|
||||
remaining = reader->nbytes - reader->pos;
|
||||
if (payload > remaining) {
|
||||
payload = remaining;
|
||||
}
|
||||
|
||||
reader->pos += payload;
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -311,6 +400,9 @@ HRESULT vfd_handle_set_cursor(struct const_iobuf* reader, struct iobuf* writer,
|
|||
iobuf_read_8(reader, &y);
|
||||
|
||||
dprintf("VFD: Set Cursor, x=%d,y=%d\n", x, y);
|
||||
vfd_state.cursor_x = x;
|
||||
vfd_state.cursor_y = y;
|
||||
vfd_publish_state();
|
||||
|
||||
return S_FALSE;
|
||||
}
|
||||
|
|
@ -326,20 +418,31 @@ HRESULT vfd_handle_set_encoding(struct const_iobuf* reader, struct iobuf* writer
|
|||
return E_FAIL;
|
||||
}
|
||||
|
||||
encoding = b;
|
||||
vfd_state.encoding = b;
|
||||
vfd_publish_state();
|
||||
|
||||
return S_FALSE;
|
||||
}
|
||||
HRESULT vfd_handle_set_text_wnd(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
|
||||
uint16_t x0, x1;
|
||||
uint8_t y0, y1;
|
||||
uint16_t x0, w;
|
||||
uint8_t y0, h;
|
||||
uint16_t x1;
|
||||
uint8_t y1;
|
||||
|
||||
iobuf_read_be16(reader, &x0);
|
||||
iobuf_read_8(reader, &y0);
|
||||
iobuf_read_be16(reader, &x1);
|
||||
iobuf_read_8(reader, &y1);
|
||||
iobuf_read_be16(reader, &w);
|
||||
iobuf_read_8(reader, &h);
|
||||
|
||||
dprintf("VFD: Set Text Window, p0:%d,%d, p1:%d,%d\n", x0, y0, x1, y1);
|
||||
x1 = (uint16_t) (x0 + w);
|
||||
y1 = (uint8_t) (y0 + h);
|
||||
|
||||
dprintf("VFD: Set Text Window, x=%d,y=%d,w=%d,h=%d\n", x0, y0, w, h);
|
||||
vfd_state.wnd_x0 = x0;
|
||||
vfd_state.wnd_y0 = y0;
|
||||
vfd_state.wnd_x1 = x1;
|
||||
vfd_state.wnd_y1 = y1;
|
||||
vfd_publish_state();
|
||||
return S_FALSE;
|
||||
}
|
||||
HRESULT vfd_handle_set_text_speed(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
|
||||
|
|
@ -347,14 +450,17 @@ HRESULT vfd_handle_set_text_speed(struct const_iobuf* reader, struct iobuf* writ
|
|||
iobuf_read_8(reader, &b);
|
||||
|
||||
dprintf("VFD: Set Text Speed, %d\n", b);
|
||||
vfd_state.text_speed = b;
|
||||
vfd_publish_state();
|
||||
return S_FALSE;
|
||||
}
|
||||
HRESULT vfd_handle_write_text(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
|
||||
uint8_t len;
|
||||
iobuf_read_8(reader, &len);
|
||||
|
||||
char* str = malloc(len);
|
||||
char* str = malloc((size_t) len + 1);
|
||||
iobuf_read(reader, str, len);
|
||||
str[len] = '\0';
|
||||
|
||||
print_vfd_text(str, len);
|
||||
free(str);
|
||||
|
|
@ -363,10 +469,14 @@ HRESULT vfd_handle_write_text(struct const_iobuf* reader, struct iobuf* writer,
|
|||
}
|
||||
HRESULT vfd_handle_enable_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
|
||||
dprintf("VFD: Enable Scrolling\n");
|
||||
vfd_state.scroll_enabled = 1;
|
||||
vfd_publish_state();
|
||||
return S_FALSE;
|
||||
}
|
||||
HRESULT vfd_handle_disable_scroll(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
|
||||
dprintf("VFD: Disable Scrolling\n");
|
||||
vfd_state.scroll_enabled = 0;
|
||||
vfd_publish_state();
|
||||
return S_FALSE;
|
||||
}
|
||||
HRESULT vfd_handle_rotate(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
|
||||
|
|
@ -374,6 +484,8 @@ HRESULT vfd_handle_rotate(struct const_iobuf* reader, struct iobuf* writer, stru
|
|||
iobuf_read_8(reader, &b);
|
||||
|
||||
dprintf("VFD: Rotate, %d\n", b);
|
||||
vfd_state.rotate = b;
|
||||
vfd_publish_state();
|
||||
return S_FALSE;
|
||||
}
|
||||
HRESULT vfd_handle_create_char(struct const_iobuf* reader, struct iobuf* writer, struct uart* vfd_uart){
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "hooklib/config.h"
|
||||
#include "hooklib/dvd.h"
|
||||
#include "hooklib/y3.h"
|
||||
#include "hooklib/y3-dll.h"
|
||||
|
||||
void dvd_config_load(struct dvd_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
|
|
@ -26,7 +28,7 @@ void touch_screen_config_load(struct touch_screen_config *cfg, const wchar_t *fi
|
|||
cfg->cursor = GetPrivateProfileIntW(L"touch", L"cursor", 1, filename);
|
||||
}
|
||||
|
||||
void printer_config_load(struct printer_config *cfg, const wchar_t *filename)
|
||||
void printer_chc_config_load(struct printer_chc_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
|
@ -84,3 +86,161 @@ void printer_config_load(struct printer_config *cfg, const wchar_t *filename)
|
|||
|
||||
cfg->wait_time = GetPrivateProfileIntW(L"printer", L"waitTime", 0, filename);
|
||||
}
|
||||
|
||||
void printer_cx_config_load(struct printer_cx_config *cfg, const wchar_t *filename){
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
char filenameA[MAX_PATH];
|
||||
|
||||
size_t n = wcstombs(filenameA, filename, MAX_PATH);
|
||||
for (int i = n; i < MAX_PATH; i++)
|
||||
{
|
||||
filenameA[i] = '\0';
|
||||
}
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"printer", L"enable", 1, filename);
|
||||
|
||||
GetPrivateProfileStringA(
|
||||
"printer",
|
||||
"firmwareVersion",
|
||||
"V04-03B",
|
||||
cfg->printer_firm_version,
|
||||
_countof(cfg->printer_firm_version),
|
||||
filenameA);
|
||||
|
||||
GetPrivateProfileStringA(
|
||||
"printer",
|
||||
"configVersion",
|
||||
"V01-75",
|
||||
cfg->printer_config_version,
|
||||
_countof(cfg->printer_config_version),
|
||||
filenameA);
|
||||
|
||||
GetPrivateProfileStringA(
|
||||
"printer",
|
||||
"tableVersion",
|
||||
"V01-E0",
|
||||
cfg->printer_table_version,
|
||||
_countof(cfg->printer_table_version),
|
||||
filenameA);
|
||||
|
||||
GetPrivateProfileStringA(
|
||||
"printer",
|
||||
"cameraVersion",
|
||||
"00.19",
|
||||
cfg->printer_camera_version,
|
||||
_countof(cfg->printer_camera_version),
|
||||
filenameA);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"printer",
|
||||
L"printerOutPath",
|
||||
L"DEVICE\\print",
|
||||
cfg->printer_out_path,
|
||||
_countof(cfg->printer_out_path),
|
||||
filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"printer",
|
||||
L"printerDataPath",
|
||||
L"DEVICE\\cx7000_data.bin",
|
||||
cfg->printer_data_path,
|
||||
_countof(cfg->printer_data_path),
|
||||
filename);
|
||||
|
||||
}
|
||||
|
||||
void y3_dll_config_load(
|
||||
struct y3_dll_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"y3io",
|
||||
L"path",
|
||||
L"",
|
||||
cfg->path,
|
||||
_countof(cfg->path),
|
||||
filename);
|
||||
}
|
||||
|
||||
void y3_config_load(
|
||||
struct y3_config *cfg,
|
||||
const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
wchar_t tmpstr[5];
|
||||
|
||||
memset(cfg->firm_name_field, ' ', sizeof(cfg->firm_name_field) - 1);
|
||||
cfg->firm_name_field[sizeof(cfg->firm_name_field) - 1] = '\0';
|
||||
|
||||
memset(cfg->firm_name_printer, ' ', sizeof(cfg->firm_name_printer) - 1);
|
||||
cfg->firm_name_printer[sizeof(cfg->firm_name_printer) - 1] = '\0';
|
||||
|
||||
memset(cfg->target_code_field, ' ', sizeof(cfg->target_code_field) - 1);
|
||||
cfg->target_code_field[sizeof(cfg->target_code_field) - 1] = '\0';
|
||||
|
||||
memset(cfg->target_code_printer, ' ', sizeof(cfg->target_code_printer) - 1);
|
||||
cfg->target_code_printer[sizeof(cfg->target_code_printer) - 1] = '\0';
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"flatPanelReader", L"enable", 1, filename);
|
||||
cfg->port_field = GetPrivateProfileIntW(L"flatPanelReader", L"port_field", 10, filename);
|
||||
cfg->port_printer = GetPrivateProfileIntW(L"flatPanelReader", L"port_printer", 11, filename);
|
||||
|
||||
cfg->dll_version = (float)GetPrivateProfileIntW(
|
||||
L"flatPanelReader",
|
||||
L"dllVersion",
|
||||
1,
|
||||
filename);
|
||||
|
||||
cfg->firm_version = (float)GetPrivateProfileIntW(
|
||||
L"flatPanelReader",
|
||||
L"firmVersion",
|
||||
1,
|
||||
filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"flatPanelReader",
|
||||
L"firmNameField",
|
||||
L"SFPR",
|
||||
tmpstr,
|
||||
_countof(tmpstr),
|
||||
filename);
|
||||
|
||||
wcstombs(cfg->firm_name_field, tmpstr, sizeof(cfg->firm_name_field) - 1);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"flatPanelReader",
|
||||
L"firmNamePrinter",
|
||||
L"SPRT",
|
||||
tmpstr,
|
||||
_countof(tmpstr),
|
||||
filename);
|
||||
|
||||
wcstombs(cfg->firm_name_printer, tmpstr, sizeof(cfg->firm_name_printer) - 1);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"flatPanelReader",
|
||||
L"targetCodeField",
|
||||
L"SFR0",
|
||||
tmpstr,
|
||||
_countof(tmpstr),
|
||||
filename);
|
||||
|
||||
wcstombs(cfg->target_code_field, tmpstr, sizeof(cfg->target_code_field) - 1);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"flatPanelReader",
|
||||
L"targetCodePrinter",
|
||||
L"SPT0",
|
||||
tmpstr,
|
||||
_countof(tmpstr),
|
||||
filename);
|
||||
|
||||
wcstombs(cfg->target_code_printer, tmpstr, sizeof(cfg->target_code_printer) - 1);
|
||||
}
|
||||
|
|
@ -4,8 +4,29 @@
|
|||
|
||||
#include "hooklib/dvd.h"
|
||||
#include "hooklib/touch.h"
|
||||
#include "hooklib/printer.h"
|
||||
#include "hooklib/printer_chc.h"
|
||||
#include "hooklib/printer_cx.h"
|
||||
|
||||
struct y3_config {
|
||||
bool enable;
|
||||
|
||||
float dll_version;
|
||||
float firm_version;
|
||||
char firm_name_field[5];
|
||||
char firm_name_printer[5];
|
||||
char target_code_field[5];
|
||||
char target_code_printer[5];
|
||||
uint8_t port_field;
|
||||
uint8_t port_printer;
|
||||
};
|
||||
|
||||
struct y3_dll_config {
|
||||
wchar_t path[MAX_PATH];
|
||||
};
|
||||
|
||||
void dvd_config_load(struct dvd_config *cfg, const wchar_t *filename);
|
||||
void touch_screen_config_load(struct touch_screen_config *cfg, const wchar_t *filename);
|
||||
void printer_config_load(struct printer_config *cfg, const wchar_t *filename);
|
||||
void printer_chc_config_load(struct printer_chc_config *cfg, const wchar_t *filename);
|
||||
void printer_cx_config_load(struct printer_cx_config *cfg, const wchar_t *filename);
|
||||
void y3_config_load(struct y3_config *cfg, const wchar_t *filename);
|
||||
void y3_dll_config_load(struct y3_dll_config *cfg, const wchar_t *filename);
|
||||
|
|
@ -5,11 +5,14 @@
|
|||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
#include "hook/table.h"
|
||||
|
||||
#include "hooklib/createprocess.h"
|
||||
|
||||
#include "path.h"
|
||||
#include "hook/procaddr.h"
|
||||
#include "util/dprintf.h"
|
||||
|
||||
void createprocess_hook_init();
|
||||
|
|
@ -36,7 +39,15 @@ BOOL my_CreateProcessW(
|
|||
LPCWSTR lpCurrentDirectory,
|
||||
LPSTARTUPINFOW lpStartupInfo,
|
||||
LPPROCESS_INFORMATION lpProcessInformation
|
||||
);
|
||||
);
|
||||
|
||||
BOOL my_ShellExecuteExA(SHELLEXECUTEINFOA *pExecInfo);
|
||||
|
||||
BOOL my_ShellExecuteExW(SHELLEXECUTEINFOW *pExecInfo);
|
||||
|
||||
static BOOL (WINAPI *next_ShellExecuteExA)(SHELLEXECUTEINFOA *pExecInfo);
|
||||
|
||||
static BOOL (WINAPI *next_ShellExecuteExW)(SHELLEXECUTEINFOW *pExecInfo);
|
||||
|
||||
static BOOL (WINAPI *next_CreateProcessA)(
|
||||
LPCSTR lpApplicationName,
|
||||
|
|
@ -76,6 +87,18 @@ static const struct hook_symbol win32_hooks[] = {
|
|||
.link = (void **) &next_CreateProcessW
|
||||
},
|
||||
};
|
||||
static const struct hook_symbol shell32_hooks[] = {
|
||||
{
|
||||
.name = "ShellExecuteExA",
|
||||
.patch = my_ShellExecuteExA,
|
||||
.link = (void **) &next_ShellExecuteExA
|
||||
},
|
||||
{
|
||||
.name = "ShellExecuteExW",
|
||||
.patch = my_ShellExecuteExW,
|
||||
.link = (void **) &next_ShellExecuteExW
|
||||
},
|
||||
};
|
||||
|
||||
static bool did_init = false;
|
||||
|
||||
|
|
@ -87,7 +110,7 @@ static size_t process_nsyms_w = 0;
|
|||
|
||||
static CRITICAL_SECTION createproc_lock;
|
||||
|
||||
HRESULT createprocess_push_hook_w(const wchar_t *name, const wchar_t *head, const wchar_t *tail, bool replace_all) {
|
||||
HRESULT createprocess_push_hook_w(const wchar_t *name, const wchar_t *head, const wchar_t *tail, bool replace_all, bool replace_paths) {
|
||||
struct process_hook_sym_w *new_mem;
|
||||
struct process_hook_sym_w *new_proc;
|
||||
HRESULT hr;
|
||||
|
|
@ -114,6 +137,7 @@ HRESULT createprocess_push_hook_w(const wchar_t *name, const wchar_t *head, cons
|
|||
new_proc->head = head;
|
||||
new_proc->tail = tail;
|
||||
new_proc->replace_all = replace_all;
|
||||
new_proc->replace_paths = replace_paths;
|
||||
|
||||
process_syms_w = new_mem;
|
||||
process_nsyms_w++;
|
||||
|
|
@ -122,7 +146,7 @@ HRESULT createprocess_push_hook_w(const wchar_t *name, const wchar_t *head, cons
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT createprocess_push_hook_a(const char *name, const char *head, const char *tail, bool replace_all) {
|
||||
HRESULT createprocess_push_hook_a(const char *name, const char *head, const char *tail, bool replace_all, bool replace_paths) {
|
||||
struct process_hook_sym_a *new_mem;
|
||||
struct process_hook_sym_a *new_proc;
|
||||
|
||||
|
|
@ -149,6 +173,7 @@ HRESULT createprocess_push_hook_a(const char *name, const char *head, const char
|
|||
new_proc->head = head;
|
||||
new_proc->tail = tail;
|
||||
new_proc->replace_all = replace_all;
|
||||
new_proc->replace_paths = replace_paths;
|
||||
|
||||
process_syms_a = new_mem;
|
||||
process_nsyms_a++;
|
||||
|
|
@ -157,18 +182,31 @@ HRESULT createprocess_push_hook_a(const char *name, const char *head, const char
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
void createprocess_hook_apply_hooks(HMODULE mod) {
|
||||
hook_table_apply(
|
||||
mod,
|
||||
"kernel32.dll",
|
||||
win32_hooks,
|
||||
_countof(win32_hooks));
|
||||
hook_table_apply(
|
||||
mod,
|
||||
"shell32.dll",
|
||||
shell32_hooks,
|
||||
_countof(shell32_hooks));
|
||||
|
||||
proc_addr_table_push(mod, "kernel32.dll", win32_hooks, _countof(win32_hooks));
|
||||
proc_addr_table_push(mod, "shell32.dll", shell32_hooks, _countof(shell32_hooks));
|
||||
|
||||
InitializeCriticalSection(&createproc_lock);
|
||||
}
|
||||
|
||||
void createprocess_hook_init() {
|
||||
if (did_init) {
|
||||
return;
|
||||
}
|
||||
did_init = true;
|
||||
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
"kernel32.dll",
|
||||
win32_hooks,
|
||||
_countof(win32_hooks));
|
||||
InitializeCriticalSection(&createproc_lock);
|
||||
createprocess_hook_apply_hooks(NULL);
|
||||
dprintf("CreateProcess: Init\n");
|
||||
}
|
||||
|
||||
|
|
@ -255,4 +293,66 @@ BOOL my_CreateProcessW(
|
|||
lpStartupInfo,
|
||||
lpProcessInformation
|
||||
);
|
||||
}
|
||||
|
||||
BOOL my_ShellExecuteExA(SHELLEXECUTEINFOA *pExecInfo) {
|
||||
for (int i = 0; i < process_nsyms_a; i++) {
|
||||
if (strncmp(process_syms_a[i].name, pExecInfo->lpFile, strlen(process_syms_a[i].name))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dprintf("CreateProcess: Hooking child process %s %s\n", pExecInfo->lpFile, pExecInfo->lpParameters);
|
||||
char new_args[MAX_PATH] = {0};
|
||||
strcat_s(new_args, MAX_PATH, process_syms_a[i].head);
|
||||
|
||||
if (!process_syms_a[i].replace_all) {
|
||||
strcat_s(new_args, MAX_PATH, pExecInfo->lpParameters);
|
||||
}
|
||||
if (process_syms_a[i].replace_paths) {
|
||||
char result[MAX_PATH];
|
||||
if (path_transform_args_a(pExecInfo->lpParameters, ' ', result, MAX_PATH)) {
|
||||
strcat_s(new_args, MAX_PATH, result);
|
||||
}
|
||||
}
|
||||
|
||||
if (process_syms_a[i].tail != NULL) {
|
||||
strcat_s(new_args, MAX_PATH, process_syms_a[i].tail);
|
||||
}
|
||||
|
||||
pExecInfo->lpParameters = new_args;
|
||||
|
||||
dprintf("CreateProcess: Replaced ShellExecuteExA %s %s\n", pExecInfo->lpFile, new_args);
|
||||
}
|
||||
return next_ShellExecuteExA(pExecInfo);
|
||||
}
|
||||
|
||||
BOOL my_ShellExecuteExW(SHELLEXECUTEINFOW *pExecInfo) {
|
||||
for (int i = 0; i < process_nsyms_w; i++) {
|
||||
if (wcsncmp(process_syms_w[i].name, pExecInfo->lpFile, wcslen(process_syms_w[i].name))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dprintf("CreateProcess: Hooking child process %ls %ls\n", pExecInfo->lpFile, pExecInfo->lpParameters);
|
||||
wchar_t new_args[MAX_PATH] = {0};
|
||||
wcscat_s(new_args, MAX_PATH, process_syms_w[i].head);
|
||||
|
||||
if (!process_syms_w[i].replace_all) {
|
||||
wcscat_s(new_args, MAX_PATH, pExecInfo->lpParameters);
|
||||
}
|
||||
if (process_syms_w[i].replace_paths) {
|
||||
wchar_t result[MAX_PATH];
|
||||
if (path_transform_args_w(pExecInfo->lpParameters, ' ', result, MAX_PATH)) {
|
||||
wcscat_s(new_args, MAX_PATH, result);
|
||||
}
|
||||
}
|
||||
|
||||
if (process_syms_w[i].tail != NULL) {
|
||||
wcscat_s(new_args, MAX_PATH, process_syms_w[i].tail);
|
||||
}
|
||||
|
||||
pExecInfo->lpParameters = new_args;
|
||||
|
||||
dprintf("CreateProcess: Replaced ShellExecuteExW %ls %ls\n", pExecInfo->lpFile, new_args);
|
||||
}
|
||||
return next_ShellExecuteExW(pExecInfo);
|
||||
}
|
||||
|
|
@ -3,14 +3,16 @@
|
|||
#include <windows.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
HRESULT createprocess_push_hook_w(const wchar_t *name, const wchar_t *head, const wchar_t *tail, bool replace_all);
|
||||
HRESULT createprocess_push_hook_a(const char *name, const char *head, const char *tail, bool replace_all);
|
||||
HRESULT createprocess_push_hook_w(const wchar_t *name, const wchar_t *head, const wchar_t *tail, bool replace_all, bool replace_paths);
|
||||
HRESULT createprocess_push_hook_a(const char *name, const char *head, const char *tail, bool replace_all, bool replace_paths);
|
||||
void createprocess_hook_apply_hooks(HMODULE mod);
|
||||
|
||||
struct process_hook_sym_w {
|
||||
const wchar_t *name;
|
||||
const wchar_t *head;
|
||||
const wchar_t *tail;
|
||||
bool replace_all;
|
||||
bool replace_paths;
|
||||
};
|
||||
|
||||
struct process_hook_sym_a {
|
||||
|
|
@ -18,4 +20,5 @@ struct process_hook_sym_a {
|
|||
const char *head;
|
||||
const char *tail;
|
||||
bool replace_all;
|
||||
bool replace_paths;
|
||||
};
|
||||
|
|
@ -71,6 +71,36 @@ static int WSAAPI hook_getaddrinfo(
|
|||
const ADDRINFOA *pHints,
|
||||
ADDRINFOA **ppResult);
|
||||
|
||||
static int WSAAPI hook_GetAddrInfoW(
|
||||
const wchar_t *pNodeName,
|
||||
const wchar_t *pServiceName,
|
||||
const ADDRINFOW *pHints,
|
||||
PADDRINFOW *ppResult);
|
||||
|
||||
static int WSAAPI hook_GetAddrInfoExA(
|
||||
const char *pName,
|
||||
const char *pServiceName,
|
||||
DWORD dwNameSpace,
|
||||
LPGUID lpNspId,
|
||||
const ADDRINFOEXW *hints,
|
||||
PADDRINFOEXA *ppResult,
|
||||
struct timeval *timeout,
|
||||
LPOVERLAPPED lpOverlapped,
|
||||
LPLOOKUPSERVICE_COMPLETION_ROUTINE lpCompletionRoutine,
|
||||
LPHANDLE lpHandle);
|
||||
|
||||
static int WSAAPI hook_GetAddrInfoExW(
|
||||
const wchar_t *pName,
|
||||
const wchar_t *pServiceName,
|
||||
DWORD dwNameSpace,
|
||||
LPGUID lpNspId,
|
||||
const ADDRINFOEXW *hints,
|
||||
PADDRINFOEXW *ppResult,
|
||||
struct timeval *timeout,
|
||||
LPOVERLAPPED lpOverlapped,
|
||||
LPLOOKUPSERVICE_COMPLETION_ROUTINE lpCompletionRoutine,
|
||||
LPHANDLE lpHandle);
|
||||
|
||||
static HINTERNET WINAPI hook_WinHttpConnect(
|
||||
HINTERNET hSession,
|
||||
const wchar_t *pwszServerName,
|
||||
|
|
@ -123,6 +153,36 @@ static int (WSAAPI *next_getaddrinfo)(
|
|||
const ADDRINFOA *pHints,
|
||||
ADDRINFOA **ppResult);
|
||||
|
||||
static int (WSAAPI *next_GetAddrInfoW)(
|
||||
const wchar_t *pNodeName,
|
||||
const wchar_t *pServiceName,
|
||||
const ADDRINFOW *pHints,
|
||||
PADDRINFOW *ppResult);
|
||||
|
||||
static int (WSAAPI *next_GetAddrInfoExA)(
|
||||
const char *pName,
|
||||
const char *pServiceName,
|
||||
DWORD dwNameSpace,
|
||||
LPGUID lpNspId,
|
||||
const ADDRINFOEXW *hints,
|
||||
PADDRINFOEXA *ppResult,
|
||||
struct timeval *timeout,
|
||||
LPOVERLAPPED lpOverlapped,
|
||||
LPLOOKUPSERVICE_COMPLETION_ROUTINE lpCompletionRoutine,
|
||||
LPHANDLE lpHandle);
|
||||
|
||||
static int (WSAAPI *next_GetAddrInfoExW)(
|
||||
const wchar_t *pName,
|
||||
const wchar_t *pServiceName,
|
||||
DWORD dwNameSpace,
|
||||
LPGUID lpNspId,
|
||||
const ADDRINFOEXW *hints,
|
||||
PADDRINFOEXW *ppResult,
|
||||
struct timeval *timeout,
|
||||
LPOVERLAPPED lpOverlapped,
|
||||
LPLOOKUPSERVICE_COMPLETION_ROUTINE lpCompletionRoutine,
|
||||
LPHANDLE lpHandle);
|
||||
|
||||
static HINTERNET (WINAPI *next_WinHttpConnect)(
|
||||
HINTERNET hSession,
|
||||
const wchar_t *pwszServerName,
|
||||
|
|
@ -169,6 +229,21 @@ static const struct hook_symbol dns_hook_syms_ws2[] = {
|
|||
.patch = hook_getaddrinfo,
|
||||
.link = (void **) &next_getaddrinfo,
|
||||
},
|
||||
{
|
||||
.name = "GetAddrInfoW",
|
||||
.patch = hook_GetAddrInfoW,
|
||||
.link = (void **) &next_GetAddrInfoW,
|
||||
},
|
||||
{
|
||||
.name = "GetAddrInfoExA",
|
||||
.patch = hook_GetAddrInfoExA,
|
||||
.link = (void **) &next_GetAddrInfoExA,
|
||||
},
|
||||
{
|
||||
.name = "GetAddrInfoExW",
|
||||
.patch = hook_GetAddrInfoExW,
|
||||
.link = (void **) &next_GetAddrInfoExW,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct hook_symbol dns_hook_syms_winhttp[] = {
|
||||
|
|
@ -612,6 +687,185 @@ end:
|
|||
return result;
|
||||
}
|
||||
|
||||
static int WSAAPI hook_GetAddrInfoW(
|
||||
const wchar_t *pNodeName,
|
||||
const wchar_t *pServiceName,
|
||||
const ADDRINFOW *pHints,
|
||||
ADDRINFOW **ppResult)
|
||||
{
|
||||
const struct dns_hook_entry *pos;
|
||||
int result;
|
||||
size_t i;
|
||||
|
||||
if (pNodeName == NULL) {
|
||||
result = WSA_INVALID_PARAMETER;
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&dns_hook_lock);
|
||||
|
||||
for (i = 0 ; i < dns_hook_nentries ; i++) {
|
||||
pos = &dns_hook_entries[i];
|
||||
|
||||
if (match_domain(pNodeName, pos->from)) {
|
||||
if(pos->to == NULL) {
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
result = EAI_NONAME;
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
// dprintf("GetAddrInfoW: %ls -> %ls\n", pNodeName, pos->to);
|
||||
|
||||
pNodeName = pos->to;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
|
||||
result = next_GetAddrInfoW(pNodeName, pServiceName, pHints, ppResult);
|
||||
|
||||
end:
|
||||
return result;
|
||||
}
|
||||
|
||||
static int WSAAPI hook_GetAddrInfoExA(
|
||||
const char *pName,
|
||||
const char *pServiceName,
|
||||
DWORD dwNameSpace,
|
||||
LPGUID lpNspId,
|
||||
const ADDRINFOEXW *hints,
|
||||
PADDRINFOEXA *ppResult,
|
||||
struct timeval *timeout,
|
||||
LPOVERLAPPED lpOverlapped,
|
||||
LPLOOKUPSERVICE_COMPLETION_ROUTINE lpCompletionRoutine,
|
||||
LPHANDLE lpHandle)
|
||||
{
|
||||
const struct dns_hook_entry *pos;
|
||||
char *str;
|
||||
size_t str_c;
|
||||
wchar_t *wstr;
|
||||
size_t wstr_c;
|
||||
int result;
|
||||
size_t i;
|
||||
|
||||
str = NULL;
|
||||
wstr = NULL;
|
||||
|
||||
if (pName == NULL) {
|
||||
result = WSA_INVALID_PARAMETER;
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
mbstowcs_s(&wstr_c, NULL, 0, pName, 0);
|
||||
wstr = malloc(wstr_c * sizeof(wchar_t));
|
||||
|
||||
if (wstr == NULL) {
|
||||
result = WSA_NOT_ENOUGH_MEMORY;
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
mbstowcs_s(NULL, wstr, wstr_c, pName, wstr_c - 1);
|
||||
|
||||
EnterCriticalSection(&dns_hook_lock);
|
||||
|
||||
for (i = 0; i < dns_hook_nentries; i++) {
|
||||
pos = &dns_hook_entries[i];
|
||||
|
||||
if (match_domain(wstr, pos->from)) {
|
||||
if (pos->to == NULL) {
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
result = WSAHOST_NOT_FOUND;
|
||||
goto end;
|
||||
}
|
||||
|
||||
// dprintf("GetAddrInfoExA: %ls -> %ls\n", pName, pos->to);
|
||||
|
||||
wcstombs_s(&str_c, NULL, 0, pos->to, 0);
|
||||
str = malloc(str_c * sizeof(char));
|
||||
|
||||
if (str == NULL) {
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
result = WSA_NOT_ENOUGH_MEMORY;
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
wcstombs_s(NULL, str, str_c, pos->to, str_c - 1);
|
||||
pName = str;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
|
||||
result = next_GetAddrInfoExA(pName, pServiceName, dwNameSpace, lpNspId,
|
||||
hints, ppResult, timeout, lpOverlapped,
|
||||
lpCompletionRoutine, lpHandle);
|
||||
|
||||
end:
|
||||
free(wstr);
|
||||
free(str);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int WSAAPI hook_GetAddrInfoExW(
|
||||
const wchar_t *pName,
|
||||
const wchar_t *pServiceName,
|
||||
DWORD dwNameSpace,
|
||||
LPGUID lpNspId,
|
||||
const ADDRINFOEXW *hints,
|
||||
PADDRINFOEXW *ppResult,
|
||||
struct timeval *timeout,
|
||||
LPOVERLAPPED lpOverlapped,
|
||||
LPLOOKUPSERVICE_COMPLETION_ROUTINE lpCompletionRoutine,
|
||||
LPHANDLE lpHandle)
|
||||
{
|
||||
const struct dns_hook_entry *pos;
|
||||
int result;
|
||||
size_t i;
|
||||
|
||||
if (pName == NULL) {
|
||||
result = WSA_INVALID_PARAMETER;
|
||||
goto end;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&dns_hook_lock);
|
||||
|
||||
for (i = 0; i < dns_hook_nentries; i++) {
|
||||
pos = &dns_hook_entries[i];
|
||||
|
||||
if (match_domain(pName, pos->from)) {
|
||||
if (pos->to == NULL) {
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
result = WSAHOST_NOT_FOUND;
|
||||
goto end;
|
||||
}
|
||||
|
||||
// dprintf("GetAddrInfoExW: %ls -> %ls\n", pName, pos->to);
|
||||
|
||||
pName = pos->to;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&dns_hook_lock);
|
||||
|
||||
result = next_GetAddrInfoExW(pName, pServiceName, dwNameSpace, lpNspId,
|
||||
hints, ppResult, timeout, lpOverlapped,
|
||||
lpCompletionRoutine, lpHandle);
|
||||
|
||||
end:
|
||||
return result;
|
||||
}
|
||||
|
||||
static HINTERNET WINAPI hook_WinHttpConnect(
|
||||
HINTERNET hSession,
|
||||
const wchar_t *pwszServerName,
|
||||
|
|
|
|||
212
common/hooklib/imageutil.c
Normal file
212
common/hooklib/imageutil.c
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
#include <windows.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "imageutil.h"
|
||||
|
||||
// copy pasted from https://dev.s-ul.net/domeori/c310emu
|
||||
#define BITMAPHEADERSIZE 0x36
|
||||
|
||||
int ConvertDataToBitmap(
|
||||
DWORD dwBitCount,
|
||||
DWORD dwWidth, DWORD dwHeight,
|
||||
PBYTE pbInput, DWORD cbInput,
|
||||
PBYTE pbOutput, DWORD cbOutput,
|
||||
PDWORD pcbResult,
|
||||
bool pFlip) {
|
||||
if (!pbInput || !pbOutput || dwBitCount < 8) return -3;
|
||||
|
||||
if (cbInput < (dwWidth * dwHeight * dwBitCount / 8)) return -3;
|
||||
|
||||
PBYTE pBuffer = malloc(cbInput);
|
||||
if (!pBuffer) return -2;
|
||||
|
||||
BYTE dwColors = (BYTE)(dwBitCount / 8);
|
||||
if (!dwColors) {
|
||||
free(pBuffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
UINT16 cbColors;
|
||||
RGBQUAD pbColors[256];
|
||||
|
||||
switch (dwBitCount) {
|
||||
case 1:
|
||||
cbColors = 1;
|
||||
break;
|
||||
case 2:
|
||||
cbColors = 4;
|
||||
break;
|
||||
case 4:
|
||||
cbColors = 16;
|
||||
break;
|
||||
case 8:
|
||||
cbColors = 256;
|
||||
break;
|
||||
default:
|
||||
cbColors = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cbColors) {
|
||||
BYTE dwStep = (BYTE)(256 / cbColors);
|
||||
|
||||
for (UINT16 i = 0; i < cbColors; ++i) {
|
||||
pbColors[i].rgbRed = dwStep * i;
|
||||
pbColors[i].rgbGreen = dwStep * i;
|
||||
pbColors[i].rgbBlue = dwStep * i;
|
||||
pbColors[i].rgbReserved = 0;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD dwTable = cbColors * sizeof(RGBQUAD);
|
||||
DWORD dwOffset = BITMAPHEADERSIZE + dwTable;
|
||||
|
||||
// calculate the padded row size, again
|
||||
DWORD dwLineSize = (dwWidth * dwBitCount / 8 + 3) & ~3;
|
||||
|
||||
BITMAPFILEHEADER bFile = {0};
|
||||
BITMAPINFOHEADER bInfo = {0};
|
||||
|
||||
bFile.bfType = 0x4D42; // MAGIC
|
||||
bFile.bfSize = dwOffset + cbInput;
|
||||
bFile.bfOffBits = dwOffset;
|
||||
|
||||
bInfo.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bInfo.biWidth = dwWidth;
|
||||
bInfo.biHeight = dwHeight;
|
||||
bInfo.biPlanes = 1;
|
||||
bInfo.biBitCount = (WORD)dwBitCount;
|
||||
bInfo.biCompression = BI_RGB;
|
||||
bInfo.biSizeImage = cbInput;
|
||||
|
||||
if (cbOutput < bFile.bfSize) {
|
||||
free(pBuffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Flip the image (if necessary) and add padding to each row
|
||||
if (pFlip) {
|
||||
for (size_t i = 0; i < dwHeight; i++) {
|
||||
for (size_t j = 0; j < dwWidth; j++) {
|
||||
for (size_t k = 0; k < dwColors; k++) {
|
||||
// Calculate the position in the padded buffer
|
||||
// Make sure to also flip the colors from RGB to BRG
|
||||
size_t x = (dwHeight - i - 1) * dwLineSize + (dwWidth - j - 1) * dwColors + (dwColors - k - 1);
|
||||
size_t y = (dwHeight - i - 1) * dwWidth * dwColors + j * dwColors + k;
|
||||
*(pBuffer + x) = *(pbInput + y);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < dwHeight; i++) {
|
||||
for (size_t j = 0; j < dwWidth; j++) {
|
||||
for (size_t k = 0; k < dwColors; k++) {
|
||||
// Calculate the position in the padded buffer
|
||||
size_t x = i * dwLineSize + j * dwColors + (dwColors - k - 1);
|
||||
size_t y = (dwHeight - i - 1) * dwWidth * dwColors + j * dwColors + k;
|
||||
*(pBuffer + x) = *(pbInput + y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(pbOutput, &bFile, sizeof(BITMAPFILEHEADER));
|
||||
memcpy(pbOutput + sizeof(BITMAPFILEHEADER), &bInfo, sizeof(BITMAPINFOHEADER));
|
||||
if (cbColors) memcpy(pbOutput + BITMAPHEADERSIZE, pbColors, dwTable);
|
||||
memcpy(pbOutput + dwOffset, pBuffer, cbInput);
|
||||
|
||||
*pcbResult = bFile.bfSize;
|
||||
|
||||
free(pBuffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WriteDataToBitmapFile(
|
||||
LPCWSTR lpFilePath, DWORD dwBitCount,
|
||||
DWORD dwWidth, DWORD dwHeight,
|
||||
PBYTE pbInput, DWORD cbInput,
|
||||
PBYTE pbMetadata, DWORD cbMetadata,
|
||||
bool pFlip) {
|
||||
if (!lpFilePath || !pbInput) return -3;
|
||||
|
||||
HANDLE hFile;
|
||||
DWORD dwBytesWritten;
|
||||
|
||||
hFile = CreateFileW(
|
||||
lpFilePath,
|
||||
GENERIC_WRITE,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
|
||||
NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) return -1;
|
||||
|
||||
// calculate the padded row size and padded image size
|
||||
DWORD dwLineSize = (dwWidth * dwBitCount / 8 + 3) & ~3;
|
||||
DWORD dwImageSize = dwLineSize * dwHeight;
|
||||
|
||||
DWORD cbResult;
|
||||
DWORD cbBuffer = dwImageSize + 0x500;
|
||||
PBYTE pbBuffer = calloc(cbBuffer, 1);
|
||||
if (!pbBuffer) return -2;
|
||||
|
||||
if (ConvertDataToBitmap(dwBitCount, dwWidth, dwHeight, pbInput, dwImageSize, pbBuffer, cbBuffer, &cbResult, pFlip) < 0) {
|
||||
cbResult = -1;
|
||||
goto WriteDataToBitmapFile_End;
|
||||
}
|
||||
|
||||
WriteFile(hFile, pbBuffer, cbResult, &dwBytesWritten, NULL);
|
||||
|
||||
if (pbMetadata)
|
||||
WriteFile(hFile, pbMetadata, cbMetadata, &dwBytesWritten, NULL);
|
||||
|
||||
CloseHandle(hFile);
|
||||
|
||||
cbResult = dwBytesWritten;
|
||||
|
||||
WriteDataToBitmapFile_End:
|
||||
free(pbBuffer);
|
||||
return cbResult;
|
||||
}
|
||||
|
||||
int WriteArrayToFile(LPCSTR lpOutputFilePath, LPVOID lpDataTemp, DWORD nDataSize, BOOL isAppend) {
|
||||
#ifdef NDEBUG
|
||||
|
||||
return nDataSize;
|
||||
|
||||
#else
|
||||
|
||||
HANDLE hFile;
|
||||
DWORD dwBytesWritten;
|
||||
DWORD dwDesiredAccess;
|
||||
DWORD dwCreationDisposition;
|
||||
|
||||
if (isAppend) {
|
||||
dwDesiredAccess = FILE_APPEND_DATA;
|
||||
dwCreationDisposition = OPEN_ALWAYS;
|
||||
} else {
|
||||
dwDesiredAccess = GENERIC_WRITE;
|
||||
dwCreationDisposition = CREATE_ALWAYS;
|
||||
}
|
||||
|
||||
hFile = CreateFileA(
|
||||
lpOutputFilePath,
|
||||
dwDesiredAccess,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
dwCreationDisposition,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
|
||||
NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WriteFile(hFile, lpDataTemp, nDataSize, &dwBytesWritten, NULL);
|
||||
CloseHandle(hFile);
|
||||
|
||||
return dwBytesWritten;
|
||||
|
||||
#endif
|
||||
}
|
||||
21
common/hooklib/imageutil.h
Normal file
21
common/hooklib/imageutil.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
int ConvertDataToBitmap(
|
||||
DWORD dwBitCount,
|
||||
DWORD dwWidth, DWORD dwHeight,
|
||||
PBYTE pbInput, DWORD cbInput,
|
||||
PBYTE pbOutput, DWORD cbOutput,
|
||||
PDWORD pcbResult,
|
||||
bool pFlip);
|
||||
|
||||
int WriteDataToBitmapFile(
|
||||
LPCWSTR lpFilePath, DWORD dwBitCount,
|
||||
DWORD dwWidth, DWORD dwHeight,
|
||||
PBYTE pbInput, DWORD cbInput,
|
||||
PBYTE pbMetadata, DWORD cbMetadata,
|
||||
bool pFlip);
|
||||
|
||||
int WriteArrayToFile(LPCSTR lpOutputFilePath, LPVOID lpDataTemp, DWORD nDataSize, BOOL isAppend);
|
||||
|
|
@ -21,6 +21,8 @@ hooklib_lib = static_library(
|
|||
'dvd.h',
|
||||
'fdshark.c',
|
||||
'fdshark.h',
|
||||
'imageutil.c',
|
||||
'imageutil.h',
|
||||
'path.c',
|
||||
'path.h',
|
||||
'reg.c',
|
||||
|
|
@ -31,7 +33,13 @@ hooklib_lib = static_library(
|
|||
'spike.h',
|
||||
'touch.c',
|
||||
'touch.h',
|
||||
'printer.c',
|
||||
'printer.h',
|
||||
'printer_chc.c',
|
||||
'printer_chc.h',
|
||||
'printer_cx.c',
|
||||
'printer_cx.h',
|
||||
'y3.c',
|
||||
'y3.h',
|
||||
'y3-dll.c',
|
||||
'y3-dll.h',
|
||||
],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
/* Helpers */
|
||||
|
||||
static void path_hook_init(void);
|
||||
static BOOL path_transform_a(char **out, const char *src);
|
||||
|
||||
/* API hooks */
|
||||
|
||||
|
|
@ -110,11 +109,43 @@ static BOOL WINAPI hook_MoveFileW(
|
|||
const wchar_t *lpExistingFileName,
|
||||
const wchar_t *lpNewFileName);
|
||||
|
||||
static BOOL WINAPI hook_CopyFileA(
|
||||
const char *lpExistingFileName,
|
||||
const char *lpNewFileName,
|
||||
BOOL bFailIfExists);
|
||||
|
||||
static BOOL WINAPI hook_CopyFileW(
|
||||
const wchar_t *lpExistingFileName,
|
||||
const wchar_t *lpNewFileName,
|
||||
BOOL bFailIfExists);
|
||||
|
||||
static BOOL WINAPI hook_MoveFileExA(
|
||||
const char *lpExistingFileName,
|
||||
const char *lpNewFileName,
|
||||
uint32_t dwFlags);
|
||||
|
||||
static BOOL WINAPI hook_MoveFileExW(
|
||||
const wchar_t *lpExistingFileName,
|
||||
const wchar_t *lpNewFileName,
|
||||
uint32_t dwFlags);
|
||||
|
||||
static BOOL WINAPI hook_CopyFileExA(
|
||||
LPCSTR lpExistingFileName,
|
||||
LPCSTR lpNewFileName,
|
||||
LPPROGRESS_ROUTINE lpProgressRoutine,
|
||||
LPVOID lpData,
|
||||
LPBOOL pbCancel,
|
||||
DWORD dwCopyFlags
|
||||
);
|
||||
|
||||
static BOOL WINAPI hook_CopyFileExW(
|
||||
LPCWSTR lpExistingFileName,
|
||||
LPCWSTR lpNewFileName,
|
||||
LPPROGRESS_ROUTINE lpProgressRoutine,
|
||||
LPVOID lpData,
|
||||
LPBOOL pbCancel,
|
||||
DWORD dwCopyFlags
|
||||
);
|
||||
|
||||
static BOOL WINAPI hook_ReplaceFileA(
|
||||
const char *lpReplacedFileName,
|
||||
|
|
@ -161,6 +192,14 @@ static DWORD WINAPI hook_GetPrivateProfileSectionW(
|
|||
LPCWSTR lpFileName
|
||||
);
|
||||
|
||||
static UINT WINAPI hook_GetDriveTypeA(
|
||||
LPCSTR lpRootPathName
|
||||
);
|
||||
|
||||
static UINT WINAPI hook_GetDriveTypeW(
|
||||
LPCWSTR lpRootPathName
|
||||
);
|
||||
|
||||
/* Link pointers */
|
||||
|
||||
static BOOL (WINAPI *next_CreateDirectoryA)(
|
||||
|
|
@ -253,11 +292,56 @@ static BOOL (WINAPI *next_MoveFileW)(
|
|||
const wchar_t *lpExistingFileName,
|
||||
const wchar_t *lpNewFileName);
|
||||
|
||||
static BOOL (WINAPI *next_CopyFileA)(
|
||||
const char *lpExistingFileName,
|
||||
const char *lpNewFileName,
|
||||
BOOL bFailIfExists);
|
||||
|
||||
static BOOL (WINAPI *next_CopyFileW)(
|
||||
const wchar_t *lpExistingFileName,
|
||||
const wchar_t *lpNewFileName,
|
||||
BOOL bFailIfExists);
|
||||
|
||||
static BOOL (WINAPI *next_MoveFileExA)(
|
||||
const char *lpExistingFileName,
|
||||
const char *lpNewFileName,
|
||||
uint32_t dwFlags);
|
||||
|
||||
static BOOL (WINAPI *next_MoveFileExW)(
|
||||
const wchar_t *lpExistingFileName,
|
||||
const wchar_t *lpNewFileName,
|
||||
uint32_t dwFlags);
|
||||
|
||||
static BOOL (WINAPI *next_CopyFileA)(
|
||||
const LPCSTR lpExistingFileName,
|
||||
const LPCSTR lpNewFileName,
|
||||
BOOL bFailIfExists
|
||||
);
|
||||
|
||||
static BOOL (WINAPI *next_CopyFileW)(
|
||||
const LPCWSTR lpExistingFileName,
|
||||
const LPCWSTR lpNewFileName,
|
||||
BOOL bFailIfExists
|
||||
);
|
||||
|
||||
static BOOL (WINAPI *next_CopyFileExA)(
|
||||
LPCSTR lpExistingFileName,
|
||||
LPCSTR lpNewFileName,
|
||||
LPPROGRESS_ROUTINE lpProgressRoutine,
|
||||
LPVOID lpData,
|
||||
LPBOOL pbCancel,
|
||||
DWORD dwCopyFlags
|
||||
);
|
||||
|
||||
static BOOL (WINAPI *next_CopyFileExW)(
|
||||
LPCWSTR lpExistingFileName,
|
||||
LPCWSTR lpNewFileName,
|
||||
LPPROGRESS_ROUTINE lpProgressRoutine,
|
||||
LPVOID lpData,
|
||||
LPBOOL pbCancel,
|
||||
DWORD dwCopyFlags
|
||||
);
|
||||
|
||||
static BOOL (WINAPI *next_ReplaceFileA)(
|
||||
const char *lpReplacedFileName,
|
||||
const char *lpReplacementFileName,
|
||||
|
|
@ -303,6 +387,14 @@ static DWORD (WINAPI *next_GetPrivateProfileSectionW)(
|
|||
LPCWSTR lpFileName
|
||||
);
|
||||
|
||||
static UINT (WINAPI *next_GetDriveTypeW)(
|
||||
LPCWSTR lpRootPathName
|
||||
);
|
||||
|
||||
static UINT (WINAPI *next_GetDriveTypeA)(
|
||||
LPCSTR lpRootPathName
|
||||
);
|
||||
|
||||
/* Hook table */
|
||||
|
||||
static const struct hook_symbol path_hook_syms[] = {
|
||||
|
|
@ -390,6 +482,26 @@ static const struct hook_symbol path_hook_syms[] = {
|
|||
.name = "MoveFileExA",
|
||||
.patch = hook_MoveFileExA,
|
||||
.link = (void **) &next_MoveFileExA,
|
||||
}, {
|
||||
.name = "MoveFileExW",
|
||||
.patch = hook_MoveFileExW,
|
||||
.link = (void **) &next_MoveFileExW,
|
||||
}, {
|
||||
.name = "CopyFileA",
|
||||
.patch = hook_CopyFileA,
|
||||
.link = (void **) &next_CopyFileA,
|
||||
}, {
|
||||
.name = "CopyFileW",
|
||||
.patch = hook_CopyFileW,
|
||||
.link = (void **) &next_CopyFileW,
|
||||
}, {
|
||||
.name = "CopyFileExA",
|
||||
.patch = hook_CopyFileExA,
|
||||
.link = (void **) &next_CopyFileExA,
|
||||
}, {
|
||||
.name = "CopyFileExW",
|
||||
.patch = hook_CopyFileW,
|
||||
.link = (void **) &next_CopyFileExW,
|
||||
}, {
|
||||
.name = "ReplaceFileA",
|
||||
.patch = hook_ReplaceFileA,
|
||||
|
|
@ -418,6 +530,14 @@ static const struct hook_symbol path_hook_syms[] = {
|
|||
.name = "GetPrivateProfileSectionW",
|
||||
.patch = hook_GetPrivateProfileSectionW,
|
||||
.link = (void **) &next_GetPrivateProfileSectionW,
|
||||
}, {
|
||||
.name = "GetDriveTypeA",
|
||||
.patch = hook_GetDriveTypeA,
|
||||
.link = (void **) &next_GetDriveTypeA,
|
||||
}, {
|
||||
.name = "GetDriveTypeW",
|
||||
.patch = hook_GetDriveTypeW,
|
||||
.link = (void **) &next_GetDriveTypeW,
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -482,7 +602,7 @@ void path_hook_insert_hooks(HMODULE target)
|
|||
_countof(path_hook_syms));
|
||||
}
|
||||
|
||||
static BOOL path_transform_a(char **out, const char *src)
|
||||
BOOL path_transform_a(char **out, const char *src)
|
||||
{
|
||||
wchar_t *src_w;
|
||||
size_t src_c;
|
||||
|
|
@ -1135,6 +1255,75 @@ static BOOL WINAPI hook_MoveFileW(
|
|||
return ok;
|
||||
}
|
||||
|
||||
|
||||
static BOOL WINAPI hook_CopyFileA(
|
||||
const char *lpExistingFileName,
|
||||
const char *lpNewFileName,
|
||||
BOOL bFailIfExists)
|
||||
{
|
||||
char *oldTrans;
|
||||
char *newTrans;
|
||||
BOOL ok;
|
||||
|
||||
ok = path_transform_a(&oldTrans, lpExistingFileName);
|
||||
|
||||
if (!ok) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = path_transform_a(&newTrans, lpNewFileName);
|
||||
|
||||
if (!ok) {
|
||||
free(oldTrans);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = next_CopyFileA(
|
||||
oldTrans ? oldTrans : lpExistingFileName,
|
||||
newTrans ? newTrans : lpNewFileName,
|
||||
bFailIfExists);
|
||||
|
||||
free(oldTrans);
|
||||
free(newTrans);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_CopyFileW(
|
||||
const wchar_t *lpExistingFileName,
|
||||
const wchar_t *lpNewFileName,
|
||||
BOOL bFailIfExists)
|
||||
{
|
||||
wchar_t *oldTrans;
|
||||
wchar_t *newTrans;
|
||||
BOOL ok;
|
||||
|
||||
ok = path_transform_w(&oldTrans, lpExistingFileName);
|
||||
|
||||
if (!ok) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = path_transform_w(&newTrans, lpNewFileName);
|
||||
|
||||
if (!ok) {
|
||||
free(oldTrans);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = next_CopyFileW(
|
||||
oldTrans ? oldTrans : lpExistingFileName,
|
||||
newTrans ? newTrans : lpNewFileName,
|
||||
bFailIfExists);
|
||||
|
||||
free(oldTrans);
|
||||
free(newTrans);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_MoveFileExA(
|
||||
const char *lpExistingFileName,
|
||||
const char *lpNewFileName,
|
||||
|
|
@ -1169,6 +1358,122 @@ static BOOL WINAPI hook_MoveFileExA(
|
|||
return ok;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_MoveFileExW(
|
||||
const wchar_t *lpExistingFileName,
|
||||
const wchar_t *lpNewFileName,
|
||||
uint32_t dwFlags)
|
||||
{
|
||||
wchar_t *oldTrans;
|
||||
wchar_t *newTrans;
|
||||
BOOL ok;
|
||||
|
||||
ok = path_transform_w(&oldTrans, lpExistingFileName);
|
||||
|
||||
if (!ok) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = path_transform_w(&newTrans, lpNewFileName);
|
||||
|
||||
if (!ok) {
|
||||
free(oldTrans);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = next_MoveFileExW(
|
||||
oldTrans ? oldTrans : lpExistingFileName,
|
||||
newTrans ? newTrans : lpNewFileName,
|
||||
dwFlags);
|
||||
|
||||
free(oldTrans);
|
||||
free(newTrans);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_CopyFileExA(
|
||||
LPCSTR lpExistingFileName,
|
||||
LPCSTR lpNewFileName,
|
||||
LPPROGRESS_ROUTINE lpProgressRoutine,
|
||||
LPVOID lpData,
|
||||
LPBOOL pbCancel,
|
||||
DWORD dwCopyFlags
|
||||
)
|
||||
{
|
||||
char *oldTrans;
|
||||
char *newTrans;
|
||||
BOOL ok;
|
||||
|
||||
ok = path_transform_a(&oldTrans, lpExistingFileName);
|
||||
|
||||
if (!ok) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = path_transform_a(&newTrans, lpNewFileName);
|
||||
|
||||
if (!ok) {
|
||||
free(oldTrans);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = next_CopyFileExA(
|
||||
oldTrans ? oldTrans : lpExistingFileName,
|
||||
newTrans ? newTrans : lpNewFileName,
|
||||
lpProgressRoutine,
|
||||
lpData,
|
||||
pbCancel,
|
||||
dwCopyFlags);
|
||||
|
||||
free(oldTrans);
|
||||
free(newTrans);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_CopyFileExW(
|
||||
LPCWSTR lpExistingFileName,
|
||||
LPCWSTR lpNewFileName,
|
||||
LPPROGRESS_ROUTINE lpProgressRoutine,
|
||||
LPVOID lpData,
|
||||
LPBOOL pbCancel,
|
||||
DWORD dwCopyFlags
|
||||
)
|
||||
{
|
||||
wchar_t *oldTrans;
|
||||
wchar_t *newTrans;
|
||||
BOOL ok;
|
||||
|
||||
ok = path_transform_w(&oldTrans, lpExistingFileName);
|
||||
|
||||
if (!ok) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = path_transform_w(&newTrans, lpNewFileName);
|
||||
|
||||
if (!ok) {
|
||||
free(oldTrans);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ok = next_CopyFileExW(
|
||||
oldTrans ? oldTrans : lpExistingFileName,
|
||||
newTrans ? newTrans : lpNewFileName,
|
||||
lpProgressRoutine,
|
||||
lpData,
|
||||
pbCancel,
|
||||
dwCopyFlags);
|
||||
|
||||
free(oldTrans);
|
||||
free(newTrans);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static BOOL WINAPI hook_ReplaceFileA(
|
||||
const char *lpReplacedFileName,
|
||||
const char *lpReplacementFileName,
|
||||
|
|
@ -1262,6 +1567,8 @@ static BOOL WINAPI hook_DeleteFileA(const char *lpFileName)
|
|||
|
||||
ok = next_DeleteFileA(trans ? trans: lpFileName);
|
||||
|
||||
free(trans);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
|
@ -1278,6 +1585,8 @@ static BOOL WINAPI hook_DeleteFileW(const wchar_t *lpFileName)
|
|||
|
||||
ok = next_DeleteFileW(trans ? trans: lpFileName);
|
||||
|
||||
free(trans);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
|
@ -1290,6 +1599,7 @@ static DWORD WINAPI hook_GetPrivateProfileStringA(
|
|||
LPCSTR lpFileName
|
||||
) {
|
||||
char *trans;
|
||||
DWORD result;
|
||||
BOOL ok;
|
||||
|
||||
ok = path_transform_a(&trans, lpFileName);
|
||||
|
|
@ -1298,7 +1608,17 @@ static DWORD WINAPI hook_GetPrivateProfileStringA(
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
return next_GetPrivateProfileStringA(lpAppName, lpKeyName, lpDefault, lpReturnedString, nSize, trans ? trans: lpFileName);
|
||||
result = next_GetPrivateProfileStringA(
|
||||
lpAppName,
|
||||
lpKeyName,
|
||||
lpDefault,
|
||||
lpReturnedString,
|
||||
nSize,
|
||||
trans ? trans: lpFileName);
|
||||
|
||||
free(trans);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static DWORD WINAPI hook_GetPrivateProfileStringW(
|
||||
|
|
@ -1310,6 +1630,7 @@ static DWORD WINAPI hook_GetPrivateProfileStringW(
|
|||
LPCWSTR lpFileName
|
||||
) {
|
||||
wchar_t *trans;
|
||||
DWORD result;
|
||||
BOOL ok;
|
||||
|
||||
ok = path_transform_w(&trans, lpFileName);
|
||||
|
|
@ -1318,7 +1639,16 @@ static DWORD WINAPI hook_GetPrivateProfileStringW(
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
return next_GetPrivateProfileStringW(lpAppName, lpKeyName, lpDefault, lpReturnedString, nSize, trans ? trans: lpFileName);
|
||||
result = next_GetPrivateProfileStringW(
|
||||
lpAppName,
|
||||
lpKeyName,
|
||||
lpDefault,
|
||||
lpReturnedString,
|
||||
nSize, trans ? trans: lpFileName);
|
||||
|
||||
free(trans);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static DWORD WINAPI hook_GetPrivateProfileSectionW(
|
||||
|
|
@ -1328,6 +1658,7 @@ static DWORD WINAPI hook_GetPrivateProfileSectionW(
|
|||
LPCWSTR lpFileName
|
||||
) {
|
||||
wchar_t *trans;
|
||||
DWORD result;
|
||||
BOOL ok;
|
||||
|
||||
ok = path_transform_w(&trans, lpFileName);
|
||||
|
|
@ -1336,5 +1667,229 @@ static DWORD WINAPI hook_GetPrivateProfileSectionW(
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
return next_GetPrivateProfileSectionW(lpAppName, lpReturnedString, nSize, trans ? trans: lpFileName);
|
||||
result = next_GetPrivateProfileSectionW(
|
||||
lpAppName,
|
||||
lpReturnedString,
|
||||
nSize,
|
||||
trans ? trans: lpFileName);
|
||||
|
||||
free(trans);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static UINT WINAPI hook_GetDriveTypeA(
|
||||
LPCSTR lpRootPathName
|
||||
) {
|
||||
char *trans;
|
||||
UINT result;
|
||||
BOOL ok;
|
||||
|
||||
ok = path_transform_a(&trans, lpRootPathName);
|
||||
|
||||
if (!ok) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
result = next_GetDriveTypeA(trans ? trans : lpRootPathName);
|
||||
|
||||
free(trans);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static UINT WINAPI hook_GetDriveTypeW(
|
||||
LPCWSTR lpRootPathName
|
||||
) {
|
||||
wchar_t *trans;
|
||||
UINT result;
|
||||
BOOL ok;
|
||||
|
||||
ok = path_transform_w(&trans, lpRootPathName);
|
||||
|
||||
if (!ok) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
result = next_GetDriveTypeW(trans ? trans : lpRootPathName);
|
||||
|
||||
free(trans);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
char** str_split_a(char* a_str, const char a_delim) {
|
||||
char** result = 0;
|
||||
size_t count = 0;
|
||||
char* tmp = a_str;
|
||||
char* last_comma = 0;
|
||||
char delim[2];
|
||||
delim[0] = a_delim;
|
||||
delim[1] = 0;
|
||||
|
||||
/* Count how many elements will be extracted. */
|
||||
while (*tmp)
|
||||
{
|
||||
if (a_delim == *tmp)
|
||||
{
|
||||
count++;
|
||||
last_comma = tmp;
|
||||
}
|
||||
tmp++;
|
||||
}
|
||||
|
||||
/* Add space for trailing token. */
|
||||
count += last_comma < (a_str + strlen(a_str) - 1);
|
||||
|
||||
/* Add space for terminating null string so caller
|
||||
knows where the list of returned strings ends. */
|
||||
count++;
|
||||
|
||||
result = malloc(sizeof(char*) * count);
|
||||
|
||||
if (result)
|
||||
{
|
||||
size_t idx = 0;
|
||||
char* token = strtok(a_str, delim);
|
||||
|
||||
while (token)
|
||||
{
|
||||
assert(idx < count);
|
||||
*(result + idx++) = strdup(token);
|
||||
token = strtok(0, delim);
|
||||
}
|
||||
assert(idx == count - 1);
|
||||
*(result + idx) = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL path_transform_args_a(const char* str, char delimiter, char* buf, size_t size) {
|
||||
assert(str != NULL);
|
||||
assert(buf != NULL);
|
||||
|
||||
if (size <= 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
char* copy = strdup(str);
|
||||
char** tokens = str_split_a(copy, delimiter);
|
||||
char *trans;
|
||||
BOOL ok;
|
||||
BOOL failed = FALSE;
|
||||
|
||||
strcpy(buf, "");
|
||||
|
||||
if (tokens) {
|
||||
int j;
|
||||
for (j = 0; *(tokens + j); j++) {
|
||||
ok = path_transform_a(&trans, *(tokens + j));
|
||||
free(*(tokens + j));
|
||||
if (ok) {
|
||||
strcat_s(buf, size, trans ? trans : *(tokens+j));
|
||||
if (*(tokens + j + 1)) {
|
||||
strcat_s(buf, size, " ");
|
||||
}
|
||||
free(trans);
|
||||
} else {
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
free(tokens);
|
||||
}
|
||||
|
||||
free(copy);
|
||||
|
||||
return !failed;
|
||||
}
|
||||
|
||||
wchar_t** str_split_w(wchar_t* a_str, const wchar_t a_delim) {
|
||||
wchar_t** result = 0;
|
||||
size_t count = 0;
|
||||
wchar_t* tmp = a_str;
|
||||
wchar_t* last_comma = 0;
|
||||
wchar_t delim[2];
|
||||
delim[0] = a_delim;
|
||||
delim[1] = 0;
|
||||
|
||||
/* Count how many elements will be extracted. */
|
||||
while (*tmp)
|
||||
{
|
||||
if (a_delim == *tmp)
|
||||
{
|
||||
count++;
|
||||
last_comma = tmp;
|
||||
}
|
||||
tmp++;
|
||||
}
|
||||
|
||||
/* Add space for trailing token. */
|
||||
count += last_comma < (a_str + wcslen(a_str) - 1);
|
||||
|
||||
/* Add space for terminating null string so caller
|
||||
knows where the list of returned strings ends. */
|
||||
count++;
|
||||
|
||||
result = malloc(sizeof(wchar_t*) * count);
|
||||
|
||||
wchar_t* pt;
|
||||
|
||||
if (result)
|
||||
{
|
||||
size_t idx = 0;
|
||||
wchar_t* token = wcstok_s(a_str, delim, &pt);
|
||||
|
||||
while (token)
|
||||
{
|
||||
assert(idx < count);
|
||||
*(result + idx++) = wcsdup(token);
|
||||
token = wcstok_s(0, delim, &pt);
|
||||
}
|
||||
assert(idx == count - 1);
|
||||
*(result + idx) = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL path_transform_args_w(const wchar_t* str, wchar_t delimiter, wchar_t* buf, size_t size) {
|
||||
assert(str != NULL);
|
||||
assert(buf != NULL);
|
||||
|
||||
if (size <= 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
wchar_t* copy = wcsdup(str);
|
||||
wchar_t** tokens = str_split_w(copy, delimiter);
|
||||
wchar_t *trans;
|
||||
BOOL ok;
|
||||
BOOL failed = FALSE;
|
||||
|
||||
wcscpy(buf, L"");
|
||||
|
||||
if (tokens) {
|
||||
int j;
|
||||
for (j = 0; *(tokens + j); j++) {
|
||||
ok = path_transform_w(&trans, *(tokens + j));
|
||||
if (ok) {
|
||||
wcscat_s(buf, size, trans ? trans : *(tokens+j));
|
||||
if (*(tokens + j + 1)) {
|
||||
wcscat_s(buf, size, L" ");
|
||||
}
|
||||
free(trans);
|
||||
} else {
|
||||
failed = true;
|
||||
}
|
||||
free(*(tokens + j));
|
||||
}
|
||||
free(tokens);
|
||||
}
|
||||
|
||||
free(copy);
|
||||
|
||||
return !failed;
|
||||
}
|
||||
|
|
@ -13,7 +13,10 @@ typedef HRESULT (*path_hook_t)(
|
|||
HRESULT path_hook_push(path_hook_t hook);
|
||||
void path_hook_insert_hooks(HMODULE target);
|
||||
int path_compare_w(const wchar_t *string1, const wchar_t *string2, size_t count);
|
||||
BOOL path_transform_a(char **out, const char *src);
|
||||
BOOL path_transform_w(wchar_t **out, const wchar_t *src);
|
||||
BOOL path_transform_args_a(const char* str, char delimiter, char* buf, size_t size);
|
||||
BOOL path_transform_args_w(const wchar_t* str, wchar_t delimiter, wchar_t* buf, size_t size);
|
||||
|
||||
static inline bool path_is_separator_w(wchar_t c)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@
|
|||
chc (emihiok)
|
||||
*/
|
||||
|
||||
#include "hooklib/printer.h"
|
||||
// ReSharper disable CppParameterNeverUsed
|
||||
// ReSharper disable CppDFAConstantFunctionResult
|
||||
#include "hooklib/printer_chc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
|
@ -90,6 +92,7 @@ int WINAPI chcusb_listupPrinterSN(uint64_t *rSerialArray);
|
|||
int WINAPI chcusb_selectPrinter(uint8_t printerId, uint16_t *rResult);
|
||||
int WINAPI chcusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult);
|
||||
int WINAPI chcusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen);
|
||||
int WINAPI chcusb_getPrinterInfo_300(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen);
|
||||
int WINAPI chcusb_imageformat(uint16_t format, uint16_t ncomp, uint16_t depth, uint16_t width, uint16_t height, uint8_t * image, uint16_t* rResult);
|
||||
int WINAPI chcusb_imageformat_330(
|
||||
uint16_t format,
|
||||
|
|
@ -98,7 +101,7 @@ int WINAPI chcusb_imageformat_330(
|
|||
uint16_t width,
|
||||
uint16_t height,
|
||||
uint16_t *rResult);
|
||||
int __fastcall chcusb_setmtf(int32_t *mtf);
|
||||
int WINAPI chcusb_setmtf(int32_t *mtf);
|
||||
int WINAPI chcusb_makeGamma(uint16_t k, uint8_t *intoneR, uint8_t *intoneG, uint8_t *intoneB);
|
||||
int WINAPI chcusb_setIcctable(
|
||||
LPCSTR icc1,
|
||||
|
|
@ -147,6 +150,7 @@ int WINAPI chcusb_getEEPROM(uint8_t index, uint8_t *rData, uint16_t *rResult);
|
|||
int WINAPI chcusb_setParameter(uint8_t a1, uint32_t a2, uint16_t *rResult);
|
||||
int WINAPI chcusb_getParameter(uint8_t a1, uint8_t *a2, uint16_t *rResult);
|
||||
int WINAPI chcusb_universal_command(int32_t a1, uint8_t a2, int32_t a3, uint8_t *a4, uint16_t *rResult);
|
||||
int WINAPI chcusb_writeIred(uint8_t* a1, uint8_t* a2, uint16_t* rResult);
|
||||
|
||||
/* PrintDLL API hooks */
|
||||
|
||||
|
|
@ -410,217 +414,6 @@ static const struct hook_symbol C3XXFWDLusb_hooks[] = {
|
|||
},
|
||||
};
|
||||
|
||||
/* C300usb hook tbl */
|
||||
|
||||
static const struct hook_symbol C300usb_hooks[] = {
|
||||
{
|
||||
.name = "chcusb_MakeThread",
|
||||
.ordinal = 0x0001,
|
||||
.patch = chcusb_MakeThread,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_open",
|
||||
.ordinal = 0x0002,
|
||||
.patch = chcusb_open,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_close",
|
||||
.ordinal = 0x0003,
|
||||
.patch = chcusb_close,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_ReleaseThread",
|
||||
.ordinal = 0x0004,
|
||||
.patch = chcusb_ReleaseThread,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_listupPrinter",
|
||||
.ordinal = 0x0005,
|
||||
.patch = chcusb_listupPrinter,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_listupPrinterSN",
|
||||
.ordinal = 0x0006,
|
||||
.patch = chcusb_listupPrinterSN,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_selectPrinter",
|
||||
.ordinal = 0x0007,
|
||||
.patch = chcusb_selectPrinter,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_selectPrinterSN",
|
||||
.ordinal = 0x0008,
|
||||
.patch = chcusb_selectPrinterSN,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_getPrinterInfo",
|
||||
.ordinal = 0x0009,
|
||||
.patch = chcusb_getPrinterInfo,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_imageformat",
|
||||
.ordinal = 0x000a,
|
||||
.patch = chcusb_imageformat,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_setmtf",
|
||||
.ordinal = 0x000b,
|
||||
.patch = chcusb_setmtf,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_makeGamma",
|
||||
.ordinal = 0x000c,
|
||||
.patch = chcusb_makeGamma,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_setIcctable",
|
||||
.ordinal = 0x000d,
|
||||
.patch = chcusb_setIcctable,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_copies",
|
||||
.ordinal = 0x000e,
|
||||
.patch = chcusb_copies,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_status",
|
||||
.ordinal = 0x000f,
|
||||
.patch = chcusb_status,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_statusAll",
|
||||
.ordinal = 0x0010,
|
||||
.patch = chcusb_statusAll,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_startpage",
|
||||
.ordinal = 0x0011,
|
||||
.patch = chcusb_startpage_300,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_endpage",
|
||||
.ordinal = 0x0012,
|
||||
.patch = chcusb_endpage,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_write",
|
||||
.ordinal = 0x0013,
|
||||
.patch = chcusb_write,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_writeLaminate",
|
||||
.ordinal = 0x0014,
|
||||
.patch = chcusb_writeLaminate,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_setPrinterInfo",
|
||||
.ordinal = 0x0015,
|
||||
.patch = chcusb_setPrinterInfo,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_getGamma",
|
||||
.ordinal = 0x0016,
|
||||
.patch = chcusb_getGamma,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_getMtf",
|
||||
.ordinal = 0x0017,
|
||||
.patch = chcusb_getMtf,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_cancelCopies",
|
||||
.ordinal = 0x0018,
|
||||
.patch = chcusb_cancelCopies,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_setPrinterToneCurve",
|
||||
.ordinal = 0x0019,
|
||||
.patch = chcusb_setPrinterToneCurve,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_getPrinterToneCurve",
|
||||
.ordinal = 0x001a,
|
||||
.patch = chcusb_getPrinterToneCurve,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_blinkLED",
|
||||
.ordinal = 0x001b,
|
||||
.patch = chcusb_blinkLED,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_resetPrinter",
|
||||
.ordinal = 0x001c,
|
||||
.patch = chcusb_resetPrinter,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_AttachThreadCount",
|
||||
.ordinal = 0x001d,
|
||||
.patch = chcusb_AttachThreadCount,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_getPrintIDStatus",
|
||||
.ordinal = 0x001e,
|
||||
.patch = chcusb_getPrintIDStatus,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_setPrintStandby",
|
||||
.ordinal = 0x001f,
|
||||
.patch = chcusb_setPrintStandby_300,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_testCardFeed",
|
||||
.ordinal = 0x0020,
|
||||
.patch = chcusb_testCardFeed,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_setParameter",
|
||||
.ordinal = 0x0021,
|
||||
.patch = chcusb_setParameter,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_getParameter",
|
||||
.ordinal = 0x0022,
|
||||
.patch = chcusb_getParameter,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_getErrorStatus",
|
||||
.ordinal = 0x0023,
|
||||
.patch = chcusb_getErrorStatus,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_setCutList",
|
||||
.ordinal = 0x0028,
|
||||
.patch = chcusb_setCutList,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_setLaminatePattern",
|
||||
.ordinal = 0x0029,
|
||||
.patch = chcusb_setLaminatePattern,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_color_adjustment",
|
||||
.ordinal = 0x002a,
|
||||
.patch = chcusb_color_adjustment,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_color_adjustmentEx",
|
||||
.ordinal = 0x002b,
|
||||
.patch = chcusb_color_adjustmentEx,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_getEEPROM",
|
||||
.ordinal = 0x003a,
|
||||
.patch = chcusb_getEEPROM,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_universal_command",
|
||||
.ordinal = 0x0049,
|
||||
.patch = chcusb_universal_command,
|
||||
.link = NULL
|
||||
},
|
||||
};
|
||||
|
||||
/* C310A-Busb/C320Ausb/C330Ausb hook tbl. The ordinals are required, as some
|
||||
games, for example Sekito, will import this library by ordinal and not by
|
||||
name. */
|
||||
|
|
@ -666,11 +459,6 @@ static const struct hook_symbol C3XXusb_hooks[] = {
|
|||
.ordinal = 0x0008,
|
||||
.patch = chcusb_selectPrinterSN,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_getPrinterInfo",
|
||||
.ordinal = 0x0009,
|
||||
.patch = chcusb_getPrinterInfo,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_imageformat",
|
||||
.ordinal = 0x000a,
|
||||
|
|
@ -706,11 +494,6 @@ static const struct hook_symbol C3XXusb_hooks[] = {
|
|||
.ordinal = 0x0010,
|
||||
.patch = chcusb_statusAll,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_startpage",
|
||||
.ordinal = 0x0011,
|
||||
.patch = chcusb_startpage,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_endpage",
|
||||
.ordinal = 0x0012,
|
||||
|
|
@ -781,11 +564,6 @@ static const struct hook_symbol C3XXusb_hooks[] = {
|
|||
.ordinal = 0x001f,
|
||||
.patch = chcusb_getPrintIDStatus,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_setPrintStandby",
|
||||
.ordinal = 0x0020,
|
||||
.patch = chcusb_setPrintStandby,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_testCardFeed",
|
||||
.ordinal = 0x0021,
|
||||
|
|
@ -841,6 +619,11 @@ static const struct hook_symbol C3XXusb_hooks[] = {
|
|||
.ordinal = 0x002b,
|
||||
.patch = chcusb_color_adjustmentEx,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_writeIred",
|
||||
.ordinal = 0x0032,
|
||||
.patch = chcusb_writeIred,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_getEEPROM",
|
||||
.ordinal = 0x003a,
|
||||
|
|
@ -864,6 +647,79 @@ static const struct hook_symbol C3XXusb_hooks[] = {
|
|||
},
|
||||
};
|
||||
|
||||
/* C300A-Busb specific hook tbl. */
|
||||
|
||||
static const struct hook_symbol C300usb_hooks[] = {
|
||||
{
|
||||
.name = "chcusb_getPrinterInfo",
|
||||
.ordinal = 0x0009,
|
||||
.patch = chcusb_getPrinterInfo_300,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_startpage",
|
||||
.ordinal = 0x0011,
|
||||
.patch = chcusb_startpage_300,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_setPrintStandby",
|
||||
.ordinal = 0x0020,
|
||||
.patch = chcusb_setPrintStandby_300,
|
||||
.link = NULL
|
||||
}
|
||||
};
|
||||
|
||||
/* C310A-Busb specific hook tbl. */
|
||||
|
||||
static const struct hook_symbol C310usb_hooks[] = {
|
||||
{
|
||||
.name = "chcusb_getPrinterInfo",
|
||||
.ordinal = 0x0009,
|
||||
.patch = chcusb_getPrinterInfo,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_imageformat",
|
||||
.ordinal = 0x000a,
|
||||
.patch = chcusb_imageformat,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_startpage",
|
||||
.ordinal = 0x0011,
|
||||
.patch = chcusb_startpage,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_setPrintStandby",
|
||||
.ordinal = 0x0020,
|
||||
.patch = chcusb_setPrintStandby,
|
||||
.link = NULL
|
||||
}
|
||||
};
|
||||
|
||||
/* C330Ausb specific hook tbl. */
|
||||
|
||||
static const struct hook_symbol C330usb_hooks[] = {
|
||||
{
|
||||
.name = "chcusb_getPrinterInfo",
|
||||
.ordinal = 0x0009,
|
||||
.patch = chcusb_getPrinterInfo,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_imageformat",
|
||||
.ordinal = 0x000a,
|
||||
.patch = chcusb_imageformat_330,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_startpage",
|
||||
.ordinal = 0x0011,
|
||||
.patch = chcusb_startpage,
|
||||
.link = NULL
|
||||
}, {
|
||||
.name = "chcusb_setPrintStandby",
|
||||
.ordinal = 0x0020,
|
||||
.patch = chcusb_setPrintStandby,
|
||||
.link = NULL
|
||||
}
|
||||
};
|
||||
|
||||
/* PrintDLL hook tbl */
|
||||
|
||||
static struct hook_symbol printdll_hooks[] = {
|
||||
|
|
@ -1150,9 +1006,9 @@ static struct hook_symbol printdll_hooks[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct printer_config printer_config;
|
||||
static struct printer_chc_config printer_config;
|
||||
|
||||
void printer_hook_init(const struct printer_config *cfg, int rfid_port_no, HINSTANCE self) {
|
||||
void printer_chc_hook_init(const struct printer_chc_config *cfg, int rfid_port_no, HINSTANCE self) {
|
||||
HANDLE fwFile = NULL;
|
||||
DWORD bytesRead = 0;
|
||||
|
||||
|
|
@ -1170,7 +1026,7 @@ void printer_hook_init(const struct printer_config *cfg, int rfid_port_no, HINST
|
|||
rotate180 = cfg->rotate_180;
|
||||
|
||||
memcpy(&printer_config, cfg, sizeof(*cfg));
|
||||
printer_hook_insert_hooks(NULL);
|
||||
printer_chc_hook_insert_hooks(NULL);
|
||||
|
||||
/*
|
||||
if (self != NULL) {
|
||||
|
|
@ -1229,7 +1085,7 @@ void printer_hook_init(const struct printer_config *cfg, int rfid_port_no, HINST
|
|||
dprintf("Printer: hook enabled.\n");
|
||||
}
|
||||
|
||||
void printer_hook_insert_hooks(HMODULE target) {
|
||||
void printer_chc_hook_insert_hooks(HMODULE target) {
|
||||
hook_table_apply(target, "C310Ausb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks));
|
||||
hook_table_apply(target, "C310Busb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks));
|
||||
hook_table_apply(target, "C310FWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks));
|
||||
|
|
@ -1239,9 +1095,18 @@ void printer_hook_insert_hooks(HMODULE target) {
|
|||
hook_table_apply(target, "C330Ausb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks));
|
||||
hook_table_apply(target, "C330AFWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks));
|
||||
|
||||
/* specific C300Ausb hooks */
|
||||
hook_table_apply(target, "C300usb.dll", C300usb_hooks, _countof(C300usb_hooks));
|
||||
proc_addr_table_push(target, "C300usb.dll", C300usb_hooks, _countof(C300usb_hooks));
|
||||
|
||||
/* specific C310Ausb/C320usb/C330Ausb hooks */
|
||||
hook_table_apply(target, "C310Ausb.dll", C330usb_hooks, _countof(C330usb_hooks));
|
||||
hook_table_apply(target, "C320Ausb.dll", C330usb_hooks, _countof(C330usb_hooks));
|
||||
hook_table_apply(target, "C330Ausb.dll", C330usb_hooks, _countof(C330usb_hooks));
|
||||
|
||||
/* Unity workaround */
|
||||
proc_addr_table_push(target, "PrintDLL.dll", printdll_hooks, _countof(printdll_hooks));
|
||||
proc_addr_table_push(target, "C300usb.dll", C300usb_hooks, _countof(C300usb_hooks));
|
||||
proc_addr_table_push(target, "C300usb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks));
|
||||
proc_addr_table_push(target, "C300FWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks));
|
||||
}
|
||||
|
||||
|
|
@ -2160,6 +2025,11 @@ int WINAPI chcusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t
|
|||
if (rBuffer) memset(rBuffer, 0, *rLen);
|
||||
break;
|
||||
|
||||
case 2: // unknown
|
||||
if (*rLen != 0x17) *rLen = 0x17;
|
||||
if (rBuffer) memset(rBuffer, 0, *rLen);
|
||||
break;
|
||||
|
||||
case 3: // getFirmwareVersion
|
||||
if (*rLen != 0x99) *rLen = 0x99;
|
||||
if (rBuffer) {
|
||||
|
|
@ -2307,6 +2177,58 @@ int WINAPI chcusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t
|
|||
return 1;
|
||||
}
|
||||
|
||||
int WINAPI chcusb_getPrinterInfo_300(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen) {
|
||||
// dprintf("Printer: C3XXusb: %s(%d)\n", __func__, tagNumber);
|
||||
|
||||
switch (tagNumber) {
|
||||
case 3: // getFirmwareVersion
|
||||
if (*rLen != 0x99) *rLen = 0x99;
|
||||
if (rBuffer) {
|
||||
memset(rBuffer, 0, *rLen);
|
||||
// C300 has 4 firmwares
|
||||
rBuffer[0] = 4; // firmware count
|
||||
|
||||
// bootFirmware
|
||||
int i = 1;
|
||||
memcpy(rBuffer + i, mainFirmware, sizeof(mainFirmware));
|
||||
// mainFirmware
|
||||
i += 0x26;
|
||||
memcpy(rBuffer + i, mainFirmware, sizeof(mainFirmware));
|
||||
// printParameterTable
|
||||
i += 0x26;
|
||||
memcpy(rBuffer + i, paramFirmware, sizeof(paramFirmware));
|
||||
// dspFirmware (C300 only)
|
||||
i += 0x26;
|
||||
memcpy(rBuffer + i, dspFirmware, sizeof(dspFirmware));
|
||||
}
|
||||
return 1;
|
||||
|
||||
case 4: // getPrintCountInfo (C300 only)
|
||||
if (!rBuffer) {
|
||||
*rLen = 0x1C;
|
||||
return 1;
|
||||
}
|
||||
int32_t bInfoC300[10] = {0};
|
||||
bInfoC300[0] = 22; // printCounter0
|
||||
bInfoC300[1] = 23; // printCounter1
|
||||
bInfoC300[2] = 33; // feedRollerCount
|
||||
bInfoC300[3] = 55; // cutterCount
|
||||
bInfoC300[4] = 88; // headCount
|
||||
bInfoC300[5] = 999; // ribbonRemain
|
||||
bInfoC300[6] = 0; // dummy
|
||||
if (*rLen <= 0x1Cu) {
|
||||
memcpy(rBuffer, bInfoC300, *rLen);
|
||||
} else {
|
||||
bInfoC300[7] = 0; // TODO
|
||||
if (*rLen > 0x20u) *rLen = 0x20;
|
||||
memcpy(rBuffer, bInfoC300, *rLen);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
return chcusb_getPrinterInfo(tagNumber, rBuffer, rLen);
|
||||
}
|
||||
|
||||
int WINAPI chcusb_imageformat(
|
||||
uint16_t format,
|
||||
uint16_t ncomp,
|
||||
|
|
@ -2334,7 +2256,7 @@ int WINAPI chcusb_imageformat_330(
|
|||
return 1;
|
||||
}
|
||||
|
||||
int __fastcall chcusb_setmtf(int32_t *mtf) {
|
||||
int WINAPI chcusb_setmtf(int32_t *mtf) {
|
||||
dprintf("Printer: C3XXusb: %s\n", __func__);
|
||||
|
||||
memcpy(MTF, mtf, sizeof(MTF));
|
||||
|
|
@ -3147,208 +3069,13 @@ int CHCUSB_writeLaminate(const void *handle, uint8_t *data, uint32_t offset, uin
|
|||
return chcusb_writeLaminate(data, writeSize, rResult);
|
||||
}
|
||||
|
||||
// copy pasted from https://dev.s-ul.net/domeori/c310emu
|
||||
#define BITMAPHEADERSIZE 0x36
|
||||
|
||||
DWORD ConvertDataToBitmap(
|
||||
DWORD dwBitCount,
|
||||
DWORD dwWidth, DWORD dwHeight,
|
||||
PBYTE pbInput, DWORD cbInput,
|
||||
PBYTE pbOutput, DWORD cbOutput,
|
||||
PDWORD pcbResult,
|
||||
bool pFlip) {
|
||||
if (!pbInput || !pbOutput || dwBitCount < 8) return -3;
|
||||
|
||||
if (cbInput < (dwWidth * dwHeight * dwBitCount / 8)) return -3;
|
||||
|
||||
PBYTE pBuffer = (PBYTE)malloc(cbInput);
|
||||
if (!pBuffer) return -2;
|
||||
|
||||
BYTE dwColors = (BYTE)(dwBitCount / 8);
|
||||
if (!dwColors) return -1;
|
||||
|
||||
UINT16 cbColors;
|
||||
RGBQUAD pbColors[256];
|
||||
|
||||
switch (dwBitCount) {
|
||||
case 1:
|
||||
cbColors = 1;
|
||||
break;
|
||||
case 2:
|
||||
cbColors = 4;
|
||||
break;
|
||||
case 4:
|
||||
cbColors = 16;
|
||||
break;
|
||||
case 8:
|
||||
cbColors = 256;
|
||||
break;
|
||||
default:
|
||||
cbColors = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cbColors) {
|
||||
BYTE dwStep = (BYTE)(256 / cbColors);
|
||||
|
||||
for (UINT16 i = 0; i < cbColors; ++i) {
|
||||
pbColors[i].rgbRed = dwStep * i;
|
||||
pbColors[i].rgbGreen = dwStep * i;
|
||||
pbColors[i].rgbBlue = dwStep * i;
|
||||
pbColors[i].rgbReserved = 0;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD dwTable = cbColors * sizeof(RGBQUAD);
|
||||
DWORD dwOffset = BITMAPHEADERSIZE + dwTable;
|
||||
|
||||
// calculate the padded row size, again
|
||||
DWORD dwLineSize = (dwWidth * dwBitCount / 8 + 3) & ~3;
|
||||
|
||||
BITMAPFILEHEADER bFile = {0};
|
||||
BITMAPINFOHEADER bInfo = {0};
|
||||
|
||||
bFile.bfType = 0x4D42; // MAGIC
|
||||
bFile.bfSize = dwOffset + cbInput;
|
||||
bFile.bfOffBits = dwOffset;
|
||||
|
||||
bInfo.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bInfo.biWidth = dwWidth;
|
||||
bInfo.biHeight = dwHeight;
|
||||
bInfo.biPlanes = 1;
|
||||
bInfo.biBitCount = (WORD)dwBitCount;
|
||||
bInfo.biCompression = BI_RGB;
|
||||
bInfo.biSizeImage = cbInput;
|
||||
|
||||
if (cbOutput < bFile.bfSize) return -1;
|
||||
|
||||
// Flip the image (if necessary) and add padding to each row
|
||||
if (pFlip) {
|
||||
for (size_t i = 0; i < dwHeight; i++) {
|
||||
for (size_t j = 0; j < dwWidth; j++) {
|
||||
for (size_t k = 0; k < dwColors; k++) {
|
||||
// Calculate the position in the padded buffer
|
||||
// Make sure to also flip the colors from RGB to BRG
|
||||
size_t x = (dwHeight - i - 1) * dwLineSize + (dwWidth - j - 1) * dwColors + (dwColors - k - 1);
|
||||
size_t y = (dwHeight - i - 1) * dwWidth * dwColors + j * dwColors + k;
|
||||
*(pBuffer + x) = *(pbInput + y);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < dwHeight; i++) {
|
||||
for (size_t j = 0; j < dwWidth; j++) {
|
||||
for (size_t k = 0; k < dwColors; k++) {
|
||||
// Calculate the position in the padded buffer
|
||||
size_t x = i * dwLineSize + j * dwColors + (dwColors - k - 1);
|
||||
size_t y = (dwHeight - i - 1) * dwWidth * dwColors + j * dwColors + k;
|
||||
*(pBuffer + x) = *(pbInput + y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(pbOutput, &bFile, sizeof(BITMAPFILEHEADER));
|
||||
memcpy(pbOutput + sizeof(BITMAPFILEHEADER), &bInfo, sizeof(BITMAPINFOHEADER));
|
||||
if (cbColors) memcpy(pbOutput + BITMAPHEADERSIZE, pbColors, dwTable);
|
||||
memcpy(pbOutput + dwOffset, pBuffer, cbInput);
|
||||
|
||||
*pcbResult = bFile.bfSize;
|
||||
|
||||
free(pBuffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD WriteDataToBitmapFile(
|
||||
LPCWSTR lpFilePath, DWORD dwBitCount,
|
||||
DWORD dwWidth, DWORD dwHeight,
|
||||
PBYTE pbInput, DWORD cbInput,
|
||||
PBYTE pbMetadata, DWORD cbMetadata,
|
||||
bool pFlip) {
|
||||
if (!lpFilePath || !pbInput) return -3;
|
||||
|
||||
HANDLE hFile;
|
||||
DWORD dwBytesWritten;
|
||||
|
||||
hFile = CreateFileW(
|
||||
lpFilePath,
|
||||
GENERIC_WRITE,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
|
||||
NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) return -1;
|
||||
|
||||
// calculate the padded row size and padded image size
|
||||
DWORD dwLineSize = (dwWidth * dwBitCount / 8 + 3) & ~3;
|
||||
DWORD dwImageSize = dwLineSize * dwHeight;
|
||||
|
||||
DWORD cbResult;
|
||||
DWORD cbBuffer = dwImageSize + 0x500;
|
||||
PBYTE pbBuffer = (PBYTE)calloc(cbBuffer, 1);
|
||||
if (!pbBuffer) return -2;
|
||||
|
||||
if (ConvertDataToBitmap(dwBitCount, dwWidth, dwHeight, pbInput, dwImageSize, pbBuffer, cbBuffer, &cbResult, pFlip) < 0) {
|
||||
cbResult = -1;
|
||||
goto WriteDataToBitmapFile_End;
|
||||
}
|
||||
|
||||
WriteFile(hFile, pbBuffer, cbResult, &dwBytesWritten, NULL);
|
||||
|
||||
if (pbMetadata)
|
||||
WriteFile(hFile, pbMetadata, cbMetadata, &dwBytesWritten, NULL);
|
||||
|
||||
CloseHandle(hFile);
|
||||
|
||||
cbResult = dwBytesWritten;
|
||||
|
||||
WriteDataToBitmapFile_End:
|
||||
free(pbBuffer);
|
||||
return cbResult;
|
||||
}
|
||||
|
||||
DWORD WriteArrayToFile(LPCSTR lpOutputFilePath, LPVOID lpDataTemp, DWORD nDataSize, BOOL isAppend) {
|
||||
#ifdef NDEBUG
|
||||
|
||||
return nDataSize;
|
||||
|
||||
#else
|
||||
|
||||
HANDLE hFile;
|
||||
DWORD dwBytesWritten;
|
||||
DWORD dwDesiredAccess;
|
||||
DWORD dwCreationDisposition;
|
||||
|
||||
if (isAppend) {
|
||||
dwDesiredAccess = FILE_APPEND_DATA;
|
||||
dwCreationDisposition = OPEN_ALWAYS;
|
||||
} else {
|
||||
dwDesiredAccess = GENERIC_WRITE;
|
||||
dwCreationDisposition = CREATE_ALWAYS;
|
||||
}
|
||||
|
||||
hFile = CreateFileA(
|
||||
lpOutputFilePath,
|
||||
dwDesiredAccess,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
dwCreationDisposition,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
|
||||
NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WriteFile(hFile, lpDataTemp, nDataSize, &dwBytesWritten, NULL);
|
||||
CloseHandle(hFile);
|
||||
|
||||
return dwBytesWritten;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void printer_set_dimensions(int width, int height){
|
||||
WIDTH = width;
|
||||
HEIGHT = height;
|
||||
}
|
||||
|
||||
int WINAPI chcusb_writeIred(uint8_t* a1, uint8_t* a2, uint16_t* rResult) {
|
||||
dprintf("Printer: C3XXusb: %s\n", __func__);
|
||||
*rResult = 0;
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct printer_config {
|
||||
struct printer_chc_config {
|
||||
bool enable;
|
||||
bool rotate_180;
|
||||
char serial_no[8];
|
||||
|
|
@ -15,8 +15,8 @@ struct printer_config {
|
|||
uint32_t wait_time;
|
||||
};
|
||||
|
||||
void printer_hook_init(const struct printer_config *cfg, int rfid_port_no, HINSTANCE self);
|
||||
void printer_hook_insert_hooks(HMODULE target);
|
||||
void printer_chc_hook_init(const struct printer_chc_config *cfg, int rfid_port_no, HINSTANCE self);
|
||||
void printer_chc_hook_insert_hooks(HMODULE target);
|
||||
|
||||
void printer_set_dimensions(int width, int height);
|
||||
int WINAPI fwdlusb_updateFirmware_main(uint8_t update, LPCSTR filename, uint16_t *rResult);
|
||||
906
common/hooklib/printer_cx.c
Normal file
906
common/hooklib/printer_cx.c
Normal file
|
|
@ -0,0 +1,906 @@
|
|||
// ReSharper disable CppParameterNeverUsed
|
||||
// ReSharper disable CppParameterMayBeConstPtrOrRef
|
||||
#include "printer_cx.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
#include <wtypes.h>
|
||||
|
||||
#include "imageutil.h"
|
||||
#include "hook/procaddr.h"
|
||||
#include "hook/table.h"
|
||||
#include "util/dprintf.h"
|
||||
|
||||
#pragma region prototypes
|
||||
static int WINAPI hook_CXCMD_Retransfer();
|
||||
|
||||
static bool WINAPI hook_CXCMD_CheckIfConnected(int* pSlotId, int* pId);
|
||||
|
||||
static int WINAPI hook_CXCMD_xImageOut();
|
||||
|
||||
static int WINAPI hook_CXCMD_MoveCard(int slotId, int id, int dest, int flip, int filmInit, int immed);
|
||||
|
||||
static int WINAPI hook_CXCMD_xWriteMagData();
|
||||
|
||||
static int WINAPI hook_CXCMD_SecurityPrint(int slotId, int id, int color, int bufferIndex, int immed);
|
||||
|
||||
static int WINAPI hook_CXCMD_ScanPrinterNext();
|
||||
|
||||
static int WINAPI hook_CXCMD_Print(int slotId, int id, int color, int bufferIndex, int immed);
|
||||
|
||||
static int WINAPI hook_CXCMD_RezeroUnit(int slotId, int id, int action);
|
||||
|
||||
static int WINAPI hook_CXCMD_WriteMagData();
|
||||
|
||||
static int WINAPI hook_CXCMD_LogSense(int iSlot, int iID, int iPage, uint8_t* pbyBuffer);
|
||||
|
||||
static int WINAPI hook_CXCMD_StandardInquiry(int iSlot, int iID, uint8_t* pbyBuffer);
|
||||
|
||||
static int WINAPI hook_CXCMD_ModeSense(int iSlot, int iID, int iPC, int iPage, uint8_t* pbyBuffer);
|
||||
|
||||
static int WINAPI hook_CXCMD_UpdateFirmware(int iSlot, int iID, char* pFile, int iDataID);
|
||||
|
||||
static int WINAPI hook_CXCMD_ModeSelect(int iSlot, int iID, int iSp, int iPage, uint8_t* pbyData);
|
||||
|
||||
static int WINAPI hook_CXCMD_GetPrintingStatus();
|
||||
|
||||
static int WINAPI hook_CXCMD_SendDiagnostic(int iSlot, int iID, int iTestMode, int iTestPatten, int iTestCount);
|
||||
|
||||
static int WINAPI hook_CXCMD_RetransferAndTurn(int slotId, int id, int immed);
|
||||
|
||||
static int WINAPI hook_CXCMD_LogSelect(int iSlot, int iID, int iMod);
|
||||
|
||||
static int WINAPI hook_CXCMD_ReadPosition(int slotId, int id, uint8_t* buffer);
|
||||
|
||||
static int WINAPI hook_CXCMD_SecurityLock();
|
||||
|
||||
static int WINAPI hook_CXCMD_SetPrintingStatus();
|
||||
|
||||
static int WINAPI hook_CXCMD_xReadISOMagData();
|
||||
|
||||
static int WINAPI hook_CXCMD_WriteISO3TrackMagData();
|
||||
|
||||
static int WINAPI hook_CXCMD_PasswordSet();
|
||||
|
||||
static int WINAPI hook_CXCMD_GetPrinterStatus();
|
||||
|
||||
static int WINAPI hook_CXCMD_WriteProjectCode();
|
||||
|
||||
static int WINAPI hook_CXCMD_LoadCard(int slotId, int id, int dest, int flip, int filmInit, int immed);
|
||||
|
||||
static int WINAPI hook_CXCMD_ReadMagData();
|
||||
|
||||
static int WINAPI hook_CXCMD_ScanPrinter(int* pSlotId, int* pId);
|
||||
|
||||
static int WINAPI hook_CXCMD_xWriteISOMagData();
|
||||
|
||||
static int WINAPI hook_CXCMD_ICControl();
|
||||
|
||||
static int WINAPI hook_CXCMD_ImageOut(int slotId, int id, uint8_t* plane, int length, int color, int bufferIndex);
|
||||
|
||||
static int WINAPI hook_CXCMD_ReadBuffer(int iSlot, int iID, int iMode, int iBufferID, uint8_t* pbyData, int iOffset,
|
||||
int iLength);
|
||||
|
||||
static int WINAPI hook_CXCMD_xReadMagData();
|
||||
|
||||
static int WINAPI hook_CXCMD_WriteBuffer(int iSlot, int iID, int iMode, int iBufferID, uint8_t* pbyData, int iOffset,
|
||||
int iLength);
|
||||
|
||||
static int WINAPI hook_CXCMD_DefineLUT(int slotId, int id, int color, int length, uint8_t* buffer);
|
||||
|
||||
static int WINAPI hook_CXCMD_ReadISO3TrackMagData();
|
||||
|
||||
static int WINAPI hook_CXCMD_TestUnitReady(int slotId, int id);
|
||||
|
||||
static int WINAPI hook_CXCMD_RetransferAndEject(int slotId, int id, int immed);
|
||||
|
||||
static bool WINAPI hook_Lut24_Exchange(const wchar_t* pFile, uint8_t* y, uint8_t* m, uint8_t* c, int sizeY, int sizeM,
|
||||
int sizeC);
|
||||
|
||||
static bool WINAPI hook_Wdata_create(uint8_t* pbyRdata, uint8_t* pbyGdata, uint8_t* pbyBdata, int iWidth,
|
||||
int iHeight, bool bPortrait, int iAlgorithim, uint8_t* pbyWdata);
|
||||
#pragma endregion
|
||||
|
||||
#pragma region hooktables
|
||||
static const struct hook_symbol hook_pcp_syms[] = {
|
||||
{
|
||||
.name = "CXCMD_Retransfer",
|
||||
.patch = hook_CXCMD_Retransfer,
|
||||
.ordinal = 19,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_CheckIfConnected",
|
||||
.patch = hook_CXCMD_CheckIfConnected,
|
||||
.ordinal = 1,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_xImageOut",
|
||||
.patch = hook_CXCMD_xImageOut,
|
||||
.ordinal = 36,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_MoveCard",
|
||||
.patch = hook_CXCMD_MoveCard,
|
||||
.ordinal = 12,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_xWriteMagData",
|
||||
.patch = hook_CXCMD_xWriteMagData,
|
||||
.ordinal = 40,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_SecurityPrint",
|
||||
.patch = hook_CXCMD_SecurityPrint,
|
||||
.ordinal = 26,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_ScanPrinterNext",
|
||||
.patch = hook_CXCMD_ScanPrinterNext,
|
||||
.ordinal = 24,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_Print",
|
||||
.patch = hook_CXCMD_Print,
|
||||
.ordinal = 14,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_RezeroUnit",
|
||||
.patch = hook_CXCMD_RezeroUnit,
|
||||
.ordinal = 22,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_WriteMagData",
|
||||
.patch = hook_CXCMD_WriteMagData,
|
||||
.ordinal = 34,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_LogSense",
|
||||
.patch = hook_CXCMD_LogSense,
|
||||
.ordinal = 9,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_StandardInquiry",
|
||||
.patch = hook_CXCMD_StandardInquiry,
|
||||
.ordinal = 29,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_ModeSense",
|
||||
.patch = hook_CXCMD_ModeSense,
|
||||
.ordinal = 11,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_UpdateFirmware",
|
||||
.patch = hook_CXCMD_UpdateFirmware,
|
||||
.ordinal = 31,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_ModeSelect",
|
||||
.patch = hook_CXCMD_ModeSelect,
|
||||
.ordinal = 10,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_GetPrintingStatus",
|
||||
.patch = hook_CXCMD_GetPrintingStatus,
|
||||
.ordinal = 4,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_SendDiagnostic",
|
||||
.patch = hook_CXCMD_SendDiagnostic,
|
||||
.ordinal = 27,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_RetransferAndTurn",
|
||||
.patch = hook_CXCMD_RetransferAndTurn,
|
||||
.ordinal = 21,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_LogSelect",
|
||||
.patch = hook_CXCMD_LogSelect,
|
||||
.ordinal = 8,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_ReadPosition",
|
||||
.patch = hook_CXCMD_ReadPosition,
|
||||
.ordinal = 18,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_SecurityLock",
|
||||
.patch = hook_CXCMD_SecurityLock,
|
||||
.ordinal = 25,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_SetPrintingStatus",
|
||||
.patch = hook_CXCMD_SetPrintingStatus,
|
||||
.ordinal = 28,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_xReadISOMagData",
|
||||
.patch = hook_CXCMD_xReadISOMagData,
|
||||
.ordinal = 37,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_WriteISO3TrackMagData",
|
||||
.patch = hook_CXCMD_WriteISO3TrackMagData,
|
||||
.ordinal = 33,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_PasswordSet",
|
||||
.patch = hook_CXCMD_PasswordSet,
|
||||
.ordinal = 13,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_GetPrinterStatus",
|
||||
.patch = hook_CXCMD_GetPrinterStatus,
|
||||
.ordinal = 3,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_WriteProjectCode",
|
||||
.patch = hook_CXCMD_WriteProjectCode,
|
||||
.ordinal = 35,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_LoadCard",
|
||||
.patch = hook_CXCMD_LoadCard,
|
||||
.ordinal = 7,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_ReadMagData",
|
||||
.patch = hook_CXCMD_ReadMagData,
|
||||
.ordinal = 17,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_ScanPrinter",
|
||||
.patch = hook_CXCMD_ScanPrinter,
|
||||
.ordinal = 23,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_xWriteISOMagData",
|
||||
.patch = hook_CXCMD_xWriteISOMagData,
|
||||
.ordinal = 39,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_ICControl",
|
||||
.patch = hook_CXCMD_ICControl,
|
||||
.ordinal = 5,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_ImageOut",
|
||||
.patch = hook_CXCMD_ImageOut,
|
||||
.ordinal = 6,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_ReadBuffer",
|
||||
.patch = hook_CXCMD_ReadBuffer,
|
||||
.ordinal = 15,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_xReadMagData",
|
||||
.patch = hook_CXCMD_xReadMagData,
|
||||
.ordinal = 38,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_WriteBuffer",
|
||||
.patch = hook_CXCMD_WriteBuffer,
|
||||
.ordinal = 32,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_DefineLUT",
|
||||
.patch = hook_CXCMD_DefineLUT,
|
||||
.ordinal = 2,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_ReadISO3TrackMagData",
|
||||
.patch = hook_CXCMD_ReadISO3TrackMagData,
|
||||
.ordinal = 16,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_TestUnitReady",
|
||||
.patch = hook_CXCMD_TestUnitReady,
|
||||
.ordinal = 30,
|
||||
},
|
||||
{
|
||||
.name = "CXCMD_RetransferAndEject",
|
||||
.patch = hook_CXCMD_RetransferAndEject,
|
||||
.ordinal = 20,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct hook_symbol hook_lut_syms[] = {
|
||||
{
|
||||
.name = "Lut24_Exchange",
|
||||
.patch = hook_Lut24_Exchange,
|
||||
.ordinal = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct hook_symbol hook_wdata_syms[] = {
|
||||
{
|
||||
.name = "Wdata_create",
|
||||
.patch = hook_Wdata_create,
|
||||
.ordinal = 1,
|
||||
},
|
||||
};
|
||||
#pragma endregion
|
||||
|
||||
static void write_int(uint8_t* data, int index, int value) {
|
||||
data[index] = value >> 24;
|
||||
data[index + 1] = value >> 16;
|
||||
data[index + 2] = value >> 8;
|
||||
data[index + 3] = value;
|
||||
}
|
||||
|
||||
static void write_short(uint8_t* data, int index, short value) {
|
||||
data[index] = value >> 8;
|
||||
data[index + 1] = value;
|
||||
}
|
||||
|
||||
static struct printer_cx_config printer_config;
|
||||
static wchar_t printer_out_path[MAX_PATH];
|
||||
static struct printer_cx_data printer_data;
|
||||
|
||||
#define HEIGHT 664
|
||||
#define WIDTH 1036
|
||||
#define IMAGE_BUFFER_SIZE WIDTH * HEIGHT
|
||||
static uint8_t* back_buffer = NULL;
|
||||
static uint8_t* front_buffer = NULL;
|
||||
static uint64_t current_card_id;
|
||||
|
||||
DWORD load_printer_data() {
|
||||
DWORD bytesRead = 0;
|
||||
HANDLE hSave = CreateFileW(printer_config.printer_data_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hSave != INVALID_HANDLE_VALUE) {
|
||||
if (!ReadFile(hSave, &printer_data, sizeof(printer_data), &bytesRead, NULL)){
|
||||
CloseHandle(hSave);
|
||||
return GetLastError();
|
||||
}
|
||||
CloseHandle(hSave);
|
||||
if (bytesRead != sizeof(printer_data)){
|
||||
return -1;
|
||||
}
|
||||
if (printer_data.version != PRINTER_DATA_VERSION) {
|
||||
return -2;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
return GetLastError();
|
||||
}
|
||||
}
|
||||
|
||||
DWORD save_printer_data() {
|
||||
DWORD bytesWritten = 0;
|
||||
HANDLE hSave = CreateFileW(printer_config.printer_data_path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hSave != NULL) {
|
||||
if (!WriteFile(hSave, &printer_data, sizeof(printer_data), &bytesWritten, NULL)){
|
||||
CloseHandle(hSave);
|
||||
dprintf("CX7000: Failed writing data: %lx\n", GetLastError());
|
||||
return GetLastError();
|
||||
}
|
||||
CloseHandle(hSave);
|
||||
return 0;
|
||||
} else {
|
||||
dprintf("CX7000: Failed opening data file for writing: %lx\n", GetLastError());
|
||||
return GetLastError();
|
||||
}
|
||||
}
|
||||
|
||||
void printer_cx_hook_init(const struct printer_cx_config* cfg, HINSTANCE self) {
|
||||
assert(cfg != NULL);
|
||||
|
||||
if (!cfg->enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&printer_config, cfg, sizeof(*cfg));
|
||||
printer_cx_hook_insert_hooks(NULL);
|
||||
|
||||
CreateDirectoryW(cfg->printer_out_path, NULL);
|
||||
memcpy(printer_out_path, cfg->printer_out_path, MAX_PATH);
|
||||
|
||||
if (load_printer_data() != 0) {
|
||||
memset(&printer_data, 0, sizeof(printer_data));
|
||||
printer_data.version = PRINTER_DATA_VERSION;
|
||||
if (save_printer_data() == 0) {
|
||||
dprintf("CX7000: Printer data initialized.\n");
|
||||
}
|
||||
}
|
||||
|
||||
dprintf("CX7000: hook enabled.\n");
|
||||
}
|
||||
|
||||
void printer_cx_hook_insert_hooks(HMODULE target) {
|
||||
hook_table_apply(target, "PCP21CT64.dll", hook_pcp_syms, _countof(hook_pcp_syms));
|
||||
hook_table_apply(target, "LUT24EXG64.dll", hook_lut_syms, _countof(hook_lut_syms));
|
||||
hook_table_apply(target, "WCREATE64.dll", hook_wdata_syms, _countof(hook_wdata_syms));
|
||||
|
||||
/* Unity workaround */
|
||||
proc_addr_table_push(target, "PCP21CT64.dll", hook_pcp_syms, _countof(hook_pcp_syms));
|
||||
proc_addr_table_push(target, "LUT24EXG64.dll", hook_lut_syms, _countof(hook_lut_syms));
|
||||
proc_addr_table_push(target, "WCREATE64.dll", hook_wdata_syms, _countof(hook_wdata_syms));
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_Retransfer() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static bool WINAPI hook_CXCMD_CheckIfConnected(int* pSlotId, int* pId) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
return printer_config.enable;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_xImageOut() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_MoveCard(int slotId, int id, int dest, int flip, int filmInit, int immed) {
|
||||
dprintf("CX7000: %s(%d, %d, %d, %d)\n", __func__, dest, flip, filmInit, immed);
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_xWriteMagData() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_SecurityPrint(int slotId, int id, int color, int bufferIndex, int immed) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_ScanPrinterNext() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_ImageOut(int slotId, int id, uint8_t* plane, int length, int color, int bufferIndex) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
|
||||
assert(color >= 0 && color <= 3);
|
||||
assert(bufferIndex >= 0 && bufferIndex <= 1);
|
||||
assert(length == IMAGE_BUFFER_SIZE);
|
||||
|
||||
// colorIndex: 0 = w, 1 = c, 2 = m, 3 = y
|
||||
// bufferIndex: 0 = back, 1 = front
|
||||
|
||||
if (bufferIndex == 0) {
|
||||
if (back_buffer == NULL) {
|
||||
back_buffer = (uint8_t*) malloc(4 * IMAGE_BUFFER_SIZE);
|
||||
}
|
||||
memcpy(back_buffer + color * IMAGE_BUFFER_SIZE, plane, length);
|
||||
} else {
|
||||
if (front_buffer == NULL) {
|
||||
front_buffer = (uint8_t*) malloc(4 * IMAGE_BUFFER_SIZE);
|
||||
}
|
||||
memcpy(front_buffer + color * IMAGE_BUFFER_SIZE, plane, length);
|
||||
}
|
||||
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_Print(int slotId, int id, int color, int bufferIndex, int immed) {
|
||||
dprintf("CX7000: %s(%d, %d, %d)\n", __func__, color, bufferIndex, immed);
|
||||
|
||||
assert(bufferIndex >= 0 && bufferIndex <= 1);
|
||||
|
||||
SYSTEMTIME t;
|
||||
GetLocalTime(&t);
|
||||
|
||||
// color: 1 = back, 3 = front
|
||||
// bufferIndex: 0 = back, 1 = front
|
||||
|
||||
wchar_t dumpPath[MAX_PATH];
|
||||
uint8_t metadata[5];
|
||||
|
||||
metadata[0] = current_card_id >> 32;
|
||||
write_int(metadata, 1, (int32_t)current_card_id);
|
||||
|
||||
swprintf_s(
|
||||
dumpPath, MAX_PATH,
|
||||
L"%s\\CX7000_%04d%02d%02d_%02d%02d%02d_%s.bmp",
|
||||
printer_out_path, t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond, bufferIndex == 0 ? L"back" : L"front");
|
||||
|
||||
// convert image from seperate CMY arrays to one RGB array
|
||||
int size = IMAGE_BUFFER_SIZE * 3;
|
||||
uint8_t* raw_image = (uint8_t*) malloc(size);
|
||||
for (int i = 0; i < IMAGE_BUFFER_SIZE; i++) {
|
||||
// 0 is "white" and we don't really care about that
|
||||
raw_image[i * 3] = 0xFF - *((bufferIndex == 0 ? back_buffer : front_buffer) + IMAGE_BUFFER_SIZE + i);
|
||||
raw_image[i * 3 + 1] = 0xFF - *((bufferIndex == 0 ? back_buffer : front_buffer) + 2 * IMAGE_BUFFER_SIZE + i);
|
||||
raw_image[i * 3 + 2] = 0xFF - *((bufferIndex == 0 ? back_buffer : front_buffer) + 3 * IMAGE_BUFFER_SIZE + i);
|
||||
}
|
||||
|
||||
dprintf("CX7000: Saving %s image to %ls\n", bufferIndex == 0 ? "back" : "front", dumpPath);
|
||||
|
||||
int ret = WriteDataToBitmapFile(dumpPath, 24, WIDTH, HEIGHT, raw_image, size, metadata, 5, false);
|
||||
|
||||
free(raw_image);
|
||||
if (bufferIndex == 0) {
|
||||
free(back_buffer);
|
||||
back_buffer = NULL;
|
||||
} else {
|
||||
free(front_buffer);
|
||||
front_buffer = NULL;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
dprintf("CX7000: WriteDataToBitmapFile returned %d\n", ret);
|
||||
return CX_ERROR_FATAL_3301;
|
||||
}
|
||||
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_RezeroUnit(int slotId, int id, int action) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_WriteMagData() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_LogSense(int iSlot, int iID, int iPage, uint8_t* pbyBuffer) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
|
||||
const int size = 108;
|
||||
memset(pbyBuffer, 0, size);
|
||||
|
||||
|
||||
if (iPage == 56) {
|
||||
dprintf("CX7000: MediumQuantity\n");
|
||||
|
||||
write_int(pbyBuffer, 8, (int)printer_data.print_counter); // total count
|
||||
write_int(pbyBuffer, 16, 22); // free count
|
||||
write_int(pbyBuffer, 24, 33); // head count
|
||||
write_int(pbyBuffer, 32, (int)printer_data.print_counter_since_clean); // cleaning count
|
||||
write_int(pbyBuffer, 40, 55); // error count
|
||||
write_int(pbyBuffer, 48, 66); // cru cleaning count
|
||||
|
||||
return CX_OK;
|
||||
} else if (iPage == 57) {
|
||||
dprintf("CX7000: Miscellaneous\n");
|
||||
|
||||
write_int(pbyBuffer, 16, 234); // re transfer hr power on time
|
||||
write_int(pbyBuffer, 24, 456); // remedy hr power on time
|
||||
write_int(pbyBuffer, 40, 789); // unresettable re transfer hr power on time
|
||||
write_int(pbyBuffer, 48, 1023); // unresettable remedy hr power on time
|
||||
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
dprintf("CX7000: Unknown LogSense\n");
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_StandardInquiry(int iSlot, int iID, uint8_t* pbyBuffer) {
|
||||
const int size = 96;
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
|
||||
memset(pbyBuffer, 0, size);
|
||||
memcpy(pbyBuffer + 32, printer_config.printer_firm_version, 8);
|
||||
memcpy(pbyBuffer + 50, printer_config.printer_camera_version, 8);
|
||||
memcpy(pbyBuffer + 71, printer_config.printer_config_version, 8);
|
||||
memcpy(pbyBuffer + 79, printer_config.printer_table_version, 8);
|
||||
//memcpy(pbyBuffer + 58, printer_config.thermal_head_info, 13); // unused
|
||||
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_ModeSense(int iSlot, int iID, int iPC, int iPage, uint8_t* pbyBuffer) {
|
||||
dprintf("CX7000: %s(%d, %d)\n", __func__, iPC, iPage);
|
||||
|
||||
const int size = 104;
|
||||
memset(pbyBuffer, 0, size);
|
||||
|
||||
if (iPC == 1 && iPage == 40) { // GetMediaInfo
|
||||
pbyBuffer[51] = 10; // film count (10=100%)
|
||||
pbyBuffer[52] = 50; // ink count (50=100%)
|
||||
return CX_OK;
|
||||
} else if (iPC == 1 && iPage == 35) { // ReadInkInfo
|
||||
pbyBuffer[6] = 0; // "b"
|
||||
write_short(pbyBuffer, 8, 50); // Remain
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
dprintf("CX7000: Unknown ModeSense\n");
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_UpdateFirmware(int iSlot, int iID, char* pFile, int iDataID) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // intentionally not implemented
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_ModeSelect(int iSlot, int iID, int iSp, int iPage, uint8_t* pbyData) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_GetPrintingStatus() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_SendDiagnostic(int iSlot, int iID, int iTestMode, int iTestPatten, int iTestCount) {
|
||||
dprintf("CX7000: %s(%d, %d, %d)\n", __func__, iTestMode, iTestPatten, iTestCount);
|
||||
if (iTestMode == 19) {
|
||||
dprintf("CX7000: Printer Front Buttons Enabled: %d\n", iTestPatten);
|
||||
return CX_OK;
|
||||
} else if (iTestMode == 17) {
|
||||
dprintf("CX7000: Printer was cleaned (haha)\n");
|
||||
printer_data.print_counter_since_clean = 0;
|
||||
save_printer_data();
|
||||
return CX_OK;
|
||||
} else if (iTestMode == 18) {
|
||||
dprintf("CX7000: Transport Mode enabled\n");
|
||||
printer_data.is_transport = true;
|
||||
save_printer_data();
|
||||
return CX_OK;
|
||||
} else if (iTestMode == 20) {
|
||||
dprintf("CX7000: Transport Mode disabled\n");
|
||||
printer_data.is_transport = false;
|
||||
save_printer_data();
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
dprintf("CX7000: Unknown SendDiagnostic\n");
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_RetransferAndTurn(int slotId, int id, int immed) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_LogSelect(int iSlot, int iID, int iMod) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_ReadPosition(int slotId, int id, uint8_t* buffer) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
const int size = 8;
|
||||
|
||||
memset(buffer, 0, size);
|
||||
buffer[0] = 1 << 2; // IsExist (0 means YES!)
|
||||
buffer[7] = 0; // position (of card; 0 = printer, 1 = "IR")
|
||||
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_SecurityLock() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_SetPrintingStatus() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_xReadISOMagData() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_WriteISO3TrackMagData() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_PasswordSet() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_GetPrinterStatus() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_WriteProjectCode() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_LoadCard(int slotId, int id, int dest, int flip, int filmInit, int immed) {
|
||||
dprintf("CX7000: %s(%d, %d, %d, %d)\n", __func__, dest, flip, filmInit, immed);
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_ReadMagData() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_ScanPrinter(int* pSlotId, int* pId) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
|
||||
if (!printer_config.enable) {
|
||||
return CX_ERROR_NOT_CONNECTED_6804;
|
||||
}
|
||||
|
||||
*pSlotId = 1;
|
||||
*pId = 1;
|
||||
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_xWriteISOMagData() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_ICControl() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_ReadBuffer(int iSlot, int iID, int iMode, int iBufferID, uint8_t* pbyData, int iOffset,
|
||||
int iLength) {
|
||||
dprintf("CX7000: %s(%d, %d, %d)\n", __func__, iMode, iBufferID, iLength);
|
||||
|
||||
memset(pbyData, 0, iLength);
|
||||
|
||||
if (iMode == 2 && iBufferID == 87 && iLength == 10) {
|
||||
dprintf("CX7000: ReadCondition\n");
|
||||
|
||||
pbyData[0] = printer_data.is_transport; // transport mode
|
||||
pbyData[1] = 0; // head white ink level, unused
|
||||
pbyData[2] = 0; // main white ink level, unused
|
||||
pbyData[3] = 0; // total white ink level, unused
|
||||
|
||||
return CX_OK;
|
||||
} else if (iMode == 2 && iBufferID == 112 && iLength == 6) {
|
||||
dprintf("CX7000: GetMacAddress\n");
|
||||
|
||||
pbyData[0] = 0x12; // displays in test menu, else ununused?
|
||||
pbyData[1] = 0x34;
|
||||
pbyData[2] = 0x56;
|
||||
pbyData[3] = 0x78;
|
||||
pbyData[4] = 0x9A;
|
||||
pbyData[5] = 0xBC;
|
||||
|
||||
return CX_OK;
|
||||
} else if (iMode == 2 && iBufferID == 82 && iLength == 4) {
|
||||
dprintf("CX7000: GetCleaningWaitCount\n");
|
||||
|
||||
// seemingly unused
|
||||
write_short(pbyData, 0, 0);
|
||||
|
||||
return CX_OK;
|
||||
} else if (iMode == 2 && iBufferID == 85 && iLength == 10) {
|
||||
dprintf("CX7000: GetSensorInfo\n");
|
||||
|
||||
pbyData[0] = 244; // retransfer heat roller thermistor; must be over 243
|
||||
pbyData[1] = 0; // main pwb thermistor; unused
|
||||
pbyData[2] = 0; // thermal head thermistor; unused
|
||||
pbyData[3] = 0; // heater cover thermistor; unused
|
||||
|
||||
return CX_OK;
|
||||
} else if (iMode == 2 && iBufferID == 88 && iLength == 16) {
|
||||
dprintf("CX7000: ReadErrorStatus\n");
|
||||
|
||||
pbyData[1] = 0; // is door open?
|
||||
//pbyData[2...] = // any of the error codes that fit in a byte (from CX_ERROR_FATAL_3301 to CX_ERROR_PRINT_INTERRUPT_6805_3)
|
||||
|
||||
return CX_OK;
|
||||
} else if (iMode == 2 && iBufferID == 224 && iLength == 10) {
|
||||
dprintf("CX7000: ReadCode\n");
|
||||
|
||||
printer_data.print_counter_since_clean++;
|
||||
current_card_id = ++printer_data.print_counter;
|
||||
dprintf("CX7000: Generated new card ID: %lld\n", current_card_id);
|
||||
|
||||
save_printer_data();
|
||||
|
||||
pbyData[0] = current_card_id >> 32; // MSB of card id
|
||||
write_int(pbyData, 1, (int32_t)current_card_id); // lower 4 bytes of card id
|
||||
pbyData[5] = 0x0; // Direction (1 = rotate image by 180 degrees)
|
||||
pbyData[6] = 0x1; // CheckCode (0 = error)
|
||||
|
||||
return CX_OK;
|
||||
} else if (iMode == 2 && iBufferID == 144 && iLength == 260) {
|
||||
dprintf("CX7000: ReadErrorLog\n");
|
||||
|
||||
write_int(pbyData, 0, 0); // LogCount
|
||||
/*for (int i = 0; false; i++) { // list of error ids
|
||||
write_int(pbyData, i + 4, 0);
|
||||
}*/
|
||||
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
dprintf("CX7000: Unknown ReadBuffer\n");
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_xReadMagData() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_WriteBuffer(int iSlot, int iID, int iMode, int iBufferID, uint8_t* pbyData, int iOffset, // NOLINT(*-non-const-parameter)
|
||||
int iLength) {
|
||||
dprintf("CX7000: %s(%d, %d, %d, %d)\n", __func__, iMode, iBufferID, iOffset, iLength);
|
||||
if (iMode == 2 && iBufferID == 82 && iLength == 4) {
|
||||
int val = pbyData[0] << 8 | pbyData[1];
|
||||
dprintf("CX7000: Set cleaning limit: %d\n", val);
|
||||
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
dprintf("CX7000: Unknown WriteBuffer\n");
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_DefineLUT(int slotId, int id, int color, int length, uint8_t* buffer) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_ReadISO3TrackMagData() {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
dprintf("CX7000: Unimplemented\n"); // unused
|
||||
return CX_ERROR_USB_COM_3201;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_TestUnitReady(int slotId, int id) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
|
||||
if (!printer_config.enable) {
|
||||
return CX_ERROR_NOT_CONNECTED_6804;
|
||||
}
|
||||
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
static int WINAPI hook_CXCMD_RetransferAndEject(int slotId, int id, int immed) {
|
||||
dprintf("CX7000: %s\n", __func__);
|
||||
return CX_OK;
|
||||
}
|
||||
|
||||
static bool WINAPI hook_Lut24_Exchange(const wchar_t* pFile, uint8_t* y, uint8_t* m, uint8_t* c, int sizeY, int sizeM,
|
||||
int sizeC) {
|
||||
dprintf("CX7000: %s(%ls)\n", __func__, pFile);
|
||||
|
||||
// stub?
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool WINAPI hook_Wdata_create(uint8_t* pbyRdata, uint8_t* pbyGdata, uint8_t* pbyBdata, int iWidth,
|
||||
int iHeight, bool bPortrait, int iAlgorithim, uint8_t* pbyWdata) {
|
||||
dprintf("CX7000: %s(%d, %d, %d)\n", __func__, iHeight, bPortrait, iAlgorithim);
|
||||
|
||||
// stub?
|
||||
|
||||
return true;
|
||||
}
|
||||
73
common/hooklib/printer_cx.h
Normal file
73
common/hooklib/printer_cx.h
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
#pragma once
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
|
||||
#define PRINTER_DATA_VERSION 1
|
||||
|
||||
struct printer_cx_config {
|
||||
bool enable;
|
||||
wchar_t printer_out_path[MAX_PATH];
|
||||
wchar_t printer_data_path[MAX_PATH];
|
||||
char printer_firm_version[8];
|
||||
char printer_camera_version[8];
|
||||
char printer_config_version[8];
|
||||
char printer_table_version[8];
|
||||
};
|
||||
|
||||
struct printer_cx_data {
|
||||
uint8_t version;
|
||||
uint64_t print_counter;
|
||||
uint64_t print_counter_since_clean;
|
||||
bool is_transport;
|
||||
};
|
||||
|
||||
enum {
|
||||
CX_OK = 0,
|
||||
CX_ERROR_FATAL_3301 = -1,
|
||||
CX_ERROR_USB_COM_3201 = -2,
|
||||
CX_ERROR_PRINT_INTERRUPT_6805_4 = -4,
|
||||
CX_ERROR_CODE_UNREADABLE_3303 = -5,
|
||||
CX_ERROR_INK_LOW_3202 = -6,
|
||||
CX_ERROR_PRINT_INTERRUPT_6805_3 = -7,
|
||||
CX_ERROR_NO_CARD_6801 = -16961536,
|
||||
CX_ERROR_DOOR_OPEN_6808 = -16961792,
|
||||
CX_ERROR_6831 = -16963328,
|
||||
CX_ERROR_6810 = -16964864,
|
||||
CX_ERROR_CLEAN_PRINTER_3999 = -16973056,
|
||||
CX_ERROR_JAM_6805_1 = -17010688,
|
||||
CX_ERROR_REVERSE_JAM_6805_2 = -17010944,
|
||||
CX_ERROR_CAMERA_JAM_6805_3 = -17011200,
|
||||
CX_ERROR_TRANSPORT_JAM_6805_4 = -17011456,
|
||||
CX_ERROR_PAPER_SENSOR_JAM_6805_5 = -17011712,
|
||||
CX_ERROR_RETRANSFER_JAM_6805_6 = -17011968,
|
||||
CX_ERROR_PAPER_RIPPED_6813_3 = -17015040,
|
||||
CX_ERROR_CODE_READ_6811 = -17018112,
|
||||
CX_ERROR_UNAUTHORIZED_INK_6803_1 = -17018880,
|
||||
CX_ERROR_INK_EMPTY_6813_1 = -17019136,
|
||||
CX_ERROR_PRINT_TIMEOUT_6810_3 = -17056768,
|
||||
CX_ERROR_CAMERA_HARDWARE_FAULT_6810_5 = -17083136,
|
||||
CX_ERROR_CAMERA_COM_6810_6 = -17083392,
|
||||
CX_ERROR_ROLLER_6810_15 = -17088768,
|
||||
CX_ERROR_OVER_TEMPERATURE_6810_16 = -17089024,
|
||||
CX_ERROR_POWER_INTERRUPT_6810_1 = -17089280,
|
||||
CX_ERROR_INITIALIZATION_6810_2 = -17094656,
|
||||
CX_ERROR_OVER_TEMPERATURE_6810_10 = -17100800,
|
||||
CX_ERROR_RETRANSFER_ROLLER_6810_11 = -17101056,
|
||||
CX_ERROR_THERMOSTAT_6810_12 = -17101312,
|
||||
CX_ERROR_OVER_TEMPERATURE_6810_20 = -17101568,
|
||||
CX_ERROR_STRAIGHTEN_ROLLER_6810_21 = -17101824,
|
||||
CX_ERROR_THERMOSTAT_6810_22 = -17102080,
|
||||
CX_ERROR_PRINTER_TOO_COLD_6833_1 = -16971264,
|
||||
CX_ERROR_OVER_TEMPERATURE_6810_25 = -17102848,
|
||||
CX_ERROR_CAMERA_NOT_FOUND_6810_7 = -17116672,
|
||||
CX_ERROR_RETRANSFER_ROLL_EMPTY_6802_3 = -21144064,
|
||||
CX_ERROR_INK_ROLL_EMPTY_6802_1 = -21148160,
|
||||
CX_ERROR_NOT_CONNECTED_6804 = -33554432,
|
||||
CX_ERROR_CAMERA_JAM_6805_7 = -17012224,
|
||||
CX_ERROR_INVALID_CLEANING_CARD_6832_1 = -16965376,
|
||||
CX_ERROR_TEMPERATURE_RESOLVED_6833_2 = -16971520,
|
||||
};
|
||||
|
||||
void printer_cx_hook_init(const struct printer_cx_config *cfg, HINSTANCE self);
|
||||
void printer_cx_hook_insert_hooks(HMODULE target);
|
||||
|
|
@ -89,29 +89,6 @@ static void spike_fn_perror(
|
|||
OutputDebugStringA(line);
|
||||
}
|
||||
|
||||
BOOL is_current_module_x64()
|
||||
{
|
||||
HMODULE hModule = GetModuleHandleW(NULL);
|
||||
MODULEINFO moduleInfo = {0};
|
||||
if (!GetModuleInformation(GetCurrentProcess(), hModule, &moduleInfo,
|
||||
sizeof(moduleInfo))) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)moduleInfo.lpBaseOfDll;
|
||||
PIMAGE_NT_HEADERS ntHeaders =
|
||||
(PIMAGE_NT_HEADERS)((BYTE *)moduleInfo.lpBaseOfDll +
|
||||
dosHeader->e_lfanew);
|
||||
|
||||
if (ntHeaders->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64) {
|
||||
return TRUE;
|
||||
} else if (ntHeaders->FileHeader.Machine == IMAGE_FILE_MACHINE_I386) {
|
||||
return FALSE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL is_valid_rva(LPCWSTR module_name, uintptr_t rva) {
|
||||
HMODULE module_base = GetModuleHandleW(module_name);
|
||||
if (!module_base) {
|
||||
|
|
@ -136,19 +113,18 @@ static void spike_insert_jmp(LPCWSTR module_name, uintptr_t rva, void *proc) {
|
|||
uintptr_t target_addr = (uintptr_t)target;
|
||||
uintptr_t func_addr = (uintptr_t)func_ptr;
|
||||
|
||||
if (is_current_module_x64()) {
|
||||
#if defined(_WIN64) || defined(__amd64__)
|
||||
uint64_t relativeOffset = (uint64_t)(func_addr - target_addr - 5);
|
||||
uint8_t absoluteJump[] = {0x48, 0xB8, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0};
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0};
|
||||
memcpy(absoluteJump + 2, &func_ptr, 8);
|
||||
pe_patch(target, absoluteJump, sizeof(absoluteJump));
|
||||
}
|
||||
else {
|
||||
#else
|
||||
uint32_t jumpOffset = (uint32_t)(func_addr - target_addr - 5);
|
||||
uint8_t relativeJump[] = {0xE9, 0x00, 0x00, 0x00, 0x00};
|
||||
memcpy(relativeJump + 1, &jumpOffset, 4);
|
||||
pe_patch(target, relativeJump, sizeof(relativeJump));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void spike_insert_ptr(LPCWSTR module_name, uintptr_t rva, void *ptr) {
|
||||
|
|
@ -242,7 +218,7 @@ void spike_hook_init(const wchar_t *ini_file)
|
|||
basename = slash + 1;
|
||||
} else {
|
||||
basename = module;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check our INI file to see if any spikes are configured for this EXE.
|
||||
Normally we separate out config reading into a separate module... */
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ static BOOL WINAPI hook_GetTouchInputInfo(
|
|||
|
||||
static HCURSOR WINAPI hook_SetCursor(HCURSOR cursor);
|
||||
|
||||
static int WINAPI hook_ShowCursor(BOOL bShow);
|
||||
|
||||
/* Link pointers */
|
||||
|
||||
static ATOM (WINAPI *next_RegisterClassExA)(
|
||||
|
|
@ -67,6 +69,9 @@ static BOOL (WINAPI *next_GetTouchInputInfo)(
|
|||
|
||||
static HCURSOR(WINAPI *next_SetCursor)(HCURSOR cursor);
|
||||
|
||||
static int (WINAPI *next_ShowCursor)(BOOL bShow);
|
||||
|
||||
|
||||
static bool touch_hook_initted;
|
||||
static bool touch_held;
|
||||
static HWND registered_hWnd;
|
||||
|
|
@ -100,6 +105,11 @@ static const struct hook_symbol touch_hooks[] = {
|
|||
.patch = hook_SetCursor,
|
||||
.link = (void **) &next_SetCursor
|
||||
},
|
||||
{
|
||||
.name = "ShowCursor",
|
||||
.patch = hook_ShowCursor,
|
||||
.link = (void **) &next_ShowCursor
|
||||
},
|
||||
};
|
||||
|
||||
void touch_screen_hook_init(const struct touch_screen_config *cfg, HINSTANCE self)
|
||||
|
|
@ -132,8 +142,15 @@ void touch_hook_insert_hooks(HMODULE target)
|
|||
_countof(touch_hooks));
|
||||
}
|
||||
|
||||
static int WINAPI hook_ShowCursor(BOOL bShow) {
|
||||
if (touch_config.cursor)
|
||||
return next_ShowCursor(1);
|
||||
|
||||
return next_ShowCursor(bShow);
|
||||
}
|
||||
|
||||
static HCURSOR WINAPI hook_SetCursor(HCURSOR cursor) {
|
||||
if (cursor == 0 && touch_config.cursor)
|
||||
if (touch_config.cursor)
|
||||
return next_SetCursor(defaultCursor);
|
||||
|
||||
return next_SetCursor(cursor);
|
||||
|
|
|
|||
109
common/hooklib/y3-dll.c
Normal file
109
common/hooklib/y3-dll.c
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "hooklib/config.h"
|
||||
|
||||
#include "util/dll-bind.h"
|
||||
#include "util/dprintf.h"
|
||||
|
||||
#include "y3.h"
|
||||
#include "y3-dll.h"
|
||||
|
||||
const struct dll_bind_sym y3_dll_syms[] = {
|
||||
{
|
||||
.sym = "y3_io_init",
|
||||
.off = offsetof(struct y3_dll, init),
|
||||
}, {
|
||||
.sym = "y3_io_get_cards",
|
||||
.off = offsetof(struct y3_dll, get_cards),
|
||||
}, {
|
||||
.sym = "y3_io_close",
|
||||
.off = offsetof(struct y3_dll, close),
|
||||
}
|
||||
};
|
||||
|
||||
struct y3_dll y3_dll;
|
||||
|
||||
// Copypasta DLL binding and diagnostic message boilerplate.
|
||||
// Not much of this lends itself to being easily factored out. Also there
|
||||
// will be a lot of API-specific branching code here eventually as new API
|
||||
// versions get defined, so even though these functions all look the same
|
||||
// now this won't remain the case forever.
|
||||
|
||||
HRESULT y3_dll_init(const struct y3_dll_config *cfg, HINSTANCE self)
|
||||
{
|
||||
uint16_t (*get_api_version)(void);
|
||||
const struct dll_bind_sym *sym;
|
||||
HINSTANCE owned;
|
||||
HINSTANCE src;
|
||||
HRESULT hr;
|
||||
|
||||
assert(cfg != NULL);
|
||||
assert(self != NULL);
|
||||
|
||||
if (cfg->path[0] != L'\0') {
|
||||
owned = LoadLibraryW(cfg->path);
|
||||
|
||||
if (owned == NULL) {
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
dprintf("Y3: Failed to load IO DLL: %lx: %S\n",
|
||||
hr,
|
||||
cfg->path);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
dprintf("Y3: Using custom IO DLL: %S\n", cfg->path);
|
||||
src = owned;
|
||||
} else {
|
||||
owned = NULL;
|
||||
src = self;
|
||||
}
|
||||
|
||||
get_api_version = (void *) GetProcAddress(src, "y3_io_get_api_version");
|
||||
|
||||
if (get_api_version != NULL) {
|
||||
y3_dll.api_version = get_api_version();
|
||||
} else {
|
||||
y3_dll.api_version = 0x0100;
|
||||
dprintf("Custom IO DLL does not expose y3_io_get_api_version, "
|
||||
"assuming API version 1.0.\n"
|
||||
"Please ask the developer to update their DLL.\n");
|
||||
}
|
||||
|
||||
if (y3_dll.api_version >= 0x0200) {
|
||||
hr = E_NOTIMPL;
|
||||
dprintf("Y3: Custom IO DLL implements an unsupported "
|
||||
"API version (%#04x). Please update Segatools.\n",
|
||||
y3_dll.api_version);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
sym = y3_dll_syms;
|
||||
hr = dll_bind(&y3_dll, src, &sym, _countof(y3_dll_syms));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
if (src != self) {
|
||||
dprintf("Y3: Custom IO DLL does not provide function "
|
||||
"\"%s\". Please contact your IO DLL's developer for "
|
||||
"further assistance.\n",
|
||||
sym->sym);
|
||||
|
||||
goto end;
|
||||
} else {
|
||||
dprintf("Internal error: could not reflect \"%s\"\n", sym->sym);
|
||||
}
|
||||
}
|
||||
|
||||
owned = NULL;
|
||||
|
||||
end:
|
||||
if (owned != NULL) {
|
||||
FreeLibrary(owned);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
19
common/hooklib/y3-dll.h
Normal file
19
common/hooklib/y3-dll.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hooklib/y3.h"
|
||||
|
||||
|
||||
struct y3_dll {
|
||||
uint16_t api_version;
|
||||
HRESULT (*init)(void);
|
||||
HRESULT (*close)(void);
|
||||
HRESULT (*get_cards)(struct CardInfo* cards, int* len);
|
||||
};
|
||||
|
||||
extern struct y3_dll y3_dll;
|
||||
|
||||
HRESULT y3_dll_init(const struct y3_dll_config *cfg, HINSTANCE self);
|
||||
625
common/hooklib/y3.c
Normal file
625
common/hooklib/y3.c
Normal file
|
|
@ -0,0 +1,625 @@
|
|||
// ReSharper disable CppParameterNeverUsed
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "y3.h"
|
||||
|
||||
#include "hook/table.h"
|
||||
#include "hook/procaddr.h"
|
||||
|
||||
#include "hooklib/y3-dll.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
#if _WIN32 || _WIN64
|
||||
#if _WIN64
|
||||
#define ENV64BIT
|
||||
#else
|
||||
#define ENV32BIT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Check GCC
|
||||
#if __GNUC__
|
||||
#if __x86_64__ || __ppc64__
|
||||
#define ENV64BIT
|
||||
#else
|
||||
#define ENV32BIT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ENV64BIT
|
||||
#define CALL
|
||||
#else
|
||||
#define CALL __cdecl
|
||||
#endif
|
||||
|
||||
float CALL API_DLLVersion();
|
||||
uint32_t CALL API_GetLastError(int* hDevice);
|
||||
uint32_t CALL API_GetErrorMessage(uint32_t errNo, char* szMessage, int numBytes);
|
||||
int* CALL API_Connect(char* szPortName);
|
||||
int CALL API_Close(int* hDevice);
|
||||
int CALL API_Start(int* hDevice);
|
||||
int CALL API_Stop(int* hDevice);
|
||||
float CALL API_GetFirmVersion(int* hDevice);
|
||||
uint32_t CALL API_GetFirmName(int* hDevice);
|
||||
uint32_t CALL API_GetTargetCode(int* hDevice);
|
||||
uint32_t CALL API_GetStatus(int* hDevice);
|
||||
uint32_t CALL API_GetCounter(int* hDevice);
|
||||
int CALL API_ClearError(int* hDevice);
|
||||
int CALL API_Reset(int* hDevice, bool isHardReset);
|
||||
int CALL API_GetCardInfo(int* hDevice, int numCards, struct CardInfo* pCardInfo);
|
||||
int CALL API_GetCardInfoCharSize();
|
||||
int CALL API_FirmwareUpdate(int* hDevice, uint32_t address, uint32_t size, uint8_t* buffer);
|
||||
int CALL API_Calibration(int* hDevice, int calib);
|
||||
int CALL API_GetCalibrationResult(int* hDevice, int calib, uint32_t* result);
|
||||
uint32_t CALL API_GetProcTime(int* hDevice);
|
||||
uint32_t CALL API_GetMemStatus(int* hDevice);
|
||||
uint32_t CALL API_GetMemCounter(int* hDevice);
|
||||
int CALL API_SetParameter(int* hDevice, uint32_t uParam, uint32_t* pParam);
|
||||
int CALL API_GetParameter(int* hDevice, uint32_t uParam, uint32_t* pParam);
|
||||
|
||||
signed int CALL API_SetDevice(int a1, int a2);
|
||||
signed int CALL API_SetCommand(int a1, int a2, int a3, int* a4);
|
||||
signed int CALL API_SetSysControl(int a1, int a2, int* a3);
|
||||
signed int CALL API_GetSysControl(int a1, int a2, int* a3);
|
||||
int CALL API_TestReset(int a1);
|
||||
signed int API_DebugReset(int a1, ...);
|
||||
int CALL API_GetBoardType(int a1);
|
||||
int CALL API_GetCardDataSize(int a1);
|
||||
int CALL API_GetFirmDate(int a1);
|
||||
int API_SystemCommand(int a1, char a2, ...);
|
||||
int CALL API_CalcCheckSum(DWORD* a1, int a2, int a3);
|
||||
int CALL API_GetCheckSumResult(int a1);
|
||||
int CALL API_BlockRead(int a1, int a2, int a3, SIZE_T dwBytes);
|
||||
int CALL API_GetBlockReadResult(int a1, void* a2);
|
||||
int CALL API_BlockWrite(int a1, int a2, int a3, SIZE_T dwBytes, void* a5);
|
||||
signed int CALL API_GetDebugParam(int a1, int a2, DWORD* a3);
|
||||
|
||||
uint32_t convert_string_to_uint(const char* firmName);
|
||||
|
||||
static const struct hook_symbol Y3_hooks[] = {
|
||||
{
|
||||
.name = "API_DLLVersion",
|
||||
.patch = API_DLLVersion,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetLastError",
|
||||
.patch = API_GetLastError,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetErrorMessage",
|
||||
.patch = API_GetErrorMessage,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_Connect",
|
||||
.patch = API_Connect,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_Close",
|
||||
.patch = API_Close,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_Start",
|
||||
.patch = API_Start,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_Stop",
|
||||
.patch = API_Stop,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetFirmVersion",
|
||||
.patch = API_GetFirmVersion,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetFirmName",
|
||||
.patch = API_GetFirmName,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetTargetCode",
|
||||
.patch = API_GetTargetCode,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetStatus",
|
||||
.patch = API_GetStatus,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetCounter",
|
||||
.patch = API_GetCounter,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_Reset",
|
||||
.patch = API_Reset,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetCardInfo",
|
||||
.patch = API_GetCardInfo,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetCardInfoCharSize",
|
||||
.patch = API_GetCardInfoCharSize,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_FirmwareUpdate",
|
||||
.patch = API_FirmwareUpdate,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_Calibration",
|
||||
.patch = API_Calibration,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetCalibrationResult",
|
||||
.patch = API_GetCalibrationResult,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetProcTime",
|
||||
.patch = API_GetProcTime,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetMemStatus",
|
||||
.patch = API_GetMemStatus,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetMemCounter",
|
||||
.patch = API_GetMemCounter,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_SetParameter",
|
||||
.patch = API_SetParameter,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetParameter",
|
||||
.patch = API_GetParameter,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_SetDevice",
|
||||
.patch = API_SetDevice,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_SetCommand",
|
||||
.patch = API_SetCommand,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_SetSysControl",
|
||||
.patch = API_SetSysControl,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetSysControl",
|
||||
.patch = API_GetSysControl,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_TestReset",
|
||||
.patch = API_TestReset,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_DebugReset",
|
||||
.patch = API_DebugReset,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetBoardType",
|
||||
.patch = API_GetBoardType,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetCardDataSize",
|
||||
.patch = API_GetCardDataSize,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetFirmDate",
|
||||
.patch = API_GetFirmDate,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_SystemCommand",
|
||||
.patch = API_SystemCommand,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_CalcCheckSum",
|
||||
.patch = API_CalcCheckSum,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetCheckSumResult",
|
||||
.patch = API_GetCheckSumResult,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_BlockRead",
|
||||
.patch = API_BlockRead,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetBlockReadResult",
|
||||
.patch = API_GetBlockReadResult,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_BlockWrite",
|
||||
.patch = API_BlockWrite,
|
||||
.link = NULL
|
||||
},
|
||||
{
|
||||
.name = "API_GetDebugParam",
|
||||
.patch = API_GetDebugParam,
|
||||
.link = NULL
|
||||
},
|
||||
};
|
||||
|
||||
static struct y3_config y3_config;
|
||||
|
||||
#define MAX_CARD_SIZE 32
|
||||
static struct CardInfo card_data[MAX_CARD_SIZE];
|
||||
|
||||
static int* Y3_COM_FIELD = (int*)10;
|
||||
static int* Y3_COM_PRINT = (int*)11;
|
||||
|
||||
HRESULT y3_hook_init(const struct y3_config* cfg, HINSTANCE self, const wchar_t* config_filename) {
|
||||
HRESULT hr;
|
||||
assert(cfg != NULL);
|
||||
|
||||
if (!cfg->enable) {
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
memcpy(&y3_config, cfg, sizeof(*cfg));
|
||||
Y3_COM_FIELD = (int*)(uintptr_t)cfg->port_field;
|
||||
Y3_COM_PRINT = (int*)(uintptr_t)cfg->port_printer;
|
||||
|
||||
y3_insert_hooks(NULL);
|
||||
|
||||
memset(card_data, 0, sizeof(card_data));
|
||||
|
||||
struct y3_dll_config config;
|
||||
y3_dll_config_load(&config, config_filename);
|
||||
|
||||
hr = y3_dll_init(&config, self);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
dprintf("Y3: hook enabled (field port = %d, printer port = %d)\n", cfg->port_field, cfg->port_printer);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
void y3_insert_hooks(HMODULE target) {
|
||||
hook_table_apply(
|
||||
target,
|
||||
"Y3CodeReaderNE.dll",
|
||||
Y3_hooks,
|
||||
_countof(Y3_hooks));
|
||||
|
||||
proc_addr_table_push(
|
||||
target,
|
||||
"Y3CodeReaderNE.dll",
|
||||
Y3_hooks,
|
||||
_countof(Y3_hooks));
|
||||
}
|
||||
|
||||
float CALL API_DLLVersion() {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t CALL API_GetLastError(int* hDevice) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
if (!y3_config.enable) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t CALL API_GetErrorMessage(uint32_t errNo, char* szMessage,
|
||||
int numBytes) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int* CALL API_Connect(char* szPortName) {
|
||||
HRESULT hr;
|
||||
|
||||
dprintf("Y3: %s(%s)\n", __func__, szPortName);
|
||||
|
||||
if (!y3_config.enable) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char number[2];
|
||||
strncpy(number, szPortName + 3, 2);
|
||||
int* hDevice = (int*)(uintptr_t)atoi(number);
|
||||
|
||||
if (hDevice == Y3_COM_FIELD) {
|
||||
hr = y3_dll.init();
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Y3: Hook DLL initialization failed: %lx\n", hr);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return hDevice;
|
||||
}
|
||||
|
||||
int CALL API_Close(int* hDevice) {
|
||||
dprintf("Y3: %s(%p)\n", __func__, hDevice);
|
||||
|
||||
if (hDevice == Y3_COM_FIELD) {
|
||||
y3_dll.close();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_Start(int* hDevice) {
|
||||
dprintf("Y3: %s(%p)\n", __func__, hDevice);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_Stop(int* hDevice) {
|
||||
dprintf("Y3: %s(%p)\n", __func__, hDevice);
|
||||
return 0;
|
||||
}
|
||||
|
||||
float CALL API_GetFirmVersion(int* hDevice) {
|
||||
dprintf("Y3: %s(%p)\n", __func__, hDevice);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t CALL API_GetFirmName(int* hDevice) {
|
||||
uint32_t result = 0;
|
||||
dprintf("Y3: %s(%p)\n", __func__, hDevice);
|
||||
|
||||
if (hDevice == Y3_COM_FIELD) {
|
||||
result = convert_string_to_uint(y3_config.firm_name_field);
|
||||
dprintf("Y3: This device is a FIELD: %s\n", y3_config.firm_name_field);
|
||||
} else if (hDevice == Y3_COM_PRINT) {
|
||||
result = convert_string_to_uint(y3_config.firm_name_printer);
|
||||
dprintf("Y3: This device is a PRINTER: %s\n", y3_config.firm_name_printer);
|
||||
} else {
|
||||
dprintf("Y3: This device is UNKNOWN\n");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t CALL API_GetTargetCode(int* hDevice) {
|
||||
uint32_t result = 1162760014;
|
||||
dprintf("Y3: %s(%p)\n", __func__, hDevice);
|
||||
|
||||
if (hDevice == Y3_COM_FIELD) {
|
||||
result = convert_string_to_uint(y3_config.target_code_field);
|
||||
dprintf("Y3: This device is a FIELD: %s\n", y3_config.target_code_field);
|
||||
} else if (hDevice == Y3_COM_PRINT) {
|
||||
result = convert_string_to_uint(y3_config.target_code_printer);
|
||||
dprintf("Y3: This device is a PRINTER: %s\n", y3_config.target_code_printer);
|
||||
} else {
|
||||
dprintf("Y3: This Y3 device is UNKNOWN\n");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t CALL API_GetStatus(int* hDevice) {
|
||||
// dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t CALL API_GetCounter(int* hDevice) {
|
||||
// dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_ClearError(int* hDevice) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_Reset(int* hDevice, bool isHardReset) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_GetCardInfo(int* hDevice, int numCards, struct CardInfo* pCardInfo) {
|
||||
// dprintf("Y3: %s(%p), %d\n", __func__, hDevice, numCards);
|
||||
// ret = num cards
|
||||
// numCards = max cards
|
||||
|
||||
if (hDevice == Y3_COM_FIELD) {
|
||||
|
||||
int cards = numCards;
|
||||
HRESULT hr = y3_dll.get_cards(pCardInfo, &cards);
|
||||
if (FAILED(hr)) {
|
||||
dprintf("Y3: DLL returned error when retrieving cards: %lx\n", hr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return cards;
|
||||
} else if (hDevice == Y3_COM_PRINT) {
|
||||
pCardInfo[0].fX = 0;
|
||||
pCardInfo[0].fY = 0;
|
||||
pCardInfo[0].fAngle = 0;
|
||||
pCardInfo[0].eCardType = TYPE0;
|
||||
pCardInfo[0].eCardStatus = MARKER;
|
||||
pCardInfo[0].uID = 0x10;
|
||||
pCardInfo[0].nNumChars = 0;
|
||||
pCardInfo[0].ubChar0.Data = 0;
|
||||
pCardInfo[0].ubChar1.Data = 0x4000;
|
||||
pCardInfo[0].ubChar2.Data = 0;
|
||||
pCardInfo[0].ubChar3.Data = 0x0; // 40
|
||||
pCardInfo[0].ubChar4.Data = 0;
|
||||
pCardInfo[0].ubChar5.Data = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_GetCardInfoCharSize() {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_FirmwareUpdate(int* hDevice, uint32_t address, uint32_t size,
|
||||
uint8_t* buffer) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 1; // not supported
|
||||
}
|
||||
|
||||
int CALL API_Calibration(int* hDevice, int calib) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CALL API_GetCalibrationResult(int* hDevice, int calib, uint32_t* result) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t CALL API_GetProcTime(int* hDevice) {
|
||||
// dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t CALL API_GetMemStatus(int* hDevice) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
uint32_t CALL API_GetMemCounter(int* hDevice) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_SetParameter(int* hDevice, uint32_t uParam, uint32_t* pParam) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_GetParameter(int* hDevice, uint32_t uParam, uint32_t* pParam) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
signed int CALL API_SetDevice(int a1, int a2) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
signed int CALL API_SetCommand(int a1, int a2, int a3, int* a4) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
signed int CALL API_SetSysControl(int a1, int a2, int* a3) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
signed int CALL API_GetSysControl(int a1, int a2, int* a3) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_TestReset(int a1) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
signed int API_DebugReset(int a1, ...) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_GetBoardType(int a1) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_GetCardDataSize(int a1) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_GetFirmDate(int a1) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int API_SystemCommand(int a1, char a2, ...) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_CalcCheckSum(DWORD* a1, int a2, int a3) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_GetCheckSumResult(int a1) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_BlockRead(int a1, int a2, int a3, SIZE_T dwBytes) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_GetBlockReadResult(int a1, void* a2) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CALL API_BlockWrite(int a1, int a2, int a3, SIZE_T dwBytes, void* a5) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
signed int CALL API_GetDebugParam(int a1, int a2, DWORD* a3) {
|
||||
dprintf("Y3: %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t convert_string_to_uint(const char* firmName) {
|
||||
uint32_t result = 0;
|
||||
|
||||
// Iterate over each character in the string and construct the uint32_t
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result |= (uint32_t)firmName[i] << (i * 8);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
71
common/hooklib/y3.h
Normal file
71
common/hooklib/y3.h
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "hooklib/config.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
// Value held on a card.
|
||||
struct CardByteData {
|
||||
unsigned int Data;
|
||||
};
|
||||
|
||||
// Unused
|
||||
enum CardType {
|
||||
TYPE0 = 0,
|
||||
TYPE1,
|
||||
TYPE2,
|
||||
TYPE3,
|
||||
TYPE4,
|
||||
TYPE5,
|
||||
TYPE6,
|
||||
TYPE7 = 7
|
||||
};
|
||||
|
||||
enum CardStatus {
|
||||
// Unset entry
|
||||
INVALID = 0,
|
||||
// Valid card
|
||||
VALID = 1,
|
||||
// Not a card but rather infrared interference. Only relevant in test mode.
|
||||
INFERENCE = 2,
|
||||
// This is only used by the printer camera.
|
||||
MARKER = 3
|
||||
};
|
||||
|
||||
struct CardInfo {
|
||||
// X position of the card.
|
||||
float fX; // 0x00|0
|
||||
// Y position of the card.
|
||||
float fY; // 0x04|4
|
||||
// Rotation of the card in degrees >=0.0 && <360.0
|
||||
float fAngle; // 0x08|8
|
||||
// Unused
|
||||
enum CardType eCardType; // 0x0C|12
|
||||
// see enum CardStatus
|
||||
enum CardStatus eCardStatus; // 0x10|16
|
||||
// card's BaseCode. used for a reference to the card being tracked as well as part of the IvCode.
|
||||
unsigned int uID; // 0x14|20
|
||||
// Unused
|
||||
int nNumChars; // 0x18|24
|
||||
// Title Code. Is 8589934592 for EKT.
|
||||
struct CardByteData ubChar0; // 0x1C|28
|
||||
// Must be 0x4000 for the printer camera.
|
||||
struct CardByteData ubChar1; // 0x20|32
|
||||
// Unused
|
||||
struct CardByteData ubChar2; // 0x24|36
|
||||
// Must be 0x0 for the printer camera.
|
||||
struct CardByteData ubChar3; // 0x28|40
|
||||
// Unused
|
||||
struct CardByteData ubChar4; // 0x2C|44
|
||||
// Unused
|
||||
struct CardByteData ubChar5; // 0x30|48
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
HRESULT y3_hook_init(const struct y3_config *cfg, HINSTANCE self, const wchar_t* config_path);
|
||||
|
||||
void y3_insert_hooks(HMODULE target);
|
||||
|
|
@ -18,6 +18,7 @@
|
|||
static HRESULT amvideo_reg_read_name(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT amvideo_reg_read_port_X(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT amvideo_reg_read_resolution_1(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT amvideo_reg_read_resolution_2(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT amvideo_reg_read_setting(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT amvideo_reg_read_use_segatiming(void *bytes, uint32_t *nbytes);
|
||||
|
||||
|
|
@ -81,6 +82,10 @@ static const struct reg_hook_val amvideo_reg_mode_vals[] = {
|
|||
.name = L"resolution_1",
|
||||
.read = amvideo_reg_read_resolution_1,
|
||||
.type = REG_SZ,
|
||||
}, {
|
||||
.name = L"resolution_2",
|
||||
.read = amvideo_reg_read_resolution_2,
|
||||
.type = REG_SZ,
|
||||
}, {
|
||||
.name = L"use_segatiming",
|
||||
.read = amvideo_reg_read_use_segatiming,
|
||||
|
|
@ -171,6 +176,11 @@ static HRESULT amvideo_reg_read_resolution_1(void *bytes, uint32_t *nbytes)
|
|||
return reg_hook_read_wstr(bytes, nbytes, L"1920x1080");
|
||||
}
|
||||
|
||||
static HRESULT amvideo_reg_read_resolution_2(void *bytes, uint32_t *nbytes)
|
||||
{
|
||||
return reg_hook_read_wstr(bytes, nbytes, L"1920x1080");
|
||||
}
|
||||
|
||||
static HRESULT amvideo_reg_read_setting(void *bytes, uint32_t *nbytes)
|
||||
{
|
||||
return reg_hook_read_wstr(bytes, nbytes, L"0");
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@
|
|||
#include "platform/amvideo.h"
|
||||
#include "platform/clock.h"
|
||||
#include "platform/config.h"
|
||||
|
||||
#include <shlwapi.h>
|
||||
|
||||
#include "platform/dns.h"
|
||||
#include "platform/epay.h"
|
||||
#include "platform/hwmon.h"
|
||||
|
|
@ -23,7 +26,9 @@
|
|||
#include "platform/platform.h"
|
||||
#include "platform/vfs.h"
|
||||
#include "platform/system.h"
|
||||
#include "util/dprintf.h"
|
||||
#include "platform/openssl.h"
|
||||
#include "util/dprintf.h"
|
||||
|
||||
|
||||
void platform_config_load(struct platform_config *cfg, const wchar_t *filename)
|
||||
|
|
@ -31,6 +36,14 @@ void platform_config_load(struct platform_config *cfg, const wchar_t *filename)
|
|||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
if (!PathFileExistsW(filename)) {
|
||||
wchar_t temp[MAX_PATH];
|
||||
dprintf("ERROR: Configuration does not exist\n");
|
||||
dprintf(" Configured: \"%ls\"\n", filename);
|
||||
GetFullPathNameW(filename, _countof(temp), temp, NULL);
|
||||
dprintf(" Expanded: \"%ls\"\n", temp);
|
||||
}
|
||||
|
||||
amvideo_config_load(&cfg->amvideo, filename);
|
||||
clock_config_load(&cfg->clock, filename);
|
||||
dns_config_load(&cfg->dns, filename);
|
||||
|
|
@ -44,6 +57,7 @@ void platform_config_load(struct platform_config *cfg, const wchar_t *filename)
|
|||
vfs_config_load(&cfg->vfs, filename);
|
||||
system_config_load(&cfg->system, filename);
|
||||
openssl_config_load(&cfg->openssl, filename);
|
||||
ewf_config_load(&cfg->ewf, filename);
|
||||
}
|
||||
|
||||
void amvideo_config_load(struct amvideo_config *cfg, const wchar_t *filename)
|
||||
|
|
@ -154,6 +168,8 @@ void misc_config_load(struct misc_config *cfg, const wchar_t *filename)
|
|||
assert(filename != NULL);
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"misc", L"enable", 1, filename);
|
||||
cfg->allowMasterKeyWrite = GetPrivateProfileIntW(L"misc", L"allowMasterKeyWrite", 0, filename);
|
||||
cfg->allowReboot = GetPrivateProfileIntW(L"misc", L"allowReboot", 0, filename);
|
||||
}
|
||||
|
||||
void netenv_config_load(struct netenv_config *cfg, const wchar_t *filename)
|
||||
|
|
@ -204,6 +220,7 @@ void nusec_config_load(struct nusec_config *cfg, const wchar_t *filename)
|
|||
wchar_t game_id[5];
|
||||
wchar_t platform_id[5];
|
||||
wchar_t subnet[16];
|
||||
wchar_t bcast[16];
|
||||
unsigned int ip[4];
|
||||
size_t i;
|
||||
|
||||
|
|
@ -215,6 +232,7 @@ void nusec_config_load(struct nusec_config *cfg, const wchar_t *filename)
|
|||
memset(game_id, 0, sizeof(game_id));
|
||||
memset(platform_id, 0, sizeof(platform_id));
|
||||
memset(subnet, 0, sizeof(subnet));
|
||||
memset(bcast, 0, sizeof(bcast));
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"keychip", L"enable", 1, filename);
|
||||
|
||||
|
|
@ -258,6 +276,14 @@ void nusec_config_load(struct nusec_config *cfg, const wchar_t *filename)
|
|||
_countof(subnet),
|
||||
filename);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"netenv",
|
||||
L"broadcast",
|
||||
L"255.255.255.255",
|
||||
bcast,
|
||||
_countof(bcast),
|
||||
filename);
|
||||
|
||||
for (i = 0 ; i < 16 ; i++) {
|
||||
cfg->keychip_id[i] = (char) keychip_id[i];
|
||||
}
|
||||
|
|
@ -273,6 +299,9 @@ void nusec_config_load(struct nusec_config *cfg, const wchar_t *filename)
|
|||
swscanf(subnet, L"%u.%u.%u.%u", &ip[0], &ip[1], &ip[2], &ip[3]);
|
||||
cfg->subnet = (ip[0] << 24) | (ip[1] << 16) | (ip[2] << 8) | 0;
|
||||
|
||||
swscanf(bcast, L"%u.%u.%u.%u", &ip[0], &ip[1], &ip[2], &ip[3]);
|
||||
cfg->bcast = (ip[0] << 24) | (ip[1] << 16) | (ip[2] << 8) | (ip[3]);
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"keychip",
|
||||
L"billingCa",
|
||||
|
|
@ -336,6 +365,32 @@ void vfs_config_load(struct vfs_config *cfg, const wchar_t *filename)
|
|||
cfg->option,
|
||||
_countof(cfg->option),
|
||||
filename);
|
||||
|
||||
for (int i = 0; i < MAX_REDIRECTIONS; i++){
|
||||
wchar_t key[32];
|
||||
wsprintfW(key, L"redirection%dfrom", i);
|
||||
GetPrivateProfileStringW(
|
||||
L"vfs",
|
||||
key,
|
||||
L"",
|
||||
cfg->redirections_from[i],
|
||||
_countof(cfg->redirections_from[i]),
|
||||
filename);
|
||||
wsprintfW(key, L"redirection%dto", i);
|
||||
GetPrivateProfileStringW(
|
||||
L"vfs",
|
||||
key,
|
||||
L"",
|
||||
cfg->redirections_to[i],
|
||||
_countof(cfg->redirections_to[i]),
|
||||
filename);
|
||||
|
||||
cfg->redirections_from_len[i] = (int)wcslen(cfg->redirections_from[i]);
|
||||
|
||||
if (cfg->redirections_from_len[i] > 0) {
|
||||
dprintf("Vfs: Set up custom redirection from %ls to %ls\n", cfg->redirections_from[i], cfg->redirections_to[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void system_config_load(struct system_config *cfg, const wchar_t *filename)
|
||||
|
|
@ -374,3 +429,11 @@ void openssl_config_load(struct openssl_config *cfg, const wchar_t *filename)
|
|||
cfg->enable = GetPrivateProfileIntW(L"openssl", L"enable", 1, filename);
|
||||
cfg->override = GetPrivateProfileIntW(L"openssl", L"override", 0, filename);
|
||||
}
|
||||
|
||||
void ewf_config_load(struct ewf_config* cfg, const wchar_t* filename) {
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"ewf", L"enable", 0, filename);
|
||||
cfg->full = GetPrivateProfileIntW(L"ewf", L"full", 0, filename);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,3 +38,4 @@ void pcbid_config_load(struct pcbid_config *cfg, const wchar_t *filename);
|
|||
void vfs_config_load(struct vfs_config *cfg, const wchar_t *filename);
|
||||
void system_config_load(struct system_config *cfg, const wchar_t *filename);
|
||||
void openssl_config_load(struct openssl_config *cfg, const wchar_t *filename);
|
||||
void ewf_config_load(struct ewf_config *cfg, const wchar_t *filename);
|
||||
|
|
|
|||
|
|
@ -90,6 +90,12 @@ HRESULT dns_platform_hook_init(const struct dns_config *cfg)
|
|||
return hr;
|
||||
}
|
||||
|
||||
hr = dns_hook_push(L"sega-initiald.net", cfg->startup);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
// crossbeats REV.
|
||||
hr = dns_hook_push(L"https://rev-ent.ac.capcom.jp:443", cfg->title);
|
||||
|
||||
|
|
|
|||
563
common/platform/ewf.c
Normal file
563
common/platform/ewf.c
Normal file
|
|
@ -0,0 +1,563 @@
|
|||
#include <windows.h>
|
||||
#include <shlwapi.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "hook/iohook.h"
|
||||
#include "hook/procaddr.h"
|
||||
|
||||
#include "platform/ewf.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "hooklib/path.h"
|
||||
#include "util/dprintf.h"
|
||||
#include "util/dump.h"
|
||||
|
||||
/* EWF hook */
|
||||
|
||||
const static struct ewf_config* ewf_config;
|
||||
static struct ewf_virtual_file virtual_file_table[EWF_MAX_VIRTUAL_FILES] = {0};
|
||||
static struct ewf_real_handle* handle_table;
|
||||
static uint32_t handle_table_size;
|
||||
static CRITICAL_SECTION file_table_lock;
|
||||
static CRITICAL_SECTION handle_table_lock;
|
||||
static wchar_t windows_directory[MAX_PATH];
|
||||
|
||||
static const wchar_t* default_drive = L"C:\\";
|
||||
static const wchar_t default_paths[][MAX_PATH] = {
|
||||
L"alib.conf",
|
||||
L"cacert.pem",
|
||||
L"first_ar.conf",
|
||||
L"last_pras.log",
|
||||
L"last_shime.log",
|
||||
L"play_history.csv"
|
||||
};
|
||||
|
||||
/* Helper functions */
|
||||
|
||||
static HRESULT atow(const char* string, wchar_t** result) {
|
||||
if (string == NULL) {
|
||||
*result = NULL;
|
||||
return S_FALSE;
|
||||
}
|
||||
const size_t n = strlen(string);
|
||||
wchar_t* widestring = malloc((n + 1) * sizeof(wchar_t));
|
||||
if (widestring == NULL) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
mbstowcs_s(NULL, widestring, n + 1, string, n);
|
||||
|
||||
*result = widestring;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static inline bool wprefix(const wchar_t* pre, const wchar_t* str) {
|
||||
return wcsncmp(pre, str, wcslen(pre)) == 0;
|
||||
}
|
||||
|
||||
static inline bool wsuffix(const wchar_t* suffix, const wchar_t* str) {
|
||||
if (str == NULL || suffix == NULL) {
|
||||
return false;
|
||||
}
|
||||
const size_t str_len = wcslen(str);
|
||||
const size_t suf_len = wcslen(suffix);
|
||||
if (suf_len > str_len) {
|
||||
return false;
|
||||
}
|
||||
return wcsncmp(str + str_len - suf_len, suffix, suf_len) == 0;
|
||||
}
|
||||
|
||||
|
||||
static BOOL ewf_needs_virtualization(const wchar_t* path) {
|
||||
if (path == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
if (ewf_config->full) {
|
||||
if (wprefix(default_drive, path) && !wprefix(windows_directory, path)) {
|
||||
return TRUE;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < _countof(default_paths); i++) {
|
||||
if (wsuffix(default_paths[i], path)) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static struct ewf_virtual_file* ewf_get_virtual_file(HANDLE handle) {
|
||||
struct ewf_virtual_file* ret = NULL;
|
||||
EnterCriticalSection(&file_table_lock);
|
||||
for (int i = 0; i < EWF_MAX_VIRTUAL_FILES; i++) {
|
||||
if (virtual_file_table[i].virtual_handle == handle) {
|
||||
ret = &virtual_file_table[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&file_table_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct ewf_virtual_file* ewf_find_virtual_file(const wchar_t* path) {
|
||||
if (path == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
HANDLE ret = NULL;
|
||||
EnterCriticalSection(&file_table_lock);
|
||||
for (int i = 0; i < EWF_MAX_VIRTUAL_FILES; i++) {
|
||||
if (virtual_file_table[i].virtual_handle != NULL && wcscmp(virtual_file_table[i].path, path) == 0) {
|
||||
ret = &virtual_file_table[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&file_table_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct ewf_virtual_file* ewf_create_virtual_file(const wchar_t* path) {
|
||||
assert(path != NULL);
|
||||
struct ewf_virtual_file* ret = NULL;
|
||||
EnterCriticalSection(&file_table_lock);
|
||||
for (int i = 0; i < EWF_MAX_VIRTUAL_FILES; i++) {
|
||||
if (virtual_file_table[i].virtual_handle == NULL) {
|
||||
struct ewf_virtual_file* h = &virtual_file_table[i];
|
||||
HRESULT hr = iohook_open_nul_fd(&h->virtual_handle);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
dprintf("EWF: Could not create handle: Failed to get NUL handle: %lx", hr);
|
||||
break;
|
||||
}
|
||||
dprintf("EWF: Created virtual file: %ls\n", path);
|
||||
wcscpy_s(h->path, MAX_PATH, path);
|
||||
h->length = 0;
|
||||
h->data = NULL;
|
||||
ret = h;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret == NULL) {
|
||||
dprintf("EWF: Could not create handle: Too many virtualized files\n");
|
||||
}
|
||||
LeaveCriticalSection(&file_table_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL ewf_delete_virtual_file(HANDLE virtual_handle) {
|
||||
if (virtual_handle == NULL) {
|
||||
return TRUE;
|
||||
}
|
||||
struct ewf_virtual_file* match = NULL;
|
||||
EnterCriticalSection(&file_table_lock);
|
||||
for (int i = 0; i < EWF_MAX_VIRTUAL_FILES; i++) {
|
||||
if (virtual_file_table[i].virtual_handle == virtual_handle) {
|
||||
match = &virtual_file_table[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&file_table_lock);
|
||||
if (match) {
|
||||
match->virtual_handle = NULL;
|
||||
#if LOG_EWF
|
||||
dprintf("EWF: Deleted file: %ls\n", match->path);
|
||||
#endif
|
||||
return CloseHandle(virtual_handle);
|
||||
} else {
|
||||
SetLastError(ERROR_INVALID_HANDLE);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static struct ewf_real_handle* ewf_open_virtual_file(HANDLE virtual_handle) {
|
||||
struct ewf_virtual_file* file = ewf_get_virtual_file(virtual_handle);
|
||||
struct ewf_real_handle* h = NULL;
|
||||
if (file == NULL) {
|
||||
dprintf("EWF: open failed: invalid handle\n");
|
||||
return NULL;
|
||||
}
|
||||
EnterCriticalSection(&handle_table_lock);
|
||||
for (int i = 0; i < handle_table_size; i++) {
|
||||
if (handle_table[i].real_handle == NULL) {
|
||||
h = &handle_table[i];
|
||||
HRESULT hr = iohook_open_nul_fd(&h->real_handle);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
dprintf("EWF: Could not create handle: Failed to get NUL handle: %lx", hr);
|
||||
break;
|
||||
}
|
||||
h->virtual_file = file;
|
||||
h->offset = 0;
|
||||
#if LOG_EWF
|
||||
dprintf("EWF: Virtual file opened: %ls\n", file->path);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&handle_table_lock);
|
||||
if (h == NULL) {
|
||||
dprintf("EWF: Could not create handle: Too many open files\n");
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
static struct ewf_real_handle* ewf_get_real_handle(HANDLE real_handle) {
|
||||
if (real_handle == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
struct ewf_real_handle* match = NULL;
|
||||
EnterCriticalSection(&handle_table_lock);
|
||||
for (int i = 0; i < handle_table_size; i++) {
|
||||
if (handle_table[i].real_handle == real_handle) {
|
||||
match = &handle_table[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&handle_table_lock);
|
||||
return match;
|
||||
}
|
||||
|
||||
static BOOL ewf_close_virtual_file(HANDLE real_handle) {
|
||||
const struct ewf_virtual_file* match = NULL;
|
||||
EnterCriticalSection(&handle_table_lock);
|
||||
for (int i = 0; i < handle_table_size; i++) {
|
||||
if (handle_table[i].real_handle == real_handle) {
|
||||
match = handle_table[i].virtual_file;
|
||||
handle_table[i].real_handle = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&handle_table_lock);
|
||||
if (match != NULL) {
|
||||
#if LOG_EWF
|
||||
dprintf("EWF: Virtual file closed: %ls\n", match->path);
|
||||
#endif
|
||||
return CloseHandle(real_handle);
|
||||
} else {
|
||||
SetLastError(ERROR_INVALID_HANDLE);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hooks */
|
||||
|
||||
static int __cdecl hook_stat64i32(
|
||||
const char* path,
|
||||
struct _stat64i32* buffer
|
||||
);
|
||||
|
||||
static int (__cdecl *next_stat64i32)(
|
||||
const char* path,
|
||||
struct _stat64i32* buffer);
|
||||
|
||||
static const struct hook_symbol ewf_hook_syms[] = {
|
||||
{
|
||||
.name = "__imp__stat64i32",
|
||||
.patch = hook_stat64i32,
|
||||
.link = (void **) &next_stat64i32,
|
||||
},
|
||||
{
|
||||
.name = "_stat64i32",
|
||||
.patch = hook_stat64i32,
|
||||
.link = (void **) &next_stat64i32,
|
||||
}
|
||||
};
|
||||
|
||||
/* EWF hook main functions */
|
||||
|
||||
static HRESULT ewf_handle_irp(struct irp* irp);
|
||||
|
||||
static HRESULT ewf_handle_open(struct irp* irp);
|
||||
|
||||
static HRESULT ewf_handle_close(const struct irp* irp, const struct ewf_real_handle* file);
|
||||
|
||||
static HRESULT ewf_handle_read(struct irp* irp, struct ewf_real_handle* handle);
|
||||
|
||||
static HRESULT ewf_handle_write(const struct irp* irp, const struct ewf_real_handle* file);
|
||||
|
||||
void ewf_hook_insert_hooks(HMODULE target) {
|
||||
hook_table_apply(
|
||||
target,
|
||||
"msvcr110d.dll",
|
||||
ewf_hook_syms,
|
||||
_countof(ewf_hook_syms));
|
||||
hook_table_apply(
|
||||
target,
|
||||
"msvcr110.dll",
|
||||
ewf_hook_syms,
|
||||
_countof(ewf_hook_syms));
|
||||
}
|
||||
|
||||
HRESULT ewf_hook_init(const struct ewf_config* config) {
|
||||
assert(config != NULL);
|
||||
|
||||
ewf_config = config;
|
||||
|
||||
if (!config->enable) {
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
handle_table_size = config->full ? 50000 : 1024;
|
||||
handle_table = malloc(sizeof(struct ewf_real_handle) * handle_table_size);
|
||||
ZeroMemory(handle_table, handle_table_size);
|
||||
|
||||
GetWindowsDirectoryW(windows_directory, MAX_PATH);
|
||||
|
||||
if (config->full) {
|
||||
wchar_t executable_path[MAX_PATH];
|
||||
GetModuleFileNameW(NULL, executable_path, MAX_PATH);
|
||||
if (wprefix(default_drive, executable_path)) {
|
||||
dprintf("FATAL: EWF full virtualization cannot be enabled with the game executable being located on %ls\n",
|
||||
default_drive);
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
dprintf("EWF: Virtualizing disk I/O to %s\n",
|
||||
config->full ? "the entirety of the C:\\ drive" : "the ALPB billing directory");
|
||||
|
||||
InitializeCriticalSection(&handle_table_lock);
|
||||
InitializeCriticalSection(&file_table_lock);
|
||||
|
||||
ewf_hook_insert_hooks(NULL);
|
||||
|
||||
return iohook_push_handler(ewf_handle_irp);
|
||||
}
|
||||
|
||||
static HRESULT ewf_handle_irp(struct irp* irp) {
|
||||
assert(irp != NULL);
|
||||
|
||||
struct ewf_real_handle* h = NULL;
|
||||
|
||||
if (irp->op == IRP_OP_OPEN) {
|
||||
if (!ewf_needs_virtualization(irp->open_filename)) {
|
||||
return iohook_invoke_next(irp);
|
||||
}
|
||||
} else {
|
||||
h = ewf_get_real_handle(irp->fd);
|
||||
if (h == NULL) {
|
||||
return iohook_invoke_next(irp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch (irp->op) {
|
||||
case IRP_OP_OPEN: return ewf_handle_open(irp);
|
||||
case IRP_OP_WRITE: return ewf_handle_write(irp, h);
|
||||
case IRP_OP_READ: return ewf_handle_read(irp, h);
|
||||
case IRP_OP_CLOSE: return ewf_handle_close(irp, h);
|
||||
default: return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT ewf_handle_open(struct irp* irp) {
|
||||
assert(irp != NULL);
|
||||
|
||||
if (irp->ovl != NULL) {
|
||||
dprintf("EWF: async file operations not supported\n");
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
struct ewf_virtual_file* f = ewf_find_virtual_file(irp->open_filename);
|
||||
|
||||
if (irp->open_creation == CREATE_NEW) {
|
||||
if (f != NULL) {
|
||||
return HRESULT_FROM_WIN32(ERROR_FILE_EXISTS);
|
||||
} else {
|
||||
f = ewf_create_virtual_file(irp->open_filename);
|
||||
}
|
||||
} else if (irp->open_creation == CREATE_ALWAYS) {
|
||||
if (f != NULL) {
|
||||
SetLastError(ERROR_ALREADY_EXISTS);
|
||||
#if LOG_EWF
|
||||
dprintf("EWF: File was truncated\n");
|
||||
#endif
|
||||
f->length = 0;
|
||||
free(f->data);
|
||||
} else {
|
||||
f = ewf_create_virtual_file(irp->open_filename);
|
||||
}
|
||||
} else if (irp->open_creation == OPEN_EXISTING) {
|
||||
if (f == NULL) {
|
||||
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
||||
}
|
||||
} else if (irp->open_creation == OPEN_ALWAYS) {
|
||||
if (f != NULL) {
|
||||
SetLastError(ERROR_ALREADY_EXISTS);
|
||||
} else {
|
||||
f = ewf_create_virtual_file(irp->open_filename);
|
||||
}
|
||||
} else if (irp->open_creation == TRUNCATE_EXISTING) {
|
||||
if (f != NULL) {
|
||||
#if LOG_EWF
|
||||
dprintf("EWF: File was truncated\n");
|
||||
#endif
|
||||
f->length = 0;
|
||||
free(f->data);
|
||||
} else {
|
||||
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
||||
}
|
||||
} else {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
const struct ewf_real_handle* h = ewf_open_virtual_file(f->virtual_handle);
|
||||
irp->fd = h->real_handle;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT ewf_handle_close(const struct irp* irp, const struct ewf_real_handle* file) {
|
||||
assert(irp != NULL);
|
||||
assert(file != NULL);
|
||||
|
||||
return ewf_close_virtual_file(file->real_handle) ? S_OK : E_FAIL;
|
||||
}
|
||||
|
||||
static HRESULT ewf_handle_read(struct irp* irp, struct ewf_real_handle* handle) {
|
||||
assert(irp != NULL);
|
||||
assert(handle != NULL);
|
||||
|
||||
const struct ewf_virtual_file* f = handle->virtual_file;
|
||||
size_t pos = handle->offset;
|
||||
size_t to_read = irp->read.nbytes;
|
||||
size_t max = f->length;
|
||||
|
||||
if (pos > max || pos < 0) {
|
||||
dprintf("EWF: Out-of-bounds read from %ls\n", f->path);
|
||||
return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
|
||||
}
|
||||
if (max == 0 || pos >= max || to_read == 0) {
|
||||
#if LOG_EWF
|
||||
dprintf("EWF: Zero read of %d at %d/%d from %ls\n", (int) to_read, (int) pos, (int) max, f->path);
|
||||
#endif
|
||||
irp->read.pos = 0;
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
if (pos + to_read > max) {
|
||||
to_read = max - pos;
|
||||
}
|
||||
|
||||
memcpy(irp->read.bytes, f->data, to_read);
|
||||
irp->read.pos = to_read;
|
||||
handle->offset += to_read;
|
||||
|
||||
#if LOG_EWF
|
||||
dprintf("EWF: Read %d/%d bytes (offset %d, max %d) from %ls\n", (int) to_read, (int) irp->read.nbytes, (int) pos,
|
||||
(int) f->length, f->path);
|
||||
dump_iobuf(&irp->read);
|
||||
#endif
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT ewf_handle_write(const struct irp* irp, const struct ewf_real_handle* file) {
|
||||
assert(irp != NULL);
|
||||
assert(file != NULL);
|
||||
|
||||
struct ewf_virtual_file* f = file->virtual_file;
|
||||
const size_t n = irp->write.nbytes;
|
||||
const void* data = irp->write.bytes;
|
||||
|
||||
if (f->length == 0) {
|
||||
const size_t initial_buf = max(n, EWF_DEFAULT_FILE_BUFFER_SIZE);
|
||||
f->data = malloc(initial_buf);
|
||||
if (f->data == NULL) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
f->alloc_length = initial_buf;
|
||||
} else if (f->length + n > f->alloc_length) {
|
||||
void* ptr = realloc(f->data, f->alloc_length + n);
|
||||
if (ptr == NULL) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
f->data = ptr;
|
||||
f->alloc_length = f->alloc_length + n;
|
||||
}
|
||||
|
||||
if (memcpy_s((char *) f->data + f->length, f->alloc_length - f->length, data, n) != 0) {
|
||||
dprintf("EWF: Failed to copy %d bytes at offset %d (max %d)\n", (int) n, (int) f->length,
|
||||
(int) f->alloc_length);
|
||||
return E_NOT_SUFFICIENT_BUFFER;
|
||||
}
|
||||
f->length += n;
|
||||
|
||||
#if LOG_EWF
|
||||
dprintf("EWF: Write %d bytes to %ls\n", (int) n, f->path);
|
||||
dump_const_iobuf(&irp->write);
|
||||
dprintf("EWF: File content (%d, allocated %d)\n", (int) f->length, (int) f->alloc_length);
|
||||
dump(f->data, f->length);
|
||||
#endif
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// MSVC implementation detail. amdaemon depends on this succeeding, or you will be spammed with "cannot get accounting info"
|
||||
static int __cdecl hook_stat64i32(
|
||||
const char* path,
|
||||
struct _stat64i32* buffer
|
||||
) {
|
||||
if (buffer == NULL || path == NULL) {
|
||||
_set_errno(EINVAL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wchar_t* wpath = NULL;
|
||||
wchar_t* trans;
|
||||
BOOL ok;
|
||||
|
||||
HRESULT result = atow(path, &wpath);
|
||||
if (!SUCCEEDED(result)) {
|
||||
_set_errno(ENOMEM);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ok = path_transform_w(&trans, wpath);
|
||||
|
||||
if (!ok) {
|
||||
_set_errno(EINVAL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wchar_t* target_path = trans ? trans : wpath;
|
||||
|
||||
if (!ewf_needs_virtualization(target_path)) {
|
||||
free(trans);
|
||||
free(wpath);
|
||||
#if LOG_EWF
|
||||
dprintf("EWF: stat64i32: ignore: %s\n", path);
|
||||
#endif
|
||||
return next_stat64i32(path, buffer);
|
||||
}
|
||||
|
||||
const struct ewf_virtual_file* f = ewf_find_virtual_file(target_path);
|
||||
if (f == NULL) {
|
||||
free(trans);
|
||||
free(wpath);
|
||||
dprintf("EWF: stat64i32: File not found: %s\n", path);
|
||||
_set_errno(ENOENT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffer->st_gid = 0;
|
||||
buffer->st_atime = time(NULL);
|
||||
buffer->st_ctime = time(NULL);
|
||||
buffer->st_dev = 0;
|
||||
buffer->st_ino = 0;
|
||||
buffer->st_mode = _S_IFREG;
|
||||
buffer->st_mtime = time(NULL);
|
||||
buffer->st_nlink = 1;
|
||||
buffer->st_rdev = 0;
|
||||
buffer->st_size = (_off_t) f->length;
|
||||
buffer->st_uid = 0;
|
||||
|
||||
#if LOG_EWF
|
||||
dprintf("EWF: stat64i32: file length of %s: %d\n", path, (int) f->length);
|
||||
#endif
|
||||
free(trans);
|
||||
free(wpath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
39
common/platform/ewf.h
Normal file
39
common/platform/ewf.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define EWF_MAX_VIRTUAL_FILES 255
|
||||
#define EWF_DEFAULT_FILE_BUFFER_SIZE 1024
|
||||
|
||||
struct ewf_config {
|
||||
bool enable;
|
||||
bool full;
|
||||
};
|
||||
|
||||
// A virtual file that we are storing in memory.
|
||||
struct ewf_virtual_file {
|
||||
// The handle that we use internally. This is NULL for a handle that doesn't exist and non-NULL for a handle that maps to a virtual file.
|
||||
HANDLE virtual_handle;
|
||||
// The path that is being virtualized (ex. C:\sample.txt).
|
||||
wchar_t path[MAX_PATH];
|
||||
// The current length of the virtual file.
|
||||
size_t length;
|
||||
// The current length of the allocated data buffer.
|
||||
size_t alloc_length;
|
||||
// Pointer to some buffer holding file data. This is guaranteed to be at least length bytes in size. If length is zero, this may be NULL.
|
||||
void* data;
|
||||
};
|
||||
|
||||
// An open handle to a ewf_virtual_file.
|
||||
struct ewf_real_handle {
|
||||
// The "real" handle passed to the application as a result of CreateFile, etc.
|
||||
HANDLE real_handle;
|
||||
// The virtual file the real handle points to.
|
||||
struct ewf_virtual_file* virtual_file;
|
||||
// The current read offset.
|
||||
size_t offset;
|
||||
};
|
||||
|
||||
HRESULT ewf_hook_init(const struct ewf_config* config);
|
||||
|
|
@ -18,6 +18,8 @@ platform_lib = static_library(
|
|||
'dns.h',
|
||||
'epay.c',
|
||||
'epay.h',
|
||||
'ewf.c',
|
||||
'ewf.h',
|
||||
'hwmon.c',
|
||||
'hwmon.h',
|
||||
'hwreset.c',
|
||||
|
|
|
|||
|
|
@ -118,11 +118,13 @@ HRESULT misc_hook_init(const struct misc_config *cfg, const char *platform_id)
|
|||
return hr;
|
||||
}
|
||||
|
||||
hr = reg_hook_push_key(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
L"SYSTEM\\SEGA\\SystemProperty\\Master",
|
||||
misc_master_keys,
|
||||
_countof(misc_master_keys));
|
||||
if (!cfg->allowMasterKeyWrite) {
|
||||
hr = reg_hook_push_key(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
L"SYSTEM\\SEGA\\SystemProperty\\Master",
|
||||
misc_master_keys,
|
||||
_countof(misc_master_keys));
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
|
|
@ -130,7 +132,9 @@ HRESULT misc_hook_init(const struct misc_config *cfg, const char *platform_id)
|
|||
|
||||
/* Apply function hooks */
|
||||
|
||||
hook_table_apply(NULL, "user32.dll", misc_syms, _countof(misc_syms));
|
||||
if (!cfg->allowReboot) {
|
||||
hook_table_apply(NULL, "user32.dll", misc_syms, _countof(misc_syms));
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct misc_config {
|
||||
bool enable;
|
||||
bool allowReboot;
|
||||
bool allowMasterKeyWrite;
|
||||
};
|
||||
|
||||
HRESULT misc_hook_init(const struct misc_config *cfg, const char *platform_id);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
#include "hook/table.h"
|
||||
|
||||
#include "platform/netenv.h"
|
||||
|
||||
#include "hook/procaddr.h"
|
||||
#include "platform/nusec.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
|
@ -72,6 +74,14 @@ static uint32_t WINAPI hook_IcmpSendEcho2(
|
|||
uint32_t ReplySize,
|
||||
uint32_t Timeout);
|
||||
|
||||
static int WINAPI hook_sendto(
|
||||
SOCKET s,
|
||||
const char* buf,
|
||||
int len,
|
||||
int flags,
|
||||
const struct sockaddr *to,
|
||||
int tolen);
|
||||
|
||||
/* Link pointers */
|
||||
|
||||
static uint32_t (WINAPI *next_GetAdaptersAddresses)(
|
||||
|
|
@ -108,6 +118,15 @@ static uint32_t (WINAPI *next_IcmpSendEcho2)(
|
|||
uint32_t ReplySize,
|
||||
uint32_t Timeout);
|
||||
|
||||
static int (WINAPI *next_sendto)(
|
||||
SOCKET s,
|
||||
const char *buf,
|
||||
int len,
|
||||
int flags,
|
||||
const struct sockaddr *to,
|
||||
int tolen);
|
||||
|
||||
|
||||
static const struct hook_symbol netenv_hook_syms[] = {
|
||||
{
|
||||
.name = "GetAdaptersAddresses",
|
||||
|
|
@ -132,7 +151,17 @@ static const struct hook_symbol netenv_hook_syms[] = {
|
|||
}
|
||||
};
|
||||
|
||||
static struct hook_symbol netenv_hook_syms_ws2[] = {
|
||||
{
|
||||
.name = "sendto",
|
||||
.patch = hook_sendto,
|
||||
.ordinal = 20,
|
||||
.link = (void **) &next_sendto
|
||||
},
|
||||
};
|
||||
|
||||
static uint32_t netenv_ip_prefix;
|
||||
static uint32_t netenv_ip_bcast;
|
||||
static uint32_t netenv_ip_iface;
|
||||
static uint32_t netenv_ip_router;
|
||||
static uint8_t netenv_mac_addr[6];
|
||||
|
|
@ -155,17 +184,34 @@ HRESULT netenv_hook_init(
|
|||
}
|
||||
|
||||
netenv_ip_prefix = kc_cfg->subnet;
|
||||
netenv_ip_bcast = kc_cfg->bcast;
|
||||
netenv_ip_iface = kc_cfg->subnet | cfg->addr_suffix;
|
||||
netenv_ip_router = kc_cfg->subnet | cfg->router_suffix;
|
||||
memcpy(netenv_mac_addr, cfg->mac_addr, sizeof(netenv_mac_addr));
|
||||
|
||||
netenv_hook_apply_hooks(NULL);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void netenv_hook_apply_hooks(HMODULE mod) {
|
||||
hook_table_apply(
|
||||
NULL,
|
||||
mod,
|
||||
"iphlpapi.dll",
|
||||
netenv_hook_syms,
|
||||
_countof(netenv_hook_syms));
|
||||
|
||||
return S_OK;
|
||||
hook_table_apply(
|
||||
mod,
|
||||
"ws2_32.dll",
|
||||
netenv_hook_syms_ws2,
|
||||
_countof(netenv_hook_syms_ws2));
|
||||
|
||||
proc_addr_table_push(
|
||||
mod,
|
||||
"ws2_32.dll",
|
||||
netenv_hook_syms_ws2,
|
||||
_countof(netenv_hook_syms_ws2));
|
||||
}
|
||||
|
||||
static uint32_t WINAPI hook_GetAdaptersAddresses(
|
||||
|
|
@ -506,3 +552,39 @@ static uint32_t WINAPI hook_IcmpSendEcho2(
|
|||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int WINAPI hook_sendto(
|
||||
SOCKET s,
|
||||
const char* buf,
|
||||
int len,
|
||||
int flags,
|
||||
const struct sockaddr* to,
|
||||
int tolen) {
|
||||
if (to->sa_family != AF_INET) {
|
||||
// we only care about IP packets
|
||||
return next_sendto(s, buf, len, flags, to, tolen);
|
||||
}
|
||||
|
||||
const struct sockaddr_in* original_to = (struct sockaddr_in*)to;
|
||||
|
||||
uint32_t bc_addr = _byteswap_ulong(netenv_ip_prefix | 0xFF);
|
||||
|
||||
if (original_to->sin_addr.S_un.S_addr == bc_addr) {
|
||||
|
||||
uint32_t src_addr = _byteswap_ulong(original_to->sin_addr.S_un.S_addr);
|
||||
uint32_t dest_addr = _byteswap_ulong(netenv_ip_bcast);
|
||||
|
||||
dprintf("Netenv: sendTo broadcast %u.%u.%u.%u -> %u.%u.%u.%u\n",
|
||||
(src_addr >> 24) & 0xff, (src_addr >> 16) & 0xff, (src_addr >> 8) & 0xff, src_addr & 0xff,
|
||||
(dest_addr >> 24) & 0xff, (dest_addr >> 16) & 0xff, (dest_addr >> 8) & 0xff, dest_addr & 0xff);
|
||||
|
||||
struct sockaddr_in modified_to = {0};
|
||||
memcpy(&modified_to, original_to, tolen);
|
||||
|
||||
modified_to.sin_addr.S_un.S_addr = dest_addr;
|
||||
|
||||
return next_sendto(s, buf, len, flags, (struct sockaddr*)&modified_to, sizeof(modified_to));
|
||||
}
|
||||
|
||||
return next_sendto(s, buf, len, flags, to, tolen);
|
||||
}
|
||||
|
|
@ -18,3 +18,4 @@ HRESULT netenv_hook_init(
|
|||
const struct netenv_config *cfg,
|
||||
const struct nusec_config *kc_cfg);
|
||||
|
||||
void netenv_hook_apply_hooks(HMODULE mod);
|
||||
|
|
@ -14,6 +14,7 @@ struct nusec_config {
|
|||
uint8_t region;
|
||||
uint8_t system_flag;
|
||||
uint32_t subnet;
|
||||
uint32_t bcast;
|
||||
uint16_t billing_type;
|
||||
wchar_t billing_ca[MAX_PATH];
|
||||
wchar_t billing_pub[MAX_PATH];
|
||||
|
|
|
|||
|
|
@ -101,5 +101,11 @@ HRESULT platform_hook_init(
|
|||
return hr;
|
||||
}
|
||||
|
||||
hr = ewf_hook_init(&cfg->ewf);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <windows.h>
|
||||
|
||||
#include "platform/ewf.h"
|
||||
#include "platform/amvideo.h"
|
||||
#include "platform/clock.h"
|
||||
#include "platform/dns.h"
|
||||
|
|
@ -30,6 +31,7 @@ struct platform_config {
|
|||
struct vfs_config vfs;
|
||||
struct system_config system;
|
||||
struct openssl_config openssl;
|
||||
struct ewf_config ewf;
|
||||
};
|
||||
|
||||
HRESULT platform_hook_init(
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hooklib/path.h"
|
||||
|
|
@ -14,9 +15,10 @@
|
|||
|
||||
#include "platform/vfs.h"
|
||||
|
||||
#include "ewf.h"
|
||||
#include "util/dprintf.h"
|
||||
|
||||
static void vfs_fixup_path(wchar_t *path, size_t max_count);
|
||||
static void vfs_fixup_path(wchar_t *path, size_t max_count, bool use_relative_envvar);
|
||||
static HRESULT vfs_mkdir_rec(const wchar_t *path);
|
||||
static HRESULT vfs_path_hook(const wchar_t *src, wchar_t *dest, size_t *count);
|
||||
static HRESULT vfs_path_hook_nthome(
|
||||
|
|
@ -35,6 +37,10 @@ static HRESULT vfs_path_hook_apm(
|
|||
const wchar_t *src,
|
||||
wchar_t *dest,
|
||||
size_t *count);
|
||||
static HRESULT vfs_custom_path_hook(
|
||||
const wchar_t *src,
|
||||
wchar_t *dest,
|
||||
size_t *count);
|
||||
static HRESULT vfs_reg_read_amfs(void *bytes, uint32_t *nbytes);
|
||||
static HRESULT vfs_reg_read_appdata(void *bytes, uint32_t *nbytes);
|
||||
|
||||
|
|
@ -85,6 +91,15 @@ static const struct reg_hook_val vfs_reg_vals[] = {
|
|||
|
||||
static struct vfs_config vfs_config;
|
||||
|
||||
const wchar_t* get_vfs_relative_envvar() {
|
||||
static wchar_t path[MAX_PATH];
|
||||
if (!GetEnvironmentVariableW(L"SEGATOOLS_VFS_RELATIVE_PATH", path, MAX_PATH)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
HRESULT vfs_hook_init(const struct vfs_config *config, const char* game_id)
|
||||
{
|
||||
wchar_t temp[MAX_PATH];
|
||||
|
|
@ -145,12 +160,12 @@ HRESULT vfs_hook_init(const struct vfs_config *config, const char* game_id)
|
|||
|
||||
memcpy(&vfs_config, config, sizeof(*config));
|
||||
|
||||
vfs_fixup_path(vfs_nthome_real, _countof(vfs_nthome_real));
|
||||
vfs_fixup_path(vfs_config.amfs, _countof(vfs_config.amfs));
|
||||
vfs_fixup_path(vfs_config.appdata, _countof(vfs_config.appdata));
|
||||
vfs_fixup_path(vfs_nthome_real, _countof(vfs_nthome_real), false);
|
||||
vfs_fixup_path(vfs_config.amfs, _countof(vfs_config.amfs), true);
|
||||
vfs_fixup_path(vfs_config.appdata, _countof(vfs_config.appdata), true);
|
||||
|
||||
if (vfs_config.option[0] != L'\0') {
|
||||
vfs_fixup_path(vfs_config.option, _countof(vfs_config.option));
|
||||
vfs_fixup_path(vfs_config.option, _countof(vfs_config.option), true);
|
||||
}
|
||||
|
||||
hr = vfs_mkdir_rec(vfs_config.amfs);
|
||||
|
|
@ -216,6 +231,12 @@ HRESULT vfs_hook_init(const struct vfs_config *config, const char* game_id)
|
|||
}
|
||||
}
|
||||
|
||||
hr = path_hook_push(vfs_custom_path_hook);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = reg_hook_push_key(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
L"SYSTEM\\SEGA\\SystemProperty\\mount",
|
||||
|
|
@ -236,7 +257,7 @@ HRESULT vfs_hook_init(const struct vfs_config *config, const char* game_id)
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
static void vfs_fixup_path(wchar_t *path, size_t max_count)
|
||||
static void vfs_fixup_path(wchar_t *path, size_t max_count, bool use_adjustment_envvar)
|
||||
{
|
||||
size_t count;
|
||||
wchar_t abspath[MAX_PATH];
|
||||
|
|
@ -246,7 +267,14 @@ static void vfs_fixup_path(wchar_t *path, size_t max_count)
|
|||
assert(max_count <= MAX_PATH);
|
||||
|
||||
if (PathIsRelativeW(path)) {
|
||||
count = GetFullPathNameW(path, _countof(abspath), abspath, NULL);
|
||||
const wchar_t* append = get_vfs_relative_envvar();
|
||||
if (append != NULL && wcslen(append) > 0 && use_adjustment_envvar) {
|
||||
wchar_t temp[MAX_PATH];
|
||||
swprintf_s(temp, MAX_PATH, L"%ls\\%ls", append, path);
|
||||
count = GetFullPathNameW(temp, _countof(abspath), abspath, NULL);
|
||||
} else {
|
||||
count = GetFullPathNameW(path, _countof(abspath), abspath, NULL);
|
||||
}
|
||||
|
||||
/* GetFullPathName's length return value is tricky, because it includes
|
||||
the NUL terminator on failure, but doesn't on success.
|
||||
|
|
@ -600,3 +628,49 @@ static wchar_t* hook_AppImage_getOptionMountRootPath()
|
|||
|
||||
return path;
|
||||
}
|
||||
|
||||
static HRESULT vfs_custom_path_hook(
|
||||
const wchar_t *src,
|
||||
wchar_t *dest,
|
||||
size_t *count){
|
||||
|
||||
assert(src != NULL);
|
||||
assert(count != NULL);
|
||||
|
||||
/* Case-insensitive check to see if src starts with one of our custom paths */
|
||||
|
||||
for (int i = 0; i < MAX_REDIRECTIONS; i++){
|
||||
|
||||
wchar_t* from = vfs_config.redirections_from[i];
|
||||
wchar_t* to = vfs_config.redirections_to[i];
|
||||
|
||||
if (from[0] == '\0' || to[0] == '\0'){
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
if (path_compare_w(src, from, vfs_config.redirections_from_len[i]) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t required = wcslen(to) + 1;
|
||||
|
||||
#if defined(LOG_CUSTOM_VFS)
|
||||
dprintf("Vfs: Redirection matched: %ls -> %ls\n", from, to);
|
||||
#endif
|
||||
|
||||
if (dest != NULL) {
|
||||
|
||||
if (required > *count) {
|
||||
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
}
|
||||
|
||||
wcscpy_s(dest, *count, to);
|
||||
}
|
||||
|
||||
*count = required;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,11 +5,16 @@
|
|||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define MAX_REDIRECTIONS 8
|
||||
|
||||
struct vfs_config {
|
||||
bool enable;
|
||||
wchar_t amfs[MAX_PATH];
|
||||
wchar_t appdata[MAX_PATH];
|
||||
wchar_t option[MAX_PATH];
|
||||
wchar_t redirections_from[MAX_REDIRECTIONS][MAX_PATH];
|
||||
int redirections_from_len[MAX_REDIRECTIONS];
|
||||
wchar_t redirections_to[MAX_REDIRECTIONS][MAX_PATH];
|
||||
};
|
||||
|
||||
HRESULT vfs_hook_init(const struct vfs_config *config, const char* game_id);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include "hooklib/dll.h"
|
||||
#include "hooklib/path.h"
|
||||
#include "hooklib/printer.h"
|
||||
#include "hooklib/printer_chc.h"
|
||||
#include "hooklib/reg.h"
|
||||
#include "hooklib/touch.h"
|
||||
#include "hooklib/serial.h"
|
||||
|
|
|
|||
67
common/util/fg-detect.c
Normal file
67
common/util/fg-detect.c
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
#include <stdbool.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "util/dprintf.h"
|
||||
#include "util/fg-detect.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
static HWND window_handle;
|
||||
static const wchar_t* window_title = NULL;
|
||||
static bool foreground_state = true;
|
||||
static bool partial_match;
|
||||
static wchar_t scanned_title[256];
|
||||
|
||||
static HWND get_window(){
|
||||
if (window_handle != NULL){
|
||||
return window_handle;
|
||||
}
|
||||
|
||||
// try detecting the window
|
||||
HWND hwnd = GetForegroundWindow();
|
||||
if (GetWindowTextW(hwnd, scanned_title, sizeof(scanned_title)) == 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (partial_match) {
|
||||
if (wcsstr(scanned_title, window_title) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (wcscmp(scanned_title, window_title) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
dprintf("FG-Detect: Program window detected\n");
|
||||
window_handle = hwnd;
|
||||
return window_handle;
|
||||
}
|
||||
|
||||
void fgdet_init(const wchar_t* wnd_title, const bool wnd_partial_match) {
|
||||
assert(wnd_title != NULL);
|
||||
|
||||
window_handle = NULL;
|
||||
window_title = wnd_title;
|
||||
partial_match = wnd_partial_match;
|
||||
dprintf("FG-Detect: Searching for \"%ls\"\n", window_title);
|
||||
}
|
||||
|
||||
bool fgdet_in_foreground(){
|
||||
return foreground_state;
|
||||
}
|
||||
|
||||
void fgdet_poll(){
|
||||
if (window_title == NULL){
|
||||
return;
|
||||
} else if (GetForegroundWindow() == get_window()){
|
||||
if (!foreground_state){
|
||||
dprintf("FG-Detect: Got focus\n");
|
||||
foreground_state = true;
|
||||
}
|
||||
} else {
|
||||
if (foreground_state){
|
||||
dprintf("FG-Detect: Lost focus\n");
|
||||
foreground_state = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
8
common/util/fg-detect.h
Normal file
8
common/util/fg-detect.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
#include <stdbool.h>
|
||||
|
||||
void fgdet_init(const wchar_t* wnd_title, const bool wnd_partial_match);
|
||||
|
||||
bool fgdet_in_foreground();
|
||||
|
||||
void fgdet_poll();
|
||||
|
|
@ -17,6 +17,8 @@ util_lib = static_library(
|
|||
'dprintf.h',
|
||||
'dump.c',
|
||||
'dump.h',
|
||||
'fg-detect.c',
|
||||
'fg-detect.h',
|
||||
'get_function_ordinal.c',
|
||||
'get_function_ordinal.h',
|
||||
'lib.c',
|
||||
|
|
|
|||
68
common/y3io/impl/dummy/y3io.c
Normal file
68
common/y3io/impl/dummy/y3io.c
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "util/dprintf.h"
|
||||
|
||||
#include "hooklib/y3.h"
|
||||
|
||||
|
||||
uint16_t y3_io_get_api_version() {
|
||||
return 0x0100;
|
||||
}
|
||||
|
||||
HRESULT y3_io_init() {
|
||||
dprintf("Y3 Dummy Cards: initialized\n");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT y3_io_close() {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT y3_io_get_cards(struct CardInfo* pCardInfo, int* numCards) {
|
||||
memset(pCardInfo, 0, sizeof(struct CardInfo) * *numCards);
|
||||
|
||||
const float paddingX = 86.0f;
|
||||
const float paddingY = 54.0f;
|
||||
|
||||
// Dimensions of the flat panel
|
||||
const float panelHeight = 1232.0f;
|
||||
const float panelWidth = 1160.0f;
|
||||
|
||||
// Number of cards in each row and column
|
||||
const int numRows = 4;
|
||||
const int numCols = 4;
|
||||
int activeCards = numRows * numCols;
|
||||
|
||||
if (*numCards < activeCards) {
|
||||
activeCards = *numCards;
|
||||
}
|
||||
*numCards = activeCards;
|
||||
|
||||
|
||||
// Calculate spacing between cards
|
||||
const float cardWidth = (panelWidth - paddingY * 2) / (numCols - 1);
|
||||
const float cardHeight = (panelHeight - paddingX * 2) / (numRows - 1);
|
||||
|
||||
// Create example card info
|
||||
for (int i = 0; i < activeCards; i++) {
|
||||
int row = i / numCols;
|
||||
int col = i % numCols;
|
||||
|
||||
pCardInfo[i].fX = paddingX + (col * cardHeight);
|
||||
pCardInfo[i].fY = paddingY + (row * cardWidth);
|
||||
pCardInfo[i].fAngle = 0.0f;
|
||||
pCardInfo[i].eCardType = TYPE0;
|
||||
pCardInfo[i].eCardStatus = VALID;
|
||||
pCardInfo[i].uID = 1000 + i;
|
||||
pCardInfo[i].nNumChars = 0;
|
||||
pCardInfo[i].ubChar0.Data = 0;
|
||||
pCardInfo[i].ubChar1.Data = 0;
|
||||
pCardInfo[i].ubChar2.Data = 0;
|
||||
pCardInfo[i].ubChar3.Data = 0;
|
||||
pCardInfo[i].ubChar4.Data = 0;
|
||||
pCardInfo[i].ubChar5.Data = 0;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
20
common/y3io/impl/websockets/3rdparty/cjson/LICENSE
vendored
Normal file
20
common/y3io/impl/websockets/3rdparty/cjson/LICENSE
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
3191
common/y3io/impl/websockets/3rdparty/cjson/cJSON.c
vendored
Normal file
3191
common/y3io/impl/websockets/3rdparty/cjson/cJSON.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
306
common/y3io/impl/websockets/3rdparty/cjson/cJSON.h
vendored
Normal file
306
common/y3io/impl/websockets/3rdparty/cjson/cJSON.h
vendored
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
/*
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef cJSON__h
|
||||
#define cJSON__h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
|
||||
#define __WINDOWS__
|
||||
#endif
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
|
||||
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
|
||||
|
||||
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
|
||||
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
|
||||
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
|
||||
|
||||
For *nix builds that support visibility attribute, you can define similar behavior by
|
||||
|
||||
setting default visibility to hidden by adding
|
||||
-fvisibility=hidden (for gcc)
|
||||
or
|
||||
-xldscope=hidden (for sun cc)
|
||||
to CFLAGS
|
||||
|
||||
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
|
||||
|
||||
*/
|
||||
|
||||
#define CJSON_CDECL __cdecl
|
||||
#define CJSON_STDCALL __stdcall
|
||||
|
||||
/* export symbols by default, this is necessary for copy pasting the C and header file */
|
||||
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_EXPORT_SYMBOLS
|
||||
#endif
|
||||
|
||||
#if defined(CJSON_HIDE_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) type CJSON_STDCALL
|
||||
#elif defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
|
||||
#elif defined(CJSON_IMPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
|
||||
#endif
|
||||
#else /* !__WINDOWS__ */
|
||||
#define CJSON_CDECL
|
||||
#define CJSON_STDCALL
|
||||
|
||||
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
|
||||
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
|
||||
#else
|
||||
#define CJSON_PUBLIC(type) type
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* project version */
|
||||
#define CJSON_VERSION_MAJOR 1
|
||||
#define CJSON_VERSION_MINOR 7
|
||||
#define CJSON_VERSION_PATCH 18
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* cJSON Types: */
|
||||
#define cJSON_Invalid (0)
|
||||
#define cJSON_False (1 << 0)
|
||||
#define cJSON_True (1 << 1)
|
||||
#define cJSON_NULL (1 << 2)
|
||||
#define cJSON_Number (1 << 3)
|
||||
#define cJSON_String (1 << 4)
|
||||
#define cJSON_Array (1 << 5)
|
||||
#define cJSON_Object (1 << 6)
|
||||
#define cJSON_Raw (1 << 7) /* raw json */
|
||||
|
||||
#define cJSON_IsReference 256
|
||||
#define cJSON_StringIsConst 512
|
||||
|
||||
/* The cJSON structure: */
|
||||
typedef struct cJSON
|
||||
{
|
||||
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||
struct cJSON *next;
|
||||
struct cJSON *prev;
|
||||
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||
struct cJSON *child;
|
||||
|
||||
/* The type of the item, as above. */
|
||||
int type;
|
||||
|
||||
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
|
||||
char *valuestring;
|
||||
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
|
||||
int valueint;
|
||||
/* The item's number, if type==cJSON_Number */
|
||||
double valuedouble;
|
||||
|
||||
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||
char *string;
|
||||
} cJSON;
|
||||
|
||||
typedef struct cJSON_Hooks
|
||||
{
|
||||
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
|
||||
void *(CJSON_CDECL *malloc_fn)(size_t sz);
|
||||
void (CJSON_CDECL *free_fn)(void *ptr);
|
||||
} cJSON_Hooks;
|
||||
|
||||
typedef int cJSON_bool;
|
||||
|
||||
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
|
||||
* This is to prevent stack overflows. */
|
||||
#ifndef CJSON_NESTING_LIMIT
|
||||
#define CJSON_NESTING_LIMIT 1000
|
||||
#endif
|
||||
|
||||
/* Limits the length of circular references can be before cJSON rejects to parse them.
|
||||
* This is to prevent stack overflows. */
|
||||
#ifndef CJSON_CIRCULAR_LIMIT
|
||||
#define CJSON_CIRCULAR_LIMIT 10000
|
||||
#endif
|
||||
|
||||
/* returns the version of cJSON as a string */
|
||||
CJSON_PUBLIC(const char*) cJSON_Version(void);
|
||||
|
||||
/* Supply malloc, realloc and free functions to cJSON */
|
||||
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
|
||||
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
|
||||
/* Render a cJSON entity to text for transfer/storage. */
|
||||
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
|
||||
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
|
||||
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
|
||||
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
|
||||
/* Delete a cJSON entity and all subentities. */
|
||||
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
|
||||
|
||||
/* Returns the number of items in an array (or object). */
|
||||
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
|
||||
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
|
||||
/* Get item "string" from object. Case insensitive. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
|
||||
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
|
||||
|
||||
/* Check item type and return its value */
|
||||
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
|
||||
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
|
||||
|
||||
/* These functions check the type of an item */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
|
||||
|
||||
/* These calls create a cJSON item of the appropriate type. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
|
||||
/* raw json */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
|
||||
|
||||
/* Create a string where valuestring references a string so
|
||||
* it will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
|
||||
/* Create an object/array that only references it's elements so
|
||||
* they will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
|
||||
|
||||
/* These utilities create an Array of count items.
|
||||
* The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
|
||||
|
||||
/* Append item to the specified array/object. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
|
||||
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
|
||||
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
|
||||
* writing to `item->string` */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
|
||||
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
|
||||
|
||||
/* Remove/Detach items from Arrays/Objects. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
|
||||
/* Update array items. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
|
||||
|
||||
/* Duplicate a cJSON item */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
|
||||
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
||||
* need to be released. With recurse!=0, it will duplicate any children connected to the item.
|
||||
* The item->next and ->prev pointers are always zero on return from Duplicate. */
|
||||
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
|
||||
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
|
||||
|
||||
/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
|
||||
* The input pointer json cannot point to a read-only address area, such as a string constant,
|
||||
* but should point to a readable and writable address area. */
|
||||
CJSON_PUBLIC(void) cJSON_Minify(char *json);
|
||||
|
||||
/* Helper functions for creating and adding items to an object at the same time.
|
||||
* They return the added item or NULL on failure. */
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
|
||||
|
||||
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
|
||||
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
|
||||
/* helper for the cJSON_SetNumberValue macro */
|
||||
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
|
||||
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
|
||||
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
|
||||
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
|
||||
|
||||
/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/
|
||||
#define cJSON_SetBoolValue(object, boolValue) ( \
|
||||
(object != NULL && ((object)->type & (cJSON_False|cJSON_True))) ? \
|
||||
(object)->type=((object)->type &(~(cJSON_False|cJSON_True)))|((boolValue)?cJSON_True:cJSON_False) : \
|
||||
cJSON_Invalid\
|
||||
)
|
||||
|
||||
/* Macro for iterating over an array or object */
|
||||
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
|
||||
|
||||
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
|
||||
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
|
||||
CJSON_PUBLIC(void) cJSON_free(void *object);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1481
common/y3io/impl/websockets/3rdparty/cjson/cJSON_Utils.c
vendored
Normal file
1481
common/y3io/impl/websockets/3rdparty/cjson/cJSON_Utils.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
88
common/y3io/impl/websockets/3rdparty/cjson/cJSON_Utils.h
vendored
Normal file
88
common/y3io/impl/websockets/3rdparty/cjson/cJSON_Utils.h
vendored
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef cJSON_Utils__h
|
||||
#define cJSON_Utils__h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "cJSON.h"
|
||||
|
||||
/* Implement RFC6901 (https://tools.ietf.org/html/rfc6901) JSON Pointer spec. */
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *pointer);
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointerCaseSensitive(cJSON * const object, const char *pointer);
|
||||
|
||||
/* Implement RFC6902 (https://tools.ietf.org/html/rfc6902) JSON Patch spec. */
|
||||
/* NOTE: This modifies objects in 'from' and 'to' by sorting the elements by their key */
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON * const from, cJSON * const to);
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatchesCaseSensitive(cJSON * const from, cJSON * const to);
|
||||
/* Utility for generating patch array entries. */
|
||||
CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON * const array, const char * const operation, const char * const path, const cJSON * const value);
|
||||
/* Returns 0 for success. */
|
||||
CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON * const object, const cJSON * const patches);
|
||||
CJSON_PUBLIC(int) cJSONUtils_ApplyPatchesCaseSensitive(cJSON * const object, const cJSON * const patches);
|
||||
|
||||
/*
|
||||
// Note that ApplyPatches is NOT atomic on failure. To implement an atomic ApplyPatches, use:
|
||||
//int cJSONUtils_AtomicApplyPatches(cJSON **object, cJSON *patches)
|
||||
//{
|
||||
// cJSON *modme = cJSON_Duplicate(*object, 1);
|
||||
// int error = cJSONUtils_ApplyPatches(modme, patches);
|
||||
// if (!error)
|
||||
// {
|
||||
// cJSON_Delete(*object);
|
||||
// *object = modme;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// cJSON_Delete(modme);
|
||||
// }
|
||||
//
|
||||
// return error;
|
||||
//}
|
||||
// Code not added to library since this strategy is a LOT slower.
|
||||
*/
|
||||
|
||||
/* Implement RFC7386 (https://tools.ietf.org/html/rfc7396) JSON Merge Patch spec. */
|
||||
/* target will be modified by patch. return value is new ptr for target. */
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch);
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatchCaseSensitive(cJSON *target, const cJSON * const patch);
|
||||
/* generates a patch to move from -> to */
|
||||
/* NOTE: This modifies objects in 'from' and 'to' by sorting the elements by their key */
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * const to);
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatchCaseSensitive(cJSON * const from, cJSON * const to);
|
||||
|
||||
/* Given a root object and a target object, construct a pointer from one to the other. */
|
||||
CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const object, const cJSON * const target);
|
||||
|
||||
/* Sorts the members of the object into alphabetical order. */
|
||||
CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object);
|
||||
CJSON_PUBLIC(void) cJSONUtils_SortObjectCaseSensitive(cJSON * const object);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
39
common/y3io/impl/websockets/config.c
Normal file
39
common/y3io/impl/websockets/config.c
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
void y3ws_config_load(struct y3ws_config *cfg, const wchar_t *filename)
|
||||
{
|
||||
assert(cfg != NULL);
|
||||
assert(filename != NULL);
|
||||
|
||||
cfg->enable = GetPrivateProfileIntW(L"y3ws", L"enable", 1, filename);
|
||||
cfg->debug = GetPrivateProfileIntW(L"y3ws", L"debug", 0, filename);
|
||||
|
||||
cfg->port = GetPrivateProfileIntW(L"y3ws", L"port", 3594, filename);
|
||||
|
||||
wchar_t tmpstr[16];
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"y3ws",
|
||||
L"gameId",
|
||||
L"SDEY",
|
||||
tmpstr,
|
||||
_countof(tmpstr),
|
||||
filename);
|
||||
|
||||
wcstombs(cfg->game_id, tmpstr, sizeof(cfg->game_id));
|
||||
|
||||
GetPrivateProfileStringW(
|
||||
L"y3ws",
|
||||
L"cardDirectory",
|
||||
L"DEVICE\\print",
|
||||
cfg->card_path,
|
||||
_countof(cfg->card_path),
|
||||
filename);
|
||||
}
|
||||
19
common/y3io/impl/websockets/config.h
Normal file
19
common/y3io/impl/websockets/config.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "hooklib/dvd.h"
|
||||
#include "hooklib/touch.h"
|
||||
#include "hooklib/printer_chc.h"
|
||||
#include "hooklib/printer_cx.h"
|
||||
|
||||
struct y3ws_config {
|
||||
bool enable;
|
||||
bool debug;
|
||||
|
||||
uint16_t port;
|
||||
char game_id[5];
|
||||
wchar_t card_path[MAX_PATH];
|
||||
};
|
||||
|
||||
void y3ws_config_load(struct y3ws_config *cfg, const wchar_t *filename);
|
||||
354
common/y3io/impl/websockets/y3ws.c
Normal file
354
common/y3io/impl/websockets/y3ws.c
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
#include "3rdparty/cjson/cJSON.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "y3ws.h"
|
||||
|
||||
#include <wchar.h>
|
||||
|
||||
#include "hooklib/y3.h"
|
||||
|
||||
#include "winwebsocket.h"
|
||||
#include "lib/base64.h"
|
||||
|
||||
#include "util/dprintf.h"
|
||||
#include "util/env.h"
|
||||
|
||||
static void onopen(struct wws_connection*);
|
||||
static void onclose(struct wws_connection*);
|
||||
static void onmessage(struct wws_connection*, const char*, size_t);
|
||||
static void onlog(const char*, ...);
|
||||
|
||||
#define PROTOCOL_VERSION 1
|
||||
#define GAME_MAX_CARDS 32
|
||||
#define MAX_CARDS 500
|
||||
#define CARD_ID_LEN 5
|
||||
#define OUTPUT_BUFFER_SIZE (1024 * 1024 * 5)
|
||||
|
||||
static struct y3ws_config cfg;
|
||||
|
||||
static bool is_initialized = false;
|
||||
static struct CardInfo card_info[GAME_MAX_CARDS];
|
||||
static int card_info_size = 0;
|
||||
static CRITICAL_SECTION card_info_lock;
|
||||
|
||||
#pragma region y3-dll functions
|
||||
uint16_t y3_io_get_api_version() {
|
||||
return 0x0100;
|
||||
}
|
||||
|
||||
HRESULT y3_io_init() {
|
||||
if (is_initialized) {
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
y3ws_config_load(&cfg, get_config_path());
|
||||
|
||||
memset(card_info, 0, sizeof(card_info));
|
||||
InitializeCriticalSection(&card_info_lock);
|
||||
|
||||
wws_set_callbacks(onopen, onclose, onmessage, onlog);
|
||||
wws_set_verbose(cfg.debug);
|
||||
|
||||
HRESULT hr = wws_start(cfg.port);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
dprintf("Y3WS: Started server on port %d\n", cfg.port);
|
||||
if (cfg.debug) {
|
||||
dprintf("Y3WS: WS debug logging is on\n");
|
||||
}
|
||||
is_initialized = true;
|
||||
} else {
|
||||
dprintf("Y3WS: Error starting server: %lx\n", hr);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT y3_io_close() {
|
||||
|
||||
HRESULT hr = wws_stop();
|
||||
|
||||
DeleteCriticalSection(&card_info_lock);
|
||||
|
||||
is_initialized = false;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT y3_io_get_cards(struct CardInfo* pCardInfo, int* numCards) {
|
||||
EnterCriticalSection(&card_info_lock);
|
||||
for (int i = 0; i < card_info_size; i++) {
|
||||
memcpy(&pCardInfo[i], &card_info[i], sizeof(struct CardInfo));
|
||||
}
|
||||
*numCards = card_info_size;
|
||||
LeaveCriticalSection(&card_info_lock);
|
||||
return S_OK;
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
#pragma region y3ws functions
|
||||
static void y3ws_make_error_packet(const char* message, char* output_data, size_t* output_size) {
|
||||
dprintf("Y3WS: Error: %s\n", message);
|
||||
*output_size = sprintf_s((char*)output_data, *output_size, "{\"version\":%d, \"success\":false,\"error\":\"%s\"}", PROTOCOL_VERSION, message);
|
||||
}
|
||||
|
||||
static void y3ws_make_success_packet(char* output_data, size_t* output_size) {
|
||||
*output_size = sprintf_s((char*)output_data, *output_size, "{\"version\":%d, \"success\":true}", PROTOCOL_VERSION);
|
||||
}
|
||||
|
||||
static void y3ws_read_cards(char* output_data, size_t* output_size) {
|
||||
WIN32_FIND_DATAW ffd;
|
||||
|
||||
wchar_t path[MAX_PATH];
|
||||
swprintf(path, MAX_PATH, L"%ls\\*", cfg.card_path);
|
||||
|
||||
HANDLE hFind = FindFirstFileW(path, &ffd);
|
||||
if (INVALID_HANDLE_VALUE == hFind) {
|
||||
dprintf("Y3WS: Failed to access directory: %ls (%ld)\n", path, GetLastError());
|
||||
y3ws_make_error_packet("Could not read from card directory", output_data, output_size);
|
||||
return;
|
||||
}
|
||||
|
||||
cJSON* response = cJSON_CreateObject();
|
||||
cJSON* pversion = cJSON_CreateNumber(PROTOCOL_VERSION);
|
||||
cJSON_AddItemToObject(response, "version", pversion);
|
||||
cJSON* success = cJSON_CreateBool(true);
|
||||
cJSON_AddItemToObject(response, "success", success);
|
||||
cJSON* cards = cJSON_CreateArray();
|
||||
cJSON_AddItemToObject(response, "cards", cards);
|
||||
|
||||
int count = 0;
|
||||
do {
|
||||
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
continue;
|
||||
}
|
||||
|
||||
swprintf(path, MAX_PATH, L"%ls\\%ls", cfg.card_path, ffd.cFileName);
|
||||
|
||||
HANDLE hImage = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hImage == INVALID_HANDLE_VALUE) {
|
||||
dprintf("Y3WS: Error opening %ls: %ld\n", path, GetLastError());
|
||||
continue;
|
||||
}
|
||||
DWORD ret = SetFilePointer(hImage, -CARD_ID_LEN, NULL, FILE_END);
|
||||
if (ret == INVALID_SET_FILE_POINTER) {
|
||||
dprintf("Y3WS: Error seeking in %ls: %ld\n", path, GetLastError());
|
||||
continue;
|
||||
}
|
||||
uint8_t buf[CARD_ID_LEN];
|
||||
DWORD bytesRead = 0;
|
||||
if (!ReadFile(hImage, &buf, CARD_ID_LEN, &bytesRead, NULL) || bytesRead != CARD_ID_LEN) {
|
||||
dprintf("Y3WS: Error reading card ID from %ls: %ld\n", path, GetLastError());
|
||||
continue;
|
||||
}
|
||||
|
||||
cJSON* card = cJSON_CreateObject();
|
||||
cJSON_AddItemToArray(cards, card);
|
||||
|
||||
// cJSON isn't wide...
|
||||
char fpatha[MAX_PATH];
|
||||
size_t fpatha_len = 0;
|
||||
wcstombs_s(&fpatha_len, fpatha, MAX_PATH, ffd.cFileName, MAX_PATH);
|
||||
fpatha[fpatha_len] = 0;
|
||||
|
||||
// ReSharper disable once CppRedundantCastExpression
|
||||
cJSON* path_str = cJSON_CreateString(fpatha);
|
||||
cJSON_AddItemToObject(card, "path", path_str);
|
||||
cJSON* card_id = cJSON_CreateNumber((double)((uint64_t)buf[0] >> 32 | (uint64_t)buf[1] >> 24 | (uint64_t)buf[2] >> 16 | (uint64_t)buf[3] >> 8 | buf[4]));
|
||||
cJSON_AddItemToObject(card, "card_id", card_id);
|
||||
|
||||
} while (FindNextFileW(hFind, &ffd) != 0 && count++ < MAX_CARDS);
|
||||
|
||||
cJSON_PrintPreallocated(response, output_data, (int)*output_size, false);
|
||||
*output_size = strlen(output_data);
|
||||
|
||||
dprintf("Y3WS: Sent %d card(s) to the client\n", count);
|
||||
|
||||
cJSON_Delete(response);
|
||||
FindClose(hFind);
|
||||
}
|
||||
|
||||
static void y3ws_read_card_image(char* file_name, char* output_data, size_t* output_size) {
|
||||
wchar_t path[MAX_PATH];
|
||||
swprintf(path, MAX_PATH, L"%ls\\%hs", cfg.card_path, file_name);
|
||||
|
||||
HANDLE hImage = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hImage == INVALID_HANDLE_VALUE) {
|
||||
dprintf("Y3WS: Failed to access file: %ls (%ld)\n", path, GetLastError());
|
||||
y3ws_make_error_packet("Could not read file", output_data, output_size);
|
||||
return;
|
||||
}
|
||||
|
||||
DWORD size = GetFileSize(hImage, NULL);
|
||||
if (size == INVALID_FILE_SIZE) {
|
||||
dprintf("Y3WS: Failed to access file size: %ls (%ld)\n", path, GetLastError());
|
||||
y3ws_make_error_packet("Could not read file", output_data, output_size);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t* buf = malloc(size);
|
||||
size_t b64size = ((size * 4) / 3) + (size / 96) + 6;
|
||||
char* b64buf = malloc(b64size);
|
||||
if (buf == NULL) {
|
||||
dprintf("Y3WS: Allocation error for file: %ls (%ld)\n", path, GetLastError());
|
||||
y3ws_make_error_packet("Could not read file", output_data, output_size);
|
||||
goto end;
|
||||
}
|
||||
|
||||
DWORD bytesRead = 0;
|
||||
if (!ReadFile(hImage, buf, size, &bytesRead, NULL) || bytesRead != size) {
|
||||
dprintf("Y3WS: File read failed: %ls (%ld)\n", path, GetLastError());
|
||||
y3ws_make_error_packet("Could not read file", output_data, output_size);
|
||||
goto end;
|
||||
}
|
||||
|
||||
b64size = base64_encode(buf, size, b64buf);
|
||||
|
||||
if (b64size + 100 > *output_size) {
|
||||
dprintf("Y3WS: Encoded file size exceeds buffer: %ls (%llu / %llu)\n", path, (uint64_t) b64size, (uint64_t) *output_size);
|
||||
y3ws_make_error_packet("File too large", output_data, output_size);
|
||||
}
|
||||
|
||||
*output_size = sprintf_s((char*)output_data, *output_size, "{\"version\":%d, \"success\":true,\"data\":\"%s\"}", PROTOCOL_VERSION, (char*)b64buf);
|
||||
end:
|
||||
free(buf);
|
||||
free(b64buf);
|
||||
}
|
||||
|
||||
static void y3ws_set_cards_from_json(const cJSON* cards, char* output_data, size_t* output_size) {
|
||||
|
||||
const cJSON* card = NULL;
|
||||
card_info_size = 0;
|
||||
|
||||
EnterCriticalSection(&card_info_lock);
|
||||
memset(card_info, 0, sizeof(card_info));
|
||||
cJSON_ArrayForEach(card, cards) {
|
||||
cJSON* x = cJSON_GetObjectItemCaseSensitive(card, "x");
|
||||
cJSON* y = cJSON_GetObjectItemCaseSensitive(card, "y");
|
||||
cJSON* r = cJSON_GetObjectItemCaseSensitive(card, "rotation");
|
||||
cJSON* id = cJSON_GetObjectItemCaseSensitive(card, "card_id");
|
||||
|
||||
if (cJSON_IsNumber(x) && cJSON_IsNumber(y) && cJSON_IsNumber(r) && cJSON_IsNumber(id)) {
|
||||
card_info[card_info_size].eCardStatus = VALID;
|
||||
card_info[card_info_size].fX = (float)x->valuedouble;
|
||||
card_info[card_info_size].fY = (float)y->valuedouble;
|
||||
card_info[card_info_size].fAngle = (float)r->valuedouble;
|
||||
card_info[card_info_size].uID = id->valueint;
|
||||
} else {
|
||||
dprintf("Y3WS: Invalid object in card array at index %d\n", card_info_size);
|
||||
}
|
||||
|
||||
if (++card_info_size >= GAME_MAX_CARDS) {
|
||||
dprintf("Y3WS: too many cards specified, truncating!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
LeaveCriticalSection(&card_info_lock);
|
||||
y3ws_make_success_packet(output_data, output_size);
|
||||
}
|
||||
|
||||
static void y3ws_handle(const char* input_data, uint32_t input_length, char* output_data, size_t* output_size) {
|
||||
cJSON* json = cJSON_ParseWithLength(input_data, input_length);
|
||||
if (json == NULL) {
|
||||
const char *error_ptr = cJSON_GetErrorPtr();
|
||||
|
||||
dprintf("Y3WS: Invalid JSON received!\n");
|
||||
dprintf("Y3WS: Message was: %s\n", input_data);
|
||||
dprintf("Y3WS: Error at: %s\n", error_ptr);
|
||||
y3ws_make_error_packet("Invalid JSON", output_data, output_size);
|
||||
goto end;
|
||||
}
|
||||
|
||||
const cJSON* ver = cJSON_GetObjectItemCaseSensitive(json, "version");
|
||||
const cJSON* cmd = cJSON_GetObjectItemCaseSensitive(json, "command");
|
||||
|
||||
if (!cJSON_IsNumber(ver) || ver->valueint <= 0) {
|
||||
y3ws_make_error_packet("Missing version attribute", output_data, output_size);
|
||||
goto end;
|
||||
}
|
||||
if (!cJSON_IsString(cmd)) {
|
||||
y3ws_make_error_packet("Missing command attribute", output_data, output_size);
|
||||
goto end;
|
||||
}
|
||||
if (ver->valueint != PROTOCOL_VERSION) {
|
||||
y3ws_make_error_packet("Incompatible version", output_data, output_size);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (strcmp(cmd->valuestring, "ping") == 0) {
|
||||
y3ws_make_success_packet(output_data, output_size);
|
||||
} else if (strcmp(cmd->valuestring, "get_game_id") == 0) {
|
||||
*output_size = sprintf_s((char*)output_data, *output_size, "{\"version\":%d, \"success\":true,\"game_id\":\"%s\"}", PROTOCOL_VERSION, cfg.game_id);
|
||||
} else if (strcmp(cmd->valuestring, "get_cards") == 0) {
|
||||
y3ws_read_cards(output_data, output_size);
|
||||
} else if (strcmp(cmd->valuestring, "get_card_image") == 0) {
|
||||
const cJSON* path = cJSON_GetObjectItemCaseSensitive(json, "path");
|
||||
if (cJSON_IsString(path)) {
|
||||
y3ws_read_card_image(path->valuestring, output_data, output_size);
|
||||
} else {
|
||||
y3ws_make_error_packet("Missing attribute", output_data, output_size);
|
||||
}
|
||||
} else if (strcmp(cmd->valuestring, "set_field") == 0) {
|
||||
const cJSON* cards = cJSON_GetObjectItemCaseSensitive(json, "cards");
|
||||
if (cJSON_IsArray(cards)) {
|
||||
y3ws_set_cards_from_json(cards, output_data, output_size);
|
||||
} else {
|
||||
y3ws_make_error_packet("Missing attribute", output_data, output_size);
|
||||
}
|
||||
} else {
|
||||
y3ws_make_error_packet("Unknown command", output_data, output_size);
|
||||
}
|
||||
|
||||
end:
|
||||
cJSON_Delete(json);
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
#pragma region websocket callbacks
|
||||
|
||||
static void onopen(struct wws_connection* client) {
|
||||
dprintf("Y3WS: Connection opened, addr: %s\n", client->ip_str);
|
||||
}
|
||||
|
||||
static void onclose(struct wws_connection* client) {
|
||||
dprintf("Y3WS: Connection closed, addr: %s\n", client->ip_str);
|
||||
}
|
||||
|
||||
static void onmessage(struct wws_connection* client, const char* msg, size_t size) {
|
||||
if (cfg.debug) {
|
||||
dprintf("Y3WS: Message: %.*s\n", (int)size, msg);
|
||||
}
|
||||
char* out_buf = malloc(OUTPUT_BUFFER_SIZE);
|
||||
if (out_buf == NULL) {
|
||||
dprintf("Y3WS: out of memory for allocating response buffer\n");
|
||||
client->is_connected = false;
|
||||
return;
|
||||
}
|
||||
size_t out_size = OUTPUT_BUFFER_SIZE;
|
||||
|
||||
y3ws_handle(msg, size, out_buf, &out_size);
|
||||
HRESULT hr = wws_send(client, out_buf, out_size);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
dprintf("Y3WS: Error sending message: %lx\n", hr);
|
||||
}
|
||||
|
||||
free(out_buf);
|
||||
}
|
||||
|
||||
static void onlog(const char* format, ...) {
|
||||
va_list args;
|
||||
va_start (args, format);
|
||||
dprintf("Websocket: ");
|
||||
dprintfv(format, args);
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
4
common/y3io/impl/websockets/y3ws.h
Normal file
4
common/y3io/impl/websockets/y3ws.h
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
31
common/y3io/impl/y3io.h
Normal file
31
common/y3io/impl/y3io.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "hooklib/y3.h"
|
||||
|
||||
/* Get the version of the Y3 IO API that this DLL supports. This
|
||||
function should return a positive 16-bit integer, where the high byte is
|
||||
the major 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. */
|
||||
uint16_t y3_io_get_api_version();
|
||||
|
||||
/* Initialize the Y3 board. This function will be called before any other
|
||||
y3_io_*() function calls. Errors returned from this function will
|
||||
manifest as a disconnected Y3 board.
|
||||
|
||||
This method may be called multiple times.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
HRESULT y3_io_init();
|
||||
|
||||
/* Fills the given buffer with cards that are detected on the play field.
|
||||
For the values inside CardInfo, see y3.h.
|
||||
The input value of numCards is the size of the pCardInfo array.
|
||||
The output value of numCards is how many cards (>=0) have been set in pCardInfo.
|
||||
|
||||
Minimum API version: 0x0100 */
|
||||
HRESULT y3_io_get_cards(struct CardInfo* pCardInfo, int* numCards);
|
||||
25
common/y3io/meson.build
Normal file
25
common/y3io/meson.build
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
y3io_lib = static_library(
|
||||
'y3io',
|
||||
name_prefix : '',
|
||||
include_directories: inc,
|
||||
implicit_include_directories : false,
|
||||
dependencies : [
|
||||
capnhook.get_variable('hook_dep'),
|
||||
capnhook.get_variable('hooklib_dep'),
|
||||
cwinwebsocket.get_variable('cws_dep'),
|
||||
],
|
||||
link_with : [
|
||||
util_lib,
|
||||
],
|
||||
sources : [
|
||||
'impl/websockets/config.c',
|
||||
'impl/websockets/config.h',
|
||||
'impl/websockets/y3ws.c',
|
||||
'impl/websockets/y3ws.h',
|
||||
'impl/websockets/3rdparty/cjson/cJSON.c',
|
||||
'impl/websockets/3rdparty/cjson/cJSON.h',
|
||||
'impl/websockets/3rdparty/cjson/cJSON_Utils.c',
|
||||
'impl/websockets/3rdparty/cjson/cJSON_Utils.h',
|
||||
'impl/y3io.h',
|
||||
],
|
||||
)
|
||||
8
dist/diva/segatools.ini
vendored
8
dist/diva/segatools.ini
vendored
|
|
@ -77,6 +77,10 @@ serialNo=ACAE01A99999999
|
|||
; Misc. hooks settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[touch]
|
||||
; Enable/Disable Elo Touchsystems 2701 (SEGA 838-14772) emulation.
|
||||
enable=1
|
||||
|
||||
[gfx]
|
||||
; Enables the graphics hook.
|
||||
enable=1
|
||||
|
|
@ -87,7 +91,6 @@ framed=0
|
|||
; Enable DPI awareness for the game process, preventing Windows from stretching the game window if a DPI scaling higher than 100% is used
|
||||
dpiAware=1
|
||||
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Custom IO settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
|
@ -122,6 +125,9 @@ service=0x71
|
|||
; Keyboard button to increment coin counter. Default is the F3 key.
|
||||
coin=0x72
|
||||
|
||||
; Touchscreen input type, currently only "mouse" is supported.
|
||||
mode=mouse
|
||||
|
||||
[slider]
|
||||
cell1=0x51
|
||||
cell2=0x57
|
||||
|
|
|
|||
224
dist/ekt/card_player.html
vendored
Normal file
224
dist/ekt/card_player.html
vendored
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
<!-- very basic thing, I can't do UX/CSS/design, don't blame me, I'm a network engineer lmao -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Taisen Card Field</title>
|
||||
</head>
|
||||
<style>
|
||||
html, body {
|
||||
width: 99%;
|
||||
height: 99%;
|
||||
}
|
||||
.playfield {
|
||||
width: 79%;
|
||||
height: 100%;
|
||||
float: left;
|
||||
border: 1px solid black;
|
||||
}
|
||||
.card_menu {
|
||||
width: 20%;
|
||||
height: 100%;
|
||||
border: 1px solid black;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.card {
|
||||
width: 200px;
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
#playfield .card {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#status {
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var VERSION = 1;
|
||||
|
||||
var socket;
|
||||
var state = 0;
|
||||
var game_id;
|
||||
var cards = [];
|
||||
var current_card_fetch = 0;
|
||||
|
||||
function send(obj){
|
||||
if (!socket){ return; }
|
||||
var data = JSON.stringify(obj);
|
||||
console.log("Sending: " + data);
|
||||
socket.send(data);
|
||||
}
|
||||
|
||||
function connect(){
|
||||
socket = new WebSocket("ws://127.0.0.1:3594/y3io");
|
||||
|
||||
socket.onopen = function(e) {
|
||||
document.getElementById("status").innerText = "Connected. Loading information...";
|
||||
state = 0;
|
||||
send({
|
||||
version: VERSION,
|
||||
command: "get_game_id"
|
||||
});
|
||||
};
|
||||
|
||||
socket.onmessage = function(event) {
|
||||
console.log("Received: " + event.data);
|
||||
handle_response(JSON.parse(event.data));
|
||||
};
|
||||
|
||||
socket.onclose = function(event) {
|
||||
state = -1;
|
||||
document.getElementById("status").innerHTML = "Disconnected. <a href='javascript:window.location.reload();'>Reconnect</a>";
|
||||
};
|
||||
|
||||
socket.onerror = function(error) {
|
||||
console.log(error);
|
||||
};
|
||||
}
|
||||
|
||||
function handle_response(obj){
|
||||
if (!obj.success){
|
||||
alert("Error receiving data while in state " + state + ": " + obj.error);
|
||||
socket.close();
|
||||
return;
|
||||
}
|
||||
if (state == 0){
|
||||
game_id = obj.game_id;
|
||||
document.getElementById("status").innerText = "Connected to "+game_id+". Loading cards...";
|
||||
state = 1;
|
||||
send({
|
||||
version: VERSION,
|
||||
command: "get_cards"
|
||||
});
|
||||
} else if (state == 1){
|
||||
cards = obj.cards;
|
||||
document.getElementById("status").innerText = "Connected to "+game_id+". Loading card images...";
|
||||
document.getElementById("cards").innerHTML = "";
|
||||
document.getElementById("playfield").innerHTML = "";
|
||||
current_card_fetch = 0;
|
||||
state = 2;
|
||||
if (cards.length > 0){
|
||||
fetch_next_card();
|
||||
} else {
|
||||
document.getElementById("status").innerText = "Connected to "+game_id+". No cards available.";
|
||||
}
|
||||
} else if (state == 2){
|
||||
cards[current_card_fetch].image = obj.data;
|
||||
document.getElementById("cards").innerHTML += "<img class='card' src='data:image/bmp;base64, "+obj.data+"' onclick='spawn_card("+current_card_fetch+");' />";
|
||||
|
||||
if (++current_card_fetch >= cards.length){
|
||||
document.getElementById("status").innerText = "Connected to "+game_id+".";
|
||||
state = 3;
|
||||
} else {
|
||||
fetch_next_card();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function fetch_next_card(){
|
||||
var p = cards[current_card_fetch].path;
|
||||
if (!p.includes("_front")){
|
||||
current_card_fetch++;
|
||||
fetch_next_card();
|
||||
return;
|
||||
}
|
||||
send({
|
||||
version: VERSION,
|
||||
command: "get_card_image",
|
||||
path: p
|
||||
});
|
||||
}
|
||||
|
||||
function spawn_card(i){
|
||||
if (state != 3){
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById("playfield").innerHTML += "<img class='card' src='data:image/bmp;base64, "+cards[i].image+"' onmousedown='startMoving(event, this, "+i+");' />";
|
||||
}
|
||||
|
||||
function update_pos(i, x, y){
|
||||
if (state != 3){
|
||||
return;
|
||||
}
|
||||
|
||||
var panelHeight = 1272;
|
||||
var panelWidth = 1260;
|
||||
|
||||
cards[i].x = panelHeight - ((y / window.screen.height) * panelHeight);
|
||||
cards[i].y = panelWidth - ((x / window.screen.width) * panelWidth);
|
||||
cards[i].rotation = 0;
|
||||
|
||||
|
||||
var list = [];
|
||||
for (var j = 0; j < cards.length; j++){
|
||||
var c = cards[j];
|
||||
if (c.x && c.y){
|
||||
list.push({
|
||||
card_id: c.card_id,
|
||||
x: c.x,
|
||||
y: c.y,
|
||||
rotation: c.rotation
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
send({
|
||||
version: VERSION,
|
||||
command: "set_field",
|
||||
cards: list
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
var mousePosition;
|
||||
var offset = [-75,-75];
|
||||
var div;
|
||||
var current_card = -1;
|
||||
var isDown = false;
|
||||
|
||||
function startMoving(e, el, card){
|
||||
div = el;
|
||||
isDown = true;
|
||||
current_card = card;
|
||||
offset = [
|
||||
div.offsetLeft - e.clientX,
|
||||
div.offsetTop - e.clientY
|
||||
];
|
||||
}
|
||||
|
||||
document.addEventListener('mouseup', function() {
|
||||
isDown = false;
|
||||
current_card = -1;
|
||||
}, true);
|
||||
|
||||
document.addEventListener('mousemove', function(event) {
|
||||
event.preventDefault();
|
||||
if (isDown) {
|
||||
mousePosition = {
|
||||
|
||||
x : event.clientX,
|
||||
y : event.clientY
|
||||
|
||||
};
|
||||
div.style.left = (mousePosition.x + offset[0]) + 'px';
|
||||
div.style.top = (mousePosition.y + offset[1]) + 'px';
|
||||
update_pos(current_card, event.clientX, event.clientY);
|
||||
}
|
||||
}, true);
|
||||
</script>
|
||||
<body onload="connect();">
|
||||
<div id="playfield" class="playfield">
|
||||
|
||||
</div>
|
||||
<div class="card_menu">
|
||||
<div id="status">Please wait...</div>
|
||||
<div id="cards">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
13
dist/ekt/config_hook.json
vendored
Normal file
13
dist/ekt/config_hook.json
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"common": {
|
||||
"language": "english"
|
||||
},
|
||||
"network": {
|
||||
"property": {
|
||||
"dhcp": true
|
||||
}
|
||||
},
|
||||
"allnet_auth": {
|
||||
"type": "1.0"
|
||||
}
|
||||
}
|
||||
24
dist/ekt/launch_satellite.bat
vendored
Normal file
24
dist/ekt/launch_satellite.bat
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
@echo off
|
||||
set SEGATOOLS_CONFIG_PATH=.\segatools_satellite.ini
|
||||
|
||||
set SEGATOOLS_VFS_RELATIVE_PATH=..\..\exe
|
||||
set SEGATOOLS_CONFIG_PATH=%SEGATOOLS_VFS_RELATIVE_PATH%\%SEGATOOLS_CONFIG_PATH%
|
||||
|
||||
pushd ..\PackageBase\am_capture
|
||||
start "AM Capture" /min %SEGATOOLS_VFS_RELATIVE_PATH%\inject_x86.exe -d -k %SEGATOOLS_VFS_RELATIVE_PATH%\ekthook_x86.dll AmCapture.exe
|
||||
popd
|
||||
|
||||
set SEGATOOLS_CONFIG_PATH=.\segatools_satellite.ini
|
||||
set SEGATOOLS_VFS_RELATIVE_PATH=
|
||||
|
||||
pushd %~dp0
|
||||
start "AM Daemon" /min inject_x64.exe -d -k ekthook_x64.dll ..\PackageBase\amdaemon.exe -c ..\PackageBase\config_sate.json config_hook.json
|
||||
|
||||
inject_x64 -d -k ekthook_x64.dll ekt.exe -logfile satellite.log -screen-fullscreen 1 -screen-width 1920 -screen-height 1080 -screen-quality Ultra -silent-crashes
|
||||
|
||||
taskkill /f /im AmCapture.exe > nul 2>&1
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
||||
echo.
|
||||
echo Game processes have terminated
|
||||
pause
|
||||
13
dist/ekt/launch_terminal.bat
vendored
Normal file
13
dist/ekt/launch_terminal.bat
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
@echo off
|
||||
set SEGATOOLS_CONFIG_PATH=.\segatools_terminal.ini
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
start "AM Daemon" /min inject_x64 -d -k ekthook_x64.dll ..\PackageBase\amdaemon.exe -c ..\PackageBase\config_terminal.json config_hook.json
|
||||
inject_x64 -d -k ekthook_x64.dll ekt.exe -terminal -logfile terminal.log -screen-fullscreen 1 -screen-width 1920 -screen-height 1080 -screen-quality Ultra -silent-crashes
|
||||
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
||||
echo.
|
||||
echo Game processes have terminated
|
||||
pause
|
||||
187
dist/ekt/segatools_satellite.ini
vendored
Normal file
187
dist/ekt/segatools_satellite.ini
vendored
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
; -----------------------------------------------------------------------------
|
||||
; Path settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[vfs]
|
||||
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
|
||||
amfs=amfs_satellite
|
||||
; Insert the path to the game Option directory here (contains Axxx directories)
|
||||
option=
|
||||
; Create an empty directory somewhere and insert the path here.
|
||||
; This directory may be shared between multiple SEGA games.
|
||||
; NOTE: This has nothing to do with Windows %APPDATA%.
|
||||
appdata=appdata_satellite
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Device settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[aime]
|
||||
; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime
|
||||
; reader.
|
||||
enable=1
|
||||
aimePath=DEVICE\aime.txt
|
||||
|
||||
; Virtual-key code. If this button is **held** then the emulated IC card reader
|
||||
; emulates an IC card in its proximity. A variety of different IC cards can be
|
||||
; emulated; the exact choice of card that is emulated depends on the presence or
|
||||
; absence of the configured card ID files. Default is the Return key.
|
||||
scan=0x0D
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Network settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[dns]
|
||||
; Insert the hostname or IP address of the server you wish to use here.
|
||||
; Note that 127.0.0.1, localhost etc are specifically rejected.
|
||||
default=127.0.0.1
|
||||
|
||||
[netenv]
|
||||
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
|
||||
; SEGA games are somewhat picky about their LAN environment, so leaving this
|
||||
; setting enabled is recommended.
|
||||
enable=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Board settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[keychip]
|
||||
; Keychip serial number. Keychip serials observed in the wild follow this
|
||||
; pattern: `A\d{2}(E|X)-(01|20)[ABCDU]\d{8}`.
|
||||
id=A69E-01A88888888
|
||||
|
||||
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
|
||||
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
||||
; that subnet must start with 192.168.
|
||||
subnet=192.168.189.0
|
||||
|
||||
; Override the game's four-character platform code (e.g. `AAV2` for Nu 2). This
|
||||
; is actually supposed to be a separate three-character `platformId` and
|
||||
; integer `modelType` setting, but they are combined here for convenience.
|
||||
; 1 = Terminal (TM)
|
||||
; 2 = Satellite (ST)
|
||||
platformId=ACA2
|
||||
|
||||
[system]
|
||||
; Enable ALLS system settings.
|
||||
enable=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Misc. hooks settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[unity]
|
||||
; Path to a .NET DLL that should run before the game. Useful for loading
|
||||
; modding frameworks such as BepInEx.
|
||||
targetAssembly=
|
||||
|
||||
[gfx]
|
||||
; Enables the graphics hook.
|
||||
enable=1
|
||||
; Enable DPI awareness for the game process, preventing Windows from stretching the game window if a DPI scaling higher than 100% is used
|
||||
dpiAware=1
|
||||
|
||||
[printer]
|
||||
; G-Printec CX-7000 Printer printer emulation setting.
|
||||
enable=1
|
||||
; Insert the path to the image output directory here.
|
||||
printerOutPath=DEVICE\print
|
||||
|
||||
[flatPanelReader]
|
||||
; Enable the Y3 board emulation.
|
||||
enable=1
|
||||
|
||||
[y3ws]
|
||||
; Enable the Y3 websocket server.
|
||||
enable=1
|
||||
; Set the TCP port on which the Y3 websocket server runs.
|
||||
port=3594
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; LED settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[led15093]
|
||||
; Enable the 837-15093-06 board emulation.
|
||||
enable=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Custom IO settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[aimeio]
|
||||
; To use a custom card reader IO DLL enter its path here.
|
||||
; Leave empty if you want to use Segatools built-in keyboard input.
|
||||
path=
|
||||
|
||||
[ektio]
|
||||
; To use a custom Eiketsu Taisen IO DLL enter its path here.
|
||||
; Leave empty if you want to use Segatools built-in keyboard/gamepad input.
|
||||
path=
|
||||
|
||||
[y3io]
|
||||
; To use a custom Y3 IO DLL enter its path here.
|
||||
; Leave empty if you want to use ... TBA ...
|
||||
path=
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Input settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
; Keyboard bindings are as hexadecimal (prefixed with 0x) or decimal
|
||||
; (not prefixed with 0x) virtual-key codes, a list of which can be found here:
|
||||
;
|
||||
; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
||||
;
|
||||
; This is, admittedly, not the most user-friendly configuration method in the
|
||||
; world. An improved solution will be provided later.
|
||||
|
||||
[io4]
|
||||
; Test button virtual-key code. Default is the F1 key.
|
||||
test=0x70
|
||||
; Service button virtual-key code. Default is the F2 key.
|
||||
service=0x71
|
||||
; Keyboard button to increment coin counter. Default is the F3 key.
|
||||
coin=0x72
|
||||
|
||||
; SW1. Default is the 4 key.
|
||||
sw1=0x34
|
||||
; SW2. Default is the 5 key.
|
||||
sw2=0x35
|
||||
|
||||
; Input API selection for IO4 input emulator.
|
||||
; For now only "keyboard" is supported.
|
||||
mode=keyboard
|
||||
|
||||
[keyboard]
|
||||
|
||||
menu=0x41
|
||||
start=0x42
|
||||
stratagem=0x43
|
||||
stratagem_lock=0x44
|
||||
hougu=0x45
|
||||
ryuuha=0x46
|
||||
|
||||
tenkey_0=0x60
|
||||
tenkey_1=0x61
|
||||
tenkey_2=0x62
|
||||
tenkey_3=0x63
|
||||
tenkey_4=0x64
|
||||
tenkey_5=0x65
|
||||
tenkey_6=0x66
|
||||
tenkey_7=0x67
|
||||
tenkey_8=0x68
|
||||
tenkey_9=0x69
|
||||
tenkey_clear=0x6E
|
||||
tenkey_enter=0x0D
|
||||
|
||||
vol_up=0x21
|
||||
vol_down=0x22
|
||||
|
||||
trackball_up=0x26
|
||||
trackball_right=0x27
|
||||
trackball_down=0x28
|
||||
trackball_left=0x25
|
||||
speed_modifier=10
|
||||
151
dist/ekt/segatools_terminal.ini
vendored
Normal file
151
dist/ekt/segatools_terminal.ini
vendored
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
; -----------------------------------------------------------------------------
|
||||
; Path settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[vfs]
|
||||
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
|
||||
amfs=amfs_terminal
|
||||
; Insert the path to the game Option directory here (contains Axxx directories)
|
||||
option=
|
||||
; Create an empty directory somewhere and insert the path here.
|
||||
; This directory may be shared between multiple SEGA games.
|
||||
; NOTE: This has nothing to do with Windows %APPDATA%.
|
||||
appdata=appdata_terminal
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Device settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[aime]
|
||||
; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime
|
||||
; reader.
|
||||
enable=1
|
||||
aimePath=DEVICE\aime.txt
|
||||
|
||||
; Virtual-key code. If this button is **held** then the emulated IC card reader
|
||||
; emulates an IC card in its proximity. A variety of different IC cards can be
|
||||
; emulated; the exact choice of card that is emulated depends on the presence or
|
||||
; absence of the configured card ID files. Default is the Return key.
|
||||
scan=0x0D
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Network settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[dns]
|
||||
; Insert the hostname or IP address of the server you wish to use here.
|
||||
; Note that 127.0.0.1, localhost etc are specifically rejected.
|
||||
default=127.0.0.1
|
||||
|
||||
[netenv]
|
||||
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
|
||||
; SEGA games are somewhat picky about their LAN environment, so leaving this
|
||||
; setting enabled is recommended.
|
||||
enable=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Board settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[keychip]
|
||||
; Keychip serial number. Keychip serials observed in the wild follow this
|
||||
; pattern: `A\d{2}(E|X)-(01|20)[ABCDU]\d{8}`.
|
||||
id=A69E-01A88888888
|
||||
|
||||
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
|
||||
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
||||
; that subnet must start with 192.168.
|
||||
subnet=192.168.189.0
|
||||
|
||||
; Override the game's four-character platform code (e.g. `AAV2` for Nu 2). This
|
||||
; is actually supposed to be a separate three-character `platformId` and
|
||||
; integer `modelType` setting, but they are combined here for convenience.
|
||||
; 1 = Terminal (TM)
|
||||
; 2 = Satellite (ST)
|
||||
platformId=ACA1
|
||||
|
||||
[system]
|
||||
; Enable ALLS system settings.
|
||||
enable=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Misc. hooks settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[unity]
|
||||
; Enable Unity hook. This will allow you to run custom .NET code before the game
|
||||
enable=1
|
||||
|
||||
; Path to a .NET DLL that should run before the game. Useful for loading
|
||||
; modding frameworks such as BepInEx.
|
||||
targetAssembly=
|
||||
|
||||
[gfx]
|
||||
; Enables the graphics hook.
|
||||
enable=1
|
||||
; Enable DPI awareness for the game process, preventing Windows from stretching the game window if a DPI scaling higher than 100% is used
|
||||
dpiAware=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; LED settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[led15093]
|
||||
; Enable the 837-15093-06 board emulation.
|
||||
enable=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Custom IO settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[aimeio]
|
||||
; To use a custom card reader IO DLL enter its path here.
|
||||
; Leave empty if you want to use Segatools built-in keyboard input.
|
||||
path=
|
||||
|
||||
[ektio]
|
||||
; To use a custom Eiketsu Taisen IO DLL enter its path here.
|
||||
; Leave empty if you want to use Segatools built-in keyboard/gamepad input.
|
||||
path=
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Input settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
; Keyboard bindings are as hexadecimal (prefixed with 0x) or decimal
|
||||
; (not prefixed with 0x) virtual-key codes, a list of which can be found here:
|
||||
;
|
||||
; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
||||
;
|
||||
; This is, admittedly, not the most user-friendly configuration method in the
|
||||
; world. An improved solution will be provided later.
|
||||
|
||||
[io4]
|
||||
; Test button virtual-key code. Default is the F1 key.
|
||||
test=0x70
|
||||
; Service button virtual-key code. Default is the F2 key.
|
||||
service=0x71
|
||||
; Keyboard button to increment coin counter. Default is the F3 key.
|
||||
coin=0x72
|
||||
|
||||
; SW1. Default is the 4 key.
|
||||
sw1=0x34
|
||||
; SW2. Default is the 5 key.
|
||||
sw2=0x35
|
||||
|
||||
; Input API selection for IO4 input emulator.
|
||||
; For now only "keyboard" is supported.
|
||||
mode=keyboard
|
||||
|
||||
[keyboard]
|
||||
|
||||
cancel=0x53
|
||||
decide=0x41
|
||||
|
||||
up=0x26
|
||||
right=0x27
|
||||
down=0x28
|
||||
left=0x25
|
||||
|
||||
left_2=0x4F
|
||||
right_2=0x57
|
||||
16
dist/idac/segatools.ini
vendored
16
dist/idac/segatools.ini
vendored
|
|
@ -36,6 +36,10 @@ scan=0x0D
|
|||
; Note that 127.0.0.1, localhost etc are specifically rejected.
|
||||
default=127.0.0.1
|
||||
|
||||
; Overrides the target of the `tenporouter.loc` and `bbrouter.loc` hostname
|
||||
; lookups. Season 3 needs a tenporouter.loc address of 10.x.y.254.
|
||||
router=10.0.0.254
|
||||
|
||||
[netenv]
|
||||
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
|
||||
; SEGA games are somewhat picky about their LAN environment, so leaving this
|
||||
|
|
@ -271,3 +275,15 @@ damperStrength=100
|
|||
rumbleStrength=100
|
||||
; Rumble duration factor from ms to µs, used to scale the duration of the rumble effect.
|
||||
rumbleDuration=1000
|
||||
; Sets the minimum amount of "weight" or stiffness in the wheel,
|
||||
; even when the car is stationary or moving slowly.
|
||||
; Higher values make the wheel feel heavier and less "springy."
|
||||
baseDamperFraction = 20
|
||||
|
||||
; Deadband (Granularity: 0.1% per unit, max 20.0%)
|
||||
; Creates a small "no-force" zone at the wheel's center.
|
||||
; This prevents the wheel from oscillating or "shaking" when driving straight.
|
||||
; Recommended: 10 (1.0%) to 100 (10.0%).
|
||||
; Default: 20 = 2.0%
|
||||
deadband = 20
|
||||
|
||||
|
|
|
|||
22
dist/idz/segatools.ini
vendored
22
dist/idz/segatools.ini
vendored
|
|
@ -230,6 +230,14 @@ accelAxis=Y
|
|||
; numbered from 1; some software numbers buttons from 0.
|
||||
start=1
|
||||
viewChg=2
|
||||
; DPad is already emulated, but in order to trigger "Time Up" and exit the
|
||||
; course you need to press both left and right on the DPad at the same time.
|
||||
; This is not possible on most devices, so we set the left and right button again.
|
||||
left=7
|
||||
right=8
|
||||
; Additional mapping for up and down buttons in DPad.
|
||||
up=4
|
||||
down=3
|
||||
; Button mappings for the simulated six-speed shifter.
|
||||
shiftDn=5
|
||||
shiftUp=6
|
||||
|
|
@ -258,8 +266,18 @@ reverseBrakeAxis=0
|
|||
constantForceStrength=100
|
||||
; Damper strength, used for steering wheel damper effect.
|
||||
damperStrength=100
|
||||
|
||||
; Rumble strength, used for road surface effects.
|
||||
rumbleStrength=100
|
||||
; Rumble duration factor from ms to µs, used to scale the duration of the rumble effect.
|
||||
rumbleDuration=1000
|
||||
rumbleDuration=1000
|
||||
; Sets the minimum amount of "weight" or stiffness in the wheel,
|
||||
; even when the car is stationary or moving slowly.
|
||||
; Higher values make the wheel feel heavier and less "springy."
|
||||
baseDamperFraction = 20
|
||||
|
||||
; Deadband (Granularity: 0.1% per unit, max 20.0%)
|
||||
; Creates a small "no-force" zone at the wheel's center.
|
||||
; This prevents the wheel from oscillating or "shaking" when driving straight.
|
||||
; Recommended: 10 (1.0%) to 100 (10.0%).
|
||||
; Default: 20 = 2.0%
|
||||
deadband = 20
|
||||
|
|
|
|||
6
dist/mai2/config_hook.json
vendored
Normal file
6
dist/mai2/config_hook.json
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"allnet_auth" :
|
||||
{
|
||||
"type" : "1.0"
|
||||
}
|
||||
}
|
||||
2
dist/mai2/launch.bat
vendored
2
dist/mai2/launch.bat
vendored
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
pushd %~dp0
|
||||
|
||||
start "AM Daemon" /min inject -d -k mai2hook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json
|
||||
start "AM Daemon" /min inject -d -k mai2hook.dll amdaemon.exe -f -c config_common.json config_server.json config_client.json config_hook.json
|
||||
inject -d -k mai2hook.dll sinmai -screen-fullscreen 0 -popupwindow -screen-width 2160 -screen-height 1920 -silent-crashes
|
||||
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
|
|
|||
8
dist/mercury/launch.bat
vendored
8
dist/mercury/launch.bat
vendored
|
|
@ -2,12 +2,14 @@
|
|||
pushd %~dp0
|
||||
|
||||
REM USA
|
||||
REM start "AM Daemon" /min inject -d -k mercuryhook.dll amdaemon.exe -f -c config.json config_lan_install_client.json config_lan_install_server.json config_video_clone.json config_video_dual.json config_video_clone_flip.json config_video_dual_flip.json config_region_exp.json config_region_chn.json config_region_usa.json
|
||||
REM start "AM Daemon" /min inject -d -k mercuryhook.dll amdaemon.exe -c config.json config_lan_install_client.json config_lan_install_server.json config_video_clone.json config_video_dual.json config_video_clone_flip.json config_video_dual_flip.json config_region_exp.json config_region_chn.json config_region_usa.json
|
||||
|
||||
REM JP
|
||||
start "AM Daemon" /min inject -d -k mercuryhook.dll amdaemon.exe -f -c config.json config_lan_install_client.json config_lan_install_server.json config_video_clone.json config_video_dual.json config_video_clone_flip.json config_video_dual_flip.json config_region_exp.json config_region_chn.json config_region_jpn.json
|
||||
start "AM Daemon" /min inject -d -k mercuryhook.dll amdaemon.exe -c config.json config_lan_install_client.json config_lan_install_server.json config_video_clone.json config_video_dual.json config_video_clone_flip.json config_video_dual_flip.json config_region_exp.json config_region_chn.json config_region_jpn.json
|
||||
inject -d -k mercuryhook.dll ../WindowsNoEditor/Mercury/Binaries/Win64/Mercury-Win64-Shipping.exe
|
||||
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
||||
echo Game processes have terminated
|
||||
echo.
|
||||
echo Game processes have terminated
|
||||
pause
|
||||
|
|
|
|||
9
dist/mercury/segatools.ini
vendored
9
dist/mercury/segatools.ini
vendored
|
|
@ -94,13 +94,12 @@ enable=1
|
|||
; Enable DPI awareness for the game process, preventing Windows from stretching the game window if a DPI scaling higher than 100% is used
|
||||
dpiAware=1
|
||||
|
||||
|
||||
; Hooks related to the touch boards
|
||||
[touch]
|
||||
enable=1
|
||||
|
||||
; Hooks related to the LED board (codenamed Elisabeth)
|
||||
[elisabeth]
|
||||
; Hooks related to the LED board (codenamed Elizabeth)
|
||||
[elizabeth]
|
||||
enable=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
|
|
@ -130,6 +129,10 @@ path=
|
|||
; world. An improved solution will be provided later.
|
||||
|
||||
[io4]
|
||||
; Only enables input when the game's main window is focused. Needs to be
|
||||
; disabled for WACVR.
|
||||
foreground=0
|
||||
|
||||
; Test button virtual-key code. Default is the F1 key.
|
||||
test=0x70
|
||||
; Service button virtual-key code. Default is the F2 key.
|
||||
|
|
|
|||
1
dist/mu3/segatools.ini
vendored
1
dist/mu3/segatools.ini
vendored
|
|
@ -90,7 +90,6 @@ enable=1
|
|||
; Enable DPI awareness for the game process, preventing Windows from stretching the game window if a DPI scaling higher than 100% is used
|
||||
dpiAware=1
|
||||
|
||||
|
||||
[unity]
|
||||
; Enable Unity hook. This will allow you to run custom .NET code before the game
|
||||
enable=1
|
||||
|
|
|
|||
228
dist/sekito/card_player.html
vendored
Normal file
228
dist/sekito/card_player.html
vendored
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
<!-- very basic thing, I can't do UX/CSS/design, don't blame me, I'm a network engineer lmao -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Taisen Card Field</title>
|
||||
</head>
|
||||
<style>
|
||||
html, body {
|
||||
width: 99%;
|
||||
height: 99%;
|
||||
}
|
||||
.playfield {
|
||||
width: 79%;
|
||||
height: 100%;
|
||||
float: left;
|
||||
border: 1px solid black;
|
||||
}
|
||||
.card_menu {
|
||||
width: 20%;
|
||||
height: 100%;
|
||||
border: 1px solid black;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.card {
|
||||
width: 200px;
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
#playfield .card {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#status {
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var VERSION = 1;
|
||||
|
||||
var socket;
|
||||
var state = 0;
|
||||
var game_id;
|
||||
var cards = [];
|
||||
var current_card_fetch = 0;
|
||||
|
||||
function send(obj){
|
||||
if (!socket){ return; }
|
||||
var data = JSON.stringify(obj);
|
||||
console.log("Sending: " + data);
|
||||
socket.send(data);
|
||||
}
|
||||
|
||||
function connect(){
|
||||
socket = new WebSocket("ws://127.0.0.1:3594/y3io");
|
||||
|
||||
socket.onopen = function(e) {
|
||||
document.getElementById("status").innerText = "Connected. Loading information...";
|
||||
state = 0;
|
||||
send({
|
||||
version: VERSION,
|
||||
command: "get_game_id"
|
||||
});
|
||||
};
|
||||
|
||||
socket.onmessage = function(event) {
|
||||
console.log("Received: " + event.data);
|
||||
handle_response(JSON.parse(event.data));
|
||||
};
|
||||
|
||||
socket.onclose = function(event) {
|
||||
state = -1;
|
||||
document.getElementById("status").innerHTML = "Disconnected. <a href='javascript:window.location.reload();'>Reconnect</a>";
|
||||
};
|
||||
|
||||
socket.onerror = function(error) {
|
||||
console.log(error);
|
||||
};
|
||||
}
|
||||
|
||||
function handle_response(obj){
|
||||
if (!obj.success){
|
||||
alert("Error receiving data while in state " + state + ": " + obj.error);
|
||||
socket.close();
|
||||
return;
|
||||
}
|
||||
if (state == 0){
|
||||
game_id = obj.game_id;
|
||||
document.getElementById("status").innerText = "Connected to "+game_id+". Loading cards...";
|
||||
state = 1;
|
||||
send({
|
||||
version: VERSION,
|
||||
command: "get_cards"
|
||||
});
|
||||
} else if (state == 1){
|
||||
cards = obj.cards;
|
||||
document.getElementById("status").innerText = "Connected to "+game_id+". Loading card images...";
|
||||
document.getElementById("cards").innerHTML = "";
|
||||
document.getElementById("playfield").innerHTML = "";
|
||||
current_card_fetch = 0;
|
||||
state = 2;
|
||||
if (cards.length > 0){
|
||||
fetch_next_card();
|
||||
} else {
|
||||
document.getElementById("status").innerText = "Connected to "+game_id+". No cards available.";
|
||||
}
|
||||
} else if (state == 2){
|
||||
cards[current_card_fetch].image = obj.data;
|
||||
document.getElementById("cards").innerHTML += "<img class='card' src='data:image/bmp;base64, "+obj.data+"' onclick='spawn_card("+current_card_fetch+");' />";
|
||||
|
||||
if (++current_card_fetch >= cards.length){
|
||||
document.getElementById("status").innerText = "Connected to "+game_id+".";
|
||||
state = 3;
|
||||
} else {
|
||||
fetch_next_card();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function fetch_next_card(){
|
||||
var p = cards[current_card_fetch].path;
|
||||
if (p.includes("holo")){
|
||||
if (++current_card_fetch >= cards.length){
|
||||
document.getElementById("status").innerText = "Connected to "+game_id+".";
|
||||
state = 3;
|
||||
} else {
|
||||
fetch_next_card();
|
||||
}
|
||||
return;
|
||||
}
|
||||
send({
|
||||
version: VERSION,
|
||||
command: "get_card_image",
|
||||
path: p
|
||||
});
|
||||
}
|
||||
|
||||
function spawn_card(i){
|
||||
if (state != 3){
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById("playfield").innerHTML += "<img class='card' src='data:image/bmp;base64, "+cards[i].image+"' onmousedown='startMoving(event, this, "+i+");' />";
|
||||
}
|
||||
|
||||
function update_pos(i, x, y){
|
||||
if (state != 3){
|
||||
return;
|
||||
}
|
||||
|
||||
var panelHeight = 1272;
|
||||
var panelWidth = 1260;
|
||||
|
||||
cards[i].x = panelHeight - ((y / window.screen.height) * panelHeight);
|
||||
cards[i].y = panelWidth - ((x / window.screen.width) * panelWidth);
|
||||
cards[i].rotation = 0;
|
||||
|
||||
|
||||
var list = [];
|
||||
for (var j = 0; j < cards.length; j++){
|
||||
var c = cards[j];
|
||||
if (c.x && c.y){
|
||||
list.push({
|
||||
card_id: c.card_id,
|
||||
x: c.x,
|
||||
y: c.y,
|
||||
rotation: c.rotation
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
send({
|
||||
version: VERSION,
|
||||
command: "set_field",
|
||||
cards: list
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
var mousePosition;
|
||||
var offset = [-75,-75];
|
||||
var div;
|
||||
var current_card = -1;
|
||||
var isDown = false;
|
||||
|
||||
function startMoving(e, el, card){
|
||||
div = el;
|
||||
isDown = true;
|
||||
current_card = card;
|
||||
offset = [
|
||||
div.offsetLeft - e.clientX,
|
||||
div.offsetTop - e.clientY
|
||||
];
|
||||
}
|
||||
|
||||
document.addEventListener('mouseup', function() {
|
||||
isDown = false;
|
||||
current_card = -1;
|
||||
}, true);
|
||||
|
||||
document.addEventListener('mousemove', function(event) {
|
||||
event.preventDefault();
|
||||
if (isDown) {
|
||||
mousePosition = {
|
||||
|
||||
x : event.clientX,
|
||||
y : event.clientY
|
||||
|
||||
};
|
||||
div.style.left = (mousePosition.x + offset[0]) + 'px';
|
||||
div.style.top = (mousePosition.y + offset[1]) + 'px';
|
||||
update_pos(current_card, event.clientX, event.clientY);
|
||||
}
|
||||
}, true);
|
||||
</script>
|
||||
<body onload="connect();">
|
||||
<div id="playfield" class="playfield">
|
||||
|
||||
</div>
|
||||
<div class="card_menu">
|
||||
<div id="status">Please wait...</div>
|
||||
<div id="cards">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
6
dist/sekito/config_hook_satellite.json
vendored
Normal file
6
dist/sekito/config_hook_satellite.json
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"common":
|
||||
{
|
||||
"language": "english"
|
||||
}
|
||||
}
|
||||
35
dist/sekito/config_hook_terminal.json
vendored
Normal file
35
dist/sekito/config_hook_terminal.json
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"common":
|
||||
{
|
||||
"language": "english"
|
||||
},
|
||||
"network":
|
||||
{
|
||||
"property":
|
||||
{
|
||||
"dhcp": true
|
||||
}
|
||||
},
|
||||
"credit" :
|
||||
{
|
||||
"coin_selector_AS6DB" :
|
||||
{
|
||||
"enable" : false
|
||||
}
|
||||
},
|
||||
"aime" :
|
||||
{
|
||||
"enable" : true,
|
||||
"unit" :
|
||||
[
|
||||
{
|
||||
"port" : 1,
|
||||
"id" : 1
|
||||
},
|
||||
{
|
||||
"port" : 12,
|
||||
"id" : 2
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
15
dist/sekito/launch_satellite.bat
vendored
Normal file
15
dist/sekito/launch_satellite.bat
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
@echo off
|
||||
set SEGATOOLS_CONFIG_PATH=.\segatools_satellite.ini
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
start "AM Daemon" /min inject_x64 -d -k sekitohook_x64.dll bin\amdaemon.exe -c bin\config_new.json -c bin\config_video_single.json -c bin\config_video_multi.json -c bin\config_input_sate.json -c bin\config_input_terminal.json -c bin\config_input_terminal_exp.json -c config_hook_satellite.json
|
||||
|
||||
inject_x86 -d -k sekitohook_x86.dll bin\appSate.exe
|
||||
|
||||
taskkill /f /im appSate.exe > nul 2>&1
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
||||
echo.
|
||||
echo Game processes have terminated
|
||||
pause
|
||||
19
dist/sekito/launch_terminal.bat
vendored
Normal file
19
dist/sekito/launch_terminal.bat
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
@echo off
|
||||
set SEGATOOLS_CONFIG_PATH=.\segatools_terminal.ini
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
start "AM Daemon" /min inject_x64 -d -k sekitohook_x64.dll bin\amdaemon.exe -c bin\config_new.json -c bin\config_video_single.json -c bin\config_video_multi.json -c bin\config_input_sate.json -c bin\config_input_terminal.json -c bin\config_input_terminal_exp.json -c config_hook_terminal.json
|
||||
|
||||
start "SKT Server Processes" /min cmd /C bin\server\server_start.bat
|
||||
|
||||
inject_x86 -d -k sekitohook_x86.dll bin\appTerminal.exe
|
||||
|
||||
taskkill /f /im appTerminal.exe > nul 2>&1
|
||||
taskkill /f /im amdaemon.exe > nul 2>&1
|
||||
|
||||
call bin\server\server_stop.bat
|
||||
|
||||
echo.
|
||||
echo Game processes have terminated
|
||||
pause
|
||||
207
dist/sekito/segatools_satellite.ini
vendored
Normal file
207
dist/sekito/segatools_satellite.ini
vendored
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
; -----------------------------------------------------------------------------
|
||||
; Path settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[vfs]
|
||||
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
|
||||
amfs=
|
||||
; Insert the path to the game Option directory here (contains Axxx directories)
|
||||
option=
|
||||
; Create an empty directory somewhere and insert the path here.
|
||||
; This directory may be shared between multiple SEGA games.
|
||||
; NOTE: This has nothing to do with Windows %APPDATA%.
|
||||
appdata=appdata_satellite
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Device settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[aime]
|
||||
; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime
|
||||
; reader.
|
||||
enable=1
|
||||
aimePath=DEVICE\aime.txt
|
||||
|
||||
; Virtual-key code. If this button is **held** then the emulated IC card reader
|
||||
; emulates an IC card in its proximity. A variety of different IC cards can be
|
||||
; emulated; the exact choice of card that is emulated depends on the presence or
|
||||
; absence of the configured card ID files. Default is the Return key.
|
||||
scan=0x0D
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Network settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[dns]
|
||||
; Insert the hostname or IP address of the server you wish to use here.
|
||||
; Note that 127.0.0.1, localhost etc are specifically rejected.
|
||||
default=127.0.0.1
|
||||
|
||||
[netenv]
|
||||
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
|
||||
; SEGA games are somewhat picky about their LAN environment, so leaving this
|
||||
; setting enabled is recommended.
|
||||
enable=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Board settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[keychip]
|
||||
; Keychip serial number. Keychip serials observed in the wild follow this
|
||||
; pattern: `A\d{2}(E|X)-(01|20)[ABCDU]\d{8}`.
|
||||
id=A69E-01A88888888
|
||||
|
||||
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
|
||||
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
||||
; that subnet must start with 192.168.
|
||||
subnet=192.168.189.0
|
||||
|
||||
; Override the game's four-character platform code (e.g. `AAV2` for Nu 2). This
|
||||
; is actually supposed to be a separate three-character `platformId` and
|
||||
; integer `modelType` setting, but they are combined here for convenience.
|
||||
; 1 = Terminal (TM)
|
||||
; 2 = Satellite (ST)
|
||||
platformId=AAV2
|
||||
|
||||
[pcbid]
|
||||
; Set the Windows host name. This should be an ALLS MAIN ID, without the
|
||||
; hyphen (which is not a valid character in a Windows host name).
|
||||
serialNo=ACAE01A99999999
|
||||
|
||||
[gpio]
|
||||
; Emulated Nu DIP switch for Distribution Server setting.
|
||||
;
|
||||
; TODO
|
||||
dipsw1=1
|
||||
|
||||
[eeprom]
|
||||
; Path to the storage file for EEPROM emulation. This file is automatically
|
||||
; created and initialized with a suitable number of zero bytes if it does not
|
||||
; already exist.
|
||||
path=appdata_satellite\eeprom.bin
|
||||
|
||||
[sram]
|
||||
; Path to the storage file for SRAM emulation.
|
||||
path=appdata_satellite\sram.bin
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Misc. hooks settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[printer]
|
||||
; Sinfonia CHC-C320 printer emulation setting.
|
||||
enable=1
|
||||
; Change the printer serial number here.
|
||||
serial_no="5A-A123"
|
||||
; Insert the path to the image output directory here.
|
||||
printerOutPath="DEVICE\print"
|
||||
; Rotate all printed images by 180 degrees.
|
||||
rotate180=1
|
||||
|
||||
[gfx]
|
||||
; Enables the graphics hook.
|
||||
enable=1
|
||||
; Force the game to run windowed.
|
||||
windowed=1
|
||||
; Add a frame to the game window if running windowed.
|
||||
framed=0
|
||||
; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen)
|
||||
monitor=0
|
||||
; Enable DPI awareness for the game process, preventing Windows from stretching the game window if a DPI scaling higher than 100% is used
|
||||
dpiAware=1
|
||||
|
||||
[flatPanelReader]
|
||||
; Enable the Y3 board emulation.
|
||||
enable=1
|
||||
|
||||
[y3ws]
|
||||
; Enable the Y3 websocket server.
|
||||
enable=1
|
||||
; Set the TCP port on which the Y3 websocket server runs.
|
||||
port=3594
|
||||
; Game ID used for clients.
|
||||
gameId=SDDD
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; LED settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[led15093]
|
||||
; Enable the 837-15093-06 board emulation.
|
||||
enable=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Custom IO settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[aimeio]
|
||||
; To use a custom card reader IO DLL enter its path here.
|
||||
; Leave empty if you want to use Segatools built-in keyboard input.
|
||||
path=
|
||||
|
||||
[sekitoio]
|
||||
; To use a custom Eiketsu Taisen IO DLL enter its path here.
|
||||
; Leave empty if you want to use Segatools built-in keyboard/gamepad input.
|
||||
path=
|
||||
|
||||
[y3io]
|
||||
; To use a custom Y3 IO DLL enter its path here.
|
||||
; Leave empty if you want to use ... TBA ...
|
||||
path=
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Input settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
; Keyboard bindings are as hexadecimal (prefixed with 0x) or decimal
|
||||
; (not prefixed with 0x) virtual-key codes, a list of which can be found here:
|
||||
;
|
||||
; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
||||
;
|
||||
; This is, admittedly, not the most user-friendly configuration method in the
|
||||
; world. An improved solution will be provided later.
|
||||
|
||||
[io4]
|
||||
; Test button virtual-key code. Default is the F1 key.
|
||||
test=0x70
|
||||
; Service button virtual-key code. Default is the F2 key.
|
||||
service=0x71
|
||||
; Keyboard button to increment coin counter. Default is the F3 key.
|
||||
coin=0x72
|
||||
|
||||
; SW1. Default is the 4 key.
|
||||
sw1=0x34
|
||||
; SW2. Default is the 5 key.
|
||||
sw2=0x35
|
||||
|
||||
; Input API selection for IO4 input emulator.
|
||||
; For now only "keyboard" is supported.
|
||||
mode=keyboard
|
||||
|
||||
[keyboard]
|
||||
|
||||
menu=0x41
|
||||
start=0x42
|
||||
stratagem=0x43
|
||||
stratagem_lock=0x44
|
||||
hougu=0x45
|
||||
|
||||
tenkey_0=0x60
|
||||
tenkey_1=0x61
|
||||
tenkey_2=0x62
|
||||
tenkey_3=0x63
|
||||
tenkey_4=0x64
|
||||
tenkey_5=0x65
|
||||
tenkey_6=0x66
|
||||
tenkey_7=0x67
|
||||
tenkey_8=0x68
|
||||
tenkey_9=0x69
|
||||
tenkey_clear=0x6E
|
||||
tenkey_enter=0x0D
|
||||
|
||||
trackball_up=0x26
|
||||
trackball_right=0x27
|
||||
trackball_down=0x28
|
||||
trackball_left=0x25
|
||||
speed_modifier=10
|
||||
174
dist/sekito/segatools_terminal.ini
vendored
Normal file
174
dist/sekito/segatools_terminal.ini
vendored
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
; -----------------------------------------------------------------------------
|
||||
; Path settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[vfs]
|
||||
; Insert the path to the game AMFS directory here (contains ICF1 and ICF2)
|
||||
amfs=
|
||||
; Insert the path to the game Option directory here (contains Axxx directories)
|
||||
option=
|
||||
; Create an empty directory somewhere and insert the path here.
|
||||
; This directory may be shared between multiple SEGA games.
|
||||
; NOTE: This has nothing to do with Windows %APPDATA%.
|
||||
appdata=appdata_terminal
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Device settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[aime]
|
||||
; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime
|
||||
; reader.
|
||||
enable=1
|
||||
aimePath=DEVICE\aime.txt
|
||||
|
||||
; Virtual-key code. If this button is **held** then the emulated IC card reader
|
||||
; emulates an IC card in its proximity. A variety of different IC cards can be
|
||||
; emulated; the exact choice of card that is emulated depends on the presence or
|
||||
; absence of the configured card ID files. Default is the Return key.
|
||||
scan=0x0D
|
||||
|
||||
; The terminal-specific Aime card reader to queue for a satellite.
|
||||
[aime2]
|
||||
; Enable Aime card reader assembly emulation. Disable to use a real SEGA Aime
|
||||
; reader.
|
||||
enable=1
|
||||
aimePath=DEVICE\aime.txt
|
||||
|
||||
; Virtual-key code. If this button is **held** then the emulated IC card reader
|
||||
; emulates an IC card in its proximity. A variety of different IC cards can be
|
||||
; emulated; the exact choice of card that is emulated depends on the presence or
|
||||
; absence of the configured card ID files. Default is the Return key.
|
||||
scan=0x0D
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Network settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[dns]
|
||||
; Insert the hostname or IP address of the server you wish to use here.
|
||||
; Note that 127.0.0.1, localhost etc are specifically rejected.
|
||||
default=127.0.0.1
|
||||
|
||||
[netenv]
|
||||
; Simulate an ideal LAN environment. This may interfere with head-to-head play.
|
||||
; SEGA games are somewhat picky about their LAN environment, so leaving this
|
||||
; setting enabled is recommended.
|
||||
enable=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Board settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[keychip]
|
||||
; Keychip serial number. Keychip serials observed in the wild follow this
|
||||
; pattern: `A\d{2}(E|X)-(01|20)[ABCDU]\d{8}`.
|
||||
id=A69E-01A88888888
|
||||
|
||||
; The /24 LAN subnet that the emulated keychip will tell the game to expect.
|
||||
; If you disable netenv then you must set this to your LAN's IP subnet, and
|
||||
; that subnet must start with 192.168.
|
||||
subnet=192.168.189.0
|
||||
|
||||
; Override the game's four-character platform code (e.g. `AAV2` for Nu 2). This
|
||||
; is actually supposed to be a separate three-character `platformId` and
|
||||
; integer `modelType` setting, but they are combined here for convenience.
|
||||
; 1 = Terminal (TM)
|
||||
; 2 = Satellite (ST)
|
||||
platformId=AAV1
|
||||
|
||||
[pcbid]
|
||||
; Set the Windows host name. This should be an ALLS MAIN ID, without the
|
||||
; hyphen (which is not a valid character in a Windows host name).
|
||||
serialNo=ACAE01A99999999
|
||||
|
||||
[eeprom]
|
||||
; Path to the storage file for EEPROM emulation. This file is automatically
|
||||
; created and initialized with a suitable number of zero bytes if it does not
|
||||
; already exist.
|
||||
path=appdata_terminal\eeprom.bin
|
||||
|
||||
[sram]
|
||||
; Path to the storage file for SRAM emulation.
|
||||
path=appdata_terminal\sram.bin
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Misc. hooks settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[gfx]
|
||||
; Enables the graphics hook.
|
||||
enable=1
|
||||
; Force the game to run windowed.
|
||||
windowed=1
|
||||
; Add a frame to the game window if running windowed.
|
||||
framed=0
|
||||
; Select the monitor to run the game on. (Fullscreen only, 0 =primary screen)
|
||||
monitor=0
|
||||
; Enable DPI awareness for the game process, preventing Windows from stretching the game window if a DPI scaling higher than 100% is used
|
||||
dpiAware=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; LED settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[led15093]
|
||||
; Enable the 837-15093-06 board emulation.
|
||||
enable=1
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Custom IO settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
[aimeio]
|
||||
; To use a custom card reader IO DLL enter its path here.
|
||||
; Leave empty if you want to use Segatools built-in keyboard input.
|
||||
path=
|
||||
|
||||
[sekitoio]
|
||||
; To use a custom Eiketsu Taisen IO DLL enter its path here.
|
||||
; Leave empty if you want to use Segatools built-in keyboard/gamepad input.
|
||||
path=
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; Input settings
|
||||
; -----------------------------------------------------------------------------
|
||||
|
||||
; Keyboard bindings are as hexadecimal (prefixed with 0x) or decimal
|
||||
; (not prefixed with 0x) virtual-key codes, a list of which can be found here:
|
||||
;
|
||||
; https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
||||
;
|
||||
; This is, admittedly, not the most user-friendly configuration method in the
|
||||
; world. An improved solution will be provided later.
|
||||
|
||||
[io4]
|
||||
; Test button virtual-key code. Default is the F1 key.
|
||||
test=0x70
|
||||
; Service button virtual-key code. Default is the F2 key.
|
||||
service=0x71
|
||||
; Keyboard button to increment coin counter. Default is the F3 key.
|
||||
coin=0x72
|
||||
|
||||
; SW1. Default is the 4 key.
|
||||
sw1=0x34
|
||||
; SW2. Default is the 5 key.
|
||||
sw2=0x35
|
||||
|
||||
; Input API selection for IO4 input emulator.
|
||||
; For now only "keyboard" is supported.
|
||||
mode=keyboard
|
||||
|
||||
[keyboard]
|
||||
|
||||
cancel=0x53
|
||||
decide=0x41
|
||||
reserve=0x45
|
||||
|
||||
up=0x26
|
||||
right=0x27
|
||||
down=0x28
|
||||
left=0x25
|
||||
|
||||
left_2=0x4F
|
||||
right_2=0x57
|
||||
17
dist/swdc/segatools.ini
vendored
17
dist/swdc/segatools.ini
vendored
|
|
@ -187,6 +187,11 @@ accelAxis=Y
|
|||
; numbered from 1; some software numbers buttons from 0.
|
||||
start=1
|
||||
viewChg=2
|
||||
; DPad is already emulated, but some wheels use buttons rather than a DPad.
|
||||
up=4
|
||||
down=3
|
||||
left=7
|
||||
right=8
|
||||
; Button mappings for the steering wheel paddles.
|
||||
paddleLeft=6
|
||||
paddleRight=5
|
||||
|
|
@ -213,8 +218,18 @@ reverseBrakeAxis=0
|
|||
constantForceStrength=100
|
||||
; Damper strength, used for steering wheel damper effect.
|
||||
damperStrength=100
|
||||
|
||||
; Rumble strength, used for road surface effects.
|
||||
rumbleStrength=100
|
||||
; Rumble duration factor from ms to µs, used to scale the duration of the rumble effect.
|
||||
rumbleDuration=1000
|
||||
; Sets the minimum amount of "weight" or stiffness in the wheel,
|
||||
; even when the car is stationary or moving slowly.
|
||||
; Higher values make the wheel feel heavier and less "springy."
|
||||
baseDamperFraction = 20
|
||||
|
||||
; Deadband (Granularity: 0.1% per unit, max 20.0%)
|
||||
; Creates a small "no-force" zone at the wheel's center.
|
||||
; This prevents the wheel from oscillating or "shaking" when driving straight.
|
||||
; Recommended: 10 (1.0%) to 100 (10.0%).
|
||||
; Default: 20 = 2.0%
|
||||
deadband = 20
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user