#include "stdafx.h" #include "IDCertFSM.h" #include "EventCode.h" #include "IDCertificate_UserErrorCode.h" #include #include #include #include #include #ifdef RVC_OS_LINUX #include "CommDevEntityErrorCode.h" #include #include #include "fileutil.h" #include #include using namespace SP::Module::Comm; #else #include "RVCComm.h" #include "publicFunExport.h" #include "json/json.h" #include #include #endif // RVC_OS_LINUX #define IDCER_INIT_COUNT 3 #define IDCER_READ_TIMEOUT 60000 #define IDCER_AUTH_INTERVAL 300 #ifdef DEVOPS_ON_ST /*DevOps流水线编译,ST环境*/ #define IMAGE_DETECT_URL "https://carddetect.paasst.cmbchina.cn/api/card/image-detect" #elif defined(DEVOPS_ON_UAT)/*DevOps流水线编译,UAT环境*/ #define IMAGE_DETECT_URL "https://carddetect.paasuat.cmbchina.cn/api/card/image-detect" #elif defined(DEVOPS_ON_PRD)/*DevOps流水线编译,PRD环境*/ #define IMAGE_DETECT_URL "https://carddetect.paas.cmbchina.cn/api/card/image-detect" #elif defined(DEVOPS_ON_DEV)/*DevOps流水线编译,Dev&生产环境*/ #define IMAGE_DETECT_URL "https://carddetect.paas.cmbchina.cn/api/card/image-detect" #else/*本地编译等非DevOps环境编译的版本*/ #define IMAGE_DETECT_URL "https://carddetect.paasst.cmbchina.cn/api/card/image-detect" #endif #ifdef RVC_OS_WIN static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) { std::string ret; int i = 0; int j = 0; unsigned char char_array_3[3]; unsigned char char_array_4[4]; while (in_len--) { char_array_3[i++] = *(bytes_to_encode++); if (i == 3) { char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[3] = char_array_3[2] & 0x3f; for (i = 0; (i < 4); i++) ret += base64_chars[char_array_4[i]]; i = 0; } } if (i) { for (j = i; j < 3; j++) char_array_3[j] = '\0'; char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[3] = char_array_3[2] & 0x3f; for (j = 0; (j < i + 1); j++) ret += base64_chars[char_array_4[j]]; while ((i++ < 3)) ret += '='; } return ret; } struct ImgChekTask : ITaskSp { CIDCertFSM* m_fsm; ImgChekTask(CIDCertFSM* fsm) :m_fsm(fsm) {} CSimpleStringA idNum; CSimpleStringA inName; CBlob imgInput; CSimpleStringA inNationality; CSimpleStringA inIdType; CSimpleStringA imgType; void Process() { CSystemStaticInfo si; m_fsm->GetEntityBase()->GetFunction()->GetSystemStaticInfo(si); IHttpFunc* client; client = create_http(m_fsm->HttpsLogCallBack); ImgCheckReq imgCheckReq; ImgCheckRet imgCheckRet; imgCheckReq.terminalNo = si.strTerminalID.GetData(); imgCheckReq.name = inName.GetData(); imgCheckReq.idNo = idNum.GetData(); imgCheckReq.nationality = inNationality.GetData(); imgCheckReq.idType = inIdType.GetData(); imgCheckReq.topN = 1; imgCheckReq.returnImgBase64 = 1; string imgIn = imgInput.m_pData; //图片原始数据 long srclen = imgInput.m_iLength; string encodeIn = base64_encode((unsigned char*)imgInput.m_pData, srclen); //string encodeIn; //Encode(imgIn, encodeIn); //传给服务端应base64编码 imgCheckReq.imageBase64 = encodeIn; imgCheckReq.m_url = m_fsm->checkImgURL; long beg = GetTickCount(); PROCESS_LINK_CONTEXT("LR0402201ImgCheck") bool ret = client->Post(imgCheckReq, imgCheckRet, &nextLink); long end = GetTickCount(); CSimpleStringA errMsg; if (ret) { if (imgCheckRet.m_success != true) { errMsg = CSimpleStringA::Format("图片检测不通过,result_data:%s,图片类型 = %s。", imgCheckRet.m_resultData.c_str(), imgType.GetData()); LogWarn(Severity_Middle, Error_Resource, IDCertificate_UserErrorCode_ScanImg_Failed, errMsg.GetData()); if (client) client->Destory(); return; } } else { errMsg = CSimpleStringA::Format("图片质量检测请求失败,请检查本地网络连接。图片类型 = %s。", imgType.GetData()); LogWarn(Severity_Middle, Error_Resource, IDCertificate_UserErrorCode_ScanImg_Failed, errMsg.GetData()); } client->Destory(); } }; #endif //RVC_OS_WIN //Normal/Idle void CIDCertFSM::s0_on_entry() { LOG_FUNCTION(); SetDevState(DEVICE_STATUS_NORMAL); } void CIDCertFSM::s0_on_exit() { LOG_FUNCTION(); } unsigned int CIDCertFSM::s0_on_event(FSMEvent* pEvt) { DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("s0 evt %d",pEvt->iEvt); switch (pEvt->iEvt) { case USER_EVT_ERROR: pEvt->SetHandled(); break; case USER_EVT_QUIT: pEvt->SetHandled(); break; case USER_EVT_READ_AND_SCAN_UTF8: //ex1 { pEvt->SetHandled(); ReadAndScanUTF8Event* ide = dynamic_cast(pEvt); ReadAndScanUTF8Task* task = new ReadAndScanUTF8Task(this); task->ctx = ide->ctx; GetEntityBase()->GetFunction()->PostThreadPoolTask(task); } break; case USER_EVT_READ_AND_SCAN_UTF8JS: //ex1 { pEvt->SetHandled(); ReadAndScanUTF8JSEvent* ide = dynamic_cast(pEvt); ReadAndScanUTF8JSTask* task = new ReadAndScanUTF8JSTask(this); task->ctx = ide->ctx; GetEntityBase()->GetFunction()->PostThreadPoolTask(task); } break; case USER_EVT_TODO_INIT: { pEvt->SetHandled(); } break; case USER_EVT_TODO_INIT_FINISHED: { pEvt->SetHandled(); return pEvt->param1; } default: break; } return 0; } //Reading void CIDCertFSM::s1_on_entry() { LOG_FUNCTION(); } void CIDCertFSM::s1_on_exit() { LOG_FUNCTION(); } unsigned int CIDCertFSM::s1_on_event(FSMEvent *pEvt) { DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("s1 evt %d", pEvt->iEvt); int ret = 0; switch(pEvt->iEvt) { case USER_EVT_CANCEL_READ: pEvt->SetHandled(); DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("Set cancel read flag"); m_bCancelRead = true; break; case USER_EVT_EXIT: pEvt->SetHandled(); SetExitFlag(); break; case USER_EVT_QUIT: pEvt->SetHandled(); break; case USER_EVT_READ_AND_SCAN_UTF8_FINISHED: if (pEvt->param1 == -1) { return 3; } pEvt->SetHandled(); ret = pEvt->param1; break; case USER_EVT_READ_AND_SCAN_UTF8JS_FINISHED: if (pEvt->param1 == -1) { return 3; } pEvt->SetHandled(); ret = pEvt->param1; break; case USER_EVT_TODO_INIT: { pEvt->SetHandled(); } break; case USER_EVT_TODO_INIT_FINISHED: { pEvt->SetHandled(); return pEvt->param1; } default: break; } return ret; } //failed void CIDCertFSM::s2_on_entry() { LOG_FUNCTION(); SetDevState(DEVICE_STATUS_FAULT); m_testResult = Error_InvalidState; } void CIDCertFSM::s2_on_exit() { LOG_FUNCTION(); } unsigned int CIDCertFSM::s2_on_event(FSMEvent* e) { LOG_FUNCTION(); if (e->iEvt == USER_EVT_QUIT) { e->SetHandled(); return 0; } return 0; } //Init void CIDCertFSM::s3_on_entry() { LOG_FUNCTION(); SetDevState(DEVICE_STATUS_NOT_READY); InitTask* task = new InitTask(this); GetEntityBase()->GetFunction()->PostThreadPoolTask(task); } void CIDCertFSM::s3_on_exit() { LOG_FUNCTION(); } unsigned int CIDCertFSM::s3_on_event(FSMEvent* pEvt) { DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("s3 evt %d", pEvt->iEvt); int ret = 0; switch (pEvt->iEvt) { case USER_EVT_ERROR: pEvt->SetHandled(); break; case USER_EVT_QUIT: pEvt->SetHandled(); break; case USER_EVT_INIT_FINISHED: { pEvt->SetHandled(); ret = pEvt->param1; } break; case USER_EVT_TODO_INIT: { pEvt->SetHandled(); } break; case USER_EVT_TODO_INIT_FINISHED: { pEvt->SetHandled(); return pEvt->param1; } default: break; } return ret; } ErrorCodeEnum CIDCertFSM::GetVendorDllPath(CSimpleStringA &strPath) { strPath = "termb.dll"; return Error_Succeed;//oiltest } ErrorCodeEnum CIDCertFSM::OnInit() { ZeroMemory(m_devCatInfo.szModel, MAX_DEV_MODEL_LEN); ZeroMemory(m_devCatInfo.szType, MAX_DEV_TYPE_LEN); ZeroMemory(m_devCatInfo.szVendor, MAX_DEV_VENDOR_LEN); #ifdef RVC_OS_WIN //windows使用宽字符 nationalCode[1] = L"汉"; nationalCode[2] = L"蒙古"; nationalCode[3] = L"回"; nationalCode[4] = L"藏"; nationalCode[5] = L"维吾尔"; nationalCode[6] = L"苗"; nationalCode[7] = L"彝"; nationalCode[8] = L"壮"; nationalCode[9] = L"布依"; nationalCode[10] = L"朝鲜"; nationalCode[11] = L"满"; nationalCode[12] = L"侗"; nationalCode[13] = L"瑶"; nationalCode[14] = L"白"; nationalCode[15] = L"土家"; nationalCode[16] = L"哈尼"; nationalCode[17] = L"哈萨克"; nationalCode[18] = L"傣"; nationalCode[19] = L"黎"; nationalCode[20] = L"傈僳"; nationalCode[21] = L"佤"; nationalCode[22] = L"畲"; nationalCode[23] = L"高山"; nationalCode[24] = L"拉祜"; nationalCode[25] = L"水"; nationalCode[26] = L"东乡"; nationalCode[27] = L"纳西"; nationalCode[28] = L"景颇"; nationalCode[29] = L"阿尔克孜"; nationalCode[30] = L"土"; nationalCode[31] = L"达斡尔"; nationalCode[32] = L"仫佬"; nationalCode[33] = L"羌"; nationalCode[34] = L"布朗"; nationalCode[35] = L"撒拉"; nationalCode[36] = L"毛南"; nationalCode[37] = L"仡佬"; nationalCode[38] = L"锡伯"; nationalCode[39] = L"阿昌"; nationalCode[40] = L"普米"; nationalCode[41] = L"塔吉克"; nationalCode[42] = L"怒"; nationalCode[43] = L"乌孜别克"; nationalCode[44] = L"俄罗斯"; nationalCode[45] = L"鄂温克"; nationalCode[46] = L"德昂"; nationalCode[47] = L"保安"; nationalCode[48] = L"裕固"; nationalCode[49] = L"京"; nationalCode[50] = L"塔塔尔"; nationalCode[51] = L"独龙"; nationalCode[52] = L"鄂伦春"; nationalCode[53] = L"赫哲"; nationalCode[54] = L"门巴"; nationalCode[55] = L"珞巴"; nationalCode[56] = L"基诺"; #else nationalCode[1] = "汉"; nationalCode[2] = "蒙古"; nationalCode[3] = "回"; nationalCode[4] = "藏"; nationalCode[5] = "维吾尔"; nationalCode[6] = "苗"; nationalCode[7] = "彝"; nationalCode[8] = "壮"; nationalCode[9] = "布依"; nationalCode[10] = "朝鲜"; nationalCode[11] = "满"; nationalCode[12] = "侗"; nationalCode[13] = "瑶"; nationalCode[14] = "白"; nationalCode[15] = "土家"; nationalCode[16] = "哈尼"; nationalCode[17] = "哈萨克"; nationalCode[18] = "傣"; nationalCode[19] = "黎"; nationalCode[20] = "傈僳"; nationalCode[21] = "佤"; nationalCode[22] = "畲"; nationalCode[23] = "高山"; nationalCode[24] = "拉祜"; nationalCode[25] = "水"; nationalCode[26] = "东乡"; nationalCode[27] = "纳西"; nationalCode[28] = "景颇"; nationalCode[29] = "阿尔克孜"; nationalCode[30] = "土"; nationalCode[31] = "达斡尔"; nationalCode[32] = "仫佬"; nationalCode[33] = "羌"; nationalCode[34] = "布朗"; nationalCode[35] = "撒拉"; nationalCode[36] = "毛南"; nationalCode[37] = "仡佬"; nationalCode[38] = "锡伯"; nationalCode[39] = "阿昌"; nationalCode[40] = "普米"; nationalCode[41] = "塔吉克"; nationalCode[42] = "怒"; nationalCode[43] = "乌孜别克"; nationalCode[44] = "俄罗斯"; nationalCode[45] = "鄂温克"; nationalCode[46] = "德昂"; nationalCode[47] = "保安"; nationalCode[48] = "裕固"; nationalCode[49] = "京"; nationalCode[50] = "塔塔尔"; nationalCode[51] = "独龙"; nationalCode[52] = "鄂伦春"; nationalCode[53] = "赫哲"; nationalCode[54] = "门巴"; nationalCode[55] = "珞巴"; nationalCode[56] = "基诺"; #endif supportUCS2 = FALSE; igestionVer = FALSE; closeImgCheck = FALSE; CSmartPointer spCtSettingConfig; GetEntityBase()->GetFunction()->OpenConfig(Config_CenterSetting, spCtSettingConfig); int tflag; spCtSettingConfig->ReadConfigValueInt("IDCertificate", "CloseImagCheckFlag", tflag); if (tflag != 0) { closeImgCheck = TRUE; } checkImgURL = IMAGE_DETECT_URL; CSimpleStringA tUrl; spCtSettingConfig->ReadConfigValue("IDCertificate", "CardDetectUrl", tUrl); if (!tUrl.IsNullOrEmpty()) { checkImgURL = tUrl.GetData(); } return Error_Succeed; } ErrorCodeEnum CIDCertFSM::OnExit() { if (m_hDevHelper) { ErrorCodeEnum err = Error_Succeed; m_hDevHelper.TearDown(); return err; } return Error_Succeed; } int CIDCertFSM::ReadAndScanUTF8(SpReqAnsContext::Pointer ctx) { LOG_FUNCTION(); DeleteZP(Bmp_ZP | Bmp_SCAN, 1); //清理图片文件 //记录身份证相关图片的最近修改时间,用于上送信息调研,后续下掉 - 2025.6.13 CJL headPhotoTimeStr.Clear(); headPhotoTime = 0; frontPhotoTimeStr.Clear(); frontPhotoTime = 0; backPhotoTimeStr.Clear(); backPhotoTime = 0; currentSysTime = time(nullptr); bool bExitWhenReading = false; int curDeleteType = Bmp_ZP; DWORD elapsed = 0; DWORD dwStart = SP::Module::Comm::RVCGetTickCount(); DWORD dwEnd = SP::Module::Comm::RVCGetTickCount(); ErrorCodeEnum errRfOpen = Error_Unexpect; ErrorCodeEnum errAuth = Error_Unexpect; ErrorCodeEnum errReadEx2 = Error_Unexpect; ErrorCodeEnum errRfClose = Error_Unexpect; m_bCancelRead = false; m_bReading = true; m_bExit = false; LogEvent(Severity_Middle, LOG_EVT_IDCERTIFICATE_GREEN_ON, "IDCer warning on"); while (elapsed < IDCER_READ_TIMEOUT && (errReadEx2 != Error_Succeed) && !m_bCancelRead) { if (m_bExit) { DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("exit"); break; } if (errRfOpen != Error_Succeed) { m_ullBeginTime = SP::Module::Comm::RVCGetTickCount(); errRfOpen = m_hDevHelper->IDCerRFControl(true); m_ullEndTime = SP::Module::Comm::RVCGetTickCount(); OpenRFControlTime = m_ullEndTime - m_ullBeginTime; if (Error_Succeed == errRfOpen) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_USER) .setAPI("DevAdapter::IDCerRFControl").setLogCode(IDCertService_LogCode_OpenIDCerRFControl) .setCostTime(OpenRFControlTime)(); } else { dwEnd = SP::Module::Comm::RVCGetTickCount(); elapsed = dwEnd - dwStart; Sleep(IDCER_AUTH_INTERVAL); continue; } } Sleep(IDCER_AUTH_INTERVAL); m_ullBeginTime = SP::Module::Comm::RVCGetTickCount(); errAuth = m_hDevHelper->IDCerAuthenticate(); m_ullEndTime = SP::Module::Comm::RVCGetTickCount(); IDCerAuthenticateTime = m_ullEndTime - m_ullBeginTime; if (Error_Succeed != errAuth) { dwEnd = SP::Module::Comm::RVCGetTickCount(); elapsed = dwEnd - dwStart; continue; } else { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_USER) .setAPI("DevAdapter::IDCerAuthenticate").setCostTime(IDCerAuthenticateTime)(); IDCerInfoEx2 idInfoEx2; memset(&idInfoEx2, 0, sizeof(idInfoEx2)); m_ullBeginTime = SP::Module::Comm::RVCGetTickCount(); errReadEx2 = m_hDevHelper->IDCerGetDataEx2(idInfoEx2); m_ullEndTime = SP::Module::Comm::RVCGetTickCount(); IDCerGetDataEx2Time = m_ullEndTime - m_ullBeginTime; if (errReadEx2 == Error_NotImpl) { ctx->Ans.msgtype = 0; //旧字段传递,GBK、字符串传递文字信息 } else { ctx->Ans.msgtype = 1; //新字段传递,UTF8、二进制传递文字信息 //ex2数据读取功能代码、UCS2转UTF8代码 if (errReadEx2 == Error_Succeed) { DbgWithLink(LOG_LEVEL_INFO, ctx->link.checkEmpty() ? LOG_TYPE_SYSTEM : LOG_TYPE_USER) .setAPI("DevAdapter::IDCerGetDataEx2").setLogCode(IDCertService_LogCode_IDCerGetDataEx2).setCostTime(IDCerGetDataEx2Time)(); LogEvent(Severity_Middle, LOG_EVT_IDCERTIFICATE_OP, "IDCertifacate op."); //转换数据并赋值至传出字段 CopyIDCerDataToCtx(idInfoEx2, ctx); ctx->Ans.photodata = ctx->Ans.headphoto; //现接口继续保持复制图片,JS接口下掉photodata字段 - 2025.6.17 ctx->Ans.hasscan = 0; if (igestionVer == TRUE) //吸入式设备才调用正反扫描功能 { if (GetScanImg(idInfoEx2, ctx->Ans.frontphoto, ctx->Ans.backphoto)) { curDeleteType = Bmp_ZP | Bmp_SCAN; ctx->Ans.hasscan = 1; } } DeleteZP(curDeleteType, 2); WarnImgCreateTime(); //记录身份证相关图片的最近修改时间,用于上送信息调研,后续下掉 - 2025.6.13 CJL break; } } } dwEnd = SP::Module::Comm::RVCGetTickCount(); elapsed = dwEnd - dwStart; } DeleteZP(curDeleteType); if (m_bExit) { bExitWhenReading = true; } m_bExit = false; m_bReading = false; LogEvent(Severity_Middle, LOG_EVT_IDCERTIFICATE_GREEN_OFF, "IDCer warning off"); m_ullBeginTime = SP::Module::Comm::RVCGetTickCount(); errRfClose = m_hDevHelper->IDCerRFControl(false); m_ullEndTime = SP::Module::Comm::RVCGetTickCount(); CloseRFControlTime = m_ullEndTime - m_ullBeginTime; if (errRfClose != Error_Succeed) { SetErrorAndLog(errRfClose, MEC_DEVAPI_IDCER_IDCerRFControl, "DevAdapter::IDCerRFControl", __FUNCTION__, false, CloseRFControlTime, IDCertService_LogCode_CloseIDCerRFControl); } else { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_USER).setAPI("DevAdapter::IDCerRFControl") .setLogCode(IDCertService_LogCode_CloseIDCerRFControl) .setCostTime(CloseRFControlTime)(); } if (errReadEx2 == Error_Succeed) { ctx->Answer(Error_Succeed); } else if (m_bCancelRead) { ctx->Answer(Error_Cancel); } else if (elapsed >= IDCER_READ_TIMEOUT) { if (errAuth == Error_Succeed) { if (errReadEx2 != Error_Succeed) { SetErrorAndLog(errReadEx2, MEC_DEVAPI_IDCER_IDCerGetDataEx2, "DevAdapter::IDCerGetDataEx2", __FUNCTION__, true, IDCerGetDataEx2Time, IDCertService_LogCode_IDCerGetDataEx2); ctx->Answer(Error_TimeOut, GetAlarmDEC()); //RTA2109 } } else if (errRfOpen != Error_Succeed) { SetErrorAndLog(errRfOpen, MEC_DEVAPI_IDCER_IDCerRFControl, "DevAdapter::IDCerRFControl", __FUNCTION__, true, OpenRFControlTime, IDCertService_LogCode_OpenIDCerRFControl); ctx->Answer(Error_TimeOut, GetAlarmDEC()); } else { if (errAuth == Error_DevMedia) { LogWarn(Severity_Low, Error_Unexpect, IDCertificate_UserErrorCode_Timeout_OtherCard, "读证超时,插入的卡片非身份."); DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_USER).setAPI("DevAdapter::IDCerAuthenticate").setCostTime(IDCerAuthenticateTime)(); ctx->Answer(Error_TimeOut); } else if (errAuth == Error_Dev_IDCardNotFound) { LogWarn(Severity_Low, Error_Unexpect, IDCertificate_UserErrorCode_Timeout_NoCard, "读证超时,未检测到有卡片插入."); DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_USER).setAPI("DevAdapter::IDCerAuthenticate").setCostTime(IDCerAuthenticateTime)(); ctx->Answer(Error_TimeOut); } else { SetErrorAndLog(errAuth, MEC_DEVAPI_IDCER_IDCerAuthenticate_Error, "DevAdapter::IDCerAuthenticate", __FUNCTION__, false, IDCerAuthenticateTime); //RTA2116 ctx->Answer(Error_TimeOut, GetAlarmDEC()); } } } else { DbgWithLink(LOG_LEVEL_ERROR, LOG_TYPE_USER).setResultCode("RTA2104")("ReadAndScanUTF8 some thing wrong."); ctx->Answer(Error_Unexpect, IDCertificate_UserErrorCode_ReadAndScan_Failed); LogError(Severity_High, Error_Unexpect, IDCertificate_UserErrorCode_ReadAndScan_Failed, "ReadAndScanUTF8 some thing wrong."); } if (m_bCancelRead) { DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("return 1"); return 1; } if (bExitWhenReading) { DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("return 2"); return 2; } DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("return 0"); return 0; } int CIDCertFSM::ReadAndScanUTF8JS(SpReqAnsContext::Pointer ctx) { LOG_FUNCTION(); DeleteZP(Bmp_ZP | Bmp_SCAN, 1); //清理图片文件 //记录身份证相关图片的最近修改时间,用于上送信息调研,后续下掉 - 2025.6.13 CJL headPhotoTimeStr.Clear(); headPhotoTime = 0; frontPhotoTimeStr.Clear(); frontPhotoTime = 0; backPhotoTimeStr.Clear(); backPhotoTime = 0; currentSysTime = time(nullptr); bool bExitWhenReading = false; int curDeleteType = Bmp_ZP; DWORD elapsed = 0; DWORD dwStart = SP::Module::Comm::RVCGetTickCount(); DWORD dwEnd = SP::Module::Comm::RVCGetTickCount(); ErrorCodeEnum errRfOpen = Error_Unexpect; ErrorCodeEnum errAuth = Error_Unexpect; ErrorCodeEnum errReadEx2 = Error_Unexpect; ErrorCodeEnum errRfClose = Error_Unexpect; m_bCancelRead = false; m_bReading = true; m_bExit = false; LogEvent(Severity_Middle, LOG_EVT_IDCERTIFICATE_GREEN_ON, "IDCer warning on"); while (elapsed < IDCER_READ_TIMEOUT && (errReadEx2 != Error_Succeed) && !m_bCancelRead) { if (m_bExit) { DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("exit"); break; } if (errRfOpen != Error_Succeed) { m_ullBeginTime = SP::Module::Comm::RVCGetTickCount(); errRfOpen = m_hDevHelper->IDCerRFControl(true); m_ullEndTime = SP::Module::Comm::RVCGetTickCount(); OpenRFControlTime = m_ullEndTime - m_ullBeginTime; if (Error_Succeed == errRfOpen) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_USER) .setAPI("DevAdapter::IDCerRFControl").setLogCode(IDCertService_LogCode_OpenIDCerRFControl) .setCostTime(OpenRFControlTime)(); } else { dwEnd = SP::Module::Comm::RVCGetTickCount(); elapsed = dwEnd - dwStart; Sleep(IDCER_AUTH_INTERVAL); continue; } } Sleep(IDCER_AUTH_INTERVAL); m_ullBeginTime = SP::Module::Comm::RVCGetTickCount(); errAuth = m_hDevHelper->IDCerAuthenticate(); m_ullEndTime = SP::Module::Comm::RVCGetTickCount(); IDCerAuthenticateTime = m_ullEndTime - m_ullBeginTime; if (Error_Succeed != errAuth) { dwEnd = SP::Module::Comm::RVCGetTickCount(); elapsed = dwEnd - dwStart; continue; } else { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_USER) .setAPI("DevAdapter::IDCerAuthenticate").setCostTime(IDCerAuthenticateTime)(); IDCerInfoEx2 idInfoEx2; memset(&idInfoEx2, 0, sizeof(idInfoEx2)); m_ullBeginTime = SP::Module::Comm::RVCGetTickCount(); errReadEx2 = m_hDevHelper->IDCerGetDataEx2(idInfoEx2); m_ullEndTime = SP::Module::Comm::RVCGetTickCount(); IDCerGetDataEx2Time = m_ullEndTime - m_ullBeginTime; //ex2数据读取功能代码、UCS2转UTF8代码 if (errReadEx2 == Error_Succeed) { DbgWithLink(LOG_LEVEL_INFO, ctx->link.checkEmpty() ? LOG_TYPE_SYSTEM : LOG_TYPE_USER) .setAPI("DevAdapter::IDCerGetDataEx2").setLogCode(IDCertService_LogCode_IDCerGetDataEx2).setCostTime(IDCerGetDataEx2Time)(); LogEvent(Severity_Middle, LOG_EVT_IDCERTIFICATE_OP, "IDCertifacate op."); //转换数据并赋值至传出字段 CopyIDCerDataToCtx(idInfoEx2, ctx); ctx->Ans.hasscan = 0; if (igestionVer == TRUE) //吸入式设备才调用正反扫描功能 { if (GetScanImg(idInfoEx2, ctx->Ans.frontphoto, ctx->Ans.backphoto)) { curDeleteType = Bmp_ZP | Bmp_SCAN; ctx->Ans.hasscan = 1; } } DeleteZP(curDeleteType, 2); WarnImgCreateTime(); //记录身份证相关图片的最近修改时间,用于上送信息调研,后续下掉 - 2025.6.13 CJL break; } } dwEnd = SP::Module::Comm::RVCGetTickCount(); elapsed = dwEnd - dwStart; } DeleteZP(curDeleteType); if (m_bExit) { bExitWhenReading = true; } m_bExit = false; m_bReading = false; LogEvent(Severity_Middle, LOG_EVT_IDCERTIFICATE_GREEN_OFF, "IDCer warning off"); m_ullBeginTime = SP::Module::Comm::RVCGetTickCount(); errRfClose = m_hDevHelper->IDCerRFControl(false); m_ullEndTime = SP::Module::Comm::RVCGetTickCount(); CloseRFControlTime = m_ullEndTime - m_ullBeginTime; if (errRfClose != Error_Succeed) { SetErrorAndLog(errRfClose, MEC_DEVAPI_IDCER_IDCerRFControl, "DevAdapter::IDCerRFControl", __FUNCTION__, false, CloseRFControlTime, IDCertService_LogCode_CloseIDCerRFControl); } else { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_USER).setAPI("DevAdapter::IDCerRFControl") .setLogCode(IDCertService_LogCode_CloseIDCerRFControl) .setCostTime(CloseRFControlTime)(); } if (errReadEx2 == Error_Succeed) { ctx->Answer(Error_Succeed); } else if (m_bCancelRead) { ctx->Answer(Error_Cancel); } else if (elapsed >= IDCER_READ_TIMEOUT) { if (errAuth == Error_Succeed) { if (errReadEx2 != Error_Succeed) { SetErrorAndLog(errReadEx2, MEC_DEVAPI_IDCER_IDCerGetDataEx2, "DevAdapter::IDCerGetDataEx2", __FUNCTION__, true, IDCerGetDataEx2Time, IDCertService_LogCode_IDCerGetDataEx2); ctx->Answer(Error_Unexpect, GetAlarmDEC()); //RTA2109 } } else if (errRfOpen != Error_Succeed) { SetErrorAndLog(errRfOpen, MEC_DEVAPI_IDCER_IDCerRFControl, "DevAdapter::IDCerRFControl", __FUNCTION__, true, OpenRFControlTime, IDCertService_LogCode_OpenIDCerRFControl); ctx->Answer(Error_Unexpect, GetAlarmDEC()); //RTA2106 } else { if (errAuth == Error_DevMedia) { LogWarn(Severity_Low, Error_Unexpect, IDCertificate_UserErrorCode_Timeout_OtherCard, "读证超时,插入的卡片非身份."); DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_USER).setAPI("DevAdapter::IDCerAuthenticate").setCostTime(IDCerAuthenticateTime)(); ctx->Answer(Error_Unexpect, GetAlarmDEC(MEC_DEVAPI_IDCER_IDCerAuthenticate_NotIDCard)); //RTA2108 } else if (errAuth == Error_Dev_IDCardNotFound) { LogWarn(Severity_Low, Error_Unexpect, IDCertificate_UserErrorCode_Timeout_NoCard, "读证超时,未检测到有卡片插入."); DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_USER).setAPI("DevAdapter::IDCerAuthenticate").setCostTime(IDCerAuthenticateTime)(); ctx->Answer(Error_Unexpect, GetAlarmDEC(MEC_DEVAPI_IDCER_IDCerAuthenticate_NoCard)); //RTA2107 } else { SetErrorAndLog(errAuth, MEC_DEVAPI_IDCER_IDCerAuthenticate_Error, "DevAdapter::IDCerAuthenticate", __FUNCTION__, false, IDCerAuthenticateTime); //RTA2116 ctx->Answer(Error_Unexpect, GetAlarmDEC()); } } } if (m_bCancelRead) { DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("return 1"); return 1; } if (bExitWhenReading) { DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("return 2"); return 2; } DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("return 0"); return 0; } ErrorCodeEnum CIDCertFSM::GetPngBlobEx(CBlob &data, CSimpleStringA fileNamePrefix) { CSimpleStringA strPath, errMsg, strOldPath; ErrorCodeEnum eErr; eErr = m_pEntity->GetFunction()->GetPath("Dep", strPath); if (eErr != Error_Succeed) { DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM).setResultCode(RTAERR_GETPATH_FAILED)("Get [Dep] path failed! errcode:%s.", SpStrError(eErr)); return Error_Param; } strPath = strPath + SPLIT_SLASH_STR + fileNamePrefix; //涉及到后缀名变更,单独实现 if (!ExistsFileA((const char*)(strPath + ".bmp"))) { eErr = m_pEntity->GetFunction()->GetPath("DepBak", strOldPath); if (eErr != Error_Succeed) { DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM).setResultCode(RTAERR_GETPATH_FAILED)("Get [DepBak] Path failed! errcode:%s.", SpStrError(eErr)); return Error_Param; } strOldPath = strOldPath + SPLIT_SLASH_STR + fileNamePrefix; if (ExistsFileA(strOldPath + ".bmp"))//在旧Dep路径下找到文件时告警 { strPath = strOldPath; CSimpleStringA warnMsg = CSimpleStringA::Format("Find %s.bmp in OLD dep path!", strOldPath.GetData()); LogWarn(Severity_Middle, Error_Unexpect, IDCertificate_UserErrorCode_FindFile_in_DepBak, warnMsg.GetData()); } } //找不到本次图片生成 CSimpleStringA imgRTACode = ""; HeadImgDelRTA headRta; ScanImgDelRTA scanRta; map errInfo; CSimpleStringA tErrStr; CSimpleStringA disecription; if (fileNamePrefix == "zp") { imgRTACode = headRta.noFindCur; //记录身份证相关图片的最近修改时间,用于上送信息调研,后续下掉 - 2025.6.13 CJL headPhotoTimeStr = GetFileLastModifyTime(strPath + ".bmp").GetData(); } else if (fileNamePrefix == "idfront") { imgRTACode = scanRta.noFindCur; //记录身份证相关图片的最近修改时间,用于上送信息调研,后续下掉 - 2025.6.13 CJL frontPhotoTimeStr = GetFileLastModifyTime(strPath + ".bmp").GetData(); } else if (fileNamePrefix == "idback") { imgRTACode = scanRta.noFindCur; //记录身份证相关图片的最近修改时间,用于上送信息调研,后续下掉 - 2025.6.13 CJL backPhotoTimeStr = GetFileLastModifyTime(strPath + ".bmp").GetData(); } IplImage *src = cvLoadImage(strPath + ".bmp"); if (!src) { if (!ExistsFileA(strPath + ".bmp")) //找不到本次图片生成 { disecription = CSimpleStringA::Format("Can not find file %s.", (fileNamePrefix + ".bmp").GetData()); errInfo.clear(); errInfo["path"] = (strPath + ".bmp").GetData(); errInfo["description"] = disecription.GetData(); tErrStr = generateJsonStr(errInfo).second.c_str(); DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM).setResultCode(imgRTACode).setAPI("DeleteFileIfExisted")(tErrStr.GetData()); } errMsg = CSimpleStringA::Format("read file %s.bmp failed.err:%d", (const char*)strPath, GetLastError()); if (transImgMsg.GetLength() != 0) { transImgMsg = transImgMsg + "," + errMsg; } else { transImgMsg = errMsg; } cvReleaseImage(&src); return Error_Unexpect; } cvSaveImage(strPath + ".jpg", src); FILE *fp = fopen(strPath + ".jpg", "rb"); if (fp) { fseek(fp, 0, SEEK_END); long flen = ftell(fp); fseek(fp, 0, SEEK_SET); data.Alloc(flen); fread(data.m_pData, 1, flen, fp); fclose(fp); cvReleaseImage(&src); return Error_Succeed; } else { if (!ExistsFileA(strPath + ".jpg")) //找不到本次图片生成 { disecription = CSimpleStringA::Format("Can not find file %s.", (fileNamePrefix + ".bmp").GetData()); errInfo.clear(); errInfo["path"] = (strPath + ".jpg").GetData(); errInfo["description"] = disecription.GetData(); tErrStr = generateJsonStr(errInfo).second.c_str(); DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM).setResultCode(imgRTACode).setAPI("DeleteFileIfExisted")(tErrStr.GetData()); } errMsg = CSimpleStringA::Format("fopen %s failed!", (const char*)strPath); //DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)(errMsg.GetData()); if (transImgMsg.GetLength() != 0) { transImgMsg = transImgMsg + "," + errMsg; } else { transImgMsg = errMsg; } cvReleaseImage(&src); return Error_IO; } } void CIDCertFSM::SelfTest(EntityTestEnum eTestType,CSmartPointer pTransactionContext) { //for simple pTransactionContext->SendAnswer(m_testResult); } template ErrorCodeEnum CIDCertFSM::DeleteFileIfExisted(LPCTSTR fileName, T picRta, int deleteTiming) { if(strlen(fileName) == 0 || strchr(fileName, (int)'*') != NULL) { DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__) ("Invalid or empty fileName(%s)", fileName); return Error_Param; } CSimpleStringA strAimPath, strAimOldPath; ErrorCodeEnum erroCode = m_pEntity->GetFunction()->GetPath("Dep", strAimPath); strAimPath = strAimPath + SPLIT_SLASH_STR + fileName; UpdateAndWarnFileFindInDepBak(strAimPath, fileName, IDCertificate_UserErrorCode_FindFile_in_DepBak); map errInfo; CSimpleStringA errMsg; if (ExistsFileA((LPCTSTR)strAimPath)) { if (deleteTiming == 1) //检测到上次读证残留图片 { errInfo["path"] = strAimPath.GetData(); errInfo["hash"] = GetFileHashStr(strAimPath).GetData(); errInfo["modifytime"] = GetFileLastModifyTime(strAimPath).GetData(); errMsg = generateJsonStr(errInfo).second.c_str(); //CSimpleStringA errMsg = CSimpleStringA::Format("检测到上次读证残留图片:[%s]", strAimPath.GetData()); DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM).setResultCode(picRta.findLast).setAPI("DeleteFileIfExisted")(errMsg.GetData()); } if (RemoveFileA((LPCTSTR)strAimPath)) { DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("RemoveFileA(%s) suc.", (LPCTSTR)strAimPath); return Error_Succeed; } else { CSimpleStringA rtaCode = ""; if (deleteTiming == 1) //删除上次读证残留图片失败 { rtaCode = picRta.delLastErr; } else if (deleteTiming == 2) //删除本次读证生成图片失败 { rtaCode = picRta.delCurErr; } errInfo.clear(); errInfo["path"] = strAimPath.GetData(); errInfo["lasterror"] = to_string(GetLastError()); errMsg = generateJsonStr(errInfo).second.c_str(); DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM).setResultCode(rtaCode.GetData()).setAPI("DeleteFileIfExisted") (errMsg.GetData()); return Error_Unexpect; } } else //如果文件不存在,会在图片格式转换函数GetPngBlobEx()里报错, 这里就不重复报错了 { return Error_Succeed; } } ErrorCodeEnum CIDCertFSM::GetDevCatInfo(DevCategoryInfo &devInfo, CSimpleStringA& devType) { if (m_getDevCategory != Error_Succeed) return m_getDevCategory; strncpy(devInfo.szModel, m_devCatInfo.szModel, (MAX_DEV_MODEL_LEN > strlen(m_devCatInfo.szModel)) ? strlen(m_devCatInfo.szModel) + 1 : MAX_DEV_MODEL_LEN); strncpy(devInfo.szType, m_devCatInfo.szType, (MAX_DEV_TYPE_LEN > strlen(m_devCatInfo.szType)) ? strlen(m_devCatInfo.szType) + 1 : MAX_DEV_TYPE_LEN); strncpy(devInfo.szVendor, m_devCatInfo.szVendor, (MAX_DEV_VENDOR_LEN > strlen(m_devCatInfo.szVendor)) ? strlen(m_devCatInfo.szVendor) + 1 : MAX_DEV_VENDOR_LEN); devType = m_adapterInfo.strVersion;//适配器版本号 return Error_Succeed; } void CIDCertFSM::DeleteZP(int type, int deleteTiming) { if ((type&Bmp_ZP) == Bmp_ZP) { HeadImgDelRTA headImgRta; DeleteFileIfExisted("zp.jpg", headImgRta, deleteTiming); DeleteFileIfExisted("zp.bmp", headImgRta, deleteTiming); //All } if ((type&Bmp_SCAN) == Bmp_SCAN) { ScanImgDelRTA sacnImgRta; DeleteFileIfExisted("idfront.bmp", sacnImgRta, deleteTiming); DeleteFileIfExisted("idback.bmp", sacnImgRta, deleteTiming); DeleteFileIfExisted("idfront.jpg", sacnImgRta, deleteTiming); DeleteFileIfExisted("idback.jpg", sacnImgRta, deleteTiming); } } int CIDCertFSM::Initial() { LOG_FUNCTION(); SetDevState(DEVICE_STATUS_NOT_READY); auto pEntity = GET_DEV_ENTITY_BASE_POINTER(); //to do device init ErrorCodeEnum eErrDev; CSmartPointer spEntityFunction = GetEntityBase()->GetFunction(); CSmartPointer spConfig; eErrDev = spEntityFunction->OpenConfig(Config_Root, spConfig); if (eErrDev != Error_Succeed) { LogWarn(Severity_Middle, eErrDev, IDCertificate_UserErrorCode_Open_RootCfg_Failed, "open cfg file failed!"); DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM).setResultCode(RTAERR_CONFIG_OPEN_FAILED).setAPI(__FUNCTION__)("open cfg file failed!"); m_bOpening = false; return 2; } eErrDev = pEntity->LoadVendorLibName(); if (eErrDev != Error_Succeed) { LogWarn(Severity_Middle, eErrDev, IDCertificate_UserErrorCode_Get_DevAdapter_Path_Failed, CSimpleStringA::Format("LoadVendorLibName failed,error:%d", eErrDev)); m_bOpening = false; return 2; } FulfillAdapterInfoFrom(pEntity->vendorLibInfo); pEntity->InitializeVendorLogSwitch(); eErrDev = LoadUpAdapterLibrary(); if (!IS_SUCCEED(eErrDev)) { LogWarn(Severity_Middle, Error_Unexpect, IDCertificate_UserErrorCode_DllLoadFailed, CSimpleStringA::Format("身份证加载厂商适配器失败!GLE=%d.", GetLastError())); m_bOpening = false; return 2; } m_ullBeginTime = SP::Module::Comm::RVCGetTickCount(); ErrorCodeEnum err = m_hDevHelper->DevOpen(m_adapterInfo.GetPortInt()); m_ullEndTime = SP::Module::Comm::RVCGetTickCount(); m_bOpening = false; if (err == Error_Succeed) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI("DevAdapter::DevOpen").setCostTime(m_ullEndTime - m_ullBeginTime) ("IDCer DevOpen port:%d", m_adapterInfo.GetPortInt()); } else { SetErrorAndLog(err, MEC_DEVAPI_IDCER_DevOpen, "DevAdapter::DevOpen", __FUNCTION__, false, m_ullEndTime - m_ullBeginTime); m_hDevHelper.TearDown(); return 2; } memset(m_devCatInfo.szModel, 0, MAX_DEV_MODEL_LEN); memset(m_devCatInfo.szType, 0, MAX_DEV_TYPE_LEN); memset(m_devCatInfo.szVendor, 0, MAX_DEV_VENDOR_LEN); m_ullBeginTime = SP::Module::Comm::RVCGetTickCount(); eErrDev = m_hDevHelper->GetDevCategory(m_devCatInfo); m_ullEndTime = SP::Module::Comm::RVCGetTickCount(); m_getDevCategory = err; //获取设备信息的api执行结果 if (eErrDev == Error_Succeed) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM).setAPI("DevAdapter::GetDevCategory").setCostTime(m_ullEndTime - m_ullBeginTime)(); CSimpleStringA szMod(m_devCatInfo.szModel); if (strstr(m_devCatInfo.szModel, "CODE=UCS2") != NULL) { supportUCS2 = TRUE; } if (strstr(m_devCatInfo.szModel, "STYLE=IG") != NULL) { igestionVer = TRUE; } if (strstr(m_devCatInfo.szModel, "FUNCTION=ITFY") != NULL) { supportNewForeigner = TRUE; } m_adapterInfo.FulfillCategoryInfo(m_devCatInfo); } else { SetErrorAndLog(eErrDev, MEC_DEVAPI_IDCER_GetDevCategory, "DevAdapter::GetDevCategory", __FUNCTION__, false, m_ullEndTime - m_ullBeginTime); } if (m_hDevHelper != nullptr) { SetDevInitFlag(); DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("身份证打开成功"); return 0; } else return 2; return 0; } void CIDCertFSM::UCS2_to_UTF8(UINT16* ucs2_code, UINT8* utf8_code) { UINT8* out = utf8_code; if (!utf8_code || !ucs2_code) { DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM) ("UCS2转换异常:UCS2[%d], UTF8[%d]", (ucs2_code == NULL), (utf8_code == NULL)); return; } while (*ucs2_code != 0) { if (0x0080 > *ucs2_code) { /* 1 byte UTF-8 Character.*/ *out = (UINT8)*ucs2_code; ++out; } else if (0x0800 > *ucs2_code) { /*2 bytes UTF-8 Character.*/ *out = ((UINT8)(*ucs2_code >> 6)) | 0xc0; *(out + 1) = ((UINT8)(*ucs2_code & 0x003F)) | 0x80; out += 2; } else { /* 3 bytes UTF-8 Character .*/ *out = ((UINT8)(*ucs2_code >> 12)) | 0xE0; *(out + 1) = ((UINT8)((*ucs2_code & 0x0FC0) >> 6)) | 0x80; *(out + 2) = ((UINT8)(*ucs2_code & 0x003F)) | 0x80; out += 3; } //挪动两个字节 ++ucs2_code; } return; } void CIDCertFSM::GetSexUTF8String(UINT16* in, UINT8* out) { if (!in || !out) { DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM) ("性别转换参数异常:in_UCS2[%d], out_UTF8[%d]", (in == NULL), (out == NULL)); return; } #ifdef RVC_OS_WIN wstring man = L"男"; wstring woman = L"女"; wstring unknow = L"未说明"; unsigned char tmp[1024]; memset(tmp, 0, 1024); UCS2_to_UTF8(in, tmp); int sexCode = _wtoi((wchar_t*)in); switch (sexCode) { case 1: UCS2_to_UTF8((UINT16*)man.c_str(), out); break; case 2: UCS2_to_UTF8((UINT16*)woman.c_str(), out); break; case 9: UCS2_to_UTF8((UINT16*)unknow.c_str(), out); break; default: UCS2_to_UTF8(in, out); break; } #else //linux默认编码就是utf8,直接拷贝 char* man = "男"; char* woman = "女"; char* unknow = "未说明"; unsigned char sexIn[1024]; memset(sexIn, 0, 1024); UCS2_to_UTF8(in, sexIn); //linux默认编码就是utf8,转成utf8格式后直接就是linux下的char类型 long sexCode = atoi((char*)sexIn); //直接转成数字 switch (sexCode) { case 1: memcpy(out, man, strlen(man)); break; case 2: memcpy(out, woman, strlen(woman)); break; case 9: memcpy(out, unknow, strlen(unknow)); break; default: UCS2_to_UTF8(in, out); break; } #endif return; } void CIDCertFSM::GetNationalUTF8String(UINT16* in, UINT8* out) { if (!in || !out) { DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM) ("民族转换参数异常:in_UCS2[%d], out_UTF8[%d]", (in == NULL), (out == NULL)); return; } #ifdef RVC_OS_WIN int nCode = _wtoi((wchar_t*)in); if (nCode >= 1 && nCode <= 56) { UCS2_to_UTF8((UINT16*)nationalCode[nCode].c_str(), out); } else { UCS2_to_UTF8(in, out); } #else unsigned char nationIn[1024]; memset(nationIn, 0, 1024); UCS2_to_UTF8(in, nationIn); //linux默认编码就是utf8,转成utf8格式后直接就是linux下的char类型 int nCode = atoi((char*)nationIn); //直接转成数字 if (nCode >= 1 && nCode <= 56) { //linux默认编码就是utf8,直接拷贝 memcpy(out, nationalCode[nCode].c_str(), strlen(nationalCode[nCode].c_str())); } else { UCS2_to_UTF8(in, out); } #endif return; } void CIDCertFSM::GetDateStandardFormatUTF8(UINT16* in, UINT8* out) { if (!in || !out) { DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM) ("日期转换参数异常:in_UCS2[%d], out_UTF8[%d]", (in == NULL), (out == NULL)); return; } #ifdef RVC_OS_WIN wstring longtime = L"长期"; unsigned char ltimeCheck[1024]; memset(ltimeCheck, 0, 1024); UCS2_to_UTF8((UINT16*)longtime.c_str(), ltimeCheck); #else char* ltimeCheck = "长期"; //linux默认编码就是utf8 #endif unsigned char ltimeIn[1024]; memset(ltimeIn, 0, 1024); UCS2_to_UTF8(in, ltimeIn); int cmp = strcmp((char*)ltimeCheck, (char*)ltimeIn); //判断长期证件 if (cmp == 0) { #ifdef RVC_OS_WIN wstring time = L"9999/12/31"; UCS2_to_UTF8((UINT16*)time.c_str(), out); #else char tEndtime[1024] = "9999/12/31"; //linux默认编码就是utf8,不转换,直接传出去就好 memcpy(out, tEndtime, strlen(tEndtime)); #endif } else //其他日期 { UINT16 trans[1024]; memset(trans, 0, 1024); int cnt = 0; UINT16* p1 = in; UINT16* p2 = trans; while (*p1 != '\0') { if (cnt == 4 || cnt == 7) //在对年份和月份后增加斜杠 { *p2 = '/'; p2++; } else { *p2 = *p1; p1++; p2++; } cnt++; } UCS2_to_UTF8(trans, out); } return; } void CIDCertFSM::RemoveUCS2Blank(UINT16* ucs2_code) { if (!ucs2_code) { DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM)("去除UCS2空格异常, UCS2数据地址为空!"); return; } bool findContent = false; UINT16* tmp = ucs2_code; UINT16* start = ucs2_code; UINT16* end = ucs2_code; while (*tmp == ' ') { tmp++; } while (*tmp != '\0') { if (*tmp != ' ' && findContent == false) { findContent = true; start = tmp; //找到内容开始位置 end = tmp; } else { if (*tmp != ' ') { end = tmp; } } tmp++; } tmp = end; while (*tmp != '\0') { if (*tmp == ' ') //去除结尾空格 { *tmp = '\0'; break; } tmp++; } ucs2_code = start; return; } int CIDCertFSM::GetUCS2ByteLength(UINT16* ucs2_code) { if (!ucs2_code) return 0; int len = 0; UINT16* tmp = ucs2_code; while (*tmp != '\0' && *tmp != ' ') { len++; tmp++; } return 2 * len; } void CIDCertFSM::CheckHanZi(UINT16* ucs2_code) { if (!ucs2_code) return; UINT16* tmp = ucs2_code; int count = 1; char* strFileHash = new char[4]; while (*tmp != '\0') { if (*tmp >= 0x4e00 && *tmp <= 0x9fa5) { //DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("是汉字。"); } else { BYTE fileHash[2]; memset(fileHash, 0, 2); memcpy(fileHash, tmp, 2); memset(strFileHash, 0, 4); SP::Module::Util::HexBuf2StrBuf(fileHash, &strFileHash, 2); CSimpleStringA warn = CSimpleStringA::Format("姓名第%d个字非汉字编码, 数据为:%s", count, strFileHash); LogWarn(Severity_Low, Error_Debug, IDCertificate_UserErrorCode_ReadAndScan_NotHanZi, warn.GetData()); } tmp++; count++; } if (strFileHash != nullptr) { delete[] strFileHash; strFileHash = nullptr; } } CSimpleStringA CIDCertFSM::GetFileHashStr(CSimpleStringA filePath) { //calculate file hash value CSimpleStringA strHash; char* strFileHash = new char[128]; if (ExistsFileA(filePath.GetData())) { BYTE fileHash[32]; SM3File(const_cast(filePath.GetData()), fileHash); ZeroMemory(strFileHash, 128); SP::Module::Util::HexBuf2StrBuf(fileHash, &strFileHash, 32); strHash = strFileHash; } else { memset(strFileHash, '\0', sizeof(char) * 128); } if (strFileHash != nullptr) { delete[] strFileHash; strFileHash = nullptr; } return strHash; } CSimpleStringA CIDCertFSM::GetFileLastModifyTime(CSimpleStringA filePath) { struct stat fileStat; if (stat(filePath.GetData(), &fileStat) != 0) { return ""; } time_t modTime = fileStat.st_mtime; struct tm* timeInfo = localtime(&modTime); if (strstr(filePath.GetData(), "zp.bmp") != NULL) //头像图片时间 { headPhotoTime = fileStat.st_mtime; } else if (strstr(filePath.GetData(), "idfront.bmp") != NULL) //正面图片时间 { frontPhotoTime = fileStat.st_mtime; } else if (strstr(filePath.GetData(), "idback.bmp") != NULL) //背面图片时间 { backPhotoTime = fileStat.st_mtime; } char buffer[20]; strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeInfo); return buffer; } template void CIDCertFSM::CopyIDCerDataToCtx(IDCerInfoEx2 idInfoEx2, T& ctx) { IDCerTextData *utf8Data = new IDCerTextData(); memset(utf8Data, 0, sizeof(utf8Data)); DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_USER)("各字段长度-姓名:%d; 性别:%d; 民族:%d; 身份证:%d;", GetUCS2ByteLength((UINT16*)idInfoEx2.name.data), GetUCS2ByteLength((UINT16*)idInfoEx2.sex.data), GetUCS2ByteLength((UINT16*)idInfoEx2.nation.data), GetUCS2ByteLength((UINT16*)idInfoEx2.idno.data)); //去除首尾空格 RemoveUCS2Blank((UINT16*)idInfoEx2.name.data); CheckHanZi((UINT16*)idInfoEx2.name.data); //检测汉字编码 RemoveUCS2Blank((UINT16*)idInfoEx2.sex.data); RemoveUCS2Blank((UINT16*)idInfoEx2.nation.data); RemoveUCS2Blank((UINT16*)idInfoEx2.birthday.data); RemoveUCS2Blank((UINT16*)idInfoEx2.address.data); RemoveUCS2Blank((UINT16*)idInfoEx2.idno.data); RemoveUCS2Blank((UINT16*)idInfoEx2.department.data); RemoveUCS2Blank((UINT16*)idInfoEx2.startDate.data); RemoveUCS2Blank((UINT16*)idInfoEx2.endDate.data); RemoveUCS2Blank((UINT16*)idInfoEx2.englishName.data); RemoveUCS2Blank((UINT16*)idInfoEx2.nationality.data); RemoveUCS2Blank((UINT16*)idInfoEx2.idVersion.data); RemoveUCS2Blank((UINT16*)idInfoEx2.idType.data); RemoveUCS2Blank((UINT16*)idInfoEx2.reserved.data); //外国人永居证旧证件关联字段 RemoveUCS2Blank((UINT16*)idInfoEx2.reserved2.data); //英文名备用字段 RemoveUCS2Blank((UINT16*)idInfoEx2.issuedSN.data); //换证次数 //转换各字段数据至UTF8格式 UCS2_to_UTF8((UINT16*)idInfoEx2.name.data, utf8Data->name); GetSexUTF8String((UINT16*)idInfoEx2.sex.data, utf8Data->sex); GetNationalUTF8String((UINT16*)idInfoEx2.nation.data, utf8Data->nation); GetDateStandardFormatUTF8((UINT16*)idInfoEx2.birthday.data, utf8Data->birthday); UCS2_to_UTF8((UINT16*)idInfoEx2.address.data, utf8Data->address); UCS2_to_UTF8((UINT16*)idInfoEx2.idno.data, utf8Data->idno); UCS2_to_UTF8((UINT16*)idInfoEx2.department.data, utf8Data->department); GetDateStandardFormatUTF8((UINT16*)idInfoEx2.startDate.data, utf8Data->startDate); GetDateStandardFormatUTF8((UINT16*)idInfoEx2.endDate.data, utf8Data->endDate); UCS2_to_UTF8((UINT16*)idInfoEx2.englishName.data, utf8Data->englishName); UCS2_to_UTF8((UINT16*)idInfoEx2.nationality.data, utf8Data->nationality); UCS2_to_UTF8((UINT16*)idInfoEx2.idVersion.data, utf8Data->idVersion); UCS2_to_UTF8((UINT16*)idInfoEx2.idType.data, utf8Data->idType); UCS2_to_UTF8((UINT16*)idInfoEx2.reserved.data, utf8Data->reserved); UCS2_to_UTF8((UINT16*)idInfoEx2.reserved2.data, utf8Data->englishNameEx); UCS2_to_UTF8((UINT16*)idInfoEx2.issuedSN.data, utf8Data->IssuedSN); //将数据拷贝至实体接口上下文 ctx->Ans.name_utf8.Alloc(strlen((char*)utf8Data->name)); ctx->Ans.sex_utf8.Alloc(strlen((char*)utf8Data->sex)); ctx->Ans.nation_utf8.Alloc(strlen((char*)utf8Data->nation)); ctx->Ans.birthday_utf8.Alloc(strlen((char*)utf8Data->birthday)); ctx->Ans.address_utf8.Alloc(strlen((char*)utf8Data->address)); ctx->Ans.idcode_utf8.Alloc(strlen((char*)utf8Data->idno)); ctx->Ans.department_utf8.Alloc(strlen((char*)utf8Data->department)); ctx->Ans.startdate_utf8.Alloc(strlen((char*)utf8Data->startDate)); ctx->Ans.enddate_utf8.Alloc(strlen((char*)utf8Data->endDate)); ctx->Ans.englishname_utf8.Alloc(strlen((char*)utf8Data->englishName)); ctx->Ans.nationality_utf8.Alloc(strlen((char*)utf8Data->nationality)); ctx->Ans.idversion_utf8.Alloc(strlen((char*)utf8Data->idVersion)); ctx->Ans.idtype_utf8.Alloc(strlen((char*)utf8Data->idType)); ctx->Ans.reserved_utf8.Alloc(strlen((char*)utf8Data->reserved)); //新外国人永居证关联字段 ctx->Ans.othercode_utf8.Alloc(strlen((char*)utf8Data->englishNameEx)); //英文名备用字段 memcpy(ctx->Ans.name_utf8.m_pData, utf8Data->name, strlen((char*)utf8Data->name)); memcpy(ctx->Ans.sex_utf8.m_pData, utf8Data->sex, strlen((char*)utf8Data->sex)); memcpy(ctx->Ans.nation_utf8.m_pData, utf8Data->nation, strlen((char*)utf8Data->nation)); memcpy(ctx->Ans.birthday_utf8.m_pData, utf8Data->birthday, strlen((char*)utf8Data->birthday)); memcpy(ctx->Ans.address_utf8.m_pData, utf8Data->address, strlen((char*)utf8Data->address)); memcpy(ctx->Ans.idcode_utf8.m_pData, utf8Data->idno, strlen((char*)utf8Data->idno)); memcpy(ctx->Ans.department_utf8.m_pData, utf8Data->department, strlen((char*)utf8Data->department)); memcpy(ctx->Ans.startdate_utf8.m_pData, utf8Data->startDate, strlen((char*)utf8Data->startDate)); memcpy(ctx->Ans.enddate_utf8.m_pData, utf8Data->endDate, strlen((char*)utf8Data->endDate)); memcpy(ctx->Ans.englishname_utf8.m_pData, utf8Data->englishName, strlen((char*)utf8Data->englishName)); memcpy(ctx->Ans.nationality_utf8.m_pData, utf8Data->nationality, strlen((char*)utf8Data->nationality)); memcpy(ctx->Ans.idversion_utf8.m_pData, utf8Data->idVersion, strlen((char*)utf8Data->idVersion)); memcpy(ctx->Ans.idtype_utf8.m_pData, utf8Data->idType, strlen((char*)utf8Data->idType)); memcpy(ctx->Ans.reserved_utf8.m_pData, utf8Data->reserved, strlen((char*)utf8Data->reserved)); //新外国人永居证关联字段 memcpy(ctx->Ans.othercode_utf8.m_pData, utf8Data->englishNameEx, strlen((char*)utf8Data->englishNameEx)); //英文名备用字段 //转换头像图片 GetPngBlobEx(ctx->Ans.headphoto, "zp"); CSimpleStringA csIDInfo, csIDLogInfo, csIDType; #ifdef RVC_OS_WIN csIDInfo = CSimpleStringA::Format("%s", GetGBKString((UINT16*)idInfoEx2.idno.data)); csIDType = CSimpleStringA::Format("%s", GetGBKString((UINT16*)idInfoEx2.idType.data)); #else csIDInfo = CSimpleStringA::Format("%s", utf8Data->idno); csIDType = CSimpleStringA::Format("%s", utf8Data->idType); #endif if (csIDType.IsNullOrEmpty()) csIDLogInfo = SP::Module::Util::DataMask(SP::Module::Util::DataMask_IDCard, csIDInfo); else if (csIDType.Compare("I") == 0 || csIDType.Compare("Y") == 0) csIDLogInfo = SP::Module::Util::DataMask(SP::Module::Util::DataMask_ForeignerPR, csIDInfo); else if (csIDType.Compare("J") == 0) csIDLogInfo = SP::Module::Util::DataMask(SP::Module::Util::DataMask_HKMOTWPermit, csIDInfo); else { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_USER)("IdType:[%s]", csIDType.GetData()); csIDLogInfo = SP::Module::Util::DataMask(SP::Module::Util::DataMask_UNKNOWN, csIDInfo); } LogWarn(Severity_Low, Error_Succeed, IDCertificate_UserErrorCode_ReadAndScan_GetIDInfo, csIDLogInfo.GetData()); if (utf8Data != nullptr) { delete utf8Data; utf8Data = nullptr; } return; } BOOL CIDCertFSM::GetScanImg(IDCerInfoEx2 idInfoEx2, CBlob& frontImg, CBlob& backImg) { BOOL resFlag = FALSE; m_ullBeginTime = SP::Module::Comm::RVCGetTickCount(); ErrorCodeEnum eErr = m_hDevHelper->ScanIDAndSaveImage(); m_ullEndTime = SP::Module::Comm::RVCGetTickCount(); ScanIDAndSaveImageTime = m_ullEndTime - m_ullBeginTime; if (eErr == Error_Succeed) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_USER).setAPI("DevAdapter::ScanIDAndSaveImage").setCostTime(ScanIDAndSaveImageTime)(); transImgMsg.Clear(); //idfront.bmp" and "idback.bmp ErrorCodeEnum eErrFront, eErrBack; eErrFront = GetPngBlobEx(frontImg, "idfront"); eErrBack = GetPngBlobEx(backImg, "idback"); if (eErrFront == Error_Succeed && eErrBack == Error_Succeed) { resFlag = TRUE; #ifdef RVC_OS_WIN if (!closeImgCheck) { ImgChekTask* frontImgCheck = new ImgChekTask(this); frontImgCheck->idNum = GetGBKString((UINT16*)idInfoEx2.idno.data); frontImgCheck->inName = GetGBKString((UINT16*)idInfoEx2.name.data); frontImgCheck->inNationality = GetGBKString((UINT16*)idInfoEx2.nationality.data); frontImgCheck->inIdType = GetGBKString((UINT16*)idInfoEx2.idType.data); frontImgCheck->imgInput = frontImg; frontImgCheck->imgType = "正面"; GetEntityBase()->GetFunction()->PostThreadPoolTask(frontImgCheck); ImgChekTask* backImgCheck = new ImgChekTask(this); backImgCheck->idNum = GetGBKString((UINT16*)idInfoEx2.idno.data); backImgCheck->inName = GetGBKString((UINT16*)idInfoEx2.name.data); backImgCheck->inNationality = GetGBKString((UINT16*)idInfoEx2.nationality.data); backImgCheck->inIdType = GetGBKString((UINT16*)idInfoEx2.idType.data); backImgCheck->imgInput = backImg; backImgCheck->imgType = "背面"; GetEntityBase()->GetFunction()->PostThreadPoolTask(backImgCheck); } #endif } else { CSimpleStringA warnMsg = "ScanIDAndSaveImage() suc. But GetPngBlobEx() failed."; if (transImgMsg.GetLength() != 0) { warnMsg = warnMsg + transImgMsg; } LogWarn(Severity_Middle, Error_Succeed, IDCertificate_UserErrorCode_ReadAndScan_TransImgFaild, warnMsg.GetData()); } } else { if (eErr != Error_NotImpl) SetErrorAndLog(eErr, MEC_DEVAPI_IDCER_ScanIDAndSaveImage, "DevAdapter::ScanIDAndSaveImage", __FUNCTION__, false, ScanIDAndSaveImageTime); } return resFlag; } void CIDCertFSM::WarnImgCreateTime() { //记录身份证相关图片的最近修改时间,用于上送信息调研,后续下掉 - 2025.6.13 CJL CSimpleStringA fileTimeWarn = CSimpleStringA::Format("头像图片时间:[%s], 正面图片时间:[%s],背面图片时间:[%s]", headPhotoTimeStr.GetData(), frontPhotoTimeStr.GetData(), backPhotoTimeStr.GetData()); SeverityLevelEnum ImgTimeWarnLevel = Severity_Low; if ((headPhotoTime > 0 && headPhotoTime < currentSysTime) || (frontPhotoTime > 0 && frontPhotoTime < currentSysTime) || (backPhotoTime > 0 && backPhotoTime < currentSysTime)) { ImgTimeWarnLevel = Severity_Middle; //若生成图片的时间早于本次交易时间,则告LEVEL2 } LogWarn(ImgTimeWarnLevel, Error_Succeed, IDCertificate_UserErrorCode_GetImgFileTime, fileTimeWarn); return; } #ifdef RVC_OS_WIN char* CIDCertFSM::GetGBKString(UINT16* ucs2_code) //将UCS2字段转换为GBK,用于WIN打印日志或者其他中文使用 { char* tData = new char[128]; memcpy(tData, ucs2_code, 128); char* gbkData = NULL; int iSize = WideCharToMultiByte(CP_ACP, 0, (wchar_t*)ucs2_code, -1, NULL, 0, NULL, NULL); gbkData = (char*)malloc((iSize + 1)); WideCharToMultiByte(CP_ACP, 0, (wchar_t*)ucs2_code, -1, gbkData, iSize, NULL, NULL); if (tData != nullptr) { delete[] tData; tData = nullptr; } return gbkData; } void CIDCertFSM::HttpsLogCallBack(const char* logtxt) { //DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM).setAPI(__FUNCTION__)("%s", logtxt); } #endif