From 3327548ca62f6edcdd51d81d45dbf7e5b5bcd27e Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Wed, 3 Sep 2025 16:58:22 +0200 Subject: [PATCH] ekt: implement cx7000 printer --- common/hooklib/config.c | 66 +- common/hooklib/config.h | 6 +- common/hooklib/imageutil.c | 211 +++++ common/hooklib/imageutil.h | 21 + common/hooklib/meson.build | 8 +- common/hooklib/{printer.c => printer_chc.c} | 213 +---- common/hooklib/{printer.h => printer_chc.h} | 6 +- common/hooklib/printer_cx.c | 918 ++++++++++++++++++++ common/hooklib/printer_cx.h | 73 ++ common/unityhook/hook.c | 2 +- common/y3io/meson.build | 2 +- games/apm3hook/config.h | 2 +- games/cmhook/config.c | 2 +- games/cmhook/config.h | 4 +- games/cmhook/dllmain.c | 2 +- games/ekthook/config.c | 1 + games/ekthook/config.h | 2 + games/ekthook/dllmain.c | 3 + games/ektio/ektio.c | 8 + games/fgohook/config.c | 2 +- games/fgohook/config.h | 4 +- games/fgohook/dllmain.c | 4 +- games/kemonohook/config.c | 2 +- games/kemonohook/config.h | 2 +- games/kemonohook/dllmain.c | 4 +- 25 files changed, 1338 insertions(+), 230 deletions(-) create mode 100644 common/hooklib/imageutil.c create mode 100644 common/hooklib/imageutil.h rename common/hooklib/{printer.c => printer_chc.c} (94%) rename common/hooklib/{printer.h => printer_chc.h} (74%) create mode 100644 common/hooklib/printer_cx.c create mode 100644 common/hooklib/printer_cx.h diff --git a/common/hooklib/config.c b/common/hooklib/config.c index b7a84cf..1fa8b38 100644 --- a/common/hooklib/config.c +++ b/common/hooklib/config.c @@ -26,7 +26,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 +84,67 @@ 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); + +} diff --git a/common/hooklib/config.h b/common/hooklib/config.h index 9daed18..db8045b 100644 --- a/common/hooklib/config.h +++ b/common/hooklib/config.h @@ -4,8 +4,10 @@ #include "hooklib/dvd.h" #include "hooklib/touch.h" -#include "hooklib/printer.h" +#include "hooklib/printer_chc.h" +#include "hooklib/printer_cx.h" 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); diff --git a/common/hooklib/imageutil.c b/common/hooklib/imageutil.c new file mode 100644 index 0000000..ed49f03 --- /dev/null +++ b/common/hooklib/imageutil.c @@ -0,0 +1,211 @@ +#include +#include + +#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 = (PBYTE)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 = (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; +} + +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 +} \ No newline at end of file diff --git a/common/hooklib/imageutil.h b/common/hooklib/imageutil.h new file mode 100644 index 0000000..0c29c45 --- /dev/null +++ b/common/hooklib/imageutil.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +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); \ No newline at end of file diff --git a/common/hooklib/meson.build b/common/hooklib/meson.build index b0ad6c2..6c1fb8f 100644 --- a/common/hooklib/meson.build +++ b/common/hooklib/meson.build @@ -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,9 @@ 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', ], ) diff --git a/common/hooklib/printer.c b/common/hooklib/printer_chc.c similarity index 94% rename from common/hooklib/printer.c rename to common/hooklib/printer_chc.c index dbd56f9..001a6c4 100644 --- a/common/hooklib/printer.c +++ b/common/hooklib/printer_chc.c @@ -9,7 +9,9 @@ chc (emihiok) */ -#include "hooklib/printer.h" +// ReSharper disable CppParameterNeverUsed +// ReSharper disable CppDFAConstantFunctionResult +#include "hooklib/printer_chc.h" #include #include @@ -1150,9 +1152,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 +1172,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 +1231,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)); @@ -3147,207 +3149,6 @@ 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; diff --git a/common/hooklib/printer.h b/common/hooklib/printer_chc.h similarity index 74% rename from common/hooklib/printer.h rename to common/hooklib/printer_chc.h index 3e451d1..cb6886b 100644 --- a/common/hooklib/printer.h +++ b/common/hooklib/printer_chc.h @@ -4,7 +4,7 @@ #include #include -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); diff --git a/common/hooklib/printer_cx.c b/common/hooklib/printer_cx.c new file mode 100644 index 0000000..0275197 --- /dev/null +++ b/common/hooklib/printer_cx.c @@ -0,0 +1,918 @@ +// ReSharper disable CppParameterNeverUsed +// ReSharper disable CppParameterMayBeConstPtrOrRef +#include "printer_cx.h" + +#include +#include +#include +#include + +#include "imageutil.h" +#include "hook/procaddr.h" +#include "hook/table.h" +#include "util/dprintf.h" + +#pragma region prototypes +static int __stdcall hook_CXCMD_Retransfer(); + +static bool __stdcall hook_CXCMD_CheckIfConnected(int* pSlotId, int* pId); + +static int __stdcall hook_CXCMD_xImageOut(); + +static int __stdcall hook_CXCMD_MoveCard(int slotId, int id, int dest, int flip, int filmInit, int immed); + +static int __stdcall hook_CXCMD_xWriteMagData(); + +static int __stdcall hook_CXCMD_SecurityPrint(int slotId, int id, int color, int bufferIndex, int immed); + +static int __stdcall hook_CXCMD_ScanPrinterNext(); + +static int __stdcall hook_CXCMD_Print(int slotId, int id, int color, int bufferIndex, int immed); + +static int __stdcall hook_CXCMD_RezeroUnit(int slotId, int id, int action); + +static int __stdcall hook_CXCMD_WriteMagData(); + +static int __stdcall hook_CXCMD_LogSense(int iSlot, int iID, int iPage, uint8_t* pbyBuffer); + +static int __stdcall hook_CXCMD_StandardInquiry(int iSlot, int iID, uint8_t* pbyBuffer); + +static int __stdcall hook_CXCMD_ModeSense(int iSlot, int iID, int iPC, int iPage, uint8_t* pbyBuffer); + +static int __stdcall hook_CXCMD_UpdateFirmware(int iSlot, int iID, char* pFile, int iDataID); + +static int __stdcall hook_CXCMD_ModeSelect(int iSlot, int iID, int iSp, int iPage, uint8_t* pbyData); + +static int __stdcall hook_CXCMD_GetPrintingStatus(); + +static int __stdcall hook_CXCMD_SendDiagnostic(int iSlot, int iID, int iTestMode, int iTestPatten, int iTestCount); + +static int __stdcall hook_CXCMD_RetransferAndTurn(int slotId, int id, int immed); + +static int __stdcall hook_CXCMD_LogSelect(int iSlot, int iID, int iMod); + +static int __stdcall hook_CXCMD_ReadPosition(int slotId, int id, uint8_t* buffer); + +static int __stdcall hook_CXCMD_SecurityLock(); + +static int __stdcall hook_CXCMD_SetPrintingStatus(); + +static int __stdcall hook_CXCMD_xReadISOMagData(); + +static int __stdcall hook_CXCMD_WriteISO3TrackMagData(); + +static int __stdcall hook_CXCMD_PasswordSet(); + +static int __stdcall hook_CXCMD_GetPrinterStatus(); + +static int __stdcall hook_CXCMD_WriteProjectCode(); + +static int __stdcall hook_CXCMD_LoadCard(int slotId, int id, int dest, int flip, int filmInit, int immed); + +static int __stdcall hook_CXCMD_ReadMagData(); + +static int __stdcall hook_CXCMD_ScanPrinter(int* pSlotId, int* pId); + +static int __stdcall hook_CXCMD_xWriteISOMagData(); + +static int __stdcall hook_CXCMD_ICControl(); + +static int __stdcall hook_CXCMD_ImageOut(int slotId, int id, uint8_t* plane, int length, int color, int bufferIndex); + +static int __stdcall hook_CXCMD_ReadBuffer(int iSlot, int iID, int iMode, int iBufferID, uint8_t* pbyData, int iOffset, + int iLength); + +static int __stdcall hook_CXCMD_xReadMagData(); + +static int __stdcall hook_CXCMD_WriteBuffer(int iSlot, int iID, int iMode, int iBufferID, uint8_t* pbyData, int iOffset, + int iLength); + +static int __stdcall hook_CXCMD_DefineLUT(int slotId, int id, int color, int length, uint8_t* buffer); + +static int __stdcall hook_CXCMD_ReadISO3TrackMagData(); + +static int __stdcall hook_CXCMD_TestUnitReady(int slotId, int id); + +static int __stdcall hook_CXCMD_RetransferAndEject(int slotId, int id, int immed); + +static bool __stdcall hook_Lut24_Exchange(const wchar_t* pFile, uint8_t* y, uint8_t* m, uint8_t* c, int sizeY, int sizeM, + int sizeC); + +static bool __stdcall hook_Wdata_create(uint8_t* pbyRdata, uint8_t* pbyGdata, uint8_t* pbyBdata, int iWidth, + int iHeight, bool bPortrait, int iAlgorithim, uint8_t* pbyWdata); + +static int __cdecl hook_init_accesscodekey(BSTR fileName); + +static int __cdecl hook_accesscodekeyoverwriteheader(void* context, BSTR header, int headerLen, BSTR accessheaderkey, int headerkeylen); +#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, + }, +}; + +static const struct hook_symbol hook_ac_syms[] = { + { + .name = "init_accesscodekey", + .patch = hook_init_accesscodekey, + },{ + .name = "accesscodekeyoverwriteheader", + .patch = hook_accesscodekeyoverwriteheader, + }, +}; +#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[4][IMAGE_BUFFER_SIZE]; +static uint8_t front_buffer[4][IMAGE_BUFFER_SIZE]; +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)); + hook_table_apply(target, "accesscode_dll.dll", hook_ac_syms, _countof(hook_ac_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)); + proc_addr_table_push(target, "accesscode_dll.dll", hook_ac_syms, _countof(hook_ac_syms)); +} + +static int __stdcall hook_CXCMD_Retransfer() { + dprintf("CX7000: %s\n", __func__); + dprintf("CX7000: Unimplemented\n"); // unused + return CX_ERROR_USB_COM_3201; +} + +static bool __stdcall hook_CXCMD_CheckIfConnected(int* pSlotId, int* pId) { + dprintf("CX7000: %s\n", __func__); + return printer_config.enable; +} + +static int __stdcall hook_CXCMD_xImageOut() { + dprintf("CX7000: %s\n", __func__); + dprintf("CX7000: Unimplemented\n"); // unused + return CX_ERROR_USB_COM_3201; +} + +static int __stdcall 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 __stdcall hook_CXCMD_xWriteMagData() { + dprintf("CX7000: %s\n", __func__); + dprintf("CX7000: Unimplemented\n"); // unused + return CX_ERROR_USB_COM_3201; +} + +static int __stdcall 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 __stdcall hook_CXCMD_ScanPrinterNext() { + dprintf("CX7000: %s\n", __func__); + dprintf("CX7000: Unimplemented\n"); // unused + return CX_ERROR_USB_COM_3201; +} + +static int __stdcall 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) { + memcpy(back_buffer[color], plane, length); + } else { + memcpy(front_buffer[color], plane, length); + } + + return CX_OK; +} + +static int __stdcall 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 = 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)[1][i]; + raw_image[i * 3 + 1] = 0xFF - (bufferIndex == 0 ? back_buffer : front_buffer)[2][i]; + raw_image[i * 3 + 2] = 0xFF - (bufferIndex == 0 ? back_buffer : front_buffer)[3][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 (ret < 0) { + dprintf("CX7000: WriteDataToBitmapFile returned %d\n", ret); + return CX_ERROR_FATAL_3301; + } + + return CX_OK; +} + +static int __stdcall hook_CXCMD_RezeroUnit(int slotId, int id, int action) { + dprintf("CX7000: %s\n", __func__); + return CX_OK; +} + +static int __stdcall hook_CXCMD_WriteMagData() { + dprintf("CX7000: %s\n", __func__); + dprintf("CX7000: Unimplemented\n"); // unused + return CX_ERROR_USB_COM_3201; +} + +static int __stdcall 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 __stdcall 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 __stdcall 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 __stdcall 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 __stdcall 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 __stdcall hook_CXCMD_GetPrintingStatus() { + dprintf("CX7000: %s\n", __func__); + dprintf("CX7000: Unimplemented\n"); // unused + return CX_ERROR_USB_COM_3201; +} + +static int __stdcall 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 __stdcall hook_CXCMD_RetransferAndTurn(int slotId, int id, int immed) { + dprintf("CX7000: %s\n", __func__); + return CX_OK; +} + +static int __stdcall 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 __stdcall 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 __stdcall hook_CXCMD_SecurityLock() { + dprintf("CX7000: %s\n", __func__); + dprintf("CX7000: Unimplemented\n"); // unused + return CX_ERROR_USB_COM_3201; +} + +static int __stdcall hook_CXCMD_SetPrintingStatus() { + dprintf("CX7000: %s\n", __func__); + dprintf("CX7000: Unimplemented\n"); // unused + return CX_ERROR_USB_COM_3201; +} + +static int __stdcall hook_CXCMD_xReadISOMagData() { + dprintf("CX7000: %s\n", __func__); + dprintf("CX7000: Unimplemented\n"); // unused + return CX_ERROR_USB_COM_3201; +} + +static int __stdcall hook_CXCMD_WriteISO3TrackMagData() { + dprintf("CX7000: %s\n", __func__); + dprintf("CX7000: Unimplemented\n"); // unused + return CX_ERROR_USB_COM_3201; +} + +static int __stdcall hook_CXCMD_PasswordSet() { + dprintf("CX7000: %s\n", __func__); + dprintf("CX7000: Unimplemented\n"); // unused + return CX_ERROR_USB_COM_3201; +} + +static int __stdcall hook_CXCMD_GetPrinterStatus() { + dprintf("CX7000: %s\n", __func__); + dprintf("CX7000: Unimplemented\n"); // unused + return CX_ERROR_USB_COM_3201; +} + +static int __stdcall hook_CXCMD_WriteProjectCode() { + dprintf("CX7000: %s\n", __func__); + dprintf("CX7000: Unimplemented\n"); // unused + return CX_ERROR_USB_COM_3201; +} + +static int __stdcall 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 __stdcall hook_CXCMD_ReadMagData() { + dprintf("CX7000: %s\n", __func__); + dprintf("CX7000: Unimplemented\n"); // unused + return CX_ERROR_USB_COM_3201; +} + +static int __stdcall 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 __stdcall hook_CXCMD_xWriteISOMagData() { + dprintf("CX7000: %s\n", __func__); + dprintf("CX7000: Unimplemented\n"); // unused + return CX_ERROR_USB_COM_3201; +} + +static int __stdcall hook_CXCMD_ICControl() { + dprintf("CX7000: %s\n", __func__); + dprintf("CX7000: Unimplemented\n"); // unused + return CX_ERROR_USB_COM_3201; +} + +static int __stdcall 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 __stdcall hook_CXCMD_xReadMagData() { + dprintf("CX7000: %s\n", __func__); + dprintf("CX7000: Unimplemented\n"); // unused + return CX_ERROR_USB_COM_3201; +} + +static int __stdcall 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 __stdcall 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 __stdcall hook_CXCMD_ReadISO3TrackMagData() { + dprintf("CX7000: %s\n", __func__); + dprintf("CX7000: Unimplemented\n"); // unused + return CX_ERROR_USB_COM_3201; +} + +static int __stdcall 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 __stdcall hook_CXCMD_RetransferAndEject(int slotId, int id, int immed) { + dprintf("CX7000: %s\n", __func__); + return CX_OK; +} + +static bool __stdcall 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 __stdcall 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; +} + +// TODO: these two only exist while we have no decrypted dump of accesscode_dll +static int __cdecl hook_init_accesscodekey(BSTR fileName) { + dprintf("AccesscodeKey: Init\n"); + return 0; +} + +static int __cdecl hook_accesscodekeyoverwriteheader(void* context, BSTR header, int headerLen, BSTR accessheaderkey, int headerkeylen) { + dprintf("AccesscodeKey: Overwrite Header\n"); + return 0; +} \ No newline at end of file diff --git a/common/hooklib/printer_cx.h b/common/hooklib/printer_cx.h new file mode 100644 index 0000000..d86773c --- /dev/null +++ b/common/hooklib/printer_cx.h @@ -0,0 +1,73 @@ +#pragma once +#include +#include +#include + +#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); \ No newline at end of file diff --git a/common/unityhook/hook.c b/common/unityhook/hook.c index 0683a6a..c8b70e0 100644 --- a/common/unityhook/hook.c +++ b/common/unityhook/hook.c @@ -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" diff --git a/common/y3io/meson.build b/common/y3io/meson.build index 1240334..0e566bc 100644 --- a/common/y3io/meson.build +++ b/common/y3io/meson.build @@ -18,6 +18,6 @@ y3io_lib = static_library( 'y3.c', 'y3.h', 'impl/dummy/y3io.c', - 'impl/dummy/y3io.h', + 'impl/y3io.h', ], ) diff --git a/games/apm3hook/config.h b/games/apm3hook/config.h index 8ff2cc3..d42751d 100644 --- a/games/apm3hook/config.h +++ b/games/apm3hook/config.h @@ -7,7 +7,7 @@ #include "hooklib/dvd.h" #include "hooklib/touch.h" -#include "hooklib/printer.h" +#include "hooklib/printer_chc.h" #include "gfxhook/config.h" diff --git a/games/cmhook/config.c b/games/cmhook/config.c index 47fcfa8..c69a5b9 100644 --- a/games/cmhook/config.c +++ b/games/cmhook/config.c @@ -40,7 +40,7 @@ void cm_hook_config_load( io4_config_load(&cfg->io4, filename); vfd_config_load(&cfg->vfd, filename); touch_screen_config_load(&cfg->touch, filename); - printer_config_load(&cfg->printer, filename); + printer_chc_config_load(&cfg->printer, filename); cm_dll_config_load(&cfg->dll, filename); unity_config_load(&cfg->unity, filename); } diff --git a/games/cmhook/config.h b/games/cmhook/config.h index 26d9a7c..c1e5066 100644 --- a/games/cmhook/config.h +++ b/games/cmhook/config.h @@ -6,7 +6,7 @@ #include "hooklib/dvd.h" #include "hooklib/touch.h" -#include "hooklib/printer.h" +#include "hooklib/printer_chc.h" #include "cmhook/cm-dll.h" @@ -22,7 +22,7 @@ struct cm_hook_config { struct vfd_config vfd; struct cm_dll_config dll; struct touch_screen_config touch; - struct printer_config printer; + struct printer_chc_config printer; struct unity_config unity; }; diff --git a/games/cmhook/dllmain.c b/games/cmhook/dllmain.c index 7d5161d..c1d9c4c 100644 --- a/games/cmhook/dllmain.c +++ b/games/cmhook/dllmain.c @@ -59,7 +59,7 @@ static DWORD CALLBACK cm_pre_startup(void) /* Hook external DLL APIs */ - printer_hook_init(&cm_hook_cfg.printer, 0, cm_hook_mod); + printer_chc_hook_init(&cm_hook_cfg.printer, 0, cm_hook_mod); /* Initialize emulation hooks */ diff --git a/games/ekthook/config.c b/games/ekthook/config.c index c5dd118..eee218e 100644 --- a/games/ekthook/config.c +++ b/games/ekthook/config.c @@ -103,6 +103,7 @@ void ekt_hook_config_load( dvd_config_load(&cfg->dvd, filename); led15093_config_load(&cfg->led15093, filename); y3_config_load(&cfg->y3, filename); + printer_cx_config_load(&cfg->printer, filename); unity_config_load(&cfg->unity, filename); ekt_dll_config_load(&cfg->dll, filename); } diff --git a/games/ekthook/config.h b/games/ekthook/config.h index eea8296..9997008 100644 --- a/games/ekthook/config.h +++ b/games/ekthook/config.h @@ -7,6 +7,7 @@ #include "board/led15093.h" #include "hooklib/dvd.h" +#include "hooklib/printer_cx.h" #include "platform/config.h" @@ -24,6 +25,7 @@ struct ekt_hook_config { struct y3_config y3; struct ekt_dll_config dll; struct unity_config unity; + struct printer_cx_config printer; }; void ekt_dll_config_load( diff --git a/games/ekthook/dllmain.c b/games/ekthook/dllmain.c index 36a54cc..a8af610 100644 --- a/games/ekthook/dllmain.c +++ b/games/ekthook/dllmain.c @@ -34,6 +34,7 @@ #include "ekthook/config.h" #include "ekthook/io4.h" +#include "hooklib/printer_cx.h" #include "platform/platform.h" @@ -72,6 +73,8 @@ static DWORD CALLBACK ekt_pre_startup(void) goto fail; } + printer_cx_hook_init(&ekt_hook_cfg.printer, ekt_hook_mod); + /* Initialize emulation hooks */ hr = platform_hook_init( diff --git a/games/ektio/ektio.c b/games/ektio/ektio.c index c0156a8..2ebb879 100644 --- a/games/ektio/ektio.c +++ b/games/ektio/ektio.c @@ -58,6 +58,14 @@ HRESULT ekt_io_poll(void) { ekt_opbtn |= EKT_IO_OPBTN_SERVICE; } + if (GetAsyncKeyState(ekt_io_cfg.vk_sw1) & 0x8000) { + ekt_opbtn |= EKT_IO_OPBTN_SW1; + } + + if (GetAsyncKeyState(ekt_io_cfg.vk_sw2) & 0x8000) { + ekt_opbtn |= EKT_IO_OPBTN_SW2; + } + if (GetAsyncKeyState(ekt_io_cfg.vk_coin) & 0x8000) { if (!ekt_io_coin) { ekt_io_coin = true; diff --git a/games/fgohook/config.c b/games/fgohook/config.c index 766240c..b5b1d24 100644 --- a/games/fgohook/config.c +++ b/games/fgohook/config.c @@ -120,7 +120,7 @@ void fgo_hook_config_load( io4_config_load(&cfg->io4, filename); vfd_config_load(&cfg->vfd, filename); touch_screen_config_load(&cfg->touch, filename); - printer_config_load(&cfg->printer, filename); + printer_chc_config_load(&cfg->printer, filename); fgo_deck_config_load(&cfg->deck, filename); ftdi_config_load(&cfg->ftdi, filename); led15093_config_load(&cfg->led15093, filename); diff --git a/games/fgohook/config.h b/games/fgohook/config.h index ca8895a..57b8bdd 100644 --- a/games/fgohook/config.h +++ b/games/fgohook/config.h @@ -7,7 +7,7 @@ #include "hooklib/dvd.h" #include "hooklib/touch.h" -#include "hooklib/printer.h" +#include "hooklib/printer_chc.h" #include "gfxhook/config.h" @@ -24,7 +24,7 @@ struct fgo_hook_config { struct io4_config io4; struct vfd_config vfd; struct touch_screen_config touch; - struct printer_config printer; + struct printer_chc_config printer; struct deck_config deck; struct ftdi_config ftdi; struct led15093_config led15093; diff --git a/games/fgohook/dllmain.c b/games/fgohook/dllmain.c index fcf5132..c22445d 100644 --- a/games/fgohook/dllmain.c +++ b/games/fgohook/dllmain.c @@ -29,7 +29,7 @@ #include "hooklib/dll.h" #include "hooklib/dvd.h" #include "hooklib/touch.h" -#include "hooklib/printer.h" +#include "hooklib/printer_chc.h" #include "hooklib/createprocess.h" #include "hooklib/serial.h" #include "hooklib/spike.h" @@ -81,7 +81,7 @@ static DWORD CALLBACK fgo_pre_startup(void) /* Hook external DLL APIs */ - printer_hook_init(&fgo_hook_cfg.printer, 4, fgo_hook_mod); + printer_chc_hook_init(&fgo_hook_cfg.printer, 4, fgo_hook_mod); if (fgo_hook_cfg.printer.enable) { dll_hook_push(fgo_hook_mod, L"C330Ausb.dll"); dll_hook_push(fgo_hook_mod, L"C330AFWDLusb.dll"); diff --git a/games/kemonohook/config.c b/games/kemonohook/config.c index c008d88..bd539dd 100644 --- a/games/kemonohook/config.c +++ b/games/kemonohook/config.c @@ -126,7 +126,7 @@ void kemono_hook_config_load( vfd_config_load(&cfg->vfd, filename); kemono_dll_config_load(&cfg->dll, filename); unity_config_load(&cfg->unity, filename); - printer_config_load(&cfg->printer, filename); + printer_chc_config_load(&cfg->printer, filename); amex_config_load(&cfg->amex, filename); led15093_config_load(&cfg->led15093, filename); } diff --git a/games/kemonohook/config.h b/games/kemonohook/config.h index bf76cff..2d3e1ea 100644 --- a/games/kemonohook/config.h +++ b/games/kemonohook/config.h @@ -22,7 +22,7 @@ struct kemono_hook_config { struct vfd_config vfd; struct kemono_dll_config dll; struct unity_config unity; - struct printer_config printer; + struct printer_chc_config printer; struct amex_config amex; struct led15093_config led15093; }; diff --git a/games/kemonohook/dllmain.c b/games/kemonohook/dllmain.c index 3373489..c586517 100644 --- a/games/kemonohook/dllmain.c +++ b/games/kemonohook/dllmain.c @@ -7,7 +7,7 @@ #include "hook/iohook.h" #include "hook/process.h" #include "hook/table.h" -#include "hooklib/printer.h" +#include "hooklib/printer_chc.h" #include "hooklib/serial.h" #include "hooklib/spike.h" #include "kemonohook/config.h" @@ -65,7 +65,7 @@ static DWORD CALLBACK kemono_pre_startup(void) { goto fail; } - printer_hook_init(&kemono_hook_cfg.printer, 0, kemono_hook_mod); + printer_chc_hook_init(&kemono_hook_cfg.printer, 0, kemono_hook_mod); printer_set_dimensions(720, 1028); // printer doesn't call setimageformat /* Initialize emulation hooks */