diff --git a/General/General/CHINT_Ecn_SendOA.cxx b/General/General/CHINT_Ecn_SendOA.cxx index fda2e34..b737efd 100644 --- a/General/General/CHINT_Ecn_SendOA.cxx +++ b/General/General/CHINT_Ecn_SendOA.cxx @@ -1,16 +1,22 @@ -#include +#include +#include +#include #include "epm_handler_common.h" -#include -#include -#include "CRUL_server_call_httpserver.h" #include #include #include "common_itk_util.h" +#include "tc_util.h" #include -#include "string_utils.h" #include +#include "CRUL_server_call_httpserver.h" #include "ocilib.h" #include "cJSON.h" +#include "tinyxml2.h" +using namespace std; +using namespace tinyxml2; + + + void connectSql() { int url_num = 0; char** url_vals = NULL; @@ -27,10 +33,44 @@ void closeConn() { DisConnServer(); } +/* + 推送SRM接口 +*/ +int CHINT_SendSRM(EPM_action_message_t msg) { + int ifail = ITK_ok; + tag_t root_task = NULLTAG, *sub_tasks = NULL, current_task = NULLTAG, type_tag = NULLTAG; + int sub_task_count = 0, attachCounts = 0; + tag_t* taskAttches = NULLTAG; + tag_t cur_task = NULLTAG; + current_task = msg.task; + EPM_ask_root_task(msg.task, &root_task); + EPM_ask_sub_tasks(root_task, &sub_task_count, &sub_tasks); + EPM_ask_attachments(root_task, EPM_target_attachment, &attachCounts, &taskAttches); + + //多流程对象 ZT2_Procure Revision + for (int i = 0; i < attachCounts; i++) { + int pdfCnt = 0; + char *objType, *wbsNo, *materialNo, *revisionId; + tag_t procureRev = taskAttches[i], *datasets; + AOM_ask_value_string(procureRev, OBJECTTYPE, &objType); + if (strcmp(objType, PROCURETYPE) == 0) { + //获取版本属性:wbs、物料编码、版本、获取规范关系下的pdf文件,获取文件和uid,通过接口推送至SRM系统 + AOM_ask_value_string(procureRev, WBSNO, &wbsNo); + AOM_ask_value_string(procureRev, MATERIALNO, &materialNo); + AOM_ask_value_string(procureRev, REVISIONID, &revisionId); + AOM_ask_value_tags(procureRev, SPECIFICATION, &pdfCnt, &datasets); + //获取数据集的名称和UID + + } + } + + return ifail; +} + cJSON* getDrawingInform(tag_t changeTag) { - int changeNo,signNo, placesNo,beforeNo,verBefNo,aftNo,aftVerNo,reasonNo,processTypeNo; + int changeNo, signNo, placesNo, beforeNo, verBefNo, aftNo, aftVerNo, reasonNo, processTypeNo, prodNct; char **changeDrawingNos, **signs, **placesNos, **changeBefs, **versionBefs, - **changeAfts, **versionAfts, **changeReasons, **processTypes; + **changeAfts, **versionAfts, **changeReasons, **processTypes, **products; AOM_ask_value_strings(changeTag, "zt2_ChangeDrawingNo",&changeNo, &changeDrawingNos); AOM_ask_value_strings(changeTag, "zt2_Sign", &signNo, &signs); AOM_ask_value_strings(changeTag, "zt2_PlacesNo", &placesNo, &placesNos); @@ -38,6 +78,7 @@ cJSON* getDrawingInform(tag_t changeTag) { AOM_ask_value_strings(changeTag, "zt2_SZVersionbefore", &verBefNo, &versionBefs); AOM_ask_value_strings(changeTag, "zt2_ChangeAfter1", &aftNo, &changeAfts); AOM_ask_value_strings(changeTag, "zt2_SZRevisedversion", &aftVerNo, &versionAfts); + AOM_ask_value_strings(changeTag, PROP_PRODUCT, &prodNct, &products); AOM_ask_value_strings(changeTag, "zt2_ChangeReason", &reasonNo, &changeReasons); AOM_ask_value_strings(changeTag, "zt2_ProcessType1", &processTypeNo, &processTypes); cJSON* infomations = cJSON_CreateArray(); @@ -50,20 +91,105 @@ cJSON* getDrawingInform(tag_t changeTag) { cJSON_AddStringToObject(infomation, "S_PreChangeVersion", verBefNo > i ? versionBefs[i] : ""); cJSON_AddStringToObject(infomation, "S_AfterChange", aftNo > i ? changeAfts[i] : ""); cJSON_AddStringToObject(infomation, "S_AfterChangeVersion", aftVerNo > i ? versionAfts[i] : ""); + cJSON_AddStringToObject(infomation, JSON_TXDJ, prodNct > i ? products[i] : ""); cJSON_AddStringToObject(infomation, "S_ChangeReason", reasonNo > i ? changeReasons[i] : ""); cJSON_AddStringToObject(infomation, "S_ZZPCL", processTypeNo > i ? processTypes[i] : ""); cJSON_AddItemToArray(infomations, infomation); } return infomations; } - +cJSON* getEHDepart(string ecnCode,string section,string &uuid) { + + string searchSql = "SELECT \"actionstatement\",\"result\",\"pctime\",\"remark\",\"principal\" FROM CHINT_ECN_NOTIFICATION where \"ecncode\" = '%s' and \"section\" = '%s' order by \"no\""; + char selectRecord2[400]; + sprintf(selectRecord2, searchSql.c_str(), ecnCode.c_str(), section); + int outputColumn1 = 0, outputValueCount1 = 0; + char*** outputValue1 = NULL; + printf("selectRecord2 ===> %s\n", selectRecord2); + QuerySQLNoInputParam(selectRecord2, &outputColumn1, &outputValueCount1, &outputValue1); + cJSON* infomations = cJSON_CreateArray(); + for (int i = 0; i < outputValueCount1; i++) { + cJSON* infomation = cJSON_CreateObject(); + if (i == 0) { + vector uuidVec; + Split(outputValue1[i][4],";", uuidVec); + if (uuidVec.size() > 1 && strstr(uuidVec[1].c_str(),"null") == NULL) { + uuid = uuidVec[1]; + } + } + cJSON_AddStringToObject(infomation, "S_JSBaction", outputValue1[i][0]); + cJSON_AddStringToObject(infomation, "S_PD", outputValue1[i][1]); + cJSON_AddStringToObject(infomation, "T_PlanTime", outputValue1[i][2]); + cJSON_AddStringToObject(infomation, "S_Remark", outputValue1[i][3]); + cJSON_AddItemToArray(infomations, infomation); + } + return infomations; +} +//上传文件到minio +string uploadMinio(string jarName, string logPath) { + char cmd[256] = ""; + strcpy(cmd, "java -jar \""); + //strcat(cmd, jar_file); + strcat(cmd, getenv("TC_ROOT")); + strcat(cmd, "\\bin\\"); + strcat(cmd, jarName.c_str()); + strcat(cmd, "\" "); + string strResult; + strcat(cmd, logPath.c_str()); + char buf[8000] = { 0 }; + printf("路径:\n%s\n", cmd); + FILE* pf = NULL; + if ((pf = _popen(cmd, "r")) == NULL) { + printf("接口返回:\n%s", "1"); + } + while (fgets(buf, sizeof buf, pf)) { + strResult += buf; + } + _pclose(pf); + return strResult; + //return; +} +/* + 复制文件 +*/ +int file_xcopy_stod(const char* source_dir, const char* destination_dir) +{ + ifstream infile(source_dir, ios::in | ios::binary);//二进制形式打开 + if (infile.is_open() == 0) {//出错处理 + cout << "文件" << source_dir << "打开失败" << endl; + return -1; + } + ofstream outfile(destination_dir, ios::out | ios::binary);//二进制形式打开 + if (outfile.is_open() == 0) {//出错处理 + cout << "文件" << destination_dir << "打开失败" << endl; + infile.close();//记得关闭 + return -1; + } + //开始读写 + const int FLUSH_NUM = 1024 * 1024;//缓冲区大小设置为1M + char* ch = new(nothrow)char[FLUSH_NUM]; + if (ch == NULL) {//出错处理 + cout << "动态申请内存失败" << endl; + infile.close();//记得关闭 + outfile.close();//记得关闭 + return -1; + } + while (!infile.eof()) { + infile.read(ch, FLUSH_NUM); + outfile.write(ch, infile.gcount());//写入读入的成功个数 + } + delete[]ch;//记得释放 + infile.close();//记得关闭 + outfile.close();//记得关闭 + return 0; +} //变更对象发送到OA -int CHINT_task_complete(EPM_action_message_t msg) { +int CHINT_ECN_SendOA(EPM_action_message_t msg) { int ifail = ITK_ok; ECHO("=========================================================\n"); - ECHO("CHINT_task_complete 开始执行\n"); + ECHO("CHINT_ECN_SendOA 开始执行\n"); ECHO("=========================================================\n"); tag_t root_task = NULLTAG, *sub_tasks = NULL, current_task = NULLTAG, type_tag = NULLTAG; int sub_task_count = 0, occur_of_counts = 0; @@ -76,19 +202,35 @@ int CHINT_task_complete(EPM_action_message_t msg) { EPM_ask_sub_tasks(root_task, &sub_task_count, &sub_tasks); EPM_ask_attachments(root_task, EPM_target_attachment, &occur_of_counts, &taskAttches); //获取url地址 - char* url; + char* url, *userId, *urlId;// PREF_ask_char_value("CHINT_ECNSendOAUrl", 0, &url); + PREF_ask_char_value("CHINT_OAUserID_RUL", 0, &urlId); + char* log_file = NULL; + CreateLogFile("CHINT_ECN_SendOA", &log_file); // //获取当前流程目标 connectSql(); + POM_get_user_id(&userId); + string email = userId; + email.append("@chint.com"); + string userXML = getUserIdOA(email, urlId); + //获取登陆组 + tag_t group; + char *groupName, *taskUid; + POM_ask_group(&groupName, &group); + AOM_ask_value_string(group, PROP_GROUP_NAME, &groupName); + string userCode = readXmlId(userXML); + ITK__convert_tag_to_uid(msg.task, &taskUid); //流程uid for (int count = 0; count < occur_of_counts; count++) { char *type; tag_t taskTag = taskAttches[count]; AOM_ask_value_string(taskTag, "object_type", &type); if (strcmp(type, "ZT2_Change") == 0) { //获取属性 查询数据库填写JSON - char* changeType,*productModel, - *productName, *fileName, *contractNo, *contractName, - *changeDateStr, *changeUnit; + int unitCnt, processCnt = 0; + char* changeType, *productModel, + *productName, *fileName, *contractNo, *contractName, + *changeDateStr, **changeUnits, *itemId, *changeRequestNo, **processTypes; + AOM_ask_value_string(taskTag, "item_id", &itemId); date_t changeDate; AOM_ask_value_string(taskTag, "zt2_ChangeType", &changeType);//变更类型 AOM_ask_value_string(taskTag, "zt2_ProductModel", &productModel);//产品型号 @@ -97,10 +239,35 @@ int CHINT_task_complete(EPM_action_message_t msg) { AOM_ask_value_string(taskTag, "zt2_ContractNo", &contractNo); // 合同代号 AOM_ask_value_string(taskTag, "zt2_ContractName", &contractName); // 合同名称 AOM_ask_value_date(taskTag, "zt2_ChangeDate", &changeDate); // 变更实施日期 - AOM_ask_value_string(taskTag, "zt2_ChangeUnit1", &changeUnit); // 合同名称 + AOM_ask_value_strings(taskTag, "zt2_ChangeUnit1",&unitCnt, &changeUnits); // 合同名称 + AOM_ask_value_string(taskTag, "zt2_ChangRequestNo", &changeRequestNo); // 更改通知单号 + AOM_ask_value_strings(taskTag, PROP_PROCESS, &processCnt, &processTypes); cJSON* paramValue = cJSON_CreateObject(); //json添加字段 - cJSON_AddStringToObject(paramValue, "S_ChangeTypes", changeType); + /*S_ProductFeature 产品特性 字符串 A; B; C + S_GCFeeature 过程特性 字符串 A; B; C*/ + cJSON_AddStringToObject(paramValue, S_GCDM, groupName);//工厂 + cJSON_AddStringToObject(paramValue, "S_ChangeCode", itemId);//更改申请单号 + cJSON_AddStringToObject(paramValue, "S_PLMCode", taskUid); + cJSON_AddStringToObject(paramValue, "S_ChangeNotificationCode", changeRequestNo); + string productFeature, changeTypeStr; + if (processCnt > 0) { + char *type = processTypes[0]; + if (strcmp(type, "Y") == 0) { + productFeature = S_Product; + } + else { + productFeature = S_Process; + } + } + if (strstr(changeType, S_ZSChange) != NULL) { + changeTypeStr = S_ZSChange; + } + else { + changeTypeStr = S_LSChange; + } + cJSON_AddStringToObject(paramValue, "S_ProductFeature", productFeature.c_str()); + cJSON_AddStringToObject(paramValue, "S_ChangeTypes", changeTypeStr.c_str()); cJSON_AddStringToObject(paramValue, "S_ProductNumber", productModel); cJSON_AddStringToObject(paramValue, "S_ProductName", productName); cJSON_AddStringToObject(paramValue, "S_Pcodename", fileName); @@ -108,16 +275,57 @@ int CHINT_task_complete(EPM_action_message_t msg) { cJSON_AddStringToObject(paramValue, "S_ContractName", contractName); DATE_date_to_string(changeDate, "%Y-%m-%d", &changeDateStr); cJSON_AddStringToObject(paramValue, "T_MaterialDate", changeDateStr); - cJSON_AddStringToObject(paramValue, "S_FFBM", changeUnit); + cJSON_AddStringToObject(paramValue, "S_FFBM", changeUnits[0]); //EH_DrawingInformation图样信息 cJSON* infomations = getDrawingInform(taskTag); cJSON_AddItemToObject(paramValue, "EH_DrawingInformation", infomations); + string jsbUUid = "", gybUUid = "", zlbUUid = "", + scbUUid = "", cgbUUid = "", xszxUUid = "", cwbUUid = ""; + cJSON* jsbZx = getEHDepart(itemId, "技术部", jsbUUid); + cJSON_AddItemToObject(paramValue, "EH_JSBZX", jsbZx); + cJSON* gybZx = getEHDepart(itemId, "工艺部", gybUUid); + cJSON_AddItemToObject(paramValue, "EH_GYBZX", gybZx); + cJSON* zlbZx = getEHDepart(itemId, "质量部", zlbUUid); + cJSON_AddItemToObject(paramValue, "EH_ZLBZX", zlbZx); + cJSON* scbZx = getEHDepart(itemId, "生产部", scbUUid); + cJSON_AddItemToObject(paramValue, "EH_SCBZX", scbZx); + cJSON* cgbZx = getEHDepart(itemId, "采购部", cgbUUid); + cJSON_AddItemToObject(paramValue, "EH_CGBZX", cgbZx); + cJSON* saleCenter = getEHDepart(itemId, "销售中心", xszxUUid); + cJSON_AddItemToObject(paramValue, "EH_XSZXZX", saleCenter); + cJSON* cwbZx = getEHDepart(itemId, "财务部", cwbUUid); + cJSON_AddItemToObject(paramValue, "EH_CWBZX", cwbZx); + cJSON_AddStringToObject(paramValue, "S_JSBZRR", jsbUUid.c_str()); + cJSON_AddStringToObject(paramValue, "S_GYBZRR", gybUUid.c_str()); + cJSON_AddStringToObject(paramValue, "S_ZLBZRR", zlbUUid.c_str()); + cJSON_AddStringToObject(paramValue, "S_SCBZRR", scbUUid.c_str()); + cJSON_AddStringToObject(paramValue, "S_CGBZRR", cgbUUid.c_str()); + cJSON_AddStringToObject(paramValue, "S_XSZXZRR", xszxUUid.c_str()); + cJSON_AddStringToObject(paramValue, "S_CWBZRR", cwbUUid.c_str()); + char *json_to_char = cJSON_Print(paramValue); + string returnMsg = ecnSendOA(userCode.c_str(), json_to_char, url); + WriteLog("组织之后的JSON\n %s\n", json_to_char); + WriteLog("回传信息\n %s\n", returnMsg.c_str()); + if (!returnMsg.empty()) { + EMH_store_error_s1(EMH_severity_user_error, EMH_USER_error_base, returnMsg.c_str()); + } } } closeConn(); - // - + CloseLog(); + //string str = uploadMinio("uploadMinio.jar", log_file); + char date_string[MAX_PATH_LENGTHE], logFileName[MAX_PATH_LENGTHE];; + time_t now; + struct tm *p; + time(&now); + //current_time(&status_now); + p = localtime(&now); + memset(date_string, 0, sizeof(date_string)); + sprintf(date_string, "%4d%02d%02d%02d%02d%02d", 1900 + p->tm_year, p->tm_mon + 1, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec); + sprintf(logFileName, "%s\\%s_%s.log", LOG_PATH, taskUid, date_string); + file_xcopy_stod(log_file, logFileName); + //printf("str %s \n", str.c_str()); return ifail; } \ No newline at end of file diff --git a/General/General/CHINT_SendOAMaterial.cpp b/General/General/CHINT_SendOAMaterial.cpp index f722434..d745ab8 100644 --- a/General/General/CHINT_SendOAMaterial.cpp +++ b/General/General/CHINT_SendOAMaterial.cpp @@ -68,7 +68,7 @@ int CHINT_SendOAMaterial(EPM_action_message_t msg) { int att_cnt = 0, rev_count = 0; tag_t rootTask_tag = NULLTAG; tag_t* attachments = NULL, - * rev_tags = NULL; + *rev_tags = NULL; char* objtype = NULL; time_t timep; @@ -117,6 +117,35 @@ int CHINT_SendOAMaterial(EPM_action_message_t msg) { } + + //修改数据库状态 + int url_num = 0; + char** url_vals = NULL; + PREF_ask_char_values("database_tc", &url_num, &url_vals); + string urlSql = url_vals[0]; + urlSql.append("/").append(url_vals[2]); + string errorBuff; + //map %s \n", urlSql.c_str()); + if (ConnServer(url_vals[3], url_vals[4], (char*)urlSql.c_str()) == -1) + { + printf("提示:中间数据表访问失败\n"); + //ifail = 1; + } + char sql5[1024] = "\0"; + sprintf(sql5, "update \"CHINT_ FROCK\" set STATE = '%s' where instanceId = '%s'", "设计中", zt2_formnumber); + printf("提示:sql5==%s\n", sql5); + if (ExecuteSQLNoInputParam(sql5) == -1) + { + printf("提示:数据插入 失败, %s \n", sql5); + return 1; + } + else { + ExecuteSQLNoInputParam("commit"); + } + + + WriteLog("item_id->%s", cPCode); WriteLog("zt2_formnumber->%s", zt2_formnumber); WriteLog("zt2_MaterialNo->%s", zt2_MaterialNo); @@ -144,6 +173,20 @@ int CHINT_SendOAMaterial(EPM_action_message_t msg) { ifail = 1; } + else { + //接口传递成功 + char sql[1024] = "\0"; + sprintf(sql, "update \"CHINT_ FROCK\" set STATE = '%s' where instanceId = '%s'", "已完成", zt2_formnumber); + printf("提示:sql==%s\n", sql); + if (ExecuteSQLNoInputParam(sql) == -1) + { + printf("提示:数据插入 失败, %s \n", sql); + return 1; + } + else { + ExecuteSQLNoInputParam("commit"); + } + } } CloseLog(); return ifail; diff --git a/General/General/CRUL_server_call_httpserver.cpp b/General/General/CRUL_server_call_httpserver.cpp index 33da4b8..67d9368 100644 --- a/General/General/CRUL_server_call_httpserver.cpp +++ b/General/General/CRUL_server_call_httpserver.cpp @@ -1,55 +1,17 @@ #include "CRUL_server_call_httpserver.h" -#include #include #include #include -//#define HTTP_HOST "localhost" -//#define HTTP_POST 9293 -//#include -//#include +#include"tinyxml2.h" +using namespace tinyxml2; size_t write_data(void* ptr, size_t size, size_t nmemb, void* stream) { string data((const char*)ptr, (size_t)size * nmemb); *((stringstream*)stream) << data << endl; return size * nmemb; } -//string callHttpserver(string signinfoJsonString,string url) -//{ -// CURL* curl; -// CURLcode res; -// curl = curl_easy_init(); -// printf("发送地址:%s\n", url); -// std::stringstream out; -// if (curl) { -// curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); -// curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); -// //curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); -// //curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https"); -// struct curl_slist* headers = NULL; -// headers = curl_slist_append(headers, "Accept-Charset: UTF-8"); -// headers = curl_slist_append(headers, "Content-Type: application/json;charset=UTF-8"); -// curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); -// // 设置接收数据的处理函数和存放变量 -// curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); -// curl_easy_setopt(curl, CURLOPT_WRITEDATA, &out); -// printf("发送内容:%s\n", signinfoJsonString.c_str()); -// //printf("data=>%s\n",signinfoJsonString.c_str()); -// const char* data = signinfoJsonString.c_str(); -// curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); -// curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); -// curl_easy_setopt(curl, CURLOPT_TIMEOUT, 20); -// res = curl_easy_perform(curl); -// -// if (res != 0) { -// string errMessage = curl_easy_strerror(res); -// } -// -// printf("返回值:%d\n", res); -// } -// string str_json = out.str(); -// curl_easy_cleanup(curl); -// printf("str_json===>%s\n", str_json.c_str()); -// return str_json; -//} + + + string callHttpserver(string signinfoJsonString, string url){ CURL *curl; CURLcode res; @@ -61,12 +23,12 @@ string callHttpserver(string signinfoJsonString, string url){ curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https"); struct curl_slist *headers = NULL; - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &out); headers = curl_slist_append(headers, "Content-Type: application/json"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); const char *data = signinfoJsonString.c_str(); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &out); res = curl_easy_perform(curl); if (res != 0) { string errMessage = curl_easy_strerror(res); @@ -155,6 +117,95 @@ string sendOA(string sfid, string instanceId, string entityParamValues, string u printf("return Msg===>%s\n", str_json.c_str()); return str_json; } +char* G2U(const char* gb2312) +{ + int len = MultiByteToWideChar(CP_ACP, 0, gb2312, -1, NULL, 0); + wchar_t* wstr = new wchar_t[len + 1]; + memset(wstr, 0, len + 1); + MultiByteToWideChar(CP_ACP, 0, gb2312, -1, wstr, len); + len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL); + char* str = new char[len + 1]; + memset(str, 0, len + 1); + WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL); + if (wstr) delete[] wstr; + return str; +} +char* U2G(const char* utf8) +{ + int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0); + wchar_t* wstr = new wchar_t[len + 1]; + memset(wstr, 0, len + 1); + MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wstr, len); + len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL); + char* str = new char[len + 1]; + memset(str, 0, len + 1); + WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, len, NULL, NULL); + if (wstr) delete[] wstr; + return str; +} +string readXmlId(string xmlMsg) { + printf("xmlMsg %s \n", xmlMsg.c_str()); + tinyxml2::XMLDocument doc; + doc.Parse(U2G(xmlMsg.c_str())); + tinyxml2::XMLElement* root = doc.RootElement(); + tinyxml2::XMLElement* typeEle = root->FirstChildElement("TYPE"); + tinyxml2::XMLElement* item = root->FirstChildElement("items"); + char * type = (char*)typeEle->GetText(); + if (strcmp(type, "S") == 0) { + printf("1111"); + tinyxml2::XMLElement* itemsCs = item->FirstChildElement("EH_HR_UserItems_CS"); + tinyxml2::XMLElement* code = itemsCs->FirstChildElement("Code"); + return code->GetText(); + } + return typeEle->GetText(); +} +/*获取用户ID +*/ +string getUserIdOA(string email, string url) { + CURL* curl; + CURLcode res; + std::stringstream out; + curl = curl_easy_init(); + if (curl) { + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https"); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &out); + struct curl_slist* headers = NULL; + headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded"); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); + string temp; //Email=string&Name=string %E9%82%B5%E9%AA%8F%E9%BD%90 + temp.append("Email=&Name=%E9%82%B5%E4%BF%8A%E9%BD%90");// .append("Email=").append("&Name=邵俊齐"); //.append(email) + printf("temp=%s\n", temp.c_str()); + const char* data = temp.c_str(); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + res = curl_easy_perform(curl); + //curl_easy_strerror + printf("temp=%d\n", res); + } + string str_json = out.str(); + curl_easy_cleanup(curl); + printf("return Msg===>%s\n", str_json.c_str()); + return str_json; +} +//解析OA的返回信息 +string readXmlMSG(string xmlMsg) { + printf("xmlMsg %s \n", xmlMsg.c_str()); + tinyxml2::XMLDocument doc; + doc.Parse(xmlMsg.c_str()); + tinyxml2::XMLElement* root = doc.RootElement(); + tinyxml2::XMLElement* succEle = root->FirstChildElement("Success");//传递状态 + tinyxml2::XMLElement* messageEle = root->FirstChildElement("Message");//错误原因 + string msg = ""; + if (strcmp(succEle->GetText(), "false") == 0) { + msg.append("更改通知单推送OA系统失败,请联系管理员处理,流程继续执行,错误原因: "); + msg.append(U2G(messageEle->GetText())); + } + return msg; +} /*变更通知单传递OA */ string ecnSendOA(string instanceId, string entityParamValues, string url) { @@ -175,7 +226,8 @@ string ecnSendOA(string instanceId, string entityParamValues, string url) { curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); string temp; temp.append("workflowCode=EH_TE_ChangeNotice").append("&userCode="). - append(instanceId).append("&finishStart=true").append("&entityParamValues=").append(entityParamValues); + append(instanceId).append("&finishStart=true").append("&entityParamValues="). + append(G2U(entityParamValues.c_str())); printf("temp=%s\n", temp.c_str()); const char* data = temp.c_str(); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); @@ -186,65 +238,54 @@ string ecnSendOA(string instanceId, string entityParamValues, string url) { string str_json = out.str(); curl_easy_cleanup(curl); printf("return Msg===>%s\n", str_json.c_str()); - return str_json; + string returnMsg = readXmlMSG(str_json); + + return returnMsg; } -//void callHttpserverDwgtopdf(string signinfoJsonString, char* HTTP_HOST) -//{ -// CURL* curl; -// CURLcode res; -// char httpUrl[1028] = "\0"; -// curl = curl_easy_init(); -// sprintf(httpUrl, "http://%s:%d/server/dwgtopdf", HTTP_HOST, HTTP_POST); -// if (curl) { -// curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); -// curl_easy_setopt(curl, CURLOPT_URL, httpUrl); -// //curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); -// //curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https"); -// struct curl_slist* headers = NULL; -// headers = curl_slist_append(headers, "Accept-Charset: GBK"); -// headers = curl_slist_append(headers, "Content-Type: application/json;charset=GBK"); -// curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); -// WriteLog("发送内容:%s\n", signinfoJsonString.c_str()); -//// printf("data=>%s\n", signinfoJsonString.c_str()); -// const char* data = signinfoJsonString.c_str(); -// curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); -// curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); -// curl_easy_setopt(curl, CURLOPT_TIMEOUT, 20); -// res = curl_easy_perform(curl); -// WriteLog("返回值:%d\n", res); -// -// } -// curl_easy_cleanup(curl); -//} -// -//void callHttpserverMail(string signinfoJsonString, char* HTTP_HOST) -//{ -// CURL* curl; -// CURLcode res; -// char httpUrl[4096] = "\0"; -// WriteLog("内容长度%d\n", signinfoJsonString.size()); -// curl = curl_easy_init(); -// sprintf(httpUrl, "http://%s:%d/server/sendmail", HTTP_HOST, HTTP_POST); -//// printf("call=>%s \n", httpUrl); -// WriteLog("发送的路径:%s\n", httpUrl); -// if (curl) { -// curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); -// curl_easy_setopt(curl, CURLOPT_URL, httpUrl); -// //curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); -// //curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https"); -// struct curl_slist* headers = NULL; -// headers = curl_slist_append(headers, "Accept-Charset: GBK"); -// headers = curl_slist_append(headers, "Content-Type: application/json;charset=GBK"); -// curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); -//// curl_easy_setopt(curl, CURLOPT_HTTPHEADER, "Expect:"); -// WriteLog("发送内容:%s\n", signinfoJsonString.c_str()); -// // printf("data=>%s\n", signinfoJsonString.c_str()); -// const char* data = signinfoJsonString.c_str(); -// curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); -// curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10); -// curl_easy_setopt(curl, CURLOPT_TIMEOUT, 20); -// res = curl_easy_perform(curl); -// WriteLog("返回值:%d\n", res); -// } -// curl_easy_cleanup(curl); -//} \ No newline at end of file +/*调用云派接口获取项目的指派人 +*/ +string getAssignFromYP(string url) { + CURL* curl; + CURLcode res; + std::stringstream out; + curl = curl_easy_init(); + if (curl) { + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET"); + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https"); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &out); + struct curl_slist* headers = NULL; + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + res = curl_easy_perform(curl); + printf("temp=%d\n", res); + } + string str_json = out.str(); + curl_easy_cleanup(curl); + return U2G(str_json.c_str()); +} + +void updatePiProject(string json,string url) { + CURL *curl; + CURLcode res; + curl = curl_easy_init(); + std::stringstream out; + if (curl) { + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https"); + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers, "Content-Type: application/json"); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + const char *data = G2U(json.c_str()); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &out); + res = curl_easy_perform(curl); + } + string str_json = out.str(); + curl_easy_cleanup(curl); + printf("str_json===>%s\n", str_json.c_str()); +} \ No newline at end of file diff --git a/General/General/CRUL_server_call_httpserver.h b/General/General/CRUL_server_call_httpserver.h index 656a52d..e9bfa53 100644 --- a/General/General/CRUL_server_call_httpserver.h +++ b/General/General/CRUL_server_call_httpserver.h @@ -5,4 +5,8 @@ using namespace std; string callHttpserver(string signinfoJsonString, string url); string callHttpGet(string url); string sendOA(string sfid, string instanceId, string entityParamValues, string url); -string ecnSendOA(string instanceId, string entityParamValues, string url); \ No newline at end of file +string ecnSendOA(string instanceId, string entityParamValues, string url); +string readXmlId(string xmlMsg); +string getUserIdOA(string email, string url); +string getAssignFromYP(string url); +void updatePiProject(string json, string url); \ No newline at end of file diff --git a/General/General/Check_range.cpp b/General/General/Check_range.cpp index 86ff21e..7641249 100644 --- a/General/General/Check_range.cpp +++ b/General/General/Check_range.cpp @@ -77,9 +77,10 @@ time_t getTimeStamp() string callHttpserver2(string jsonStr,string jarName) { - char date[128] = ""; + time_t now = time(0); tm* p = localtime(&now); + char date[128] = ""; sprintf_s(date, "%04d%02d%02d%02d%02d%02d", 1900 + p->tm_year, p->tm_mon + 1, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec); //把数据用写入文件 diff --git a/General/General/CloneProcess.cpp b/General/General/CloneProcess.cpp index 08b0ea7..62e063d 100644 --- a/General/General/CloneProcess.cpp +++ b/General/General/CloneProcess.cpp @@ -502,6 +502,51 @@ void getGxbmMap(tag_t processTag, map& gxDocMap, map 0) { + ITKCALL(AOM_set_value_tags(newGx, relation, n_found, tags)); + } + return tags; +} +//根据数据库获取ID 2023/12/19 新增逻辑 +void queryProcessRule(char *windWay, boolean isXq, char *processCode, tag_t &newGx) { + + char selectGyId[200]; //根据工厂M060 二级工序编码 绕线方式(线圈) 获取工时信息 + if (isXq) { + string sqlRuleId = "select \"processroutefiles\",\"esopfiles\" from CHINT_PROCESS_SOP_RULE where \"companycode\" = 'M060' and \"windway\" = '%s' and \"gxcode\" = '%s' "; + sprintf(selectGyId, sqlRuleId.c_str(), windWay, processCode); + } + else { + string sqlRuleId = "select \"processroutefiles\",\"esopfiles\" from CHINT_PROCESS_SOP_RULE where \"companycode\" = 'M060' and \"gxcode\" = '%s' "; + sprintf(selectGyId, sqlRuleId.c_str(), processCode); + } + printf("selectGyId %s \n", selectGyId); + int outputColumn3 = 0, outputValueCount3 = 0; + char*** outputValue3 = NULL; + QuerySQLNoInputParam(selectGyId, &outputColumn3, &outputValueCount3, &outputValue3); + printf("outputValueCount3 %d \n", outputValueCount3); + string processIds, esopIds; + for (int j = 0; j < outputValueCount3; j++) { + char* processId = outputValue3[j][0]; + char* esopId = outputValue3[j][1]; + if (strcmp(processId, "") != 0) { + processIds.append(processId).append(";"); + } + if (strcmp(esopId, "") != 0) { + esopIds.append(esopId).append(";"); + } + } + queryItem((char*)processIds.c_str(), newGx,"ZT2_ProcessRuleRelation"); + queryItem((char*)esopIds.c_str(), newGx, "ZT2_ProcGuidBookRelation"); +} + tag_t clone_process_from_template(char* process_item_id, boolean isXq, string productZu, string xqfs,string th, string lastId) { tag_t item_tag = NULLTAG; @@ -575,14 +620,14 @@ tag_t clone_process_from_template(char* process_item_id, boolean isXq, string pr updateTemGxCode(clone_tag, temGxMap); } //if (!isXq) { - map tmpProcessMap; + map tmpProcessMap; //存放的是二级工序编码对应的二级工序版本 模板的 //vector timeVec; //工艺模板 map beanMap; //根据数据库配置修改工时 getGxbmMap(revision_tag, tmpProcessMap, beanMap); - map newProcessMap; - char selectGyId[200]; + map newProcessMap;//存放的是二级工序编码对应的二级工序版本 克隆出来的 + char selectGyId[200]; //根据产品族 模板id 绕线方式(线圈) 获取工时信息 if (isXq) { sprintf(selectGyId, sqlGxTime2.c_str(), productZu.c_str(), process_item_id, xqfs.c_str()); } @@ -594,7 +639,7 @@ tag_t clone_process_from_template(char* process_item_id, boolean isXq, string pr string gyId; printf("search3 ===> %s\n", selectGyId); QuerySQLNoInputParam(selectGyId, &outputColumn1, &outputValueCount1, &outputValue1); - //查询结果 + //查询结果 四种工时 for (int num = 0; num < outputValueCount1; num++) { string gxbm = outputValue1[num][0]; string rgsj = outputValue1[num][1]; @@ -635,6 +680,7 @@ tag_t clone_process_from_template(char* process_item_id, boolean isXq, string pr if (ret) { searchTh = "1ZDB5**000X"; } + //查询二级工序编码的信息,更新克隆出来的BOM的工序编码 string sqlFl = "select \"materialno\",\"EJBM\",\"quantity\",\"xuhao\" from CHINT_GYFL_001 where \"ProductZu\" = '%s' and \"TuHao\" ='%s' and \"quantity\" !='/' ORDER BY CAST(\"xuhao\" AS DECIMAL) asc"; char selectFlId[600]; sprintf(selectFlId, sqlFl.c_str(), productZu.c_str(), searchTh); @@ -668,8 +714,8 @@ tag_t clone_process_from_template(char* process_item_id, boolean isXq, string pr getGxbmMap(clone_tag, newProcessMap, beanMap, flBeanMap,th, lastId); map::iterator it; - //复制“工艺守则”、“工序作业指导书” - for (it = tmpProcessMap.begin(); it != tmpProcessMap.end(); it++) { + //复制“工艺守则”、“工序作业指导书” 旧逻辑 + /*for (it = tmpProcessMap.begin(); it != tmpProcessMap.end(); it++) { string gxbm = it->first; tag_t tmpGx = it->second; if (newProcessMap.count(gxbm) != 0) { @@ -688,6 +734,31 @@ tag_t clone_process_from_template(char* process_item_id, boolean isXq, string pr AOM_save(newGx); AOM_unlock(newGx); } + }*/ + //复制“工艺守则”、“工序作业指导书” 2023/12/19新增逻辑 CHINT_PROCESS_SOP_RULE 表中查询 + for (it = newProcessMap.begin(); it != newProcessMap.end(); it++) { + string gxbm = it->first; + tag_t newGx = it->second; + queryProcessRule((char*)xqfs.c_str(), isXq, (char*)gxbm.c_str(), newGx); + /*if (newProcessMap.count(gxbm) != 0) { + tag_t* procGuidBooks, *processRules; + int cnt2 = 0, cnt3 = 0; + if (isXq) { + sprintf(selectGyId, sqlGxTime2.c_str(), productZu.c_str(), process_item_id, xqfs.c_str()); + } + tag_t newGx = newProcessMap[gxbm]; + ITKCALL(AOM_ask_value_tags(tmpGx, "ZT2_ProcGuidBookRelation", &cnt2, &procGuidBooks)); + ITKCALL(AOM_ask_value_tags(tmpGx, "ZT2_ProcessRuleRelation", &cnt3, &processRules)); + AOM_lock(newGx); + if (cnt2 > 0) { + ITKCALL(AOM_set_value_tags(newGx, "ZT2_ProcGuidBookRelation", cnt2, procGuidBooks)); + } + if (cnt3 > 0) { + ITKCALL(AOM_set_value_tags(newGx, "ZT2_ProcessRuleRelation", cnt3, processRules)); + } + AOM_save(newGx); + AOM_unlock(newGx); + }*/ } //} return clone_tag; diff --git a/General/General/DtoEBOM2.cpp b/General/General/DtoEBOM2.cpp index e69de29..70362f2 100644 --- a/General/General/DtoEBOM2.cpp +++ b/General/General/DtoEBOM2.cpp @@ -0,0 +1,1682 @@ +#include +#include +#include +#include "epm_handler_common.h" +#include "ado.h" +#include +#include +#include +#include +#include +#include "ps/ps.h"; +#include "ps/vrule.h" +#include "sstream" +#include +#include "epm/epm.h" +#include "sa/sa.h" +#include "libxl.h" +#include +#include "epm/signoff.h" +#include +#include +#include +#include +#include "ae/dataset.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// #include "hx_custom.h" +#include +#include "tc_log.h" +// #include "jk_custom.h" +#include "chint_Handler.h" +#include "tc_util.h" +#include "ocilib.h" +struct NodeBean +{ + int topNum = 1; + int packNum = 0; //打包信息 + string revUid; //物料信息 + tag_t designRev; //图纸信息 + tag_t mantr = NULLTAG; + string bl_quantity; //数量 + char* bl_plmxml_occ_xform; //BOM属性 + string bl_sequence_no; // 查找编号 + vector childs;//子件 + vector ccps;//产成品 + int xnNum = 1;//虚拟件数量累乘 + boolean isOutBuy = false;//记录是否外购、或者权限不是自己的 +}; +bool isTcm(tag_t mantr) { + int releaseCount = 0; + tag_t* releaseTags = NULL; + //判断子件是否发布 + AOM_ask_value_tags(mantr, "release_status_list", &releaseCount, &releaseTags); + if (releaseCount > 0) { + return true; + } + else { + return false; + } +} +//判断物料的BOM视图有没有发布 +bool isBomViewTcm(tag_t mantr) { + int structs = 0; + tag_t *structure_revisions; + //版本有BOM视图且发布 + AOM_ask_value_tags(mantr, "structure_revisions", &structs, &structure_revisions); + if (structs > 0) { + return isTcm(structure_revisions[0]); + } + else { + return false; + } +} +bool myCompare(string o1, string o2) { + if (o1.rfind("3", 0) == 0) { + cout << o1.c_str() << endl; + return 1; + } + return 0; +} +vector KeySet(map test) +{ + vector keys; + for (map::iterator it = test.begin(); it != test.end(); ++it) { + keys.push_back(it->first); + } + return keys; +} +string& replace_all2(string& str, const string& old_value, const string& new_value) +{ + if (strstr(str.c_str(), old_value.c_str()) != NULL) { + vector type_vec; + Split(str.c_str(), old_value.c_str(), type_vec); + char new_str[512] = "\0"; + for (int i = 0; i < type_vec.size(); i++) + { + strcat(new_str, type_vec[i].c_str()); + if (i < type_vec.size() - 1) { + strcat(new_str, new_value.c_str()); + } + } + string new_value(new_str); + str = new_value.c_str(); + } + return str; +} +tag_t getSapPart(tag_t designRevLine, tag_t designRev, string& errBuff, NodeBean& bean) { + int num = 0; + tag_t* mantrs; + char *type, *item_id; + AOM_ask_value_string(designRev, "object_type", &type); + AOM_ask_value_string(designRev, "item_id", &item_id); + if (strcmp(type, "Part Revision") == 0) { + return designRev; + } + ITKCALL(AOM_ask_value_tags(designRev, "representation_for", &num, &mantrs)); + + //新增逻辑 获取图纸下最新版本的E物料对象 会存在多个版本的 + + vector parts; + if (strstr(item_id, "1ZDB300000P") != NULL) { + map partsCcp; + for (int i = 0; i < num; i++) { + char* type, *zt2_ifpbom, *itemId; + AOM_ask_value_string(mantrs[i], "object_type", &type); + AOM_ask_value_string(mantrs[i], "zt2_ifpbom", &zt2_ifpbom); + AOM_ask_value_string(mantrs[i], "item_id", &itemId); + if (strstr(type, "Part") != NULL && strcmp(zt2_ifpbom, "P") != 0) { // + tag_t matnrItem; + ITEM_ask_item_of_rev(mantrs[i], &matnrItem); + partsCcp[itemId] = matnrItem; + } + } + map::iterator it; + for (it = partsCcp.begin(); it != partsCcp.end(); it++) { + string s = it->first; + tag_t partLast = partsCcp[s], partRevLast; + ITEM_ask_latest_rev(partLast, &partRevLast); + if (parts.size() == 0) { + parts.push_back(partRevLast); + } + else { + printf("===========\n"); + bean.ccps.push_back(partRevLast); + } + } + } + else { + map partsCcp; + for (int i = 0; i < num; i++) { + char* type, *zt2_ifpbom, *itemId; + AOM_ask_value_string(mantrs[i], "object_type", &type); + AOM_ask_value_string(mantrs[i], "zt2_ifpbom", &zt2_ifpbom); + AOM_ask_value_string(mantrs[i], "item_id", &itemId); + if (strstr(type, "Part") != NULL && strcmp(zt2_ifpbom, "P") != 0) { // + tag_t matnrItem; + ITEM_ask_item_of_rev(mantrs[i], &matnrItem); + partsCcp[itemId] = matnrItem; + } + } + map::iterator it; + for (it = partsCcp.begin(); it != partsCcp.end(); it++) { + string s = it->first; + tag_t partLast = partsCcp[s], partRevLast; + ITEM_ask_latest_rev(partLast, &partRevLast); + if (parts.size() == 0) { + parts.push_back(partRevLast); + } + } + //for (int i = 0; i < num; i++) { + // char* type, *zt2_ifpbom; + // AOM_ask_value_string(mantrs[i], "object_type", &type); + // AOM_ask_value_string(mantrs[i], "zt2_ifpbom", &zt2_ifpbom); + // if (strstr(type, "Part") != NULL && strcmp(zt2_ifpbom, "P") != 0) { // + // tag_t matnrItem, partRevLast; + // ITEM_ask_item_of_rev(mantrs[i], &matnrItem); + // ITEM_ask_latest_rev(matnrItem, &partRevLast); + // parts.push_back(partRevLast); + // } + //} + } + if (parts.size() == 1) { + return parts[0]; + } + string searchId; + char* id, *zt2_TYJNo, *spec, *zt2_Diagram; + AOM_ask_value_string(designRev, "zt2_Diagram", &zt2_Diagram); + AOM_ask_value_string(designRev, "item_id", &id); + //AOM_ask_value_string(designRev, "zt2_DrawingNo", &zt2_DrawingNo); + /*if (strcmp(zt2_DrawingNo,"") != 0 && strcmp(zt2_DrawingNo, id) != 0) { + searchId = zt2_DrawingNo; + } + else {*/ + searchId = id; + //} + AOM_ask_value_string(designRevLine, "ZT2_TYSpecifications", &zt2_TYJNo); + AOM_ask_value_string(designRev, "zt2_Specifications", &spec); + if (strcmp(zt2_TYJNo, "") != 0) { + string qryVal; + tag_t query = NULLTAG, *tags; + map map_revs; + qryVal.append("* ").append(zt2_TYJNo).append("*"); + //fields.put("描述", "*" + item_id + "*" + zt2_TYJNo + "*"); + ITKCALL(QRY_find2("chint_query_material_test", &query)); + char* qry_entries[2] = { "描述" ,"关联的图号" }, *qry_values[2] = { (char *)qryVal.c_str(),id }; + int n_found; + ITKCALL(QRY_execute(query, 2, qry_entries, qry_values, &n_found, &tags)); + printf("n_found===>%d\n", n_found); + for (int t = 0; t < n_found; t++) { + tag_t rev = tags[t]; + if (isTcm(rev)) { + char* zt2_MaterialNo; + AOM_ask_value_string(rev, "zt2_MaterialNo", &zt2_MaterialNo); + map_revs[zt2_MaterialNo] = rev; + } + } + vector keySet = KeySet(map_revs); + sort(keySet.begin(), keySet.end(), myCompare); + for (int i = 0; i < keySet.size(); i++) { + string materialNo = keySet[i]; + string sql_query = "select FeatureList from CcemVW_GoodsFeature where GoodsCode ='"; + sql_query.append(materialNo).append("'"); + printf("sql_query===>%s\n", sql_query.c_str()); + int outputColumn = 0, outputValueCount = 0; + char*** outputValue = NULL; + ado_QuerySQLNoInputParam((char*)sql_query.c_str(), &outputColumn, &outputValueCount, &outputValue); + for (int j = 0; j < outputValueCount; j++) { + char* val = outputValue[j][0]; + vector vals; + Split(val, ",", vals); + for (int k = 0; k < vals.size(); k++) { + printf("vals===>%s\n", vals[k].c_str()); + if (vals[k].rfind("F064:", 0) == 0) { + string temp = replace_all2(vals[k], "F064:", ""); + printf("temp===>%s\n", temp.c_str()); + if (strstr(zt2_TYJNo, temp.c_str()) != NULL) { + return map_revs[materialNo]; + } + break; + } + } + } + } + if (!strcmp(zt2_Diagram, "Y") == 0 && !strcmp(zt2_Diagram, "是") == 0) { + string buffErr = ""; + buffErr.append("缺少物料编码[找不到与通用件规格相匹配的物料-(*").append(searchId) + .append("*").append(zt2_TYJNo).append(")];\n"); + size_t found = errBuff.find(buffErr); + if (found == std::string::npos) { + errBuff.append(buffErr); + } + return NULLTAG; + } + } + + for (int i = 0; i < parts.size(); i++) { + tag_t part = parts[i]; + char* specPart; + AOM_ask_value_string(part, "zt2_Specifications", &specPart); + if (strcmp(specPart, spec) == 0) { + return part; + } + /*String spec2 = parts.get(i).getProperty("zt2_Specifications"); + if (spec.equals(spec2)) { + return parts.get(i); + }*/ + } + if (!strcmp(zt2_Diagram, "Y") == 0 && !strcmp(zt2_Diagram, "是") == 0) { + //errBuff.append("缺少物料编码[找不到相同规格的物料(").append(spec).append(")];"); + string buffErr = ""; + buffErr.append("缺少物料编码[找不到相同规格的物料(").append(spec).append(")];"); + size_t found = errBuff.find(buffErr); + if (found == std::string::npos) { + errBuff.append(buffErr); + } + return NULLTAG; + } + + return NULLTAG; + /*else{ + return NULLTAG; + }*/ +} + +/** + * 遍历DBOM + * @param bom_line DBOM的父级 + * @param bean 记录BOM结构 + * @param errBuff 记录错误信息 + * @param designRev 图纸版本 + * @param flagMat 是否外购 + */ +void askLineVal(NodeBean& bean, tag_t bom_line, tag_t designRev, string& errBuff, boolean &flagMat) { + char* bl_quantity, *bl_plmxml_occ_xform, *bl_sequence_no, *sffc; + ITKCALL(AOM_ask_value_string(bom_line, "bl_sequence_no", &bl_sequence_no)); + //printf("revUid===>%s\n", bl_sequence_no); + ITKCALL(AOM_ask_value_string(bom_line, "bl_quantity", &bl_quantity)); + //printf("revUid===>%s\n", bl_quantity); + ITKCALL(AOM_ask_value_string(bom_line, "bl_plmxml_occ_xform", &bl_plmxml_occ_xform)); + //printf("revUid===>%s\n", bl_plmxml_occ_xform); + if (strcmp(bl_quantity, "") == 0) { + bl_quantity = "1"; + } + + bean.bl_plmxml_occ_xform = bl_plmxml_occ_xform; + if (bean.xnNum > 1) { + int qtyCut = atoi(bl_quantity); + bean.bl_quantity = to_string(qtyCut*bean.xnNum); + } + else { + bean.bl_quantity = bl_quantity; + } + if (strcmp(bean.bl_sequence_no.c_str(), "") == 0) { + bean.bl_sequence_no = bl_sequence_no; + } + //根据图纸获取物料 包含通用件的逻辑 + tag_t part = getSapPart(bom_line, designRev, errBuff, bean); + //printf("11111111\n"); + if (part != NULLTAG) { + //BOM_writer + char* name, *partId, **sealeds, **factorys, *matnr, **procureType; + AOM_refresh(part, false); + AOM_ask_value_string(part, "object_name", &name); + printf("name%s\n", name); + int cnt2, numFac, cnt3; + //检查物料是否可用 + ITKCALL(AOM_ask_value_string(part, "item_id", &partId)); + AOM_ask_value_string(part, "zt2_MaterialNo", &matnr); + if (strcmp(matnr, "") == 0) { + string buffErr = ""; + buffErr.append("物料:").append(partId).append("/").append(name).append("没有物料编码.\n"); + size_t found = errBuff.find(buffErr); + if (found == std::string::npos) { + errBuff.append(buffErr); + } + //errBuff.append("物料:").append(partId).append("/").append(name).append("没有物料编码.\n"); + //return; + } + boolean numFlag = true; + AOM_ask_value_strings(part, "zt2_SZSealedornot", &cnt2, &sealeds); + AOM_ask_value_strings(part, "zt2_SZFactory", &numFac, &factorys); + AOM_ask_value_strings(part, "zt2_SZProcuretype", &cnt3, &procureType); //包含自制 + for (int i = 0; i < numFac; i++) { + if (strcmp(factorys[i], "M060") == 0) { + numFlag = false; + } + if (strcmp(factorys[i], "M060") == 0 && cnt2 > i) { + if (strcmp(sealeds[i], "Y") == 0) { + //errBuff.append("物料:").append(partId).append("/").append(name).append("已封存无法转换EBOM.\n"); + string buffErr = ""; + buffErr.append("物料:").append(partId).append("/").append(name).append("已封存无法转换EBOM.\n"); + size_t found = errBuff.find(buffErr); + if (found == std::string::npos) { + errBuff.append(buffErr); + } + } + if (cnt3 > i && strstr(procureType[i], "自制") != NULL) { + flagMat = true; + } + } + } + char*objName; + AOM_ask_value_string(part, OBJECT_NAME, &objName); + if (numFlag && strstr(objName, CCP_NAME) == NULL) {// || (strstr(partId,"2ZD")!=NULL|| strstr(partId, "4ZD") != NULL) + string buffErr = ""; + buffErr.append("物料:").append(partId).append("/").append(name).append("物料视图没有维护,请检查.\n"); + size_t found = errBuff.find(buffErr); + if (found == std::string::npos) { + errBuff.append(buffErr); + } + //errBuff.append("物料:").append(partId).append("/").append(name).append("物料视图没有维护,请检查.\n"); + } + ITKCALL(AOM_ask_value_string(part, "zt2_State", &sffc)); + if (strcmp(sffc, "D1") == 0 || strcmp(sffc, "封存") == 0) { + string buffErr = ""; + buffErr.append("物料:").append(partId).append("/").append(name).append("已封存无法转换EBOM.\n"); + size_t found = errBuff.find(buffErr); + if (found == std::string::npos) { + errBuff.append(buffErr); + } + } + bean.mantr = part; + } + else { + char *partId, *name; + AOM_ask_value_string(designRev, "item_id", &partId); + AOM_ask_value_string(designRev, "object_name", &name); + + string buffErr = ""; + buffErr.append("图纸:").append(partId).append("/").append(name).append("下未找到物料对象.\n"); + size_t found = errBuff.find(buffErr); + if (found == std::string::npos) { + errBuff.append(buffErr); + } + // errBuff.append("图纸:").append(partId).append("/").append(name).append("下未找到物料对象.\n"); + } +} +/** + * 获取通用件重量 + * @param bom_line DBOM + * @param materialutilization 材料利用率 + * @param errMessage 记录错误信息 + * @param desginRev 图纸版本 + */ +string getTyjZl(tag_t bom_line, string materialutilization, tag_t desginRev, string &errMessage) { + char *ZT2_TYSpecifications, *ZT2_TYWeight, *item_id; + AOM_ask_value_string(bom_line, "item_id", &item_id); + AOM_ask_value_string(bom_line, "ZT2_TYSpecifications", &ZT2_TYSpecifications); + double lyl = 0.85; + char strff[21]; + if (!materialutilization.empty()) { + lyl = stod(materialutilization); + } + if (strcmp(ZT2_TYSpecifications, "") == 0) { + double weight = 0; + AOM_ask_value_double(desginRev, "zt2_DesignWeight", &weight); + if (weight == 0) { + errMessage.append(item_id).append("未填写设计重量;\n"); + return "0"; + } + double two = weight / lyl; + sprintf(strff, "%.3f", two); + } + else { + AOM_ask_value_string(bom_line, "ZT2_TYWeight", &ZT2_TYWeight); + if (strcmp(ZT2_TYWeight, "") == 0) { + errMessage.append(item_id).append("未填写通用件重量;\n"); + return "0"; + } + double weight = stod(ZT2_TYWeight); + double two = weight / lyl; + sprintf(strff, "%.3f", two); + } + return strff; +} + +void getRemarkMsg(string remark, int len, string &errBuff, char*bl_quantity, char* pId, + char*c_pId, char*bl_line_name) { + char* idss[5] = { (char*)"A",(char*)"B",(char*)"C",(char*)"D",(char*)"E" }; + //tring x = "9A9.1B2C3"; + string markMsg = ""; + for (int i = 0; i < len; i++) { + if (strstr(remark.c_str(), idss[i]) != NULL) { + markMsg.append(idss[i]); + } + } + if (markMsg.length() == 0) { + int blQty = atoi(bl_quantity); + if (blQty % len != 0 + && strstr(bl_line_name, "线") == NULL) { + errBuff.append("图纸:").append(pId).append("下子件").append(c_pId) + .append("无法整除,请检查。").append("\n"); + } + } + else { + int blQty = atoi(bl_quantity); + if (blQty % markMsg.length() != 0 + && strstr(bl_line_name, "线") == NULL) { + errBuff.append("图纸:").append(pId).append("下子件").append(c_pId) + .append("无法整除,请检查。").append("\n"); + } + } +} + +int xsLen = 0; +void getAllXnj(vector xnzjbVec, int maxNum, int &xxt, + string& errBuff, string dbName, NodeBean& pBean, int qtyXn, char *loginUserId); +void getAllXnj(vector xnzjbVec, int maxNum, int &xxt, + string& errBuff, string dbName, NodeBean& pBean, int qtyXn, vector idVector); +/** + * 遍历DBOM + * @param bom_line DBOM的父级 + * @param pBean 记录BOM结构 + * @param errBuff 记录错误信息 + * @param dbName 原材料展开数据库信息 + * @param loginUserId 用户信息 + */ +void recyReadBom(tag_t bom_line, NodeBean& pBean, string& errBuff, string dbName, char *loginUserId) +{ + int c_line_count; + char* uid, *type, *zt2_Diagram, *source, *itemId, *object_name; + //图纸版本、子行 + tag_t designRev, *c_line_tags; + ITKCALL(AOM_ask_value_tag(bom_line, "bl_line_object", &designRev)); + //printf("1222"); + ITK__convert_tag_to_uid(designRev, &uid); + //printf("revUid===>%s\n", uid); + pBean.revUid = uid; + pBean.designRev = designRev; + ITKCALL(AOM_ask_value_string(designRev, "object_type", &type)); + ITKCALL(AOM_ask_value_string(designRev, "item_id", &itemId)); + ITKCALL(AOM_ask_value_string(designRev, "object_name", &object_name)); + //printf("type===>%s\n", type); + if (strcmp(type, "ZT2_Design3DRevision") == 0) { + AOM_ask_value_string(designRev, "zt2_Diagram", &zt2_Diagram); + if (strcmp(zt2_Diagram, "Y") == 0 || strcmp(zt2_Diagram, "是") == 0) { + return; + } + } + //判断类型是否为 Part Revision ZT2_Design3DRevision ZT2_XNZJB 不是报错 + if (strcmp(type, "ZT2_Design3DRevision") != 0 + && strcmp(type, "Part Revision") != 0 && strcmp(type, "ZT2_XNZJBRevision") != 0) { + string buffErr = ""; + buffErr.append("对象类型异常:").append(itemId).append("/").append(object_name).append("/").append(type).append("\n"); + size_t found = errBuff.find(buffErr); + if (found == std::string::npos) { + errBuff.append(buffErr); + } + return; + } + + boolean flagMat = false; + //根据图纸获取物料信息 + askLineVal(pBean, bom_line, designRev, errBuff, flagMat); + tag_t tagUser; + char *tagId; + AOM_ask_value_tag(designRev, "owning_user", &tagUser); + AOM_ask_value_string(tagUser, "user_id", &tagId); + //检查权限 + if (strcmp(type, "ZT2_Design3DRevision") == 0 && strcmp(loginUserId, tagId) != 0 && strstr(itemId, "2ZD") == NULL) { + pBean.isOutBuy = true; + return; + } + if (strcmp(type, "ZT2_XNZJBRevision") == 0) { + return; + } + //外购 不展开子件 + if (strstr(itemId, "2ZD") != NULL || strstr(itemId, "4ZD") != NULL) { + if (!flagMat) { + pBean.isOutBuy = true; + return; + } + } + if (strstr(itemId, "1ZD") != NULL) { + AOM_ask_value_string(designRev, "zt2_Source", &source); + if (strcmp(source, "S2") == 0 || strcmp(source, "外购") == 0) { + pBean.isOutBuy = true; + return; + } + } + + ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags)); + for (int i = 0; i < c_line_count; i++) { + logical flag; + BOM_line_is_packed(c_line_tags[i], &flag); + if (flag) { + BOM_line_unpack(c_line_tags[i]); + } + } + AOM_refresh(bom_line, FALSE); + ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags)); + //转换时原材料展开逻辑 + if (c_line_count == 0 && !dbName.empty() && (strstr(itemId, "1ZD") != NULL || + strstr(itemId, "2ZD") != NULL || strstr(itemId, "4ZD") != NULL)) { + //原材料展开 + char *zt2_MaterialMark; + AOM_ask_value_string(designRev, "zt2_MaterialMark", &zt2_MaterialMark); + //String zt2_MaterialMark = rev.getProperty("zt2_MaterialMark") + string sql = "select materialno, materialutilization, materialunit FROM %s where materialmark = '%s'"; + char selectRxfs[500]; + sprintf(selectRxfs, sql.c_str(), dbName.c_str(), zt2_MaterialMark); + int outputColumn1 = 0, outputValueCount1 = 0; + char*** outputValue1 = NULL; + printf("search3 ===> %s\n", selectRxfs); + QuerySQLNoInputParam(selectRxfs, &outputColumn1, &outputValueCount1, &outputValue1); + if (outputValueCount1 == 0 && strcmp(zt2_MaterialMark, "") != 0) { + string buffErr = ""; + buffErr.append("图纸:").append(itemId).append("-"). + append(object_name).append(zt2_MaterialMark).append("材料标记没有维护.\n"); + size_t found = errBuff.find(buffErr); + if (found == std::string::npos) { + errBuff.append(buffErr); + } + + } + for (int t = 0; t < outputValueCount1; t++) { + string materialno = outputValue1[t][0]; + string materialutilization = outputValue1[t][1]; + string materialunit = outputValue1[t][2]; + tag_t material, materialRev; + ITEM_find_item(materialno.c_str(), &material); + ITEM_ask_latest_rev(material, &materialRev); + string bl_qty = getTyjZl(bom_line, materialutilization, designRev, errBuff); + printf("bl_qty%s\n", bl_qty.c_str()); + NodeBean cBean; + cBean.bl_quantity = bl_qty; + cBean.bl_sequence_no = "10"; + cBean.bl_plmxml_occ_xform = ""; + cBean.mantr = materialRev; + pBean.childs.push_back(cBean); + } + } + string maxSeqNo; + vector xnzjbVec; + string item_id = itemId; + smatch result; + //检查是否线圈 + regex qq_reg2("^1ZDB5.*\\d{1,}1000X.*"); + bool ret = regex_match(item_id, result, qq_reg2); + for (int i = 0; i < c_line_count; i++) { + logical suppressed; + AOM_ask_value_logical(c_line_tags[i], "bl_is_occ_suppressed", &suppressed); + if (suppressed) { + continue; + } + //修改过之后之前已经是解包的状态了 + logical flag; + BOM_line_is_packed(c_line_tags[i], &flag); + //printf("flag===>%d\n", flag); + if (flag) { + int count = 0; + char *topNum; + AOM_ask_value_string(c_line_tags[i], "bl_quantity", &topNum); + tag_t* packLines; + BOM_line_ask_packed_lines(c_line_tags[i], &count, &packLines); + for (int t = 0; t < count; t++) { + tag_t c_Rev; + ITKCALL(AOM_ask_value_tag(packLines[t], "bl_line_object", &c_Rev)); + char* cUid; + ITK__convert_tag_to_uid(c_Rev, &cUid); + NodeBean cBean; + cBean.revUid = cUid; + cBean.designRev = c_Rev; + cBean.packNum = count + 1; + cBean.topNum = atoi(topNum); + recyReadBom(c_line_tags[i], cBean, errBuff, dbName, loginUserId); + pBean.childs.push_back(cBean); + } + AOM_refresh(c_line_tags[i], FALSE); + tag_t c_Rev; + ITKCALL(AOM_ask_value_tag(c_line_tags[i], "bl_line_object", &c_Rev)); + char* cUid; + ITK__convert_tag_to_uid(c_Rev, &cUid); + NodeBean cBean; + cBean.revUid = cUid; + cBean.designRev = c_Rev; + cBean.packNum = count + 1; + cBean.topNum = atoi(topNum); + recyReadBom(c_line_tags[i], cBean, errBuff, dbName, loginUserId); + pBean.childs.push_back(cBean); + + } + else { + //检查E转P时的拆分逻辑 + tag_t c_Rev; + char *seqNo, *c_type, *remark, *bl_quantity, *bl_line_name; + ITKCALL(AOM_ask_value_tag(c_line_tags[i], "bl_line_object", &c_Rev)); + char* id; + AOM_ask_value_string(c_Rev, "item_id", &id); + //获取BOM行的REMARK + if (ret) { + AOM_ask_value_string(c_line_tags[i], "ZT2_Remark", &remark); + AOM_ask_value_string(c_line_tags[i], "bl_quantity", &bl_quantity); + AOM_ask_value_string(c_line_tags[i], "bl_line_name", &bl_line_name); + getRemarkMsg(remark, xsLen, errBuff, bl_quantity, itemId, id, bl_line_name); + } + //新增逻辑 当前对象类型为ZT2_XNZJB 虚拟组件包时 进行削层处理 数量*虚拟层数量 + AOM_ask_value_string(c_Rev, "object_type", &c_type); + if (strcmp(c_type, "ZT2_XNZJBRevision") == 0) { + xnzjbVec.push_back(c_line_tags[i]); + continue; + } + AOM_ask_value_string(c_line_tags[i], "bl_sequence_no", &seqNo); + maxSeqNo = seqNo; + char* cUid; + ITK__convert_tag_to_uid(c_Rev, &cUid); + NodeBean cBean; + cBean.revUid = cUid; + cBean.designRev = c_Rev; + recyReadBom(c_line_tags[i], cBean, errBuff, dbName, loginUserId); + pBean.childs.push_back(cBean); + } + } + int maxNum = atoi(maxSeqNo.c_str()); + int xxt = 1; + printf("xnzjbVec ===> %d\n", xnzjbVec.size()); + //提取虚拟装配件的逻辑 + getAllXnj(xnzjbVec, maxNum, xxt, errBuff, dbName, pBean, 1, loginUserId); +} +/** + * DBOM转EBOM框架BOM使用 + * @param bom_line DBOM顶层 + * @param pBean 记录EBOM结构 + * @param errBuff 记录错误信息 + * @param dbName 原材料展开的数据表 + * @param idVector 需要D转E的BOM类别 + */ +void recyReadBom(tag_t bom_line, NodeBean& pBean, string& errBuff, string dbName, vector idVector) +{ + int c_line_count; + char* uid, *type, *zt2_Diagram, *source, *itemId, *object_name; + //图纸版本、子行 + tag_t designRev, *c_line_tags; + ITKCALL(AOM_ask_value_tag(bom_line, "bl_line_object", &designRev)); + //printf("1222"); + ITK__convert_tag_to_uid(designRev, &uid); + //printf("revUid===>%s\n", uid); + pBean.revUid = uid; + pBean.designRev = designRev; + ITKCALL(AOM_ask_value_string(designRev, "object_type", &type)); + ITKCALL(AOM_ask_value_string(designRev, "item_id", &itemId)); + ITKCALL(AOM_ask_value_string(designRev, "object_name", &object_name)); + //printf("type===>%s\n", type); + if (strcmp(type, "ZT2_Design3DRevision") == 0) { + AOM_ask_value_string(designRev, "zt2_Diagram", &zt2_Diagram); + if (strcmp(zt2_Diagram, "Y") == 0 || strcmp(zt2_Diagram, "是") == 0) { + return; + } + } + //判断类型是否为 Part Revision ZT2_Design3DRevision ZT2_XNZJB 不是报错 + if (strcmp(type, "ZT2_Design3DRevision") != 0 + && strcmp(type, "Part Revision") != 0 && strcmp(type, "ZT2_XNZJBRevision") != 0) { + string buffErr = ""; + buffErr.append("对象类型异常:").append(itemId).append("/").append(object_name).append("/").append(type).append("\n"); + size_t found = errBuff.find(buffErr); + if (found == std::string::npos) { + errBuff.append(buffErr); + } + return; + } + + boolean flagMat = false; + askLineVal(pBean, bom_line, designRev, errBuff, flagMat); + vector idVec; + Split(itemId, "-", idVec); + //未在首选项配置的类型不展开 + if (std::find(idVector.begin(), idVector.end(), idVec[0]) == idVector.end()) { + return; + } + if (strcmp(type, "ZT2_XNZJBRevision") == 0) { + return; + } + //外购 不展开子件 + if (strstr(itemId, "2ZD") != NULL || strstr(itemId, "4ZD") != NULL) { + if (!flagMat) { + return; + } + } + if (strstr(itemId, "1ZD") != NULL) { + AOM_ask_value_string(designRev, "zt2_Source", &source); + if (strcmp(source, "S2") == 0 || strcmp(source, "外购") == 0) { + return; + } + } + + ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags)); + for (int i = 0; i < c_line_count; i++) { + logical flag; + BOM_line_is_packed(c_line_tags[i], &flag); + if (flag) { + BOM_line_unpack(c_line_tags[i]); + } + } + AOM_refresh(bom_line, FALSE); + ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags)); + //转换时原材料展开逻辑 + if (c_line_count == 0 && !dbName.empty() && (strstr(itemId, "1ZD") != NULL || + strstr(itemId, "2ZD") != NULL || strstr(itemId, "4ZD") != NULL)) { + //原材料展开 + char *zt2_MaterialMark; + AOM_ask_value_string(designRev, "zt2_MaterialMark", &zt2_MaterialMark); + //String zt2_MaterialMark = rev.getProperty("zt2_MaterialMark") + string sql = "select materialno, materialutilization, materialunit FROM %s where materialmark = '%s'"; + char selectRxfs[500]; + sprintf(selectRxfs, sql.c_str(), dbName.c_str(), zt2_MaterialMark); + int outputColumn1 = 0, outputValueCount1 = 0; + char*** outputValue1 = NULL; + printf("search3 ===> %s\n", selectRxfs); + QuerySQLNoInputParam(selectRxfs, &outputColumn1, &outputValueCount1, &outputValue1); + if (outputValueCount1 == 0 && strcmp(zt2_MaterialMark, "") != 0) { + string buffErr = ""; + buffErr.append("图纸:").append(itemId).append("-"). + append(object_name).append(zt2_MaterialMark).append("材料标记没有维护.\n"); + size_t found = errBuff.find(buffErr); + if (found == std::string::npos) { + errBuff.append(buffErr); + } + + } + for (int t = 0; t < outputValueCount1; t++) { + string materialno = outputValue1[t][0]; + string materialutilization = outputValue1[t][1]; + string materialunit = outputValue1[t][2]; + tag_t material, materialRev; + ITEM_find_item(materialno.c_str(), &material); + ITEM_ask_latest_rev(material, &materialRev); + string bl_qty = getTyjZl(bom_line, materialutilization, designRev, errBuff); + printf("bl_qty%s\n", bl_qty.c_str()); + NodeBean cBean; + cBean.bl_quantity = bl_qty; + cBean.bl_sequence_no = "10"; + cBean.bl_plmxml_occ_xform = ""; + cBean.mantr = materialRev; + pBean.childs.push_back(cBean); + } + } + string maxSeqNo; + vector xnzjbVec; + for (int i = 0; i < c_line_count; i++) { + logical suppressed; + AOM_ask_value_logical(c_line_tags[i], "bl_is_occ_suppressed", &suppressed); + if (suppressed) { + continue; + } + //修改过之后之前已经是解包的状态了 + logical flag; + BOM_line_is_packed(c_line_tags[i], &flag); + //printf("flag===>%d\n", flag); + if (flag) { + int count = 0; + char *topNum; + AOM_ask_value_string(c_line_tags[i], "bl_quantity", &topNum); + tag_t* packLines; + BOM_line_ask_packed_lines(c_line_tags[i], &count, &packLines); + for (int t = 0; t < count; t++) { + tag_t c_Rev; + ITKCALL(AOM_ask_value_tag(packLines[t], "bl_line_object", &c_Rev)); + char* cUid; + ITK__convert_tag_to_uid(c_Rev, &cUid); + NodeBean cBean; + cBean.revUid = cUid; + cBean.designRev = c_Rev; + cBean.packNum = count + 1; + cBean.topNum = atoi(topNum); + recyReadBom(c_line_tags[i], cBean, errBuff, dbName, idVector); + pBean.childs.push_back(cBean); + } + AOM_refresh(c_line_tags[i], FALSE); + tag_t c_Rev; + ITKCALL(AOM_ask_value_tag(c_line_tags[i], "bl_line_object", &c_Rev)); + char* cUid; + ITK__convert_tag_to_uid(c_Rev, &cUid); + NodeBean cBean; + cBean.revUid = cUid; + cBean.designRev = c_Rev; + cBean.packNum = count + 1; + cBean.topNum = atoi(topNum); + recyReadBom(c_line_tags[i], cBean, errBuff, dbName, idVector); + pBean.childs.push_back(cBean); + + } + else { + tag_t c_Rev; + char *seqNo, *c_type; + ITKCALL(AOM_ask_value_tag(c_line_tags[i], "bl_line_object", &c_Rev)); + //新增逻辑 当前对象类型为ZT2_XNZJB 虚拟组件包时 进行削层处理 数量*虚拟层数量 + AOM_ask_value_string(c_Rev, "object_type", &c_type); + if (strcmp(c_type, "ZT2_XNZJBRevision") == 0) { + xnzjbVec.push_back(c_line_tags[i]); + continue; + } + AOM_ask_value_string(c_line_tags[i], "bl_sequence_no", &seqNo); + maxSeqNo = seqNo; + char* cUid; + ITK__convert_tag_to_uid(c_Rev, &cUid); + NodeBean cBean; + cBean.revUid = cUid; + cBean.designRev = c_Rev; + recyReadBom(c_line_tags[i], cBean, errBuff, dbName, idVector); + pBean.childs.push_back(cBean); + } + } + int maxNum = atoi(maxSeqNo.c_str()); + int xxt = 1; + printf("xnzjbVec ===> %d\n", xnzjbVec.size()); + + getAllXnj(xnzjbVec, maxNum, xxt, errBuff, dbName, pBean, 1, idVector); +} +/** + * 提取虚拟装配件 + * @param xnzjbVec 虚拟装配件版本集合 + * @param maxNum 提取之后的查找编号 + * @param xxt 查找编号累加的 + * @param errBuff 错误信息 + * @param dbName 原材料展开数据表 + * @param qtyXn 提取时需要累乘数量 + * @param idVector 需要展开的ID类别 + */ +void getAllXnj(vector xnzjbVec, int maxNum, int &xxt, + string& errBuff, string dbName, NodeBean& pBean, int qtyXn, vector idVector) { + + + for (int t = 0; t < xnzjbVec.size(); t++) { + tag_t c_line_tag = xnzjbVec[t], *cc_line_tags; + int cc_line_count; + ITKCALL(BOM_line_ask_all_child_lines(c_line_tag, &cc_line_count, &cc_line_tags)); + char *cnt, *c_type; + int qtyPXn = 1; + AOM_ask_value_string(c_line_tag, "bl_quantity", &cnt); + if (strcmp(cnt, "") != 0) { + qtyPXn = atoi(cnt); + } + //qtyPXn = qtyPXn * qtyXn; + vector xnzjbVec2; + for (int j = 0; j < cc_line_count; j++) { + tag_t c_Rev; + char *itemId, *object_name; + ITKCALL(AOM_ask_value_tag(cc_line_tags[j], "bl_line_object", &c_Rev)); + AOM_ask_value_string(c_Rev, "object_type", &c_type); + AOM_ask_value_string(c_Rev, "item_id", &itemId); + AOM_ask_value_string(c_Rev, "object_name", &object_name); + if (strcmp(c_type, "ZT2_XNZJBRevision") == 0) { + printf("itemId===>%s\n", itemId); + xnzjbVec2.push_back(cc_line_tags[j]); + continue; + } + //判断类型是否为 Part Revision ZT2_Design3DRevision ZT2_XNZJB 不是报错 + if (strcmp(c_type, "ZT2_Design3DRevision") != 0 + && strcmp(c_type, "Part Revision") != 0) { + string buffErr = ""; + buffErr.append("对象类型异常:").append(itemId).append("/").append(object_name).append("/").append(c_type).append("\n"); + size_t found = errBuff.find(buffErr); + if (found == std::string::npos) { + errBuff.append(buffErr); + } + } + NodeBean cBean; + char* cUid; + ITK__convert_tag_to_uid(c_Rev, &cUid); + cBean.revUid = cUid; + cBean.designRev = c_Rev; + cBean.xnNum = qtyXn * qtyPXn; + int srqNum = maxNum + xxt * 10; + string lastnum = to_string(srqNum); + xxt = xxt + 1; + cBean.bl_sequence_no = lastnum; + recyReadBom(cc_line_tags[j], cBean, errBuff, dbName, idVector); + pBean.childs.push_back(cBean); + } + printf("xnzjbVec2 ===> %d ==>%d \n", xnzjbVec2.size(), qtyPXn); + if (xnzjbVec2.size() > 0) { + getAllXnj(xnzjbVec2, maxNum, xxt, errBuff, dbName, pBean, qtyPXn, idVector); + } + } +} +/** + * 提取虚拟装配件 + * @param xnzjbVec 虚拟装配件版本集合 + * @param maxNum 提取之后的查找编号 + * @param xxt 查找编号累加的 + * @param errBuff 错误信息 + * @param dbName 原材料展开数据表 + * @param qtyXn 提取时需要累乘数量 + * @param loginUserId 用户ID + */ +void getAllXnj(vector xnzjbVec, int maxNum, int &xxt, + string& errBuff, string dbName, NodeBean& pBean, int qtyXn, char *loginUserId) { + + for (int t = 0; t < xnzjbVec.size(); t++) { + tag_t c_line_tag = xnzjbVec[t], *cc_line_tags; + int cc_line_count; + ITKCALL(BOM_line_ask_all_child_lines(c_line_tag, &cc_line_count, &cc_line_tags)); + char *cnt, *c_type; + int qtyPXn = 1; + AOM_ask_value_string(c_line_tag, "bl_quantity", &cnt); + if (strcmp(cnt, "") != 0) { + //虚拟件的BOM数量 + qtyPXn = atoi(cnt); + } + //qtyPXn = qtyPXn * qtyXn; + vector xnzjbVec2; + for (int j = 0; j < cc_line_count; j++) { + tag_t c_Rev; + char *itemId, *object_name; + ITKCALL(AOM_ask_value_tag(cc_line_tags[j], "bl_line_object", &c_Rev)); + AOM_ask_value_string(c_Rev, "object_type", &c_type); + AOM_ask_value_string(c_Rev, "item_id", &itemId); + AOM_ask_value_string(c_Rev, "object_name", &object_name); + if (strcmp(c_type, "ZT2_XNZJBRevision") == 0) { + printf("itemId===>%s\n", itemId); + xnzjbVec2.push_back(cc_line_tags[j]); + continue; + } + //判断类型是否为 Part Revision ZT2_Design3DRevision ZT2_XNZJB 不是报错 + if (strcmp(c_type, "ZT2_Design3DRevision") != 0 + && strcmp(c_type, "Part Revision") != 0) { + string buffErr = ""; + buffErr.append("对象类型异常:").append(itemId).append("/").append(object_name).append("/").append(c_type).append("\n"); + size_t found = errBuff.find(buffErr); + if (found == std::string::npos) { + errBuff.append(buffErr); + } + } + NodeBean cBean; + char* cUid; + ITK__convert_tag_to_uid(c_Rev, &cUid); + cBean.revUid = cUid; + cBean.designRev = c_Rev; + cBean.xnNum = qtyXn * qtyPXn; + int srqNum = maxNum + xxt * 10; + string lastnum = to_string(srqNum); + xxt = xxt + 1; + cBean.bl_sequence_no = lastnum; + //非虚拟件的继续原逻辑展开 + recyReadBom(cc_line_tags[j], cBean, errBuff, dbName, loginUserId); + pBean.childs.push_back(cBean); + } + printf("xnzjbVec2 ===> %d ==>%d \n", xnzjbVec2.size(), qtyPXn); + //存在多层级的虚拟装配件,递归提取 + if (xnzjbVec2.size() > 0) { + getAllXnj(xnzjbVec2, maxNum, xxt, errBuff, dbName, pBean, qtyPXn, loginUserId); + } + } +} +string GBKToUTF8(const std::string& strGBK) +{ + string strOutUTF8 = ""; + WCHAR * str1; + int n = MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, NULL, 0); + str1 = new WCHAR[n]; + MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, str1, n); + n = WideCharToMultiByte(CP_UTF8, 0, str1, -1, NULL, 0, NULL, NULL); + char * str2 = new char[n]; + WideCharToMultiByte(CP_UTF8, 0, str1, -1, str2, n, NULL, NULL); + strOutUTF8 = str2; + delete[]str1; + str1 = NULL; + delete[]str2; + str2 = NULL; + return strOutUTF8; +} +string proProcessCreate(tag_t rev, string process_name) +{ + tag_t template_tag = NULLTAG; + EPM_find_template2(process_name.c_str(), PROCESS_TEMPLATE, &template_tag); + tag_t new_process = NULLTAG; + int *tagType = (int *)MEM_alloc(1024 * sizeof(int));//EPM_reference_attachment + tag_t * itemTag = (tag_t *)MEM_alloc(1024 * sizeof(tag_t)); + tagType[0] = EPM_target_attachment; + itemTag[0] = rev; + EPM_create_process("快速发布", "", template_tag, 1, itemTag, tagType, &new_process); + return "1"; +} + +boolean firstRevision(tag_t designRev, tag_t mantr) { + char *revId; + int revNum = 0, statusNum = 0; + tag_t *structure_revisions; + AOM_ask_value_string(designRev, "item_revision_id", &revId); + AOM_ask_value_tags(mantr, "structure_revisions", &revNum, &structure_revisions); + if (revNum > 0) { + tag_t struct_revision = structure_revisions[0], *release_status_list; + AOM_ask_value_tags(struct_revision, "release_status_list", &statusNum, &release_status_list); + if (statusNum == 0) { + return false; + } + } + if (strcmp(revId, "V01") > 0) { + return true; + } + else { + return false; + } +} +/** + * 获取单层DBOM的信息 跟EBOM比较用的 + * @param topBean 记录的BOM结构 + */ +map getDBomMesg(NodeBean topBean) { + vector childs = topBean.childs; + map dMap; + for (int i = 0; i < childs.size(); i++) { + NodeBean cBean = childs[i]; + char *matnrNo, *uid; + AOM_ask_value_string(cBean.mantr, MATERIALNO, &matnrNo); + ITK__convert_tag_to_uid(cBean.mantr, &uid); + printf("uid[%s]\n", uid); + printf("matnrNo[%s]\n", matnrNo); + int qtyPXn = 1; + string cnt = cBean.bl_quantity; + if (strcmp(cnt.c_str(), "") != 0) { + qtyPXn = atoi(cnt.c_str()); + } + if (dMap.count(matnrNo) > 0) { + dMap[matnrNo] = dMap[matnrNo] + qtyPXn; + } + else { + dMap[matnrNo] = qtyPXn; + } + } + return dMap; +} +/** + * 获取单层EBOM的信息 跟DBOM比较用的 + * @param mantrRev E物料 + * @param flag 记录有没有bom视图 + */ +map getBomMsg(tag_t mantrRev, bool& flag) { + map bomMsgMap; + tag_t* bvr_list = NULL, bom_line, ebom_window; + int bvr_count = 0; + ITKCALL(ITEM_rev_list_bom_view_revs(mantrRev, &bvr_count, &bvr_list)); + //没有BOM视图创建 + if (bvr_count == 0) { + flag = true; + return bomMsgMap; + } + ITKCALL(BOM_create_window(&ebom_window)); + //移除原来的 + ITKCALL(BOM_set_window_top_line(ebom_window, NULL, mantrRev, NULLTAG, &bom_line)); + int c_line_count; + tag_t* c_line_tags; + ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags)); + printf("c_line_count===>%d\n", c_line_count); + for (int t = 0; t < c_line_count; t++) { + tag_t c_Rev; + char *matnrNo, *cnt; + ITKCALL(AOM_ask_value_tag(c_line_tags[t], "bl_line_object", &c_Rev)); + AOM_ask_value_string(c_Rev, "zt2_MaterialNo", &matnrNo); + printf("zt2_MaterialNo===>%s\n", matnrNo); + int qtyPXn = 1; + AOM_ask_value_string(c_line_tags[t], "bl_quantity", &cnt); + if (strcmp(cnt, "") != 0) { + qtyPXn = atoi(cnt); + } + if (bomMsgMap.count(matnrNo) > 0) { + bomMsgMap[matnrNo] = bomMsgMap[matnrNo] + qtyPXn; + } + else { + bomMsgMap[matnrNo] = qtyPXn; + } + } + BOM_close_window(ebom_window); + return bomMsgMap; +} +/** + * 对比Ebom和Dbom + * @param dMap D物料编码 - 数量 + * @param eMap E物料编码 - 数量 + */ +boolean combEAndDbom(map dMap, map eMap) { + map::iterator it; + //名称模糊匹配 + for (it = dMap.begin(); it != dMap.end(); it++) { + string s = it->first; + int dnum = dMap[s]; + if (eMap.count(s) == 0) { + return true; + } + else if (dnum != eMap[s]) { + return true; + } + } + return false; +} +/** + * 发布并且修改所有权 + */ +void TCMAndOwner(tag_t matnrTop) { + int num = 0, revNum; + tag_t *mantrsAs, dsuser, *structure_revisions; + AOM_ask_value_tags(matnrTop, "TC_Is_Represented_By", &num, &mantrsAs); + AOM_ask_value_tag(mantrsAs[0], "owning_user", &dsuser); + tag_t defGroup; + ITKCALL(AOM_ask_value_tag(dsuser, "default_group", &defGroup)); + ITKCALL(AOM_set_ownership(matnrTop, dsuser, defGroup)); + if (num > 0) { + AOM_ask_value_tags(matnrTop, "structure_revisions", &revNum, &structure_revisions); + if (revNum > 0) { + ITKCALL(AOM_set_ownership(structure_revisions[0], dsuser, defGroup)); + } + } + /*string process_name = "TCM Release Process"; + proProcessCreate(matnrTop, process_name);*/ +} +/** + * 比较DBOM、EBOM是否相同,不同则升版 + * @param topBean 存放BOM信息 + * @param isTop 是否产成品 + * @param hasChange 是否发布 + * @param saveAsMap 存放升版之前的版本uid - 升版之后的新版本 存在打包的对象防止多次升版 + */ +tag_t saveAsMaterial(NodeBean topBean, boolean isTop, string &hasChange, map& saveAsMap) { + tag_t mantr = topBean.mantr;//升版之前的E物料 + char* oldUid; + ITK__convert_tag_to_uid(mantr, &oldUid); + if (saveAsMap.count(oldUid) > 0) { + return saveAsMap[oldUid]; + } + bool flag = false; + map dBomMesg = getDBomMesg(topBean); + map eBomMesg = getBomMsg(mantr, flag); + if (flag) { + return mantr; + } + printf("dBomMesg[%d]", dBomMesg.size()); + printf("eBomMesg[%d]", eBomMesg.size()); + boolean needAs = false; + if (dBomMesg.size() != eBomMesg.size()) { + //升版 + 发布 + needAs = true; + } + else if (combEAndDbom(dBomMesg, eBomMesg)) { + //升版 + 发布 + needAs = true; + } + if (needAs && !topBean.isOutBuy) { + printf("=======TEST======\n"); + //升版并发布 没发布的产成品直接更新 + if (isTcm(mantr) && isBomViewTcm(mantr)) { + ITKCALL(ITEM_copy_rev(mantr, NULL, &mantr)); + TCMAndOwner(mantr); + if (isTop) { + hasChange = true; + } + saveAsMap[oldUid] = mantr; + } + } + return mantr; +} +void createEbom(NodeBean topBean, boolean isTop, string &hasChange, map& saveAsMap) +{ + tag_t ebom_window = NULLTAG; + tag_t bom_line = NULLTAG; + vector childs = topBean.childs; + //printf("子line数量 %d \n", childs.size()); + tag_t desBean = topBean.designRev; + char* id; + AOM_ask_value_string(desBean, "item_id", &id); + printf("id %s \n", id); + tag_t mantr = topBean.mantr; + //判断是否最初版本 不是就和当前的EBOM进行比较 + //相同就跳过不升版、不同就升版、只比较数量 + //ITEM_ask_f + mantr = saveAsMaterial(topBean, isTop, hasChange, saveAsMap); + boolean flagChange = true; + + if (mantr != NULLTAG && childs.size() > 0) { + printf("-----"); + tag_t* bvr_list = NULL; + int bvr_count; + ITKCALL(ITEM_rev_list_bom_view_revs(mantr, &bvr_count, &bvr_list)); + //没有BOM视图创建 + if (bvr_count == 0) { + tag_t newView, newViewBvr, pitem, dsuser; + ITEM_ask_item_of_rev(mantr, &pitem); + ITKCALL(PS_create_bom_view(NULL, NULL, NULL, pitem, &newView)); + AOM_save(newView); + ITKCALL(PS_create_bvr(newView, NULL, NULL, FALSE, mantr, &newViewBvr)); + AOM_save(newViewBvr); + AOM_save(mantr); + AOM_ask_value_tag(desBean, "owning_user", &dsuser); + tag_t defGroup; + ITKCALL(AOM_ask_value_tag(dsuser, "default_group", &defGroup)); + ITKCALL(AOM_set_ownership(newView, dsuser, defGroup)); + ITKCALL(AOM_set_ownership(newViewBvr, dsuser, defGroup)); + } + ITKCALL(BOM_create_window(&ebom_window)); + //移除原来的 + char*topUidTest; + ITK__convert_tag_to_uid(mantr, &topUidTest); + printf("topUidTest =======> %s \n", topUidTest); + ITKCALL(BOM_set_window_top_line(ebom_window, NULL, mantr, NULLTAG, &bom_line)); + //变更当前BOM层级 已发布的不需要更改 + if (flagChange) { + if (bvr_count > 0) { + int c_line_count; + tag_t* c_line_tags; + ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags)); + for (int t = 0; t < c_line_count; t++) { + char* val; + AOM_ask_value_string(c_line_tags[t], "bl_occ_zt2_DtoE", &val); + if (strcmp(val, "DBOM转换") == 0) { + BOM_line_cut(c_line_tags[t]); + } + } + } + for (int i = 0; i < childs.size(); i++) { + NodeBean cBean = childs[i]; + if (cBean.mantr != NULLTAG) { + tag_t cLine; + ITKCALL(BOM_line_add(bom_line, NULL, cBean.mantr, NULL, &cLine)); + AOM_lock(cLine); + if (cBean.packNum > 0) { + string num = cBean.bl_quantity; + num = to_string(cBean.topNum / cBean.packNum); + ITKCALL(AOM_set_value_string(cLine, "bl_quantity", num.c_str())); + } + else { + printf("num %s \n", cBean.bl_quantity.c_str()); + ITKCALL(AOM_set_value_string(cLine, "bl_quantity", cBean.bl_quantity.c_str())); + } + + + AOM_set_value_string(cLine, "bl_plmxml_occ_xform", cBean.bl_plmxml_occ_xform); + AOM_set_value_string(cLine, "bl_sequence_no", cBean.bl_sequence_no.c_str()); + ITKCALL(AOM_set_value_string(cLine, "bl_occ_zt2_DtoE", "DBOM转换")); + AOM_save(cLine); + //最后unlock + AOM_unlock(cLine); + AOM_refresh(cLine, FALSE); + } + else { + printf("eeeeee\n"); + } + } + ITKCALL(BOM_save_window(ebom_window)); + } + BOM_close_window(ebom_window); + for (int i = 0; i < childs.size(); i++) { + NodeBean cBean = childs[i]; + createEbom(cBean, false, hasChange, saveAsMap); + } + } + else { + printf("topBean.mantr == NULLTAG\n"); + } + +} + +void copyEBomLine(tag_t matnrTop, tag_t otherPbom) { + tag_t ebom_window, ebom_window2, *bvr_list, *bvr_list2, bom_line, bom_line2, *c_line_tags, *c_line_tags2; + int bvr_count = 0, bvr_count2 = 0, c_line_count, c_line_count2; + (BOM_create_window(&ebom_window)); + (ITEM_rev_list_bom_view_revs(matnrTop, &bvr_count, &bvr_list)); + printf("bvr_count=%d \n", bvr_count); + if (bvr_count == 0) { + //errBuff.append("不存在EBOM请检查\n"); + } + ITKCALL(BOM_set_window_top_line_bvr(ebom_window, bvr_list[0], &bom_line)); //顶层bom获取 + printf("顶层bom获取\n"); + //ITKCALL(AOM_ask_value_tag(bom_line, "bl_line_object", &mantr)); + ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags)); + + + (ITEM_rev_list_bom_view_revs(otherPbom, &bvr_count2, &bvr_list2)); + if (bvr_count2 == 0) { + tag_t newView, newViewBvr, pitem; + ITEM_ask_item_of_rev(otherPbom, &pitem); + ITKCALL(PS_create_bom_view(NULL, NULL, NULL, pitem, &newView)); + AOM_save(newView); + ITKCALL(PS_create_bvr(newView, NULL, NULL, FALSE, otherPbom, &newViewBvr)); + AOM_save(newViewBvr); + AOM_save(otherPbom); + int num = 0; + tag_t dsuser, *structure_revisions, *bom_view_tags, *mantrs; + ITKCALL(AOM_ask_value_tags(otherPbom, "TC_Is_Represented_By", &num, &mantrs)); + if (num == 1) { + AOM_ask_value_tag(mantrs[0], "owning_user", &dsuser); + tag_t defGroup; + ITKCALL(AOM_ask_value_tag(dsuser, "default_group", &defGroup)); + ITKCALL(AOM_set_ownership(newView, dsuser, defGroup)); + ITKCALL(AOM_set_ownership(newViewBvr, dsuser, defGroup)); + } + //return; + (ITEM_rev_list_bom_view_revs(otherPbom, &bvr_count2, &bvr_list2)); + } + (BOM_create_window(&ebom_window2)); + (BOM_set_window_top_line_bvr(ebom_window2, bvr_list2[0], &bom_line2)); //顶层bom获取 + ITKCALL(BOM_line_ask_all_child_lines(bom_line2, &c_line_count2, &c_line_tags2)); + for (int i = 0; i < c_line_count2; i++) { + BOM_line_cut(c_line_tags2[i]); + } + for (int i = 0; i < c_line_count; i++) { + tag_t newChild; char *bl_seqNo; + ITKCALL(BOM_line_copy(bom_line2, c_line_tags[i], NULLTAG, &newChild)); + AOM_ask_value_string(c_line_tags[i], "bl_sequence_no", &bl_seqNo); + AOM_lock(newChild); + AOM_set_value_string(newChild, "bl_sequence_no", bl_seqNo); + AOM_save(newChild); + //最后unlock + AOM_unlock(newChild); + } + //tag_t newChild; + //ITKCALL(BOM_line_copy(bom_line2, c_line_tags[i], NULLTAG, &newChild)); + + ITKCALL(BOM_save_window(ebom_window2)); + BOM_close_window(ebom_window2); + BOM_close_window(ebom_window); +} +//获取分类属性 判断是否整除 +int getClassValByTop(tag_t item, string& errMessage) { + char*id; + AOM_ask_value_string(item, "item_id", &id); + vector vec; + Split(id, "-", vec); + tag_t topItem; + if (vec.size() > 1) { + string topId; + topId.append("1ZDB300000P-").append(vec[1]); + ITEM_find_item(topId.c_str(), &topItem); + } + else { + return 1; + } + tag_t top_classificationObject; + ICS_ask_classification_object(topItem, &top_classificationObject); + if (top_classificationObject == NULL_TAG) + { + errMessage.append("顶层对象没有发送到分类\n"); + return 0; + } + char* top_class_id = NULL, *top_class_name = NULL; + //ICS_ask_class_of_classification_obj(top_classificationObject, &top_class_tag); + //ICS_ask_id_name(top_class_tag, &top_class_id, &top_class_name); + printf("BOM TOP LINE CLASS ID = %s | NAME = %s \n", top_class_id, top_class_name); + int n_attrs; + char** attr_names; + char** attr_vals; + ITKCALL(ICS_ask_attributes_of_classification_obj(top_classificationObject, &n_attrs, &attr_names, &attr_vals)); + cout << n_attrs << endl; + int num = 1; + for (int ii = 0; ii < n_attrs; ii++) + { + printf("attr_names[ii]==>%sTTT\n", attr_names[ii]); + printf("attr_vals[ii]==>%sTTT\n", attr_vals[ii]); + if (strcmp(attr_names[ii], "相数") == 0) { + if (strcmp(attr_vals[ii], "") == 0) { + errMessage.append("分类属性相数为空,请检查。\n"); + return 0; + } + else { + printf("111[ii]==TTT\n"); + if (strstr(attr_vals[ii], "3") != NULL) { + num = 3; + } + else if (strstr(attr_vals[ii], "1") != NULL) { + num = 1; + } + else if (strstr(attr_vals[ii], "5") != NULL) { + num = 5; + } + //num = atoi(attr_vals[ii]); + } + break; + } + } + return num; +} +/** + * DBOM转EBOM + */ +int DbomToEMethod(void* returnValue) { + int ifail = ITK_ok; + char *sql = NULL, *revUid; + tag_t designRev, item; + ITKCALL(ifail = USERARG_get_string_argument(&revUid)); + ITK__convert_uid_to_tag(revUid, &designRev); + ITEM_ask_item_of_rev(designRev, &item); + ITEM_ask_latest_rev(item, &designRev); + if (open("PLMUser", "PLMUser", "BDP2020", "10.128.20.35")) { + printf("链接SQLSERVER失败\n"); + } + else { + printf("链接SQLSERVER成功\n"); + } + //遍历design BOM 获取物料信息 + int bvr_count = 0, c_line_count; + tag_t ebom_window = NULLTAG; + tag_t bom_line = NULLTAG; + tag_t item_tag = NULLTAG, *c_line_tags; + (BOM_create_window(&ebom_window)); + tag_t* bvr_list = NULL; + (ITEM_rev_list_bom_view_revs(designRev, &bvr_count, &bvr_list)); + printf("bvr_count=%d", bvr_count); + + (BOM_set_window_top_line_bvr(ebom_window, bvr_list[0], &bom_line)); //顶层bom获取 + printf("顶层bom获取\n"); + + //(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags)); + NodeBean topBean; + //遍历 + string errBuff; + //xsLen = 1; + xsLen = getClassValByTop(designRev, errBuff); + int url_num = 0; + char** url_vals = NULL; + PREF_ask_char_values("database_tc", &url_num, &url_vals); + string url = url_vals[0]; + url.append("/").append(url_vals[2]); + + //map %s \n", url.c_str()); + if (ConnServer(url_vals[3], url_vals[4], (char*)url.c_str()) == -1) + { + printf("提示:中间数据表访问失败\n"); + ifail = 1; + } + string dbName; + int url_num2 = 0; + char** url_vals2 = NULL; + PREF_ask_char_values("CHINT_MATERIAL_RAW", &url_num2, &url_vals2); + for (int t = 0; t < url_num2; t++) { + vector vec; + Split(url_vals2[t], ":", vec); + if (vec[0].compare("M060") == 0) { + dbName = vec[1]; + } + } + char *loginUserId; + printf("dbName===%s\n", dbName.c_str()); + POM_get_user_id(&loginUserId); + + recyReadBom(bom_line, topBean, errBuff, dbName, loginUserId); + DisConnServer(); + BOM_close_window(ebom_window); + //搭建BOM + POM_AM__set_application_bypass(true); + printf("error %s \n", errBuff.c_str()); + if (errBuff.empty()) { + string hasChange = ""; + map saveAsMap; + createEbom(topBean, true, hasChange, saveAsMap); + printf("topBean.ccps.size()====>%d\n", topBean.ccps.size()); + //没有更改直接跳过 + if (topBean.ccps.size() > 0 && hasChange.compare("no") != 0) { + tag_t desBean = topBean.designRev; + //vector childs = topBean.childs; + /*map dMap; + for (int i = 0; i < childs.size(); i++) { + NodeBean cBean = childs[i]; + char *matnrNo, *uid; + AOM_ask_value_string(cBean.mantr, "zt2_MaterialNo", &matnrNo); + ITK__convert_tag_to_uid(cBean.mantr, &uid); + printf("uid[%s]\n", uid); + printf("matnrNo[%s]\n", matnrNo); + int qtyPXn = 1; + string cnt = cBean.bl_quantity; + if (strcmp(cnt.c_str(), "") != 0) { + qtyPXn = atoi(cnt.c_str()); + } + if (dMap.count(matnrNo) > 0) { + dMap[matnrNo] = dMap[matnrNo] + qtyPXn; + } + else { + dMap[matnrNo] = qtyPXn; + } + } + printf("dMap[%d]", dMap.size());*/ + map dMap = getDBomMesg(topBean); + for (int t = 0; t < topBean.ccps.size(); t++) { + tag_t mantr = topBean.ccps[t]; + boolean flagChange = true; + bool flag = false; + map eMap = getBomMsg(mantr, flag); + printf("eMap[%d]", eMap.size()); + boolean needAs = false; + if (dMap.size() != eMap.size()) { + //升版 + 发布 + needAs = true; + } + else if (combEAndDbom(dMap, eMap)) { + //升版 + 发布 + needAs = true; + } + if (needAs && !flag) { + printf("=======TEST======\n"); + //升版并发布 + ITKCALL(ITEM_copy_rev(mantr, NULL, &mantr)); + TCMAndOwner(mantr); + //return; + } + if (flagChange) { + tag_t topItem, topRev; + ITEM_ask_item_of_rev(topBean.mantr, &topItem); + ITEM_ask_latest_rev(topItem, &topRev); + copyEBomLine(topRev, mantr); + } + } + } + errBuff = "succ"; + } + /*else { + printf(errBuff.c_str()); + }*/ + + POM_AM__set_application_bypass(false); + + close(); + printf("释放数据库成功\n"); + printf("子line数量 %d \n", topBean.childs.size()); + string buff = errBuff; + *((char**)returnValue) = (char*)MEM_alloc((strlen(buff.c_str()) + 1) * sizeof(char)); + tc_strcpy(*((char**)returnValue), buff.c_str()); + return ifail; +} +/** + * DBOM转EBOM 传递框架BOM之后使用 + * 区别在于需要通过首选项进行D转E,没有配置的不转换 + */ +int DbomToEMethodUser(void* returnValue) { + int ifail = ITK_ok; + char *sql = NULL, *revUid; + tag_t designRev; + ITKCALL(ifail = USERARG_get_string_argument(&revUid)); + ITK__convert_uid_to_tag(revUid, &designRev); + + if (open("PLMUser", "PLMUser", "BDP2020", "10.128.20.35")) { + printf("链接SQLSERVER失败\n"); + } + else { + printf("链接SQLSERVER成功\n"); + } + //遍历design BOM 获取物料信息 + int bvr_count = 0, c_line_count; + tag_t ebom_window = NULLTAG; + tag_t bom_line = NULLTAG; + tag_t item_tag = NULLTAG, *c_line_tags; + (BOM_create_window(&ebom_window)); + tag_t* bvr_list = NULL; + (ITEM_rev_list_bom_view_revs(designRev, &bvr_count, &bvr_list)); + printf("bvr_count=%d", bvr_count); + + (BOM_set_window_top_line_bvr(ebom_window, bvr_list[0], &bom_line)); //顶层bom获取 + printf("顶层bom获取\n"); + + //(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags)); + NodeBean topBean; + //遍历 + string errBuff; + + int url_num = 0; + char** url_vals = NULL; + PREF_ask_char_values("database_tc", &url_num, &url_vals); + string url = url_vals[0]; + url.append("/").append(url_vals[2]); + + //map %s \n", url.c_str()); + if (ConnServer(url_vals[3], url_vals[4], (char*)url.c_str()) == -1) + { + printf("提示:中间数据表访问失败\n"); + ifail = 1; + } + string dbName; + int url_num2 = 0, url_num3 = 0; + char** url_vals2 = NULL, **url_vals3 = NULL; + PREF_ask_char_values("CHINT_MATERIAL_RAW", &url_num2, &url_vals2); + for (int t = 0; t < url_num2; t++) { + vector vec; + Split(url_vals2[t], ":", vec); + if (vec[0].compare("M060") == 0) { + dbName = vec[1]; + } + } + //配置哪些ID类别需要D转E + PREF_ask_char_values("CHINT_M060_KJTOSAP", &url_num3, &url_vals3); + vector idVector; + if (url_num3 > 0) { + Split(url_vals3[0], ";", idVector); + } + + recyReadBom(bom_line, topBean, errBuff, dbName, idVector); + DisConnServer(); + BOM_close_window(ebom_window); + //搭建BOM + POM_AM__set_application_bypass(true); + printf("error %s \n", errBuff.c_str()); + //没有错误信息开始DBOM转换EBOM + if (errBuff.empty()) { + string change; + //EBOM的搭建 + map saveAsMap; + createEbom(topBean, false, change, saveAsMap); + printf("topBean.ccps.size()====>%d\n", topBean.ccps.size()); + if (topBean.ccps.size() > 0) { + //总装图下可能会有多个物料,BOM结构相同,只需要复制就行 + for (int t = 0; t < topBean.ccps.size(); t++) { + copyEBomLine(topBean.mantr, topBean.ccps[t]); + } + } + errBuff = "succ"; + } + + POM_AM__set_application_bypass(false); + + close(); + printf("释放数据库成功\n"); + printf("子line数量 %d \n", topBean.childs.size()); + string buff = errBuff; + *((char**)returnValue) = (char*)MEM_alloc((strlen(buff.c_str()) + 1) * sizeof(char)); + tc_strcpy(*((char**)returnValue), buff.c_str()); + return ifail; +} \ No newline at end of file diff --git a/General/General/EbomToPMethod.cpp b/General/General/EbomToPMethod.cpp index cb302b0..605ee20 100644 --- a/General/General/EbomToPMethod.cpp +++ b/General/General/EbomToPMethod.cpp @@ -48,6 +48,7 @@ regex qq_reg("^1ZDB5.*\\d{1,}1000X.*"); //\\d{5,}$ struct newCBean { int num; + string blQty; tag_t cLine; }; struct EBomBean @@ -88,6 +89,7 @@ struct PMPC }; PMPC pmpc; vector prds; +/**/ void save_representation2222(tag_t primaryTag, tag_t secondTag, char* relationType) { @@ -126,6 +128,12 @@ void replaceBom(tag_t newTopLine, tag_t newChild) { } string sql_query = "select FeatureList from CcemVW_GoodsFeature where GoodsCode ='%s' "; +/** + * 另存EBOM,从下往上另存 + * @param childPm 存放EBOM信息 + * @param map 用来存放另存之后的信息 key:E val:P物料 + * @param topPrev 顶层P物料 + */ void saveAsCycle(EBomBean& childPm, map& map, tag_t& topPrev) { tag_t tcType, newItem, newRev; char* newId; @@ -147,6 +155,7 @@ void saveAsCycle(EBomBean& childPm, map& map, tag_t& topPrev) { childPm.pRev.push_back(map[eRevUid]); } else { + //另存操作 char* newid = NULL; logical isModified = FALSE; tag_t item_type_tag; @@ -190,6 +199,7 @@ void saveAsCycle(EBomBean& childPm, map& map, tag_t& topPrev) { } } } + //另存之后需要替换BOM,按EBOM结构搭建PBOM if (childPm.parentBean.size() > 0) { EBomBean parentBean = childPm.parentBean[0]; vector pRevs = parentBean.pRev; @@ -237,7 +247,17 @@ void getSpecs(tag_t rev, vector &vec) { //} } string insertSql = "insert into chint_material(\"Code\",\"PUID\",\"PmpcCode\",\"GoodsCode\",\"GoodsName\",\"UnitCode\",\"CompanyCode\",\"BpNo\",\"Spec\",\"TeRe\",\"State\",\"User\",\"Time\",\"Condition\",\"Info\") values('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s',to_date('%s','yyyy-mm-dd HH24:mi:ss'),'%s','%s')"; -//根据项数拆解线圈,并申请物料编码 + +/** + * 根据项数拆解线圈,并申请物料编码 + * @param rev 图纸对象 + * @param user_id 用户信息 + * @param jsons JSON + * @param groupId 组 + * @param spec 规格 + * @param nameNum A项信息 + * @param dcproxy 转权限的用户 + */ tag_t send1(tag_t rev, string now, char* user_id, vector& jsons, string groupId, string spec, char* nameNum, char* idss, tag_t dcproxy) { //map>::iterator it; @@ -451,7 +471,14 @@ string getXqName(char *name) { return xq; } -//添加A项线圈的子行 +/** + * 把线圈子项添加到A项线圈下面 + * @param c_line_tags 子行 + * @param c_line_count 子行数量 + * @param len 拆分数量 + * @param newPAmatnr 新的A项线圈 + * @param lastFlag + */ void addToAmatnr(tag_t *c_line_tags, int c_line_count, int len, tag_t newPAmatnr,boolean lastFlag) { tag_t mantr = newPAmatnr, ebom_window, bom_line; @@ -554,6 +581,7 @@ void replaceBom(EBomBean& childPm, map& map, int len, tag_t dcpro ITKCALL(AOM_ask_value_string(owning_group, "name", &grpId)); ITKCALL(AOM_ask_value_string(owning_user, "user_id", &user_id)); vector specs; + //获取物料属性规格 getSpecs(tzRev, specs); printf("获取规格结束 \n"); time_t now; @@ -574,7 +602,7 @@ void replaceBom(EBomBean& childPm, map& map, int len, tag_t dcpro tag_t* bvr_list = NULL; (ITEM_rev_list_bom_view_revs(axqPmatnr, &bvr_count, &bvr_list)); printf("bvr_count=%d\n", bvr_count); - + //没有物料视图的时候需要创建一个 if (bvr_count == 0) { tag_t newView, newViewBvr, pitem; ITEM_ask_item_of_rev(axqPmatnr, &pitem); @@ -595,6 +623,7 @@ void replaceBom(EBomBean& childPm, map& map, int len, tag_t dcpro (BOM_create_window(&ebom_window)); (BOM_set_window_top_line_bvr(ebom_window, bvr_list[0], &bom_line)); //顶层bom获取 //ITKCALL(AOM_ask_value_tag(bom_line, "bl_line_object", &mantr)); + //线圈转PBOM时候的特殊处理:申请物料 A、B、C项线圈 然后把原来的线圈的子项拆分数量复制 ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags)); printf("int===>%d\n", len); vector newPAmatnrs; @@ -625,7 +654,8 @@ void replaceBom(EBomBean& childPm, map& map, int len, tag_t dcpro printf("jsons ===> %s \n", jsons[i].c_str()); string url = "http://10.128.20.35:9002/Post/PLM_Goods"; string jsonUf = G2U222(jsons[i].c_str()); - string msg = callHttpserver(jsonUf, url); + //调用接口申请物料 + //string msg = callHttpserver(jsonUf, url); } } } @@ -686,7 +716,14 @@ string getRemarkMsg(string remark,int len) { } return xs; } - +/** + * 记遍历EBOM + * @param tag_t EBOM头 + * @param parentBean EBOM对应的PBOM结构 + * @param len 根据分类属性项数获取的拆分数 + * @param pErev EBOM对应的E物料 + * @param errBuff 记录错误信息 + */ void recyReadEBom(tag_t pLine, EBomBean parentBean, vector& beans, int len, tag_t pErev, string& errBuff) { int c_line_count, cnt2, numFac, cnt3; @@ -742,7 +779,7 @@ void recyReadEBom(tag_t pLine, EBomBean parentBean, vector& beans, int if (ret) { char *zt2_ifpbom; AOM_ask_value_string(eRev, "zt2_ifpbom", &zt2_ifpbom); - if (zt2_ifpbom!=NULL&&strcmp(zt2_ifpbom, "P") == 0) { + if (zt2_ifpbom != NULL && strcmp(zt2_ifpbom, "P") == 0) { continue; } int cc_cnt; @@ -806,6 +843,7 @@ void recyReadEBom(tag_t pLine, EBomBean parentBean, vector& beans, int } } +//获取dcproxy用户 tag_t findDcUser() { tag_t* tags; tag_t query = NULLTAG; @@ -846,27 +884,32 @@ public: }; struct EBomUpBean { + string blQuantity; string matnrNo; tag_t bomline; + tag_t mantr; vector parentBean; //遍历EBOM时候的父级 vector c_lines; //EBOM中的子件 只有线圈用 }; -//遍历EBOM 存放所有EBOM的 +//遍历EBOM 存放所有EBOM的更新时使用 void updatePbomCycle(tag_t eLine, string &errBuff, int len, EBomUpBean &upBean) { int c_line_count; tag_t *c_line_tags; ITKCALL(BOM_line_ask_all_child_lines(eLine, &c_line_count, &c_line_tags)); //printf("upBean===>%s\n", upBean.matnrNo.c_str()); for (int i = 0; i < c_line_count; i++) { - char* ifpBom, *matnrNo; + char* ifpBom, *matnrNo, *childQty; tag_t c_line_tag = c_line_tags[i], eRev; ITKCALL(AOM_ask_value_tag(c_line_tag, "bl_line_object", &eRev)); + AOM_ask_value_string(c_line_tag, BL_QUANTITY, &childQty); AOM_ask_value_string(eRev, "zt2_ifpbom", &ifpBom); AOM_ask_value_string(eRev, "zt2_MaterialNo", &matnrNo); EBomUpBean cBean; cBean.matnrNo = matnrNo; //printf("CChild===>%s\n", matnrNo); + cBean.blQuantity = childQty; + cBean.mantr = eRev; //E物料 cBean.bomline = c_line_tag; int num = 0; tag_t* mantrs; @@ -915,18 +958,20 @@ void updatePbomCycle(tag_t eLine, string &errBuff, int len, EBomUpBean &upBean) newCBean aBean; aBean.num = blQty / len; aBean.cLine = cc_line; + aBean.blQty = blQty; cBean.c_lines.push_back(aBean); } } else { int blQty = atoi(bl_quantity); - if (blQty % len != 0 && strstr(bl_line_name, "线") == NULL) { + if (blQty % markMsg.length() != 0 && strstr(bl_line_name, "线") == NULL) { errBuff.append("P类物料:").append(pId).append("下子件").append(c_pId) .append("无法整除,请检查。").append("\n"); } else { newCBean aBean; aBean.num = blQty / len; + aBean.blQty = blQty; aBean.cLine = cc_line; cBean.c_lines.push_back(aBean); } @@ -1017,6 +1062,11 @@ tag_t saveAsUpdate(tag_t eRev, char *uid, tag_t pLine) { } return newRev; } +/** + * 另存E物料转为P物料,并在BOM中替换 + * @param eRev 要另存的E物料 + * @param newChild 判断单元是否多次出现 + */ tag_t saveAsUpdate(tag_t eRev, tag_t newChild) { char* newid = NULL; logical isModified = FALSE; @@ -1057,32 +1107,6 @@ tag_t saveAsUpdate(tag_t eRev, tag_t newChild) { } { ITKCALL(BOM_line_replace(newChild, NULLTAG, newRev, NULLTAG)); - //int bvr_count = 0, c_line_count; - //tag_t ebom_window = NULLTAG; - //tag_t bom_line = NULLTAG, * c_line_tags; - //(BOM_create_window(&ebom_window)); - //tag_t* bvr_list = NULL; - //(ITEM_rev_list_bom_view_revs(pRevs[0], &bvr_count, &bvr_list)); - //printf("bvr_count=%d\n", bvr_count); - - //(BOM_set_window_top_line_bvr(ebom_window, bvr_list[0], &bom_line)); //顶层bom获取 - ////ITKCALL(AOM_ask_value_tag(bom_line, "bl_line_object", &mantr)); - //ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags)); - - //for (int ind = 0; ind < c_line_count; ind++) { - // tag_t c_line_tag = c_line_tags[ind], mantr; - // AOM_ask_value_tag(c_line_tag, "bl_line_object", &mantr); - // char* eRevUid2; - // ITK__convert_tag_to_uid(mantr, &eRevUid2); - // if (strcmp(eRevUid2, eRevUid) == 0) { - // if (childPm.pRev.size() > 0) { - // printf("eRevUid===>%s\n", eRevUid); - // ITKCALL(BOM_line_replace(c_line_tag, NULLTAG, childPm.pRev[0], NULLTAG)); - // } - // } - //} - //BOM_save_window(ebom_window); - //BOM_close_window(ebom_window); } return newRev; } @@ -1171,7 +1195,7 @@ void createAXxq(tag_t eRev, tag_t pRev, int len, tag_t dcproxy) { printf("jsons ===> %s \n", jsons[i].c_str()); string url = "http://10.128.20.35:9002/Post/PLM_Goods"; string jsonUf = G2U222(jsons[i].c_str()); - string msg = callHttpserver(jsonUf, url); + //string msg = callHttpserver(jsonUf, url); } } } @@ -1241,13 +1265,246 @@ void addToAmatnrUp(vector vecs, int len, tag_t newPAmatnr, boolean l ITKCALL(BOM_save_window(ebom_window)); ITKCALL(BOM_close_window(ebom_window)); } -void startUpdate(EBomUpBean upBean, tag_t bom_line, int len, tag_t dcproxy,tag_t ebom_window2) { + +/** + * 获取单层EBOM的信息 跟EBOM比较用的 + * @param upBean 记录的EBOM结构 + */ +map getEBomMesg(EBomUpBean upBean) { + vector childs = upBean.parentBean; + map eMap; + for (int i = 0; i < childs.size(); i++) { + EBomUpBean cBean = childs[i]; + double qtyPXn = 1; + string matnrNo = cBean.matnrNo; + printf("matnrNo====> %s\n", matnrNo.c_str()); + string cnt = cBean.blQuantity; + if (strcmp(cnt.c_str(), "") != 0) { + qtyPXn = atof(cnt.c_str()); //atof(oldQty); + } + if (eMap.count(matnrNo) > 0) { + eMap[matnrNo] = eMap[matnrNo] + qtyPXn; + } + else { + eMap[matnrNo] = qtyPXn; + } + } + return eMap; +} +/** + * 计算PBOM里线圈的数量 + * @param mantrRev P物料 + * @param flag 记录有没有bom视图 + */ +void getPBomMsg(tag_t bom_line, map& bomMsgMap) { + int c_line_count; + tag_t* c_line_tags; + ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags)); + printf("c_line_count===>%d\n", c_line_count); + for (int t = 0; t < c_line_count; t++) { + tag_t c_Rev; + char *matnrNo, *cnt, *objName; + ITKCALL(AOM_ask_value_tag(c_line_tags[t], BL_LINE_OBJECT, &c_Rev)); + AOM_ask_value_string(c_Rev, MATERIALNO, &matnrNo); + printf("zt2_MaterialNo===>%s\n", matnrNo); + double qtyPXn = 1; + AOM_ask_value_string(c_line_tags[t], BL_QUANTITY, &cnt); + if (strcmp(cnt, "") != 0) { + qtyPXn = atof(cnt); + } + if (bomMsgMap.count(matnrNo) > 0) { + bomMsgMap[matnrNo] = bomMsgMap[matnrNo] + qtyPXn; + } + else { + bomMsgMap[matnrNo] = qtyPXn; + } + } +} +/** + * 获取单层PBOM的信息 跟EBOM比较用的 + * 线圈装配P - 线圈P - ABC项 - 线圈E拆分的子项 + * @param mantrRev P物料 + * @param flag 记录有没有bom视图 + */ +map getPBomMsg(tag_t mantrRev, bool& flag, vector& termCoils) { + map bomMsgMap; + tag_t* bvr_list = NULL, bom_line, ebom_window; + int bvr_count = 0; + ITKCALL(ITEM_rev_list_bom_view_revs(mantrRev, &bvr_count, &bvr_list)); + //没有BOM视图创建 + if (bvr_count == 0) { + flag = true; + return bomMsgMap; + } + ITKCALL(BOM_create_window(&ebom_window)); + //移除原来的 + ITKCALL(BOM_set_window_top_line(ebom_window, NULL, mantrRev, NULLTAG, &bom_line)); + int c_line_count; + tag_t* c_line_tags; + ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags)); + printf("c_line_count===>%d\n", c_line_count); + for (int t = 0; t < c_line_count; t++) { + tag_t c_Rev; + char *matnrNo, *cnt, *objName; + ITKCALL(AOM_ask_value_tag(c_line_tags[t], "bl_line_object", &c_Rev)); + AOM_ask_value_string(c_Rev, "zt2_MaterialNo", &matnrNo); + + double qtyPXn = 1; + AOM_ask_value_string(c_line_tags[t], "bl_quantity", &cnt); + AOM_ask_value_string(c_Rev, OBJECT_NAME, &objName); + printf("zt2_MaterialNo===>%s objName ===> %s\n", matnrNo, objName); + if (checkName(objName)) { + termCoils.push_back(c_Rev); + getPBomMsg(c_line_tags[t], bomMsgMap); + continue; + } + if (strcmp(cnt, "") != 0) { + qtyPXn = atof(cnt); + } + if (bomMsgMap.count(matnrNo) > 0) { + bomMsgMap[matnrNo] = bomMsgMap[matnrNo] + qtyPXn; + } + else { + bomMsgMap[matnrNo] = qtyPXn; + } + } + BOM_close_window(ebom_window); + return bomMsgMap; +} +/** + * 对比Ebom和Dbom + * @param dMap D物料编码 - 数量 + * @param eMap E物料编码 - 数量 + */ +boolean combEAndDbom(map dMap, map eMap) { + map::iterator it; + //名称模糊匹配 + for (it = dMap.begin(); it != dMap.end(); it++) { + string s = it->first; + double dnum = dMap[s]; + if (eMap.count(s) == 0) { + return true; + } + else if (dnum != eMap[s]) { + return true; + } + } + return false; +} +/** + * 根据升版前的线圈视图权限,修改升版后的 + * @param newPMantr 升版后的 + * @param oldPMantr 升版前的 + */ +void changeCoilOwner(tag_t newPMantr, tag_t oldPMantr) { + tag_t dsuser, *oldRevisions; + int revNum = 0, revNumOld = 0; + AOM_ask_value_tags(newPMantr, "structure_revisions", &revNumOld, &oldRevisions); + if (revNumOld > 0) { + AOM_ask_value_tag(oldRevisions[0], "owning_user", &dsuser); + tag_t defGroup, *structure_revisions; + ITKCALL(AOM_ask_value_tag(dsuser, "default_group", &defGroup)); + AOM_ask_value_tags(newPMantr, "structure_revisions", &revNum, &structure_revisions); + if (revNum > 0) { + ITKCALL(AOM_set_ownership(structure_revisions[0], dsuser, defGroup)); + } + } +} +/** + * 比较DBOM、EBOM是否相同,不同则升版 + * @param topBean 存放BOM信息 + * @param isTop 是否产成品 + * @param hasChange 是否发布 + * @param saveAsMap 存放升版之前的版本uid - 升版之后的新版本 存在打包的对象防止多次升版 + * @param pMaterial P物料 + */ +tag_t saveAsMaterial(EBomUpBean topBean, boolean isTop, + string &hasChange, map& saveAsMap, tag_t pMaterial) { + char* oldUid; + ITK__convert_tag_to_uid(pMaterial, &oldUid); + if (saveAsMap.count(oldUid) > 0) { + return saveAsMap[oldUid]; + } + bool flagTest = false; + map dBomMesg = getEBomMesg(topBean); + vector termCoils; + map eBomMesg = getPBomMsg(pMaterial, flagTest, termCoils); + if (flagTest) { + printf("dddd=====\n"); + return pMaterial; + } + printf("dBomMesg[%d]", dBomMesg.size()); + printf("eBomMesg[%d]\n", eBomMesg.size()); + boolean needAs = false; + if (dBomMesg.size() != eBomMesg.size()) { + //升版 + 发布 + needAs = true; + } + else if (combEAndDbom(dBomMesg, eBomMesg)) { + //升版 + 发布 + needAs = true; + } + if (needAs) { + printf("=======TEST====== %d \n", termCoils.size()); + //升版并发布 没发布的产成品直接更新 + if (isTcm(pMaterial) && isBomViewTcm(pMaterial)) { + ITKCALL(ITEM_copy_rev(pMaterial, NULL, &pMaterial)); + TCMAndOwner(pMaterial); + if (isTop) { + hasChange = "true"; + } + saveAsMap[oldUid] = pMaterial; + } + for (int i = 0; i < termCoils.size(); i++) { + char* itemId; + AOM_ask_value_string(termCoils[i], "item_id", &itemId); + printf("=======itemId====== %s \n", itemId); + if (isTcm(termCoils[i]) && isBomViewTcm(termCoils[i])) { + tag_t newPMantr; + ITKCALL(ITEM_copy_rev(termCoils[i], NULL, &newPMantr)); + changeCoilOwner(newPMantr, termCoils[i]); + //TCMAndOwner(newPMantr); + } + } + } + return pMaterial; +} +/** + * 更新PBOM逻辑 + * @param upBean EBOM结构 + * @param bom_line PBOM顶层 + * @param len 拆分数量 + * @param dcproxy dcproxy用户 + * @param isTop 是否最上层 + * @param hasChange 最顶层是否变更 + * @param saveAsMap 记录已经另存过的对象,防止解包之后重复另存 + */ +void startUpdate(EBomUpBean upBean, tag_t pBomTag, int len, tag_t dcproxy, + boolean isTop, string &hasChange, map& saveAsMap) { + //记录的EBOM下面的子件 vector vecs = upBean.parentBean; int c_line_count = 0; tag_t* c_line_tags; vector matnrVec; + //线圈 vector xqTagVec; + //PBOM map pBomMap; + //线圈对象需要特别处理 + tag_t pBomTop = saveAsMaterial(upBean, isTop, hasChange, saveAsMap, pBomTag); + tag_t ebom_window2, *bvr_list2, bom_line; + int bvr_count2 = 0; + char* pBomUid; + (BOM_create_window(&ebom_window2)); + ITK__convert_tag_to_uid(pBomTop, &pBomUid); + + (ITEM_rev_list_bom_view_revs(pBomTop, &bvr_count2, &bvr_list2)); + if (bvr_count2 == 0) { + //errBuff.append("不存在EBOM请检查\n"); + //原来没有PBOM + return; + } + ITKCALL(BOM_set_window_top_line_bvr(ebom_window2, bvr_list2[0], &bom_line)); //顶层bom获取 ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags)); for (int i = 0; i < c_line_count; i++) { char* ifpBom, *matnrNo, *name; @@ -1259,6 +1516,7 @@ void startUpdate(EBomUpBean upBean, tag_t bom_line, int len, tag_t dcproxy,tag_t //移除PBOM printf("zt2_MaterialNo ===>%s ifpBom==>%s\n", matnrNo, ifpBom); if (strcmp(ifpBom, "P") == 0) { + //A项线圈是不带P的 matnrVec.push_back(matnrNo); pBomMap[matnrNo] = c_line_tag; //BOM_line_cut(c_line_tag); @@ -1277,6 +1535,7 @@ void startUpdate(EBomUpBean upBean, tag_t bom_line, int len, tag_t dcproxy,tag_t int c_line_countXq = 0; ITKCALL(BOM_line_ask_all_child_lines(xqLine, &c_line_countXq, &c_xqLine_tags)); printf("c_line_countXq===>%d\n", c_line_countXq); + //移除原来的 -> 进行对比是否有修改 for (int j = 0; j < c_line_countXq; j++) { BOM_line_cut(c_xqLine_tags[j]); } @@ -1287,15 +1546,9 @@ void startUpdate(EBomUpBean upBean, tag_t bom_line, int len, tag_t dcproxy,tag_t lastFlag = true; } addToAmatnrUp(vecs, len, newPAmatnr, lastFlag); - /*for (int i = 0; i < vecs.size(); i++) { - EBomUpBean cupBean = vecs[i]; - if (std::find(xqTagVec.begin(), xqTagVec.end(), cupBean.matnrNo) != xqTagVec.end()) { - tag_t c_line_tag = pBomMap[cupBean.matnrNo]; - } - }*/ - } if (xqTagVec.size() == 0) { + //不是线圈 移除后复制 printf("vecs===>%d\n", vecs.size()); for (int i = 0; i < vecs.size(); i++) { EBomUpBean cupBean = vecs[i]; @@ -1305,40 +1558,11 @@ void startUpdate(EBomUpBean upBean, tag_t bom_line, int len, tag_t dcproxy,tag_t tag_t c_Rev, bomView = NULLTAG; ITKCALL(AOM_ask_value_tag(c_line_tag, "bl_line_object", &c_Rev)); boolean flagAs = false; - { - int structs = 0, statusNum = 0; - tag_t* structure_revisions, *release_status_list; - AOM_ask_value_tags(c_Rev, "structure_revisions", &structs, &structure_revisions); - if (structs > 0) { - AOM_ask_value_tags(structure_revisions[0], "release_status_list", &statusNum, &release_status_list); - if (statusNum > 0) { - tag_t* mantrsAs, dsuser, pBomTop, *bvr_list; - int revNum = 0, num = 0, bvr_count = 0; - ITEM_copy_rev(c_Rev, NULL, &pBomTop); - flagAs = true; - AOM_ask_value_tags(c_Rev, "TC_Is_Represented_By", &num, &mantrsAs); - AOM_ask_value_tag(mantrsAs[0], "owning_user", &dsuser); - tag_t defGroup; - ITKCALL(AOM_ask_value_tag(dsuser, "default_group", &defGroup)); - ITKCALL(AOM_set_ownership(pBomTop, dsuser, defGroup)); - if (num > 0) { - AOM_ask_value_tags(pBomTop, "structure_revisions", &revNum, &structure_revisions); - if (revNum > 0) { - ITKCALL(AOM_set_ownership(structure_revisions[0], dsuser, defGroup)); - } - } - (BOM_create_window(&bomView)); - (ITEM_rev_list_bom_view_revs(pBomTop, &bvr_count, &bvr_list)); - printf("bvr_count=%d \n", bvr_count); - if (bvr_count == 0) { - //errBuff.append("不存在EBOM请检查\n"); - } - ITKCALL(BOM_set_window_top_line_bvr(bomView, bvr_list[0], &c_line_tag)); //顶层bom获取 - } - } - } + + tag_t childPTag; printf("matnrVec ===>%s\n", cupBean.matnrNo.c_str()); - startUpdate(cupBean, c_line_tag, len, dcproxy, ebom_window2); + ITKCALL(AOM_ask_value_tag(c_line_tag, BL_LINE_OBJECT, &childPTag)); + startUpdate(cupBean, childPTag, len, dcproxy, isTop, hasChange, saveAsMap); if (bomView != NULLTAG && flagAs) { BOM_save_window(bomView); BOM_close_window(bomView); @@ -1347,10 +1571,15 @@ void startUpdate(EBomUpBean upBean, tag_t bom_line, int len, tag_t dcproxy,tag_t else { boolean flagLc = false; char* seq; + printf(" pBomUid ===>%s \n", pBomUid); printf("matnrVecNotP===>%s\n", cupBean.matnrNo.c_str()); tag_t cline = cupBean.bomline; tag_t newChild; ITKCALL(BOM_line_copy(bom_line, cline, NULLTAG, &newChild)); + if (newChild == NULLTAG) { + printf(" newChild === NULLTAG 没有权限修改BOM视图 \n"); + continue; + } AOM_ask_value_string(cline, "bl_sequence_no", &seq); AOM_lock(newChild); AOM_set_value_string(newChild, "bl_sequence_no", seq); @@ -1363,14 +1592,15 @@ void startUpdate(EBomUpBean upBean, tag_t bom_line, int len, tag_t dcproxy,tag_t //线圈装配 for (int j = 0; j < ccBeans.size(); j++) { EBomUpBean ccBean = ccBeans[j]; + //创建线圈对象 if (ccBean.c_lines.size() > 0) { //要另存操作 char* uid; tag_t cc_Rev; - tag_t newPrev = saveAsUpdate(c_Rev, newChild); + tag_t newPrev = saveAsUpdate(c_Rev, newChild); //另存调压线圈装配 ITKCALL(AOM_ask_value_tag(ccBean.bomline, "bl_line_object", &cc_Rev)); ITK__convert_tag_to_uid(cc_Rev, &uid); - tag_t cc_PRev = saveAsUpdate(cc_Rev, uid, newPrev); + tag_t cc_PRev = saveAsUpdate(cc_Rev, uid, newPrev);//另存调压线圈 createAXxq(cc_Rev, cc_PRev, len, dcproxy); } } @@ -1380,7 +1610,13 @@ void startUpdate(EBomUpBean upBean, tag_t bom_line, int len, tag_t dcproxy,tag_t //移除所有非P 再从EBOM复制 ITKCALL(BOM_save_window(ebom_window2)); + ITKCALL(BOM_close_window(ebom_window2)); } +/** + * 复制BOM信息 + * @param matnrTop 旧 + * @param otherPbom 新 + */ void copyBomLine(tag_t matnrTop, tag_t otherPbom) { tag_t ebom_window, ebom_window2, *bvr_list, *bvr_list2, bom_line, bom_line2, *c_line_tags, *c_line_tags2; int bvr_count = 0, bvr_count2 = 0, c_line_count, c_line_count2; @@ -1432,6 +1668,8 @@ void copyBomLine(tag_t matnrTop, tag_t otherPbom) { BOM_close_window(ebom_window2); BOM_close_window(ebom_window); } + +//EBOM转PBOM int EbomToPMethod(void* returnValue) { int ifail = ITK_ok; char *sql = NULL, *revUid; @@ -1439,6 +1677,7 @@ int EbomToPMethod(void* returnValue) { ITKCALL(ifail = USERARG_get_string_argument(&revUid)); ITK__convert_uid_to_tag(revUid, &matnrRev1); + //链接mdm数据库获取物料申请需要的信息 if (open("PLMUser", "PLMUser", "BDP2020", "10.128.20.35")) { printf("链接SQLSERVER失败\n"); } @@ -1478,7 +1717,6 @@ int EbomToPMethod(void* returnValue) { prds.push_back(prd); } } - close(); //遍历design BOM 获取物料信息 int bvr_count = 0, c_line_count; @@ -1489,6 +1727,7 @@ int EbomToPMethod(void* returnValue) { int num = 0,num2=0; tag_t* mantrs, designRev; string errBuff; + //获取E物料的图纸 ITKCALL(AOM_ask_value_tags(matnrRev1, "TC_Is_Represented_By", &num, &mantrs)); int len = 1; if (num >= 1) { @@ -1624,6 +1863,7 @@ int EbomToPMethod(void* returnValue) { replaceBom(beans[t], map, len, dcproxy, topPrev); } DisConnServer(); + //多个产成品直接复制BOM for (it2 = wlbmMap.begin(); it2 != wlbmMap.end(); it2++) { string ss = it2->first; tag_t eMantr = wlbmMap[ss].eMantr; @@ -1672,7 +1912,7 @@ int EbomToPMethod(void* returnValue) { } } else { - //更新逻辑 遍历Ebom 不带P的和带P的 目前更新逻辑移除所有重新添加 + //更新逻辑 遍历Ebom 不带P的和带P的 目前更新逻辑移除所有重新添加 2024/1/15增加对比逻辑 tag_t matnrTop = NULLTAG; tag_t pBomTop = NULLTAG; map::iterator it; @@ -1686,29 +1926,6 @@ int EbomToPMethod(void* returnValue) { matnrTop = tagBean.eMantr; pBomTop = tagBean.pMantr; //判断版本视图是否发布,如果发布了,升版 - int structs = 0, statusNum = 0; - tag_t *structure_revisions, *release_status_list; - AOM_ask_value_tags(pBomTop, "structure_revisions", &structs, &structure_revisions); - if (structs > 0) { - AOM_ask_value_tags(structure_revisions[0], "release_status_list", &statusNum, &release_status_list); - if (statusNum > 0) { - tag_t *mantrsAs, dsuser; - int revNum; - ITEM_copy_rev(pBomTop, NULL, &pBomTop); - AOM_ask_value_tags(matnrTop, "TC_Is_Represented_By", &num, &mantrsAs); - AOM_ask_value_tag(mantrsAs[0], "owning_user", &dsuser); - tag_t defGroup; - ITKCALL(AOM_ask_value_tag(dsuser, "default_group", &defGroup)); - ITKCALL(AOM_set_ownership(pBomTop, dsuser, defGroup)); - if (num > 0) { - AOM_ask_value_tags(pBomTop, "structure_revisions", &revNum, &structure_revisions); - if (revNum > 0) { - ITKCALL(AOM_set_ownership(structure_revisions[0], dsuser, defGroup)); - } - } - - } - } break; } (BOM_create_window(&ebom_window)); @@ -1721,20 +1938,10 @@ int EbomToPMethod(void* returnValue) { printf("顶层bom获取\n"); EBomUpBean upBean; upBean.bomline = bom_line; + //遍历获取EBOM信息 updatePbomCycle(bom_line, errBuff, len, upBean); - tag_t ebom_window2, *bvr_list2, bom_line2; - int bvr_count2 = 0; - char* revIdP; - (BOM_create_window(&ebom_window2)); - (ITEM_rev_list_bom_view_revs(pBomTop, &bvr_count2, &bvr_list2)); - AOM_ask_value_string(pBomTop, "item_revision_id", &revIdP); - printf("bvr_count=%d revIdP==>%s \n", bvr_count2, revIdP); - if (bvr_count2 == 0) { - errBuff.append("不存在EBOM请检查\n"); - } - ITKCALL(BOM_set_window_top_line_bvr(ebom_window2, bvr_list2[0], &bom_line2)); //顶层bom获取 - //AOM_lock(ebom_window2); + //ITKCALL(BOM_set_window_top_line_bvr(ebom_window2, bvr_list2[0], &bom_line2)); //顶层bom获取 int url_num = 0; char** url_vals = NULL; PREF_ask_char_values("database_tc", &url_num, &url_vals); @@ -1746,12 +1953,15 @@ int EbomToPMethod(void* returnValue) { printf("提示:中间数据表访问失败\n"); ifail = 1; } - startUpdate(upBean, bom_line2, len, dcproxy, ebom_window2); + //更新PBOM + string hasChange; + map saveAsMap; + startUpdate(upBean, pBomTop, len, dcproxy, true, hasChange, saveAsMap); DisConnServer(); - - ITKCALL(BOM_save_window(ebom_window2)); - //ITKCALL(AOM_unlock(ebom_window2)); - ITKCALL(BOM_close_window(ebom_window2)); + //保存PBOM + //ITKCALL(BOM_save_window(ebom_window2)); + ////ITKCALL(AOM_unlock(ebom_window2)); + //ITKCALL(BOM_close_window(ebom_window2)); ITKCALL(BOM_close_window(ebom_window)); printf("keyNum===>%s\n", keyNum.c_str()); @@ -1768,7 +1978,7 @@ int EbomToPMethod(void* returnValue) { int structs = 0, statusNum = 0; tag_t* structure_revisions, *release_status_list; AOM_ask_value_tags(newRev, "structure_revisions", &structs, &structure_revisions); - if (structs > 0) { + if (structs > 0 && hasChange.compare("true") != 0) { AOM_ask_value_tags(structure_revisions[0], "release_status_list", &statusNum, &release_status_list); if (statusNum > 0) { int revNum = 0; diff --git a/General/General/General.vcxproj b/General/General/General.vcxproj index c880789..1e34225 100644 --- a/General/General/General.vcxproj +++ b/General/General/General.vcxproj @@ -164,6 +164,7 @@ + @@ -182,6 +183,7 @@ + @@ -214,10 +216,12 @@ + + diff --git a/General/General/General.vcxproj.filters b/General/General/General.vcxproj.filters index bc08890..10ff400 100644 --- a/General/General/General.vcxproj.filters +++ b/General/General/General.vcxproj.filters @@ -78,6 +78,9 @@ 澶存枃浠 + + 澶存枃浠 + @@ -206,5 +209,14 @@ 婧愭枃浠 + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + \ No newline at end of file diff --git a/General/General/ProjectSavePost.cxx b/General/General/ProjectSavePost.cxx new file mode 100644 index 0000000..9a667b6 --- /dev/null +++ b/General/General/ProjectSavePost.cxx @@ -0,0 +1,157 @@ +#include +#include +#include +#include "epm_handler_common.h" +#include +#include +#include +#include +#include "CRUL_server_call_httpserver.h" +#include "cJSON.h" + +tag_t getCcpFolder(tag_t projectItem) { + tag_t *folders; + int num = 0; + tag_t ccpFolder = NULLTAG; + AOM_ask_value_tags(projectItem, "IMAN_reference", &num, &folders); + for (int i = 0; i < num; i++) { + char *folderName; + AOM_ask_value_string(folders[i], "object_name", &folderName); + if (strcmp(folderName, "项目启动") == 0) { + int num2 = 0; + tag_t *folders2; + AOM_ask_value_tags(folders[i], "contents", &num2, &folders2); + for (int j = 0; j < num2; j++){ + char *folderName2; + AOM_ask_value_string(folders2[j], "object_name", &folderName2); + if (strcmp(folderName2, "产成品") == 0) { + ccpFolder = folders2[j]; + } + } + break; + } + } + return ccpFolder; +} + +char* askDateVal(tag_t new_rev_tag,char *propName) { //"zt2_DeliveryDate" + date_t deliveryDate; + AOM_ask_value_date(new_rev_tag, propName, &deliveryDate); + char date[128] = ""; + sprintf_s(date, "%04d%02d%02d", deliveryDate.year, deliveryDate.month + 1, deliveryDate.day); + return date; +} +/* + 添加项目的属性到JSON +*/ +void addStringJson(cJSON *paramValue, char *propName, tag_t project, char*piName) { + char *propVal; + AOM_UIF_ask_value(project, propName, &propVal); + cJSON_AddStringToObject(paramValue, piName, propVal); +} + +int CHINT_SavePost(METHOD_message_t* msg, va_list args) { + + tag_t new_rev_tag = va_arg(args, tag_t); + //ZT2_ProjectItem + tag_t userTag; + char *objType, *item_id, *zt2_ProjectNo, *object_name, *zt2_WBSNo, *userId; + AOM_ask_value_string(new_rev_tag, "object_type", &objType); + if (strcmp(objType, "ZT2_ProjectItem") == 0) { + + int num = 0, taskNum = 0; + tag_t *ccpTags, *ztTasks; + AOM_ask_value_string(new_rev_tag, "item_id", &item_id); + AOM_ask_value_string(new_rev_tag, "zt2_ProjectNo", &zt2_ProjectNo); + AOM_ask_value_string(new_rev_tag, "object_name", &object_name); + AOM_ask_value_string(new_rev_tag, WBSNO, &zt2_WBSNo); + AOM_ask_value_tag(new_rev_tag, "owning_user", &userTag); + POM_ask_user_id(userTag, &userId); + char *date = askDateVal(new_rev_tag,"zt2_DeliveryDate");//"zt2_DeliveryDate" + printf("item_id===>%s \n", item_id); + cJSON* paramValue = cJSON_CreateObject(); + //新增属性 + cJSON_AddStringToObject(paramValue, "tcid", item_id); + cJSON_AddStringToObject(paramValue, "objectName", object_name); + cJSON_AddStringToObject(paramValue, "owningUser", userId); + cJSON_AddStringToObject(paramValue, "zt2WBSNo", zt2_WBSNo); + cJSON_AddStringToObject(paramValue, "zt2ProjectNo", zt2_ProjectNo); + cJSON_AddStringToObject(paramValue, "zt2DeliveryDate", date); + addStringJson(paramValue, "zt2_ShortName", new_rev_tag, "zt2ShortName"); + addStringJson(paramValue, "zt2_MaterialNo", new_rev_tag, "ztMaterialNo"); + addStringJson(paramValue, "zt2_ProductModel", new_rev_tag, "zt2ProductModel"); + addStringJson(paramValue, "zt2_ProjectCode", new_rev_tag, "zt2ProjectCode"); + addStringJson(paramValue, "zt2_ProjectPhase", new_rev_tag, "zt2ProjectPhase"); + addStringJson(paramValue, "zt2_DrawingNo", new_rev_tag, "zt2DrawingNo"); + addStringJson(paramValue, "zt2_ProjectPhase", new_rev_tag, "zt2ProjectPhase"); + addStringJson(paramValue, "zt2_model", new_rev_tag, "zt2model"); + + addStringJson(paramValue, "zt2_Code", new_rev_tag, "zt2Code"); + addStringJson(paramValue, "zt2_Numberofunits", new_rev_tag, "zt2Numberofunits"); + addStringJson(paramValue, "zt2_Productionscheduling", new_rev_tag, "zt2Productionscheduling"); + addStringJson(paramValue, "zt2_agreementsigned", new_rev_tag, "zt2agreementsigned"); + addStringJson(paramValue, "zt2_classification", new_rev_tag, "zt2classification"); + addStringJson(paramValue, "zt2_assessor", new_rev_tag, "zt2assessor"); + addStringJson(paramValue, "zt2_Productcategory", new_rev_tag, "zt2Productcategory"); + addStringJson(paramValue, "zt2_BElectromagnetic", new_rev_tag, "zt2BElectromagnetic"); + + addStringJson(paramValue, "zt2_StructuralSupervisor", new_rev_tag, "zt2StructuralSupervisor"); + addStringJson(paramValue, "zt2_schedule", new_rev_tag, "zt2schedule"); + addStringJson(paramValue, "zt2_month", new_rev_tag, "zt2month"); + addStringJson(paramValue, "zt2_notes", new_rev_tag, "zt2notes"); + tag_t ccpFolder = getCcpFolder(new_rev_tag); + AOM_ask_value_tags(ccpFolder, "contents", &num, &ccpTags); + cJSON* ccpValues = cJSON_CreateArray(); + //产成品信息 + for (int i = 0; i < num; i++) { + tag_t ccpRev; + char *ccpName, *ccpWbs, *ccpMatnrNo, *ccpQty; + cJSON* ccpValue = cJSON_CreateObject(); + ITEM_ask_latest_rev(ccpTags[i], &ccpRev); + AOM_ask_value_string(ccpRev, "zt2_Quantity", &ccpQty); + AOM_ask_value_string(ccpRev, "zt2_MaterialNo", &ccpMatnrNo); + AOM_ask_value_string(ccpRev, "object_name", &ccpName); + AOM_ask_value_string(ccpRev, "zt2_WBSNo", &ccpWbs); + cJSON_AddStringToObject(ccpValue, "objectname", ccpName); + cJSON_AddStringToObject(ccpValue, "ztMaterialNo", ccpMatnrNo); + string qtyBase = ccpQty; + if (strcmp(ccpQty, "") == 0) { + qtyBase = "1"; + } + cJSON_AddStringToObject(ccpValue, "ztQuantity", qtyBase.c_str()); + cJSON_AddStringToObject(ccpValue, "ztWBSNo", ccpWbs); + cJSON_AddStringToObject(ccpValue, "ztFactory", "M060"); + cJSON_AddItemToArray(ccpValues, ccpValue); + } + //APS信息 + cJSON_AddItemToObject(paramValue, "zt2productinformation", ccpValues); + AOM_ask_value_tags(new_rev_tag, "zt2_Tasks", &taskNum, &ztTasks); + cJSON* taskValues = cJSON_CreateArray(); + for (int i = 0; i < taskNum; i++) { + cJSON* taskValue = cJSON_CreateObject(); + char *activeName, *activeNo; + AOM_ask_value_string(ztTasks[i], "zt2_activeName", &activeName); + AOM_ask_value_string(ztTasks[i], "zt2_activeNo", &activeNo); + char *plansStart = askDateVal(ztTasks[i], "zt2_plansStart"); + char *plansEnd = askDateVal(ztTasks[i], "zt2_plansEnd"); + cJSON_AddStringToObject(taskValue, "ztactiveName", activeName); + cJSON_AddStringToObject(taskValue, "ztnetWorkNo", activeNo); + cJSON_AddStringToObject(taskValue, "ztplansStart", plansStart); + cJSON_AddStringToObject(taskValue, "ztplansEnd", plansEnd); + cJSON_AddItemToArray(taskValues, taskValue); + } + cJSON_AddItemToObject(paramValue, "zt2APSMasterPlan", taskValues); + char *json_to_char = cJSON_PrintUnformatted(paramValue); + printf("json_to_char===>%s\n", json_to_char); + char* url; + PREF_ask_char_value("CHINT_PIUrl", 0, &url); + string ypUrl = url; + ypUrl = ypUrl.append("/api/open/project/create"); + printf("ypUrl ==>%s\n", ypUrl.c_str()); + updatePiProject(json_to_char, ypUrl); + //Request request = new Request.Builder().url(preference + "/api/open/project/create") + } + + + return ITK_ok; +} \ No newline at end of file diff --git a/General/General/chintSignChange.cpp b/General/General/chintSignChange.cpp index f9046d8..6a9cf7f 100644 --- a/General/General/chintSignChange.cpp +++ b/General/General/chintSignChange.cpp @@ -473,1457 +473,6 @@ int writeToExcel2(int page,tag_t excelTag,const char *zt2_Design,const char *zt2 return 0; } -struct NodeBean -{ - int topNum = 1; - int packNum = 0; - string revUid; - tag_t designRev; - tag_t mantr = NULLTAG; - string bl_quantity; - char* bl_plmxml_occ_xform; - string bl_sequence_no; - vector childs; - vector ccps; - int xnNum = 1; -}; -boolean isTcm(tag_t mantr) { - int releaseCount = 0; - tag_t* releaseTags = NULL; - //判断子件是否发布 - AOM_ask_value_tags(mantr, "release_status_list", &releaseCount, &releaseTags); - if (releaseCount > 0) { - return true; - } - else { - return false; - } -} -bool myCompare(string o1, string o2) { - if (o1.rfind("3", 0) == 0) { - cout << o1.c_str() << endl; - return 1; - } - return 0; -} -vector KeySet(map test) -{ - vector keys; - for (map::iterator it = test.begin(); it != test.end(); ++it) { - keys.push_back(it->first); - } - return keys; -} -string& replace_all2(string& str, const string& old_value, const string& new_value) -{ - if (strstr(str.c_str(), old_value.c_str()) != NULL) { - vector type_vec; - Split(str.c_str(), old_value.c_str(), type_vec); - char new_str[512] = "\0"; - for (int i = 0; i < type_vec.size(); i++) - { - strcat(new_str, type_vec[i].c_str()); - if (i < type_vec.size() - 1) { - strcat(new_str, new_value.c_str()); - } - } - string new_value(new_str); - str = new_value.c_str(); - } - return str; -} -tag_t getSapPart(tag_t designRevLine, tag_t designRev, string& errBuff, NodeBean& bean) { - int num = 0; - tag_t* mantrs; - char *type,*item_id; - AOM_ask_value_string(designRev,"object_type",&type); - AOM_ask_value_string(designRev, "item_id", &item_id); - if (strcmp(type, "Part Revision") == 0) { - return designRev; - } - ITKCALL(AOM_ask_value_tags(designRev, "representation_for", &num, &mantrs)); - //printf("num===>%d\n", num); - vector parts; - if (strstr(item_id, "1ZDB300000P") != NULL) { - map partsCcp; - for (int i = 0; i < num; i++) { - char* type, *zt2_ifpbom,*itemId; - AOM_ask_value_string(mantrs[i], "object_type", &type); - AOM_ask_value_string(mantrs[i], "zt2_ifpbom", &zt2_ifpbom); - AOM_ask_value_string(mantrs[i], "item_id", &itemId); - if (strstr(type, "Part") != NULL && strcmp(zt2_ifpbom, "P") != 0) { // - tag_t matnrItem; - ITEM_ask_item_of_rev(mantrs[i], &matnrItem); - partsCcp[itemId] = matnrItem; - //partsCcp.push_back(); - /*if (parts.size()==0) { - parts.push_back(mantrs[i]); - } - else { - printf("===========\n"); - bean.ccps.push_back(mantrs[i]); - }*/ - } - } - map::iterator it; - for (it = partsCcp.begin(); it != partsCcp.end(); it++) { - string s = it->first; - tag_t partLast = partsCcp[s],partRevLast; - ITEM_ask_latest_rev(partLast,&partRevLast); - if (parts.size() == 0) { - parts.push_back(partRevLast); - } - else { - printf("===========\n"); - bean.ccps.push_back(partRevLast); - } - } - } - else { - for (int i = 0; i < num; i++) { - char* type, *zt2_ifpbom; - AOM_ask_value_string(mantrs[i], "object_type", &type); - AOM_ask_value_string(mantrs[i], "zt2_ifpbom", &zt2_ifpbom); - if (strstr(type, "Part") != NULL && strcmp(zt2_ifpbom, "P") != 0) { // - parts.push_back(mantrs[i]); - } - } - } - if (parts.size() == 1) { - return parts[0]; - } - string searchId; - char* id, *zt2_TYJNo, *spec, *zt2_Diagram; - AOM_ask_value_string(designRev, "zt2_Diagram", &zt2_Diagram); - AOM_ask_value_string(designRev, "item_id", &id); - //AOM_ask_value_string(designRev, "zt2_DrawingNo", &zt2_DrawingNo); - /*if (strcmp(zt2_DrawingNo,"") != 0 && strcmp(zt2_DrawingNo, id) != 0) { - searchId = zt2_DrawingNo; - } - else {*/ - searchId = id; - //} - AOM_ask_value_string(designRevLine, "ZT2_TYSpecifications", &zt2_TYJNo); - AOM_ask_value_string(designRev, "zt2_Specifications", &spec); - if (strcmp(zt2_TYJNo, "") != 0) { - string qryVal; - tag_t query = NULLTAG, *tags; - map map_revs; - qryVal.append("* ").append(zt2_TYJNo).append("*"); - //fields.put("描述", "*" + item_id + "*" + zt2_TYJNo + "*"); - ITKCALL(QRY_find2("chint_query_material_test", &query)); - char* qry_entries[2] = { "描述" ,"关联的图号" }, *qry_values[2] = { (char *)qryVal.c_str(),id }; - int n_found; - ITKCALL(QRY_execute(query, 2, qry_entries, qry_values, &n_found, &tags)); - printf("n_found===>%d\n", n_found); - for (int t = 0; t < n_found; t++) { - tag_t rev = tags[t]; - if (isTcm(rev)) { - char* zt2_MaterialNo; - AOM_ask_value_string(rev, "zt2_MaterialNo", &zt2_MaterialNo); - map_revs[zt2_MaterialNo] = rev; - } - } - vector keySet = KeySet(map_revs); - sort(keySet.begin(), keySet.end(), myCompare); - for (int i = 0; i < keySet.size(); i++) { - string materialNo = keySet[i]; - string sql_query = "select FeatureList from CcemVW_GoodsFeature where GoodsCode ='"; - sql_query.append(materialNo).append("'"); - printf("sql_query===>%s\n", sql_query.c_str()); - int outputColumn = 0, outputValueCount = 0; - char*** outputValue = NULL; - ado_QuerySQLNoInputParam((char*)sql_query.c_str(), &outputColumn, &outputValueCount, &outputValue); - for (int j = 0; j < outputValueCount; j++) { - char* val = outputValue[j][0]; - vector vals; - Split(val, ",", vals); - for (int k = 0; k < vals.size(); k++) { - printf("vals===>%s\n", vals[k].c_str()); - if (vals[k].rfind("F064:", 0) == 0) { - string temp = replace_all2(vals[k], "F064:", ""); - printf("temp===>%s\n", temp.c_str()); - if (strstr(zt2_TYJNo, temp.c_str()) != NULL) { - return map_revs[materialNo]; - } - break; - } - } - } - } - if (!strcmp(zt2_Diagram, "Y") == 0 && !strcmp(zt2_Diagram, "是") == 0) { - string buffErr = ""; - buffErr.append("缺少物料编码[找不到与通用件规格相匹配的物料-(*").append(searchId) - .append("*").append(zt2_TYJNo).append(")];\n"); - size_t found = errBuff.find(buffErr); - if (found == std::string::npos) { - errBuff.append(buffErr); - } - return NULLTAG; - } - } - - for (int i = 0; i < parts.size(); i++) { - tag_t part = parts[i]; - char* specPart; - AOM_ask_value_string(part, "zt2_Specifications", &specPart); - if (strcmp(specPart, spec) == 0) { - return part; - } - /*String spec2 = parts.get(i).getProperty("zt2_Specifications"); - if (spec.equals(spec2)) { - return parts.get(i); - }*/ - } - if (!strcmp(zt2_Diagram, "Y") == 0 && !strcmp(zt2_Diagram, "是") == 0) { - //errBuff.append("缺少物料编码[找不到相同规格的物料(").append(spec).append(")];"); - string buffErr = ""; - buffErr.append("缺少物料编码[找不到相同规格的物料(").append(spec).append(")];"); - size_t found = errBuff.find(buffErr); - if (found == std::string::npos) { - errBuff.append(buffErr); - } - return NULLTAG; - } - - return NULLTAG; - /*else{ - return NULLTAG; - }*/ -} -void askLineVal(NodeBean& bean, tag_t bom_line, tag_t designRev, string& errBuff,boolean &flagMat) { - char* bl_quantity, *bl_plmxml_occ_xform, *bl_sequence_no,*sffc; - ITKCALL(AOM_ask_value_string(bom_line, "bl_sequence_no", &bl_sequence_no)); - //printf("revUid===>%s\n", bl_sequence_no); - ITKCALL(AOM_ask_value_string(bom_line, "bl_quantity", &bl_quantity)); - //printf("revUid===>%s\n", bl_quantity); - ITKCALL(AOM_ask_value_string(bom_line, "bl_plmxml_occ_xform", &bl_plmxml_occ_xform)); - //printf("revUid===>%s\n", bl_plmxml_occ_xform); - if (strcmp(bl_quantity, "") == 0) { - bl_quantity = "1"; - } - - bean.bl_plmxml_occ_xform = bl_plmxml_occ_xform; - if (bean.xnNum > 1) { - int qtyCut = atoi(bl_quantity); - bean.bl_quantity = to_string(qtyCut*bean.xnNum); - } - else { - bean.bl_quantity = bl_quantity; - } - if (strcmp(bean.bl_sequence_no.c_str(), "") == 0) { - bean.bl_sequence_no = bl_sequence_no; - } - - tag_t part = getSapPart(bom_line, designRev, errBuff, bean); - //printf("11111111\n"); - if (part != NULLTAG) { - //BOM_writer - char* name,*partId,**sealeds,**factorys,*matnr,**procureType; - AOM_refresh(part, false); - AOM_ask_value_string(part, "object_name", &name); - printf("name%s\n", name); - int cnt2,numFac, cnt3; - ITKCALL(AOM_ask_value_string(part, "item_id", &partId)); - AOM_ask_value_string(part, "zt2_MaterialNo", &matnr); - if (strcmp(matnr, "") == 0) { - string buffErr = ""; - buffErr.append("物料:").append(partId).append("/").append(name).append("没有物料编码.\n"); - size_t found = errBuff.find(buffErr); - if (found == std::string::npos) { - errBuff.append(buffErr); - } - //errBuff.append("物料:").append(partId).append("/").append(name).append("没有物料编码.\n"); - //return; - } - boolean numFlag = true; - AOM_ask_value_strings(part, "zt2_SZSealedornot", &cnt2, &sealeds); - AOM_ask_value_strings(part, "zt2_SZFactory", &numFac, &factorys); - AOM_ask_value_strings(part, "zt2_SZProcuretype", &cnt3, &procureType); //包含自制 - for (int i = 0; i < numFac; i++) { - if (strcmp(factorys[i], "M060") == 0) { - numFlag = false; - } - if (strcmp(factorys[i],"M060") == 0 && cnt2>i) { - if (strcmp(sealeds[i],"Y") == 0) { - //errBuff.append("物料:").append(partId).append("/").append(name).append("已封存无法转换EBOM.\n"); - string buffErr = ""; - buffErr.append("物料:").append(partId).append("/").append(name).append("已封存无法转换EBOM.\n"); - size_t found = errBuff.find(buffErr); - if (found == std::string::npos) { - errBuff.append(buffErr); - } - } - if (cnt3 > i && strstr(procureType[i], "自制") != NULL) { - flagMat = true; - } - } - } - if (numFlag && (strstr(partId,"2ZD")!=NULL|| strstr(partId, "4ZD") != NULL)) { - string buffErr = ""; - buffErr.append("物料:").append(partId).append("/").append(name).append("物料视图没有维护,请检查.\n"); - size_t found = errBuff.find(buffErr); - if (found == std::string::npos) { - errBuff.append(buffErr); - } - //errBuff.append("物料:").append(partId).append("/").append(name).append("物料视图没有维护,请检查.\n"); - } - ITKCALL(AOM_ask_value_string(part, "zt2_State", &sffc)); - if (strcmp(sffc, "D1") == 0 || strcmp(sffc, "封存") == 0) { - string buffErr = ""; - buffErr.append("物料:").append(partId).append("/").append(name).append("已封存无法转换EBOM.\n"); - size_t found = errBuff.find(buffErr); - if (found == std::string::npos) { - errBuff.append(buffErr); - } - } - bean.mantr = part; - } - else { - char *partId,*name; - AOM_ask_value_string(designRev,"item_id",&partId); - AOM_ask_value_string(designRev, "object_name", &name); - - string buffErr = ""; - buffErr.append("图纸:").append(partId).append("/").append(name).append("下未找到物料对象.\n"); - size_t found = errBuff.find(buffErr); - if (found == std::string::npos) { - errBuff.append(buffErr); - } - // errBuff.append("图纸:").append(partId).append("/").append(name).append("下未找到物料对象.\n"); - } -} -string getTyjZl(tag_t bom_line,string materialutilization,tag_t desginRev,string &errMessage) { - char *ZT2_TYSpecifications,*ZT2_TYWeight,*item_id; - AOM_ask_value_string(bom_line, "item_id", &item_id); - AOM_ask_value_string(bom_line,"ZT2_TYSpecifications",&ZT2_TYSpecifications); - double lyl = 0.85; - char strff[21]; - if (!materialutilization.empty()) { - lyl = stod(materialutilization); - } - if (strcmp(ZT2_TYSpecifications,"")==0) { - double weight = 0; - AOM_ask_value_double(desginRev,"zt2_DesignWeight",&weight); - if (weight == 0) { - errMessage.append(item_id).append("未填写设计重量;\n"); - return "0"; - } - double two = weight / lyl; - sprintf(strff, "%.3f", two); - } - else { - AOM_ask_value_string(bom_line, "ZT2_TYWeight", &ZT2_TYWeight); - if (strcmp(ZT2_TYWeight, "") == 0) { - errMessage.append(item_id).append("未填写通用件重量;\n"); - return "0"; - } - double weight = stod(ZT2_TYWeight); - double two = weight / lyl; - sprintf(strff, "%.3f", two); - } - return strff; -} - -void getRemarkMsg(string remark, int len,string &errBuff,char*bl_quantity,char* pId, - char*c_pId,char*bl_line_name) { - char* idss[5] = { (char*)"A",(char*)"B",(char*)"C",(char*)"D",(char*)"E" }; - //tring x = "9A9.1B2C3"; - string markMsg = ""; - for (int i = 0; i < len; i++) { - if (strstr(remark.c_str(), idss[i]) != NULL) { - markMsg.append(idss[i]); - } - } - if (markMsg.length() == 0) { - int blQty = atoi(bl_quantity); - if (blQty % len != 0 - && strstr(bl_line_name, "线") == NULL) { - errBuff.append("图纸:").append(pId).append("下子件").append(c_pId) - .append("无法整除,请检查。").append("\n"); - } - } - else { - int blQty = atoi(bl_quantity); - if (blQty % markMsg.length() != 0 - && strstr(bl_line_name, "线") == NULL) { - errBuff.append("图纸:").append(pId).append("下子件").append(c_pId) - .append("无法整除,请检查。").append("\n"); - } - } -} - -int xsLen = 0; -void getAllXnj(vector xnzjbVec, int maxNum, int &xxt, - string& errBuff, string dbName, NodeBean& pBean, int qtyXn,char *loginUserId); -void getAllXnj(vector xnzjbVec, int maxNum, int &xxt, - string& errBuff, string dbName, NodeBean& pBean, int qtyXn, vector idVector); -void recyReadBom(tag_t bom_line, NodeBean& pBean, string& errBuff,string dbName, char *loginUserId) -{ - int c_line_count; - char* uid, *type, *zt2_Diagram,*source,*itemId,*object_name; - //图纸版本、子行 - tag_t designRev, *c_line_tags; - ITKCALL(AOM_ask_value_tag(bom_line, "bl_line_object", &designRev)); - //printf("1222"); - ITK__convert_tag_to_uid(designRev, &uid); - //printf("revUid===>%s\n", uid); - pBean.revUid = uid; - pBean.designRev = designRev; - ITKCALL(AOM_ask_value_string(designRev, "object_type", &type)); - ITKCALL(AOM_ask_value_string(designRev, "item_id", &itemId)); - ITKCALL(AOM_ask_value_string(designRev, "object_name", &object_name)); - //printf("type===>%s\n", type); - if (strcmp(type, "ZT2_Design3DRevision") == 0) { - AOM_ask_value_string(designRev, "zt2_Diagram", &zt2_Diagram); - if (strcmp(zt2_Diagram, "Y") == 0 || strcmp(zt2_Diagram, "是") == 0) { - return; - } - } - //判断类型是否为 Part Revision ZT2_Design3DRevision ZT2_XNZJB 不是报错 - if (strcmp(type, "ZT2_Design3DRevision") != 0 - && strcmp(type, "Part Revision") != 0 && strcmp(type, "ZT2_XNZJBRevision") != 0) { - string buffErr = ""; - buffErr.append("对象类型异常:").append(itemId).append("/").append(object_name).append("/").append(type).append("\n"); - size_t found = errBuff.find(buffErr); - if (found == std::string::npos) { - errBuff.append(buffErr); - } - return; - } - - boolean flagMat = false; - askLineVal(pBean, bom_line, designRev, errBuff, flagMat); - tag_t tagUser; - char *tagId; - AOM_ask_value_tag(designRev, "owning_user", &tagUser); - AOM_ask_value_string(tagUser, "user_id", &tagId); - if (strcmp(type, "ZT2_Design3DRevision") == 0 && strcmp(loginUserId, tagId) != 0 && strstr(itemId, "2ZD") == NULL) { - return; - } - if (strcmp(type, "ZT2_XNZJBRevision") == 0) { - return; - } - //外购 不展开子件 - if (strstr(itemId, "2ZD") != NULL || strstr(itemId, "4ZD") != NULL) { - if (!flagMat) { - return; - } - } - if (strstr(itemId, "1ZD") != NULL) { - AOM_ask_value_string(designRev, "zt2_Source", &source); - if (strcmp(source, "S2") == 0 || strcmp(source, "外购") == 0) { - return; - } - } - - ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags)); - for (int i = 0; i < c_line_count; i++) { - logical flag; - BOM_line_is_packed(c_line_tags[i], &flag); - if (flag) { - BOM_line_unpack(c_line_tags[i]); - } - } - AOM_refresh(bom_line, FALSE); - ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags)); - //转换时原材料展开逻辑 - if (c_line_count == 0 && !dbName.empty() &&(strstr(itemId, "1ZD") != NULL|| - strstr(itemId, "2ZD") != NULL || strstr(itemId, "4ZD") != NULL)) { - //原材料展开 - char *zt2_MaterialMark; - AOM_ask_value_string(designRev,"zt2_MaterialMark",&zt2_MaterialMark); - //String zt2_MaterialMark = rev.getProperty("zt2_MaterialMark") - string sql = "select materialno, materialutilization, materialunit FROM %s where materialmark = '%s'"; - char selectRxfs[500]; - sprintf(selectRxfs, sql.c_str(), dbName.c_str(), zt2_MaterialMark); - int outputColumn1 = 0, outputValueCount1 = 0; - char*** outputValue1 = NULL; - printf("search3 ===> %s\n", selectRxfs); - QuerySQLNoInputParam(selectRxfs, &outputColumn1, &outputValueCount1, &outputValue1); - if (outputValueCount1 == 0 && strcmp(zt2_MaterialMark, "") != 0) { - string buffErr = ""; - buffErr.append("图纸:").append(itemId).append("-"). - append(object_name).append(zt2_MaterialMark).append("材料标记没有维护.\n"); - size_t found = errBuff.find(buffErr); - if (found ==std::string::npos) { - errBuff.append(buffErr); - } - - } - for (int t = 0; t < outputValueCount1; t++) { - string materialno = outputValue1[t][0]; - string materialutilization = outputValue1[t][1]; - string materialunit = outputValue1[t][2]; - tag_t material, materialRev; - ITEM_find_item(materialno.c_str(),&material); - ITEM_ask_latest_rev(material, &materialRev); - string bl_qty = getTyjZl(bom_line, materialutilization, designRev, errBuff); - printf("bl_qty%s\n", bl_qty.c_str()); - NodeBean cBean; - cBean.bl_quantity = bl_qty; - cBean.bl_sequence_no = "10"; - cBean.bl_plmxml_occ_xform = ""; - cBean.mantr = materialRev; - pBean.childs.push_back(cBean); - } - } - string maxSeqNo; - vector xnzjbVec; - string item_id = itemId; - smatch result;// - regex qq_reg2("^1ZDB5.*\\d{1,}1000X.*"); - bool ret = regex_match(item_id, result, qq_reg2); - for (int i = 0; i < c_line_count; i++) { - logical suppressed; - AOM_ask_value_logical(c_line_tags[i],"bl_is_occ_suppressed",&suppressed); - if (suppressed) { - continue; - } - //修改过之后之前已经是解包的状态了 - logical flag; - BOM_line_is_packed(c_line_tags[i], &flag); - //printf("flag===>%d\n", flag); - if (flag) { - int count = 0; - char *topNum; - AOM_ask_value_string(c_line_tags[i],"bl_quantity",&topNum); - tag_t* packLines; - BOM_line_ask_packed_lines(c_line_tags[i], &count, &packLines); - for (int t = 0; t < count; t++) { - tag_t c_Rev; - ITKCALL(AOM_ask_value_tag(packLines[t], "bl_line_object", &c_Rev)); - char* cUid; - ITK__convert_tag_to_uid(c_Rev, &cUid); - NodeBean cBean; - cBean.revUid = cUid; - cBean.designRev = c_Rev; - cBean.packNum = count+1; - cBean.topNum = atoi(topNum); - recyReadBom(c_line_tags[i], cBean, errBuff, dbName, loginUserId); - pBean.childs.push_back(cBean); - } - AOM_refresh(c_line_tags[i], FALSE); - tag_t c_Rev; - ITKCALL(AOM_ask_value_tag(c_line_tags[i], "bl_line_object", &c_Rev)); - char* cUid; - ITK__convert_tag_to_uid(c_Rev, &cUid); - NodeBean cBean; - cBean.revUid = cUid; - cBean.designRev = c_Rev; - cBean.packNum = count+1; - cBean.topNum = atoi(topNum); - recyReadBom(c_line_tags[i], cBean, errBuff, dbName, loginUserId); - pBean.childs.push_back(cBean); - - } - else { - //检查E转P时的拆分逻辑 - tag_t c_Rev; - char *seqNo,*c_type,*remark,*bl_quantity,*bl_line_name; - ITKCALL(AOM_ask_value_tag(c_line_tags[i], "bl_line_object", &c_Rev)); - char* id; - AOM_ask_value_string(c_Rev, "item_id", &id); - //获取BOM行的REMARK - if (ret) { - AOM_ask_value_string(c_line_tags[i], "ZT2_Remark", &remark); - AOM_ask_value_string(c_line_tags[i], "bl_quantity", &bl_quantity); - AOM_ask_value_string(c_line_tags[i], "bl_line_name", &bl_line_name); - getRemarkMsg(remark,xsLen, errBuff, bl_quantity, itemId, id, bl_line_name); - } - //新增逻辑 当前对象类型为ZT2_XNZJB 虚拟组件包时 进行削层处理 数量*虚拟层数量 - AOM_ask_value_string(c_Rev,"object_type",&c_type); - if (strcmp(c_type, "ZT2_XNZJBRevision") == 0) { - xnzjbVec.push_back(c_line_tags[i]); - continue; - } - AOM_ask_value_string(c_line_tags[i], "bl_sequence_no", &seqNo); - maxSeqNo = seqNo; - char* cUid; - ITK__convert_tag_to_uid(c_Rev, &cUid); - NodeBean cBean; - cBean.revUid = cUid; - cBean.designRev = c_Rev; - recyReadBom(c_line_tags[i], cBean, errBuff, dbName, loginUserId); - pBean.childs.push_back(cBean); - } - } - int maxNum = atoi(maxSeqNo.c_str()); - int xxt = 1; - printf("xnzjbVec ===> %d\n", xnzjbVec.size()); - - getAllXnj(xnzjbVec, maxNum, xxt, errBuff,dbName,pBean,1, loginUserId); -} -void recyReadBom(tag_t bom_line, NodeBean& pBean, string& errBuff, string dbName, vector idVector) -{ - int c_line_count; - char* uid, *type, *zt2_Diagram, *source, *itemId, *object_name; - //图纸版本、子行 - tag_t designRev, *c_line_tags; - ITKCALL(AOM_ask_value_tag(bom_line, "bl_line_object", &designRev)); - //printf("1222"); - ITK__convert_tag_to_uid(designRev, &uid); - //printf("revUid===>%s\n", uid); - pBean.revUid = uid; - pBean.designRev = designRev; - ITKCALL(AOM_ask_value_string(designRev, "object_type", &type)); - ITKCALL(AOM_ask_value_string(designRev, "item_id", &itemId)); - ITKCALL(AOM_ask_value_string(designRev, "object_name", &object_name)); - //printf("type===>%s\n", type); - if (strcmp(type, "ZT2_Design3DRevision") == 0) { - AOM_ask_value_string(designRev, "zt2_Diagram", &zt2_Diagram); - if (strcmp(zt2_Diagram, "Y") == 0 || strcmp(zt2_Diagram, "是") == 0) { - return; - } - } - //判断类型是否为 Part Revision ZT2_Design3DRevision ZT2_XNZJB 不是报错 - if (strcmp(type, "ZT2_Design3DRevision") != 0 - && strcmp(type, "Part Revision") != 0 && strcmp(type, "ZT2_XNZJBRevision") != 0) { - string buffErr = ""; - buffErr.append("对象类型异常:").append(itemId).append("/").append(object_name).append("/").append(type).append("\n"); - size_t found = errBuff.find(buffErr); - if (found == std::string::npos) { - errBuff.append(buffErr); - } - return; - } - - boolean flagMat = false; - askLineVal(pBean, bom_line, designRev, errBuff, flagMat); - vector idVec; - Split(itemId, "-", idVec); - if (std::find(idVector.begin(), idVector.end(), idVec[0]) == idVector.end()) { - return; - } - if (strcmp(type, "ZT2_XNZJBRevision") == 0) { - return; - } - //外购 不展开子件 - if (strstr(itemId, "2ZD") != NULL || strstr(itemId, "4ZD") != NULL) { - if (!flagMat) { - return; - } - } - if (strstr(itemId, "1ZD") != NULL) { - AOM_ask_value_string(designRev, "zt2_Source", &source); - if (strcmp(source, "S2") == 0 || strcmp(source, "外购") == 0) { - return; - } - } - - ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags)); - for (int i = 0; i < c_line_count; i++) { - logical flag; - BOM_line_is_packed(c_line_tags[i], &flag); - if (flag) { - BOM_line_unpack(c_line_tags[i]); - } - } - AOM_refresh(bom_line, FALSE); - ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags)); - //转换时原材料展开逻辑 - if (c_line_count == 0 && !dbName.empty() && (strstr(itemId, "1ZD") != NULL || - strstr(itemId, "2ZD") != NULL || strstr(itemId, "4ZD") != NULL)) { - //原材料展开 - char *zt2_MaterialMark; - AOM_ask_value_string(designRev, "zt2_MaterialMark", &zt2_MaterialMark); - //String zt2_MaterialMark = rev.getProperty("zt2_MaterialMark") - string sql = "select materialno, materialutilization, materialunit FROM %s where materialmark = '%s'"; - char selectRxfs[500]; - sprintf(selectRxfs, sql.c_str(), dbName.c_str(), zt2_MaterialMark); - int outputColumn1 = 0, outputValueCount1 = 0; - char*** outputValue1 = NULL; - printf("search3 ===> %s\n", selectRxfs); - QuerySQLNoInputParam(selectRxfs, &outputColumn1, &outputValueCount1, &outputValue1); - if (outputValueCount1 == 0 && strcmp(zt2_MaterialMark, "") != 0) { - string buffErr = ""; - buffErr.append("图纸:").append(itemId).append("-"). - append(object_name).append(zt2_MaterialMark).append("材料标记没有维护.\n"); - size_t found = errBuff.find(buffErr); - if (found == std::string::npos) { - errBuff.append(buffErr); - } - - } - for (int t = 0; t < outputValueCount1; t++) { - string materialno = outputValue1[t][0]; - string materialutilization = outputValue1[t][1]; - string materialunit = outputValue1[t][2]; - tag_t material, materialRev; - ITEM_find_item(materialno.c_str(), &material); - ITEM_ask_latest_rev(material, &materialRev); - string bl_qty = getTyjZl(bom_line, materialutilization, designRev, errBuff); - printf("bl_qty%s\n", bl_qty.c_str()); - NodeBean cBean; - cBean.bl_quantity = bl_qty; - cBean.bl_sequence_no = "10"; - cBean.bl_plmxml_occ_xform = ""; - cBean.mantr = materialRev; - pBean.childs.push_back(cBean); - } - } - string maxSeqNo; - vector xnzjbVec; - for (int i = 0; i < c_line_count; i++) { - logical suppressed; - AOM_ask_value_logical(c_line_tags[i], "bl_is_occ_suppressed", &suppressed); - if (suppressed) { - continue; - } - //修改过之后之前已经是解包的状态了 - logical flag; - BOM_line_is_packed(c_line_tags[i], &flag); - //printf("flag===>%d\n", flag); - if (flag) { - int count = 0; - char *topNum; - AOM_ask_value_string(c_line_tags[i], "bl_quantity", &topNum); - tag_t* packLines; - BOM_line_ask_packed_lines(c_line_tags[i], &count, &packLines); - for (int t = 0; t < count; t++) { - tag_t c_Rev; - ITKCALL(AOM_ask_value_tag(packLines[t], "bl_line_object", &c_Rev)); - char* cUid; - ITK__convert_tag_to_uid(c_Rev, &cUid); - NodeBean cBean; - cBean.revUid = cUid; - cBean.designRev = c_Rev; - cBean.packNum = count + 1; - cBean.topNum = atoi(topNum); - recyReadBom(c_line_tags[i], cBean, errBuff, dbName, idVector); - pBean.childs.push_back(cBean); - } - AOM_refresh(c_line_tags[i], FALSE); - tag_t c_Rev; - ITKCALL(AOM_ask_value_tag(c_line_tags[i], "bl_line_object", &c_Rev)); - char* cUid; - ITK__convert_tag_to_uid(c_Rev, &cUid); - NodeBean cBean; - cBean.revUid = cUid; - cBean.designRev = c_Rev; - cBean.packNum = count + 1; - cBean.topNum = atoi(topNum); - recyReadBom(c_line_tags[i], cBean, errBuff, dbName, idVector); - pBean.childs.push_back(cBean); - - } - else { - tag_t c_Rev; - char *seqNo, *c_type; - ITKCALL(AOM_ask_value_tag(c_line_tags[i], "bl_line_object", &c_Rev)); - //新增逻辑 当前对象类型为ZT2_XNZJB 虚拟组件包时 进行削层处理 数量*虚拟层数量 - AOM_ask_value_string(c_Rev, "object_type", &c_type); - if (strcmp(c_type, "ZT2_XNZJBRevision") == 0) { - xnzjbVec.push_back(c_line_tags[i]); - continue; - } - AOM_ask_value_string(c_line_tags[i], "bl_sequence_no", &seqNo); - maxSeqNo = seqNo; - char* cUid; - ITK__convert_tag_to_uid(c_Rev, &cUid); - NodeBean cBean; - cBean.revUid = cUid; - cBean.designRev = c_Rev; - recyReadBom(c_line_tags[i], cBean, errBuff, dbName, idVector); - pBean.childs.push_back(cBean); - } - } - int maxNum = atoi(maxSeqNo.c_str()); - int xxt = 1; - printf("xnzjbVec ===> %d\n", xnzjbVec.size()); - - getAllXnj(xnzjbVec, maxNum, xxt, errBuff, dbName, pBean, 1, idVector); -} -void getAllXnj(vector xnzjbVec, int maxNum, int &xxt, - string& errBuff, string dbName, NodeBean& pBean, int qtyXn, vector idVector) { - - - for (int t = 0; t < xnzjbVec.size(); t++) { - tag_t c_line_tag = xnzjbVec[t], *cc_line_tags; - int cc_line_count; - ITKCALL(BOM_line_ask_all_child_lines(c_line_tag, &cc_line_count, &cc_line_tags)); - char *cnt, *c_type; - int qtyPXn = 1; - AOM_ask_value_string(c_line_tag, "bl_quantity", &cnt); - if (strcmp(cnt, "") != 0) { - qtyPXn = atoi(cnt); - } - //qtyPXn = qtyPXn * qtyXn; - vector xnzjbVec2; - for (int j = 0; j < cc_line_count; j++) { - tag_t c_Rev; - char *itemId, *object_name; - ITKCALL(AOM_ask_value_tag(cc_line_tags[j], "bl_line_object", &c_Rev)); - AOM_ask_value_string(c_Rev, "object_type", &c_type); - AOM_ask_value_string(c_Rev, "item_id", &itemId); - AOM_ask_value_string(c_Rev, "object_name", &object_name); - if (strcmp(c_type, "ZT2_XNZJBRevision") == 0) { - printf("itemId===>%s\n", itemId); - xnzjbVec2.push_back(cc_line_tags[j]); - continue; - } - //判断类型是否为 Part Revision ZT2_Design3DRevision ZT2_XNZJB 不是报错 - if (strcmp(c_type, "ZT2_Design3DRevision") != 0 - && strcmp(c_type, "Part Revision") != 0) { - string buffErr = ""; - buffErr.append("对象类型异常:").append(itemId).append("/").append(object_name).append("/").append(c_type).append("\n"); - size_t found = errBuff.find(buffErr); - if (found == std::string::npos) { - errBuff.append(buffErr); - } - } - NodeBean cBean; - char* cUid; - ITK__convert_tag_to_uid(c_Rev, &cUid); - cBean.revUid = cUid; - cBean.designRev = c_Rev; - cBean.xnNum = qtyXn * qtyPXn; - int srqNum = maxNum + xxt * 10; - string lastnum = to_string(srqNum); - xxt = xxt + 1; - cBean.bl_sequence_no = lastnum; - recyReadBom(cc_line_tags[j], cBean, errBuff, dbName, idVector); - pBean.childs.push_back(cBean); - } - printf("xnzjbVec2 ===> %d ==>%d \n", xnzjbVec2.size(), qtyPXn); - if (xnzjbVec2.size() > 0) { - getAllXnj(xnzjbVec2, maxNum, xxt, errBuff, dbName, pBean, qtyPXn, idVector); - } - } -} -void getAllXnj(vector xnzjbVec, int maxNum, int &xxt, - string& errBuff, string dbName, NodeBean& pBean, int qtyXn,char *loginUserId) { - - for (int t = 0; t < xnzjbVec.size(); t++) { - tag_t c_line_tag = xnzjbVec[t], *cc_line_tags; - int cc_line_count; - ITKCALL(BOM_line_ask_all_child_lines(c_line_tag, &cc_line_count, &cc_line_tags)); - char *cnt, *c_type; - int qtyPXn = 1; - AOM_ask_value_string(c_line_tag, "bl_quantity", &cnt); - if (strcmp(cnt, "") != 0) { - qtyPXn = atoi(cnt); - } - //qtyPXn = qtyPXn * qtyXn; - vector xnzjbVec2; - for (int j = 0; j < cc_line_count; j++) { - tag_t c_Rev; - char *itemId, *object_name; - ITKCALL(AOM_ask_value_tag(cc_line_tags[j], "bl_line_object", &c_Rev)); - AOM_ask_value_string(c_Rev, "object_type", &c_type); - AOM_ask_value_string(c_Rev, "item_id", &itemId); - AOM_ask_value_string(c_Rev, "object_name", &object_name); - if (strcmp(c_type, "ZT2_XNZJBRevision") == 0) { - printf("itemId===>%s\n", itemId); - xnzjbVec2.push_back(cc_line_tags[j]); - continue; - } - //判断类型是否为 Part Revision ZT2_Design3DRevision ZT2_XNZJB 不是报错 - if (strcmp(c_type, "ZT2_Design3DRevision") != 0 - && strcmp(c_type, "Part Revision") != 0) { - string buffErr = ""; - buffErr.append("对象类型异常:").append(itemId).append("/").append(object_name).append("/").append(c_type).append("\n"); - size_t found = errBuff.find(buffErr); - if (found == std::string::npos) { - errBuff.append(buffErr); - } - } - NodeBean cBean; - char* cUid; - ITK__convert_tag_to_uid(c_Rev, &cUid); - cBean.revUid = cUid; - cBean.designRev = c_Rev; - cBean.xnNum = qtyXn * qtyPXn; - int srqNum = maxNum + xxt * 10; - string lastnum = to_string(srqNum); - xxt = xxt + 1; - cBean.bl_sequence_no = lastnum; - recyReadBom(cc_line_tags[j], cBean, errBuff, dbName, loginUserId); - pBean.childs.push_back(cBean); - } - printf("xnzjbVec2 ===> %d ==>%d \n", xnzjbVec2.size(), qtyPXn); - if (xnzjbVec2.size()>0) { - getAllXnj(xnzjbVec2, maxNum, xxt, errBuff, dbName, pBean, qtyPXn, loginUserId); - } - } -} -string GBKToUTF8(const std::string& strGBK) -{ - string strOutUTF8 = ""; - WCHAR * str1; - int n = MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, NULL, 0); - str1 = new WCHAR[n]; - MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, str1, n); - n = WideCharToMultiByte(CP_UTF8, 0, str1, -1, NULL, 0, NULL, NULL); - char * str2 = new char[n]; - WideCharToMultiByte(CP_UTF8, 0, str1, -1, str2, n, NULL, NULL); - strOutUTF8 = str2; - delete[]str1; - str1 = NULL; - delete[]str2; - str2 = NULL; - return strOutUTF8; -} -string proProcessCreate(tag_t rev, string process_name) -{ - tag_t template_tag = NULLTAG; - EPM_find_template2(process_name.c_str(), PROCESS_TEMPLATE, &template_tag); - tag_t new_process = NULLTAG; - int *tagType = (int *)MEM_alloc(1024 * sizeof(int));//EPM_reference_attachment - tag_t * itemTag = (tag_t *)MEM_alloc(1024 * sizeof(tag_t)); - tagType[0] = EPM_target_attachment; - itemTag[0] = rev; - EPM_create_process("快速发布", "", template_tag, 1, itemTag, tagType, &new_process); - return "1"; -} - -boolean firstRevision(tag_t designRev, tag_t mantr) { - char *revId; - int revNum = 0, statusNum=0; - tag_t *structure_revisions; - AOM_ask_value_string(designRev,"item_revision_id",&revId); - AOM_ask_value_tags(mantr, "structure_revisions", &revNum, &structure_revisions); - if (revNum > 0) { - tag_t struct_revision = structure_revisions[0],*release_status_list; - AOM_ask_value_tags(struct_revision, "release_status_list", &statusNum, &release_status_list); - if (statusNum == 0) { - return false; - } - } - if (strcmp(revId,"V01") > 0) { - return true; - } - else { - return false; - } -} -map getBomMsg(tag_t mantrRev) { - map bomMsgMap; - tag_t* bvr_list = NULL, bom_line, ebom_window; - int bvr_count=0; - ITKCALL(ITEM_rev_list_bom_view_revs(mantrRev, &bvr_count, &bvr_list)); - //没有BOM视图创建 - if (bvr_count == 0) { - return bomMsgMap; - } - ITKCALL(BOM_create_window(&ebom_window)); - //移除原来的 - ITKCALL(BOM_set_window_top_line(ebom_window, NULL, mantrRev, NULLTAG, &bom_line)); - int c_line_count; - tag_t* c_line_tags; - ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags)); - printf("c_line_count===>%d\n", c_line_count); - for (int t = 0; t < c_line_count; t++) { - tag_t c_Rev; - char *matnrNo,*cnt; - ITKCALL(AOM_ask_value_tag(c_line_tags[t], "bl_line_object", &c_Rev)); - AOM_ask_value_string(c_Rev,"zt2_MaterialNo",&matnrNo); - printf("zt2_MaterialNo===>%s\n", matnrNo); - int qtyPXn = 1; - AOM_ask_value_string(c_line_tags[t], "bl_quantity", &cnt); - if (strcmp(cnt, "") != 0) { - qtyPXn = atoi(cnt); - } - if (bomMsgMap.count(matnrNo)>0) { - bomMsgMap[matnrNo] = bomMsgMap[matnrNo] + qtyPXn; - } - else { - bomMsgMap[matnrNo] = qtyPXn; - } - } - - BOM_close_window(ebom_window); - return bomMsgMap; -} -//对比Ebom和Dbom -boolean combEAndDbom(map dMap, map eMap) { - map::iterator it; - //名称模糊匹配 - for (it = dMap.begin(); it != dMap.end(); it++) { - string s = it->first; - int dnum = dMap[s]; - if (eMap.count(s) == 0) { - return true; - } - else if(dnum!= eMap[s]){ - return true; - } - } - return false; -} -void TCMAndOwner(tag_t matnrTop) { - int num = 0, revNum; - tag_t *mantrsAs, dsuser,*structure_revisions; - AOM_ask_value_tags(matnrTop, "TC_Is_Represented_By", &num, &mantrsAs); - AOM_ask_value_tag(mantrsAs[0], "owning_user", &dsuser); - tag_t defGroup; - ITKCALL(AOM_ask_value_tag(dsuser, "default_group", &defGroup)); - ITKCALL(AOM_set_ownership(matnrTop, dsuser, defGroup)); - if (num > 0) { - AOM_ask_value_tags(matnrTop, "structure_revisions", &revNum, &structure_revisions); - if (revNum > 0) { - ITKCALL(AOM_set_ownership(structure_revisions[0], dsuser, defGroup)); - } - } - string process_name = "TCM Release Process"; - proProcessCreate(matnrTop, process_name); -} -void createEbom(NodeBean topBean,boolean isTop,string &hasChange) -{ - tag_t ebom_window = NULLTAG; - tag_t bom_line = NULLTAG; - vector childs = topBean.childs; - //printf("子line数量 %d \n", childs.size()); - tag_t desBean = topBean.designRev; - char* id; - AOM_ask_value_string(desBean, "item_id", &id); - printf("id %s \n", id); - tag_t mantr = topBean.mantr; - //判断是否最初版本 不是就和当前的EBOM进行比较 - //相同就跳过不升版、不同就升版、只比较数量 - //ITEM_ask_f - boolean flagChange = true; - - if (mantr != NULLTAG && childs.size() > 0) { - printf("-----"); - tag_t* bvr_list = NULL; - int bvr_count; - ITKCALL(ITEM_rev_list_bom_view_revs(mantr, &bvr_count, &bvr_list)); - //没有BOM视图创建 - if (bvr_count == 0) { - tag_t newView, newViewBvr, pitem,dsuser; - ITEM_ask_item_of_rev(mantr, &pitem); - ITKCALL(PS_create_bom_view(NULL, NULL, NULL, pitem, &newView)); - AOM_save(newView); - ITKCALL(PS_create_bvr(newView, NULL, NULL, FALSE, mantr, &newViewBvr)); - AOM_save(newViewBvr); - AOM_save(mantr); - AOM_ask_value_tag(desBean,"owning_user", &dsuser); - tag_t defGroup; - ITKCALL(AOM_ask_value_tag(dsuser, "default_group", &defGroup)); - ITKCALL(AOM_set_ownership(newView, dsuser, defGroup)); - ITKCALL(AOM_set_ownership(newViewBvr, dsuser, defGroup)); - } - ITKCALL(BOM_create_window(&ebom_window)); - //移除原来的 - ITKCALL(BOM_set_window_top_line(ebom_window, NULL, mantr, NULLTAG, &bom_line)); - //变更当前BOM层级 已发布的不需要更改 - if(flagChange){ - if (bvr_count > 0) { - int c_line_count; - tag_t* c_line_tags; - ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags)); - for (int t = 0; t < c_line_count; t++) { - char* val; - AOM_ask_value_string(c_line_tags[t], "bl_occ_zt2_DtoE", &val); - if (strcmp(val, "DBOM转换") == 0) { - BOM_line_cut(c_line_tags[t]); - } - } - } - for (int i = 0; i < childs.size(); i++) { - NodeBean cBean = childs[i]; - if (cBean.mantr != NULLTAG) { - tag_t cLine; - ITKCALL(BOM_line_add(bom_line, NULL, cBean.mantr, NULL, &cLine)); - AOM_lock(cLine); - if (cBean.packNum > 0) { - string num = cBean.bl_quantity; - num = to_string(cBean.topNum / cBean.packNum); - ITKCALL(AOM_set_value_string(cLine, "bl_quantity", num.c_str())); - } - else { - printf("num %s \n", cBean.bl_quantity.c_str()); - ITKCALL(AOM_set_value_string(cLine, "bl_quantity", cBean.bl_quantity.c_str())); - } - - - AOM_set_value_string(cLine, "bl_plmxml_occ_xform", cBean.bl_plmxml_occ_xform); - AOM_set_value_string(cLine, "bl_sequence_no", cBean.bl_sequence_no.c_str()); - ITKCALL(AOM_set_value_string(cLine, "bl_occ_zt2_DtoE", "DBOM转换")); - AOM_save(cLine); - //最后unlock - AOM_unlock(cLine); - AOM_refresh(cLine, FALSE); - } - else { - printf("eeeeee\n"); - } - } - ITKCALL(BOM_save_window(ebom_window)); - } - BOM_close_window(ebom_window); - for (int i = 0; i < childs.size(); i++) { - NodeBean cBean = childs[i]; - createEbom(cBean,false,hasChange); - } - } - else { - printf("topBean.mantr == NULLTAG\n"); - } - -} -void copyEBomLine(tag_t matnrTop, tag_t otherPbom) { - tag_t ebom_window, ebom_window2, *bvr_list, *bvr_list2, bom_line, bom_line2, *c_line_tags, *c_line_tags2; - int bvr_count = 0, bvr_count2 = 0, c_line_count, c_line_count2; - (BOM_create_window(&ebom_window)); - (ITEM_rev_list_bom_view_revs(matnrTop, &bvr_count, &bvr_list)); - printf("bvr_count=%d \n", bvr_count); - if (bvr_count == 0) { - //errBuff.append("不存在EBOM请检查\n"); - } - ITKCALL(BOM_set_window_top_line_bvr(ebom_window, bvr_list[0], &bom_line)); //顶层bom获取 - printf("顶层bom获取\n"); - //ITKCALL(AOM_ask_value_tag(bom_line, "bl_line_object", &mantr)); - ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags)); - - - (ITEM_rev_list_bom_view_revs(otherPbom, &bvr_count2, &bvr_list2)); - if (bvr_count2 == 0) { - tag_t newView, newViewBvr, pitem; - ITEM_ask_item_of_rev(otherPbom, &pitem); - ITKCALL(PS_create_bom_view(NULL, NULL, NULL, pitem, &newView)); - AOM_save(newView); - ITKCALL(PS_create_bvr(newView, NULL, NULL, FALSE, otherPbom, &newViewBvr)); - AOM_save(newViewBvr); - AOM_save(otherPbom); - int num = 0; - tag_t dsuser, *structure_revisions, *bom_view_tags, *mantrs; - ITKCALL(AOM_ask_value_tags(otherPbom, "TC_Is_Represented_By", &num, &mantrs)); - if (num == 1) { - AOM_ask_value_tag(mantrs[0], "owning_user", &dsuser); - tag_t defGroup; - ITKCALL(AOM_ask_value_tag(dsuser, "default_group", &defGroup)); - ITKCALL(AOM_set_ownership(newView, dsuser, defGroup)); - ITKCALL(AOM_set_ownership(newViewBvr, dsuser, defGroup)); - } - //return; - (ITEM_rev_list_bom_view_revs(otherPbom, &bvr_count2, &bvr_list2)); - } - (BOM_create_window(&ebom_window2)); - (BOM_set_window_top_line_bvr(ebom_window2, bvr_list2[0], &bom_line2)); //顶层bom获取 - ITKCALL(BOM_line_ask_all_child_lines(bom_line2, &c_line_count2, &c_line_tags2)); - for (int i = 0; i < c_line_count2; i++) { - BOM_line_cut(c_line_tags2[i]); - } - for (int i = 0; i < c_line_count; i++) { - tag_t newChild; char *bl_seqNo; - ITKCALL(BOM_line_copy(bom_line2, c_line_tags[i], NULLTAG, &newChild)); - AOM_ask_value_string(c_line_tags[i],"bl_sequence_no",&bl_seqNo); - AOM_lock(newChild); - AOM_set_value_string(newChild, "bl_sequence_no", bl_seqNo); - AOM_save(newChild); - //最后unlock - AOM_unlock(newChild); - } - //tag_t newChild; - //ITKCALL(BOM_line_copy(bom_line2, c_line_tags[i], NULLTAG, &newChild)); - - ITKCALL(BOM_save_window(ebom_window2)); - BOM_close_window(ebom_window2); - BOM_close_window(ebom_window); -} -//获取分类属性 判断是否整除 -int getClassValByTop(tag_t item, string& errMessage) { - char*id; - AOM_ask_value_string(item,"item_id",&id); - vector vec; - Split(id, "-", vec); - tag_t topItem; - if (vec.size() > 1) { - string topId; - topId.append("1ZDB300000P-").append(vec[1]); - ITEM_find_item(topId.c_str(),&topItem); - } - else { - return 1; - } - tag_t top_classificationObject; - ICS_ask_classification_object(topItem, &top_classificationObject); - if (top_classificationObject == NULL_TAG) - { - errMessage.append("顶层对象没有发送到分类\n"); - return 0; - } - char* top_class_id = NULL, *top_class_name = NULL; - //ICS_ask_class_of_classification_obj(top_classificationObject, &top_class_tag); - //ICS_ask_id_name(top_class_tag, &top_class_id, &top_class_name); - printf("BOM TOP LINE CLASS ID = %s | NAME = %s \n", top_class_id, top_class_name); - int n_attrs; - char** attr_names; - char** attr_vals; - ITKCALL(ICS_ask_attributes_of_classification_obj(top_classificationObject, &n_attrs, &attr_names, &attr_vals)); - cout << n_attrs << endl; - int num = 1; - for (int ii = 0; ii < n_attrs; ii++) - { - printf("attr_names[ii]==>%sTTT\n", attr_names[ii]); - printf("attr_vals[ii]==>%sTTT\n", attr_vals[ii]); - if (strcmp(attr_names[ii], "相数") == 0) { - if (strcmp(attr_vals[ii], "") == 0) { - errMessage.append("分类属性相数为空,请检查。\n"); - return 0; - } - else { - printf("111[ii]==TTT\n"); - if (strstr(attr_vals[ii], "3") != NULL) { - num = 3; - } - else if (strstr(attr_vals[ii], "1") != NULL) { - num = 1; - } - else if (strstr(attr_vals[ii], "5") != NULL) { - num = 5; - } - //num = atoi(attr_vals[ii]); - } - break; - } - } - return num; -} -int DbomToEMethod(void* returnValue) { - int ifail = ITK_ok; - char *sql = NULL,*revUid; - tag_t designRev,item; - ITKCALL(ifail = USERARG_get_string_argument(&revUid)); - ITK__convert_uid_to_tag(revUid, &designRev); - ITEM_ask_item_of_rev(designRev,&item); - ITEM_ask_latest_rev(item,&designRev); - if (open("PLMUser", "PLMUser", "BDP2020", "10.128.20.35")) { - printf("链接SQLSERVER失败\n"); - } - else { - printf("链接SQLSERVER成功\n"); - } - //遍历design BOM 获取物料信息 - int bvr_count = 0, c_line_count; - tag_t ebom_window = NULLTAG; - tag_t bom_line = NULLTAG; - tag_t item_tag = NULLTAG, *c_line_tags; - (BOM_create_window(&ebom_window)); - tag_t* bvr_list = NULL; - (ITEM_rev_list_bom_view_revs(designRev, &bvr_count, &bvr_list)); - printf("bvr_count=%d", bvr_count); - - (BOM_set_window_top_line_bvr(ebom_window, bvr_list[0], &bom_line)); //顶层bom获取 - printf("顶层bom获取\n"); - - //(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags)); - NodeBean topBean; - //遍历 - string errBuff; - //xsLen = 1; - xsLen = getClassValByTop(designRev, errBuff); - int url_num = 0; - char** url_vals = NULL; - PREF_ask_char_values("database_tc", &url_num, &url_vals); - string url = url_vals[0]; - url.append("/").append(url_vals[2]); - - //map %s \n", url.c_str()); - if (ConnServer(url_vals[3], url_vals[4], (char*)url.c_str()) == -1) - { - printf("提示:中间数据表访问失败\n"); - ifail = 1; - } - string dbName; - int url_num2 = 0; - char** url_vals2 = NULL; - PREF_ask_char_values("CHINT_MATERIAL_RAW", &url_num2, &url_vals2); - for (int t = 0; t < url_num2; t++) { - vector vec; - Split(url_vals2[t], ":", vec); - if (vec[0].compare("M060") == 0) { - dbName = vec[1]; - } - } - char *loginUserId; - printf("dbName===%s\n", dbName.c_str()); - POM_get_user_id(&loginUserId); - recyReadBom(bom_line, topBean, errBuff, dbName, loginUserId); - DisConnServer(); - BOM_close_window(ebom_window); - //搭建BOM - POM_AM__set_application_bypass(true); - printf("error %s \n", errBuff.c_str()); - if (errBuff.empty()) { - string hasChange=""; - createEbom(topBean,true, hasChange); - printf("topBean.ccps.size()====>%d\n", topBean.ccps.size()); - //没有更改直接跳过 - if (topBean.ccps.size()>0 && hasChange.compare("no")!=0) { - tag_t desBean = topBean.designRev; - //vector childs = topBean.childs; - /*map dMap; - for (int i = 0; i < childs.size(); i++) { - NodeBean cBean = childs[i]; - char *matnrNo, *uid; - AOM_ask_value_string(cBean.mantr, "zt2_MaterialNo", &matnrNo); - ITK__convert_tag_to_uid(cBean.mantr, &uid); - printf("uid[%s]\n", uid); - printf("matnrNo[%s]\n", matnrNo); - int qtyPXn = 1; - string cnt = cBean.bl_quantity; - if (strcmp(cnt.c_str(), "") != 0) { - qtyPXn = atoi(cnt.c_str()); - } - if (dMap.count(matnrNo) > 0) { - dMap[matnrNo] = dMap[matnrNo] + qtyPXn; - } - else { - dMap[matnrNo] = qtyPXn; - } - } - printf("dMap[%d]", dMap.size());*/ - for (int t = 0; t < topBean.ccps.size();t++) { - tag_t mantr = topBean.ccps[t]; - boolean flagChange = true; - //if (firstRevision(desBean, mantr)) { - // map eMap = getBomMsg(mantr); - // printf("eMap[%d]", eMap.size()); - // boolean needAs = false; - // if (dMap.size() != eMap.size()) { - // //升版 + 发布 - // needAs = true; - // } - // else if (combEAndDbom(dMap, eMap)) { - // //升版 + 发布 - // needAs = true; - // } - // if (needAs) { - // printf("=======TEST======\n"); - // //升版并发布 - // ITKCALL(ITEM_copy_rev(mantr, NULL, &mantr)); - // TCMAndOwner(mantr); - // //return; - // } - // else { - // flagChange = false; - // } - //} - if (flagChange) { - tag_t topItem,topRev; - ITEM_ask_item_of_rev(topBean.mantr, &topItem); - ITEM_ask_latest_rev(topItem,&topRev); - copyEBomLine(topRev, mantr); - } - } - } - errBuff = "succ"; - } - /*else { - printf(errBuff.c_str()); - }*/ - - POM_AM__set_application_bypass(false); - - close(); - printf("释放数据库成功\n"); - printf("子line数量 %d \n", topBean.childs.size()); - string buff = errBuff; - *((char**)returnValue) = (char*)MEM_alloc((strlen(buff.c_str()) + 1) * sizeof(char)); - tc_strcpy(*((char**)returnValue), buff.c_str()); - return ifail; -} - -int DbomToEMethodUser(void* returnValue) { - int ifail = ITK_ok; - char *sql = NULL, *revUid; - tag_t designRev; - ITKCALL(ifail = USERARG_get_string_argument(&revUid)); - ITK__convert_uid_to_tag(revUid, &designRev); - - if (open("PLMUser", "PLMUser", "BDP2020", "10.128.20.35")) { - printf("链接SQLSERVER失败\n"); - } - else { - printf("链接SQLSERVER成功\n"); - } - //遍历design BOM 获取物料信息 - int bvr_count = 0, c_line_count; - tag_t ebom_window = NULLTAG; - tag_t bom_line = NULLTAG; - tag_t item_tag = NULLTAG, *c_line_tags; - (BOM_create_window(&ebom_window)); - tag_t* bvr_list = NULL; - (ITEM_rev_list_bom_view_revs(designRev, &bvr_count, &bvr_list)); - printf("bvr_count=%d", bvr_count); - - (BOM_set_window_top_line_bvr(ebom_window, bvr_list[0], &bom_line)); //顶层bom获取 - printf("顶层bom获取\n"); - - //(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags)); - NodeBean topBean; - //遍历 - string errBuff; - - int url_num = 0; - char** url_vals = NULL; - PREF_ask_char_values("database_tc", &url_num, &url_vals); - string url = url_vals[0]; - url.append("/").append(url_vals[2]); - - //map %s \n", url.c_str()); - if (ConnServer(url_vals[3], url_vals[4], (char*)url.c_str()) == -1) - { - printf("提示:中间数据表访问失败\n"); - ifail = 1; - } - string dbName; - int url_num2 = 0, url_num3=0; - char** url_vals2 = NULL,**url_vals3=NULL; - PREF_ask_char_values("CHINT_MATERIAL_RAW", &url_num2, &url_vals2); - for (int t = 0; t < url_num2; t++) { - vector vec; - Split(url_vals2[t], ":", vec); - if (vec[0].compare("M060") == 0) { - dbName = vec[1]; - } - } - PREF_ask_char_values("CHINT_M060_KJTOSAP", &url_num3, &url_vals3); - vector idVector; - if (url_num3>0) { - Split(url_vals3[0], ";", idVector); - } - - //if (std::find(v.begin(), v.end(), key) != v.end()) { - - //} - recyReadBom(bom_line, topBean, errBuff, dbName, idVector); - DisConnServer(); - BOM_close_window(ebom_window); - //搭建BOM - POM_AM__set_application_bypass(true); - printf("error %s \n", errBuff.c_str()); - if (errBuff.empty()) { - string change; - createEbom(topBean,false, change); - printf("topBean.ccps.size()====>%d\n", topBean.ccps.size()); - if (topBean.ccps.size() > 0) { - for (int t = 0; t < topBean.ccps.size(); t++) { - copyEBomLine(topBean.mantr, topBean.ccps[t]); - } - } - errBuff = "succ"; - } - /*else { - printf(errBuff.c_str()); - }*/ - - POM_AM__set_application_bypass(false); - - close(); - printf("释放数据库成功\n"); - printf("子line数量 %d \n", topBean.childs.size()); - string buff = errBuff; - *((char**)returnValue) = (char*)MEM_alloc((strlen(buff.c_str()) + 1) * sizeof(char)); - tc_strcpy(*((char**)returnValue), buff.c_str()); - return ifail; -} - int chintSignChange(EPM_action_message_t msg) { diff --git a/General/General/chint_add_to_workflow.cpp b/General/General/chint_add_to_workflow.cpp index 0b41882..e33c331 100644 --- a/General/General/chint_add_to_workflow.cpp +++ b/General/General/chint_add_to_workflow.cpp @@ -43,7 +43,156 @@ #include "ocilib.h" #include #include "CRUL_server_call_httpserver.h" +#include "cJSON.h" +boolean isUseGroup(char *groupName) { + int url_num = 0; + char** url_vals = NULL; + PREF_ask_char_values("CHINT_AssignmentLimits", &url_num, &url_vals); + if (url_num > 0) { + if (strstr(url_vals[0], groupName)!=NULL) { + return true; + } + } + return false; +} +//(char*)projectVec[0].c_str() +tag_t getUserFromYP(char* designId, char** url_vals, int url_num,char* projectId) { + vector idVector; + tag_t userTag = NULLTAG; + char* url; + PREF_ask_char_value("CHINT_PIUrl", 0, &url); + string ypUrl = url; + ypUrl.append("/api/open/task/getTaskInfo/").append(projectId); + if (url_num > 0) { + Split(url_vals[0], ";", idVector); + for (int i = 0; i < idVector.size(); i++) { + if (strstr(idVector[i].c_str(), designId)!=NULL) { + vector nameVector; + Split(idVector[i], "=", nameVector); + printf("nameVector===>%s \n", nameVector[1].c_str()); + string jsonStr = getAssignFromYP(ypUrl); + cJSON* json = cJSON_Parse(jsonStr.c_str()); + char *json_to_char = cJSON_Print(json); + printf("json_to_char===>%s \n", json_to_char); + cJSON* dataJson = cJSON_GetObjectItem(json, "data"); + int size = cJSON_GetArraySize(dataJson); + for (int i = 0; i < size; i++) { + cJSON *arr = cJSON_GetArrayItem(dataJson, i); + cJSON *taskName = cJSON_GetObjectItem(arr, "taskname"); + if (taskName != NULL && taskName->type == cJSON_String) { + char* tskName = taskName->valuestring; + if (strcmp(nameVector[1].c_str(), tskName) == 0) { + cJSON *userIdJson = cJSON_GetObjectItem(arr, "userid"); + if (userIdJson != NULL && userIdJson->type == cJSON_String) { + char* userId = userIdJson->valuestring; + printf("tskName = %s\n", userId); + printf("tskName = %s\n", tskName); + SA_find_user(userId, &userTag); + } + } + } + } + } + } + } + return userTag; +} + +int CHINT_Assignment(EPM_action_message_t msg) { + + int ifail = ITK_ok; + ECHO("=========================================================\n"); + ECHO("CHINT_Assignment 开始执行\n"); + ECHO("=========================================================\n"); + tag_t root_task = NULLTAG, *sub_tasks = NULL, current_task = NULLTAG, type_tag = NULLTAG; + int sub_task_count = 0; + tag_t cur_task = NULLTAG,groupTag; + char* jobName; + current_task = msg.task; + //获取流程名称 截取项目ID + AOM_ask_value_string(current_task, "job_name", &jobName); + EPM_ask_root_task(msg.task, &root_task); + EPM_ask_sub_tasks(root_task, &sub_task_count, &sub_tasks); + printf("sub_task_count===>%d\n", sub_task_count); + tag_t reviewTask = NULLTAG; + for (int i = 0; i < sub_task_count; i++) { + char*taskType, *objectName; + WSOM_ask_object_type2(sub_tasks[i], &taskType); + AOM_ask_value_string(sub_tasks[i],"object_name" ,&objectName); + if (strcmp("EPMReviewTask", taskType) == 0 && strcmp(objectName,"校对")==0) { + reviewTask = sub_tasks[i]; + } + } + int url_num = 0; + char** url_vals = NULL, *groupName; + POM_ask_group(&groupName, &groupTag); + //首选项 配置哪些组可以使用 + if (isUseGroup(groupName) && reviewTask !=NULLTAG) { + //1ZDB400000T=铁心校对; 1ZDB860000Y=油箱校对 + PREF_ask_char_values("CHINT_Assignment", &url_num, &url_vals); + //获取当前节点信息 00089 和 ID前缀 + vectornameVec; + Split(jobName, "/", nameVec); + vector projectVec; + Split(nameVec[0], "-", projectVec); + tag_t query = NULLTAG, *tags; + int n_found = 0; + ITKCALL(QRY_find2("查询项目", &query)); + if (projectVec.size() > 1) { + char* qry_entries[1] = { "工程编号" }, *qry_values[1] = { (char*)projectVec[1].c_str() }; + ITKCALL(QRY_execute(query, 1, qry_entries, qry_values, &n_found, &tags)); + } + printf("n_found===>%d\n", n_found); + for (int t = 0; t < n_found; t++) { + tag_t project = tags[t], login_group; + char *id; + AOM_ask_value_string(project, "item_id", &id); + tag_t userTag = getUserFromYP((char*)projectVec[0].c_str(), url_vals, url_num, id); + if (userTag != NULLTAG) { + int mem_cnt = 0, signoff_cnt = 0, n_signoff = 0; + tag_t select_signoff_tag, *members, *signoffs; + EPM_ask_sub_task(reviewTask, EPM_select_signoff_team_task, &select_signoff_tag); + ITKCALL(SA_ask_user_login_group(userTag, &login_group)); + ITKCALL(SA_find_groupmembers(userTag, login_group, &mem_cnt, &members)); + //移除审核节点的审核人 + tag_t signoffTag; + EPM_ask_attachments(select_signoff_tag, EPM_signoff_attachment, + &n_signoff, &signoffs); + printf(" n_signoff %d \n", n_signoff); + if (n_signoff > 0) { + try + { + tag_t member = NULLTAG; + SIGNOFF_TYPE_t type; + ITKCALL(EPM_ask_signoff_member(signoffs[0], &member, &type)); + tag_t groupmembers[1] = { member }; + int code = 0; + ITKCALL(code = EPM_remove_signoffs(reviewTask, 1, &groupmembers[0])); + printf("ifail %d \n", code); + EMH_clear_errors(); + } + catch (const IFail &e) + { + printf("ifail %d \n", ifail); + ifail = e.ifail(); + + if (ifail == EPM_signoff_profile_not_staffed) + { + cout << "INFORMATION: The required staffing for the signoff"; + cout << " profiles are not complete." << endl; + } + } + } + ITKCALL(EPM_create_adhoc_signoff(select_signoff_tag, members[0], &signoff_cnt, &signoffs)); + ITKCALL(EPM_set_adhoc_signoff_selection_done(select_signoff_tag, true)); + } + + } + } + + return ifail; +} void addToFlow(tag_t bom_line,tag_t rootTask_tag, map &uidMap) { int structs=0; @@ -132,10 +281,13 @@ int CHINT_task_complete(EPM_action_message_t msg) { //SA_workcontext_invalid_group_member tag_t query = NULLTAG, *tags; //fields.put("描述", "*" + item_id + "*" + zt2_TYJNo + "*"); + int n_found = 0; ITKCALL(QRY_find2("查询项目", &query)); - char* qry_entries[1] = { "工程编号" }, *qry_values[1] = { (char*)projectVec[1].c_str() }; - int n_found; - ITKCALL(QRY_execute(query, 1, qry_entries, qry_values, &n_found, &tags)); + if (projectVec.size() > 1) { + char* qry_entries[1] = { "工程编号" }, *qry_values[1] = { (char*)projectVec[1].c_str() }; + ITKCALL(QRY_execute(query, 1, qry_entries, qry_values, &n_found, &tags)); + } + printf("n_found===>%d\n", n_found); for (int t = 0; t < n_found; t++) { tag_t rev = tags[t]; @@ -228,9 +380,9 @@ int chint_CheckTable_State(EPM_action_message_t msg) { printf("selectRecord2 ===> %s\n", selectRecord2); QuerySQLNoInputParam(selectRecord2, &outputColumn1, &outputValueCount1, &outputValue1); if (outputValueCount1>0) { - string status = outputValue1[0][0]; - string date = outputValue1[0][1]; - if (status.compare("正式提交") != 0 || date.empty()) { + //string status = ; + //string date = outputValue1[0][1]; + if (strcmp(outputValue1[0][0],"正式提交") != 0 || strcmp(outputValue1[0][1], "") == 0) { ifail = 1; errmsg.append("图纸:").append(itemId).append(" 校对表没有正式提交,请检查.\n"); } diff --git a/General/General/common_itk_util.c b/General/General/common_itk_util.c index 5e5b334..2fcbb74 100644 --- a/General/General/common_itk_util.c +++ b/General/General/common_itk_util.c @@ -58,7 +58,7 @@ #define ARGS_LENGTH 200 #define ARGS_NAME_DEBUG "-debug" #define DEBUG "-debug=" -#define MAX_PRINTLINE_LENGTH 2000 +#define MAX_PRINTLINE_LENGTH 12000 #define MAX_PATH_LENGTH 2000 #define MAX_ARGUMENT_LENGTH 400 #define MAX_PARAMNAME_LENGTH 50 @@ -136,12 +136,13 @@ void CreateLogFile(char* FunctionName, char **fullname) int i=0, ifail = ITK_ok; //date_t status_now; //char* date_string = NULL; - char date_string[MAX_PATH_LENGTH]; + char logFileDir[MAX_PATH_LENGTH]; char logFileName[MAX_PATH_LENGTH]; char* session_uid = NULL; tag_t session_tag = NULLTAG; + char date_string[MAX_PATH_LENGTH]; time_t now; struct tm *p; @@ -231,9 +232,6 @@ void WriteLog(const char* format, ...) va_start(arg, format); vsprintf(tmp, format, arg); va_end(arg); - - //----------print to command window for trace--------// - printf("%s\n", tmp); //print message to log file fprintf(logFile, "%s\n", tmp); diff --git a/General/General/common_itk_util.h b/General/General/common_itk_util.h index 79360ab..3460dd4 100644 --- a/General/General/common_itk_util.h +++ b/General/General/common_itk_util.h @@ -23,7 +23,7 @@ extern "C" { obj = NULL; \ } \ } -void ECHO(char *format, ...); +//void ECHO(char *format, ...); void CreateLogFile(char* FunctionName, char **fullname); void WriteLog(const char* format, ...); void CloseLog(void); diff --git a/General/General/epm_handler_common.h b/General/General/epm_handler_common.h index 15d011f..a2b9646 100644 --- a/General/General/epm_handler_common.h +++ b/General/General/epm_handler_common.h @@ -50,13 +50,41 @@ int CHINT_task_complete(EPM_action_message_t msg); int CHINT_cossheet_upgrade(EPM_action_message_t msg); int CHINT_SendOAMaterial(EPM_action_message_t msg); int CHINT_GetFrock(EPM_action_message_t msg); +int CHINT_ECN_SendOA(EPM_action_message_t msg); +int CHINT_Assignment(EPM_action_message_t msg); +int CHINT_SavePost(METHOD_message_t* msg, va_list args); +bool isTcm(tag_t mantr); +bool isBomViewTcm(tag_t mantr); +void TCMAndOwner(tag_t matnrTop); //user service end #ifdef __cplusplus } #endif -#endif - +#endif +#define OBJECT_NAME "object_name" +#define CCP_NAME "变压器" +#define OBJECTTYPE "object_type" +#define PROCURETYPE "ZT2_Procure Revision" +#define WBSNO "zt2_WBSNo" +#define MATERIALNO "zt2_MaterialNo" +#define REVISIONID "item_revision_id" +#define SPECIFICATION "IMAN_specification" +#define PDF "pdf" +#define S_GCDM "S_GCDM" //工厂 +#define LOG_PATH "D:\\Siemens\\ECNtoOAlog" //工厂 +#define PROP_GROUP_NAME "name" //组ID +#define MAX_PATH_LENGTHE 2000 +#define JSON_TXDJ "S_txdj" +#define PROP_PRODUCT "zt2_SZProduct" +#define PROP_PROCESS "zt2_SZProcess" +#define S_ProductFeature "S_ProductFeature" //工厂 +#define S_Product "产品" +#define S_Process "过程" +#define S_ZSChange "正式更改" +#define S_LSChange "临时更改" +#define BL_QUANTITY "bl_quantity" +#define BL_LINE_OBJECT "bl_line_object" #define ITKCALL( argument ) \ { \ int retcode = argument; \ diff --git a/General/General/epm_register_handler.cpp b/General/General/epm_register_handler.cpp index af20a22..6a20517 100644 --- a/General/General/epm_register_handler.cpp +++ b/General/General/epm_register_handler.cpp @@ -184,7 +184,7 @@ extern DLLAPI int USERSERVICE_custom_register_handlers(int *decision, va_list ar printf("Registering action handler chint_add_to_workflow successful\n"); } else { - printf("Registering action handler chint_remove_other_deisgndata failed %d\n", ifail); + printf("Registering action handler chint_add_to_workflow failed %d\n", ifail); } ifail = EPM_register_action_handler("chint_remove_other_deisgndata", "chint_remove_other_deisgndata", (EPM_action_handler_t)chint_remove_other_deisgndata); if (ifail == 0) { @@ -254,6 +254,24 @@ extern DLLAPI int USERSERVICE_custom_register_handlers(int *decision, va_list ar else { printf("Registering action handler CHINT_GetFrock failed %d\n", ifail); } + //oa 变更传递OA + ifail = EPM_register_action_handler("chint_ecn_to_oa", "chint_ecn_to_oa", (EPM_action_handler_t)CHINT_ECN_SendOA); + if (ifail == 0) { + printf("Registering action handler chint_ecn_to_oa successful\n"); + } + else { + printf("Registering action handler chint_ecn_to_oa failed %d\n", ifail); + } + //3.9.2.2.1流程指派人员自动获取 + ifail = EPM_register_action_handler("CHINT_Assignment", "CHINT_Assignment", (EPM_action_handler_t)CHINT_Assignment); + if (ifail == 0) { + printf("Registering action handler CHINT_Assignment successful\n"); + } + else { + printf("Registering action handler CHINT_Assignment failed %d\n", ifail); + } + + return ifail; } // @@ -261,7 +279,14 @@ extern DLLAPI int USERSERVICE_custom_register_handlers(int *decision, va_list ar //register service method extern DLLAPI int USERSERVICE_custom_register_methods(int *decision, va_list args) { - + { //2023 12 27 新增项目更新后操作 + METHOD_id_t mth_tag; + METHOD_find_method("Item", "IMAN_save", &mth_tag); + if (mth_tag.id != 0) { + METHOD_add_action(mth_tag, METHOD_post_action_type, (METHOD_function_t)CHINT_SavePost, NULL); + printf("注册ItemRevision函数成功!\n"); + } + } { int numberOfArguments = 1; int returnValueType = USERARG_STRING_TYPE; diff --git a/General/General/tc_util.cpp b/General/General/tc_util.cpp index 27be661..afe2210 100644 --- a/General/General/tc_util.cpp +++ b/General/General/tc_util.cpp @@ -69,9 +69,6 @@ void ECHO(char *format, ...) printf( msg ); TC_write_syslog( msg ); } - - - /** * 获取首选项 */ diff --git a/General/General/tc_util.h b/General/General/tc_util.h index cf8e557..97c86f6 100644 --- a/General/General/tc_util.h +++ b/General/General/tc_util.h @@ -45,6 +45,7 @@ //#include #include #include "string_utils.h" +#include "ocilib.h" using namespace std; diff --git a/General/General/tinyxml2.cpp b/General/General/tinyxml2.cpp new file mode 100644 index 0000000..2449256 --- /dev/null +++ b/General/General/tinyxml2.cpp @@ -0,0 +1,2956 @@ +/* +Original code by Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include "tinyxml2.h" + +#include // yes, this one new style header, is in the Android SDK. +#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) +# include +# include +#else +# include +# include +#endif + +#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) +// Microsoft Visual Studio, version 2005 and higher. Not WinCE. +/*int _snprintf_s( + char *buffer, + size_t sizeOfBuffer, + size_t count, + const char *format [, + argument] ... +);*/ +static inline int TIXML_SNPRINTF(char* buffer, size_t size, const char* format, ...) +{ + va_list va; + va_start(va, format); + const int result = vsnprintf_s(buffer, size, _TRUNCATE, format, va); + va_end(va); + return result; +} + +static inline int TIXML_VSNPRINTF(char* buffer, size_t size, const char* format, va_list va) +{ + const int result = vsnprintf_s(buffer, size, _TRUNCATE, format, va); + return result; +} + +#define TIXML_VSCPRINTF _vscprintf +#define TIXML_SSCANF sscanf_s +#elif defined _MSC_VER +// Microsoft Visual Studio 2003 and earlier or WinCE +#define TIXML_SNPRINTF _snprintf +#define TIXML_VSNPRINTF _vsnprintf +#define TIXML_SSCANF sscanf +#if (_MSC_VER < 1400 ) && (!defined WINCE) + // Microsoft Visual Studio 2003 and not WinCE. +#define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have. +#else + // Microsoft Visual Studio 2003 and earlier or WinCE. +static inline int TIXML_VSCPRINTF(const char* format, va_list va) +{ + int len = 512; + for (;;) { + len = len * 2; + char* str = new char[len](); + const int required = _vsnprintf(str, len, format, va); + delete[] str; + if (required != -1) { + TIXMLASSERT(required >= 0); + len = required; + break; + } + } + TIXMLASSERT(len >= 0); + return len; +} +#endif +#else +// GCC version 3 and higher +//#warning( "Using sn* functions." ) +#define TIXML_SNPRINTF snprintf +#define TIXML_VSNPRINTF vsnprintf +static inline int TIXML_VSCPRINTF(const char* format, va_list va) +{ + int len = vsnprintf(0, 0, format, va); + TIXMLASSERT(len >= 0); + return len; +} +#define TIXML_SSCANF sscanf +#endif + +#if defined(_WIN64) +#define TIXML_FSEEK _fseeki64 +#define TIXML_FTELL _ftelli64 +#elif defined(__APPLE__) +#define TIXML_FSEEK fseeko +#define TIXML_FTELL ftello +#elif defined(__x86_64__) +#define TIXML_FSEEK fseeko64 +#define TIXML_FTELL ftello64 +#else +#define TIXML_FSEEK fseek +#define TIXML_FTELL ftell +#endif + + +static const char LINE_FEED = static_cast(0x0a); // all line endings are normalized to LF +static const char LF = LINE_FEED; +static const char CARRIAGE_RETURN = static_cast(0x0d); // CR gets filtered out +static const char CR = CARRIAGE_RETURN; +static const char SINGLE_QUOTE = '\''; +static const char DOUBLE_QUOTE = '\"'; + +// Bunch of unicode info at: +// http://www.unicode.org/faq/utf_bom.html +// ef bb bf (Microsoft "lead bytes") - designates UTF-8 + +static const unsigned char TIXML_UTF_LEAD_0 = 0xefU; +static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; +static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; + +namespace tinyxml2 +{ + + struct Entity { + const char* pattern; + int length; + char value; + }; + + static const int NUM_ENTITIES = 5; + static const Entity entities[NUM_ENTITIES] = { + { "quot", 4, DOUBLE_QUOTE }, + { "amp", 3, '&' }, + { "apos", 4, SINGLE_QUOTE }, + { "lt", 2, '<' }, + { "gt", 2, '>' } + }; + + + StrPair::~StrPair() + { + Reset(); + } + + + void StrPair::TransferTo(StrPair* other) + { + if (this == other) { + return; + } + // This in effect implements the assignment operator by "moving" + // ownership (as in auto_ptr). + + TIXMLASSERT(other != 0); + TIXMLASSERT(other->_flags == 0); + TIXMLASSERT(other->_start == 0); + TIXMLASSERT(other->_end == 0); + + other->Reset(); + + other->_flags = _flags; + other->_start = _start; + other->_end = _end; + + _flags = 0; + _start = 0; + _end = 0; + } + + + void StrPair::Reset() + { + if (_flags & NEEDS_DELETE) { + delete[] _start; + } + _flags = 0; + _start = 0; + _end = 0; + } + + + void StrPair::SetStr(const char* str, int flags) + { + TIXMLASSERT(str); + Reset(); + size_t len = strlen(str); + TIXMLASSERT(_start == 0); + _start = new char[len + 1]; + memcpy(_start, str, len + 1); + _end = _start + len; + _flags = flags | NEEDS_DELETE; + } + + + char* StrPair::ParseText(char* p, const char* endTag, int strFlags, int* curLineNumPtr) + { + TIXMLASSERT(p); + TIXMLASSERT(endTag && *endTag); + TIXMLASSERT(curLineNumPtr); + + char* start = p; + const char endChar = *endTag; + size_t length = strlen(endTag); + + // Inner loop of text parsing. + while (*p) { + if (*p == endChar && strncmp(p, endTag, length) == 0) { + Set(start, p, strFlags); + return p + length; + } + else if (*p == '\n') { + ++(*curLineNumPtr); + } + ++p; + TIXMLASSERT(p); + } + return 0; + } + + + char* StrPair::ParseName(char* p) + { + if (!p || !(*p)) { + return 0; + } + if (!XMLUtil::IsNameStartChar(*p)) { + return 0; + } + + char* const start = p; + ++p; + while (*p && XMLUtil::IsNameChar(*p)) { + ++p; + } + + Set(start, p, 0); + return p; + } + + + void StrPair::CollapseWhitespace() + { + // Adjusting _start would cause undefined behavior on delete[] + TIXMLASSERT((_flags & NEEDS_DELETE) == 0); + // Trim leading space. + _start = XMLUtil::SkipWhiteSpace(_start, 0); + + if (*_start) { + const char* p = _start; // the read pointer + char* q = _start; // the write pointer + + while (*p) { + if (XMLUtil::IsWhiteSpace(*p)) { + p = XMLUtil::SkipWhiteSpace(p, 0); + if (*p == 0) { + break; // don't write to q; this trims the trailing space. + } + *q = ' '; + ++q; + } + *q = *p; + ++q; + ++p; + } + *q = 0; + } + } + + + const char* StrPair::GetStr() + { + TIXMLASSERT(_start); + TIXMLASSERT(_end); + if (_flags & NEEDS_FLUSH) { + *_end = 0; + _flags ^= NEEDS_FLUSH; + + if (_flags) { + const char* p = _start; // the read pointer + char* q = _start; // the write pointer + + while (p < _end) { + if ((_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR) { + // CR-LF pair becomes LF + // CR alone becomes LF + // LF-CR becomes LF + if (*(p + 1) == LF) { + p += 2; + } + else { + ++p; + } + *q = LF; + ++q; + } + else if ((_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF) { + if (*(p + 1) == CR) { + p += 2; + } + else { + ++p; + } + *q = LF; + ++q; + } + else if ((_flags & NEEDS_ENTITY_PROCESSING) && *p == '&') { + // Entities handled by tinyXML2: + // - special entities in the entity table [in/out] + // - numeric character reference [in] + // 中 or 中 + + if (*(p + 1) == '#') { + const int buflen = 10; + char buf[buflen] = { 0 }; + int len = 0; + const char* adjusted = const_cast(XMLUtil::GetCharacterRef(p, buf, &len)); + if (adjusted == 0) { + *q = *p; + ++p; + ++q; + } + else { + TIXMLASSERT(0 <= len && len <= buflen); + TIXMLASSERT(q + len <= adjusted); + p = adjusted; + memcpy(q, buf, len); + q += len; + } + } + else { + bool entityFound = false; + for (int i = 0; i < NUM_ENTITIES; ++i) { + const Entity& entity = entities[i]; + if (strncmp(p + 1, entity.pattern, entity.length) == 0 + && *(p + entity.length + 1) == ';') { + // Found an entity - convert. + *q = entity.value; + ++q; + p += entity.length + 2; + entityFound = true; + break; + } + } + if (!entityFound) { + // fixme: treat as error? + ++p; + ++q; + } + } + } + else { + *q = *p; + ++p; + ++q; + } + } + *q = 0; + } + // The loop below has plenty going on, and this + // is a less useful mode. Break it out. + if (_flags & NEEDS_WHITESPACE_COLLAPSING) { + CollapseWhitespace(); + } + _flags = (_flags & NEEDS_DELETE); + } + TIXMLASSERT(_start); + return _start; + } + + + + + // --------- XMLUtil ----------- // + + const char* XMLUtil::writeBoolTrue = "true"; + const char* XMLUtil::writeBoolFalse = "false"; + + void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse) + { + static const char* defTrue = "true"; + static const char* defFalse = "false"; + + writeBoolTrue = (writeTrue) ? writeTrue : defTrue; + writeBoolFalse = (writeFalse) ? writeFalse : defFalse; + } + + + const char* XMLUtil::ReadBOM(const char* p, bool* bom) + { + TIXMLASSERT(p); + TIXMLASSERT(bom); + *bom = false; + const unsigned char* pu = reinterpret_cast(p); + // Check for BOM: + if (*(pu + 0) == TIXML_UTF_LEAD_0 + && *(pu + 1) == TIXML_UTF_LEAD_1 + && *(pu + 2) == TIXML_UTF_LEAD_2) { + *bom = true; + p += 3; + } + TIXMLASSERT(p); + return p; + } + + + void XMLUtil::ConvertUTF32ToUTF8(unsigned long input, char* output, int* length) + { + const unsigned long BYTE_MASK = 0xBF; + const unsigned long BYTE_MARK = 0x80; + const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + + if (input < 0x80) { + *length = 1; + } + else if (input < 0x800) { + *length = 2; + } + else if (input < 0x10000) { + *length = 3; + } + else if (input < 0x200000) { + *length = 4; + } + else { + *length = 0; // This code won't convert this correctly anyway. + return; + } + + output += *length; + + // Scary scary fall throughs are annotated with carefully designed comments + // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc + switch (*length) { + case 4: + --output; + *output = static_cast((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + //fall through + case 3: + --output; + *output = static_cast((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + //fall through + case 2: + --output; + *output = static_cast((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + //fall through + case 1: + --output; + *output = static_cast(input | FIRST_BYTE_MARK[*length]); + break; + default: + TIXMLASSERT(false); + } + } + + + const char* XMLUtil::GetCharacterRef(const char* p, char* value, int* length) + { + // Presume an entity, and pull it out. + *length = 0; + + if (*(p + 1) == '#' && *(p + 2)) { + unsigned long ucs = 0; + TIXMLASSERT(sizeof(ucs) >= 4); + ptrdiff_t delta = 0; + unsigned mult = 1; + static const char SEMICOLON = ';'; + + if (*(p + 2) == 'x') { + // Hexadecimal. + const char* q = p + 3; + if (!(*q)) { + return 0; + } + + q = strchr(q, SEMICOLON); + + if (!q) { + return 0; + } + TIXMLASSERT(*q == SEMICOLON); + + delta = q - p; + --q; + + while (*q != 'x') { + unsigned int digit = 0; + + if (*q >= '0' && *q <= '9') { + digit = *q - '0'; + } + else if (*q >= 'a' && *q <= 'f') { + digit = *q - 'a' + 10; + } + else if (*q >= 'A' && *q <= 'F') { + digit = *q - 'A' + 10; + } + else { + return 0; + } + TIXMLASSERT(digit < 16); + TIXMLASSERT(digit == 0 || mult <= UINT_MAX / digit); + const unsigned int digitScaled = mult * digit; + TIXMLASSERT(ucs <= ULONG_MAX - digitScaled); + ucs += digitScaled; + TIXMLASSERT(mult <= UINT_MAX / 16); + mult *= 16; + --q; + } + } + else { + // Decimal. + const char* q = p + 2; + if (!(*q)) { + return 0; + } + + q = strchr(q, SEMICOLON); + + if (!q) { + return 0; + } + TIXMLASSERT(*q == SEMICOLON); + + delta = q - p; + --q; + + while (*q != '#') { + if (*q >= '0' && *q <= '9') { + const unsigned int digit = *q - '0'; + TIXMLASSERT(digit < 10); + TIXMLASSERT(digit == 0 || mult <= UINT_MAX / digit); + const unsigned int digitScaled = mult * digit; + TIXMLASSERT(ucs <= ULONG_MAX - digitScaled); + ucs += digitScaled; + } + else { + return 0; + } + TIXMLASSERT(mult <= UINT_MAX / 10); + mult *= 10; + --q; + } + } + // convert the UCS to UTF-8 + ConvertUTF32ToUTF8(ucs, value, length); + return p + delta + 1; + } + return p + 1; + } + + + void XMLUtil::ToStr(int v, char* buffer, int bufferSize) + { + TIXML_SNPRINTF(buffer, bufferSize, "%d", v); + } + + + void XMLUtil::ToStr(unsigned v, char* buffer, int bufferSize) + { + TIXML_SNPRINTF(buffer, bufferSize, "%u", v); + } + + + void XMLUtil::ToStr(bool v, char* buffer, int bufferSize) + { + TIXML_SNPRINTF(buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse); + } + + /* + ToStr() of a number is a very tricky topic. + https://github.com/leethomason/tinyxml2/issues/106 + */ + void XMLUtil::ToStr(float v, char* buffer, int bufferSize) + { + TIXML_SNPRINTF(buffer, bufferSize, "%.8g", v); + } + + + void XMLUtil::ToStr(double v, char* buffer, int bufferSize) + { + TIXML_SNPRINTF(buffer, bufferSize, "%.17g", v); + } + + + void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize) + { + // horrible syntax trick to make the compiler happy about %lld + TIXML_SNPRINTF(buffer, bufferSize, "%lld", static_cast(v)); + } + + void XMLUtil::ToStr(uint64_t v, char* buffer, int bufferSize) + { + // horrible syntax trick to make the compiler happy about %llu + TIXML_SNPRINTF(buffer, bufferSize, "%llu", (long long)v); + } + + bool XMLUtil::ToInt(const char* str, int* value) + { + if (TIXML_SSCANF(str, "%d", value) == 1) { + return true; + } + return false; + } + + bool XMLUtil::ToUnsigned(const char* str, unsigned* value) + { + if (TIXML_SSCANF(str, "%u", value) == 1) { + return true; + } + return false; + } + + bool XMLUtil::ToBool(const char* str, bool* value) + { + int ival = 0; + if (ToInt(str, &ival)) { + *value = (ival == 0) ? false : true; + return true; + } + static const char* TRUE_VALS[] = { "true", "True", "TRUE", 0 }; + static const char* FALSE_VALS[] = { "false", "False", "FALSE", 0 }; + + for (int i = 0; TRUE_VALS[i]; ++i) { + if (StringEqual(str, TRUE_VALS[i])) { + *value = true; + return true; + } + } + for (int i = 0; FALSE_VALS[i]; ++i) { + if (StringEqual(str, FALSE_VALS[i])) { + *value = false; + return true; + } + } + return false; + } + + + bool XMLUtil::ToFloat(const char* str, float* value) + { + if (TIXML_SSCANF(str, "%f", value) == 1) { + return true; + } + return false; + } + + + bool XMLUtil::ToDouble(const char* str, double* value) + { + if (TIXML_SSCANF(str, "%lf", value) == 1) { + return true; + } + return false; + } + + + bool XMLUtil::ToInt64(const char* str, int64_t* value) + { + long long v = 0; // horrible syntax trick to make the compiler happy about %lld + if (TIXML_SSCANF(str, "%lld", &v) == 1) { + *value = static_cast(v); + return true; + } + return false; + } + + + bool XMLUtil::ToUnsigned64(const char* str, uint64_t* value) { + unsigned long long v = 0; // horrible syntax trick to make the compiler happy about %llu + if (TIXML_SSCANF(str, "%llu", &v) == 1) { + *value = (uint64_t)v; + return true; + } + return false; + } + + + char* XMLDocument::Identify(char* p, XMLNode** node) + { + TIXMLASSERT(node); + TIXMLASSERT(p); + char* const start = p; + int const startLine = _parseCurLineNum; + p = XMLUtil::SkipWhiteSpace(p, &_parseCurLineNum); + if (!*p) { + *node = 0; + TIXMLASSERT(p); + return p; + } + + // These strings define the matching patterns: + static const char* xmlHeader = { "(_commentPool); + returnNode->_parseLineNum = _parseCurLineNum; + p += xmlHeaderLen; + } + else if (XMLUtil::StringEqual(p, commentHeader, commentHeaderLen)) { + returnNode = CreateUnlinkedNode(_commentPool); + returnNode->_parseLineNum = _parseCurLineNum; + p += commentHeaderLen; + } + else if (XMLUtil::StringEqual(p, cdataHeader, cdataHeaderLen)) { + XMLText* text = CreateUnlinkedNode(_textPool); + returnNode = text; + returnNode->_parseLineNum = _parseCurLineNum; + p += cdataHeaderLen; + text->SetCData(true); + } + else if (XMLUtil::StringEqual(p, dtdHeader, dtdHeaderLen)) { + returnNode = CreateUnlinkedNode(_commentPool); + returnNode->_parseLineNum = _parseCurLineNum; + p += dtdHeaderLen; + } + else if (XMLUtil::StringEqual(p, elementHeader, elementHeaderLen)) { + returnNode = CreateUnlinkedNode(_elementPool); + returnNode->_parseLineNum = _parseCurLineNum; + p += elementHeaderLen; + } + else { + returnNode = CreateUnlinkedNode(_textPool); + returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character + p = start; // Back it up, all the text counts. + _parseCurLineNum = startLine; + } + + TIXMLASSERT(returnNode); + TIXMLASSERT(p); + *node = returnNode; + return p; + } + + + bool XMLDocument::Accept(XMLVisitor* visitor) const + { + TIXMLASSERT(visitor); + if (visitor->VisitEnter(*this)) { + for (const XMLNode* node = FirstChild(); node; node = node->NextSibling()) { + if (!node->Accept(visitor)) { + break; + } + } + } + return visitor->VisitExit(*this); + } + + + // --------- XMLNode ----------- // + + XMLNode::XMLNode(XMLDocument* doc) : + _document(doc), + _parent(0), + _value(), + _parseLineNum(0), + _firstChild(0), _lastChild(0), + _prev(0), _next(0), + _userData(0), + _memPool(0) + { + } + + + XMLNode::~XMLNode() + { + DeleteChildren(); + if (_parent) { + _parent->Unlink(this); + } + } + + const char* XMLNode::Value() const + { + // Edge case: XMLDocuments don't have a Value. Return null. + if (this->ToDocument()) + return 0; + return _value.GetStr(); + } + + void XMLNode::SetValue(const char* str, bool staticMem) + { + if (staticMem) { + _value.SetInternedStr(str); + } + else { + _value.SetStr(str); + } + } + + XMLNode* XMLNode::DeepClone(XMLDocument* target) const + { + XMLNode* clone = this->ShallowClone(target); + if (!clone) return 0; + + for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) { + XMLNode* childClone = child->DeepClone(target); + TIXMLASSERT(childClone); + clone->InsertEndChild(childClone); + } + return clone; + } + + void XMLNode::DeleteChildren() + { + while (_firstChild) { + TIXMLASSERT(_lastChild); + DeleteChild(_firstChild); + } + _firstChild = _lastChild = 0; + } + + + void XMLNode::Unlink(XMLNode* child) + { + TIXMLASSERT(child); + TIXMLASSERT(child->_document == _document); + TIXMLASSERT(child->_parent == this); + if (child == _firstChild) { + _firstChild = _firstChild->_next; + } + if (child == _lastChild) { + _lastChild = _lastChild->_prev; + } + + if (child->_prev) { + child->_prev->_next = child->_next; + } + if (child->_next) { + child->_next->_prev = child->_prev; + } + child->_next = 0; + child->_prev = 0; + child->_parent = 0; + } + + + void XMLNode::DeleteChild(XMLNode* node) + { + TIXMLASSERT(node); + TIXMLASSERT(node->_document == _document); + TIXMLASSERT(node->_parent == this); + Unlink(node); + TIXMLASSERT(node->_prev == 0); + TIXMLASSERT(node->_next == 0); + TIXMLASSERT(node->_parent == 0); + DeleteNode(node); + } + + + XMLNode* XMLNode::InsertEndChild(XMLNode* addThis) + { + TIXMLASSERT(addThis); + if (addThis->_document != _document) { + TIXMLASSERT(false); + return 0; + } + InsertChildPreamble(addThis); + + if (_lastChild) { + TIXMLASSERT(_firstChild); + TIXMLASSERT(_lastChild->_next == 0); + _lastChild->_next = addThis; + addThis->_prev = _lastChild; + _lastChild = addThis; + + addThis->_next = 0; + } + else { + TIXMLASSERT(_firstChild == 0); + _firstChild = _lastChild = addThis; + + addThis->_prev = 0; + addThis->_next = 0; + } + addThis->_parent = this; + return addThis; + } + + + XMLNode* XMLNode::InsertFirstChild(XMLNode* addThis) + { + TIXMLASSERT(addThis); + if (addThis->_document != _document) { + TIXMLASSERT(false); + return 0; + } + InsertChildPreamble(addThis); + + if (_firstChild) { + TIXMLASSERT(_lastChild); + TIXMLASSERT(_firstChild->_prev == 0); + + _firstChild->_prev = addThis; + addThis->_next = _firstChild; + _firstChild = addThis; + + addThis->_prev = 0; + } + else { + TIXMLASSERT(_lastChild == 0); + _firstChild = _lastChild = addThis; + + addThis->_prev = 0; + addThis->_next = 0; + } + addThis->_parent = this; + return addThis; + } + + + XMLNode* XMLNode::InsertAfterChild(XMLNode* afterThis, XMLNode* addThis) + { + TIXMLASSERT(addThis); + if (addThis->_document != _document) { + TIXMLASSERT(false); + return 0; + } + + TIXMLASSERT(afterThis); + + if (afterThis->_parent != this) { + TIXMLASSERT(false); + return 0; + } + if (afterThis == addThis) { + // Current state: BeforeThis -> AddThis -> OneAfterAddThis + // Now AddThis must disappear from it's location and then + // reappear between BeforeThis and OneAfterAddThis. + // So just leave it where it is. + return addThis; + } + + if (afterThis->_next == 0) { + // The last node or the only node. + return InsertEndChild(addThis); + } + InsertChildPreamble(addThis); + addThis->_prev = afterThis; + addThis->_next = afterThis->_next; + afterThis->_next->_prev = addThis; + afterThis->_next = addThis; + addThis->_parent = this; + return addThis; + } + + + + + const XMLElement* XMLNode::FirstChildElement(const char* name) const + { + for (const XMLNode* node = _firstChild; node; node = node->_next) { + const XMLElement* element = node->ToElementWithName(name); + if (element) { + return element; + } + } + return 0; + } + + + const XMLElement* XMLNode::LastChildElement(const char* name) const + { + for (const XMLNode* node = _lastChild; node; node = node->_prev) { + const XMLElement* element = node->ToElementWithName(name); + if (element) { + return element; + } + } + return 0; + } + + + const XMLElement* XMLNode::NextSiblingElement(const char* name) const + { + for (const XMLNode* node = _next; node; node = node->_next) { + const XMLElement* element = node->ToElementWithName(name); + if (element) { + return element; + } + } + return 0; + } + + + const XMLElement* XMLNode::PreviousSiblingElement(const char* name) const + { + for (const XMLNode* node = _prev; node; node = node->_prev) { + const XMLElement* element = node->ToElementWithName(name); + if (element) { + return element; + } + } + return 0; + } + + + char* XMLNode::ParseDeep(char* p, StrPair* parentEndTag, int* curLineNumPtr) + { + // This is a recursive method, but thinking about it "at the current level" + // it is a pretty simple flat list: + // + // + // + // With a special case: + // + // + // + // + // Where the closing element (/foo) *must* be the next thing after the opening + // element, and the names must match. BUT the tricky bit is that the closing + // element will be read by the child. + // + // 'endTag' is the end tag for this node, it is returned by a call to a child. + // 'parentEnd' is the end tag for the parent, which is filled in and returned. + + XMLDocument::DepthTracker tracker(_document); + if (_document->Error()) + return 0; + + while (p && *p) { + XMLNode* node = 0; + + p = _document->Identify(p, &node); + TIXMLASSERT(p); + if (node == 0) { + break; + } + + const int initialLineNum = node->_parseLineNum; + + StrPair endTag; + p = node->ParseDeep(p, &endTag, curLineNumPtr); + if (!p) { + DeleteNode(node); + if (!_document->Error()) { + _document->SetError(XML_ERROR_PARSING, initialLineNum, 0); + } + break; + } + + const XMLDeclaration* const decl = node->ToDeclaration(); + if (decl) { + // Declarations are only allowed at document level + // + // Multiple declarations are allowed but all declarations + // must occur before anything else. + // + // Optimized due to a security test case. If the first node is + // a declaration, and the last node is a declaration, then only + // declarations have so far been added. + bool wellLocated = false; + + if (ToDocument()) { + if (FirstChild()) { + wellLocated = + FirstChild() && + FirstChild()->ToDeclaration() && + LastChild() && + LastChild()->ToDeclaration(); + } + else { + wellLocated = true; + } + } + if (!wellLocated) { + _document->SetError(XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value()); + DeleteNode(node); + break; + } + } + + XMLElement* ele = node->ToElement(); + if (ele) { + // We read the end tag. Return it to the parent. + if (ele->ClosingType() == XMLElement::CLOSING) { + if (parentEndTag) { + ele->_value.TransferTo(parentEndTag); + } + node->_memPool->SetTracked(); // created and then immediately deleted. + DeleteNode(node); + return p; + } + + // Handle an end tag returned to this level. + // And handle a bunch of annoying errors. + bool mismatch = false; + if (endTag.Empty()) { + if (ele->ClosingType() == XMLElement::OPEN) { + mismatch = true; + } + } + else { + if (ele->ClosingType() != XMLElement::OPEN) { + mismatch = true; + } + else if (!XMLUtil::StringEqual(endTag.GetStr(), ele->Name())) { + mismatch = true; + } + } + if (mismatch) { + _document->SetError(XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name()); + DeleteNode(node); + break; + } + } + InsertEndChild(node); + } + return 0; + } + + /*static*/ void XMLNode::DeleteNode(XMLNode* node) + { + if (node == 0) { + return; + } + TIXMLASSERT(node->_document); + if (!node->ToDocument()) { + node->_document->MarkInUse(node); + } + + MemPool* pool = node->_memPool; + node->~XMLNode(); + pool->Free(node); + } + + void XMLNode::InsertChildPreamble(XMLNode* insertThis) const + { + TIXMLASSERT(insertThis); + TIXMLASSERT(insertThis->_document == _document); + + if (insertThis->_parent) { + insertThis->_parent->Unlink(insertThis); + } + else { + insertThis->_document->MarkInUse(insertThis); + insertThis->_memPool->SetTracked(); + } + } + + const XMLElement* XMLNode::ToElementWithName(const char* name) const + { + const XMLElement* element = this->ToElement(); + if (element == 0) { + return 0; + } + if (name == 0) { + return element; + } + if (XMLUtil::StringEqual(element->Name(), name)) { + return element; + } + return 0; + } + + // --------- XMLText ---------- // + char* XMLText::ParseDeep(char* p, StrPair*, int* curLineNumPtr) + { + if (this->CData()) { + p = _value.ParseText(p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr); + if (!p) { + _document->SetError(XML_ERROR_PARSING_CDATA, _parseLineNum, 0); + } + return p; + } + else { + int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES; + if (_document->WhitespaceMode() == COLLAPSE_WHITESPACE) { + flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING; + } + + p = _value.ParseText(p, "<", flags, curLineNumPtr); + if (p && *p) { + return p - 1; + } + if (!p) { + _document->SetError(XML_ERROR_PARSING_TEXT, _parseLineNum, 0); + } + } + return 0; + } + + + XMLNode* XMLText::ShallowClone(XMLDocument* doc) const + { + if (!doc) { + doc = _document; + } + XMLText* text = doc->NewText(Value()); // fixme: this will always allocate memory. Intern? + text->SetCData(this->CData()); + return text; + } + + + bool XMLText::ShallowEqual(const XMLNode* compare) const + { + TIXMLASSERT(compare); + const XMLText* text = compare->ToText(); + return (text && XMLUtil::StringEqual(text->Value(), Value())); + } + + + bool XMLText::Accept(XMLVisitor* visitor) const + { + TIXMLASSERT(visitor); + return visitor->Visit(*this); + } + + + // --------- XMLComment ---------- // + + XMLComment::XMLComment(XMLDocument* doc) : XMLNode(doc) + { + } + + + XMLComment::~XMLComment() + { + } + + + char* XMLComment::ParseDeep(char* p, StrPair*, int* curLineNumPtr) + { + // Comment parses as text. + p = _value.ParseText(p, "-->", StrPair::COMMENT, curLineNumPtr); + if (p == 0) { + _document->SetError(XML_ERROR_PARSING_COMMENT, _parseLineNum, 0); + } + return p; + } + + + XMLNode* XMLComment::ShallowClone(XMLDocument* doc) const + { + if (!doc) { + doc = _document; + } + XMLComment* comment = doc->NewComment(Value()); // fixme: this will always allocate memory. Intern? + return comment; + } + + + bool XMLComment::ShallowEqual(const XMLNode* compare) const + { + TIXMLASSERT(compare); + const XMLComment* comment = compare->ToComment(); + return (comment && XMLUtil::StringEqual(comment->Value(), Value())); + } + + + bool XMLComment::Accept(XMLVisitor* visitor) const + { + TIXMLASSERT(visitor); + return visitor->Visit(*this); + } + + + // --------- XMLDeclaration ---------- // + + XMLDeclaration::XMLDeclaration(XMLDocument* doc) : XMLNode(doc) + { + } + + + XMLDeclaration::~XMLDeclaration() + { + //printf( "~XMLDeclaration\n" ); + } + + + char* XMLDeclaration::ParseDeep(char* p, StrPair*, int* curLineNumPtr) + { + // Declaration parses as text. + p = _value.ParseText(p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr); + if (p == 0) { + _document->SetError(XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0); + } + return p; + } + + + XMLNode* XMLDeclaration::ShallowClone(XMLDocument* doc) const + { + if (!doc) { + doc = _document; + } + XMLDeclaration* dec = doc->NewDeclaration(Value()); // fixme: this will always allocate memory. Intern? + return dec; + } + + + bool XMLDeclaration::ShallowEqual(const XMLNode* compare) const + { + TIXMLASSERT(compare); + const XMLDeclaration* declaration = compare->ToDeclaration(); + return (declaration && XMLUtil::StringEqual(declaration->Value(), Value())); + } + + + + bool XMLDeclaration::Accept(XMLVisitor* visitor) const + { + TIXMLASSERT(visitor); + return visitor->Visit(*this); + } + + // --------- XMLUnknown ---------- // + + XMLUnknown::XMLUnknown(XMLDocument* doc) : XMLNode(doc) + { + } + + + XMLUnknown::~XMLUnknown() + { + } + + + char* XMLUnknown::ParseDeep(char* p, StrPair*, int* curLineNumPtr) + { + // Unknown parses as text. + p = _value.ParseText(p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr); + if (!p) { + _document->SetError(XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0); + } + return p; + } + + + XMLNode* XMLUnknown::ShallowClone(XMLDocument* doc) const + { + if (!doc) { + doc = _document; + } + XMLUnknown* text = doc->NewUnknown(Value()); // fixme: this will always allocate memory. Intern? + return text; + } + + + bool XMLUnknown::ShallowEqual(const XMLNode* compare) const + { + TIXMLASSERT(compare); + const XMLUnknown* unknown = compare->ToUnknown(); + return (unknown && XMLUtil::StringEqual(unknown->Value(), Value())); + } + + + bool XMLUnknown::Accept(XMLVisitor* visitor) const + { + TIXMLASSERT(visitor); + return visitor->Visit(*this); + } + + // --------- XMLAttribute ---------- // + + const char* XMLAttribute::Name() const + { + return _name.GetStr(); + } + + const char* XMLAttribute::Value() const + { + return _value.GetStr(); + } + + char* XMLAttribute::ParseDeep(char* p, bool processEntities, int* curLineNumPtr) + { + // Parse using the name rules: bug fix, was using ParseText before + p = _name.ParseName(p); + if (!p || !*p) { + return 0; + } + + // Skip white space before = + p = XMLUtil::SkipWhiteSpace(p, curLineNumPtr); + if (*p != '=') { + return 0; + } + + ++p; // move up to opening quote + p = XMLUtil::SkipWhiteSpace(p, curLineNumPtr); + if (*p != '\"' && *p != '\'') { + return 0; + } + + const char endTag[2] = { *p, 0 }; + ++p; // move past opening quote + + p = _value.ParseText(p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr); + return p; + } + + + void XMLAttribute::SetName(const char* n) + { + _name.SetStr(n); + } + + + XMLError XMLAttribute::QueryIntValue(int* value) const + { + if (XMLUtil::ToInt(Value(), value)) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; + } + + + XMLError XMLAttribute::QueryUnsignedValue(unsigned int* value) const + { + if (XMLUtil::ToUnsigned(Value(), value)) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; + } + + + XMLError XMLAttribute::QueryInt64Value(int64_t* value) const + { + if (XMLUtil::ToInt64(Value(), value)) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; + } + + + XMLError XMLAttribute::QueryUnsigned64Value(uint64_t* value) const + { + if (XMLUtil::ToUnsigned64(Value(), value)) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; + } + + + XMLError XMLAttribute::QueryBoolValue(bool* value) const + { + if (XMLUtil::ToBool(Value(), value)) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; + } + + + XMLError XMLAttribute::QueryFloatValue(float* value) const + { + if (XMLUtil::ToFloat(Value(), value)) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; + } + + + XMLError XMLAttribute::QueryDoubleValue(double* value) const + { + if (XMLUtil::ToDouble(Value(), value)) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; + } + + + void XMLAttribute::SetAttribute(const char* v) + { + _value.SetStr(v); + } + + + void XMLAttribute::SetAttribute(int v) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + _value.SetStr(buf); + } + + + void XMLAttribute::SetAttribute(unsigned v) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + _value.SetStr(buf); + } + + + void XMLAttribute::SetAttribute(int64_t v) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + _value.SetStr(buf); + } + + void XMLAttribute::SetAttribute(uint64_t v) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + _value.SetStr(buf); + } + + + void XMLAttribute::SetAttribute(bool v) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + _value.SetStr(buf); + } + + void XMLAttribute::SetAttribute(double v) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + _value.SetStr(buf); + } + + void XMLAttribute::SetAttribute(float v) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + _value.SetStr(buf); + } + + + // --------- XMLElement ---------- // + XMLElement::XMLElement(XMLDocument* doc) : XMLNode(doc), + _closingType(OPEN), + _rootAttribute(0) + { + } + + + XMLElement::~XMLElement() + { + while (_rootAttribute) { + XMLAttribute* next = _rootAttribute->_next; + DeleteAttribute(_rootAttribute); + _rootAttribute = next; + } + } + + + const XMLAttribute* XMLElement::FindAttribute(const char* name) const + { + for (XMLAttribute* a = _rootAttribute; a; a = a->_next) { + if (XMLUtil::StringEqual(a->Name(), name)) { + return a; + } + } + return 0; + } + + + const char* XMLElement::Attribute(const char* name, const char* value) const + { + const XMLAttribute* a = FindAttribute(name); + if (!a) { + return 0; + } + if (!value || XMLUtil::StringEqual(a->Value(), value)) { + return a->Value(); + } + return 0; + } + + int XMLElement::IntAttribute(const char* name, int defaultValue) const + { + int i = defaultValue; + QueryIntAttribute(name, &i); + return i; + } + + unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const + { + unsigned i = defaultValue; + QueryUnsignedAttribute(name, &i); + return i; + } + + int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const + { + int64_t i = defaultValue; + QueryInt64Attribute(name, &i); + return i; + } + + uint64_t XMLElement::Unsigned64Attribute(const char* name, uint64_t defaultValue) const + { + uint64_t i = defaultValue; + QueryUnsigned64Attribute(name, &i); + return i; + } + + bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const + { + bool b = defaultValue; + QueryBoolAttribute(name, &b); + return b; + } + + double XMLElement::DoubleAttribute(const char* name, double defaultValue) const + { + double d = defaultValue; + QueryDoubleAttribute(name, &d); + return d; + } + + float XMLElement::FloatAttribute(const char* name, float defaultValue) const + { + float f = defaultValue; + QueryFloatAttribute(name, &f); + return f; + } + + const char* XMLElement::GetText() const + { + if (FirstChild() && FirstChild()->ToText()) { + return FirstChild()->Value(); + } + return 0; + } + + + void XMLElement::SetText(const char* inText) + { + if (FirstChild() && FirstChild()->ToText()) + FirstChild()->SetValue(inText); + else { + XMLText* theText = GetDocument()->NewText(inText); + InsertFirstChild(theText); + } + } + + + void XMLElement::SetText(int v) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + SetText(buf); + } + + + void XMLElement::SetText(unsigned v) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + SetText(buf); + } + + + void XMLElement::SetText(int64_t v) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + SetText(buf); + } + + void XMLElement::SetText(uint64_t v) { + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + SetText(buf); + } + + + void XMLElement::SetText(bool v) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + SetText(buf); + } + + + void XMLElement::SetText(float v) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + SetText(buf); + } + + + void XMLElement::SetText(double v) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + SetText(buf); + } + + + XMLError XMLElement::QueryIntText(int* ival) const + { + if (FirstChild() && FirstChild()->ToText()) { + const char* t = FirstChild()->Value(); + if (XMLUtil::ToInt(t, ival)) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; + } + + + XMLError XMLElement::QueryUnsignedText(unsigned* uval) const + { + if (FirstChild() && FirstChild()->ToText()) { + const char* t = FirstChild()->Value(); + if (XMLUtil::ToUnsigned(t, uval)) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; + } + + + XMLError XMLElement::QueryInt64Text(int64_t* ival) const + { + if (FirstChild() && FirstChild()->ToText()) { + const char* t = FirstChild()->Value(); + if (XMLUtil::ToInt64(t, ival)) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; + } + + + XMLError XMLElement::QueryUnsigned64Text(uint64_t* ival) const + { + if (FirstChild() && FirstChild()->ToText()) { + const char* t = FirstChild()->Value(); + if (XMLUtil::ToUnsigned64(t, ival)) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; + } + + + XMLError XMLElement::QueryBoolText(bool* bval) const + { + if (FirstChild() && FirstChild()->ToText()) { + const char* t = FirstChild()->Value(); + if (XMLUtil::ToBool(t, bval)) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; + } + + + XMLError XMLElement::QueryDoubleText(double* dval) const + { + if (FirstChild() && FirstChild()->ToText()) { + const char* t = FirstChild()->Value(); + if (XMLUtil::ToDouble(t, dval)) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; + } + + + XMLError XMLElement::QueryFloatText(float* fval) const + { + if (FirstChild() && FirstChild()->ToText()) { + const char* t = FirstChild()->Value(); + if (XMLUtil::ToFloat(t, fval)) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; + } + + int XMLElement::IntText(int defaultValue) const + { + int i = defaultValue; + QueryIntText(&i); + return i; + } + + unsigned XMLElement::UnsignedText(unsigned defaultValue) const + { + unsigned i = defaultValue; + QueryUnsignedText(&i); + return i; + } + + int64_t XMLElement::Int64Text(int64_t defaultValue) const + { + int64_t i = defaultValue; + QueryInt64Text(&i); + return i; + } + + uint64_t XMLElement::Unsigned64Text(uint64_t defaultValue) const + { + uint64_t i = defaultValue; + QueryUnsigned64Text(&i); + return i; + } + + bool XMLElement::BoolText(bool defaultValue) const + { + bool b = defaultValue; + QueryBoolText(&b); + return b; + } + + double XMLElement::DoubleText(double defaultValue) const + { + double d = defaultValue; + QueryDoubleText(&d); + return d; + } + + float XMLElement::FloatText(float defaultValue) const + { + float f = defaultValue; + QueryFloatText(&f); + return f; + } + + + XMLAttribute* XMLElement::FindOrCreateAttribute(const char* name) + { + XMLAttribute* last = 0; + XMLAttribute* attrib = 0; + for (attrib = _rootAttribute; + attrib; + last = attrib, attrib = attrib->_next) { + if (XMLUtil::StringEqual(attrib->Name(), name)) { + break; + } + } + if (!attrib) { + attrib = CreateAttribute(); + TIXMLASSERT(attrib); + if (last) { + TIXMLASSERT(last->_next == 0); + last->_next = attrib; + } + else { + TIXMLASSERT(_rootAttribute == 0); + _rootAttribute = attrib; + } + attrib->SetName(name); + } + return attrib; + } + + + void XMLElement::DeleteAttribute(const char* name) + { + XMLAttribute* prev = 0; + for (XMLAttribute* a = _rootAttribute; a; a = a->_next) { + if (XMLUtil::StringEqual(name, a->Name())) { + if (prev) { + prev->_next = a->_next; + } + else { + _rootAttribute = a->_next; + } + DeleteAttribute(a); + break; + } + prev = a; + } + } + + + char* XMLElement::ParseAttributes(char* p, int* curLineNumPtr) + { + XMLAttribute* prevAttribute = 0; + + // Read the attributes. + while (p) { + p = XMLUtil::SkipWhiteSpace(p, curLineNumPtr); + if (!(*p)) { + _document->SetError(XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name()); + return 0; + } + + // attribute. + if (XMLUtil::IsNameStartChar(*p)) { + XMLAttribute* attrib = CreateAttribute(); + TIXMLASSERT(attrib); + attrib->_parseLineNum = _document->_parseCurLineNum; + + const int attrLineNum = attrib->_parseLineNum; + + p = attrib->ParseDeep(p, _document->ProcessEntities(), curLineNumPtr); + if (!p || Attribute(attrib->Name())) { + DeleteAttribute(attrib); + _document->SetError(XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name()); + return 0; + } + // There is a minor bug here: if the attribute in the source xml + // document is duplicated, it will not be detected and the + // attribute will be doubly added. However, tracking the 'prevAttribute' + // avoids re-scanning the attribute list. Preferring performance for + // now, may reconsider in the future. + if (prevAttribute) { + TIXMLASSERT(prevAttribute->_next == 0); + prevAttribute->_next = attrib; + } + else { + TIXMLASSERT(_rootAttribute == 0); + _rootAttribute = attrib; + } + prevAttribute = attrib; + } + // end of the tag + else if (*p == '>') { + ++p; + break; + } + // end of the tag + else if (*p == '/' && *(p + 1) == '>') { + _closingType = CLOSED; + return p + 2; // done; sealed element. + } + else { + _document->SetError(XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0); + return 0; + } + } + return p; + } + + void XMLElement::DeleteAttribute(XMLAttribute* attribute) + { + if (attribute == 0) { + return; + } + MemPool* pool = attribute->_memPool; + attribute->~XMLAttribute(); + pool->Free(attribute); + } + + XMLAttribute* XMLElement::CreateAttribute() + { + TIXMLASSERT(sizeof(XMLAttribute) == _document->_attributePool.ItemSize()); + XMLAttribute* attrib = new (_document->_attributePool.Alloc()) XMLAttribute(); + TIXMLASSERT(attrib); + attrib->_memPool = &_document->_attributePool; + attrib->_memPool->SetTracked(); + return attrib; + } + + + XMLElement* XMLElement::InsertNewChildElement(const char* name) + { + XMLElement* node = _document->NewElement(name); + return InsertEndChild(node) ? node : 0; + } + + XMLComment* XMLElement::InsertNewComment(const char* comment) + { + XMLComment* node = _document->NewComment(comment); + return InsertEndChild(node) ? node : 0; + } + + XMLText* XMLElement::InsertNewText(const char* text) + { + XMLText* node = _document->NewText(text); + return InsertEndChild(node) ? node : 0; + } + + XMLDeclaration* XMLElement::InsertNewDeclaration(const char* text) + { + XMLDeclaration* node = _document->NewDeclaration(text); + return InsertEndChild(node) ? node : 0; + } + + XMLUnknown* XMLElement::InsertNewUnknown(const char* text) + { + XMLUnknown* node = _document->NewUnknown(text); + return InsertEndChild(node) ? node : 0; + } + + + + // + // + // foobar + // + char* XMLElement::ParseDeep(char* p, StrPair* parentEndTag, int* curLineNumPtr) + { + // Read the element name. + p = XMLUtil::SkipWhiteSpace(p, curLineNumPtr); + + // The closing element is the form. It is + // parsed just like a regular element then deleted from + // the DOM. + if (*p == '/') { + _closingType = CLOSING; + ++p; + } + + p = _value.ParseName(p); + if (_value.Empty()) { + return 0; + } + + p = ParseAttributes(p, curLineNumPtr); + if (!p || !*p || _closingType != OPEN) { + return p; + } + + p = XMLNode::ParseDeep(p, parentEndTag, curLineNumPtr); + return p; + } + + + + XMLNode* XMLElement::ShallowClone(XMLDocument* doc) const + { + if (!doc) { + doc = _document; + } + XMLElement* element = doc->NewElement(Value()); // fixme: this will always allocate memory. Intern? + for (const XMLAttribute* a = FirstAttribute(); a; a = a->Next()) { + element->SetAttribute(a->Name(), a->Value()); // fixme: this will always allocate memory. Intern? + } + return element; + } + + + bool XMLElement::ShallowEqual(const XMLNode* compare) const + { + TIXMLASSERT(compare); + const XMLElement* other = compare->ToElement(); + if (other && XMLUtil::StringEqual(other->Name(), Name())) { + + const XMLAttribute* a = FirstAttribute(); + const XMLAttribute* b = other->FirstAttribute(); + + while (a && b) { + if (!XMLUtil::StringEqual(a->Value(), b->Value())) { + return false; + } + a = a->Next(); + b = b->Next(); + } + if (a || b) { + // different count + return false; + } + return true; + } + return false; + } + + + bool XMLElement::Accept(XMLVisitor* visitor) const + { + TIXMLASSERT(visitor); + if (visitor->VisitEnter(*this, _rootAttribute)) { + for (const XMLNode* node = FirstChild(); node; node = node->NextSibling()) { + if (!node->Accept(visitor)) { + break; + } + } + } + return visitor->VisitExit(*this); + } + + + // --------- XMLDocument ----------- // + + // Warning: List must match 'enum XMLError' + const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = { + "XML_SUCCESS", + "XML_NO_ATTRIBUTE", + "XML_WRONG_ATTRIBUTE_TYPE", + "XML_ERROR_FILE_NOT_FOUND", + "XML_ERROR_FILE_COULD_NOT_BE_OPENED", + "XML_ERROR_FILE_READ_ERROR", + "XML_ERROR_PARSING_ELEMENT", + "XML_ERROR_PARSING_ATTRIBUTE", + "XML_ERROR_PARSING_TEXT", + "XML_ERROR_PARSING_CDATA", + "XML_ERROR_PARSING_COMMENT", + "XML_ERROR_PARSING_DECLARATION", + "XML_ERROR_PARSING_UNKNOWN", + "XML_ERROR_EMPTY_DOCUMENT", + "XML_ERROR_MISMATCHED_ELEMENT", + "XML_ERROR_PARSING", + "XML_CAN_NOT_CONVERT_TEXT", + "XML_NO_TEXT_NODE", + "XML_ELEMENT_DEPTH_EXCEEDED" + }; + + + XMLDocument::XMLDocument(bool processEntities, Whitespace whitespaceMode) : + XMLNode(0), + _writeBOM(false), + _processEntities(processEntities), + _errorID(XML_SUCCESS), + _whitespaceMode(whitespaceMode), + _errorStr(), + _errorLineNum(0), + _charBuffer(0), + _parseCurLineNum(0), + _parsingDepth(0), + _unlinked(), + _elementPool(), + _attributePool(), + _textPool(), + _commentPool() + { + // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+) + _document = this; + } + + + XMLDocument::~XMLDocument() + { + Clear(); + } + + + void XMLDocument::MarkInUse(const XMLNode* const node) + { + TIXMLASSERT(node); + TIXMLASSERT(node->_parent == 0); + + for (int i = 0; i < _unlinked.Size(); ++i) { + if (node == _unlinked[i]) { + _unlinked.SwapRemove(i); + break; + } + } + } + + void XMLDocument::Clear() + { + DeleteChildren(); + while (_unlinked.Size()) { + DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete. + } + +#ifdef TINYXML2_DEBUG + const bool hadError = Error(); +#endif + ClearError(); + + delete[] _charBuffer; + _charBuffer = 0; + _parsingDepth = 0; + +#if 0 + _textPool.Trace("text"); + _elementPool.Trace("element"); + _commentPool.Trace("comment"); + _attributePool.Trace("attribute"); +#endif + +#ifdef TINYXML2_DEBUG + if (!hadError) { + TIXMLASSERT(_elementPool.CurrentAllocs() == _elementPool.Untracked()); + TIXMLASSERT(_attributePool.CurrentAllocs() == _attributePool.Untracked()); + TIXMLASSERT(_textPool.CurrentAllocs() == _textPool.Untracked()); + TIXMLASSERT(_commentPool.CurrentAllocs() == _commentPool.Untracked()); + } +#endif + } + + + void XMLDocument::DeepCopy(XMLDocument* target) const + { + TIXMLASSERT(target); + if (target == this) { + return; // technically success - a no-op. + } + + target->Clear(); + for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) { + target->InsertEndChild(node->DeepClone(target)); + } + } + + XMLElement* XMLDocument::NewElement(const char* name) + { + XMLElement* ele = CreateUnlinkedNode(_elementPool); + ele->SetName(name); + return ele; + } + + + XMLComment* XMLDocument::NewComment(const char* str) + { + XMLComment* comment = CreateUnlinkedNode(_commentPool); + comment->SetValue(str); + return comment; + } + + + XMLText* XMLDocument::NewText(const char* str) + { + XMLText* text = CreateUnlinkedNode(_textPool); + text->SetValue(str); + return text; + } + + + XMLDeclaration* XMLDocument::NewDeclaration(const char* str) + { + XMLDeclaration* dec = CreateUnlinkedNode(_commentPool); + dec->SetValue(str ? str : "xml version=\"1.0\" encoding=\"UTF-8\""); + return dec; + } + + + XMLUnknown* XMLDocument::NewUnknown(const char* str) + { + XMLUnknown* unk = CreateUnlinkedNode(_commentPool); + unk->SetValue(str); + return unk; + } + + static FILE* callfopen(const char* filepath, const char* mode) + { + TIXMLASSERT(filepath); + TIXMLASSERT(mode); +#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) + FILE* fp = 0; + const errno_t err = fopen_s(&fp, filepath, mode); + if (err) { + return 0; + } +#else + FILE* fp = fopen(filepath, mode); +#endif + return fp; + } + + void XMLDocument::DeleteNode(XMLNode* node) { + TIXMLASSERT(node); + TIXMLASSERT(node->_document == this); + if (node->_parent) { + node->_parent->DeleteChild(node); + } + else { + // Isn't in the tree. + // Use the parent delete. + // Also, we need to mark it tracked: we 'know' + // it was never used. + node->_memPool->SetTracked(); + // Call the static XMLNode version: + XMLNode::DeleteNode(node); + } + } + + + XMLError XMLDocument::LoadFile(const char* filename) + { + if (!filename) { + TIXMLASSERT(false); + SetError(XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename="); + return _errorID; + } + + Clear(); + FILE* fp = callfopen(filename, "rb"); + if (!fp) { + SetError(XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename); + return _errorID; + } + LoadFile(fp); + fclose(fp); + return _errorID; + } + + XMLError XMLDocument::LoadFile(FILE* fp) + { + Clear(); + + TIXML_FSEEK(fp, 0, SEEK_SET); + if (fgetc(fp) == EOF && ferror(fp) != 0) { + SetError(XML_ERROR_FILE_READ_ERROR, 0, 0); + return _errorID; + } + + TIXML_FSEEK(fp, 0, SEEK_END); + + unsigned long long filelength; + { + const long long fileLengthSigned = TIXML_FTELL(fp); + TIXML_FSEEK(fp, 0, SEEK_SET); + if (fileLengthSigned == -1L) { + SetError(XML_ERROR_FILE_READ_ERROR, 0, 0); + return _errorID; + } + TIXMLASSERT(fileLengthSigned >= 0); + filelength = static_cast(fileLengthSigned); + } + + const size_t maxSizeT = static_cast(-1); + // We'll do the comparison as an unsigned long long, because that's guaranteed to be at + // least 8 bytes, even on a 32-bit platform. + if (filelength >= static_cast(maxSizeT)) { + // Cannot handle files which won't fit in buffer together with null terminator + SetError(XML_ERROR_FILE_READ_ERROR, 0, 0); + return _errorID; + } + + if (filelength == 0) { + SetError(XML_ERROR_EMPTY_DOCUMENT, 0, 0); + return _errorID; + } + + const size_t size = static_cast(filelength); + TIXMLASSERT(_charBuffer == 0); + _charBuffer = new char[size + 1]; + const size_t read = fread(_charBuffer, 1, size, fp); + if (read != size) { + SetError(XML_ERROR_FILE_READ_ERROR, 0, 0); + return _errorID; + } + + _charBuffer[size] = 0; + + Parse(); + return _errorID; + } + + + XMLError XMLDocument::SaveFile(const char* filename, bool compact) + { + if (!filename) { + TIXMLASSERT(false); + SetError(XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename="); + return _errorID; + } + + FILE* fp = callfopen(filename, "w"); + if (!fp) { + SetError(XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename); + return _errorID; + } + SaveFile(fp, compact); + fclose(fp); + return _errorID; + } + + + XMLError XMLDocument::SaveFile(FILE* fp, bool compact) + { + // Clear any error from the last save, otherwise it will get reported + // for *this* call. + ClearError(); + XMLPrinter stream(fp, compact); + Print(&stream); + return _errorID; + } + + + XMLError XMLDocument::Parse(const char* p, size_t len) + { + Clear(); + + if (len == 0 || !p || !*p) { + SetError(XML_ERROR_EMPTY_DOCUMENT, 0, 0); + return _errorID; + } + if (len == static_cast(-1)) { + len = strlen(p); + } + TIXMLASSERT(_charBuffer == 0); + _charBuffer = new char[len + 1]; + memcpy(_charBuffer, p, len); + _charBuffer[len] = 0; + + Parse(); + if (Error()) { + // clean up now essentially dangling memory. + // and the parse fail can put objects in the + // pools that are dead and inaccessible. + DeleteChildren(); + _elementPool.Clear(); + _attributePool.Clear(); + _textPool.Clear(); + _commentPool.Clear(); + } + return _errorID; + } + + + void XMLDocument::Print(XMLPrinter* streamer) const + { + if (streamer) { + Accept(streamer); + } + else { + XMLPrinter stdoutStreamer(stdout); + Accept(&stdoutStreamer); + } + } + + + void XMLDocument::SetError(XMLError error, int lineNum, const char* format, ...) + { + TIXMLASSERT(error >= 0 && error < XML_ERROR_COUNT); + _errorID = error; + _errorLineNum = lineNum; + _errorStr.Reset(); + + const size_t BUFFER_SIZE = 1000; + char* buffer = new char[BUFFER_SIZE]; + + TIXMLASSERT(sizeof(error) <= sizeof(int)); + TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d", ErrorIDToName(error), int(error), int(error), lineNum); + + if (format) { + size_t len = strlen(buffer); + TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": "); + len = strlen(buffer); + + va_list va; + va_start(va, format); + TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va); + va_end(va); + } + _errorStr.SetStr(buffer); + delete[] buffer; + } + + + /*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID) + { + TIXMLASSERT(errorID >= 0 && errorID < XML_ERROR_COUNT); + const char* errorName = _errorNames[errorID]; + TIXMLASSERT(errorName && errorName[0]); + return errorName; + } + + const char* XMLDocument::ErrorStr() const + { + return _errorStr.Empty() ? "" : _errorStr.GetStr(); + } + + + void XMLDocument::PrintError() const + { + printf("%s\n", ErrorStr()); + } + + const char* XMLDocument::ErrorName() const + { + return ErrorIDToName(_errorID); + } + + void XMLDocument::Parse() + { + TIXMLASSERT(NoChildren()); // Clear() must have been called previously + TIXMLASSERT(_charBuffer); + _parseCurLineNum = 1; + _parseLineNum = 1; + char* p = _charBuffer; + p = XMLUtil::SkipWhiteSpace(p, &_parseCurLineNum); + p = const_cast(XMLUtil::ReadBOM(p, &_writeBOM)); + if (!*p) { + SetError(XML_ERROR_EMPTY_DOCUMENT, 0, 0); + return; + } + ParseDeep(p, 0, &_parseCurLineNum); + } + + void XMLDocument::PushDepth() + { + _parsingDepth++; + if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) { + SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep."); + } + } + + void XMLDocument::PopDepth() + { + TIXMLASSERT(_parsingDepth > 0); + --_parsingDepth; + } + + XMLPrinter::XMLPrinter(FILE* file, bool compact, int depth) : + _elementJustOpened(false), + _stack(), + _firstElement(true), + _fp(file), + _depth(depth), + _textDepth(-1), + _processEntities(true), + _compactMode(compact), + _buffer() + { + for (int i = 0; i < ENTITY_RANGE; ++i) { + _entityFlag[i] = false; + _restrictedEntityFlag[i] = false; + } + for (int i = 0; i < NUM_ENTITIES; ++i) { + const char entityValue = entities[i].value; + const unsigned char flagIndex = static_cast(entityValue); + TIXMLASSERT(flagIndex < ENTITY_RANGE); + _entityFlag[flagIndex] = true; + } + _restrictedEntityFlag[static_cast('&')] = true; + _restrictedEntityFlag[static_cast('<')] = true; + _restrictedEntityFlag[static_cast('>')] = true; // not required, but consistency is nice + _buffer.Push(0); + } + + + void XMLPrinter::Print(const char* format, ...) + { + va_list va; + va_start(va, format); + + if (_fp) { + vfprintf(_fp, format, va); + } + else { + const int len = TIXML_VSCPRINTF(format, va); + // Close out and re-start the va-args + va_end(va); + TIXMLASSERT(len >= 0); + va_start(va, format); + TIXMLASSERT(_buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0); + char* p = _buffer.PushArr(len) - 1; // back up over the null terminator. + TIXML_VSNPRINTF(p, len + 1, format, va); + } + va_end(va); + } + + + void XMLPrinter::Write(const char* data, size_t size) + { + if (_fp) { + fwrite(data, sizeof(char), size, _fp); + } + else { + char* p = _buffer.PushArr(static_cast(size)) - 1; // back up over the null terminator. + memcpy(p, data, size); + p[size] = 0; + } + } + + + void XMLPrinter::Putc(char ch) + { + if (_fp) { + fputc(ch, _fp); + } + else { + char* p = _buffer.PushArr(sizeof(char)) - 1; // back up over the null terminator. + p[0] = ch; + p[1] = 0; + } + } + + + void XMLPrinter::PrintSpace(int depth) + { + for (int i = 0; i < depth; ++i) { + Write(" "); + } + } + + + void XMLPrinter::PrintString(const char* p, bool restricted) + { + // Look for runs of bytes between entities to print. + const char* q = p; + + if (_processEntities) { + const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag; + while (*q) { + TIXMLASSERT(p <= q); + // Remember, char is sometimes signed. (How many times has that bitten me?) + if (*q > 0 && *q < ENTITY_RANGE) { + // Check for entities. If one is found, flush + // the stream up until the entity, write the + // entity, and keep looking. + if (flag[static_cast(*q)]) { + while (p < q) { + const size_t delta = q - p; + const int toPrint = (INT_MAX < delta) ? INT_MAX : static_cast(delta); + Write(p, toPrint); + p += toPrint; + } + bool entityPatternPrinted = false; + for (int i = 0; i < NUM_ENTITIES; ++i) { + if (entities[i].value == *q) { + Putc('&'); + Write(entities[i].pattern, entities[i].length); + Putc(';'); + entityPatternPrinted = true; + break; + } + } + if (!entityPatternPrinted) { + // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release + TIXMLASSERT(false); + } + ++p; + } + } + ++q; + TIXMLASSERT(p <= q); + } + // Flush the remaining string. This will be the entire + // string if an entity wasn't found. + if (p < q) { + const size_t delta = q - p; + const int toPrint = (INT_MAX < delta) ? INT_MAX : static_cast(delta); + Write(p, toPrint); + } + } + else { + Write(p); + } + } + + + void XMLPrinter::PushHeader(bool writeBOM, bool writeDec) + { + if (writeBOM) { + static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 }; + Write(reinterpret_cast(bom)); + } + if (writeDec) { + PushDeclaration("xml version=\"1.0\""); + } + } + + + void XMLPrinter::OpenElement(const char* name, bool compactMode) + { + SealElementIfJustOpened(); + _stack.Push(name); + + if (_textDepth < 0 && !_firstElement && !compactMode) { + Putc('\n'); + PrintSpace(_depth); + } + + Write("<"); + Write(name); + + _elementJustOpened = true; + _firstElement = false; + ++_depth; + } + + + void XMLPrinter::PushAttribute(const char* name, const char* value) + { + TIXMLASSERT(_elementJustOpened); + Putc(' '); + Write(name); + Write("=\""); + PrintString(value, false); + Putc('\"'); + } + + + void XMLPrinter::PushAttribute(const char* name, int v) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + PushAttribute(name, buf); + } + + + void XMLPrinter::PushAttribute(const char* name, unsigned v) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + PushAttribute(name, buf); + } + + + void XMLPrinter::PushAttribute(const char* name, int64_t v) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + PushAttribute(name, buf); + } + + + void XMLPrinter::PushAttribute(const char* name, uint64_t v) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + PushAttribute(name, buf); + } + + + void XMLPrinter::PushAttribute(const char* name, bool v) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + PushAttribute(name, buf); + } + + + void XMLPrinter::PushAttribute(const char* name, double v) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + PushAttribute(name, buf); + } + + + void XMLPrinter::CloseElement(bool compactMode) + { + --_depth; + const char* name = _stack.Pop(); + + if (_elementJustOpened) { + Write("/>"); + } + else { + if (_textDepth < 0 && !compactMode) { + Putc('\n'); + PrintSpace(_depth); + } + Write(""); + } + + if (_textDepth == _depth) { + _textDepth = -1; + } + if (_depth == 0 && !compactMode) { + Putc('\n'); + } + _elementJustOpened = false; + } + + + void XMLPrinter::SealElementIfJustOpened() + { + if (!_elementJustOpened) { + return; + } + _elementJustOpened = false; + Putc('>'); + } + + + void XMLPrinter::PushText(const char* text, bool cdata) + { + _textDepth = _depth - 1; + + SealElementIfJustOpened(); + if (cdata) { + Write(""); + } + else { + PrintString(text, true); + } + } + + + void XMLPrinter::PushText(int64_t value) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(value, buf, BUF_SIZE); + PushText(buf, false); + } + + + void XMLPrinter::PushText(uint64_t value) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(value, buf, BUF_SIZE); + PushText(buf, false); + } + + + void XMLPrinter::PushText(int value) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(value, buf, BUF_SIZE); + PushText(buf, false); + } + + + void XMLPrinter::PushText(unsigned value) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(value, buf, BUF_SIZE); + PushText(buf, false); + } + + + void XMLPrinter::PushText(bool value) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(value, buf, BUF_SIZE); + PushText(buf, false); + } + + + void XMLPrinter::PushText(float value) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(value, buf, BUF_SIZE); + PushText(buf, false); + } + + + void XMLPrinter::PushText(double value) + { + char buf[BUF_SIZE]; + XMLUtil::ToStr(value, buf, BUF_SIZE); + PushText(buf, false); + } + + + void XMLPrinter::PushComment(const char* comment) + { + SealElementIfJustOpened(); + if (_textDepth < 0 && !_firstElement && !_compactMode) { + Putc('\n'); + PrintSpace(_depth); + } + _firstElement = false; + + Write(""); + } + + + void XMLPrinter::PushDeclaration(const char* value) + { + SealElementIfJustOpened(); + if (_textDepth < 0 && !_firstElement && !_compactMode) { + Putc('\n'); + PrintSpace(_depth); + } + _firstElement = false; + + Write(""); + } + + + void XMLPrinter::PushUnknown(const char* value) + { + SealElementIfJustOpened(); + if (_textDepth < 0 && !_firstElement && !_compactMode) { + Putc('\n'); + PrintSpace(_depth); + } + _firstElement = false; + + Write("'); + } + + + bool XMLPrinter::VisitEnter(const XMLDocument& doc) + { + _processEntities = doc.ProcessEntities(); + if (doc.HasBOM()) { + PushHeader(true, false); + } + return true; + } + + + bool XMLPrinter::VisitEnter(const XMLElement& element, const XMLAttribute* attribute) + { + const XMLElement* parentElem = 0; + if (element.Parent()) { + parentElem = element.Parent()->ToElement(); + } + const bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode; + OpenElement(element.Name(), compactMode); + while (attribute) { + PushAttribute(attribute->Name(), attribute->Value()); + attribute = attribute->Next(); + } + return true; + } + + + bool XMLPrinter::VisitExit(const XMLElement& element) + { + CloseElement(CompactMode(element)); + return true; + } + + + bool XMLPrinter::Visit(const XMLText& text) + { + PushText(text.Value(), text.CData()); + return true; + } + + + bool XMLPrinter::Visit(const XMLComment& comment) + { + PushComment(comment.Value()); + return true; + } + + bool XMLPrinter::Visit(const XMLDeclaration& declaration) + { + PushDeclaration(declaration.Value()); + return true; + } + + + bool XMLPrinter::Visit(const XMLUnknown& unknown) + { + PushUnknown(unknown.Value()); + return true; + } + +} // namespace tinyxml2 \ No newline at end of file diff --git a/General/General/tinyxml2.h b/General/General/tinyxml2.h new file mode 100644 index 0000000..bd42cee --- /dev/null +++ b/General/General/tinyxml2.h @@ -0,0 +1,2365 @@ +#pragma onc/* +Original code by Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef TINYXML2_INCLUDED +#define TINYXML2_INCLUDED + +#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) +# include +# include +# include +# include +# include +# if defined(__PS3__) +# include +# endif +#else +# include +# include +# include +# include +# include +#endif +#include + +/* + TODO: intern strings instead of allocation. +*/ +/* + gcc: + g++ -Wall -DTINYXML2_DEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe + + Formatting, Artistic Style: + AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h +*/ + +#if defined( _DEBUG ) || defined (__DEBUG__) +# ifndef TINYXML2_DEBUG +# define TINYXML2_DEBUG +# endif +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4251) +#endif + +#ifdef _WIN32 +# ifdef TINYXML2_EXPORT +# define TINYXML2_LIB __declspec(dllexport) +# elif defined(TINYXML2_IMPORT) +# define TINYXML2_LIB __declspec(dllimport) +# else +# define TINYXML2_LIB +# endif +#elif __GNUC__ >= 4 +# define TINYXML2_LIB __attribute__((visibility("default"))) +#else +# define TINYXML2_LIB +#endif + + +#if defined(TINYXML2_DEBUG) +# if defined(_MSC_VER) +# // "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like +# define TIXMLASSERT( x ) if ( !((void)0,(x))) { __debugbreak(); } +# elif defined (ANDROID_NDK) +# include +# define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); } +# else +# include +# define TIXMLASSERT assert +# endif +#else +# define TIXMLASSERT( x ) {} +#endif + + +/* Versioning, past 1.0.14: + http://semver.org/ +*/ +static const int TIXML2_MAJOR_VERSION = 8; +static const int TIXML2_MINOR_VERSION = 0; +static const int TIXML2_PATCH_VERSION = 0; + +#define TINYXML2_MAJOR_VERSION 8 +#define TINYXML2_MINOR_VERSION 0 +#define TINYXML2_PATCH_VERSION 0 + +// A fixed element depth limit is problematic. There needs to be a +// limit to avoid a stack overflow. However, that limit varies per +// system, and the capacity of the stack. On the other hand, it's a trivial +// attack that can result from ill, malicious, or even correctly formed XML, +// so there needs to be a limit in place. +static const int TINYXML2_MAX_ELEMENT_DEPTH = 100; + +namespace tinyxml2 +{ + class XMLDocument; + class XMLElement; + class XMLAttribute; + class XMLComment; + class XMLText; + class XMLDeclaration; + class XMLUnknown; + class XMLPrinter; + + /* + A class that wraps strings. Normally stores the start and end + pointers into the XML file itself, and will apply normalization + and entity translation if actually read. Can also store (and memory + manage) a traditional char[] + + Isn't clear why TINYXML2_LIB is needed; but seems to fix #719 + */ + class TINYXML2_LIB StrPair + { + public: + enum { + NEEDS_ENTITY_PROCESSING = 0x01, + NEEDS_NEWLINE_NORMALIZATION = 0x02, + NEEDS_WHITESPACE_COLLAPSING = 0x04, + + TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, + TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, + ATTRIBUTE_NAME = 0, + ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, + ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, + COMMENT = NEEDS_NEWLINE_NORMALIZATION + }; + + StrPair() : _flags(0), _start(0), _end(0) {} + ~StrPair(); + + void Set(char* start, char* end, int flags) { + TIXMLASSERT(start); + TIXMLASSERT(end); + Reset(); + _start = start; + _end = end; + _flags = flags | NEEDS_FLUSH; + } + + const char* GetStr(); + + bool Empty() const { + return _start == _end; + } + + void SetInternedStr(const char* str) { + Reset(); + _start = const_cast(str); + } + + void SetStr(const char* str, int flags = 0); + + char* ParseText(char* in, const char* endTag, int strFlags, int* curLineNumPtr); + char* ParseName(char* in); + + void TransferTo(StrPair* other); + void Reset(); + + private: + void CollapseWhitespace(); + + enum { + NEEDS_FLUSH = 0x100, + NEEDS_DELETE = 0x200 + }; + + int _flags; + char* _start; + char* _end; + + StrPair(const StrPair& other); // not supported + void operator=(const StrPair& other); // not supported, use TransferTo() + }; + + + /* + A dynamic array of Plain Old Data. Doesn't support constructors, etc. + Has a small initial memory pool, so that low or no usage will not + cause a call to new/delete + */ + template + class DynArray + { + public: + DynArray() : + _mem(_pool), + _allocated(INITIAL_SIZE), + _size(0) + { + } + + ~DynArray() { + if (_mem != _pool) { + delete[] _mem; + } + } + + void Clear() { + _size = 0; + } + + void Push(T t) { + TIXMLASSERT(_size < INT_MAX); + EnsureCapacity(_size + 1); + _mem[_size] = t; + ++_size; + } + + T* PushArr(int count) { + TIXMLASSERT(count >= 0); + TIXMLASSERT(_size <= INT_MAX - count); + EnsureCapacity(_size + count); + T* ret = &_mem[_size]; + _size += count; + return ret; + } + + T Pop() { + TIXMLASSERT(_size > 0); + --_size; + return _mem[_size]; + } + + void PopArr(int count) { + TIXMLASSERT(_size >= count); + _size -= count; + } + + bool Empty() const { + return _size == 0; + } + + T& operator[](int i) { + TIXMLASSERT(i >= 0 && i < _size); + return _mem[i]; + } + + const T& operator[](int i) const { + TIXMLASSERT(i >= 0 && i < _size); + return _mem[i]; + } + + const T& PeekTop() const { + TIXMLASSERT(_size > 0); + return _mem[_size - 1]; + } + + int Size() const { + TIXMLASSERT(_size >= 0); + return _size; + } + + int Capacity() const { + TIXMLASSERT(_allocated >= INITIAL_SIZE); + return _allocated; + } + + void SwapRemove(int i) { + TIXMLASSERT(i >= 0 && i < _size); + TIXMLASSERT(_size > 0); + _mem[i] = _mem[_size - 1]; + --_size; + } + + const T* Mem() const { + TIXMLASSERT(_mem); + return _mem; + } + + T* Mem() { + TIXMLASSERT(_mem); + return _mem; + } + + private: + DynArray(const DynArray&); // not supported + void operator=(const DynArray&); // not supported + + void EnsureCapacity(int cap) { + TIXMLASSERT(cap > 0); + if (cap > _allocated) { + TIXMLASSERT(cap <= INT_MAX / 2); + const int newAllocated = cap * 2; + T* newMem = new T[newAllocated]; + TIXMLASSERT(newAllocated >= _size); + memcpy(newMem, _mem, sizeof(T) * _size); // warning: not using constructors, only works for PODs + if (_mem != _pool) { + delete[] _mem; + } + _mem = newMem; + _allocated = newAllocated; + } + } + + T* _mem; + T _pool[INITIAL_SIZE]; + int _allocated; // objects allocated + int _size; // number objects in use + }; + + + /* + Parent virtual class of a pool for fast allocation + and deallocation of objects. + */ + class MemPool + { + public: + MemPool() {} + virtual ~MemPool() {} + + virtual int ItemSize() const = 0; + virtual void* Alloc() = 0; + virtual void Free(void*) = 0; + virtual void SetTracked() = 0; + }; + + + /* + Template child class to create pools of the correct type. + */ + template< int ITEM_SIZE > + class MemPoolT : public MemPool + { + public: + MemPoolT() : _blockPtrs(), _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {} + ~MemPoolT() { + MemPoolT< ITEM_SIZE >::Clear(); + } + + void Clear() { + // Delete the blocks. + while (!_blockPtrs.Empty()) { + Block* lastBlock = _blockPtrs.Pop(); + delete lastBlock; + } + _root = 0; + _currentAllocs = 0; + _nAllocs = 0; + _maxAllocs = 0; + _nUntracked = 0; + } + + virtual int ItemSize() const { + return ITEM_SIZE; + } + int CurrentAllocs() const { + return _currentAllocs; + } + + virtual void* Alloc() { + if (!_root) { + // Need a new block. + Block* block = new Block(); + _blockPtrs.Push(block); + + Item* blockItems = block->items; + for (int i = 0; i < ITEMS_PER_BLOCK - 1; ++i) { + blockItems[i].next = &(blockItems[i + 1]); + } + blockItems[ITEMS_PER_BLOCK - 1].next = 0; + _root = blockItems; + } + Item* const result = _root; + TIXMLASSERT(result != 0); + _root = _root->next; + + ++_currentAllocs; + if (_currentAllocs > _maxAllocs) { + _maxAllocs = _currentAllocs; + } + ++_nAllocs; + ++_nUntracked; + return result; + } + + virtual void Free(void* mem) { + if (!mem) { + return; + } + --_currentAllocs; + Item* item = static_cast(mem); +#ifdef TINYXML2_DEBUG + memset(item, 0xfe, sizeof(*item)); +#endif + item->next = _root; + _root = item; + } + void Trace(const char* name) { + printf("Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n", + name, _maxAllocs, _maxAllocs * ITEM_SIZE / 1024, _currentAllocs, + ITEM_SIZE, _nAllocs, _blockPtrs.Size()); + } + + void SetTracked() { + --_nUntracked; + } + + int Untracked() const { + return _nUntracked; + } + + // This number is perf sensitive. 4k seems like a good tradeoff on my machine. + // The test file is large, 170k. + // Release: VS2010 gcc(no opt) + // 1k: 4000 + // 2k: 4000 + // 4k: 3900 21000 + // 16k: 5200 + // 32k: 4300 + // 64k: 4000 21000 + // Declared public because some compilers do not accept to use ITEMS_PER_BLOCK + // in private part if ITEMS_PER_BLOCK is private + enum { ITEMS_PER_BLOCK = (4 * 1024) / ITEM_SIZE }; + + private: + MemPoolT(const MemPoolT&); // not supported + void operator=(const MemPoolT&); // not supported + + union Item { + Item* next; + char itemData[ITEM_SIZE]; + }; + struct Block { + Item items[ITEMS_PER_BLOCK]; + }; + DynArray< Block*, 10 > _blockPtrs; + Item* _root; + + int _currentAllocs; + int _nAllocs; + int _maxAllocs; + int _nUntracked; + }; + + + + /** + Implements the interface to the "Visitor pattern" (see the Accept() method.) + If you call the Accept() method, it requires being passed a XMLVisitor + class to handle callbacks. For nodes that contain other nodes (Document, Element) + you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs + are simply called with Visit(). + + If you return 'true' from a Visit method, recursive parsing will continue. If you return + false, no children of this node or its siblings will be visited. + + All flavors of Visit methods have a default implementation that returns 'true' (continue + visiting). You need to only override methods that are interesting to you. + + Generally Accept() is called on the XMLDocument, although all nodes support visiting. + + You should never change the document from a callback. + + @sa XMLNode::Accept() + */ + class TINYXML2_LIB XMLVisitor + { + public: + virtual ~XMLVisitor() {} + + /// Visit a document. + virtual bool VisitEnter(const XMLDocument& /*doc*/) { + return true; + } + /// Visit a document. + virtual bool VisitExit(const XMLDocument& /*doc*/) { + return true; + } + + /// Visit an element. + virtual bool VisitEnter(const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/) { + return true; + } + /// Visit an element. + virtual bool VisitExit(const XMLElement& /*element*/) { + return true; + } + + /// Visit a declaration. + virtual bool Visit(const XMLDeclaration& /*declaration*/) { + return true; + } + /// Visit a text node. + virtual bool Visit(const XMLText& /*text*/) { + return true; + } + /// Visit a comment node. + virtual bool Visit(const XMLComment& /*comment*/) { + return true; + } + /// Visit an unknown node. + virtual bool Visit(const XMLUnknown& /*unknown*/) { + return true; + } + }; + + // WARNING: must match XMLDocument::_errorNames[] + enum XMLError { + XML_SUCCESS = 0, + XML_NO_ATTRIBUTE, + XML_WRONG_ATTRIBUTE_TYPE, + XML_ERROR_FILE_NOT_FOUND, + XML_ERROR_FILE_COULD_NOT_BE_OPENED, + XML_ERROR_FILE_READ_ERROR, + XML_ERROR_PARSING_ELEMENT, + XML_ERROR_PARSING_ATTRIBUTE, + XML_ERROR_PARSING_TEXT, + XML_ERROR_PARSING_CDATA, + XML_ERROR_PARSING_COMMENT, + XML_ERROR_PARSING_DECLARATION, + XML_ERROR_PARSING_UNKNOWN, + XML_ERROR_EMPTY_DOCUMENT, + XML_ERROR_MISMATCHED_ELEMENT, + XML_ERROR_PARSING, + XML_CAN_NOT_CONVERT_TEXT, + XML_NO_TEXT_NODE, + XML_ELEMENT_DEPTH_EXCEEDED, + + XML_ERROR_COUNT + }; + + + /* + Utility functionality. + */ + class TINYXML2_LIB XMLUtil + { + public: + static const char* SkipWhiteSpace(const char* p, int* curLineNumPtr) { + TIXMLASSERT(p); + + while (IsWhiteSpace(*p)) { + if (curLineNumPtr && *p == '\n') { + ++(*curLineNumPtr); + } + ++p; + } + TIXMLASSERT(p); + return p; + } + static char* SkipWhiteSpace(char* const p, int* curLineNumPtr) { + return const_cast(SkipWhiteSpace(const_cast(p), curLineNumPtr)); + } + + // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't + // correct, but simple, and usually works. + static bool IsWhiteSpace(char p) { + return !IsUTF8Continuation(p) && isspace(static_cast(p)); + } + + inline static bool IsNameStartChar(unsigned char ch) { + if (ch >= 128) { + // This is a heuristic guess in attempt to not implement Unicode-aware isalpha() + return true; + } + if (isalpha(ch)) { + return true; + } + return ch == ':' || ch == '_'; + } + + inline static bool IsNameChar(unsigned char ch) { + return IsNameStartChar(ch) + || isdigit(ch) + || ch == '.' + || ch == '-'; + } + + inline static bool StringEqual(const char* p, const char* q, int nChar = INT_MAX) { + if (p == q) { + return true; + } + TIXMLASSERT(p); + TIXMLASSERT(q); + TIXMLASSERT(nChar >= 0); + return strncmp(p, q, nChar) == 0; + } + + inline static bool IsUTF8Continuation(const char p) { + return (p & 0x80) != 0; + } + + static const char* ReadBOM(const char* p, bool* hasBOM); + // p is the starting location, + // the UTF-8 value of the entity will be placed in value, and length filled in. + static const char* GetCharacterRef(const char* p, char* value, int* length); + static void ConvertUTF32ToUTF8(unsigned long input, char* output, int* length); + + // converts primitive types to strings + static void ToStr(int v, char* buffer, int bufferSize); + static void ToStr(unsigned v, char* buffer, int bufferSize); + static void ToStr(bool v, char* buffer, int bufferSize); + static void ToStr(float v, char* buffer, int bufferSize); + static void ToStr(double v, char* buffer, int bufferSize); + static void ToStr(int64_t v, char* buffer, int bufferSize); + static void ToStr(uint64_t v, char* buffer, int bufferSize); + + // converts strings to primitive types + static bool ToInt(const char* str, int* value); + static bool ToUnsigned(const char* str, unsigned* value); + static bool ToBool(const char* str, bool* value); + static bool ToFloat(const char* str, float* value); + static bool ToDouble(const char* str, double* value); + static bool ToInt64(const char* str, int64_t* value); + static bool ToUnsigned64(const char* str, uint64_t* value); + // Changes what is serialized for a boolean value. + // Default to "true" and "false". Shouldn't be changed + // unless you have a special testing or compatibility need. + // Be careful: static, global, & not thread safe. + // Be sure to set static const memory as parameters. + static void SetBoolSerialization(const char* writeTrue, const char* writeFalse); + + private: + static const char* writeBoolTrue; + static const char* writeBoolFalse; + }; + + + /** XMLNode is a base class for every object that is in the + XML Document Object Model (DOM), except XMLAttributes. + Nodes have siblings, a parent, and children which can + be navigated. A node is always in a XMLDocument. + The type of a XMLNode can be queried, and it can + be cast to its more defined type. + + A XMLDocument allocates memory for all its Nodes. + When the XMLDocument gets deleted, all its Nodes + will also be deleted. + + @verbatim + A Document can contain: Element (container or leaf) + Comment (leaf) + Unknown (leaf) + Declaration( leaf ) + + An Element can contain: Element (container or leaf) + Text (leaf) + Attributes (not on tree) + Comment (leaf) + Unknown (leaf) + + @endverbatim + */ + class TINYXML2_LIB XMLNode + { + friend class XMLDocument; + friend class XMLElement; + public: + + /// Get the XMLDocument that owns this XMLNode. + const XMLDocument* GetDocument() const { + TIXMLASSERT(_document); + return _document; + } + /// Get the XMLDocument that owns this XMLNode. + XMLDocument* GetDocument() { + TIXMLASSERT(_document); + return _document; + } + + /// Safely cast to an Element, or null. + virtual XMLElement* ToElement() { + return 0; + } + /// Safely cast to Text, or null. + virtual XMLText* ToText() { + return 0; + } + /// Safely cast to a Comment, or null. + virtual XMLComment* ToComment() { + return 0; + } + /// Safely cast to a Document, or null. + virtual XMLDocument* ToDocument() { + return 0; + } + /// Safely cast to a Declaration, or null. + virtual XMLDeclaration* ToDeclaration() { + return 0; + } + /// Safely cast to an Unknown, or null. + virtual XMLUnknown* ToUnknown() { + return 0; + } + + virtual const XMLElement* ToElement() const { + return 0; + } + virtual const XMLText* ToText() const { + return 0; + } + virtual const XMLComment* ToComment() const { + return 0; + } + virtual const XMLDocument* ToDocument() const { + return 0; + } + virtual const XMLDeclaration* ToDeclaration() const { + return 0; + } + virtual const XMLUnknown* ToUnknown() const { + return 0; + } + + /** The meaning of 'value' changes for the specific type. + @verbatim + Document: empty (NULL is returned, not an empty string) + Element: name of the element + Comment: the comment text + Unknown: the tag contents + Text: the text string + @endverbatim + */ + const char* Value() const; + + /** Set the Value of an XML node. + @sa Value() + */ + void SetValue(const char* val, bool staticMem = false); + + /// Gets the line number the node is in, if the document was parsed from a file. + int GetLineNum() const { return _parseLineNum; } + + /// Get the parent of this node on the DOM. + const XMLNode* Parent() const { + return _parent; + } + + XMLNode* Parent() { + return _parent; + } + + /// Returns true if this node has no children. + bool NoChildren() const { + return !_firstChild; + } + + /// Get the first child node, or null if none exists. + const XMLNode* FirstChild() const { + return _firstChild; + } + + XMLNode* FirstChild() { + return _firstChild; + } + + /** Get the first child element, or optionally the first child + element with the specified name. + */ + const XMLElement* FirstChildElement(const char* name = 0) const; + + XMLElement* FirstChildElement(const char* name = 0) { + return const_cast(const_cast(this)->FirstChildElement(name)); + } + + /// Get the last child node, or null if none exists. + const XMLNode* LastChild() const { + return _lastChild; + } + + XMLNode* LastChild() { + return _lastChild; + } + + /** Get the last child element or optionally the last child + element with the specified name. + */ + const XMLElement* LastChildElement(const char* name = 0) const; + + XMLElement* LastChildElement(const char* name = 0) { + return const_cast(const_cast(this)->LastChildElement(name)); + } + + /// Get the previous (left) sibling node of this node. + const XMLNode* PreviousSibling() const { + return _prev; + } + + XMLNode* PreviousSibling() { + return _prev; + } + + /// Get the previous (left) sibling element of this node, with an optionally supplied name. + const XMLElement* PreviousSiblingElement(const char* name = 0) const; + + XMLElement* PreviousSiblingElement(const char* name = 0) { + return const_cast(const_cast(this)->PreviousSiblingElement(name)); + } + + /// Get the next (right) sibling node of this node. + const XMLNode* NextSibling() const { + return _next; + } + + XMLNode* NextSibling() { + return _next; + } + + /// Get the next (right) sibling element of this node, with an optionally supplied name. + const XMLElement* NextSiblingElement(const char* name = 0) const; + + XMLElement* NextSiblingElement(const char* name = 0) { + return const_cast(const_cast(this)->NextSiblingElement(name)); + } + + /** + Add a child node as the last (right) child. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the node does not + belong to the same document. + */ + XMLNode* InsertEndChild(XMLNode* addThis); + + XMLNode* LinkEndChild(XMLNode* addThis) { + return InsertEndChild(addThis); + } + /** + Add a child node as the first (left) child. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the node does not + belong to the same document. + */ + XMLNode* InsertFirstChild(XMLNode* addThis); + /** + Add a node after the specified child node. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the afterThis node + is not a child of this node, or if the node does not + belong to the same document. + */ + XMLNode* InsertAfterChild(XMLNode* afterThis, XMLNode* addThis); + + /** + Delete all the children of this node. + */ + void DeleteChildren(); + + /** + Delete a child of this node. + */ + void DeleteChild(XMLNode* node); + + /** + Make a copy of this node, but not its children. + You may pass in a Document pointer that will be + the owner of the new Node. If the 'document' is + null, then the node returned will be allocated + from the current Document. (this->GetDocument()) + + Note: if called on a XMLDocument, this will return null. + */ + virtual XMLNode* ShallowClone(XMLDocument* document) const = 0; + + /** + Make a copy of this node and all its children. + + If the 'target' is null, then the nodes will + be allocated in the current document. If 'target' + is specified, the memory will be allocated is the + specified XMLDocument. + + NOTE: This is probably not the correct tool to + copy a document, since XMLDocuments can have multiple + top level XMLNodes. You probably want to use + XMLDocument::DeepCopy() + */ + XMLNode* DeepClone(XMLDocument* target) const; + + /** + Test if 2 nodes are the same, but don't test children. + The 2 nodes do not need to be in the same Document. + + Note: if called on a XMLDocument, this will return false. + */ + virtual bool ShallowEqual(const XMLNode* compare) const = 0; + + /** Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the + XML tree will be conditionally visited and the host will be called back + via the XMLVisitor interface. + + This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse + the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this + interface versus any other.) + + The interface has been based on ideas from: + + - http://www.saxproject.org/ + - http://c2.com/cgi/wiki?HierarchicalVisitorPattern + + Which are both good references for "visiting". + + An example of using Accept(): + @verbatim + XMLPrinter printer; + tinyxmlDoc.Accept( &printer ); + const char* xmlcstr = printer.CStr(); + @endverbatim + */ + virtual bool Accept(XMLVisitor* visitor) const = 0; + + /** + Set user data into the XMLNode. TinyXML-2 in + no way processes or interprets user data. + It is initially 0. + */ + void SetUserData(void* userData) { _userData = userData; } + + /** + Get user data set into the XMLNode. TinyXML-2 in + no way processes or interprets user data. + It is initially 0. + */ + void* GetUserData() const { return _userData; } + + protected: + explicit XMLNode(XMLDocument*); + virtual ~XMLNode(); + + virtual char* ParseDeep(char* p, StrPair* parentEndTag, int* curLineNumPtr); + + XMLDocument* _document; + XMLNode* _parent; + mutable StrPair _value; + int _parseLineNum; + + XMLNode* _firstChild; + XMLNode* _lastChild; + + XMLNode* _prev; + XMLNode* _next; + + void* _userData; + + private: + MemPool* _memPool; + void Unlink(XMLNode* child); + static void DeleteNode(XMLNode* node); + void InsertChildPreamble(XMLNode* insertThis) const; + const XMLElement* ToElementWithName(const char* name) const; + + XMLNode(const XMLNode&); // not supported + XMLNode& operator=(const XMLNode&); // not supported + }; + + + /** XML text. + + Note that a text node can have child element nodes, for example: + @verbatim + This is bold + @endverbatim + + A text node can have 2 ways to output the next. "normal" output + and CDATA. It will default to the mode it was parsed from the XML file and + you generally want to leave it alone, but you can change the output mode with + SetCData() and query it with CData(). + */ + class TINYXML2_LIB XMLText : public XMLNode + { + friend class XMLDocument; + public: + virtual bool Accept(XMLVisitor* visitor) const; + + virtual XMLText* ToText() { + return this; + } + virtual const XMLText* ToText() const { + return this; + } + + /// Declare whether this should be CDATA or standard text. + void SetCData(bool isCData) { + _isCData = isCData; + } + /// Returns true if this is a CDATA text element. + bool CData() const { + return _isCData; + } + + virtual XMLNode* ShallowClone(XMLDocument* document) const; + virtual bool ShallowEqual(const XMLNode* compare) const; + + protected: + explicit XMLText(XMLDocument* doc) : XMLNode(doc), _isCData(false) {} + virtual ~XMLText() {} + + char* ParseDeep(char* p, StrPair* parentEndTag, int* curLineNumPtr); + + private: + bool _isCData; + + XMLText(const XMLText&); // not supported + XMLText& operator=(const XMLText&); // not supported + }; + + + /** An XML Comment. */ + class TINYXML2_LIB XMLComment : public XMLNode + { + friend class XMLDocument; + public: + virtual XMLComment* ToComment() { + return this; + } + virtual const XMLComment* ToComment() const { + return this; + } + + virtual bool Accept(XMLVisitor* visitor) const; + + virtual XMLNode* ShallowClone(XMLDocument* document) const; + virtual bool ShallowEqual(const XMLNode* compare) const; + + protected: + explicit XMLComment(XMLDocument* doc); + virtual ~XMLComment(); + + char* ParseDeep(char* p, StrPair* parentEndTag, int* curLineNumPtr); + + private: + XMLComment(const XMLComment&); // not supported + XMLComment& operator=(const XMLComment&); // not supported + }; + + + /** In correct XML the declaration is the first entry in the file. + @verbatim + + @endverbatim + + TinyXML-2 will happily read or write files without a declaration, + however. + + The text of the declaration isn't interpreted. It is parsed + and written as a string. + */ + class TINYXML2_LIB XMLDeclaration : public XMLNode + { + friend class XMLDocument; + public: + virtual XMLDeclaration* ToDeclaration() { + return this; + } + virtual const XMLDeclaration* ToDeclaration() const { + return this; + } + + virtual bool Accept(XMLVisitor* visitor) const; + + virtual XMLNode* ShallowClone(XMLDocument* document) const; + virtual bool ShallowEqual(const XMLNode* compare) const; + + protected: + explicit XMLDeclaration(XMLDocument* doc); + virtual ~XMLDeclaration(); + + char* ParseDeep(char* p, StrPair* parentEndTag, int* curLineNumPtr); + + private: + XMLDeclaration(const XMLDeclaration&); // not supported + XMLDeclaration& operator=(const XMLDeclaration&); // not supported + }; + + + /** Any tag that TinyXML-2 doesn't recognize is saved as an + unknown. It is a tag of text, but should not be modified. + It will be written back to the XML, unchanged, when the file + is saved. + + DTD tags get thrown into XMLUnknowns. + */ + class TINYXML2_LIB XMLUnknown : public XMLNode + { + friend class XMLDocument; + public: + virtual XMLUnknown* ToUnknown() { + return this; + } + virtual const XMLUnknown* ToUnknown() const { + return this; + } + + virtual bool Accept(XMLVisitor* visitor) const; + + virtual XMLNode* ShallowClone(XMLDocument* document) const; + virtual bool ShallowEqual(const XMLNode* compare) const; + + protected: + explicit XMLUnknown(XMLDocument* doc); + virtual ~XMLUnknown(); + + char* ParseDeep(char* p, StrPair* parentEndTag, int* curLineNumPtr); + + private: + XMLUnknown(const XMLUnknown&); // not supported + XMLUnknown& operator=(const XMLUnknown&); // not supported + }; + + + + /** An attribute is a name-value pair. Elements have an arbitrary + number of attributes, each with a unique name. + + @note The attributes are not XMLNodes. You may only query the + Next() attribute in a list. + */ + class TINYXML2_LIB XMLAttribute + { + friend class XMLElement; + public: + /// The name of the attribute. + const char* Name() const; + + /// The value of the attribute. + const char* Value() const; + + /// Gets the line number the attribute is in, if the document was parsed from a file. + int GetLineNum() const { return _parseLineNum; } + + /// The next attribute in the list. + const XMLAttribute* Next() const { + return _next; + } + + /** IntValue interprets the attribute as an integer, and returns the value. + If the value isn't an integer, 0 will be returned. There is no error checking; + use QueryIntValue() if you need error checking. + */ + int IntValue() const { + int i = 0; + QueryIntValue(&i); + return i; + } + + int64_t Int64Value() const { + int64_t i = 0; + QueryInt64Value(&i); + return i; + } + + uint64_t Unsigned64Value() const { + uint64_t i = 0; + QueryUnsigned64Value(&i); + return i; + } + + /// Query as an unsigned integer. See IntValue() + unsigned UnsignedValue() const { + unsigned i = 0; + QueryUnsignedValue(&i); + return i; + } + /// Query as a boolean. See IntValue() + bool BoolValue() const { + bool b = false; + QueryBoolValue(&b); + return b; + } + /// Query as a double. See IntValue() + double DoubleValue() const { + double d = 0; + QueryDoubleValue(&d); + return d; + } + /// Query as a float. See IntValue() + float FloatValue() const { + float f = 0; + QueryFloatValue(&f); + return f; + } + + /** QueryIntValue interprets the attribute as an integer, and returns the value + in the provided parameter. The function will return XML_SUCCESS on success, + and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful. + */ + XMLError QueryIntValue(int* value) const; + /// See QueryIntValue + XMLError QueryUnsignedValue(unsigned int* value) const; + /// See QueryIntValue + XMLError QueryInt64Value(int64_t* value) const; + /// See QueryIntValue + XMLError QueryUnsigned64Value(uint64_t* value) const; + /// See QueryIntValue + XMLError QueryBoolValue(bool* value) const; + /// See QueryIntValue + XMLError QueryDoubleValue(double* value) const; + /// See QueryIntValue + XMLError QueryFloatValue(float* value) const; + + /// Set the attribute to a string value. + void SetAttribute(const char* value); + /// Set the attribute to value. + void SetAttribute(int value); + /// Set the attribute to value. + void SetAttribute(unsigned value); + /// Set the attribute to value. + void SetAttribute(int64_t value); + /// Set the attribute to value. + void SetAttribute(uint64_t value); + /// Set the attribute to value. + void SetAttribute(bool value); + /// Set the attribute to value. + void SetAttribute(double value); + /// Set the attribute to value. + void SetAttribute(float value); + + private: + enum { BUF_SIZE = 200 }; + + XMLAttribute() : _name(), _value(), _parseLineNum(0), _next(0), _memPool(0) {} + virtual ~XMLAttribute() {} + + XMLAttribute(const XMLAttribute&); // not supported + void operator=(const XMLAttribute&); // not supported + void SetName(const char* name); + + char* ParseDeep(char* p, bool processEntities, int* curLineNumPtr); + + mutable StrPair _name; + mutable StrPair _value; + int _parseLineNum; + XMLAttribute* _next; + MemPool* _memPool; + }; + + + /** The element is a container class. It has a value, the element name, + and can contain other elements, text, comments, and unknowns. + Elements also contain an arbitrary number of attributes. + */ + class TINYXML2_LIB XMLElement : public XMLNode + { + friend class XMLDocument; + public: + /// Get the name of an element (which is the Value() of the node.) + const char* Name() const { + return Value(); + } + /// Set the name of the element. + void SetName(const char* str, bool staticMem = false) { + SetValue(str, staticMem); + } + + virtual XMLElement* ToElement() { + return this; + } + virtual const XMLElement* ToElement() const { + return this; + } + virtual bool Accept(XMLVisitor* visitor) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none + exists. For example: + + @verbatim + const char* value = ele->Attribute( "foo" ); + @endverbatim + + The 'value' parameter is normally null. However, if specified, + the attribute will only be returned if the 'name' and 'value' + match. This allow you to write code: + + @verbatim + if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar(); + @endverbatim + + rather than: + @verbatim + if ( ele->Attribute( "foo" ) ) { + if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar(); + } + @endverbatim + */ + const char* Attribute(const char* name, const char* value = 0) const; + + /** Given an attribute name, IntAttribute() returns the value + of the attribute interpreted as an integer. The default + value will be returned if the attribute isn't present, + or if there is an error. (For a method with error + checking, see QueryIntAttribute()). + */ + int IntAttribute(const char* name, int defaultValue = 0) const; + /// See IntAttribute() + unsigned UnsignedAttribute(const char* name, unsigned defaultValue = 0) const; + /// See IntAttribute() + int64_t Int64Attribute(const char* name, int64_t defaultValue = 0) const; + /// See IntAttribute() + uint64_t Unsigned64Attribute(const char* name, uint64_t defaultValue = 0) const; + /// See IntAttribute() + bool BoolAttribute(const char* name, bool defaultValue = false) const; + /// See IntAttribute() + double DoubleAttribute(const char* name, double defaultValue = 0) const; + /// See IntAttribute() + float FloatAttribute(const char* name, float defaultValue = 0) const; + + /** Given an attribute name, QueryIntAttribute() returns + XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion + can't be performed, or XML_NO_ATTRIBUTE if the attribute + doesn't exist. If successful, the result of the conversion + will be written to 'value'. If not successful, nothing will + be written to 'value'. This allows you to provide default + value: + + @verbatim + int value = 10; + QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 + @endverbatim + */ + XMLError QueryIntAttribute(const char* name, int* value) const { + const XMLAttribute* a = FindAttribute(name); + if (!a) { + return XML_NO_ATTRIBUTE; + } + return a->QueryIntValue(value); + } + + /// See QueryIntAttribute() + XMLError QueryUnsignedAttribute(const char* name, unsigned int* value) const { + const XMLAttribute* a = FindAttribute(name); + if (!a) { + return XML_NO_ATTRIBUTE; + } + return a->QueryUnsignedValue(value); + } + + /// See QueryIntAttribute() + XMLError QueryInt64Attribute(const char* name, int64_t* value) const { + const XMLAttribute* a = FindAttribute(name); + if (!a) { + return XML_NO_ATTRIBUTE; + } + return a->QueryInt64Value(value); + } + + /// See QueryIntAttribute() + XMLError QueryUnsigned64Attribute(const char* name, uint64_t* value) const { + const XMLAttribute* a = FindAttribute(name); + if (!a) { + return XML_NO_ATTRIBUTE; + } + return a->QueryUnsigned64Value(value); + } + + /// See QueryIntAttribute() + XMLError QueryBoolAttribute(const char* name, bool* value) const { + const XMLAttribute* a = FindAttribute(name); + if (!a) { + return XML_NO_ATTRIBUTE; + } + return a->QueryBoolValue(value); + } + /// See QueryIntAttribute() + XMLError QueryDoubleAttribute(const char* name, double* value) const { + const XMLAttribute* a = FindAttribute(name); + if (!a) { + return XML_NO_ATTRIBUTE; + } + return a->QueryDoubleValue(value); + } + /// See QueryIntAttribute() + XMLError QueryFloatAttribute(const char* name, float* value) const { + const XMLAttribute* a = FindAttribute(name); + if (!a) { + return XML_NO_ATTRIBUTE; + } + return a->QueryFloatValue(value); + } + + /// See QueryIntAttribute() + XMLError QueryStringAttribute(const char* name, const char** value) const { + const XMLAttribute* a = FindAttribute(name); + if (!a) { + return XML_NO_ATTRIBUTE; + } + *value = a->Value(); + return XML_SUCCESS; + } + + + + /** Given an attribute name, QueryAttribute() returns + XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion + can't be performed, or XML_NO_ATTRIBUTE if the attribute + doesn't exist. It is overloaded for the primitive types, + and is a generally more convenient replacement of + QueryIntAttribute() and related functions. + + If successful, the result of the conversion + will be written to 'value'. If not successful, nothing will + be written to 'value'. This allows you to provide default + value: + + @verbatim + int value = 10; + QueryAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 + @endverbatim + */ + XMLError QueryAttribute(const char* name, int* value) const { + return QueryIntAttribute(name, value); + } + + XMLError QueryAttribute(const char* name, unsigned int* value) const { + return QueryUnsignedAttribute(name, value); + } + + XMLError QueryAttribute(const char* name, int64_t* value) const { + return QueryInt64Attribute(name, value); + } + + XMLError QueryAttribute(const char* name, uint64_t* value) const { + return QueryUnsigned64Attribute(name, value); + } + + XMLError QueryAttribute(const char* name, bool* value) const { + return QueryBoolAttribute(name, value); + } + + XMLError QueryAttribute(const char* name, double* value) const { + return QueryDoubleAttribute(name, value); + } + + XMLError QueryAttribute(const char* name, float* value) const { + return QueryFloatAttribute(name, value); + } + + /// Sets the named attribute to value. + void SetAttribute(const char* name, const char* value) { + XMLAttribute* a = FindOrCreateAttribute(name); + a->SetAttribute(value); + } + /// Sets the named attribute to value. + void SetAttribute(const char* name, int value) { + XMLAttribute* a = FindOrCreateAttribute(name); + a->SetAttribute(value); + } + /// Sets the named attribute to value. + void SetAttribute(const char* name, unsigned value) { + XMLAttribute* a = FindOrCreateAttribute(name); + a->SetAttribute(value); + } + + /// Sets the named attribute to value. + void SetAttribute(const char* name, int64_t value) { + XMLAttribute* a = FindOrCreateAttribute(name); + a->SetAttribute(value); + } + + /// Sets the named attribute to value. + void SetAttribute(const char* name, uint64_t value) { + XMLAttribute* a = FindOrCreateAttribute(name); + a->SetAttribute(value); + } + + /// Sets the named attribute to value. + void SetAttribute(const char* name, bool value) { + XMLAttribute* a = FindOrCreateAttribute(name); + a->SetAttribute(value); + } + /// Sets the named attribute to value. + void SetAttribute(const char* name, double value) { + XMLAttribute* a = FindOrCreateAttribute(name); + a->SetAttribute(value); + } + /// Sets the named attribute to value. + void SetAttribute(const char* name, float value) { + XMLAttribute* a = FindOrCreateAttribute(name); + a->SetAttribute(value); + } + + /** + Delete an attribute. + */ + void DeleteAttribute(const char* name); + + /// Return the first attribute in the list. + const XMLAttribute* FirstAttribute() const { + return _rootAttribute; + } + /// Query a specific attribute in the list. + const XMLAttribute* FindAttribute(const char* name) const; + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, GetText() is limited compared to getting the XMLText child + and accessing it directly. + + If the first child of 'this' is a XMLText, the GetText() + returns the character string of the Text node, else null is returned. + + This is a convenient method for getting the text of simple contained text: + @verbatim + This is text + const char* str = fooElement->GetText(); + @endverbatim + + 'str' will be a pointer to "This is text". + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + This is text + @endverbatim + + then the value of str would be null. The first child node isn't a text node, it is + another element. From this XML: + @verbatim + This is text + @endverbatim + GetText() will return "This is ". + */ + const char* GetText() const; + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, SetText() is limited compared to creating an XMLText child + and mutating it directly. + + If the first child of 'this' is a XMLText, SetText() sets its value to + the given string, otherwise it will create a first child that is an XMLText. + + This is a convenient method for setting the text of simple contained text: + @verbatim + This is text + fooElement->SetText( "Hullaballoo!" ); + Hullaballoo! + @endverbatim + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + This is text + @endverbatim + + then it will not change "This is text", but rather prefix it with a text element: + @verbatim + Hullaballoo!This is text + @endverbatim + + For this XML: + @verbatim + + @endverbatim + SetText() will generate + @verbatim + Hullaballoo! + @endverbatim + */ + void SetText(const char* inText); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText(int value); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText(unsigned value); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText(int64_t value); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText(uint64_t value); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText(bool value); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText(double value); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText(float value); + + /** + Convenience method to query the value of a child text node. This is probably best + shown by example. Given you have a document is this form: + @verbatim + + 1 + 1.4 + + @endverbatim + + The QueryIntText() and similar functions provide a safe and easier way to get to the + "value" of x and y. + + @verbatim + int x = 0; + float y = 0; // types of x and y are contrived for example + const XMLElement* xElement = pointElement->FirstChildElement( "x" ); + const XMLElement* yElement = pointElement->FirstChildElement( "y" ); + xElement->QueryIntText( &x ); + yElement->QueryFloatText( &y ); + @endverbatim + + @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted + to the requested type, and XML_NO_TEXT_NODE if there is no child text to query. + + */ + XMLError QueryIntText(int* ival) const; + /// See QueryIntText() + XMLError QueryUnsignedText(unsigned* uval) const; + /// See QueryIntText() + XMLError QueryInt64Text(int64_t* uval) const; + /// See QueryIntText() + XMLError QueryUnsigned64Text(uint64_t* uval) const; + /// See QueryIntText() + XMLError QueryBoolText(bool* bval) const; + /// See QueryIntText() + XMLError QueryDoubleText(double* dval) const; + /// See QueryIntText() + XMLError QueryFloatText(float* fval) const; + + int IntText(int defaultValue = 0) const; + + /// See QueryIntText() + unsigned UnsignedText(unsigned defaultValue = 0) const; + /// See QueryIntText() + int64_t Int64Text(int64_t defaultValue = 0) const; + /// See QueryIntText() + uint64_t Unsigned64Text(uint64_t defaultValue = 0) const; + /// See QueryIntText() + bool BoolText(bool defaultValue = false) const; + /// See QueryIntText() + double DoubleText(double defaultValue = 0) const; + /// See QueryIntText() + float FloatText(float defaultValue = 0) const; + + /** + Convenience method to create a new XMLElement and add it as last (right) + child of this node. Returns the created and inserted element. + */ + XMLElement* InsertNewChildElement(const char* name); + /// See InsertNewChildElement() + XMLComment* InsertNewComment(const char* comment); + /// See InsertNewChildElement() + XMLText* InsertNewText(const char* text); + /// See InsertNewChildElement() + XMLDeclaration* InsertNewDeclaration(const char* text); + /// See InsertNewChildElement() + XMLUnknown* InsertNewUnknown(const char* text); + + + // internal: + enum ElementClosingType { + OPEN, // + CLOSED, // + CLOSING // + }; + ElementClosingType ClosingType() const { + return _closingType; + } + virtual XMLNode* ShallowClone(XMLDocument* document) const; + virtual bool ShallowEqual(const XMLNode* compare) const; + + protected: + char* ParseDeep(char* p, StrPair* parentEndTag, int* curLineNumPtr); + + private: + XMLElement(XMLDocument* doc); + virtual ~XMLElement(); + XMLElement(const XMLElement&); // not supported + void operator=(const XMLElement&); // not supported + + XMLAttribute* FindOrCreateAttribute(const char* name); + char* ParseAttributes(char* p, int* curLineNumPtr); + static void DeleteAttribute(XMLAttribute* attribute); + XMLAttribute* CreateAttribute(); + + enum { BUF_SIZE = 200 }; + ElementClosingType _closingType; + // The attribute list is ordered; there is no 'lastAttribute' + // because the list needs to be scanned for dupes before adding + // a new attribute. + XMLAttribute* _rootAttribute; + }; + + + enum Whitespace { + PRESERVE_WHITESPACE, + COLLAPSE_WHITESPACE + }; + + + /** A Document binds together all the functionality. + It can be saved, loaded, and printed to the screen. + All Nodes are connected and allocated to a Document. + If the Document is deleted, all its Nodes are also deleted. + */ + class TINYXML2_LIB XMLDocument : public XMLNode + { + friend class XMLElement; + // Gives access to SetError and Push/PopDepth, but over-access for everything else. + // Wishing C++ had "internal" scope. + friend class XMLNode; + friend class XMLText; + friend class XMLComment; + friend class XMLDeclaration; + friend class XMLUnknown; + public: + /// constructor + XMLDocument(bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE); + ~XMLDocument(); + + virtual XMLDocument* ToDocument() { + TIXMLASSERT(this == _document); + return this; + } + virtual const XMLDocument* ToDocument() const { + TIXMLASSERT(this == _document); + return this; + } + + /** + Parse an XML file from a character string. + Returns XML_SUCCESS (0) on success, or + an errorID. + + You may optionally pass in the 'nBytes', which is + the number of bytes which will be parsed. If not + specified, TinyXML-2 will assume 'xml' points to a + null terminated string. + */ + XMLError Parse(const char* xml, size_t nBytes = static_cast(-1)); + + /** + Load an XML file from disk. + Returns XML_SUCCESS (0) on success, or + an errorID. + */ + XMLError LoadFile(const char* filename); + + /** + Load an XML file from disk. You are responsible + for providing and closing the FILE*. + + NOTE: The file should be opened as binary ("rb") + not text in order for TinyXML-2 to correctly + do newline normalization. + + Returns XML_SUCCESS (0) on success, or + an errorID. + */ + XMLError LoadFile(FILE*); + + /** + Save the XML file to disk. + Returns XML_SUCCESS (0) on success, or + an errorID. + */ + XMLError SaveFile(const char* filename, bool compact = false); + + /** + Save the XML file to disk. You are responsible + for providing and closing the FILE*. + + Returns XML_SUCCESS (0) on success, or + an errorID. + */ + XMLError SaveFile(FILE* fp, bool compact = false); + + bool ProcessEntities() const { + return _processEntities; + } + Whitespace WhitespaceMode() const { + return _whitespaceMode; + } + + /** + Returns true if this document has a leading Byte Order Mark of UTF8. + */ + bool HasBOM() const { + return _writeBOM; + } + /** Sets whether to write the BOM when writing the file. + */ + void SetBOM(bool useBOM) { + _writeBOM = useBOM; + } + + /** Return the root element of DOM. Equivalent to FirstChildElement(). + To get the first node, use FirstChild(). + */ + XMLElement* RootElement() { + return FirstChildElement(); + } + const XMLElement* RootElement() const { + return FirstChildElement(); + } + + /** Print the Document. If the Printer is not provided, it will + print to stdout. If you provide Printer, this can print to a file: + @verbatim + XMLPrinter printer( fp ); + doc.Print( &printer ); + @endverbatim + + Or you can use a printer to print to memory: + @verbatim + XMLPrinter printer; + doc.Print( &printer ); + // printer.CStr() has a const char* to the XML + @endverbatim + */ + void Print(XMLPrinter* streamer = 0) const; + virtual bool Accept(XMLVisitor* visitor) const; + + /** + Create a new Element associated with + this Document. The memory for the Element + is managed by the Document. + */ + XMLElement* NewElement(const char* name); + /** + Create a new Comment associated with + this Document. The memory for the Comment + is managed by the Document. + */ + XMLComment* NewComment(const char* comment); + /** + Create a new Text associated with + this Document. The memory for the Text + is managed by the Document. + */ + XMLText* NewText(const char* text); + /** + Create a new Declaration associated with + this Document. The memory for the object + is managed by the Document. + + If the 'text' param is null, the standard + declaration is used.: + @verbatim + + @endverbatim + */ + XMLDeclaration* NewDeclaration(const char* text = 0); + /** + Create a new Unknown associated with + this Document. The memory for the object + is managed by the Document. + */ + XMLUnknown* NewUnknown(const char* text); + + /** + Delete a node associated with this document. + It will be unlinked from the DOM. + */ + void DeleteNode(XMLNode* node); + + void ClearError() { + SetError(XML_SUCCESS, 0, 0); + } + + /// Return true if there was an error parsing the document. + bool Error() const { + return _errorID != XML_SUCCESS; + } + /// Return the errorID. + XMLError ErrorID() const { + return _errorID; + } + const char* ErrorName() const; + static const char* ErrorIDToName(XMLError errorID); + + /** Returns a "long form" error description. A hopefully helpful + diagnostic with location, line number, and/or additional info. + */ + const char* ErrorStr() const; + + /// A (trivial) utility function that prints the ErrorStr() to stdout. + void PrintError() const; + + /// Return the line where the error occurred, or zero if unknown. + int ErrorLineNum() const + { + return _errorLineNum; + } + + /// Clear the document, resetting it to the initial state. + void Clear(); + + /** + Copies this document to a target document. + The target will be completely cleared before the copy. + If you want to copy a sub-tree, see XMLNode::DeepClone(). + + NOTE: that the 'target' must be non-null. + */ + void DeepCopy(XMLDocument* target) const; + + // internal + char* Identify(char* p, XMLNode** node); + + // internal + void MarkInUse(const XMLNode* const); + + virtual XMLNode* ShallowClone(XMLDocument* /*document*/) const { + return 0; + } + virtual bool ShallowEqual(const XMLNode* /*compare*/) const { + return false; + } + + private: + XMLDocument(const XMLDocument&); // not supported + void operator=(const XMLDocument&); // not supported + + bool _writeBOM; + bool _processEntities; + XMLError _errorID; + Whitespace _whitespaceMode; + mutable StrPair _errorStr; + int _errorLineNum; + char* _charBuffer; + int _parseCurLineNum; + int _parsingDepth; + // Memory tracking does add some overhead. + // However, the code assumes that you don't + // have a bunch of unlinked nodes around. + // Therefore it takes less memory to track + // in the document vs. a linked list in the XMLNode, + // and the performance is the same. + DynArray _unlinked; + + MemPoolT< sizeof(XMLElement) > _elementPool; + MemPoolT< sizeof(XMLAttribute) > _attributePool; + MemPoolT< sizeof(XMLText) > _textPool; + MemPoolT< sizeof(XMLComment) > _commentPool; + + static const char* _errorNames[XML_ERROR_COUNT]; + + void Parse(); + + void SetError(XMLError error, int lineNum, const char* format, ...); + + // Something of an obvious security hole, once it was discovered. + // Either an ill-formed XML or an excessively deep one can overflow + // the stack. Track stack depth, and error out if needed. + class DepthTracker { + public: + explicit DepthTracker(XMLDocument* document) { + this->_document = document; + document->PushDepth(); + } + ~DepthTracker() { + _document->PopDepth(); + } + private: + XMLDocument* _document; + }; + void PushDepth(); + void PopDepth(); + + template + NodeType* CreateUnlinkedNode(MemPoolT& pool); + }; + + template + inline NodeType* XMLDocument::CreateUnlinkedNode(MemPoolT& pool) + { + TIXMLASSERT(sizeof(NodeType) == PoolElementSize); + TIXMLASSERT(sizeof(NodeType) == pool.ItemSize()); + NodeType* returnNode = new (pool.Alloc()) NodeType(this); + TIXMLASSERT(returnNode); + returnNode->_memPool = &pool; + + _unlinked.Push(returnNode); + return returnNode; + } + + /** + A XMLHandle is a class that wraps a node pointer with null checks; this is + an incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2 + DOM structure. It is a separate utility class. + + Take an example: + @verbatim + + + + + + + @endverbatim + + Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very + easy to write a *lot* of code that looks like: + + @verbatim + XMLElement* root = document.FirstChildElement( "Document" ); + if ( root ) + { + XMLElement* element = root->FirstChildElement( "Element" ); + if ( element ) + { + XMLElement* child = element->FirstChildElement( "Child" ); + if ( child ) + { + XMLElement* child2 = child->NextSiblingElement( "Child" ); + if ( child2 ) + { + // Finally do something useful. + @endverbatim + + And that doesn't even cover "else" cases. XMLHandle addresses the verbosity + of such code. A XMLHandle checks for null pointers so it is perfectly safe + and correct to use: + + @verbatim + XMLHandle docHandle( &document ); + XMLElement* child2 = docHandle.FirstChildElement( "Document" ).FirstChildElement( "Element" ).FirstChildElement().NextSiblingElement(); + if ( child2 ) + { + // do something useful + @endverbatim + + Which is MUCH more concise and useful. + + It is also safe to copy handles - internally they are nothing more than node pointers. + @verbatim + XMLHandle handleCopy = handle; + @endverbatim + + See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects. + */ + class TINYXML2_LIB XMLHandle + { + public: + /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. + explicit XMLHandle(XMLNode* node) : _node(node) { + } + /// Create a handle from a node. + explicit XMLHandle(XMLNode& node) : _node(&node) { + } + /// Copy constructor + XMLHandle(const XMLHandle& ref) : _node(ref._node) { + } + /// Assignment + XMLHandle& operator=(const XMLHandle& ref) { + _node = ref._node; + return *this; + } + + /// Get the first child of this handle. + XMLHandle FirstChild() { + return XMLHandle(_node ? _node->FirstChild() : 0); + } + /// Get the first child element of this handle. + XMLHandle FirstChildElement(const char* name = 0) { + return XMLHandle(_node ? _node->FirstChildElement(name) : 0); + } + /// Get the last child of this handle. + XMLHandle LastChild() { + return XMLHandle(_node ? _node->LastChild() : 0); + } + /// Get the last child element of this handle. + XMLHandle LastChildElement(const char* name = 0) { + return XMLHandle(_node ? _node->LastChildElement(name) : 0); + } + /// Get the previous sibling of this handle. + XMLHandle PreviousSibling() { + return XMLHandle(_node ? _node->PreviousSibling() : 0); + } + /// Get the previous sibling element of this handle. + XMLHandle PreviousSiblingElement(const char* name = 0) { + return XMLHandle(_node ? _node->PreviousSiblingElement(name) : 0); + } + /// Get the next sibling of this handle. + XMLHandle NextSibling() { + return XMLHandle(_node ? _node->NextSibling() : 0); + } + /// Get the next sibling element of this handle. + XMLHandle NextSiblingElement(const char* name = 0) { + return XMLHandle(_node ? _node->NextSiblingElement(name) : 0); + } + + /// Safe cast to XMLNode. This can return null. + XMLNode* ToNode() { + return _node; + } + /// Safe cast to XMLElement. This can return null. + XMLElement* ToElement() { + return (_node ? _node->ToElement() : 0); + } + /// Safe cast to XMLText. This can return null. + XMLText* ToText() { + return (_node ? _node->ToText() : 0); + } + /// Safe cast to XMLUnknown. This can return null. + XMLUnknown* ToUnknown() { + return (_node ? _node->ToUnknown() : 0); + } + /// Safe cast to XMLDeclaration. This can return null. + XMLDeclaration* ToDeclaration() { + return (_node ? _node->ToDeclaration() : 0); + } + + private: + XMLNode* _node; + }; + + + /** + A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the + same in all regards, except for the 'const' qualifiers. See XMLHandle for API. + */ + class TINYXML2_LIB XMLConstHandle + { + public: + explicit XMLConstHandle(const XMLNode* node) : _node(node) { + } + explicit XMLConstHandle(const XMLNode& node) : _node(&node) { + } + XMLConstHandle(const XMLConstHandle& ref) : _node(ref._node) { + } + + XMLConstHandle& operator=(const XMLConstHandle& ref) { + _node = ref._node; + return *this; + } + + const XMLConstHandle FirstChild() const { + return XMLConstHandle(_node ? _node->FirstChild() : 0); + } + const XMLConstHandle FirstChildElement(const char* name = 0) const { + return XMLConstHandle(_node ? _node->FirstChildElement(name) : 0); + } + const XMLConstHandle LastChild() const { + return XMLConstHandle(_node ? _node->LastChild() : 0); + } + const XMLConstHandle LastChildElement(const char* name = 0) const { + return XMLConstHandle(_node ? _node->LastChildElement(name) : 0); + } + const XMLConstHandle PreviousSibling() const { + return XMLConstHandle(_node ? _node->PreviousSibling() : 0); + } + const XMLConstHandle PreviousSiblingElement(const char* name = 0) const { + return XMLConstHandle(_node ? _node->PreviousSiblingElement(name) : 0); + } + const XMLConstHandle NextSibling() const { + return XMLConstHandle(_node ? _node->NextSibling() : 0); + } + const XMLConstHandle NextSiblingElement(const char* name = 0) const { + return XMLConstHandle(_node ? _node->NextSiblingElement(name) : 0); + } + + + const XMLNode* ToNode() const { + return _node; + } + const XMLElement* ToElement() const { + return (_node ? _node->ToElement() : 0); + } + const XMLText* ToText() const { + return (_node ? _node->ToText() : 0); + } + const XMLUnknown* ToUnknown() const { + return (_node ? _node->ToUnknown() : 0); + } + const XMLDeclaration* ToDeclaration() const { + return (_node ? _node->ToDeclaration() : 0); + } + + private: + const XMLNode* _node; + }; + + + /** + Printing functionality. The XMLPrinter gives you more + options than the XMLDocument::Print() method. + + It can: + -# Print to memory. + -# Print to a file you provide. + -# Print XML without a XMLDocument. + + Print to Memory + + @verbatim + XMLPrinter printer; + doc.Print( &printer ); + SomeFunction( printer.CStr() ); + @endverbatim + + Print to a File + + You provide the file pointer. + @verbatim + XMLPrinter printer( fp ); + doc.Print( &printer ); + @endverbatim + + Print without a XMLDocument + + When loading, an XML parser is very useful. However, sometimes + when saving, it just gets in the way. The code is often set up + for streaming, and constructing the DOM is just overhead. + + The Printer supports the streaming case. The following code + prints out a trivially simple XML file without ever creating + an XML document. + + @verbatim + XMLPrinter printer( fp ); + printer.OpenElement( "foo" ); + printer.PushAttribute( "foo", "bar" ); + printer.CloseElement(); + @endverbatim + */ + class TINYXML2_LIB XMLPrinter : public XMLVisitor + { + public: + /** Construct the printer. If the FILE* is specified, + this will print to the FILE. Else it will print + to memory, and the result is available in CStr(). + If 'compact' is set to true, then output is created + with only required whitespace and newlines. + */ + XMLPrinter(FILE* file = 0, bool compact = false, int depth = 0); + virtual ~XMLPrinter() {} + + /** If streaming, write the BOM and declaration. */ + void PushHeader(bool writeBOM, bool writeDeclaration); + /** If streaming, start writing an element. + The element must be closed with CloseElement() + */ + void OpenElement(const char* name, bool compactMode = false); + /// If streaming, add an attribute to an open element. + void PushAttribute(const char* name, const char* value); + void PushAttribute(const char* name, int value); + void PushAttribute(const char* name, unsigned value); + void PushAttribute(const char* name, int64_t value); + void PushAttribute(const char* name, uint64_t value); + void PushAttribute(const char* name, bool value); + void PushAttribute(const char* name, double value); + /// If streaming, close the Element. + virtual void CloseElement(bool compactMode = false); + + /// Add a text node. + void PushText(const char* text, bool cdata = false); + /// Add a text node from an integer. + void PushText(int value); + /// Add a text node from an unsigned. + void PushText(unsigned value); + /// Add a text node from a signed 64bit integer. + void PushText(int64_t value); + /// Add a text node from an unsigned 64bit integer. + void PushText(uint64_t value); + /// Add a text node from a bool. + void PushText(bool value); + /// Add a text node from a float. + void PushText(float value); + /// Add a text node from a double. + void PushText(double value); + + /// Add a comment + void PushComment(const char* comment); + + void PushDeclaration(const char* value); + void PushUnknown(const char* value); + + virtual bool VisitEnter(const XMLDocument& /*doc*/); + virtual bool VisitExit(const XMLDocument& /*doc*/) { + return true; + } + + virtual bool VisitEnter(const XMLElement& element, const XMLAttribute* attribute); + virtual bool VisitExit(const XMLElement& element); + + virtual bool Visit(const XMLText& text); + virtual bool Visit(const XMLComment& comment); + virtual bool Visit(const XMLDeclaration& declaration); + virtual bool Visit(const XMLUnknown& unknown); + + /** + If in print to memory mode, return a pointer to + the XML file in memory. + */ + const char* CStr() const { + return _buffer.Mem(); + } + /** + If in print to memory mode, return the size + of the XML file in memory. (Note the size returned + includes the terminating null.) + */ + int CStrSize() const { + return _buffer.Size(); + } + /** + If in print to memory mode, reset the buffer to the + beginning. + */ + void ClearBuffer(bool resetToFirstElement = true) { + _buffer.Clear(); + _buffer.Push(0); + _firstElement = resetToFirstElement; + } + + protected: + virtual bool CompactMode(const XMLElement&) { return _compactMode; } + + /** Prints out the space before an element. You may override to change + the space and tabs used. A PrintSpace() override should call Print(). + */ + virtual void PrintSpace(int depth); + void Print(const char* format, ...); + void Write(const char* data, size_t size); + inline void Write(const char* data) { Write(data, strlen(data)); } + void Putc(char ch); + + void SealElementIfJustOpened(); + bool _elementJustOpened; + DynArray< const char*, 10 > _stack; + + private: + void PrintString(const char*, bool restrictedEntitySet); // prints out, after detecting entities. + + bool _firstElement; + FILE* _fp; + int _depth; + int _textDepth; + bool _processEntities; + bool _compactMode; + + enum { + ENTITY_RANGE = 64, + BUF_SIZE = 200 + }; + bool _entityFlag[ENTITY_RANGE]; + bool _restrictedEntityFlag[ENTITY_RANGE]; + + DynArray< char, 20 > _buffer; + + // Prohibit cloning, intentionally not implemented + XMLPrinter(const XMLPrinter&); + XMLPrinter& operator=(const XMLPrinter&); + }; + + +} // tinyxml2 + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif + +#endif // TINYXML2_INCLUDED diff --git a/General/General/w2_Clear_Form_PropValue.cpp b/General/General/w2_Clear_Form_PropValue.cpp index 3e02080..23c9e7c 100644 --- a/General/General/w2_Clear_Form_PropValue.cpp +++ b/General/General/w2_Clear_Form_PropValue.cpp @@ -335,8 +335,6 @@ extern "C" { MEM_free(newREV_type); newREV_type=NULL; } - - printf("*******************************************************\n"); printf("* W2_Clear_Form_PropValue is end *\n"); printf("*******************************************************\n");