/* Sinfonia CHC-C3XX Printer emulator Credits: c310emu (rakisaionji) segatools-kancolle (OLEG) c310emu (doremi) */ #include "hooklib/printer.h" #include #include #include #include #include #include #include "hook/table.h" #include "hooklib/dll.h" #include "hooklib/uart.h" #include "util/dprintf.h" #include "util/dump.h" // #define IMAGE_SIZE 0x24FC00 #define IMAGE_SIZE 0x1F0800 #define HOLO_SIZE 0xC5400 static const int8_t idNumber = 0x01; static uint64_t serialNo = 0x333231412D4135; static uint16_t WIDTH = 0; static uint16_t HEIGHT = 0; static bool rotate180 = false; static uint8_t cardRFID[0xC] = {0}; static uint8_t cardDataBuffer[0x20] = {0}; static bool awaitingCardExit = false; static wchar_t printer_out_path[MAX_PATH]; /* Firmware data */ static uint8_t mainFirmware[0x40] = {0}; static uint8_t dspFirmware[0x40] = {0}; static uint8_t paramFirmware[0x40] = {0}; /* printerInfo variables */ static int32_t PAPERINFO[10]; static int32_t CURVE[3][3]; static uint8_t POLISH[2]; static int32_t MTF[9]; /* C3xxFWDLusb API hooks */ int fwdlusb_open(uint16_t *rResult); void fwdlusb_close(); int fwdlusb_listupPrinter(uint8_t *rIdArray); int fwdlusb_listupPrinterSN(uint64_t *rSerialArray); int fwdlusb_selectPrinter(uint8_t printerId, uint16_t *rResult); int fwdlusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult); int fwdlusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen); int fwdlusb_status(uint16_t *rResult); int fwdlusb_statusAll(uint8_t *idArray, uint16_t *rResultArray); int fwdlusb_resetPrinter(uint16_t *rResult); int fwdlusb_updateFirmware(uint8_t update, LPCSTR filename, uint16_t *rResult); int fwdlusb_getFirmwareInfo(uint8_t update, LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult); int fwdlusb_MakeThread(uint16_t maxCount); int fwdlusb_ReleaseThread(uint16_t *rResult); int fwdlusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount); int fwdlusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult); /* C3xxusb API hooks */ int chcusb_MakeThread(uint16_t maxCount); int chcusb_open(uint16_t *rResult); void chcusb_close(); int chcusb_ReleaseThread(uint16_t *rResult); int chcusb_listupPrinter(uint8_t *rIdArray); int chcusb_listupPrinterSN(uint64_t *rSerialArray); int chcusb_selectPrinter(uint8_t printerId, uint16_t *rResult); int chcusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult); int chcusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen); int chcusb_imageformat( uint16_t format, uint16_t ncomp, uint16_t depth, uint16_t width, uint16_t height, uint16_t *rResult); int chcusb_setmtf(int32_t *mtf); int chcusb_makeGamma(uint16_t k, uint8_t *intoneR, uint8_t *intoneG, uint8_t *intoneB); int chcusb_setIcctable( LPCSTR icc1, LPCSTR icc2, uint16_t intents, uint8_t *intoneR, uint8_t *intoneG, uint8_t *intoneB, uint8_t *outtoneR, uint8_t *outtoneG, uint8_t *outtoneB, uint16_t *rResult); int chcusb_copies(uint16_t copies, uint16_t *rResult); int chcusb_status(uint16_t *rResult); int chcusb_statusAll(uint8_t *idArray, uint16_t *rResultArray); int chcusb_startpage(uint16_t postCardState, uint16_t *pageId, uint16_t *rResult); int chcusb_endpage(uint16_t *rResult); int chcusb_write(uint8_t *data, uint32_t *writeSize, uint16_t *rResult); int chcusb_writeLaminate(uint8_t *data, uint32_t *writeSize, uint16_t *rResult); int chcusb_writeHolo(uint8_t *data, uint32_t *writeSize, uint16_t *rResult); int chcusb_setPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult); int chcusb_getGamma(LPCSTR filename, uint8_t *r, uint8_t *g, uint8_t *b, uint16_t *rResult); int chcusb_getMtf(LPCSTR filename, int32_t *mtf, uint16_t *rResult); int chcusb_cancelCopies(uint16_t pageId, uint16_t *rResult); int chcusb_setPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult); int chcusb_getPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult); int chcusb_blinkLED(uint16_t *rResult); int chcusb_resetPrinter(uint16_t *rResult); int chcusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount); int chcusb_getPrintIDStatus(uint16_t pageId, uint8_t *rBuffer, uint16_t *rResult); int chcusb_setPrintStandby(uint16_t position, uint16_t *rResult); int chcusb_testCardFeed(uint16_t mode, uint16_t times, uint16_t *rResult); int chcusb_exitCard(uint16_t *rResult); int chcusb_getCardRfidTID(uint8_t *rCardTID, uint16_t *rResult); int chcusb_commCardRfidReader(uint8_t *sendData, uint8_t *rRecvData, uint32_t sendSize, uint32_t *rRecvSize, uint16_t *rResult); int chcusb_updateCardRfidReader(uint8_t *data, uint32_t size, uint16_t *rResult); int chcusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult); int chcusb_getErrorStatus(uint16_t *rBuffer); int chcusb_setCutList(uint8_t *rData, uint16_t *rResult); int chcusb_setLaminatePattern(uint16_t index, uint8_t *rData, uint16_t *rResult); int chcusb_color_adjustment(LPCSTR filename, int32_t a2, int32_t a3, int16_t a4, int16_t a5, int64_t a6, int64_t a7, uint16_t *rResult); int chcusb_color_adjustmentEx(int32_t a1, int32_t a2, int32_t a3, int16_t a4, int16_t a5, int64_t a6, int64_t a7, uint16_t *rResult); int chcusb_getEEPROM(uint8_t index, uint8_t *rData, uint16_t *rResult); int chcusb_setParameter(uint8_t a1, uint32_t a2, uint16_t *rResult); int chcusb_getParameter(uint8_t a1, uint8_t *a2, uint16_t *rResult); int chcusb_universal_command(int32_t a1, uint8_t a2, int32_t a3, uint8_t *a4, uint16_t *rResult); /* Bitmap writing utils */ DWORD WriteDataToBitmapFile( LPCWSTR lpFilePath, DWORD dwBitCount, DWORD dwWidth, DWORD dwHeight, PBYTE pbInput, DWORD cbInput, PBYTE pbMetadata, DWORD cbMetadata, bool pFlip); DWORD WriteArrayToFile(LPCSTR lpOutputFilePath, LPVOID lpDataTemp, DWORD nDataSize, BOOL isAppend); #define MAX_CARDS 36 // big thanks to Coburn and Mitsuhide for helping me figure out this thing // request format: // 0xe0 - sync // 0x?? - command // 0x?? - payload length // ... - payload // 0x?? - checksum (sum of everything except the sync byte) // // response format: // 0xe0 - sync // 0x?? - command // 0x?? - status code // 0x?? - payload length // ... - payload // 0x?? - checksum enum { DECK_CMD_RESET = 0x41, DECK_CMD_GET_BOOT_FW_VERSION = 0x84, DECK_CMD_GET_BOARD_INFO = 0x85, DECK_CMD_INIT_UNK1 = 0x81, DECK_CMD_GET_APP_FW_VERSION = 0x42, DECK_CMD_READ_DATA = 0x02, DECK_CMD_WRITE = 0x03, DECK_CMD_INIT_UNK2 = 0x04, DECK_CMD_INIT_UNK3 = 0x05, DECK_CMD_READ = 0x06 }; enum { DECK_READ_START = 0x81, DECK_READ_DATA = 0x82, DECK_READ_END = 0x83 }; struct deck_hdr { uint8_t sync; uint8_t cmd; uint8_t nbytes; }; struct deck_resp_hdr { uint8_t sync; uint8_t cmd; uint8_t status; uint8_t nbytes; }; struct deck_resp_get_boot_fw_version { struct deck_resp_hdr hdr; uint8_t boot_fw_version; }; struct deck_resp_get_app_fw_version { struct deck_resp_hdr hdr; uint8_t app_fw_version; }; struct deck_resp_get_board_info { struct deck_resp_hdr hdr; uint8_t board[9]; }; struct deck_resp_read_data { struct deck_resp_hdr hdr; uint8_t card_data[32]; }; struct deck_resp_read { struct deck_resp_hdr hdr; uint8_t card_data[44]; }; union deck_req_any { struct deck_hdr hdr; uint8_t bytes[520]; }; static HRESULT deck_handle_irp(struct irp *irp); static HRESULT deck_handle_irp_locked(struct irp *irp); static HRESULT deck_req_dispatch(const union deck_req_any *req); static HRESULT deck_req_get_boot_fw_version(void); static HRESULT deck_req_get_app_fw_version(void); static HRESULT deck_req_get_board_info(void); static HRESULT deck_req_read(void); static HRESULT deck_req_read_data(void); static HRESULT deck_req_write(const uint8_t *req_bytes); static HRESULT deck_req_nop(uint8_t cmd); static void deck_read_one(void); static HRESULT deck_frame_accept(const struct iobuf *dest); static void deck_frame_sync(struct iobuf *src); static HRESULT deck_frame_decode(struct iobuf *dest, struct iobuf *src); static HRESULT deck_frame_encode(struct iobuf *dest, const void *ptr, size_t nbytes); static HRESULT deck_frame_encode_byte(struct iobuf *dest, uint8_t byte); static CRITICAL_SECTION deck_lock; static struct uart deck_uart; static uint8_t deck_written_bytes[1024]; static uint8_t deck_readable_bytes[1024]; static uint8_t current_card_idx = 0; static bool read_pending = false; /* C3xxFWDLusb hook tbl. */ static const struct hook_symbol C3XXFWDLusb_hooks[] = { {.name = "fwdlusb_open", .patch = fwdlusb_open, .link = NULL}, {.name = "fwdlusb_close", .patch = fwdlusb_close, .link = NULL}, {.name = "fwdlusb_listupPrinter", .patch = fwdlusb_listupPrinter, .link = NULL}, {.name = "fwdlusb_listupPrinterSN", .patch = fwdlusb_listupPrinterSN, .link = NULL}, {.name = "fwdlusb_selectPrinter", .patch = fwdlusb_selectPrinter, .link = NULL}, {.name = "fwdlusb_selectPrinterSN", .patch = fwdlusb_selectPrinterSN, .link = NULL}, {.name = "fwdlusb_getPrinterInfo", .patch = fwdlusb_getPrinterInfo, .link = NULL}, {.name = "fwdlusb_status", .patch = fwdlusb_status, .link = NULL}, {.name = "fwdlusb_statusAll", .patch = fwdlusb_statusAll, .link = NULL}, {.name = "fwdlusb_resetPrinter", .patch = fwdlusb_resetPrinter, .link = NULL}, {.name = "fwdlusb_updateFirmware", .patch = fwdlusb_updateFirmware, .link = NULL}, {.name = "fwdlusb_getFirmwareInfo", .patch = fwdlusb_getFirmwareInfo, .link = NULL}, {.name = "fwdlusb_MakeThread", .patch = fwdlusb_MakeThread, .link = NULL}, {.name = "fwdlusb_ReleaseThread", .patch = fwdlusb_ReleaseThread, .link = NULL}, {.name = "fwdlusb_AttachThreadCount", .patch = fwdlusb_AttachThreadCount, .link = NULL}, {.name = "fwdlusb_getErrorLog", .patch = fwdlusb_getErrorLog, .link = NULL}, }; /* C310A-Busb/C320Ausb/C330Ausb hook tbl. */ static const struct hook_symbol C3XXusb_hooks[] = { {.name = "chcusb_MakeThread", .patch = chcusb_MakeThread, .link = NULL}, {.name = "chcusb_open", .patch = chcusb_open, .link = NULL}, {.name = "chcusb_close", .patch = chcusb_close, .link = NULL}, {.name = "chcusb_ReleaseThread", .patch = chcusb_ReleaseThread, .link = NULL}, {.name = "chcusb_listupPrinter", .patch = chcusb_listupPrinter, .link = NULL}, {.name = "chcusb_listupPrinterSN", .patch = chcusb_listupPrinterSN, .link = NULL}, {.name = "chcusb_selectPrinter", .patch = chcusb_selectPrinter, .link = NULL}, {.name = "chcusb_selectPrinterSN", .patch = chcusb_selectPrinterSN, .link = NULL}, {.name = "chcusb_getPrinterInfo", .patch = chcusb_getPrinterInfo, .link = NULL}, {.name = "chcusb_imageformat", .patch = chcusb_imageformat, .link = NULL}, {.name = "chcusb_setmtf", .patch = chcusb_setmtf, .link = NULL}, {.name = "chcusb_makeGamma", .patch = chcusb_makeGamma, .link = NULL}, {.name = "chcusb_setIcctable", .patch = chcusb_setIcctable, .link = NULL}, {.name = "chcusb_copies", .patch = chcusb_copies, .link = NULL}, {.name = "chcusb_status", .patch = chcusb_status, .link = NULL}, {.name = "chcusb_statusAll", .patch = chcusb_statusAll, .link = NULL}, {.name = "chcusb_startpage", .patch = chcusb_startpage, .link = NULL}, {.name = "chcusb_endpage", .patch = chcusb_endpage, .link = NULL}, {.name = "chcusb_write", .patch = chcusb_write, .link = NULL}, {.name = "chcusb_writeLaminate", .patch = chcusb_writeLaminate, .link = NULL}, {.name = "chcusb_writeHolo", .patch = chcusb_writeHolo, .link = NULL}, {.name = "chcusb_setPrinterInfo", .patch = chcusb_setPrinterInfo, .link = NULL}, {.name = "chcusb_getGamma", .patch = chcusb_getGamma, .link = NULL}, {.name = "chcusb_getMtf", .patch = chcusb_getMtf, .link = NULL}, {.name = "chcusb_cancelCopies", .patch = chcusb_cancelCopies, .link = NULL}, {.name = "chcusb_setPrinterToneCurve", .patch = chcusb_setPrinterToneCurve, .link = NULL}, {.name = "chcusb_getPrinterToneCurve", .patch = chcusb_getPrinterToneCurve, .link = NULL}, {.name = "chcusb_blinkLED", .patch = chcusb_blinkLED, .link = NULL}, {.name = "chcusb_resetPrinter", .patch = chcusb_resetPrinter, .link = NULL}, {.name = "chcusb_AttachThreadCount", .patch = chcusb_AttachThreadCount, .link = NULL}, {.name = "chcusb_getPrintIDStatus", .patch = chcusb_getPrintIDStatus, .link = NULL}, {.name = "chcusb_setPrintStandby", .patch = chcusb_setPrintStandby, .link = NULL}, {.name = "chcusb_testCardFeed", .patch = chcusb_testCardFeed, .link = NULL}, {.name = "chcusb_exitCard", .patch = chcusb_exitCard, .link = NULL}, {.name = "chcusb_getCardRfidTID", .patch = chcusb_getCardRfidTID, .link = NULL}, {.name = "chcusb_commCardRfidReader", .patch = chcusb_commCardRfidReader, .link = NULL}, {.name = "chcusb_updateCardRfidReader", .patch = chcusb_updateCardRfidReader, .link = NULL}, {.name = "chcusb_getErrorLog", .patch = chcusb_getErrorLog, .link = NULL}, {.name = "chcusb_getErrorStatus", .patch = chcusb_getErrorStatus, .link = NULL}, {.name = "chcusb_setCutList", .patch = chcusb_setCutList, .link = NULL}, {.name = "chcusb_setLaminatePattern", .patch = chcusb_setLaminatePattern, .link = NULL}, {.name = "chcusb_color_adjustment", .patch = chcusb_color_adjustment, .link = NULL}, {.name = "chcusb_color_adjustmentEx", .patch = chcusb_color_adjustmentEx, .link = NULL}, {.name = "chcusb_getEEPROM", .patch = chcusb_getEEPROM, .link = NULL}, {.name = "chcusb_setParameter", .patch = chcusb_setParameter, .link = NULL}, {.name = "chcusb_getParameter", .patch = chcusb_getParameter, .link = NULL}, {.name = "chcusb_universal_command", .patch = chcusb_universal_command, .link = NULL}, }; /* C300usb hook tbl */ static struct hook_symbol C300usb_hooks[] = { {.name = "chcusb_MakeThread", .patch = chcusb_MakeThread, .link = NULL}, {.name = "chcusb_open", .patch = chcusb_open, .link = NULL}, {.name = "chcusb_close", .patch = chcusb_close, .link = NULL}, {.name = "chcusb_ReleaseThread", .patch = chcusb_ReleaseThread, .link = NULL}, {.name = "chcusb_listupPrinter", .patch = chcusb_listupPrinter, .link = NULL}, {.name = "chcusb_listupPrinterSN", .patch = chcusb_listupPrinterSN, .link = NULL}, {.name = "chcusb_selectPrinter", .patch = chcusb_selectPrinter, .link = NULL}, {.name = "chcusb_selectPrinterSN", .patch = chcusb_selectPrinterSN, .link = NULL}, {.name = "chcusb_getPrinterInfo", .patch = chcusb_getPrinterInfo, .link = NULL}, {.name = "chcusb_imageformat", .patch = chcusb_imageformat, .link = NULL}, {.name = "chcusb_setmtf", .patch = chcusb_setmtf, .link = NULL}, {.name = "chcusb_makeGamma", .patch = chcusb_makeGamma, .link = NULL}, {.name = "chcusb_setIcctable", .patch = chcusb_setIcctable, .link = NULL}, {.name = "chcusb_copies", .patch = chcusb_copies, .link = NULL}, {.name = "chcusb_status", .patch = chcusb_status, .link = NULL}, {.name = "chcusb_statusAll", .patch = chcusb_statusAll, .link = NULL}, {.name = "chcusb_startpage", .patch = chcusb_startpage, .link = NULL}, {.name = "chcusb_endpage", .patch = chcusb_endpage, .link = NULL}, {.name = "chcusb_write", .patch = chcusb_write, .link = NULL}, {.name = "chcusb_writeLaminate", .patch = chcusb_writeLaminate, .link = NULL}, {.name = "chcusb_setPrinterInfo", .patch = chcusb_setPrinterInfo, .link = NULL}, {.name = "chcusb_getGamma", .patch = chcusb_getGamma, .link = NULL}, {.name = "chcusb_getMtf", .patch = chcusb_getMtf, .link = NULL}, {.name = "chcusb_cancelCopies", .patch = chcusb_cancelCopies, .link = NULL}, {.name = "chcusb_setPrinterToneCurve", .patch = chcusb_setPrinterToneCurve, .link = NULL}, {.name = "chcusb_getPrinterToneCurve", .patch = chcusb_getPrinterToneCurve, .link = NULL}, {.name = "chcusb_blinkLED", .patch = chcusb_blinkLED, .link = NULL}, {.name = "chcusb_resetPrinter", .patch = chcusb_resetPrinter, .link = NULL}, {.name = "chcusb_AttachThreadCount", .patch = chcusb_AttachThreadCount, .link = NULL}, {.name = "chcusb_getPrintIDStatus", .patch = chcusb_getPrintIDStatus, .link = NULL}, {.name = "chcusb_setPrintStandby", .patch = chcusb_setPrintStandby, .link = NULL}, {.name = "chcusb_testCardFeed", .patch = chcusb_testCardFeed, .link = NULL}, {.name = "chcusb_setParameter", .patch = chcusb_setParameter, .link = NULL}, {.name = "chcusb_getParameter", .patch = chcusb_getParameter, .link = NULL}, {.name = "chcusb_getErrorStatus", .patch = chcusb_getErrorStatus, .link = NULL}, {.name = "chcusb_setCutList", .patch = chcusb_setCutList, .link = NULL}, {.name = "chcusb_setLaminatePattern", .patch = chcusb_setLaminatePattern, .link = NULL}, {.name = "chcusb_color_adjustment", .patch = chcusb_color_adjustment, .link = NULL}, {.name = "chcusb_color_adjustmentEx", .patch = chcusb_color_adjustmentEx, .link = NULL}, {.name = "chcusb_getEEPROM", .patch = chcusb_getEEPROM, .link = NULL}, {.name = "chcusb_universal_command", .patch = chcusb_universal_command, .link = NULL}, }; static struct printer_config printer_config; void printer_hook_init(const struct printer_config *cfg, int rfid_port_no, HINSTANCE self) { HANDLE fwFile = NULL; DWORD bytesRead = 0; assert(cfg != NULL); if (!cfg->enable) { return; } /* Set serial and rotate cfg */ memcpy(&serialNo, cfg->serial_no, sizeof(serialNo)); _byteswap_uint64(serialNo); rotate180 = cfg->rotate_180; memcpy(&printer_config, cfg, sizeof(*cfg)); hook_table_apply(NULL, "C300usb.dll", C300usb_hooks, _countof(C300usb_hooks)); hook_table_apply(NULL, "C300FWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks)); hook_table_apply(NULL, "C310Ausb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks)); hook_table_apply(NULL, "C310Busb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks)); hook_table_apply(NULL, "C310FWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks)); hook_table_apply(NULL, "C310BFWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks)); hook_table_apply(NULL, "C320Ausb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks)); hook_table_apply(NULL, "C320AFWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks)); hook_table_apply(NULL, "C330Ausb.dll", C3XXusb_hooks, _countof(C3XXusb_hooks)); hook_table_apply(NULL, "C330AFWDLusb.dll", C3XXFWDLusb_hooks, _countof(C3XXFWDLusb_hooks)); if (self != NULL) { dll_hook_push(self, L"C300usb.dll"); // TODO: This doesn't work. Unity moment dll_hook_push(self, L"C300FWDLusb.dll"); // TODO: ...and this... dll_hook_push(self, L"C310Ausb.dll"); dll_hook_push(self, L"C310Busb.dll"); // TODO: ...and this... dll_hook_push(self, L"C310FWDLusb.dll"); dll_hook_push(self, L"C310BFWDLusb.dll"); // TODO: ...aaaand this. dll_hook_push(self, L"C320Ausb.dll"); dll_hook_push(self, L"C320AFWDLusb.dll"); dll_hook_push(self, L"C330Ausb.dll"); dll_hook_push(self, L"C330AFWDLusb.dll"); } // Load firmware if has previously been written to fwFile = CreateFileW(cfg->main_fw_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (fwFile != NULL) { ReadFile(fwFile, mainFirmware, sizeof(mainFirmware), &bytesRead, NULL); CloseHandle(fwFile); } fwFile = CreateFileW(cfg->dsp_fw_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (fwFile != NULL) { ReadFile(fwFile, dspFirmware, sizeof(dspFirmware), &bytesRead, NULL); CloseHandle(fwFile); } fwFile = CreateFileW(cfg->param_fw_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (fwFile != NULL) { ReadFile(fwFile, paramFirmware, sizeof(dspFirmware), &bytesRead, NULL); CloseHandle(fwFile); } CreateDirectoryW(cfg->printer_out_path, NULL); memcpy(printer_out_path, cfg->printer_out_path, MAX_PATH); if (rfid_port_no != 0) { InitializeCriticalSection(&deck_lock); uart_init(&deck_uart, rfid_port_no); deck_uart.written.bytes = deck_written_bytes; deck_uart.written.nbytes = sizeof(deck_written_bytes); deck_uart.readable.bytes = deck_readable_bytes; deck_uart.readable.nbytes = sizeof(deck_readable_bytes); dprintf("Printer: RFID: hook enabled.\n"); if (FAILED(iohook_push_handler(deck_handle_irp))) { dprintf("Printer: RFID: failed to hook IRP handler.\n"); } } dprintf("Printer: hook enabled.\n"); } static void generate_rfid(void) { for (int i = 0; i < sizeof(cardRFID); i++) cardRFID[i] = rand(); dprintf("Printer: New card RFID:\n"); dump(cardRFID, sizeof(cardRFID)); } static HRESULT deck_handle_irp(struct irp *irp) { HRESULT hr; assert(irp != NULL); if (!uart_match_irp(&deck_uart, irp)) { return iohook_invoke_next(irp); } EnterCriticalSection(&deck_lock); hr = deck_handle_irp_locked(irp); LeaveCriticalSection(&deck_lock); return hr; } static HRESULT deck_handle_irp_locked(struct irp *irp) { uint8_t req[1024]; struct iobuf req_iobuf; HRESULT hr; if (irp->op == IRP_OP_OPEN) { dprintf("Printer: RFID: Starting backend\n"); } hr = uart_handle_irp(&deck_uart, irp); if (SUCCEEDED(hr) && irp->op == IRP_OP_READ && read_pending == true) { deck_read_one(); return S_OK; } if (FAILED(hr) || irp->op != IRP_OP_WRITE) { return hr; } for (;;) { // if (deck_uart.written.pos != 0) { // dprintf("Printer: RFID: TX Buffer:\n"); // dump_iobuf(&deck_uart.written); // } req_iobuf.bytes = req; req_iobuf.nbytes = sizeof(req); req_iobuf.pos = 0; hr = deck_frame_decode(&req_iobuf, &deck_uart.written); if (hr != S_OK) { if (FAILED(hr)) { dprintf("Printer: RFID: Deframe error: %x, %d %d\n", (int)hr, (int)req_iobuf.nbytes, (int)req_iobuf.pos); } return hr; } // dprintf("Printer: RFID: Deframe Buffer:\n"); // dump_iobuf(&req_iobuf); hr = deck_req_dispatch((const union deck_req_any *)&req); if (FAILED(hr)) { dprintf("Printer: RFID: Processing error: %x\n", (int)hr); } // dprintf("Printer: RFID: Written bytes:\n"); // dump_iobuf(&deck_uart.readable); } } static HRESULT deck_req_dispatch(const union deck_req_any *req) { switch (req->hdr.cmd) { case DECK_CMD_RESET: case DECK_CMD_INIT_UNK1: case DECK_CMD_INIT_UNK2: case DECK_CMD_INIT_UNK3: return deck_req_nop(req->hdr.cmd); case DECK_CMD_GET_BOOT_FW_VERSION: return deck_req_get_boot_fw_version(); case DECK_CMD_GET_APP_FW_VERSION: return deck_req_get_app_fw_version(); case DECK_CMD_GET_BOARD_INFO: return deck_req_get_board_info(); case DECK_CMD_READ: return deck_req_read(); case DECK_CMD_READ_DATA: return deck_req_read_data(); case DECK_CMD_WRITE: return deck_req_write(req->bytes); default: dprintf("Printer: RFID: Unhandled command %#02x\n", req->hdr.cmd); return S_OK; } } static HRESULT deck_req_get_boot_fw_version(void) { struct deck_resp_get_boot_fw_version resp; dprintf("Printer: RFID: Get Boot FW Version\n"); resp.hdr.sync = 0xE0; resp.hdr.cmd = DECK_CMD_GET_BOOT_FW_VERSION; resp.hdr.status = 0; resp.hdr.nbytes = 1; resp.boot_fw_version = 0x90; return deck_frame_encode(&deck_uart.readable, &resp, sizeof(resp)); } static HRESULT deck_req_get_app_fw_version(void) { struct deck_resp_get_app_fw_version resp; dprintf("Printer: RFID: Get App FW Version\n"); resp.hdr.sync = 0xE0; resp.hdr.cmd = DECK_CMD_GET_APP_FW_VERSION; resp.hdr.status = 0; resp.hdr.nbytes = 1; resp.app_fw_version = 0x90; return deck_frame_encode(&deck_uart.readable, &resp, sizeof(resp)); } static HRESULT deck_req_get_board_info(void) { struct deck_resp_get_board_info resp; dprintf("Printer: RFID: Get Board Info\n"); resp.hdr.sync = 0xE0; resp.hdr.cmd = DECK_CMD_GET_BOARD_INFO; resp.hdr.status = 0; resp.hdr.nbytes = 9; memcpy(resp.board, (void *)"837-15347", 9); return deck_frame_encode(&deck_uart.readable, &resp, sizeof(resp)); } static HRESULT deck_req_read(void) { struct deck_resp_read resp; dprintf("Printer: RFID: Read Card\n"); resp.hdr.sync = 0xE0; resp.hdr.cmd = DECK_CMD_READ; resp.hdr.status = DECK_READ_START; resp.hdr.nbytes = 0; current_card_idx = 0; read_pending = true; return deck_frame_encode(&deck_uart.readable, &resp.hdr, sizeof(resp.hdr)); } static HRESULT deck_req_read_data(void) { struct deck_resp_read_data resp; dprintf("Printer: RFID: Read Card Data\n"); resp.hdr.sync = 0xE0; resp.hdr.cmd = DECK_CMD_READ_DATA; resp.hdr.status = 0; resp.hdr.nbytes = 32; memcpy(resp.card_data, cardDataBuffer, 32); return deck_frame_encode(&deck_uart.readable, &resp, sizeof(resp)); } static HRESULT deck_req_write(const uint8_t *req_bytes) { struct deck_resp_hdr resp; uint8_t off; resp.sync = 0xE0; resp.cmd = DECK_CMD_WRITE; resp.status = 0; resp.nbytes = 0; off = (req_bytes[5] - 1) * 2; cardDataBuffer[off] = req_bytes[6]; cardDataBuffer[off + 1] = req_bytes[7]; if (req_bytes[5] == 0x10) { dprintf("Printer: RFID: Card Data Buffer: \n"); dump(cardDataBuffer, 0x20); } return deck_frame_encode(&deck_uart.readable, &resp, sizeof(resp)); } static void deck_read_one(void) { struct deck_resp_read resp; dprintf("Printer: RFID: Read One Card\n"); resp.hdr.sync = 0xE0; resp.hdr.cmd = DECK_CMD_READ; if (current_card_idx < 1) { resp.hdr.status = DECK_READ_DATA; resp.hdr.nbytes = 44; memset(resp.card_data, 0, 44); memcpy(resp.card_data, cardRFID, 0xC); memcpy(resp.card_data + 0x0C, cardDataBuffer, 0x20); dump(resp.card_data, 44); deck_frame_encode(&deck_uart.readable, &resp, sizeof(resp)); current_card_idx++; } else { resp.hdr.status = DECK_READ_END; resp.hdr.nbytes = 0; deck_frame_encode(&deck_uart.readable, &resp.hdr, sizeof(resp.hdr)); read_pending = false; } } static HRESULT deck_req_nop(uint8_t cmd) { struct deck_resp_hdr resp; dprintf("Printer: RFID: No-op cmd %#02x\n", cmd); resp.sync = 0xE0; resp.cmd = cmd; resp.status = 0; resp.nbytes = 0; return deck_frame_encode(&deck_uart.readable, &resp, sizeof(resp)); } static void deck_frame_sync(struct iobuf *src) { size_t i; for (i = 0; i < src->pos && src->bytes[i] != 0xE0; i++) ; src->pos -= i; memmove(&src->bytes[0], &src->bytes[i], i); } static HRESULT deck_frame_accept(const struct iobuf *dest) { if (dest->pos < 2 || dest->pos != dest->bytes[2] + 4) { return S_FALSE; } return S_OK; } static HRESULT deck_frame_decode(struct iobuf *dest, struct iobuf *src) { uint8_t byte; bool escape; 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); dest->pos = 0; escape = false; for (i = 0, hr = S_FALSE; i < src->pos && hr == S_FALSE; i++) { /* Step the FSM to unstuff another byte */ byte = src->bytes[i]; if (dest->pos >= dest->nbytes) { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } else if (i == 0) { dest->bytes[dest->pos++] = byte; } else if (byte == 0xE0) { hr = E_FAIL; } else if (byte == 0xD0) { if (escape) { hr = E_FAIL; } escape = true; } else if (escape) { dest->bytes[dest->pos++] = byte + 1; escape = false; } else { dest->bytes[dest->pos++] = byte; } /* Try to accept the packet we've built up so far */ if (SUCCEEDED(hr)) { hr = deck_frame_accept(dest); } } /* Handle FSM terminal state */ if (hr != S_FALSE) { /* Frame was either accepted or rejected, remove it from src */ memmove(&src->bytes[0], &src->bytes[i], src->pos - i); src->pos -= i; } return hr; } static HRESULT deck_frame_encode( struct iobuf *dest, const void *ptr, size_t nbytes) { const uint8_t *src; uint8_t checksum; uint8_t byte; size_t i; HRESULT hr; assert(dest != NULL); assert(dest->bytes != NULL || dest->nbytes == 0); assert(dest->pos <= dest->nbytes); assert(ptr != NULL); src = ptr; assert(nbytes >= 2 && src[0] == 0xE0 && src[3] + 4 == nbytes); if (dest->pos >= dest->nbytes) { return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } dest->bytes[dest->pos++] = 0xE0; checksum = 0x0; for (i = 1; i < nbytes; i++) { byte = src[i]; checksum += byte; hr = deck_frame_encode_byte(dest, byte); if (FAILED(hr)) { return hr; } } return deck_frame_encode_byte(dest, checksum); } static HRESULT deck_frame_encode_byte(struct iobuf *dest, uint8_t byte) { if (byte == 0xD0 || byte == 0xE0) { if (dest->pos + 2 > dest->nbytes) { return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } dest->bytes[dest->pos++] = 0xD0; dest->bytes[dest->pos++] = byte - 1; } else { if (dest->pos + 1 > dest->nbytes) { return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } dest->bytes[dest->pos++] = byte; } return S_OK; } // C3XXFWDLusb stubs int fwdlusb_open(uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); *rResult = 0; return 1; } void fwdlusb_close() {} int fwdlusb_listupPrinter(uint8_t *rIdArray) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); memset(rIdArray, 0xFF, 0x80); rIdArray[0] = idNumber; return 1; } int fwdlusb_listupPrinterSN(uint64_t *rSerialArray) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); memset(rSerialArray, 0xFF, 0x400); rSerialArray[0] = serialNo; return 1; } int fwdlusb_selectPrinter(uint8_t printerId, uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); *rResult = 0; return 1; } int fwdlusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); *rResult = 0; return 1; } int fwdlusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); switch (tagNumber) { case 0: // getPaperInfo if (*rLen != 0x67) *rLen = 0x67; if (rBuffer) memset(rBuffer, 0, *rLen); return 1; case 3: // getFirmwareVersion if (*rLen != 0x99) *rLen = 0x99; if (rBuffer) { memset(rBuffer, 0, *rLen); // 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, 0x26); } return 1; case 4: // getPrintCountInfo (C300 only) if (!rBuffer) { *rLen = 0x1C; return 1; } int32_t bInfoC300[10] = {0}; uint16_t printCounterC300; 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); } break; case 5: // getPrintCountInfo if (!rBuffer) { *rLen = 0x28; return 1; } int32_t bInfo[10] = {0}; bInfo[0] = 22; // printCounter0 bInfo[1] = 23; // printCounter1 bInfo[2] = 33; // feedRollerCount bInfo[3] = 55; // cutterCount bInfo[4] = 88; // headCount bInfo[5] = 999; // ribbonRemain bInfo[6] = 99; // holoHeadCount if (*rLen <= 0x1Cu) { memcpy(rBuffer, bInfo, *rLen); } else { bInfo[7] = 69; // paperCount bInfo[8] = 21; // printCounter2 bInfo[9] = 20; // holoPrintCounter if (*rLen > 0x28u) *rLen = 0x28; memcpy(rBuffer, bInfo, *rLen); } break; case 26: // getPrinterSerial if (*rLen != 8) *rLen = 8; if (rBuffer) memcpy(rBuffer, &serialNo, 8); return 1; default: dprintf("Printer: %s: Unknown parameter 'tagNumber' value %d.\n", __func__, tagNumber); break; } return 1; } int fwdlusb_status(uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); *rResult = 0; return 1; } int fwdlusb_statusAll(uint8_t *idArray, uint16_t *rResultArray) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); for (int i = 0; *(uint8_t *)(idArray + i) != 255 && i < 128; ++i) { *(uint16_t *)(rResultArray + 2 * i) = 0; } return 1; } int fwdlusb_resetPrinter(uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); *rResult = 0; return 1; } int fwdlusb_getFirmwareVersion(uint8_t *buffer, int size) { int8_t a; uint32_t b = 0; for (int32_t i = 0; i < size; ++i) { if (*(int8_t *)(buffer + i) < 0x30 || *(int8_t *)(buffer + i) > 0x39) { if (*(int8_t *)(buffer + i) < 0x41 || *(int8_t *)(buffer + i) > 0x46) { if (*(int8_t *)(buffer + i) < 0x61 || *(int8_t *)(buffer + i) > 0x66) { return 0; } a = *(int8_t *)(buffer + i) - 0x57; } else { a = *(int8_t *)(buffer + i) - 0x37; } } else { a = *(int8_t *)(buffer + i) - 0x30; } b = a + 0x10 * b; } return b; } int fwdlusb_updateFirmware_main(uint8_t update, LPCSTR filename, uint16_t *rResult) { DWORD result; HANDLE fwFile = NULL; DWORD bytesWritten = 0; if (filename) { HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) return 0; { if (rResult) *rResult = 1005; result = 0; } DWORD read; uint8_t buffer[0x40]; result = ReadFile(hFile, buffer, 0x40, &read, NULL); CloseHandle(hFile); if (result && read > 0x24) { uint8_t rBuffer[0x40] = {0}; memcpy(rBuffer, buffer + 0x2, 0x8); memcpy(rBuffer + 0x8, buffer + 0xA, 0x10); memcpy(rBuffer + 0x18, buffer + 0x20, 0xA); *(rBuffer + 0x22) = (uint8_t)fwdlusb_getFirmwareVersion(buffer + 0x1A, 0x2); *(rBuffer + 0x23) = (uint8_t)fwdlusb_getFirmwareVersion(buffer + 0x1C, 0x2); memcpy(rBuffer + 0x24, buffer + 0x2A, 0x2); memcpy(mainFirmware, rBuffer, 0x40); fwFile = CreateFileW(printer_config.main_fw_path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (fwFile != NULL) { WriteFile(fwFile, rBuffer, 0x40, &bytesWritten, NULL); CloseHandle(fwFile); } if (rResult) *rResult = 0; result = 1; } else { if (rResult) *rResult = 1005; result = 0; } } else { if (rResult) *rResult = 1006; result = 0; } return result; } int fwdlusb_updateFirmware_dsp(uint8_t update, LPCSTR filename, uint16_t *rResult) { DWORD result; HANDLE fwFile = NULL; DWORD bytesWritten = 0; if (filename) { HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) return 0; { if (rResult) *rResult = 1005; result = 0; } DWORD read; uint8_t buffer[0x40]; result = ReadFile(hFile, buffer, 0x40, &read, NULL); CloseHandle(hFile); if (result && read > 0x24) { uint8_t rBuffer[0x40] = {0}; memcpy(rBuffer, buffer + 0x2, 8); memcpy(rBuffer + 0x8, buffer + 0xA, 0x10); memcpy(rBuffer + 0x18, buffer + 0x20, 0xA); memcpy(rBuffer + 0x22, buffer + 0x1A, 0x1); memcpy(rBuffer + 0x23, buffer + 0x1C, 0x1); memcpy(rBuffer + 0x24, buffer + 0x2A, 0x2); memcpy(dspFirmware, rBuffer, 0x40); fwFile = CreateFileW(printer_config.dsp_fw_path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (fwFile != NULL) { WriteFile(fwFile, rBuffer, 0x40, &bytesWritten, NULL); CloseHandle(fwFile); } if (rResult) *rResult = 0; result = 1; } else { if (rResult) *rResult = 1005; result = 0; } } else { if (rResult) *rResult = 1006; result = 0; } return result; } int fwdlusb_updateFirmware_param(uint8_t update, LPCSTR filename, uint16_t *rResult) { DWORD result; HANDLE fwFile = NULL; DWORD bytesWritten = 0; if (filename) { HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) return 0; { if (rResult) *rResult = 1005; result = 0; } DWORD read; uint8_t buffer[0x40]; result = ReadFile(hFile, buffer, 0x40, &read, NULL); CloseHandle(hFile); if (result && read > 0x24) { uint8_t rBuffer[0x40] = {0}; memcpy(rBuffer, buffer + 0x2, 8); memcpy(rBuffer + 0x8, buffer + 0xA, 0x10); memcpy(rBuffer + 0x18, buffer + 0x20, 0xA); memcpy(rBuffer + 0x22, buffer + 0x1A, 0x1); memcpy(rBuffer + 0x23, buffer + 0x1C, 0x1); memcpy(rBuffer + 0x24, buffer + 0x2A, 0x2); memcpy(paramFirmware, rBuffer, 0x40); fwFile = CreateFileW(printer_config.param_fw_path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (fwFile != NULL) { WriteFile(fwFile, rBuffer, 0x40, &bytesWritten, NULL); CloseHandle(fwFile); } if (rResult) *rResult = 0; result = 1; } else { if (rResult) *rResult = 1005; result = 0; } } else { if (rResult) *rResult = 1006; result = 0; } return result; } int fwdlusb_updateFirmware(uint8_t update, LPCSTR filename, uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); if (update == 1) { return fwdlusb_updateFirmware_main(update, filename, rResult); } else if (update == 2) { return fwdlusb_updateFirmware_dsp(update, filename, rResult); } else if (update == 3) { return fwdlusb_updateFirmware_param(update, filename, rResult); } else { *rResult = 0; return 1; } } int fwdlusb_getFirmwareInfo_main(LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { DWORD result; if (filename) { HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) return 0; { if (rResult) *rResult = 1005; result = 0; } DWORD read; uint8_t buffer[0x40]; result = ReadFile(hFile, buffer, 0x40, &read, NULL); if (result && read > 0x24) { memcpy(rBuffer, buffer + 0x2, 0x8); memcpy(rBuffer + 0x8, buffer + 0xA, 0x10); memcpy(rBuffer + 0x18, buffer + 0x20, 0xA); *(rBuffer + 0x22) = (uint8_t)fwdlusb_getFirmwareVersion(buffer + 0x1A, 0x2); *(rBuffer + 0x23) = (uint8_t)fwdlusb_getFirmwareVersion(buffer + 0x1C, 0x2); memcpy(rBuffer + 0x24, buffer + 0x2A, 0x2); if (rResult) *rResult = 0; result = 1; } else { if (rResult) *rResult = 1005; result = 0; } } else { if (rResult) *rResult = 1006; result = 0; } return result; } int fwdlusb_getFirmwareInfo_dsp(LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { DWORD result; if (filename) { HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) return 0; { if (rResult) *rResult = 1005; result = 0; } DWORD read; uint8_t buffer[0x40]; result = ReadFile(hFile, buffer, 0x40, &read, NULL); if (result && read > 0x24) { memcpy(rBuffer, buffer + 0x2, 8); memcpy(rBuffer + 0x8, buffer + 0xA, 0x10); memcpy(rBuffer + 0x18, buffer + 0x20, 0xA); memcpy(rBuffer + 0x22, buffer + 0x1A, 0x1); memcpy(rBuffer + 0x23, buffer + 0x1C, 0x1); memcpy(rBuffer + 0x24, buffer + 0x2A, 0x2); if (rResult) *rResult = 0; result = 1; } else { if (rResult) *rResult = 1005; result = 0; } } else { if (rResult) *rResult = 1006; result = 0; } return result; } int fwdlusb_getFirmwareInfo_param(LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { DWORD result; if (filename) { HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) return 0; { if (rResult) *rResult = 1005; result = 0; } DWORD read; uint8_t buffer[0x40]; result = ReadFile(hFile, buffer, 0x40, &read, NULL); if (result && read > 0x24) { memcpy(rBuffer, buffer + 0x2, 8); memcpy(rBuffer + 0x8, buffer + 0xA, 0x10); memcpy(rBuffer + 0x18, buffer + 0x20, 0xA); memcpy(rBuffer + 0x22, buffer + 0x1A, 0x1); memcpy(rBuffer + 0x23, buffer + 0x1C, 0x1); memcpy(rBuffer + 0x24, buffer + 0x2A, 0x2); if (rResult) *rResult = 0; result = 1; } else { if (rResult) *rResult = 1005; result = 0; } } else { if (rResult) *rResult = 1006; result = 0; } return result; } int fwdlusb_getFirmwareInfo(uint8_t update, LPCSTR filename, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s(update: %d, filename: %s)\n", __func__, update, filename); if (!rBuffer) { *rLen = 38; return 1; } if (*rLen > 38) *rLen = 38; if (update == 1) { return fwdlusb_getFirmwareInfo_main(filename, rBuffer, rLen, rResult); } else if (update == 2) { return fwdlusb_getFirmwareInfo_dsp(filename, rBuffer, rLen, rResult); } else if (update == 3) { return fwdlusb_getFirmwareInfo_param(filename, rBuffer, rLen, rResult); } else { if (rResult) *rResult = 0; return 1; } } int fwdlusb_MakeThread(uint16_t maxCount) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); return 1; } int fwdlusb_ReleaseThread(uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); *rResult = 0; return 1; } int fwdlusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); *rCount = 0; *rMaxCount = 1; return 1; } int fwdlusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult) { dprintf("Printer: C3XXFWDLusb: %s\n", __func__); *rResult = 0; return 1; } // C3XXusb stubs int chcusb_MakeThread(uint16_t maxCount) { dprintf("Printer: C3XXusb: %s\n", __func__); return 1; } int chcusb_open(uint16_t *rResult) { // Seed random for card id generation srand(time(NULL)); generate_rfid(); dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } void chcusb_close() { dprintf("Printer: C3XXusb: %s\n", __func__); } int chcusb_ReleaseThread(uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); return 1; } int chcusb_listupPrinter(uint8_t *rIdArray) { dprintf("Printer: C3XXusb: %s\n", __func__); memset(rIdArray, 0xFF, 0x80); rIdArray[0] = idNumber; return 1; } int chcusb_listupPrinterSN(uint64_t *rSerialArray) { dprintf("Printer: C3XXusb: %s\n", __func__); memset(rSerialArray, 0xFF, 0x400); rSerialArray[0] = serialNo; return 1; } int chcusb_selectPrinter(uint8_t printerId, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } int chcusb_selectPrinterSN(uint64_t printerSN, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } int chcusb_getPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen) { // dprintf("Printer: C3XXusb: %s\n", __func__); switch (tagNumber) { // getPaperInfo case 0: if (*rLen != 0x67) *rLen = 0x67; if (rBuffer) memset(rBuffer, 0, *rLen); break; case 3: // getFirmwareVersion if (*rLen != 0x99) *rLen = 0x99; if (rBuffer) { memset(rBuffer, 0, *rLen); // 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, 0x26); } break; 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); } break; case 5: // getPrintCountInfo2 (C310A and later) if (!rBuffer) { *rLen = 0x28; return 1; } int32_t bInfo[10] = {0}; bInfo[0] = 22; // printCounter0 bInfo[1] = 23; // printCounter1 bInfo[2] = 33; // feedRollerCount bInfo[3] = 55; // cutterCount bInfo[4] = 88; // headCount bInfo[5] = 999; // ribbonRemain bInfo[6] = 99; // holoHeadCount if (*rLen <= 0x1Cu) { memcpy(rBuffer, bInfo, *rLen); } else { bInfo[7] = 69; // paperCount bInfo[8] = 21; // printCounter2 bInfo[9] = 20; // holoPrintCounter if (*rLen > 0x28u) *rLen = 0x28; memcpy(rBuffer, bInfo, *rLen); } break; case 6: // pageStatusInfo *rLen = 32; if (rBuffer) { memset(rBuffer, 0, 32); rBuffer[0] = 88; // holoRemain rBuffer[1] = 0; rBuffer[2] = 0; rBuffer[3] = 0; } break; case 7: // svc *rLen = 2; if (rBuffer) { memset(rBuffer, 0, 2); rBuffer[0] = 0; // mainError rBuffer[1] = 0; // subError } break; case 8: // printStandby *rLen = 1; if (awaitingCardExit) *rBuffer = 0xF0; else *rBuffer = 0; break; case 16: // memoryInfo *rLen = 18; if (rBuffer) memset(rBuffer, 0, 18); break; case 20: // printMode dprintf("Printer: C3XXusb: Unimpl tagNumber 20\n"); break; case 26: // getPrinterSerial if (*rLen != 8) *rLen = 8; if (rBuffer) memcpy(rBuffer, &serialNo, 8); break; case 30: // TODO dprintf("Printer: C3XXusb: Unimpl tagNumber 30\n"); break; case 31: // TODO, possibly CardRFIDCheck? *rLen = 1; if (rBuffer) memset(rBuffer, 0, 1); break; case 40: // temperature *rLen = 10; if (rBuffer) { memset(rBuffer, 0, 10); rBuffer[0] = 1; rBuffer[1] = 2; rBuffer[2] = 3; } break; case 50: // errHistory *rLen = 61; if (rBuffer) memset(rBuffer, 0, 61); break; case 60: // getToneTable *rLen = 6; if (rBuffer) memset(rBuffer, 0, 6); break; default: dprintf("Printer: unknown tagNumber, %d", tagNumber); break; } return 1; } int chcusb_imageformat( uint16_t format, uint16_t ncomp, uint16_t depth, uint16_t width, uint16_t height, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); WIDTH = width; HEIGHT = height; *rResult = 0; return 1; } int chcusb_setmtf(int32_t *mtf) { dprintf("Printer: C3XXusb: %s\n", __func__); memcpy(MTF, mtf, sizeof(MTF)); return 1; } int chcusb_makeGamma(uint16_t k, uint8_t *intoneR, uint8_t *intoneG, uint8_t *intoneB) { dprintf("Printer: C3XXusb: %s\n", __func__); uint8_t tone; int32_t value; double power; double factor = (double)k / 100.0; for (int i = 0; i < 256; ++i) { power = pow((double)i, factor); value = (int)(power / pow(255.0, factor) * 255.0); if (value > 255) tone = 255; if (value >= 0) tone = value; else tone = 0; if (intoneR) *(uint8_t *)(intoneR + i) = tone; if (intoneG) *(uint8_t *)(intoneG + i) = tone; if (intoneB) *(uint8_t *)(intoneB + i) = tone; } return 1; } int chcusb_setIcctable( LPCSTR icc1, LPCSTR icc2, uint16_t intents, uint8_t *intoneR, uint8_t *intoneG, uint8_t *intoneB, uint8_t *outtoneR, uint8_t *outtoneG, uint8_t *outtoneB, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); for (int i = 0; i < 256; ++i) { intoneR[i] = i; intoneG[i] = i; intoneB[i] = i; outtoneR[i] = i; outtoneG[i] = i; outtoneB[i] = i; } *rResult = 0; return 1; } int chcusb_copies(uint16_t copies, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } int chcusb_status(uint16_t *rResult) { // dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } int chcusb_statusAll(uint8_t *idArray, uint16_t *rResultArray) { dprintf("Printer: C3XXusb: %s\n", __func__); for (int i = 0; *(uint8_t *)(idArray + i) != 255 && i < 128; ++i) { *(uint16_t *)(rResultArray + 2 * i) = 0; } return 1; } int chcusb_startpage(uint16_t postCardState, uint16_t *pageId, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *pageId = 1; *rResult = 0; return 1; } int chcusb_endpage(uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); awaitingCardExit = true; *rResult = 0; return 1; } int chcusb_write(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) { SYSTEMTIME t; GetLocalTime(&t); wchar_t dumpPath[MAX_PATH]; uint8_t metadata[44]; swprintf_s( dumpPath, MAX_PATH, L"%s\\C3XX_%04d%02d%02d_%02d%02d%02d.bmp", printer_out_path, t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond); memcpy(metadata, cardRFID, 12); memcpy(metadata + 12, cardDataBuffer, 32); WriteDataToBitmapFile(dumpPath, 24, WIDTH, HEIGHT, data, *writeSize, metadata, 44, rotate180); // WriteArrayToFile(dumpPath, data, IMAGE_SIZE, FALSE); dprintf("Printer: C3XXusb: %s\n", __func__); dwprintf(L"Printer: File written: %s\n", dumpPath); *rResult = 0; return 1; } int chcusb_writeLaminate(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) { SYSTEMTIME t; GetLocalTime(&t); char dumpPath[0x80]; sprintf_s( dumpPath, 0x80, "C3XXusb_%04d%02d%02d_%02d%02d%02d_writeLaminate.bin", t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond); // WriteArrayToFile(dumpPath, data, *writeSize, FALSE); dprintf("Printer: C3XXusb: %s\n", __func__); // *writeSize = written; *rResult = 0; return 1; } int chcusb_writeHolo(uint8_t *data, uint32_t *writeSize, uint16_t *rResult) { SYSTEMTIME t; GetLocalTime(&t); char dumpPath[0x80]; sprintf_s( dumpPath, 0x80, "C3XXusb_%04d%02d%02d_%02d%02d%02d_writeHolo.bin", t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond); // WriteArrayToFile(dumpPath, data, HOLO_SIZE, FALSE); dprintf("Printer: C3XXusb: %s\n", __func__); *writeSize = HOLO_SIZE; *rResult = 0; return 1; } int chcusb_setPrinterInfo(uint16_t tagNumber, uint8_t *rBuffer, uint32_t *rLen, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); switch (tagNumber) { case 0: // setPaperInfo memcpy(PAPERINFO, rBuffer, sizeof(PAPERINFO)); break; case 20: // setPolishInfo memcpy(POLISH, rBuffer, sizeof(POLISH)); break; default: break; } *rResult = 0; return 1; } int chcusb_getGamma(LPCSTR filename, uint8_t *r, uint8_t *g, uint8_t *b, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); for (int i = 0; i < 256; ++i) { r[i] = i; g[i] = i; b[i] = i; } *rResult = 0; return 1; } int chcusb_getMtf(LPCSTR filename, int32_t *mtf, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) return 0; DWORD read; uint8_t buffer[0x40]; BOOL result = ReadFile(hFile, buffer, 0x40, &read, NULL); if (!result) return 0; int a, c; int b = 1; int d = c = 0; memset(mtf, 0, sizeof(MTF)); for (DWORD i = 0; i < read; i++) { a = buffer[i] - 0x30; if (a == -3 && c == 0) { b = -1; } else if (a >= 0 && a <= 9) { mtf[d] = mtf[d] * 10 + a; c++; } else if (c > 0) { mtf[d] *= b; b = 1; c = 0; d++; } if (d > 9) break; } *rResult = 0; return 1; } int chcusb_cancelCopies(uint16_t pageId, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } int chcusb_setPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); if ((type > 0 && type < 3) && (number > 0 && number < 3)) { CURVE[type][number] = *data; } *rResult = 0; return 1; } int chcusb_getPrinterToneCurve(uint16_t type, uint16_t number, uint16_t *data, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); if ((type > 0 && type < 3) && (number > 0 && number < 3)) { *data = CURVE[type][number]; } *rResult = 0; return 1; } int chcusb_blinkLED(uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } int chcusb_resetPrinter(uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } int chcusb_AttachThreadCount(uint16_t *rCount, uint16_t *rMaxCount) { dprintf("Printer: C3XXusb: %s\n", __func__); *rCount = 0; *rMaxCount = 1; return 1; } int chcusb_getPrintIDStatus(uint16_t pageId, uint8_t *rBuffer, uint16_t *rResult) { // dprintf("Printer: C3XXusb: %s\n", __func__); memset(rBuffer, 0, 8); *((uint16_t *)(rBuffer + 6)) = 2300; *rResult = 0; return 1; } int chcusb_setPrintStandby(uint16_t position, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } int chcusb_testCardFeed(uint16_t mode, uint16_t times, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } int chcusb_exitCard(uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); awaitingCardExit = false; generate_rfid(); *rResult = 0; return 1; } int chcusb_getCardRfidTID(uint8_t *rCardTID, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); memcpy(rCardTID, cardRFID, sizeof(cardRFID)); *rResult = 2405; return 1; } int chcusb_commCardRfidReader(uint8_t *sendData, uint8_t *rRecvData, uint32_t sendSize, uint32_t *rRecvSize, uint16_t *rResult) { uint8_t off; dprintf("Printer: C3XXusb: %s\n", __func__); // dprintf("Printer: C3XXusb: commCardRfidReader send buffer: \n"); // dump(sendData, sendSize); *rResult = 0; switch (sendData[0]) { case 0x02: memset(rRecvData, 0, 35); rRecvData[0] = 2; rRecvData[2] = 32; memcpy(rRecvData + 3, cardDataBuffer, 32); *rRecvSize = 35; break; case 0x03: off = (sendData[4] - 1) * 2; cardDataBuffer[off] = sendData[5]; cardDataBuffer[off + 1] = sendData[6]; if (sendData[4] == 0x10) { dprintf("Printer: C3XXusb: commCardRfidReader card data buffer: \n"); dump(cardDataBuffer, 0x20); } memset(rRecvData, 0, 3); rRecvData[0] = 0x03; *rRecvSize = 3; break; case 0x84: memset(rRecvData, 0, 4); rRecvData[0] = 0x84; rRecvData[2] = 1; rRecvData[3] = 0x90; *rRecvSize = 4; break; case 0x85: memset(rRecvData, 0, 12); rRecvData[0] = 0x85; rRecvData[2] = 9; memcpy(rRecvData + 3, (void *)"837-15345", 9); *rRecvSize = 12; break; case 0x42: memset(rRecvData, 0, 4); rRecvData[0] = 0x42; rRecvData[2] = 1; rRecvData[3] = 0x91; *rRecvSize = 4; break; default: memset(rRecvData, 0, 3); rRecvData[0] = sendData[0]; *rRecvSize = 3; break; } // dprintf("Printer: C3XXusb: commCardRfidReader recv buffer: \n"); // dump(rRecvData, *rRecvSize); return 1; } int chcusb_updateCardRfidReader(uint8_t *data, uint32_t size, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } int chcusb_getErrorLog(uint16_t index, uint8_t *rData, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } int chcusb_getErrorStatus(uint16_t *rBuffer) { dprintf("Printer: C3XXusb: %s\n", __func__); memset(rBuffer, 0, 0x80); return 1; } int chcusb_setCutList(uint8_t *rData, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } int chcusb_setLaminatePattern(uint16_t index, uint8_t *rData, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } int chcusb_color_adjustment(LPCSTR filename, int32_t a2, int32_t a3, int16_t a4, int16_t a5, int64_t a6, int64_t a7, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } int chcusb_color_adjustmentEx(int32_t a1, int32_t a2, int32_t a3, int16_t a4, int16_t a5, int64_t a6, int64_t a7, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } int chcusb_getEEPROM(uint8_t index, uint8_t *rData, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } int chcusb_setParameter(uint8_t a1, uint32_t a2, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } int chcusb_getParameter(uint8_t a1, uint8_t *a2, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } int chcusb_universal_command(int32_t a1, uint8_t a2, int32_t a3, uint8_t *a4, uint16_t *rResult) { dprintf("Printer: C3XXusb: %s\n", __func__); *rResult = 0; return 1; } // 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 }