commit
dfea385dd5
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <iostream>
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <curl\curl.h>
|
||||||
|
using namespace std;
|
||||||
|
void callHttpserver(string signinfoJsonString, char* HTTP_HOST);
|
||||||
|
void callHttpserverDwgtopdf(string signinfoJsonString, char* HTTP_HOST);
|
||||||
|
void callHttpserverMail(string signinfoJsonString, char* HTTP_HOST);
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
/*==============================================================================
|
||||||
|
Copyright (c) 2008-2018 Connor Corporation
|
||||||
|
Unpublished - All Rights Reserved
|
||||||
|
==============================================================================*/
|
||||||
|
#include "kutil.h"
|
||||||
|
|
||||||
|
int LD_ElevateTask(EPM_action_message_t msg)
|
||||||
|
{
|
||||||
|
printf("=========================提升流程节点 Start===================\n");
|
||||||
|
int ifail = ITK_ok, att_cnt = 0, i = 0, arg_cnt = 0;
|
||||||
|
tag_t task_tag = NULL_TAG, rootTask_tag = NULL_TAG;
|
||||||
|
task_tag = msg.task;
|
||||||
|
if (task_tag == NULLTAG)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ITKCALL(EPM_ask_root_task(task_tag, &rootTask_tag));
|
||||||
|
char* taskname = NULL, * type = NULL;
|
||||||
|
ITKCALL(EPM_ask_name2(task_tag, &taskname));
|
||||||
|
ITKCALL(AOM_ask_value_string(task_tag, "object_type", &type));
|
||||||
|
printf("name=%s\n", taskname);
|
||||||
|
printf("type=%s\n", type);
|
||||||
|
if (strcmp(type, "EPMReviewTask") == 0 || strcmp(type, "EPMAcknowledgeTask") == 0)
|
||||||
|
{
|
||||||
|
int num = 0;
|
||||||
|
tag_t* sub_tags = NULL;
|
||||||
|
ITKCALL(EPM_ask_sub_tasks(task_tag, &num, &sub_tags));
|
||||||
|
for (int j = 0; j < num; j++)
|
||||||
|
{
|
||||||
|
char* taskname2 = NULL, * type2 = NULL;
|
||||||
|
ITKCALL(EPM_ask_name2(sub_tags[j], &taskname2));
|
||||||
|
ITKCALL(AOM_ask_value_string(sub_tags[j], "object_type", &type2));
|
||||||
|
if (strcmp(type2, "EPMPerformSignoffTask") == 0)
|
||||||
|
{
|
||||||
|
printf("name2=%s,type2=%s\n", taskname2, type2);
|
||||||
|
int valid_num = 0;
|
||||||
|
tag_t* valid_tags = NULL;
|
||||||
|
ITKCALL(AOM_ask_value_tags(sub_tags[j], "valid_signoffs", &valid_num, &valid_tags));
|
||||||
|
printf("valid_num=%d\n", valid_num);
|
||||||
|
if (valid_num == 0)
|
||||||
|
{
|
||||||
|
printf("未选人执行提升\n");
|
||||||
|
POM_AM__set_application_bypass(true);
|
||||||
|
ITKCALL(EPM_promote_task(task_tag, ""));
|
||||||
|
POM_AM__set_application_bypass(false);
|
||||||
|
}
|
||||||
|
DOFREE(valid_tags);
|
||||||
|
|
||||||
|
}
|
||||||
|
DOFREE(taskname2);
|
||||||
|
DOFREE(type2);
|
||||||
|
|
||||||
|
}
|
||||||
|
DOFREE(sub_tags);
|
||||||
|
|
||||||
|
}
|
||||||
|
DOFREE(taskname);
|
||||||
|
DOFREE(type);
|
||||||
|
printf("=========================提升流程节点 End===================\n");
|
||||||
|
return ITK_ok;
|
||||||
|
}
|
||||||
@ -0,0 +1,92 @@
|
|||||||
|
#include"kutil.h"
|
||||||
|
#define ITK_err 919012
|
||||||
|
|
||||||
|
int Connor_allow_Workflow(EPM_action_message_t msg) {
|
||||||
|
int ifail = ITK_ok, att_cnt = 0, arg_cnt = 0;
|
||||||
|
char* arg = NULL, * argflag = NULL, * argvalue = NULL;
|
||||||
|
tag_t* attachments = NULLTAG, task_tag = NULLTAG, rootTask_tag;
|
||||||
|
string type, grant_value;
|
||||||
|
vector<string> types;
|
||||||
|
arg_cnt = TC_number_of_arguments(msg.arguments);
|
||||||
|
if (arg_cnt > 0) {
|
||||||
|
for (int i = 0; i < arg_cnt; i++) {
|
||||||
|
arg = TC_next_argument(msg.arguments);
|
||||||
|
ITKCALL(ifail = ITK_ask_argument_named_value(arg, &argflag, &argvalue));
|
||||||
|
if (strcmp(argflag, "type") == 0) {
|
||||||
|
type.assign(argvalue);
|
||||||
|
printf("%s\n", argvalue);
|
||||||
|
}
|
||||||
|
else if (strcmp(argflag, "grant") == 0) {
|
||||||
|
grant_value.assign(argvalue);
|
||||||
|
printf("%s\n", argvalue);
|
||||||
|
}
|
||||||
|
MEM_free(argflag);
|
||||||
|
MEM_free(argvalue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
EMH_store_error_s1(EMH_severity_error, ITK_err, "未配置流程参数");
|
||||||
|
ifail = 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
if (grant_value.empty()) {
|
||||||
|
EMH_store_error_s1(EMH_severity_error, ITK_err, "未配置流程参数:-grant");
|
||||||
|
ifail = 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
Split(type, ";", types);
|
||||||
|
if (types.size() == 0) {
|
||||||
|
EMH_store_error_s1(EMH_severity_error, ITK_err, "未配置流程参数:-type");
|
||||||
|
ifail = 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
task_tag = msg.task;
|
||||||
|
if (task_tag == NULLTAG) {
|
||||||
|
ifail = 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
ITKCALL(ifail = EPM_ask_root_task(task_tag, &rootTask_tag));
|
||||||
|
//获取目标下所有对象
|
||||||
|
ITKCALL(ifail = EPM_ask_attachments(rootTask_tag, EPM_target_attachment, &att_cnt, &attachments));
|
||||||
|
if (att_cnt == 0) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
printf("types的长度为%d\n", types.size());
|
||||||
|
for (int i = 0; i < att_cnt; i++)
|
||||||
|
{
|
||||||
|
tag_t target_tag = attachments[i];
|
||||||
|
char* object_type = NULL;
|
||||||
|
AOM_ask_value_string(target_tag,"object_type",&object_type);
|
||||||
|
printf("当前对象的类型为:%s\n",object_type);
|
||||||
|
int sum = 0;
|
||||||
|
for each (string type in types)
|
||||||
|
{
|
||||||
|
if (isTypeOf(target_tag, type.c_str()))
|
||||||
|
{
|
||||||
|
sum++;
|
||||||
|
//EMH_store_error_s1(EMH_severity_error, ITK_err, "对象类型在流程参数-type中不存在");
|
||||||
|
//ifail = 1;
|
||||||
|
//goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("sum的长度为%d\n", sum);
|
||||||
|
if (sum == 0) {
|
||||||
|
EMH_store_error_s1(EMH_severity_error, ITK_err, "对象类型在流程参数-type中不存在");
|
||||||
|
ifail = 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
logical verdict = false;
|
||||||
|
ITKCALL(ifail = AM_check_privilege(target_tag, grant_value.c_str(), &verdict));
|
||||||
|
if (!verdict) {
|
||||||
|
EMH_store_error_s1(EMH_severity_error, ITK_err, "对象权限不符合!");
|
||||||
|
ifail = 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
DOFREE(attachments);
|
||||||
|
return ifail;
|
||||||
|
}
|
||||||
@ -0,0 +1,265 @@
|
|||||||
|
#include"kutil.h"
|
||||||
|
#include "ado.h"
|
||||||
|
#define debug true
|
||||||
|
#define ITK_err 919012
|
||||||
|
|
||||||
|
//导出数据集文件
|
||||||
|
int export_dataset_file_to_dir(tag_t dataset, const char *ref_name, const char* temp_path, char *ext, char **filename, char **original_name)
|
||||||
|
{
|
||||||
|
int ifail = ITK_ok;
|
||||||
|
tag_t ref_object = NULLTAG,
|
||||||
|
datasettype = NULLTAG,
|
||||||
|
new_ds = NULLTAG,
|
||||||
|
tool = NULLTAG,
|
||||||
|
folder_tag = NULLTAG,
|
||||||
|
spec_dataset_rev = NULLTAG;
|
||||||
|
AE_reference_type_t reference_type;
|
||||||
|
tag_t new_file_tag = NULLTAG;
|
||||||
|
IMF_file_t file_descriptor;
|
||||||
|
char *target_ds_name = NULL;
|
||||||
|
char *new_file_name;
|
||||||
|
WSOM_ask_name2(dataset, &target_ds_name);
|
||||||
|
WriteLog(debug, "开始从数据集<%s>下载文件", target_ds_name);
|
||||||
|
DOFREE(target_ds_name);
|
||||||
|
*filename = (char *)MEM_alloc(sizeof(char) * 512);
|
||||||
|
*original_name = (char *)MEM_alloc(sizeof(char) * 512);
|
||||||
|
strcpy(*filename, "");
|
||||||
|
AE_ask_dataset_latest_rev(dataset, &spec_dataset_rev);
|
||||||
|
AE_ask_dataset_named_ref2(dataset, ref_name, &reference_type, &ref_object);
|
||||||
|
if (ref_object == NULLTAG)
|
||||||
|
{
|
||||||
|
WriteLog(debug, "文件引用为空");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (reference_type == AE_PART_OF)
|
||||||
|
{
|
||||||
|
char *pathname2 = NULL;
|
||||||
|
IMF_ask_file_pathname2(ref_object, SS_WNT_MACHINE, &pathname2);
|
||||||
|
DOFREE(pathname2);
|
||||||
|
char *origin_file_name2 = NULL;
|
||||||
|
IMF_ask_original_file_name2(ref_object, &origin_file_name2);
|
||||||
|
strcpy(*original_name, origin_file_name2);
|
||||||
|
DOFREE(origin_file_name2);
|
||||||
|
char new_ds_name[WSO_name_size_c + 1] = "";
|
||||||
|
char *new_file_name = USER_new_file_name(new_ds_name, ref_name, ext, 0);
|
||||||
|
char temp_file[SS_MAXPATHLEN] = "";
|
||||||
|
strcpy(temp_file, temp_path);
|
||||||
|
strcat(temp_file, "\\");
|
||||||
|
strcat(temp_file, new_file_name);
|
||||||
|
WriteLog(debug, "临时文件路径:%s", temp_file);
|
||||||
|
if ((_access(temp_file, 0)) != -1) {
|
||||||
|
if (!remove(temp_file)) {
|
||||||
|
remove(temp_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ITKCALL(ifail = IMF_export_file(ref_object, temp_file));
|
||||||
|
strcpy(*filename, temp_file);
|
||||||
|
return ifail;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int uploadFile(void* returnValue) {
|
||||||
|
int ifail = ITK_ok;
|
||||||
|
char *datasetUid,*refName,*ext, *dataset_file_path, *dataset_file_name;
|
||||||
|
ITKCALL(ifail = USERARG_get_string_argument(&datasetUid));
|
||||||
|
ITKCALL(ifail = USERARG_get_string_argument(&refName));
|
||||||
|
ITKCALL(ifail = USERARG_get_string_argument(&ext));
|
||||||
|
tag_t dataset;
|
||||||
|
ITK__convert_uid_to_tag(datasetUid, &dataset);
|
||||||
|
export_dataset_file_to_dir(debug, dataset, refName, "D:\\Siemens\\IIS\\web\\file", ext, &dataset_file_path, &dataset_file_name);
|
||||||
|
string buff = dataset_file_path;
|
||||||
|
*((char**)returnValue) = (char*)MEM_alloc((strlen(buff.c_str()) + 1) * sizeof(char));
|
||||||
|
tc_strcpy(*((char**)returnValue), buff.c_str());
|
||||||
|
return ifail;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LD_AutoAssign(EPM_action_message_t msg) {
|
||||||
|
int ifail = ITK_ok, arg_cnt = 0, att_cnt = 0, task_count = 0;
|
||||||
|
char* arg = NULL, * argflag = NULL, * argvalue = NULL;
|
||||||
|
tag_t* attachments = NULLTAG, task_tag = NULLTAG, rootTask_tag = NULLTAG, * task_tags = NULLTAG;
|
||||||
|
vector<string> values;
|
||||||
|
set<string> sh_set;
|
||||||
|
getPrefStrings("Connor_PRType_Person_Mapping", TC_preference_site,values);
|
||||||
|
//拿到当前节点
|
||||||
|
task_tag = msg.task;
|
||||||
|
if (task_tag == NULLTAG) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
ITKCALL(ifail = EPM_ask_root_task(task_tag, &rootTask_tag));
|
||||||
|
//获取目标下所有对象
|
||||||
|
ITKCALL(ifail = EPM_ask_attachments(rootTask_tag, EPM_target_attachment, &att_cnt, &attachments));
|
||||||
|
if (att_cnt == 0) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < att_cnt; i++)
|
||||||
|
{
|
||||||
|
char* object_type = NULL;
|
||||||
|
AOM_ask_value_string(attachments[i],"object_type",&object_type);
|
||||||
|
if (strcmp("LD6_PRRevision",object_type) == 0) {
|
||||||
|
char* problem_type = NULL;
|
||||||
|
char* company_value = NULL;
|
||||||
|
AOM_ask_value_string(attachments[i], "ld6_company", &company_value);
|
||||||
|
AOM_ask_value_string(attachments[i], "ld6_problemType", &problem_type);
|
||||||
|
/*for each (string problem in values)
|
||||||
|
{
|
||||||
|
vector<string> split;
|
||||||
|
Split(problem.c_str(), "=", split);
|
||||||
|
if (split.size() == 2 && strcmp(split[0].c_str(),problem_type) == 0) {
|
||||||
|
if (sh_set.insert(split[1]).second == false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
for each (string company in values)
|
||||||
|
{
|
||||||
|
vector<string> split;
|
||||||
|
vector<string> split2;
|
||||||
|
Split(company.c_str(), ":", split);
|
||||||
|
if (split[0].empty()) {
|
||||||
|
EMH_store_error_s2(EMH_severity_error, ITK_err, "首选项配置错误", company.c_str());
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
//公司属性相同
|
||||||
|
if (split.size() == 2 && strcmp(split[0].c_str(), company_value) == 0) {
|
||||||
|
Split(split[1].c_str(), "=", split2);
|
||||||
|
if (split2.size() == 2) {
|
||||||
|
//问题类型为空
|
||||||
|
if (split2[0].empty()) {
|
||||||
|
if (sh_set.insert(split2[1]).second == false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//问题类型不为空,且相同
|
||||||
|
else if (strcmp(split2[0].c_str(), problem_type) == 0) {
|
||||||
|
if (sh_set.insert(split2[1]).second == false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char* task_type = NULL;
|
||||||
|
WSOM_ask_object_type2(task_tag, &task_type);
|
||||||
|
printf("当前节点的类型为:%s\n", task_type);
|
||||||
|
if (strcmp("EPMReviewTask", task_type) == 0 || strcmp("EPMAcknowledgeTask", task_type) == 0) {
|
||||||
|
char* object_name = NULL;
|
||||||
|
int mem_cnt = 0, signoff_cnt = 0;
|
||||||
|
tag_t user_tag = NULLTAG, login_group = NULLTAG, * members = NULLTAG, * signoffs = NULLTAG, select_signoff_tag = NULLTAG;
|
||||||
|
AOM_ask_value_string(task_tag, "object_name", &object_name);//对象名称
|
||||||
|
EPM_ask_sub_task(task_tag, "select-signoff-team", &select_signoff_tag);
|
||||||
|
printf("当前节点的名称为:%s\n", object_name);
|
||||||
|
|
||||||
|
int attachments_num = 0,* attach_type; tag_t* attachmentTags;
|
||||||
|
EPM_ask_all_attachments(select_signoff_tag, &attachments_num, &attachmentTags, &attach_type);
|
||||||
|
if (attachments_num > 0) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (set<string>::iterator it = sh_set.begin(); it != sh_set.end(); it++) {
|
||||||
|
printf("添加:%s\n", it->c_str());
|
||||||
|
ITKCALL(SA_find_user2(it->c_str(), &user_tag));
|
||||||
|
ITKCALL(SA_ask_user_login_group(user_tag, &login_group));
|
||||||
|
ITKCALL(SA_find_groupmembers(user_tag, login_group, &mem_cnt, &members));
|
||||||
|
ITKCALL(EPM_create_adhoc_signoff(select_signoff_tag, members[0], &signoff_cnt, &signoffs));
|
||||||
|
}
|
||||||
|
if (sh_set.size() > 0) {
|
||||||
|
ITKCALL(EPM_set_adhoc_signoff_selection_done(select_signoff_tag, true));
|
||||||
|
}
|
||||||
|
DOFREE(object_name);
|
||||||
|
DOFREE(members);
|
||||||
|
DOFREE(signoffs);
|
||||||
|
}
|
||||||
|
if (strcmp("EPMDoTask", task_type) == 0 || strcmp("EPMConditionTask", task_type) == 0) {
|
||||||
|
tag_t user_tag = NULLTAG;
|
||||||
|
for (set<string>::iterator it = sh_set.begin(); it != sh_set.end(); it++) {
|
||||||
|
ITKCALL(SA_find_user2(it->c_str(), &user_tag));
|
||||||
|
ITKCALL(EPM_assign_responsible_party(task_tag, user_tag));//设置编制节点的责任方
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
DOFREE(attachments);
|
||||||
|
return ifail;
|
||||||
|
}
|
||||||
|
int ML_ItemRevSave(METHOD_message_t* msg, va_list args)
|
||||||
|
{
|
||||||
|
printf("=========================创建后操作 Start===================\n");
|
||||||
|
int ifail = ITK_ok;
|
||||||
|
tag_t new_rev = va_arg(args, tag_t);
|
||||||
|
|
||||||
|
if (isTypeOf(new_rev, "Part Revision")) {
|
||||||
|
printf("类型为Part Revision 检查物料描述\n");
|
||||||
|
char* ld6_materialDesc, * item_id;
|
||||||
|
AOM_ask_value_string(new_rev, "ld6_materialDesc", &ld6_materialDesc);
|
||||||
|
AOM_ask_value_string(new_rev, "item_id", &item_id);
|
||||||
|
tag_t query;
|
||||||
|
int n_found;
|
||||||
|
ITKCALL(ifail = QRY_find2("6LD_Om_PartRevision", &query));
|
||||||
|
tag_t* tags;
|
||||||
|
boolean saveFlag = true;
|
||||||
|
char* qry_entries[2] = { "materialDesc" ,"id01" },
|
||||||
|
* qry_values[2] = { ld6_materialDesc ,item_id }, * errorId = "";
|
||||||
|
ITKCALL(ifail = QRY_execute(query, 2, qry_entries, qry_values, &n_found, &tags));
|
||||||
|
if (n_found == 0) {
|
||||||
|
saveFlag = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
for (int i = 0; i < n_found; i++) {
|
||||||
|
char* itemId;
|
||||||
|
AOM_ask_value_string(tags[i], "item_id", &itemId);
|
||||||
|
printf("查询到的itemId==> %s\n", itemId);
|
||||||
|
}
|
||||||
|
ifail = 1;
|
||||||
|
saveFlag = false;
|
||||||
|
EMH_store_error_s2(EMH_severity_error,
|
||||||
|
ITK_err,
|
||||||
|
"提示",
|
||||||
|
"已存在相同物料描述的对象,无需重复创建!");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
return ifail;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//int LD6_CusProdFolderSave(METHOD_message_t* msg, va_list args)
|
||||||
|
//{
|
||||||
|
//
|
||||||
|
// char* log_file = NULL;
|
||||||
|
//
|
||||||
|
// printf("创建日志文件\n");
|
||||||
|
// char* TO_SRM = (char*)malloc(sizeof("LD6_CusProdFolderSave"));
|
||||||
|
// strcpy(TO_SRM, "emp_register_handler");
|
||||||
|
// CreateLogFile(TO_SRM,"", &log_file);
|
||||||
|
//
|
||||||
|
// WriteLog(true, "=========================文件夹后操作 Start===================\n");
|
||||||
|
// int ifail = ITK_ok;
|
||||||
|
// tag_t folder = va_arg(args, tag_t);
|
||||||
|
//
|
||||||
|
// if (isTypeOf(folder, "LD6_CusProdFolder")) {
|
||||||
|
// //连接数据库保存当前名称到数据库
|
||||||
|
// char* folder_uid;
|
||||||
|
// ITK__convert_tag_to_uid(folder,&folder_uid);//获取文件夹uid
|
||||||
|
// bool conn = open("infodba", "infodba", "TC13", "10.10.22.39");
|
||||||
|
// if (conn != NULL && conn) {
|
||||||
|
// WriteLog(true, "=========================连接成功===================\n");
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// WriteLog(true, "=========================连接失败==================\n");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// va_end(args);
|
||||||
|
// WriteLog(true, "=========================文件夹后操作 End===================\n");
|
||||||
|
// CloseLog();
|
||||||
|
// return ifail;
|
||||||
|
//}
|
||||||
@ -0,0 +1,128 @@
|
|||||||
|
#include"kutil.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include "libxl.h"
|
||||||
|
#include <io.h>
|
||||||
|
#include <direct.h>
|
||||||
|
#include <cfm/cfm.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
#include <locale>
|
||||||
|
#include <codecvt>
|
||||||
|
#include <chrono>
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <thread>
|
||||||
|
#include <regex>
|
||||||
|
#include <res\reservation.h>
|
||||||
|
#include "libxl.h"
|
||||||
|
#include <map>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include "ado.h"
|
||||||
|
using namespace libxl;
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#define debug true
|
||||||
|
#define ITK_err 919012
|
||||||
|
|
||||||
|
int LD_CompletionDate(EPM_action_message_t msg) {
|
||||||
|
printf("=========================开始===================\n");
|
||||||
|
|
||||||
|
int cnt = 0;
|
||||||
|
char** vals = NULL;
|
||||||
|
//获取首选项的值
|
||||||
|
PREF_ask_char_values("LD_dbinfo2", &cnt, &vals);
|
||||||
|
|
||||||
|
|
||||||
|
//获取当前时间
|
||||||
|
time_t now = time(0);
|
||||||
|
tm* p = localtime(&now);
|
||||||
|
char dateNow[128] = "";
|
||||||
|
sprintf_s(dateNow, "%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);
|
||||||
|
string dateString = dateNow;
|
||||||
|
|
||||||
|
int ifail = ITK_ok;
|
||||||
|
int attachments_num = 0;
|
||||||
|
tag_t rootTask = NULLTAG, * attachments = NULLTAG;
|
||||||
|
//获取任务对象
|
||||||
|
EPM_ask_root_task(msg.task, &rootTask);
|
||||||
|
//获取任务目标对象
|
||||||
|
EPM_ask_attachments(rootTask, EPM_target_attachment, &attachments_num, &attachments);
|
||||||
|
|
||||||
|
|
||||||
|
for (int r = 0; r < attachments_num; r++) {
|
||||||
|
char* itemObjId;
|
||||||
|
char* objectType;
|
||||||
|
char* revision_id;
|
||||||
|
AOM_ask_value_string(attachments[r], "object_type", &objectType);
|
||||||
|
printf("objectType===%s\n", objectType);
|
||||||
|
if (strcmp(objectType, "LD6_CusProdFolder") == 0) {
|
||||||
|
|
||||||
|
//获取前面condition节点的值
|
||||||
|
tag_t* fnd0ActuatedInteractiveTsks_val;
|
||||||
|
int fnd0ActuatedInteractiveTsks_num = 0;
|
||||||
|
AOM_ask_value_tags(attachments[r], "fnd0ActuatedInteractiveTsks", &fnd0ActuatedInteractiveTsks_num, &fnd0ActuatedInteractiveTsks_val);
|
||||||
|
if (fnd0ActuatedInteractiveTsks_num > 0) {
|
||||||
|
|
||||||
|
for (int i = 0; i < fnd0ActuatedInteractiveTsks_num; i++)
|
||||||
|
{
|
||||||
|
char* task_type;
|
||||||
|
AOM_ask_value_string(fnd0ActuatedInteractiveTsks_val[i], "task_type", &task_type);
|
||||||
|
printf("task_type===%s\n", task_type);
|
||||||
|
if (strcmp(task_type, "EPMConditionTask") == 0) {
|
||||||
|
|
||||||
|
char* task_result;
|
||||||
|
AOM_ask_value_string(fnd0ActuatedInteractiveTsks_val[i], "task_result", &task_result);
|
||||||
|
printf("task_result===%s\n", task_result);
|
||||||
|
|
||||||
|
//连接数据库保存当前名称到数据库
|
||||||
|
char* folder_uid;
|
||||||
|
ITK__convert_tag_to_uid(attachments[r], &folder_uid);//获取文件夹uid
|
||||||
|
|
||||||
|
if (open("infodba", "infodba", vals[1], vals[0])) {
|
||||||
|
printf("=========================连接失败===================\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//获取当前时间
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
std::time_t time = std::chrono::system_clock::to_time_t(now);
|
||||||
|
std::tm* ptm = std::localtime(&time);
|
||||||
|
char buf[128];
|
||||||
|
strftime(buf, sizeof(buf), "%Y-%m-%d", ptm);
|
||||||
|
printf("time===%s\n", buf);
|
||||||
|
//update语句
|
||||||
|
char sql[200] = "";
|
||||||
|
sprintf(sql, "UPDATE LD6_NewProdForm_VALUES SET CompletionDate = '%s' WHERE ClientProductFolderPUID = '%s' AND NewProductTaskItem = '%s'", buf, folder_uid, task_result);
|
||||||
|
printf("sql===%s\n", sql);
|
||||||
|
if (ExecuteSQLNoInputParam(sql) == 0)
|
||||||
|
{
|
||||||
|
printf("=========================修改成功===================\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("=========================修改失败===================\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("=========================结束===================\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,125 @@
|
|||||||
|
#include"kutil.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include "libxl.h"
|
||||||
|
#include <io.h>
|
||||||
|
#include <direct.h>
|
||||||
|
#include <cfm/cfm.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
#include <locale>
|
||||||
|
#include <codecvt>
|
||||||
|
#include <chrono>
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <thread>
|
||||||
|
#include <regex>
|
||||||
|
#include <res\reservation.h>
|
||||||
|
#include "libxl.h"
|
||||||
|
#include <map>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include "ado.h"
|
||||||
|
using namespace libxl;
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#define debug true
|
||||||
|
#define ITK_err 919012
|
||||||
|
|
||||||
|
int LD_TaskAssignmentDate(EPM_action_message_t msg) {
|
||||||
|
printf("=========================开始===================\n");
|
||||||
|
int cnt = 0;
|
||||||
|
char** vals = NULL;
|
||||||
|
//获取首选项的值
|
||||||
|
PREF_ask_char_values("LD_dbinfo2", &cnt, &vals);
|
||||||
|
//获取当前时间
|
||||||
|
time_t now = time(0);
|
||||||
|
tm* p = localtime(&now);
|
||||||
|
char dateNow[128] = "";
|
||||||
|
sprintf_s(dateNow, "%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);
|
||||||
|
string dateString = dateNow;
|
||||||
|
|
||||||
|
int ifail = ITK_ok;
|
||||||
|
int attachments_num = 0;
|
||||||
|
tag_t rootTask = NULLTAG, * attachments = NULLTAG;
|
||||||
|
//获取任务对象
|
||||||
|
EPM_ask_root_task(msg.task, &rootTask);
|
||||||
|
//获取任务目标对象
|
||||||
|
EPM_ask_attachments(rootTask, EPM_target_attachment, &attachments_num, &attachments);
|
||||||
|
|
||||||
|
|
||||||
|
for (int r = 0; r < attachments_num; r++) {
|
||||||
|
char* itemObjId;
|
||||||
|
char* objectType;
|
||||||
|
char* revision_id;
|
||||||
|
AOM_ask_value_string(attachments[r], "object_type", &objectType);
|
||||||
|
printf("objectType===%s\n", objectType);
|
||||||
|
if (strcmp(objectType, "LD6_CusProdFolder") == 0) {
|
||||||
|
|
||||||
|
//获取前面condition节点的值
|
||||||
|
tag_t* fnd0ActuatedInteractiveTsks_val;
|
||||||
|
int fnd0ActuatedInteractiveTsks_num = 0;
|
||||||
|
AOM_ask_value_tags(attachments[r], "fnd0ActuatedInteractiveTsks", &fnd0ActuatedInteractiveTsks_num, &fnd0ActuatedInteractiveTsks_val);
|
||||||
|
if (fnd0ActuatedInteractiveTsks_num > 0) {
|
||||||
|
|
||||||
|
for (int i = 0; i < fnd0ActuatedInteractiveTsks_num; i++)
|
||||||
|
{
|
||||||
|
char* task_type;
|
||||||
|
AOM_ask_value_string(fnd0ActuatedInteractiveTsks_val[i], "task_type", &task_type);
|
||||||
|
printf("task_type===%s\n", task_type);
|
||||||
|
if (strcmp(task_type, "EPMConditionTask") == 0) {
|
||||||
|
|
||||||
|
char* task_result;
|
||||||
|
AOM_ask_value_string(fnd0ActuatedInteractiveTsks_val[i], "task_result", &task_result);
|
||||||
|
printf("task_result===%s\n", task_result);
|
||||||
|
|
||||||
|
//连接数据库保存当前名称到数据库
|
||||||
|
char* folder_uid;
|
||||||
|
ITK__convert_tag_to_uid(attachments[r], &folder_uid);//获取文件夹uid
|
||||||
|
|
||||||
|
if (open("infodba", "infodba", vals[1], vals[0])) {
|
||||||
|
printf("=========================连接失败===================\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//获取当前时间
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
std::time_t time = std::chrono::system_clock::to_time_t(now);
|
||||||
|
std::tm* ptm = std::localtime(&time);
|
||||||
|
char buf[128];
|
||||||
|
strftime(buf, sizeof(buf), "%Y-%m-%d", ptm);
|
||||||
|
printf("time===%s\n", buf);
|
||||||
|
//update语句
|
||||||
|
char sql[200] = "";
|
||||||
|
sprintf(sql, "UPDATE LD6_NewProdForm_VALUES SET TaskAssignmentDate = '%s' WHERE ClientProductFolderPUID = '%s' AND NewProductTaskItem = '%s'", buf, folder_uid, task_result);
|
||||||
|
printf("sql===%s\n", sql);
|
||||||
|
if (ExecuteSQLNoInputParam(sql) == 0)
|
||||||
|
{
|
||||||
|
printf("=========================修改成功===================\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("=========================修改失败===================\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("=========================结束===================\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,77 @@
|
|||||||
|
#include"kutil.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include "libxl.h"
|
||||||
|
#include <io.h>
|
||||||
|
#include <direct.h>
|
||||||
|
#include <cfm/cfm.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
#include <locale>
|
||||||
|
#include <codecvt>
|
||||||
|
#include <chrono>
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <thread>
|
||||||
|
#include <regex>
|
||||||
|
#include <res\reservation.h>
|
||||||
|
#include "libxl.h"
|
||||||
|
#include <map>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
using namespace libxl;
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#define debug true
|
||||||
|
#define ITK_err 919012
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int UpgradeTask(EPM_action_message_t msg) {
|
||||||
|
printf("++++++++++++++++++开始提升流程节点++++++++++++++++++++\n");
|
||||||
|
POM_AM__set_application_bypass(true);
|
||||||
|
int ifail = ITK_ok, att_cnt = 0, i = 0, arg_cnt = 0;
|
||||||
|
tag_t task_tag = NULL_TAG, rootTask_tag = NULL_TAG;
|
||||||
|
task_tag = msg.task;
|
||||||
|
if (task_tag == NULLTAG)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ITKCALL(EPM_ask_root_task(task_tag, &rootTask_tag));
|
||||||
|
char* uid;
|
||||||
|
ITK__convert_tag_to_uid(rootTask_tag, &uid);
|
||||||
|
printf("uid:%s\n", uid);
|
||||||
|
int allstartnum = 0; tag_t* allstart;
|
||||||
|
ITKCALL(AOM_ask_value_tags(rootTask_tag, "child_tasks", &allstartnum, &allstart));
|
||||||
|
for (int i = 0; i < allstartnum;i++) {
|
||||||
|
char* taskName;
|
||||||
|
ITKCALL(AOM_ask_value_string(allstart[i], "object_name", &taskName));
|
||||||
|
printf("子任务%d:%s\n",i,taskName);
|
||||||
|
}
|
||||||
|
char* taskname = NULL, * type = NULL;
|
||||||
|
ITKCALL(EPM_ask_name2(task_tag, &taskname));
|
||||||
|
ITKCALL(AOM_ask_value_string(task_tag, "object_type", &type));
|
||||||
|
printf("name=%s\n", taskname);
|
||||||
|
printf("type=%s\n", type);
|
||||||
|
if (strcmp(type, "EPMDoTask") == 0)
|
||||||
|
{
|
||||||
|
EPM_remove_task_hold(task_tag);
|
||||||
|
printf("开始提升节点\n");
|
||||||
|
ITKCALL(EPM_promote_task(task_tag, ""));
|
||||||
|
printf("提升节点结束\n");
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
DOFREE(taskname);
|
||||||
|
DOFREE(type);
|
||||||
|
POM_AM__set_application_bypass(false);
|
||||||
|
|
||||||
|
printf("++++++++++++++++++提升流程节点结束++++++++++++++++++++\n");
|
||||||
|
return ITK_ok;
|
||||||
|
}
|
||||||
@ -0,0 +1,244 @@
|
|||||||
|
#include "handler.h"
|
||||||
|
|
||||||
|
#define ARGS_LENGTH 200
|
||||||
|
#define MAX_PRINTLINE_LENGTH 2000
|
||||||
|
#define MAX_PATH_LENGTH 2000
|
||||||
|
#define MAX_ARGUMENT_LENGTH 400
|
||||||
|
#define MAX_PARAMNAME_LENGTH 50
|
||||||
|
#define MAX_FILE_EXT_LENGTH 10
|
||||||
|
#define TRUE_FLAG 1
|
||||||
|
#define FALSE_FLAG 0
|
||||||
|
#define DETAILLOG 1
|
||||||
|
#define DOFREE(obj) \
|
||||||
|
{ \
|
||||||
|
if(obj) \
|
||||||
|
{ \
|
||||||
|
MEM_free(obj); \
|
||||||
|
obj = NULL; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
int delete_release_status(EPM_action_message_t msg) {
|
||||||
|
int ifail = ITK_ok, att_cnt = 0, rel_cnt = 0;
|
||||||
|
EPM_target_attachment;
|
||||||
|
tag_t task = NULLTAG, rootTask_tag = NULLTAG, *attchments = NULL, *releases = NULL, release_status = NULL;
|
||||||
|
|
||||||
|
ITKCALL(EPM_ask_root_task(msg.task, &rootTask_tag));
|
||||||
|
ITKCALL(EPM_ask_attachments(rootTask_tag, EPM_target_attachment, &att_cnt, &attchments));
|
||||||
|
POM_AM__set_application_bypass(true);
|
||||||
|
for (int i = 0; i < att_cnt; i++)
|
||||||
|
{
|
||||||
|
ITKCALL(AOM_ask_value_tags(attchments[i], "release_status_list", &rel_cnt, &releases));
|
||||||
|
for (int j = rel_cnt - 1; j > -1; j--)
|
||||||
|
{
|
||||||
|
EPM_remove_status_from_targets(releases[j], rootTask_tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
POM_AM__set_application_bypass(false);
|
||||||
|
return ifail;
|
||||||
|
}
|
||||||
|
|
||||||
|
//发布对象
|
||||||
|
int set_release_status(tag_t item, char release_name[]) {
|
||||||
|
int ifail = ITK_ok;
|
||||||
|
tag_t release_status = NULL;
|
||||||
|
|
||||||
|
ITKCALL(ifail = RELSTAT_create_release_status(release_name, &release_status));
|
||||||
|
ITKCALL(ifail = RELSTAT_add_release_status(release_status, 1, &item, TRUE));
|
||||||
|
|
||||||
|
return ifail;
|
||||||
|
}
|
||||||
|
|
||||||
|
int reviseDesignPost(METHOD_message_t* msg, va_list va)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
int ifail = ITK_ok, rev_cnt = 0;
|
||||||
|
tag_t new_rev = va_arg(va, tag_t);
|
||||||
|
tag_t item = NULLTAG;
|
||||||
|
tag_t *rev_list;
|
||||||
|
|
||||||
|
POM_AM__set_application_bypass(true);
|
||||||
|
|
||||||
|
printf("图纸升版后操作\n");
|
||||||
|
ITKCALL(ITEM_ask_item_of_rev(new_rev, &item));
|
||||||
|
ITKCALL(AOM_ask_value_tags(item, "revision_list", &rev_cnt, &rev_list));
|
||||||
|
if (rev_cnt > 1)
|
||||||
|
{
|
||||||
|
int wl_cnt = 0;
|
||||||
|
tag_t *wl_list;
|
||||||
|
tag_t pre_rev = rev_list[rev_cnt - 2],wlobj,newwlrev;
|
||||||
|
char * revtype,* wltype;
|
||||||
|
|
||||||
|
int wlcount = 0; tag_t *wltags;
|
||||||
|
ITKCALL(AOM_ask_value_string(pre_rev, "object_type", &revtype));
|
||||||
|
if (strcmp("LD6_2DdesignRevision", revtype)==0) {
|
||||||
|
printf("2D升版后操\n");
|
||||||
|
ITKCALL(AOM_ask_value_tags(pre_rev, "LD6_ProductInfo", &wlcount, &wltags));
|
||||||
|
for (int i = 0; i < wlcount;i++) {
|
||||||
|
ITKCALL(AOM_ask_value_string(wltags[i], "object_type", &wltype));
|
||||||
|
if (strcmp("LD6_ProductRevision", wltype)==0 || strcmp("LD6_MachinesPRevision", wltype) == 0) {
|
||||||
|
ITKCALL(ITEM_ask_item_of_rev(wltags[i], &wlobj));
|
||||||
|
if (wlobj!=NULL) {
|
||||||
|
int status = ITEM_ask_latest_rev(wlobj, &newwlrev);
|
||||||
|
if (status == ITK_ok)
|
||||||
|
{
|
||||||
|
printf("start 开始删除关系\n");
|
||||||
|
tag_t gx_gx_type = NULLTAG; tag_t gx_relation = NULLTAG;
|
||||||
|
ITKCALL(GRM_find_relation_type("LD6_ProductInfo", &gx_gx_type));
|
||||||
|
GRM_find_relation(new_rev, wltags[i], gx_gx_type, &gx_relation);
|
||||||
|
GRM_delete_relation(gx_relation);
|
||||||
|
printf("end 删除关系完毕\n");
|
||||||
|
printf("start 开始添加关系\n");
|
||||||
|
tag_t relation = NULLTAG;
|
||||||
|
ITKCALL(GRM_create_relation(new_rev, newwlrev, gx_gx_type, NULLTAG, &relation));
|
||||||
|
ITKCALL(GRM_save_relation(relation));
|
||||||
|
printf("end 添加关系完毕\n");
|
||||||
|
//ITKCALL(AOM_set_value_tag(new_rev, "LD6_ProductInfo",newwlrev));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp("LD6_MEProcessCrRevision", revtype) == 0 || strcmp("LD6_LSMEProcessRevision", revtype) == 0) {
|
||||||
|
printf("工艺路线升版后操\n");
|
||||||
|
ITKCALL(AOM_ask_value_tags(pre_rev, "IMAN_METarget", &wlcount, &wltags));
|
||||||
|
for (int i = 0; i < wlcount; i++) {
|
||||||
|
ITKCALL(AOM_ask_value_string(wltags[i], "object_type", &wltype));
|
||||||
|
if (strcmp("LD6_ProductRevision", wltype) == 0 || strcmp("LD6_MachinesPRevision", wltype) == 0) {
|
||||||
|
ITKCALL(ITEM_ask_item_of_rev(wltags[i], &wlobj));
|
||||||
|
if (wlobj != NULL) {
|
||||||
|
int status = ITEM_ask_latest_rev(wlobj, &newwlrev);
|
||||||
|
if (status == ITK_ok)
|
||||||
|
{
|
||||||
|
printf("start 开始删除关系\n");
|
||||||
|
tag_t gx_gx_type = NULLTAG; tag_t gx_relation = NULLTAG;
|
||||||
|
ITKCALL(GRM_find_relation_type("IMAN_METarget", &gx_gx_type));
|
||||||
|
GRM_find_relation(new_rev, wltags[i], gx_gx_type, &gx_relation);
|
||||||
|
GRM_delete_relation(gx_relation);
|
||||||
|
printf("end 删除关系完毕\n");
|
||||||
|
printf("start 开始添加关系\n");
|
||||||
|
tag_t relation = NULLTAG;
|
||||||
|
ITKCALL(GRM_create_relation(new_rev, newwlrev, gx_gx_type, NULLTAG, &relation));
|
||||||
|
ITKCALL(GRM_save_relation(relation));
|
||||||
|
printf("end 添加关系完毕\n");
|
||||||
|
//ITKCALL(AOM_set_value_tag(new_rev, "IMAN_METarget", newwlrev));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//修改属性
|
||||||
|
printf("开始修改属性\n");
|
||||||
|
|
||||||
|
char *getnum, *part;
|
||||||
|
ITKCALL(AOM_ask_value_string(newwlrev, "ld6_clientPartNum",&getnum));
|
||||||
|
ITKCALL(AOM_ask_value_string(newwlrev, "ld6_clientPartRev", &part));
|
||||||
|
AOM_lock(new_rev);
|
||||||
|
|
||||||
|
ITKCALL(AOM_set_value_string(new_rev, "ld6_clientPartNum", getnum));
|
||||||
|
ITKCALL(AOM_set_value_string(new_rev, "ld6_clientPartRev", part));
|
||||||
|
AOM_save(new_rev);
|
||||||
|
AOM_unlock(new_rev);
|
||||||
|
AOM_refresh(new_rev,true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp("LD6_TecDOCRevision", revtype) == 0) {
|
||||||
|
printf("技术文档\n");
|
||||||
|
ITKCALL(AOM_ask_value_tags(pre_rev, "LD6_ProductInfo", &wlcount, &wltags));
|
||||||
|
for (int i = 0; i < wlcount; i++) {
|
||||||
|
ITKCALL(AOM_ask_value_string(wltags[i], "object_type", &wltype));
|
||||||
|
if (strcmp("LD6_ProductRevision", wltype) == 0 || strcmp("LD6_MachinesPRevision", wltype) == 0) {
|
||||||
|
ITKCALL(ITEM_ask_item_of_rev(wltags[i], &wlobj));
|
||||||
|
if (wlobj != NULL) {
|
||||||
|
int status = ITEM_ask_latest_rev(wlobj, &newwlrev);
|
||||||
|
if (status == ITK_ok)
|
||||||
|
{
|
||||||
|
printf("start 开始删除关系\n");
|
||||||
|
tag_t gx_gx_type = NULLTAG; tag_t gx_relation = NULLTAG;
|
||||||
|
ITKCALL(GRM_find_relation_type("LD6_ProductInfo", &gx_gx_type));
|
||||||
|
GRM_find_relation(new_rev, wltags[i], gx_gx_type, &gx_relation);
|
||||||
|
GRM_delete_relation(gx_relation);
|
||||||
|
printf("end 删除关系完毕\n");
|
||||||
|
printf("start 开始添加关系\n");
|
||||||
|
tag_t relation = NULLTAG;
|
||||||
|
ITKCALL(GRM_create_relation(new_rev, newwlrev, gx_gx_type, NULLTAG, &relation));
|
||||||
|
ITKCALL(GRM_save_relation(relation));
|
||||||
|
printf("end 添加关系完毕\n");
|
||||||
|
//ITKCALL(AOM_set_value_tag(new_rev, "LD6_ProductInfo", newwlrev));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp("LD6_3DdesignRevision", revtype)==0) {
|
||||||
|
ITKCALL(AOM_ask_value_tags(pre_rev, "representation_for", &wl_cnt, &wl_list));
|
||||||
|
map<string, tag_t> wl_map;
|
||||||
|
for (int i = 0; i < wl_cnt; i++)
|
||||||
|
{
|
||||||
|
char *wl_id;
|
||||||
|
ITKCALL(AOM_ask_value_string(wl_list[i], "item_id", &wl_id));
|
||||||
|
wl_map.find(wl_id);
|
||||||
|
if (wl_map.find(wl_id) == wl_map.end())
|
||||||
|
{
|
||||||
|
tag_t wl_item;
|
||||||
|
ITKCALL(ITEM_ask_item_of_rev(wl_list[i], &wl_item));
|
||||||
|
wl_map[wl_id] = wl_item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list<tag_t> wl_add;
|
||||||
|
map<string, tag_t>::iterator it;
|
||||||
|
for (map<string, tag_t>::iterator it = wl_map.begin(); it != wl_map.end(); it++)
|
||||||
|
{
|
||||||
|
tag_t wl_item = it->second;
|
||||||
|
//int wl_rev_cnt = 0;
|
||||||
|
//tag_t *wl_rev_list;
|
||||||
|
tag_t wl_rev;
|
||||||
|
//ITKCALL(AOM_ask_value_tags(wl_item, "revision_list", &wl_rev_cnt, &wl_rev_list));
|
||||||
|
int status = ITEM_ask_latest_rev(wl_item, &wl_rev);
|
||||||
|
if (status == ITK_ok)
|
||||||
|
{
|
||||||
|
// 获取最新版本成功,可以使用 revision 变量进行后续操作
|
||||||
|
wl_add.push_back(wl_rev);
|
||||||
|
|
||||||
|
}
|
||||||
|
//if (wl_rev_cnt > 0)
|
||||||
|
//{
|
||||||
|
// wl_add.push_back(wl_rev_list[wl_rev_cnt - 1]);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
for (list<tag_t>::iterator it = wl_add.begin(); it != wl_add.end(); it++)
|
||||||
|
{
|
||||||
|
char *obj_str;
|
||||||
|
tag_t relation_type = NULLTAG, relation = NULLTAG;
|
||||||
|
ITKCALL(AOM_ask_value_string(*it, "object_string", &obj_str));
|
||||||
|
printf("object_string = %s\n", obj_str);
|
||||||
|
|
||||||
|
ITKCALL(AOM_lock(*it));
|
||||||
|
GRM_find_relation_type("TC_Is_Represented_By", &relation_type);
|
||||||
|
if (relation_type != NULLTAG)
|
||||||
|
{
|
||||||
|
GRM_create_relation(*it, new_rev, relation_type, NULLTAG, &relation);
|
||||||
|
GRM_save_relation(relation);
|
||||||
|
}
|
||||||
|
ITKCALL(AOM_save(*it));
|
||||||
|
ITKCALL(AOM_unlock(*it));
|
||||||
|
ITKCALL(AOM_refresh(*it, true));
|
||||||
|
}
|
||||||
|
/*int n = 0;
|
||||||
|
tag_t *value = (tag_t*)MEM_alloc(sizeof(tag_t)*(wl_add.size()));
|
||||||
|
for (list<tag_t>::iterator it = wl_add.begin(); it != wl_add.end(); it++)
|
||||||
|
{
|
||||||
|
char *obj_str;
|
||||||
|
ITKCALL(AOM_ask_value_string(*it, "object_string", &obj_str));
|
||||||
|
printf("object_string = %s\n", obj_str);
|
||||||
|
value[n] = *it;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
ITKCALL(AOM_set_value_tags(new_rev, "representation_for", wl_add.size(), value));*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
POM_AM__set_application_bypass(false);
|
||||||
|
return ifail;
|
||||||
|
}
|
||||||
@ -0,0 +1,107 @@
|
|||||||
|
|
||||||
|
#include "ado.h"
|
||||||
|
|
||||||
|
_ConnectionPtr m_pConnection;
|
||||||
|
_RecordsetPtr m_pRecordset;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
bool open(char* username, char* password, char* dbname, char* ip)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
::CoInitialize(NULL); //初始化COM环境
|
||||||
|
m_pConnection.CreateInstance(__uuidof(Connection)); //创建连接对象
|
||||||
|
char connStr[200] = "";
|
||||||
|
sprintf(connStr, "Provider=SQLOLEDB;Data Source=%s;Initial Catalog=%s;", ip, dbname);
|
||||||
|
hr = m_pConnection->Open(connStr, username, password, -1);
|
||||||
|
if (hr != S_OK)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (_com_error e)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 有输入参数的查询
|
||||||
|
int QuerySQL(char *SQL, int inputValueCount, int * outputColumn, int * outputValueCount, char **** outputValue)
|
||||||
|
{
|
||||||
|
|
||||||
|
Fields * fields = NULL;
|
||||||
|
long ColCount = 0;
|
||||||
|
|
||||||
|
*outputColumn = 0;
|
||||||
|
*outputValueCount = 0;
|
||||||
|
m_pRecordset.CreateInstance(__uuidof(Recordset));
|
||||||
|
|
||||||
|
m_pRecordset->Open(SQL, m_pConnection.GetInterfacePtr(), adOpenStatic, adLockOptimistic, adCmdText);
|
||||||
|
hr = m_pRecordset->get_Fields(&fields); //得到记录集的字段集和
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
fields->get_Count(&ColCount);
|
||||||
|
*outputValueCount = (int)ColCount;
|
||||||
|
}
|
||||||
|
if (*outputValueCount == 0)
|
||||||
|
return 0;
|
||||||
|
int index = 0;
|
||||||
|
// 开始分配内存并且存储
|
||||||
|
*outputValue = (char ***)calloc((*outputValueCount) + 1, sizeof(char**));
|
||||||
|
while (!m_pRecordset->adoEOF)
|
||||||
|
{
|
||||||
|
(*outputValue)[index] = (char **)calloc((*outputColumn) + 1, sizeof(char *));
|
||||||
|
for (long i = 0; i < ColCount; i++)
|
||||||
|
{
|
||||||
|
BSTR bstrColName=NULL;
|
||||||
|
fields->Item[i]->get_Name(&bstrColName);
|
||||||
|
(*outputValue)[index][i] = (char *)calloc(1000, sizeof(char));
|
||||||
|
_variant_t taskStyle = NULL;
|
||||||
|
taskStyle = m_pRecordset->GetCollect(bstrColName);
|
||||||
|
const char* str;
|
||||||
|
_bstr_t bst_t = (_bstr_t)taskStyle;
|
||||||
|
str = (const char*)bst_t;
|
||||||
|
strcpy((*outputValue)[index][i], str);
|
||||||
|
}
|
||||||
|
m_pRecordset->MoveNext();///移到下一条记录
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行查询
|
||||||
|
int QuerySQLNoInputParam(char *SQL, int * outputColumn, int * outputValueCount, char **** outputValue)
|
||||||
|
{
|
||||||
|
return QuerySQL(SQL, 0, outputColumn, outputValueCount, outputValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行删除更新
|
||||||
|
int ExecuteSQLNoInputParam(char *SQL)
|
||||||
|
{
|
||||||
|
return ExecuteSQL(SQL, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ExecuteSQL(char *SQL, int valueCount, char **value)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_pConnection->Execute(_bstr_t(SQL), 0, adCmdText);
|
||||||
|
}
|
||||||
|
catch (_com_error e)
|
||||||
|
{
|
||||||
|
printf("插入失败\n");
|
||||||
|
printf(e.Description());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void close(void)
|
||||||
|
{
|
||||||
|
if (m_pRecordset != NULL) {
|
||||||
|
//m_pRecordset->MoveFirst();
|
||||||
|
m_pRecordset->Close();
|
||||||
|
m_pConnection->Close();
|
||||||
|
}
|
||||||
|
::CoUninitialize(); //释放环境
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
#import "C:/Program Files/Common Files/System/ado/msado15.dll" no_namespace rename("EOF", "adoEOF")
|
||||||
|
|
||||||
|
bool open(char* username, char* password, char* dbname, char* ip);
|
||||||
|
_RecordsetPtr& execute(_bstr_t SQL);
|
||||||
|
/**
|
||||||
|
* 带输入参数的查询SQL语句.
|
||||||
|
* @param SQL - <I> SQL语句
|
||||||
|
* @param inputValueCount - <I> 输入参数数量
|
||||||
|
* @param inputValue - <I> 输入参数值
|
||||||
|
* @param outputColumn - <O> 输出表的列的数量
|
||||||
|
* @param outputValueCount - <O> 输出表的行的数量
|
||||||
|
* @param outputValue - <O> 输出表内容
|
||||||
|
* @return - OCI_OK or error code
|
||||||
|
*
|
||||||
|
* ORACLE 数据库的连接与封装函数
|
||||||
|
*/
|
||||||
|
int QuerySQL(char *SQL, int inputValueCount, char ** inputValue, int * outputColumn, int * outputValueCount, char **** outputValue);
|
||||||
|
|
||||||
|
int QuerySQLNoInputParam(char *SQL, int * outputColumn, int * outputValueCount, char **** outputValue);
|
||||||
|
// 执行类操作
|
||||||
|
int ExecuteSQL(char *SQL, int valueCount, char **value);
|
||||||
|
/**
|
||||||
|
* 不带输入参数的执行SQL语句.
|
||||||
|
* @param SQL - <I> SQL语句
|
||||||
|
* @return - OCI_OK or error code
|
||||||
|
*
|
||||||
|
* ORACLE 数据库的连接与封装函数
|
||||||
|
*/
|
||||||
|
int ExecuteSQLNoInputParam(char *SQL);
|
||||||
|
/**
|
||||||
|
* 断开数据库连接.
|
||||||
|
*
|
||||||
|
* ORACLE 数据库的连接与封装函数
|
||||||
|
*/
|
||||||
|
void close();
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef JSON_AUTOLINK_H_INCLUDED
|
||||||
|
# define JSON_AUTOLINK_H_INCLUDED
|
||||||
|
|
||||||
|
# include "config.h"
|
||||||
|
|
||||||
|
# ifdef JSON_IN_CPPTL
|
||||||
|
# include <cpptl/cpptl_autolink.h>
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL)
|
||||||
|
# define CPPTL_AUTOLINK_NAME "json"
|
||||||
|
# undef CPPTL_AUTOLINK_DLL
|
||||||
|
# ifdef JSON_DLL
|
||||||
|
# define CPPTL_AUTOLINK_DLL
|
||||||
|
# endif
|
||||||
|
# include "autolink.h"
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#endif // JSON_AUTOLINK_H_INCLUDED
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
#ifndef JSON_CONFIG_H_INCLUDED
|
||||||
|
# define JSON_CONFIG_H_INCLUDED
|
||||||
|
|
||||||
|
/// If defined, indicates that json library is embedded in CppTL library.
|
||||||
|
//# define JSON_IN_CPPTL 1
|
||||||
|
|
||||||
|
/// If defined, indicates that json may leverage CppTL library
|
||||||
|
//# define JSON_USE_CPPTL 1
|
||||||
|
/// If defined, indicates that cpptl vector based map should be used instead of std::map
|
||||||
|
/// as Value container.
|
||||||
|
//# define JSON_USE_CPPTL_SMALLMAP 1
|
||||||
|
/// If defined, indicates that Json specific container should be used
|
||||||
|
/// (hash table & simple deque container with customizable allocator).
|
||||||
|
/// THIS FEATURE IS STILL EXPERIMENTAL!
|
||||||
|
//# define JSON_VALUE_USE_INTERNAL_MAP 1
|
||||||
|
/// Force usage of standard new/malloc based allocator instead of memory pool based allocator.
|
||||||
|
/// The memory pools allocator used optimization (initializing Value and ValueInternalLink
|
||||||
|
/// as if it was a POD) that may cause some validation tool to report errors.
|
||||||
|
/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined.
|
||||||
|
//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1
|
||||||
|
|
||||||
|
/// If defined, indicates that Json use exception to report invalid type manipulation
|
||||||
|
/// instead of C assert macro.
|
||||||
|
# define JSON_USE_EXCEPTION 1
|
||||||
|
|
||||||
|
# ifdef JSON_IN_CPPTL
|
||||||
|
# include <cpptl/config.h>
|
||||||
|
# ifndef JSON_USE_CPPTL
|
||||||
|
# define JSON_USE_CPPTL 1
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifdef JSON_IN_CPPTL
|
||||||
|
# define JSON_API CPPTL_API
|
||||||
|
# elif defined(JSON_DLL_BUILD)
|
||||||
|
# define JSON_API __declspec(dllexport)
|
||||||
|
# elif defined(JSON_DLL)
|
||||||
|
# define JSON_API __declspec(dllimport)
|
||||||
|
# else
|
||||||
|
# define JSON_API
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#endif // JSON_CONFIG_H_INCLUDED
|
||||||
@ -0,0 +1,170 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="源文件">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="头文件">
|
||||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="资源文件">
|
||||||
|
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||||
|
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="json">
|
||||||
|
<UniqueIdentifier>{5a9d0713-46ed-4d01-9976-96843444adb3}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="lib_json">
|
||||||
|
<UniqueIdentifier>{a3b918fb-f652-44f5-ade5-7d72f29a86e1}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Text Include="ReadMe.txt" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="kutil.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="ado.cxx">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="json_reader.cpp">
|
||||||
|
<Filter>lib_json</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="json_value.cpp">
|
||||||
|
<Filter>lib_json</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="json_writer.cpp">
|
||||||
|
<Filter>lib_json</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="raycus_itk.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Send_Sap_material.cpp.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Send_Sap_Bom.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="TEST.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="ocilib.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Connor_Review_Person.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="a.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Connor_allow_Workflow.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Connor_ElevateTask.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="LD_AutoAssign.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="addLb.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="LD_FormAttrToExcel.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="LD_PartCompFLAG.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="LD_PartChange.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="LD_SendDJJDD_To_MES.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="LD_ECN01_SetCICNFormProperty.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="UpgradeTask.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="LD_SendECRECN_ToSAPMES.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="LD_GYLXFrozen.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="SH_PLM_Email.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="LD_CompletionDate.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="LD_TaskAssignmentDate.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="handler.h">
|
||||||
|
<Filter>头文件</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="kutil.h">
|
||||||
|
<Filter>头文件</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="ado.h">
|
||||||
|
<Filter>头文件</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="autolink.h">
|
||||||
|
<Filter>json</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="config.h">
|
||||||
|
<Filter>json</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="features.h">
|
||||||
|
<Filter>json</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="forwards.h">
|
||||||
|
<Filter>json</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="json.h">
|
||||||
|
<Filter>json</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="reader.h">
|
||||||
|
<Filter>json</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="value.h">
|
||||||
|
<Filter>json</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="writer.h">
|
||||||
|
<Filter>json</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="json_batchallocator.h">
|
||||||
|
<Filter>lib_json</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="raycus_itk.h">
|
||||||
|
<Filter>头文件</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="CRUL_server_call_httpserver2.h">
|
||||||
|
<Filter>头文件</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="ocilib.h">
|
||||||
|
<Filter>头文件</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="json_internalarray.inl">
|
||||||
|
<Filter>lib_json</Filter>
|
||||||
|
</None>
|
||||||
|
<None Include="json_internalmap.inl">
|
||||||
|
<Filter>lib_json</Filter>
|
||||||
|
</None>
|
||||||
|
<None Include="json_valueiterator.inl">
|
||||||
|
<Filter>lib_json</Filter>
|
||||||
|
</None>
|
||||||
|
<None Include="sconscript">
|
||||||
|
<Filter>lib_json</Filter>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<ShowAllFiles>true</ShowAllFiles>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
|
||||||
|
# define CPPTL_JSON_FEATURES_H_INCLUDED
|
||||||
|
|
||||||
|
# include "forwards.h"
|
||||||
|
|
||||||
|
namespace Json {
|
||||||
|
|
||||||
|
/** \brief Configuration passed to reader and writer.
|
||||||
|
* This configuration object can be used to force the Reader or Writer
|
||||||
|
* to behave in a standard conforming way.
|
||||||
|
*/
|
||||||
|
class JSON_API Features
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** \brief A configuration that allows all features and assumes all strings are UTF-8.
|
||||||
|
* - C & C++ comments are allowed
|
||||||
|
* - Root object can be any JSON value
|
||||||
|
* - Assumes Value strings are encoded in UTF-8
|
||||||
|
*/
|
||||||
|
static Features all();
|
||||||
|
|
||||||
|
/** \brief A configuration that is strictly compatible with the JSON specification.
|
||||||
|
* - Comments are forbidden.
|
||||||
|
* - Root object must be either an array or an object value.
|
||||||
|
* - Assumes Value strings are encoded in UTF-8
|
||||||
|
*/
|
||||||
|
static Features strictMode();
|
||||||
|
|
||||||
|
/** \brief Initialize the configuration like JsonConfig::allFeatures;
|
||||||
|
*/
|
||||||
|
Features();
|
||||||
|
|
||||||
|
/// \c true if comments are allowed. Default: \c true.
|
||||||
|
bool allowComments_;
|
||||||
|
|
||||||
|
/// \c true if root must be either an array or an object value. Default: \c false.
|
||||||
|
bool strictRoot_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Json
|
||||||
|
|
||||||
|
#endif // CPPTL_JSON_FEATURES_H_INCLUDED
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
#ifndef JSON_FORWARDS_H_INCLUDED
|
||||||
|
# define JSON_FORWARDS_H_INCLUDED
|
||||||
|
|
||||||
|
# include "config.h"
|
||||||
|
|
||||||
|
namespace Json {
|
||||||
|
|
||||||
|
// writer.h
|
||||||
|
class FastWriter;
|
||||||
|
class StyledWriter;
|
||||||
|
|
||||||
|
// reader.h
|
||||||
|
class Reader;
|
||||||
|
|
||||||
|
// features.h
|
||||||
|
class Features;
|
||||||
|
|
||||||
|
// value.h
|
||||||
|
typedef int Int;
|
||||||
|
typedef unsigned int UInt;
|
||||||
|
class StaticString;
|
||||||
|
class Path;
|
||||||
|
class PathArgument;
|
||||||
|
class Value;
|
||||||
|
class ValueIteratorBase;
|
||||||
|
class ValueIterator;
|
||||||
|
class ValueConstIterator;
|
||||||
|
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
class ValueAllocator;
|
||||||
|
class ValueMapAllocator;
|
||||||
|
class ValueInternalLink;
|
||||||
|
class ValueInternalArray;
|
||||||
|
class ValueInternalMap;
|
||||||
|
#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
|
||||||
|
} // namespace Json
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JSON_FORWARDS_H_INCLUDED
|
||||||
@ -0,0 +1,110 @@
|
|||||||
|
#include "kutil.h"
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <ae\dataset.h>
|
||||||
|
#include <bom\bom.h>
|
||||||
|
#include <epm\signoff.h>
|
||||||
|
#include <fclasses/tc_date.h>
|
||||||
|
#include <form/form.h>
|
||||||
|
#include <map>
|
||||||
|
#include <list>
|
||||||
|
#include <ict\ict_userservice.h>
|
||||||
|
#include <qry/qry.h>
|
||||||
|
#include <sa/sa.h>
|
||||||
|
#include <sa\person.h>
|
||||||
|
#include <sa\user.h>
|
||||||
|
#include <sa\group.h>
|
||||||
|
#include <sa\role.h>
|
||||||
|
#include <schmgt/schmgt_bridge_itk.h>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <string.h>
|
||||||
|
#include <tccore\item.h>
|
||||||
|
#include <tc\folder.h>
|
||||||
|
#include <tc/preferences.h>
|
||||||
|
#include <tc/tc_arguments.h>
|
||||||
|
#include <tc/tc_startup.h>
|
||||||
|
#include <tccore\aom.h>
|
||||||
|
#include <tccore\aom_prop.h>
|
||||||
|
#include <tccore\grm.h>
|
||||||
|
#include <tccore\grmtype.h>
|
||||||
|
#include <tccore/tctype.h>
|
||||||
|
#include <tccore/releasestatus.h>
|
||||||
|
#include <tccore/workspaceobject.h>
|
||||||
|
#include <tccore\item_msg.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <user_exits\user_exit_msg.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <fstream>
|
||||||
|
#include <ae\ae.h>
|
||||||
|
#include "ocilib.h"
|
||||||
|
|
||||||
|
int ML_append_code(EPM_action_message_t msg);
|
||||||
|
int CONNOR_SIGN_MASTER(EPM_action_message_t msg);
|
||||||
|
int CONNOR_CLEAR_MASTER(EPM_action_message_t msg);
|
||||||
|
int CONNOR_REVISE_CLEAR_FORM(METHOD_message_t msg,va_list args);
|
||||||
|
int CONNOR_Signature_WORD(EPM_action_message_t msg);
|
||||||
|
int CONNOR_AVIC_CATIASIGN(EPM_action_message_t msg);
|
||||||
|
extern int K_add_release_status(void * return_data);
|
||||||
|
int CONNOR_SIGN_PRE_REVISION(EPM_action_message_t msg);
|
||||||
|
int QF8_WGJ_check(EPM_action_message_t msg);
|
||||||
|
int connor_set_prop_value(void *returnValue);
|
||||||
|
int ML_update_currentState(EPM_action_message_t msg);
|
||||||
|
int ML_WBS(EPM_action_message_t msg);
|
||||||
|
int ML_ProductCode(EPM_action_message_t msg);
|
||||||
|
int ML_nowtime(EPM_action_message_t msg);
|
||||||
|
int ML_sendToWeixin(EPM_action_message_t msg);
|
||||||
|
int ML_sendToPutinfo(EPM_action_message_t msg);
|
||||||
|
int ML_update_CChosenRevision(EPM_action_message_t msg);
|
||||||
|
int ML_sendByProposer(EPM_action_message_t msg);
|
||||||
|
int ML_sendChangeOrder(EPM_action_message_t msg);
|
||||||
|
int ML_createProjectForm(EPM_action_message_t msg);
|
||||||
|
int ML_handler266(EPM_action_message_t msg);
|
||||||
|
int ML_1106(EPM_action_message_t msg);
|
||||||
|
int ML_sendToQMS(EPM_action_message_t msg);
|
||||||
|
int ML_1128(EPM_action_message_t msg);
|
||||||
|
int ML_1207(EPM_action_message_t msg);
|
||||||
|
int ML_1214(EPM_action_message_t msg);
|
||||||
|
int ML_1215(EPM_action_message_t msg);
|
||||||
|
int ML_1216(EPM_action_message_t msg);
|
||||||
|
int ML_loginCheck(EPM_action_message_t msg);
|
||||||
|
int ML_1217(EPM_action_message_t msg);
|
||||||
|
int ML_checkState(EPM_action_message_t msg);
|
||||||
|
int ML_1227(EPM_action_message_t msg);
|
||||||
|
int ML_ItemRevPreUpdate(METHOD_message_t* msg, va_list args);
|
||||||
|
int ML_ChildGeneralIdentify(EPM_action_message_t msg);
|
||||||
|
int PLM_TO_OA(EPM_action_message_t msg);
|
||||||
|
int PLM_TO_SAP_NEW(EPM_action_message_t msg);
|
||||||
|
int PLM_TO_SAP_Revise(EPM_action_message_t msg);
|
||||||
|
int PLM_TO_SAP_Disuse(EPM_action_message_t msg);
|
||||||
|
int PLM_MBOM_TO_SAP_NEW(EPM_action_message_t msg);
|
||||||
|
int PLM_MBOM_TO_SAP_Revise(EPM_action_message_t msg);
|
||||||
|
int PLM_FBMBOM_TO_SAP(EPM_action_message_t msg);
|
||||||
|
int PLM_BZGX_TO_SAP(EPM_action_message_t msg);
|
||||||
|
int TEST(EPM_action_message_t msg);
|
||||||
|
int RK_getProjectData(void* returnValue);
|
||||||
|
int RK_getProjectAssignId(void* returnValue);
|
||||||
|
int RK_getProjectIdAndName(void* returnValue);
|
||||||
|
int Raycus_auto_TBYWL(EPM_action_message_t msg);
|
||||||
|
int RK_attach_assembly_components(EPM_action_message_t msg);
|
||||||
|
int RK_Assign_Inform(EPM_action_message_t msg);
|
||||||
|
int Connor_Review_Person(EPM_action_message_t msg);
|
||||||
|
int Connor_allow_Workflow(EPM_action_message_t msg);
|
||||||
|
int LD_FormAttrToExcel(EPM_action_message_t msg);
|
||||||
|
int LD_PartCompFLAG(EPM_action_message_t msg);
|
||||||
|
int LD_SendDJJDD_To_MES(EPM_action_message_t msg);
|
||||||
|
int UpgradeTask(EPM_action_message_t msg);
|
||||||
|
int LD_PartChange(EPM_action_message_t msg);
|
||||||
|
int ML_ItemRevSave(METHOD_message_t* msg, va_list args);
|
||||||
|
int LD_ElevateTask(EPM_action_message_t msg);
|
||||||
|
int LD_AutoAssign(EPM_action_message_t msg);
|
||||||
|
int reviseDesignPost(METHOD_message_t* msg, va_list va);
|
||||||
|
int uploadFile(void* returnValue);
|
||||||
|
int LD_ECN01_SetCICNFormProperty(EPM_action_message_t msg);
|
||||||
|
int LD_515_SetCICNFormProperty(EPM_action_message_t msg);
|
||||||
|
int LD_SendECRECN_ToSAPMES(EPM_action_message_t msg);
|
||||||
|
int LD_GYLXFrozen(EPM_action_message_t msg);
|
||||||
|
int LD_CompletionDate(EPM_action_message_t msg);
|
||||||
|
int LD_TaskAssignmentDate(EPM_action_message_t msg);
|
||||||
|
int SH_PLM_Email(EPM_action_message_t msg);
|
||||||
|
//int LD6_CusProdFolderSave(METHOD_message_t* msg, va_list args);
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef JSON_JSON_H_INCLUDED
|
||||||
|
# define JSON_JSON_H_INCLUDED
|
||||||
|
|
||||||
|
# include "autolink.h"
|
||||||
|
# include "value.h"
|
||||||
|
# include "reader.h"
|
||||||
|
# include "writer.h"
|
||||||
|
# include "features.h"
|
||||||
|
|
||||||
|
#endif // JSON_JSON_H_INCLUDED
|
||||||
@ -0,0 +1,125 @@
|
|||||||
|
#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
||||||
|
# define JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
||||||
|
|
||||||
|
# include <stdlib.h>
|
||||||
|
# include <assert.h>
|
||||||
|
|
||||||
|
# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
||||||
|
|
||||||
|
namespace Json {
|
||||||
|
|
||||||
|
/* Fast memory allocator.
|
||||||
|
*
|
||||||
|
* This memory allocator allocates memory for a batch of object (specified by
|
||||||
|
* the page size, the number of object in each page).
|
||||||
|
*
|
||||||
|
* It does not allow the destruction of a single object. All the allocated objects
|
||||||
|
* can be destroyed at once. The memory can be either released or reused for future
|
||||||
|
* allocation.
|
||||||
|
*
|
||||||
|
* The in-place new operator must be used to construct the object using the pointer
|
||||||
|
* returned by allocate.
|
||||||
|
*/
|
||||||
|
template<typename AllocatedType
|
||||||
|
,const unsigned int objectPerAllocation>
|
||||||
|
class BatchAllocator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef AllocatedType Type;
|
||||||
|
|
||||||
|
BatchAllocator( unsigned int objectsPerPage = 255 )
|
||||||
|
: freeHead_( 0 )
|
||||||
|
, objectsPerPage_( objectsPerPage )
|
||||||
|
{
|
||||||
|
// printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() );
|
||||||
|
assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space.
|
||||||
|
assert( objectsPerPage >= 16 );
|
||||||
|
batches_ = allocateBatch( 0 ); // allocated a dummy page
|
||||||
|
currentBatch_ = batches_;
|
||||||
|
}
|
||||||
|
|
||||||
|
~BatchAllocator()
|
||||||
|
{
|
||||||
|
for ( BatchInfo *batch = batches_; batch; )
|
||||||
|
{
|
||||||
|
BatchInfo *nextBatch = batch->next_;
|
||||||
|
free( batch );
|
||||||
|
batch = nextBatch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// allocate space for an array of objectPerAllocation object.
|
||||||
|
/// @warning it is the responsability of the caller to call objects constructors.
|
||||||
|
AllocatedType *allocate()
|
||||||
|
{
|
||||||
|
if ( freeHead_ ) // returns node from free list.
|
||||||
|
{
|
||||||
|
AllocatedType *object = freeHead_;
|
||||||
|
freeHead_ = *(AllocatedType **)object;
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
if ( currentBatch_->used_ == currentBatch_->end_ )
|
||||||
|
{
|
||||||
|
currentBatch_ = currentBatch_->next_;
|
||||||
|
while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ )
|
||||||
|
currentBatch_ = currentBatch_->next_;
|
||||||
|
|
||||||
|
if ( !currentBatch_ ) // no free batch found, allocate a new one
|
||||||
|
{
|
||||||
|
currentBatch_ = allocateBatch( objectsPerPage_ );
|
||||||
|
currentBatch_->next_ = batches_; // insert at the head of the list
|
||||||
|
batches_ = currentBatch_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AllocatedType *allocated = currentBatch_->used_;
|
||||||
|
currentBatch_->used_ += objectPerAllocation;
|
||||||
|
return allocated;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Release the object.
|
||||||
|
/// @warning it is the responsability of the caller to actually destruct the object.
|
||||||
|
void release( AllocatedType *object )
|
||||||
|
{
|
||||||
|
assert( object != 0 );
|
||||||
|
*(AllocatedType **)object = freeHead_;
|
||||||
|
freeHead_ = object;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct BatchInfo
|
||||||
|
{
|
||||||
|
BatchInfo *next_;
|
||||||
|
AllocatedType *used_;
|
||||||
|
AllocatedType *end_;
|
||||||
|
AllocatedType buffer_[objectPerAllocation];
|
||||||
|
};
|
||||||
|
|
||||||
|
// disabled copy constructor and assignement operator.
|
||||||
|
BatchAllocator( const BatchAllocator & );
|
||||||
|
void operator =( const BatchAllocator &);
|
||||||
|
|
||||||
|
static BatchInfo *allocateBatch( unsigned int objectsPerPage )
|
||||||
|
{
|
||||||
|
const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation
|
||||||
|
+ sizeof(AllocatedType) * objectPerAllocation * objectsPerPage;
|
||||||
|
BatchInfo *batch = static_cast<BatchInfo*>( malloc( mallocSize ) );
|
||||||
|
batch->next_ = 0;
|
||||||
|
batch->used_ = batch->buffer_;
|
||||||
|
batch->end_ = batch->buffer_ + objectsPerPage;
|
||||||
|
return batch;
|
||||||
|
}
|
||||||
|
|
||||||
|
BatchInfo *batches_;
|
||||||
|
BatchInfo *currentBatch_;
|
||||||
|
/// Head of a single linked list within the allocated space of freeed object
|
||||||
|
AllocatedType *freeHead_;
|
||||||
|
unsigned int objectsPerPage_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Json
|
||||||
|
|
||||||
|
# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION
|
||||||
|
|
||||||
|
#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
||||||
|
|
||||||
@ -0,0 +1,448 @@
|
|||||||
|
// included by json_value.cpp
|
||||||
|
// everything is within Json namespace
|
||||||
|
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// class ValueInternalArray
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ValueArrayAllocator::~ValueArrayAllocator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// class DefaultValueArrayAllocator
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
||||||
|
class DefaultValueArrayAllocator : public ValueArrayAllocator
|
||||||
|
{
|
||||||
|
public: // overridden from ValueArrayAllocator
|
||||||
|
virtual ~DefaultValueArrayAllocator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ValueInternalArray *newArray()
|
||||||
|
{
|
||||||
|
return new ValueInternalArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
|
||||||
|
{
|
||||||
|
return new ValueInternalArray( other );
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void destructArray( ValueInternalArray *array )
|
||||||
|
{
|
||||||
|
delete array;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void reallocateArrayPageIndex( Value **&indexes,
|
||||||
|
ValueInternalArray::PageIndex &indexCount,
|
||||||
|
ValueInternalArray::PageIndex minNewIndexCount )
|
||||||
|
{
|
||||||
|
ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
|
||||||
|
if ( minNewIndexCount > newIndexCount )
|
||||||
|
newIndexCount = minNewIndexCount;
|
||||||
|
void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
|
||||||
|
if ( !newIndexes )
|
||||||
|
throw std::bad_alloc();
|
||||||
|
indexCount = newIndexCount;
|
||||||
|
indexes = static_cast<Value **>( newIndexes );
|
||||||
|
}
|
||||||
|
virtual void releaseArrayPageIndex( Value **indexes,
|
||||||
|
ValueInternalArray::PageIndex indexCount )
|
||||||
|
{
|
||||||
|
if ( indexes )
|
||||||
|
free( indexes );
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Value *allocateArrayPage()
|
||||||
|
{
|
||||||
|
return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void releaseArrayPage( Value *value )
|
||||||
|
{
|
||||||
|
if ( value )
|
||||||
|
free( value );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
||||||
|
/// @todo make this thread-safe (lock when accessign batch allocator)
|
||||||
|
class DefaultValueArrayAllocator : public ValueArrayAllocator
|
||||||
|
{
|
||||||
|
public: // overridden from ValueArrayAllocator
|
||||||
|
virtual ~DefaultValueArrayAllocator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ValueInternalArray *newArray()
|
||||||
|
{
|
||||||
|
ValueInternalArray *array = arraysAllocator_.allocate();
|
||||||
|
new (array) ValueInternalArray(); // placement new
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
|
||||||
|
{
|
||||||
|
ValueInternalArray *array = arraysAllocator_.allocate();
|
||||||
|
new (array) ValueInternalArray( other ); // placement new
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void destructArray( ValueInternalArray *array )
|
||||||
|
{
|
||||||
|
if ( array )
|
||||||
|
{
|
||||||
|
array->~ValueInternalArray();
|
||||||
|
arraysAllocator_.release( array );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void reallocateArrayPageIndex( Value **&indexes,
|
||||||
|
ValueInternalArray::PageIndex &indexCount,
|
||||||
|
ValueInternalArray::PageIndex minNewIndexCount )
|
||||||
|
{
|
||||||
|
ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
|
||||||
|
if ( minNewIndexCount > newIndexCount )
|
||||||
|
newIndexCount = minNewIndexCount;
|
||||||
|
void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
|
||||||
|
if ( !newIndexes )
|
||||||
|
throw std::bad_alloc();
|
||||||
|
indexCount = newIndexCount;
|
||||||
|
indexes = static_cast<Value **>( newIndexes );
|
||||||
|
}
|
||||||
|
virtual void releaseArrayPageIndex( Value **indexes,
|
||||||
|
ValueInternalArray::PageIndex indexCount )
|
||||||
|
{
|
||||||
|
if ( indexes )
|
||||||
|
free( indexes );
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Value *allocateArrayPage()
|
||||||
|
{
|
||||||
|
return static_cast<Value *>( pagesAllocator_.allocate() );
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void releaseArrayPage( Value *value )
|
||||||
|
{
|
||||||
|
if ( value )
|
||||||
|
pagesAllocator_.release( value );
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
BatchAllocator<ValueInternalArray,1> arraysAllocator_;
|
||||||
|
BatchAllocator<Value,ValueInternalArray::itemsPerPage> pagesAllocator_;
|
||||||
|
};
|
||||||
|
#endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
||||||
|
|
||||||
|
static ValueArrayAllocator *&arrayAllocator()
|
||||||
|
{
|
||||||
|
static DefaultValueArrayAllocator defaultAllocator;
|
||||||
|
static ValueArrayAllocator *arrayAllocator = &defaultAllocator;
|
||||||
|
return arrayAllocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct DummyArrayAllocatorInitializer {
|
||||||
|
DummyArrayAllocatorInitializer()
|
||||||
|
{
|
||||||
|
arrayAllocator(); // ensure arrayAllocator() statics are initialized before main().
|
||||||
|
}
|
||||||
|
} dummyArrayAllocatorInitializer;
|
||||||
|
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// class ValueInternalArray
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
bool
|
||||||
|
ValueInternalArray::equals( const IteratorState &x,
|
||||||
|
const IteratorState &other )
|
||||||
|
{
|
||||||
|
return x.array_ == other.array_
|
||||||
|
&& x.currentItemIndex_ == other.currentItemIndex_
|
||||||
|
&& x.currentPageIndex_ == other.currentPageIndex_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ValueInternalArray::increment( IteratorState &it )
|
||||||
|
{
|
||||||
|
JSON_ASSERT_MESSAGE( it.array_ &&
|
||||||
|
(it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
|
||||||
|
!= it.array_->size_,
|
||||||
|
"ValueInternalArray::increment(): moving iterator beyond end" );
|
||||||
|
++(it.currentItemIndex_);
|
||||||
|
if ( it.currentItemIndex_ == itemsPerPage )
|
||||||
|
{
|
||||||
|
it.currentItemIndex_ = 0;
|
||||||
|
++(it.currentPageIndex_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ValueInternalArray::decrement( IteratorState &it )
|
||||||
|
{
|
||||||
|
JSON_ASSERT_MESSAGE( it.array_ && it.currentPageIndex_ == it.array_->pages_
|
||||||
|
&& it.currentItemIndex_ == 0,
|
||||||
|
"ValueInternalArray::decrement(): moving iterator beyond end" );
|
||||||
|
if ( it.currentItemIndex_ == 0 )
|
||||||
|
{
|
||||||
|
it.currentItemIndex_ = itemsPerPage-1;
|
||||||
|
--(it.currentPageIndex_);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
--(it.currentItemIndex_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Value &
|
||||||
|
ValueInternalArray::unsafeDereference( const IteratorState &it )
|
||||||
|
{
|
||||||
|
return (*(it.currentPageIndex_))[it.currentItemIndex_];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Value &
|
||||||
|
ValueInternalArray::dereference( const IteratorState &it )
|
||||||
|
{
|
||||||
|
JSON_ASSERT_MESSAGE( it.array_ &&
|
||||||
|
(it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
|
||||||
|
< it.array_->size_,
|
||||||
|
"ValueInternalArray::dereference(): dereferencing invalid iterator" );
|
||||||
|
return unsafeDereference( it );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ValueInternalArray::makeBeginIterator( IteratorState &it ) const
|
||||||
|
{
|
||||||
|
it.array_ = const_cast<ValueInternalArray *>( this );
|
||||||
|
it.currentItemIndex_ = 0;
|
||||||
|
it.currentPageIndex_ = pages_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ValueInternalArray::makeIterator( IteratorState &it, ArrayIndex index ) const
|
||||||
|
{
|
||||||
|
it.array_ = const_cast<ValueInternalArray *>( this );
|
||||||
|
it.currentItemIndex_ = index % itemsPerPage;
|
||||||
|
it.currentPageIndex_ = pages_ + index / itemsPerPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ValueInternalArray::makeEndIterator( IteratorState &it ) const
|
||||||
|
{
|
||||||
|
makeIterator( it, size_ );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ValueInternalArray::ValueInternalArray()
|
||||||
|
: pages_( 0 )
|
||||||
|
, size_( 0 )
|
||||||
|
, pageCount_( 0 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ValueInternalArray::ValueInternalArray( const ValueInternalArray &other )
|
||||||
|
: pages_( 0 )
|
||||||
|
, pageCount_( 0 )
|
||||||
|
, size_( other.size_ )
|
||||||
|
{
|
||||||
|
PageIndex minNewPages = other.size_ / itemsPerPage;
|
||||||
|
arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages );
|
||||||
|
JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages,
|
||||||
|
"ValueInternalArray::reserve(): bad reallocation" );
|
||||||
|
IteratorState itOther;
|
||||||
|
other.makeBeginIterator( itOther );
|
||||||
|
Value *value;
|
||||||
|
for ( ArrayIndex index = 0; index < size_; ++index, increment(itOther) )
|
||||||
|
{
|
||||||
|
if ( index % itemsPerPage == 0 )
|
||||||
|
{
|
||||||
|
PageIndex pageIndex = index / itemsPerPage;
|
||||||
|
value = arrayAllocator()->allocateArrayPage();
|
||||||
|
pages_[pageIndex] = value;
|
||||||
|
}
|
||||||
|
new (value) Value( dereference( itOther ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ValueInternalArray &
|
||||||
|
ValueInternalArray::operator =( const ValueInternalArray &other )
|
||||||
|
{
|
||||||
|
ValueInternalArray temp( other );
|
||||||
|
swap( temp );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ValueInternalArray::~ValueInternalArray()
|
||||||
|
{
|
||||||
|
// destroy all constructed items
|
||||||
|
IteratorState it;
|
||||||
|
IteratorState itEnd;
|
||||||
|
makeBeginIterator( it);
|
||||||
|
makeEndIterator( itEnd );
|
||||||
|
for ( ; !equals(it,itEnd); increment(it) )
|
||||||
|
{
|
||||||
|
Value *value = &dereference(it);
|
||||||
|
value->~Value();
|
||||||
|
}
|
||||||
|
// release all pages
|
||||||
|
PageIndex lastPageIndex = size_ / itemsPerPage;
|
||||||
|
for ( PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex )
|
||||||
|
arrayAllocator()->releaseArrayPage( pages_[pageIndex] );
|
||||||
|
// release pages index
|
||||||
|
arrayAllocator()->releaseArrayPageIndex( pages_, pageCount_ );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ValueInternalArray::swap( ValueInternalArray &other )
|
||||||
|
{
|
||||||
|
Value **tempPages = pages_;
|
||||||
|
pages_ = other.pages_;
|
||||||
|
other.pages_ = tempPages;
|
||||||
|
ArrayIndex tempSize = size_;
|
||||||
|
size_ = other.size_;
|
||||||
|
other.size_ = tempSize;
|
||||||
|
PageIndex tempPageCount = pageCount_;
|
||||||
|
pageCount_ = other.pageCount_;
|
||||||
|
other.pageCount_ = tempPageCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ValueInternalArray::clear()
|
||||||
|
{
|
||||||
|
ValueInternalArray dummy;
|
||||||
|
swap( dummy );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ValueInternalArray::resize( ArrayIndex newSize )
|
||||||
|
{
|
||||||
|
if ( newSize == 0 )
|
||||||
|
clear();
|
||||||
|
else if ( newSize < size_ )
|
||||||
|
{
|
||||||
|
IteratorState it;
|
||||||
|
IteratorState itEnd;
|
||||||
|
makeIterator( it, newSize );
|
||||||
|
makeIterator( itEnd, size_ );
|
||||||
|
for ( ; !equals(it,itEnd); increment(it) )
|
||||||
|
{
|
||||||
|
Value *value = &dereference(it);
|
||||||
|
value->~Value();
|
||||||
|
}
|
||||||
|
PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage;
|
||||||
|
PageIndex lastPageIndex = size_ / itemsPerPage;
|
||||||
|
for ( ; pageIndex < lastPageIndex; ++pageIndex )
|
||||||
|
arrayAllocator()->releaseArrayPage( pages_[pageIndex] );
|
||||||
|
size_ = newSize;
|
||||||
|
}
|
||||||
|
else if ( newSize > size_ )
|
||||||
|
resolveReference( newSize );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ValueInternalArray::makeIndexValid( ArrayIndex index )
|
||||||
|
{
|
||||||
|
// Need to enlarge page index ?
|
||||||
|
if ( index >= pageCount_ * itemsPerPage )
|
||||||
|
{
|
||||||
|
PageIndex minNewPages = (index + 1) / itemsPerPage;
|
||||||
|
arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages );
|
||||||
|
JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, "ValueInternalArray::reserve(): bad reallocation" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to allocate new pages ?
|
||||||
|
ArrayIndex nextPageIndex =
|
||||||
|
(size_ % itemsPerPage) != 0 ? size_ - (size_%itemsPerPage) + itemsPerPage
|
||||||
|
: size_;
|
||||||
|
if ( nextPageIndex <= index )
|
||||||
|
{
|
||||||
|
PageIndex pageIndex = nextPageIndex / itemsPerPage;
|
||||||
|
PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1;
|
||||||
|
for ( ; pageToAllocate-- > 0; ++pageIndex )
|
||||||
|
pages_[pageIndex] = arrayAllocator()->allocateArrayPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize all new entries
|
||||||
|
IteratorState it;
|
||||||
|
IteratorState itEnd;
|
||||||
|
makeIterator( it, size_ );
|
||||||
|
size_ = index + 1;
|
||||||
|
makeIterator( itEnd, size_ );
|
||||||
|
for ( ; !equals(it,itEnd); increment(it) )
|
||||||
|
{
|
||||||
|
Value *value = &dereference(it);
|
||||||
|
new (value) Value(); // Construct a default value using placement new
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Value &
|
||||||
|
ValueInternalArray::resolveReference( ArrayIndex index )
|
||||||
|
{
|
||||||
|
if ( index >= size_ )
|
||||||
|
makeIndexValid( index );
|
||||||
|
return pages_[index/itemsPerPage][index%itemsPerPage];
|
||||||
|
}
|
||||||
|
|
||||||
|
Value *
|
||||||
|
ValueInternalArray::find( ArrayIndex index ) const
|
||||||
|
{
|
||||||
|
if ( index >= size_ )
|
||||||
|
return 0;
|
||||||
|
return &(pages_[index/itemsPerPage][index%itemsPerPage]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueInternalArray::ArrayIndex
|
||||||
|
ValueInternalArray::size() const
|
||||||
|
{
|
||||||
|
return size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ValueInternalArray::distance( const IteratorState &x, const IteratorState &y )
|
||||||
|
{
|
||||||
|
return indexOf(y) - indexOf(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ValueInternalArray::ArrayIndex
|
||||||
|
ValueInternalArray::indexOf( const IteratorState &iterator )
|
||||||
|
{
|
||||||
|
if ( !iterator.array_ )
|
||||||
|
return ArrayIndex(-1);
|
||||||
|
return ArrayIndex(
|
||||||
|
(iterator.currentPageIndex_ - iterator.array_->pages_) * itemsPerPage
|
||||||
|
+ iterator.currentItemIndex_ );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ValueInternalArray::compare( const ValueInternalArray &other ) const
|
||||||
|
{
|
||||||
|
int sizeDiff( size_ - other.size_ );
|
||||||
|
if ( sizeDiff != 0 )
|
||||||
|
return sizeDiff;
|
||||||
|
|
||||||
|
for ( ArrayIndex index =0; index < size_; ++index )
|
||||||
|
{
|
||||||
|
int diff = pages_[index/itemsPerPage][index%itemsPerPage].compare(
|
||||||
|
other.pages_[index/itemsPerPage][index%itemsPerPage] );
|
||||||
|
if ( diff != 0 )
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@ -0,0 +1,607 @@
|
|||||||
|
// included by json_value.cpp
|
||||||
|
// everything is within Json namespace
|
||||||
|
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// class ValueInternalMap
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/** \internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) );
|
||||||
|
* This optimization is used by the fast allocator.
|
||||||
|
*/
|
||||||
|
ValueInternalLink::ValueInternalLink()
|
||||||
|
: previous_( 0 )
|
||||||
|
, next_( 0 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueInternalLink::~ValueInternalLink()
|
||||||
|
{
|
||||||
|
for ( int index =0; index < itemPerLink; ++index )
|
||||||
|
{
|
||||||
|
if ( !items_[index].isItemAvailable() )
|
||||||
|
{
|
||||||
|
if ( !items_[index].isMemberNameStatic() )
|
||||||
|
free( keys_[index] );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ValueMapAllocator::~ValueMapAllocator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
||||||
|
class DefaultValueMapAllocator : public ValueMapAllocator
|
||||||
|
{
|
||||||
|
public: // overridden from ValueMapAllocator
|
||||||
|
virtual ValueInternalMap *newMap()
|
||||||
|
{
|
||||||
|
return new ValueInternalMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
|
||||||
|
{
|
||||||
|
return new ValueInternalMap( other );
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void destructMap( ValueInternalMap *map )
|
||||||
|
{
|
||||||
|
delete map;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
|
||||||
|
{
|
||||||
|
return new ValueInternalLink[size];
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void releaseMapBuckets( ValueInternalLink *links )
|
||||||
|
{
|
||||||
|
delete [] links;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ValueInternalLink *allocateMapLink()
|
||||||
|
{
|
||||||
|
return new ValueInternalLink();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void releaseMapLink( ValueInternalLink *link )
|
||||||
|
{
|
||||||
|
delete link;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
/// @todo make this thread-safe (lock when accessign batch allocator)
|
||||||
|
class DefaultValueMapAllocator : public ValueMapAllocator
|
||||||
|
{
|
||||||
|
public: // overridden from ValueMapAllocator
|
||||||
|
virtual ValueInternalMap *newMap()
|
||||||
|
{
|
||||||
|
ValueInternalMap *map = mapsAllocator_.allocate();
|
||||||
|
new (map) ValueInternalMap(); // placement new
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
|
||||||
|
{
|
||||||
|
ValueInternalMap *map = mapsAllocator_.allocate();
|
||||||
|
new (map) ValueInternalMap( other ); // placement new
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void destructMap( ValueInternalMap *map )
|
||||||
|
{
|
||||||
|
if ( map )
|
||||||
|
{
|
||||||
|
map->~ValueInternalMap();
|
||||||
|
mapsAllocator_.release( map );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
|
||||||
|
{
|
||||||
|
return new ValueInternalLink[size];
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void releaseMapBuckets( ValueInternalLink *links )
|
||||||
|
{
|
||||||
|
delete [] links;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ValueInternalLink *allocateMapLink()
|
||||||
|
{
|
||||||
|
ValueInternalLink *link = linksAllocator_.allocate();
|
||||||
|
memset( link, 0, sizeof(ValueInternalLink) );
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void releaseMapLink( ValueInternalLink *link )
|
||||||
|
{
|
||||||
|
link->~ValueInternalLink();
|
||||||
|
linksAllocator_.release( link );
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
BatchAllocator<ValueInternalMap,1> mapsAllocator_;
|
||||||
|
BatchAllocator<ValueInternalLink,1> linksAllocator_;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static ValueMapAllocator *&mapAllocator()
|
||||||
|
{
|
||||||
|
static DefaultValueMapAllocator defaultAllocator;
|
||||||
|
static ValueMapAllocator *mapAllocator = &defaultAllocator;
|
||||||
|
return mapAllocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct DummyMapAllocatorInitializer {
|
||||||
|
DummyMapAllocatorInitializer()
|
||||||
|
{
|
||||||
|
mapAllocator(); // ensure mapAllocator() statics are initialized before main().
|
||||||
|
}
|
||||||
|
} dummyMapAllocatorInitializer;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32.
|
||||||
|
|
||||||
|
/*
|
||||||
|
use linked list hash map.
|
||||||
|
buckets array is a container.
|
||||||
|
linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124)
|
||||||
|
value have extra state: valid, available, deleted
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
ValueInternalMap::ValueInternalMap()
|
||||||
|
: buckets_( 0 )
|
||||||
|
, tailLink_( 0 )
|
||||||
|
, bucketsSize_( 0 )
|
||||||
|
, itemCount_( 0 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ValueInternalMap::ValueInternalMap( const ValueInternalMap &other )
|
||||||
|
: buckets_( 0 )
|
||||||
|
, tailLink_( 0 )
|
||||||
|
, bucketsSize_( 0 )
|
||||||
|
, itemCount_( 0 )
|
||||||
|
{
|
||||||
|
reserve( other.itemCount_ );
|
||||||
|
IteratorState it;
|
||||||
|
IteratorState itEnd;
|
||||||
|
other.makeBeginIterator( it );
|
||||||
|
other.makeEndIterator( itEnd );
|
||||||
|
for ( ; !equals(it,itEnd); increment(it) )
|
||||||
|
{
|
||||||
|
bool isStatic;
|
||||||
|
const char *memberName = key( it, isStatic );
|
||||||
|
const Value &aValue = value( it );
|
||||||
|
resolveReference(memberName, isStatic) = aValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ValueInternalMap &
|
||||||
|
ValueInternalMap::operator =( const ValueInternalMap &other )
|
||||||
|
{
|
||||||
|
ValueInternalMap dummy( other );
|
||||||
|
swap( dummy );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ValueInternalMap::~ValueInternalMap()
|
||||||
|
{
|
||||||
|
if ( buckets_ )
|
||||||
|
{
|
||||||
|
for ( BucketIndex bucketIndex =0; bucketIndex < bucketsSize_; ++bucketIndex )
|
||||||
|
{
|
||||||
|
ValueInternalLink *link = buckets_[bucketIndex].next_;
|
||||||
|
while ( link )
|
||||||
|
{
|
||||||
|
ValueInternalLink *linkToRelease = link;
|
||||||
|
link = link->next_;
|
||||||
|
mapAllocator()->releaseMapLink( linkToRelease );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mapAllocator()->releaseMapBuckets( buckets_ );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ValueInternalMap::swap( ValueInternalMap &other )
|
||||||
|
{
|
||||||
|
ValueInternalLink *tempBuckets = buckets_;
|
||||||
|
buckets_ = other.buckets_;
|
||||||
|
other.buckets_ = tempBuckets;
|
||||||
|
ValueInternalLink *tempTailLink = tailLink_;
|
||||||
|
tailLink_ = other.tailLink_;
|
||||||
|
other.tailLink_ = tempTailLink;
|
||||||
|
BucketIndex tempBucketsSize = bucketsSize_;
|
||||||
|
bucketsSize_ = other.bucketsSize_;
|
||||||
|
other.bucketsSize_ = tempBucketsSize;
|
||||||
|
BucketIndex tempItemCount = itemCount_;
|
||||||
|
itemCount_ = other.itemCount_;
|
||||||
|
other.itemCount_ = tempItemCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ValueInternalMap::clear()
|
||||||
|
{
|
||||||
|
ValueInternalMap dummy;
|
||||||
|
swap( dummy );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ValueInternalMap::BucketIndex
|
||||||
|
ValueInternalMap::size() const
|
||||||
|
{
|
||||||
|
return itemCount_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ValueInternalMap::reserveDelta( BucketIndex growth )
|
||||||
|
{
|
||||||
|
return reserve( itemCount_ + growth );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ValueInternalMap::reserve( BucketIndex newItemCount )
|
||||||
|
{
|
||||||
|
if ( !buckets_ && newItemCount > 0 )
|
||||||
|
{
|
||||||
|
buckets_ = mapAllocator()->allocateMapBuckets( 1 );
|
||||||
|
bucketsSize_ = 1;
|
||||||
|
tailLink_ = &buckets_[0];
|
||||||
|
}
|
||||||
|
// BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const Value *
|
||||||
|
ValueInternalMap::find( const char *key ) const
|
||||||
|
{
|
||||||
|
if ( !bucketsSize_ )
|
||||||
|
return 0;
|
||||||
|
HashKey hashedKey = hash( key );
|
||||||
|
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
||||||
|
for ( const ValueInternalLink *current = &buckets_[bucketIndex];
|
||||||
|
current != 0;
|
||||||
|
current = current->next_ )
|
||||||
|
{
|
||||||
|
for ( BucketIndex index=0; index < ValueInternalLink::itemPerLink; ++index )
|
||||||
|
{
|
||||||
|
if ( current->items_[index].isItemAvailable() )
|
||||||
|
return 0;
|
||||||
|
if ( strcmp( key, current->keys_[index] ) == 0 )
|
||||||
|
return ¤t->items_[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Value *
|
||||||
|
ValueInternalMap::find( const char *key )
|
||||||
|
{
|
||||||
|
const ValueInternalMap *constThis = this;
|
||||||
|
return const_cast<Value *>( constThis->find( key ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Value &
|
||||||
|
ValueInternalMap::resolveReference( const char *key,
|
||||||
|
bool isStatic )
|
||||||
|
{
|
||||||
|
HashKey hashedKey = hash( key );
|
||||||
|
if ( bucketsSize_ )
|
||||||
|
{
|
||||||
|
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
||||||
|
ValueInternalLink **previous = 0;
|
||||||
|
BucketIndex index;
|
||||||
|
for ( ValueInternalLink *current = &buckets_[bucketIndex];
|
||||||
|
current != 0;
|
||||||
|
previous = ¤t->next_, current = current->next_ )
|
||||||
|
{
|
||||||
|
for ( index=0; index < ValueInternalLink::itemPerLink; ++index )
|
||||||
|
{
|
||||||
|
if ( current->items_[index].isItemAvailable() )
|
||||||
|
return setNewItem( key, isStatic, current, index );
|
||||||
|
if ( strcmp( key, current->keys_[index] ) == 0 )
|
||||||
|
return current->items_[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reserveDelta( 1 );
|
||||||
|
return unsafeAdd( key, isStatic, hashedKey );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ValueInternalMap::remove( const char *key )
|
||||||
|
{
|
||||||
|
HashKey hashedKey = hash( key );
|
||||||
|
if ( !bucketsSize_ )
|
||||||
|
return;
|
||||||
|
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
||||||
|
for ( ValueInternalLink *link = &buckets_[bucketIndex];
|
||||||
|
link != 0;
|
||||||
|
link = link->next_ )
|
||||||
|
{
|
||||||
|
BucketIndex index;
|
||||||
|
for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
|
||||||
|
{
|
||||||
|
if ( link->items_[index].isItemAvailable() )
|
||||||
|
return;
|
||||||
|
if ( strcmp( key, link->keys_[index] ) == 0 )
|
||||||
|
{
|
||||||
|
doActualRemove( link, index, bucketIndex );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ValueInternalMap::doActualRemove( ValueInternalLink *link,
|
||||||
|
BucketIndex index,
|
||||||
|
BucketIndex bucketIndex )
|
||||||
|
{
|
||||||
|
// find last item of the bucket and swap it with the 'removed' one.
|
||||||
|
// set removed items flags to 'available'.
|
||||||
|
// if last page only contains 'available' items, then desallocate it (it's empty)
|
||||||
|
ValueInternalLink *&lastLink = getLastLinkInBucket( index );
|
||||||
|
BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1
|
||||||
|
for ( ;
|
||||||
|
lastItemIndex < ValueInternalLink::itemPerLink;
|
||||||
|
++lastItemIndex ) // may be optimized with dicotomic search
|
||||||
|
{
|
||||||
|
if ( lastLink->items_[lastItemIndex].isItemAvailable() )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
BucketIndex lastUsedIndex = lastItemIndex - 1;
|
||||||
|
Value *valueToDelete = &link->items_[index];
|
||||||
|
Value *valueToPreserve = &lastLink->items_[lastUsedIndex];
|
||||||
|
if ( valueToDelete != valueToPreserve )
|
||||||
|
valueToDelete->swap( *valueToPreserve );
|
||||||
|
if ( lastUsedIndex == 0 ) // page is now empty
|
||||||
|
{ // remove it from bucket linked list and delete it.
|
||||||
|
ValueInternalLink *linkPreviousToLast = lastLink->previous_;
|
||||||
|
if ( linkPreviousToLast != 0 ) // can not deleted bucket link.
|
||||||
|
{
|
||||||
|
mapAllocator()->releaseMapLink( lastLink );
|
||||||
|
linkPreviousToLast->next_ = 0;
|
||||||
|
lastLink = linkPreviousToLast;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Value dummy;
|
||||||
|
valueToPreserve->swap( dummy ); // restore deleted to default Value.
|
||||||
|
valueToPreserve->setItemUsed( false );
|
||||||
|
}
|
||||||
|
--itemCount_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ValueInternalLink *&
|
||||||
|
ValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex )
|
||||||
|
{
|
||||||
|
if ( bucketIndex == bucketsSize_ - 1 )
|
||||||
|
return tailLink_;
|
||||||
|
ValueInternalLink *&previous = buckets_[bucketIndex+1].previous_;
|
||||||
|
if ( !previous )
|
||||||
|
previous = &buckets_[bucketIndex];
|
||||||
|
return previous;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Value &
|
||||||
|
ValueInternalMap::setNewItem( const char *key,
|
||||||
|
bool isStatic,
|
||||||
|
ValueInternalLink *link,
|
||||||
|
BucketIndex index )
|
||||||
|
{
|
||||||
|
char *duplicatedKey = valueAllocator()->makeMemberName( key );
|
||||||
|
++itemCount_;
|
||||||
|
link->keys_[index] = duplicatedKey;
|
||||||
|
link->items_[index].setItemUsed();
|
||||||
|
link->items_[index].setMemberNameIsStatic( isStatic );
|
||||||
|
return link->items_[index]; // items already default constructed.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Value &
|
||||||
|
ValueInternalMap::unsafeAdd( const char *key,
|
||||||
|
bool isStatic,
|
||||||
|
HashKey hashedKey )
|
||||||
|
{
|
||||||
|
JSON_ASSERT_MESSAGE( bucketsSize_ > 0, "ValueInternalMap::unsafeAdd(): internal logic error." );
|
||||||
|
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
||||||
|
ValueInternalLink *&previousLink = getLastLinkInBucket( bucketIndex );
|
||||||
|
ValueInternalLink *link = previousLink;
|
||||||
|
BucketIndex index;
|
||||||
|
for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
|
||||||
|
{
|
||||||
|
if ( link->items_[index].isItemAvailable() )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ( index == ValueInternalLink::itemPerLink ) // need to add a new page
|
||||||
|
{
|
||||||
|
ValueInternalLink *newLink = mapAllocator()->allocateMapLink();
|
||||||
|
index = 0;
|
||||||
|
link->next_ = newLink;
|
||||||
|
previousLink = newLink;
|
||||||
|
link = newLink;
|
||||||
|
}
|
||||||
|
return setNewItem( key, isStatic, link, index );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ValueInternalMap::HashKey
|
||||||
|
ValueInternalMap::hash( const char *key ) const
|
||||||
|
{
|
||||||
|
HashKey hash = 0;
|
||||||
|
while ( *key )
|
||||||
|
hash += *key++ * 37;
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ValueInternalMap::compare( const ValueInternalMap &other ) const
|
||||||
|
{
|
||||||
|
int sizeDiff( itemCount_ - other.itemCount_ );
|
||||||
|
if ( sizeDiff != 0 )
|
||||||
|
return sizeDiff;
|
||||||
|
// Strict order guaranty is required. Compare all keys FIRST, then compare values.
|
||||||
|
IteratorState it;
|
||||||
|
IteratorState itEnd;
|
||||||
|
makeBeginIterator( it );
|
||||||
|
makeEndIterator( itEnd );
|
||||||
|
for ( ; !equals(it,itEnd); increment(it) )
|
||||||
|
{
|
||||||
|
if ( !other.find( key( it ) ) )
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All keys are equals, let's compare values
|
||||||
|
makeBeginIterator( it );
|
||||||
|
for ( ; !equals(it,itEnd); increment(it) )
|
||||||
|
{
|
||||||
|
const Value *otherValue = other.find( key( it ) );
|
||||||
|
int valueDiff = value(it).compare( *otherValue );
|
||||||
|
if ( valueDiff != 0 )
|
||||||
|
return valueDiff;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ValueInternalMap::makeBeginIterator( IteratorState &it ) const
|
||||||
|
{
|
||||||
|
it.map_ = const_cast<ValueInternalMap *>( this );
|
||||||
|
it.bucketIndex_ = 0;
|
||||||
|
it.itemIndex_ = 0;
|
||||||
|
it.link_ = buckets_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ValueInternalMap::makeEndIterator( IteratorState &it ) const
|
||||||
|
{
|
||||||
|
it.map_ = const_cast<ValueInternalMap *>( this );
|
||||||
|
it.bucketIndex_ = bucketsSize_;
|
||||||
|
it.itemIndex_ = 0;
|
||||||
|
it.link_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
ValueInternalMap::equals( const IteratorState &x, const IteratorState &other )
|
||||||
|
{
|
||||||
|
return x.map_ == other.map_
|
||||||
|
&& x.bucketIndex_ == other.bucketIndex_
|
||||||
|
&& x.link_ == other.link_
|
||||||
|
&& x.itemIndex_ == other.itemIndex_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ValueInternalMap::incrementBucket( IteratorState &iterator )
|
||||||
|
{
|
||||||
|
++iterator.bucketIndex_;
|
||||||
|
JSON_ASSERT_MESSAGE( iterator.bucketIndex_ <= iterator.map_->bucketsSize_,
|
||||||
|
"ValueInternalMap::increment(): attempting to iterate beyond end." );
|
||||||
|
if ( iterator.bucketIndex_ == iterator.map_->bucketsSize_ )
|
||||||
|
iterator.link_ = 0;
|
||||||
|
else
|
||||||
|
iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]);
|
||||||
|
iterator.itemIndex_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ValueInternalMap::increment( IteratorState &iterator )
|
||||||
|
{
|
||||||
|
JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterator using invalid iterator." );
|
||||||
|
++iterator.itemIndex_;
|
||||||
|
if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink )
|
||||||
|
{
|
||||||
|
JSON_ASSERT_MESSAGE( iterator.link_ != 0,
|
||||||
|
"ValueInternalMap::increment(): attempting to iterate beyond end." );
|
||||||
|
iterator.link_ = iterator.link_->next_;
|
||||||
|
if ( iterator.link_ == 0 )
|
||||||
|
incrementBucket( iterator );
|
||||||
|
}
|
||||||
|
else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable() )
|
||||||
|
{
|
||||||
|
incrementBucket( iterator );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ValueInternalMap::decrement( IteratorState &iterator )
|
||||||
|
{
|
||||||
|
if ( iterator.itemIndex_ == 0 )
|
||||||
|
{
|
||||||
|
JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterate using invalid iterator." );
|
||||||
|
if ( iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_] )
|
||||||
|
{
|
||||||
|
JSON_ASSERT_MESSAGE( iterator.bucketIndex_ > 0, "Attempting to iterate beyond beginning." );
|
||||||
|
--(iterator.bucketIndex_);
|
||||||
|
}
|
||||||
|
iterator.link_ = iterator.link_->previous_;
|
||||||
|
iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char *
|
||||||
|
ValueInternalMap::key( const IteratorState &iterator )
|
||||||
|
{
|
||||||
|
JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
|
||||||
|
return iterator.link_->keys_[iterator.itemIndex_];
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
ValueInternalMap::key( const IteratorState &iterator, bool &isStatic )
|
||||||
|
{
|
||||||
|
JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
|
||||||
|
isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic();
|
||||||
|
return iterator.link_->keys_[iterator.itemIndex_];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Value &
|
||||||
|
ValueInternalMap::value( const IteratorState &iterator )
|
||||||
|
{
|
||||||
|
JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
|
||||||
|
return iterator.link_->items_[iterator.itemIndex_];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ValueInternalMap::distance( const IteratorState &x, const IteratorState &y )
|
||||||
|
{
|
||||||
|
int offset = 0;
|
||||||
|
IteratorState it = x;
|
||||||
|
while ( !equals( it, y ) )
|
||||||
|
increment( it );
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
@ -0,0 +1,885 @@
|
|||||||
|
#include "reader.h"
|
||||||
|
#include "value.h"
|
||||||
|
#include <utility>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#if _MSC_VER >= 1400 // VC++ 8.0
|
||||||
|
#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Json {
|
||||||
|
|
||||||
|
// Implementation of class Features
|
||||||
|
// ////////////////////////////////
|
||||||
|
|
||||||
|
Features::Features()
|
||||||
|
: allowComments_( true )
|
||||||
|
, strictRoot_( false )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Features
|
||||||
|
Features::all()
|
||||||
|
{
|
||||||
|
return Features();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Features
|
||||||
|
Features::strictMode()
|
||||||
|
{
|
||||||
|
Features features;
|
||||||
|
features.allowComments_ = false;
|
||||||
|
features.strictRoot_ = true;
|
||||||
|
return features;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implementation of class Reader
|
||||||
|
// ////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 )
|
||||||
|
{
|
||||||
|
return c == c1 || c == c2 || c == c3 || c == c4;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 )
|
||||||
|
{
|
||||||
|
return c == c1 || c == c2 || c == c3 || c == c4 || c == c5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
containsNewLine( Reader::Location begin,
|
||||||
|
Reader::Location end )
|
||||||
|
{
|
||||||
|
for ( ;begin < end; ++begin )
|
||||||
|
if ( *begin == '\n' || *begin == '\r' )
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string codePointToUTF8(unsigned int cp)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
// based on description from http://en.wikipedia.org/wiki/UTF-8
|
||||||
|
|
||||||
|
if (cp <= 0x7f)
|
||||||
|
{
|
||||||
|
result.resize(1);
|
||||||
|
result[0] = static_cast<char>(cp);
|
||||||
|
}
|
||||||
|
else if (cp <= 0x7FF)
|
||||||
|
{
|
||||||
|
result.resize(2);
|
||||||
|
result[1] = static_cast<char>(0x80 | (0x3f & cp));
|
||||||
|
result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
|
||||||
|
}
|
||||||
|
else if (cp <= 0xFFFF)
|
||||||
|
{
|
||||||
|
result.resize(3);
|
||||||
|
result[2] = static_cast<char>(0x80 | (0x3f & cp));
|
||||||
|
result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6)));
|
||||||
|
result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12)));
|
||||||
|
}
|
||||||
|
else if (cp <= 0x10FFFF)
|
||||||
|
{
|
||||||
|
result.resize(4);
|
||||||
|
result[3] = static_cast<char>(0x80 | (0x3f & cp));
|
||||||
|
result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
|
||||||
|
result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
|
||||||
|
result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Class Reader
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Reader::Reader()
|
||||||
|
: features_( Features::all() )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reader::Reader( const Features &features )
|
||||||
|
: features_( features )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::parse( const std::string &document,
|
||||||
|
Value &root,
|
||||||
|
bool collectComments )
|
||||||
|
{
|
||||||
|
document_ = document;
|
||||||
|
const char *begin = document_.c_str();
|
||||||
|
const char *end = begin + document_.length();
|
||||||
|
return parse( begin, end, root, collectComments );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::parse( std::istream& sin,
|
||||||
|
Value &root,
|
||||||
|
bool collectComments )
|
||||||
|
{
|
||||||
|
//std::istream_iterator<char> begin(sin);
|
||||||
|
//std::istream_iterator<char> end;
|
||||||
|
// Those would allow streamed input from a file, if parse() were a
|
||||||
|
// template function.
|
||||||
|
|
||||||
|
// Since std::string is reference-counted, this at least does not
|
||||||
|
// create an extra copy.
|
||||||
|
std::string doc;
|
||||||
|
std::getline(sin, doc, (char)EOF);
|
||||||
|
return parse( doc, root, collectComments );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::parse( const char *beginDoc, const char *endDoc,
|
||||||
|
Value &root,
|
||||||
|
bool collectComments )
|
||||||
|
{
|
||||||
|
if ( !features_.allowComments_ )
|
||||||
|
{
|
||||||
|
collectComments = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
begin_ = beginDoc;
|
||||||
|
end_ = endDoc;
|
||||||
|
collectComments_ = collectComments;
|
||||||
|
current_ = begin_;
|
||||||
|
lastValueEnd_ = 0;
|
||||||
|
lastValue_ = 0;
|
||||||
|
commentsBefore_ = "";
|
||||||
|
errors_.clear();
|
||||||
|
while ( !nodes_.empty() )
|
||||||
|
nodes_.pop();
|
||||||
|
nodes_.push( &root );
|
||||||
|
|
||||||
|
bool successful = readValue();
|
||||||
|
Token token;
|
||||||
|
skipCommentTokens( token );
|
||||||
|
if ( collectComments_ && !commentsBefore_.empty() )
|
||||||
|
root.setComment( commentsBefore_, commentAfter );
|
||||||
|
if ( features_.strictRoot_ )
|
||||||
|
{
|
||||||
|
if ( !root.isArray() && !root.isObject() )
|
||||||
|
{
|
||||||
|
// Set error location to start of doc, ideally should be first token found in doc
|
||||||
|
token.type_ = tokenError;
|
||||||
|
token.start_ = beginDoc;
|
||||||
|
token.end_ = endDoc;
|
||||||
|
addError( "A valid JSON document must be either an array or an object value.",
|
||||||
|
token );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return successful;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readValue()
|
||||||
|
{
|
||||||
|
Token token;
|
||||||
|
skipCommentTokens( token );
|
||||||
|
bool successful = true;
|
||||||
|
|
||||||
|
if ( collectComments_ && !commentsBefore_.empty() )
|
||||||
|
{
|
||||||
|
currentValue().setComment( commentsBefore_, commentBefore );
|
||||||
|
commentsBefore_ = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
switch ( token.type_ )
|
||||||
|
{
|
||||||
|
case tokenObjectBegin:
|
||||||
|
successful = readObject( token );
|
||||||
|
break;
|
||||||
|
case tokenArrayBegin:
|
||||||
|
successful = readArray( token );
|
||||||
|
break;
|
||||||
|
case tokenNumber:
|
||||||
|
successful = decodeNumber( token );
|
||||||
|
break;
|
||||||
|
case tokenString:
|
||||||
|
successful = decodeString( token );
|
||||||
|
break;
|
||||||
|
case tokenTrue:
|
||||||
|
currentValue() = true;
|
||||||
|
break;
|
||||||
|
case tokenFalse:
|
||||||
|
currentValue() = false;
|
||||||
|
break;
|
||||||
|
case tokenNull:
|
||||||
|
currentValue() = Value();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return addError( "Syntax error: value, object or array expected.", token );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( collectComments_ )
|
||||||
|
{
|
||||||
|
lastValueEnd_ = current_;
|
||||||
|
lastValue_ = ¤tValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
return successful;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Reader::skipCommentTokens( Token &token )
|
||||||
|
{
|
||||||
|
if ( features_.allowComments_ )
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
readToken( token );
|
||||||
|
}
|
||||||
|
while ( token.type_ == tokenComment );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
readToken( token );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::expectToken( TokenType type, Token &token, const char *message )
|
||||||
|
{
|
||||||
|
readToken( token );
|
||||||
|
if ( token.type_ != type )
|
||||||
|
return addError( message, token );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readToken( Token &token )
|
||||||
|
{
|
||||||
|
skipSpaces();
|
||||||
|
token.start_ = current_;
|
||||||
|
Char c = getNextChar();
|
||||||
|
bool ok = true;
|
||||||
|
switch ( c )
|
||||||
|
{
|
||||||
|
case '{':
|
||||||
|
token.type_ = tokenObjectBegin;
|
||||||
|
break;
|
||||||
|
case '}':
|
||||||
|
token.type_ = tokenObjectEnd;
|
||||||
|
break;
|
||||||
|
case '[':
|
||||||
|
token.type_ = tokenArrayBegin;
|
||||||
|
break;
|
||||||
|
case ']':
|
||||||
|
token.type_ = tokenArrayEnd;
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
token.type_ = tokenString;
|
||||||
|
ok = readString();
|
||||||
|
break;
|
||||||
|
case '/':
|
||||||
|
token.type_ = tokenComment;
|
||||||
|
ok = readComment();
|
||||||
|
break;
|
||||||
|
case '0':
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
case '4':
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
case '7':
|
||||||
|
case '8':
|
||||||
|
case '9':
|
||||||
|
case '-':
|
||||||
|
token.type_ = tokenNumber;
|
||||||
|
readNumber();
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
token.type_ = tokenTrue;
|
||||||
|
ok = match( "rue", 3 );
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
token.type_ = tokenFalse;
|
||||||
|
ok = match( "alse", 4 );
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
token.type_ = tokenNull;
|
||||||
|
ok = match( "ull", 3 );
|
||||||
|
break;
|
||||||
|
case ',':
|
||||||
|
token.type_ = tokenArraySeparator;
|
||||||
|
break;
|
||||||
|
case ':':
|
||||||
|
token.type_ = tokenMemberSeparator;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
token.type_ = tokenEndOfStream;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ( !ok )
|
||||||
|
token.type_ = tokenError;
|
||||||
|
token.end_ = current_;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Reader::skipSpaces()
|
||||||
|
{
|
||||||
|
while ( current_ != end_ )
|
||||||
|
{
|
||||||
|
Char c = *current_;
|
||||||
|
if ( c == ' ' || c == '\t' || c == '\r' || c == '\n' )
|
||||||
|
++current_;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::match( Location pattern,
|
||||||
|
int patternLength )
|
||||||
|
{
|
||||||
|
if ( end_ - current_ < patternLength )
|
||||||
|
return false;
|
||||||
|
int index = patternLength;
|
||||||
|
while ( index-- )
|
||||||
|
if ( current_[index] != pattern[index] )
|
||||||
|
return false;
|
||||||
|
current_ += patternLength;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readComment()
|
||||||
|
{
|
||||||
|
Location commentBegin = current_ - 1;
|
||||||
|
Char c = getNextChar();
|
||||||
|
bool successful = false;
|
||||||
|
if ( c == '*' )
|
||||||
|
successful = readCStyleComment();
|
||||||
|
else if ( c == '/' )
|
||||||
|
successful = readCppStyleComment();
|
||||||
|
if ( !successful )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( collectComments_ )
|
||||||
|
{
|
||||||
|
CommentPlacement placement = commentBefore;
|
||||||
|
if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) )
|
||||||
|
{
|
||||||
|
if ( c != '*' || !containsNewLine( commentBegin, current_ ) )
|
||||||
|
placement = commentAfterOnSameLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
addComment( commentBegin, current_, placement );
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Reader::addComment( Location begin,
|
||||||
|
Location end,
|
||||||
|
CommentPlacement placement )
|
||||||
|
{
|
||||||
|
assert( collectComments_ );
|
||||||
|
if ( placement == commentAfterOnSameLine )
|
||||||
|
{
|
||||||
|
assert( lastValue_ != 0 );
|
||||||
|
lastValue_->setComment( std::string( begin, end ), placement );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( !commentsBefore_.empty() )
|
||||||
|
commentsBefore_ += "\n";
|
||||||
|
commentsBefore_ += std::string( begin, end );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readCStyleComment()
|
||||||
|
{
|
||||||
|
while ( current_ != end_ )
|
||||||
|
{
|
||||||
|
Char c = getNextChar();
|
||||||
|
if ( c == '*' && *current_ == '/' )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return getNextChar() == '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readCppStyleComment()
|
||||||
|
{
|
||||||
|
while ( current_ != end_ )
|
||||||
|
{
|
||||||
|
Char c = getNextChar();
|
||||||
|
if ( c == '\r' || c == '\n' )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Reader::readNumber()
|
||||||
|
{
|
||||||
|
while ( current_ != end_ )
|
||||||
|
{
|
||||||
|
if ( !(*current_ >= '0' && *current_ <= '9') &&
|
||||||
|
!in( *current_, '.', 'e', 'E', '+', '-' ) )
|
||||||
|
break;
|
||||||
|
++current_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readString()
|
||||||
|
{
|
||||||
|
Char c = 0;
|
||||||
|
while ( current_ != end_ )
|
||||||
|
{
|
||||||
|
c = getNextChar();
|
||||||
|
if ( c == '\\' )
|
||||||
|
getNextChar();
|
||||||
|
else if ( c == '"' )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return c == '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readObject( Token &tokenStart )
|
||||||
|
{
|
||||||
|
Token tokenName;
|
||||||
|
std::string name;
|
||||||
|
currentValue() = Value( objectValue );
|
||||||
|
while ( readToken( tokenName ) )
|
||||||
|
{
|
||||||
|
bool initialTokenOk = true;
|
||||||
|
while ( tokenName.type_ == tokenComment && initialTokenOk )
|
||||||
|
initialTokenOk = readToken( tokenName );
|
||||||
|
if ( !initialTokenOk )
|
||||||
|
break;
|
||||||
|
if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object
|
||||||
|
return true;
|
||||||
|
if ( tokenName.type_ != tokenString )
|
||||||
|
break;
|
||||||
|
|
||||||
|
name = "";
|
||||||
|
if ( !decodeString( tokenName, name ) )
|
||||||
|
return recoverFromError( tokenObjectEnd );
|
||||||
|
|
||||||
|
Token colon;
|
||||||
|
if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator )
|
||||||
|
{
|
||||||
|
return addErrorAndRecover( "Missing ':' after object member name",
|
||||||
|
colon,
|
||||||
|
tokenObjectEnd );
|
||||||
|
}
|
||||||
|
Value &value = currentValue()[ name ];
|
||||||
|
nodes_.push( &value );
|
||||||
|
bool ok = readValue();
|
||||||
|
nodes_.pop();
|
||||||
|
if ( !ok ) // error already set
|
||||||
|
return recoverFromError( tokenObjectEnd );
|
||||||
|
|
||||||
|
Token comma;
|
||||||
|
if ( !readToken( comma )
|
||||||
|
|| ( comma.type_ != tokenObjectEnd &&
|
||||||
|
comma.type_ != tokenArraySeparator &&
|
||||||
|
comma.type_ != tokenComment ) )
|
||||||
|
{
|
||||||
|
return addErrorAndRecover( "Missing ',' or '}' in object declaration",
|
||||||
|
comma,
|
||||||
|
tokenObjectEnd );
|
||||||
|
}
|
||||||
|
bool finalizeTokenOk = true;
|
||||||
|
while ( comma.type_ == tokenComment &&
|
||||||
|
finalizeTokenOk )
|
||||||
|
finalizeTokenOk = readToken( comma );
|
||||||
|
if ( comma.type_ == tokenObjectEnd )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return addErrorAndRecover( "Missing '}' or object member name",
|
||||||
|
tokenName,
|
||||||
|
tokenObjectEnd );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readArray( Token &tokenStart )
|
||||||
|
{
|
||||||
|
currentValue() = Value( arrayValue );
|
||||||
|
skipSpaces();
|
||||||
|
if ( *current_ == ']' ) // empty array
|
||||||
|
{
|
||||||
|
Token endArray;
|
||||||
|
readToken( endArray );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int index = 0;
|
||||||
|
while ( true )
|
||||||
|
{
|
||||||
|
Value &value = currentValue()[ index++ ];
|
||||||
|
nodes_.push( &value );
|
||||||
|
bool ok = readValue();
|
||||||
|
nodes_.pop();
|
||||||
|
if ( !ok ) // error already set
|
||||||
|
return recoverFromError( tokenArrayEnd );
|
||||||
|
|
||||||
|
Token token;
|
||||||
|
// Accept Comment after last item in the array.
|
||||||
|
ok = readToken( token );
|
||||||
|
while ( token.type_ == tokenComment && ok )
|
||||||
|
{
|
||||||
|
ok = readToken( token );
|
||||||
|
}
|
||||||
|
bool badTokenType = ( token.type_ == tokenArraySeparator &&
|
||||||
|
token.type_ == tokenArrayEnd );
|
||||||
|
if ( !ok || badTokenType )
|
||||||
|
{
|
||||||
|
return addErrorAndRecover( "Missing ',' or ']' in array declaration",
|
||||||
|
token,
|
||||||
|
tokenArrayEnd );
|
||||||
|
}
|
||||||
|
if ( token.type_ == tokenArrayEnd )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::decodeNumber( Token &token )
|
||||||
|
{
|
||||||
|
bool isDouble = false;
|
||||||
|
for ( Location inspect = token.start_; inspect != token.end_; ++inspect )
|
||||||
|
{
|
||||||
|
isDouble = isDouble
|
||||||
|
|| in( *inspect, '.', 'e', 'E', '+' )
|
||||||
|
|| ( *inspect == '-' && inspect != token.start_ );
|
||||||
|
}
|
||||||
|
if ( isDouble )
|
||||||
|
return decodeDouble( token );
|
||||||
|
Location current = token.start_;
|
||||||
|
bool isNegative = *current == '-';
|
||||||
|
if ( isNegative )
|
||||||
|
++current;
|
||||||
|
Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt)
|
||||||
|
: Value::maxUInt) / 10;
|
||||||
|
Value::UInt value = 0;
|
||||||
|
while ( current < token.end_ )
|
||||||
|
{
|
||||||
|
Char c = *current++;
|
||||||
|
if ( c < '0' || c > '9' )
|
||||||
|
return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
|
||||||
|
if ( value >= threshold )
|
||||||
|
return decodeDouble( token );
|
||||||
|
value = value * 10 + Value::UInt(c - '0');
|
||||||
|
}
|
||||||
|
if ( isNegative )
|
||||||
|
currentValue() = -Value::Int( value );
|
||||||
|
else if ( value <= Value::UInt(Value::maxInt) )
|
||||||
|
currentValue() = Value::Int( value );
|
||||||
|
else
|
||||||
|
currentValue() = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::decodeDouble( Token &token )
|
||||||
|
{
|
||||||
|
double value = 0;
|
||||||
|
const int bufferSize = 32;
|
||||||
|
int count;
|
||||||
|
int length = int(token.end_ - token.start_);
|
||||||
|
if ( length <= bufferSize )
|
||||||
|
{
|
||||||
|
Char buffer[bufferSize];
|
||||||
|
memcpy( buffer, token.start_, length );
|
||||||
|
buffer[length] = 0;
|
||||||
|
count = sscanf( buffer, "%lf", &value );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string buffer( token.start_, token.end_ );
|
||||||
|
count = sscanf( buffer.c_str(), "%lf", &value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( count != 1 )
|
||||||
|
return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
|
||||||
|
currentValue() = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::decodeString( Token &token )
|
||||||
|
{
|
||||||
|
std::string decoded;
|
||||||
|
if ( !decodeString( token, decoded ) )
|
||||||
|
return false;
|
||||||
|
currentValue() = decoded;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::decodeString( Token &token, std::string &decoded )
|
||||||
|
{
|
||||||
|
decoded.reserve( token.end_ - token.start_ - 2 );
|
||||||
|
Location current = token.start_ + 1; // skip '"'
|
||||||
|
Location end = token.end_ - 1; // do not include '"'
|
||||||
|
while ( current != end )
|
||||||
|
{
|
||||||
|
Char c = *current++;
|
||||||
|
if ( c == '"' )
|
||||||
|
break;
|
||||||
|
else if ( c == '\\' )
|
||||||
|
{
|
||||||
|
if ( current == end )
|
||||||
|
return addError( "Empty escape sequence in string", token, current );
|
||||||
|
Char escape = *current++;
|
||||||
|
switch ( escape )
|
||||||
|
{
|
||||||
|
case '"': decoded += '"'; break;
|
||||||
|
case '/': decoded += '/'; break;
|
||||||
|
case '\\': decoded += '\\'; break;
|
||||||
|
case 'b': decoded += '\b'; break;
|
||||||
|
case 'f': decoded += '\f'; break;
|
||||||
|
case 'n': decoded += '\n'; break;
|
||||||
|
case 'r': decoded += '\r'; break;
|
||||||
|
case 't': decoded += '\t'; break;
|
||||||
|
case 'u':
|
||||||
|
{
|
||||||
|
unsigned int unicode;
|
||||||
|
if ( !decodeUnicodeCodePoint( token, current, end, unicode ) )
|
||||||
|
return false;
|
||||||
|
decoded += codePointToUTF8(unicode);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return addError( "Bad escape sequence in string", token, current );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
decoded += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::decodeUnicodeCodePoint( Token &token,
|
||||||
|
Location ¤t,
|
||||||
|
Location end,
|
||||||
|
unsigned int &unicode )
|
||||||
|
{
|
||||||
|
|
||||||
|
if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) )
|
||||||
|
return false;
|
||||||
|
if (unicode >= 0xD800 && unicode <= 0xDBFF)
|
||||||
|
{
|
||||||
|
// surrogate pairs
|
||||||
|
if (end - current < 6)
|
||||||
|
return addError( "additional six characters expected to parse unicode surrogate pair.", token, current );
|
||||||
|
unsigned int surrogatePair;
|
||||||
|
if (*(current++) == '\\' && *(current++)== 'u')
|
||||||
|
{
|
||||||
|
if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair ))
|
||||||
|
{
|
||||||
|
unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current );
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::decodeUnicodeEscapeSequence( Token &token,
|
||||||
|
Location ¤t,
|
||||||
|
Location end,
|
||||||
|
unsigned int &unicode )
|
||||||
|
{
|
||||||
|
if ( end - current < 4 )
|
||||||
|
return addError( "Bad unicode escape sequence in string: four digits expected.", token, current );
|
||||||
|
unicode = 0;
|
||||||
|
for ( int index =0; index < 4; ++index )
|
||||||
|
{
|
||||||
|
Char c = *current++;
|
||||||
|
unicode *= 16;
|
||||||
|
if ( c >= '0' && c <= '9' )
|
||||||
|
unicode += c - '0';
|
||||||
|
else if ( c >= 'a' && c <= 'f' )
|
||||||
|
unicode += c - 'a' + 10;
|
||||||
|
else if ( c >= 'A' && c <= 'F' )
|
||||||
|
unicode += c - 'A' + 10;
|
||||||
|
else
|
||||||
|
return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current );
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::addError( const std::string &message,
|
||||||
|
Token &token,
|
||||||
|
Location extra )
|
||||||
|
{
|
||||||
|
ErrorInfo info;
|
||||||
|
info.token_ = token;
|
||||||
|
info.message_ = message;
|
||||||
|
info.extra_ = extra;
|
||||||
|
errors_.push_back( info );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::recoverFromError( TokenType skipUntilToken )
|
||||||
|
{
|
||||||
|
int errorCount = int(errors_.size());
|
||||||
|
Token skip;
|
||||||
|
while ( true )
|
||||||
|
{
|
||||||
|
if ( !readToken(skip) )
|
||||||
|
errors_.resize( errorCount ); // discard errors caused by recovery
|
||||||
|
if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
errors_.resize( errorCount );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::addErrorAndRecover( const std::string &message,
|
||||||
|
Token &token,
|
||||||
|
TokenType skipUntilToken )
|
||||||
|
{
|
||||||
|
addError( message, token );
|
||||||
|
return recoverFromError( skipUntilToken );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Value &
|
||||||
|
Reader::currentValue()
|
||||||
|
{
|
||||||
|
return *(nodes_.top());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reader::Char
|
||||||
|
Reader::getNextChar()
|
||||||
|
{
|
||||||
|
if ( current_ == end_ )
|
||||||
|
return 0;
|
||||||
|
return *current_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Reader::getLocationLineAndColumn( Location location,
|
||||||
|
int &line,
|
||||||
|
int &column ) const
|
||||||
|
{
|
||||||
|
Location current = begin_;
|
||||||
|
Location lastLineStart = current;
|
||||||
|
line = 0;
|
||||||
|
while ( current < location && current != end_ )
|
||||||
|
{
|
||||||
|
Char c = *current++;
|
||||||
|
if ( c == '\r' )
|
||||||
|
{
|
||||||
|
if ( *current == '\n' )
|
||||||
|
++current;
|
||||||
|
lastLineStart = current;
|
||||||
|
++line;
|
||||||
|
}
|
||||||
|
else if ( c == '\n' )
|
||||||
|
{
|
||||||
|
lastLineStart = current;
|
||||||
|
++line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// column & line start at 1
|
||||||
|
column = int(location - lastLineStart) + 1;
|
||||||
|
++line;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string
|
||||||
|
Reader::getLocationLineAndColumn( Location location ) const
|
||||||
|
{
|
||||||
|
int line, column;
|
||||||
|
getLocationLineAndColumn( location, line, column );
|
||||||
|
char buffer[18+16+16+1];
|
||||||
|
sprintf( buffer, "Line %d, Column %d", line, column );
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string
|
||||||
|
Reader::getFormatedErrorMessages() const
|
||||||
|
{
|
||||||
|
std::string formattedMessage;
|
||||||
|
for ( Errors::const_iterator itError = errors_.begin();
|
||||||
|
itError != errors_.end();
|
||||||
|
++itError )
|
||||||
|
{
|
||||||
|
const ErrorInfo &error = *itError;
|
||||||
|
formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n";
|
||||||
|
formattedMessage += " " + error.message_ + "\n";
|
||||||
|
if ( error.extra_ )
|
||||||
|
formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n";
|
||||||
|
}
|
||||||
|
return formattedMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::istream& operator>>( std::istream &sin, Value &root )
|
||||||
|
{
|
||||||
|
Json::Reader reader;
|
||||||
|
bool ok = reader.parse(sin, root, true);
|
||||||
|
//JSON_ASSERT( ok );
|
||||||
|
if (!ok) throw std::runtime_error(reader.getFormatedErrorMessages());
|
||||||
|
return sin;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Json
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,292 @@
|
|||||||
|
// included by json_value.cpp
|
||||||
|
// everything is within Json namespace
|
||||||
|
|
||||||
|
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// class ValueIteratorBase
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ValueIteratorBase::ValueIteratorBase()
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
: current_()
|
||||||
|
, isNull_( true )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
: isArray_( true )
|
||||||
|
, isNull_( true )
|
||||||
|
{
|
||||||
|
iterator_.array_ = ValueInternalArray::IteratorState();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator ¤t )
|
||||||
|
: current_( current )
|
||||||
|
, isNull_( false )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state )
|
||||||
|
: isArray_( true )
|
||||||
|
{
|
||||||
|
iterator_.array_ = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state )
|
||||||
|
: isArray_( false )
|
||||||
|
{
|
||||||
|
iterator_.map_ = state;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Value &
|
||||||
|
ValueIteratorBase::deref() const
|
||||||
|
{
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
return current_->second;
|
||||||
|
#else
|
||||||
|
if ( isArray_ )
|
||||||
|
return ValueInternalArray::dereference( iterator_.array_ );
|
||||||
|
return ValueInternalMap::value( iterator_.map_ );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ValueIteratorBase::increment()
|
||||||
|
{
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
++current_;
|
||||||
|
#else
|
||||||
|
if ( isArray_ )
|
||||||
|
ValueInternalArray::increment( iterator_.array_ );
|
||||||
|
ValueInternalMap::increment( iterator_.map_ );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ValueIteratorBase::decrement()
|
||||||
|
{
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
--current_;
|
||||||
|
#else
|
||||||
|
if ( isArray_ )
|
||||||
|
ValueInternalArray::decrement( iterator_.array_ );
|
||||||
|
ValueInternalMap::decrement( iterator_.map_ );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ValueIteratorBase::difference_type
|
||||||
|
ValueIteratorBase::computeDistance( const SelfType &other ) const
|
||||||
|
{
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
# ifdef JSON_USE_CPPTL_SMALLMAP
|
||||||
|
return current_ - other.current_;
|
||||||
|
# else
|
||||||
|
// Iterator for null value are initialized using the default
|
||||||
|
// constructor, which initialize current_ to the default
|
||||||
|
// std::map::iterator. As begin() and end() are two instance
|
||||||
|
// of the default std::map::iterator, they can not be compared.
|
||||||
|
// To allow this, we handle this comparison specifically.
|
||||||
|
if ( isNull_ && other.isNull_ )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL,
|
||||||
|
// which is the one used by default).
|
||||||
|
// Using a portable hand-made version for non random iterator instead:
|
||||||
|
// return difference_type( std::distance( current_, other.current_ ) );
|
||||||
|
difference_type myDistance = 0;
|
||||||
|
for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it )
|
||||||
|
{
|
||||||
|
++myDistance;
|
||||||
|
}
|
||||||
|
return myDistance;
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
if ( isArray_ )
|
||||||
|
return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ );
|
||||||
|
return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
ValueIteratorBase::isEqual( const SelfType &other ) const
|
||||||
|
{
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
if ( isNull_ )
|
||||||
|
{
|
||||||
|
return other.isNull_;
|
||||||
|
}
|
||||||
|
return current_ == other.current_;
|
||||||
|
#else
|
||||||
|
if ( isArray_ )
|
||||||
|
return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ );
|
||||||
|
return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ValueIteratorBase::copy( const SelfType &other )
|
||||||
|
{
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
current_ = other.current_;
|
||||||
|
#else
|
||||||
|
if ( isArray_ )
|
||||||
|
iterator_.array_ = other.iterator_.array_;
|
||||||
|
iterator_.map_ = other.iterator_.map_;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Value
|
||||||
|
ValueIteratorBase::key() const
|
||||||
|
{
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
const Value::CZString czstring = (*current_).first;
|
||||||
|
if ( czstring.c_str() )
|
||||||
|
{
|
||||||
|
if ( czstring.isStaticString() )
|
||||||
|
return Value( StaticString( czstring.c_str() ) );
|
||||||
|
return Value( czstring.c_str() );
|
||||||
|
}
|
||||||
|
return Value( czstring.index() );
|
||||||
|
#else
|
||||||
|
if ( isArray_ )
|
||||||
|
return Value( ValueInternalArray::indexOf( iterator_.array_ ) );
|
||||||
|
bool isStatic;
|
||||||
|
const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic );
|
||||||
|
if ( isStatic )
|
||||||
|
return Value( StaticString( memberName ) );
|
||||||
|
return Value( memberName );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
UInt
|
||||||
|
ValueIteratorBase::index() const
|
||||||
|
{
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
const Value::CZString czstring = (*current_).first;
|
||||||
|
if ( !czstring.c_str() )
|
||||||
|
return czstring.index();
|
||||||
|
return Value::UInt( -1 );
|
||||||
|
#else
|
||||||
|
if ( isArray_ )
|
||||||
|
return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) );
|
||||||
|
return Value::UInt( -1 );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char *
|
||||||
|
ValueIteratorBase::memberName() const
|
||||||
|
{
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
const char *name = (*current_).first.c_str();
|
||||||
|
return name ? name : "";
|
||||||
|
#else
|
||||||
|
if ( !isArray_ )
|
||||||
|
return ValueInternalMap::key( iterator_.map_ );
|
||||||
|
return "";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// class ValueConstIterator
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ValueConstIterator::ValueConstIterator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator ¤t )
|
||||||
|
: ValueIteratorBase( current )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state )
|
||||||
|
: ValueIteratorBase( state )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state )
|
||||||
|
: ValueIteratorBase( state )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ValueConstIterator &
|
||||||
|
ValueConstIterator::operator =( const ValueIteratorBase &other )
|
||||||
|
{
|
||||||
|
copy( other );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// class ValueIterator
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ValueIterator::ValueIterator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
|
ValueIterator::ValueIterator( const Value::ObjectValues::iterator ¤t )
|
||||||
|
: ValueIteratorBase( current )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state )
|
||||||
|
: ValueIteratorBase( state )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state )
|
||||||
|
: ValueIteratorBase( state )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ValueIterator::ValueIterator( const ValueConstIterator &other )
|
||||||
|
: ValueIteratorBase( other )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueIterator::ValueIterator( const ValueIterator &other )
|
||||||
|
: ValueIteratorBase( other )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueIterator &
|
||||||
|
ValueIterator::operator =( const SelfType &other )
|
||||||
|
{
|
||||||
|
copy( other );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
@ -0,0 +1,829 @@
|
|||||||
|
#include "writer.h"
|
||||||
|
#include <utility>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
#if _MSC_VER >= 1400 // VC++ 8.0
|
||||||
|
#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Json {
|
||||||
|
|
||||||
|
static bool isControlCharacter(char ch)
|
||||||
|
{
|
||||||
|
return ch > 0 && ch <= 0x1F;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool containsControlCharacter( const char* str )
|
||||||
|
{
|
||||||
|
while ( *str )
|
||||||
|
{
|
||||||
|
if ( isControlCharacter( *(str++) ) )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static void uintToString( unsigned int value,
|
||||||
|
char *¤t )
|
||||||
|
{
|
||||||
|
*--current = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
*--current = (value % 10) + '0';
|
||||||
|
value /= 10;
|
||||||
|
}
|
||||||
|
while ( value != 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string valueToString( Int value )
|
||||||
|
{
|
||||||
|
char buffer[32];
|
||||||
|
char *current = buffer + sizeof(buffer);
|
||||||
|
bool isNegative = value < 0;
|
||||||
|
if ( isNegative )
|
||||||
|
value = -value;
|
||||||
|
uintToString( UInt(value), current );
|
||||||
|
if ( isNegative )
|
||||||
|
*--current = '-';
|
||||||
|
assert( current >= buffer );
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string valueToString( UInt value )
|
||||||
|
{
|
||||||
|
char buffer[32];
|
||||||
|
char *current = buffer + sizeof(buffer);
|
||||||
|
uintToString( value, current );
|
||||||
|
assert( current >= buffer );
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string valueToString( double value )
|
||||||
|
{
|
||||||
|
char buffer[32];
|
||||||
|
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning.
|
||||||
|
sprintf_s(buffer, sizeof(buffer), "%#.16g", value);
|
||||||
|
#else
|
||||||
|
sprintf(buffer, "%#.16g", value);
|
||||||
|
#endif
|
||||||
|
char* ch = buffer + strlen(buffer) - 1;
|
||||||
|
if (*ch != '0') return buffer; // nothing to truncate, so save time
|
||||||
|
while(ch > buffer && *ch == '0'){
|
||||||
|
--ch;
|
||||||
|
}
|
||||||
|
char* last_nonzero = ch;
|
||||||
|
while(ch >= buffer){
|
||||||
|
switch(*ch){
|
||||||
|
case '0':
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
case '4':
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
case '7':
|
||||||
|
case '8':
|
||||||
|
case '9':
|
||||||
|
--ch;
|
||||||
|
continue;
|
||||||
|
case '.':
|
||||||
|
// Truncate zeroes to save bytes in output, but keep one.
|
||||||
|
*(last_nonzero+2) = '\0';
|
||||||
|
return buffer;
|
||||||
|
default:
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string valueToString( bool value )
|
||||||
|
{
|
||||||
|
return value ? "true" : "false";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string valueToQuotedString( const char *value )
|
||||||
|
{
|
||||||
|
// Not sure how to handle unicode...
|
||||||
|
if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value ))
|
||||||
|
return std::string("\"") + value + "\"";
|
||||||
|
// We have to walk value and escape any special characters.
|
||||||
|
// Appending to std::string is not efficient, but this should be rare.
|
||||||
|
// (Note: forward slashes are *not* rare, but I am not escaping them.)
|
||||||
|
unsigned maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL
|
||||||
|
std::string result;
|
||||||
|
result.reserve(maxsize); // to avoid lots of mallocs
|
||||||
|
result += "\"";
|
||||||
|
for (const char* c=value; *c != 0; ++c)
|
||||||
|
{
|
||||||
|
switch(*c)
|
||||||
|
{
|
||||||
|
case '\"':
|
||||||
|
result += "\\\"";
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
result += "\\\\";
|
||||||
|
break;
|
||||||
|
case '\b':
|
||||||
|
result += "\\b";
|
||||||
|
break;
|
||||||
|
case '\f':
|
||||||
|
result += "\\f";
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
result += "\\n";
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
result += "\\r";
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
result += "\\t";
|
||||||
|
break;
|
||||||
|
//case '/':
|
||||||
|
// Even though \/ is considered a legal escape in JSON, a bare
|
||||||
|
// slash is also legal, so I see no reason to escape it.
|
||||||
|
// (I hope I am not misunderstanding something.
|
||||||
|
// blep notes: actually escaping \/ may be useful in javascript to avoid </
|
||||||
|
// sequence.
|
||||||
|
// Should add a flag to allow this compatibility mode and prevent this
|
||||||
|
// sequence from occurring.
|
||||||
|
default:
|
||||||
|
if ( isControlCharacter( *c ) )
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c);
|
||||||
|
result += oss.str();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result += *c;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result += "\"";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Class Writer
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
Writer::~Writer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Class FastWriter
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
FastWriter::FastWriter()
|
||||||
|
: yamlCompatiblityEnabled_( false )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
FastWriter::enableYAMLCompatibility()
|
||||||
|
{
|
||||||
|
yamlCompatiblityEnabled_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string
|
||||||
|
FastWriter::write( const Value &root )
|
||||||
|
{
|
||||||
|
document_ = "";
|
||||||
|
writeValue( root );
|
||||||
|
document_ += "\n";
|
||||||
|
return document_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
FastWriter::writeValue( const Value &value )
|
||||||
|
{
|
||||||
|
switch ( value.type() )
|
||||||
|
{
|
||||||
|
case nullValue:
|
||||||
|
document_ += "null";
|
||||||
|
break;
|
||||||
|
case intValue:
|
||||||
|
document_ += valueToString( value.asInt() );
|
||||||
|
break;
|
||||||
|
case uintValue:
|
||||||
|
document_ += valueToString( value.asUInt() );
|
||||||
|
break;
|
||||||
|
case realValue:
|
||||||
|
document_ += valueToString( value.asDouble() );
|
||||||
|
break;
|
||||||
|
case stringValue:
|
||||||
|
document_ += valueToQuotedString( value.asCString() );
|
||||||
|
break;
|
||||||
|
case booleanValue:
|
||||||
|
document_ += valueToString( value.asBool() );
|
||||||
|
break;
|
||||||
|
case arrayValue:
|
||||||
|
{
|
||||||
|
document_ += "[";
|
||||||
|
int size = value.size();
|
||||||
|
for ( int index =0; index < size; ++index )
|
||||||
|
{
|
||||||
|
if ( index > 0 )
|
||||||
|
document_ += ",";
|
||||||
|
writeValue( value[index] );
|
||||||
|
}
|
||||||
|
document_ += "]";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case objectValue:
|
||||||
|
{
|
||||||
|
Value::Members members( value.getMemberNames() );
|
||||||
|
document_ += "{";
|
||||||
|
for ( Value::Members::iterator it = members.begin();
|
||||||
|
it != members.end();
|
||||||
|
++it )
|
||||||
|
{
|
||||||
|
const std::string &name = *it;
|
||||||
|
if ( it != members.begin() )
|
||||||
|
document_ += ",";
|
||||||
|
document_ += valueToQuotedString( name.c_str() );
|
||||||
|
document_ += yamlCompatiblityEnabled_ ? ": "
|
||||||
|
: ":";
|
||||||
|
writeValue( value[name] );
|
||||||
|
}
|
||||||
|
document_ += "}";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Class StyledWriter
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
StyledWriter::StyledWriter()
|
||||||
|
: rightMargin_( 74 )
|
||||||
|
, indentSize_( 3 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string
|
||||||
|
StyledWriter::write( const Value &root )
|
||||||
|
{
|
||||||
|
document_ = "";
|
||||||
|
addChildValues_ = false;
|
||||||
|
indentString_ = "";
|
||||||
|
writeCommentBeforeValue( root );
|
||||||
|
writeValue( root );
|
||||||
|
writeCommentAfterValueOnSameLine( root );
|
||||||
|
document_ += "\n";
|
||||||
|
return document_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StyledWriter::writeValue( const Value &value )
|
||||||
|
{
|
||||||
|
switch ( value.type() )
|
||||||
|
{
|
||||||
|
case nullValue:
|
||||||
|
pushValue( "null" );
|
||||||
|
break;
|
||||||
|
case intValue:
|
||||||
|
pushValue( valueToString( value.asInt() ) );
|
||||||
|
break;
|
||||||
|
case uintValue:
|
||||||
|
pushValue( valueToString( value.asUInt() ) );
|
||||||
|
break;
|
||||||
|
case realValue:
|
||||||
|
pushValue( valueToString( value.asDouble() ) );
|
||||||
|
break;
|
||||||
|
case stringValue:
|
||||||
|
pushValue( valueToQuotedString( value.asCString() ) );
|
||||||
|
break;
|
||||||
|
case booleanValue:
|
||||||
|
pushValue( valueToString( value.asBool() ) );
|
||||||
|
break;
|
||||||
|
case arrayValue:
|
||||||
|
writeArrayValue( value);
|
||||||
|
break;
|
||||||
|
case objectValue:
|
||||||
|
{
|
||||||
|
Value::Members members( value.getMemberNames() );
|
||||||
|
if ( members.empty() )
|
||||||
|
pushValue( "{}" );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writeWithIndent( "{" );
|
||||||
|
indent();
|
||||||
|
Value::Members::iterator it = members.begin();
|
||||||
|
while ( true )
|
||||||
|
{
|
||||||
|
const std::string &name = *it;
|
||||||
|
const Value &childValue = value[name];
|
||||||
|
writeCommentBeforeValue( childValue );
|
||||||
|
writeWithIndent( valueToQuotedString( name.c_str() ) );
|
||||||
|
document_ += " : ";
|
||||||
|
writeValue( childValue );
|
||||||
|
if ( ++it == members.end() )
|
||||||
|
{
|
||||||
|
writeCommentAfterValueOnSameLine( childValue );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
document_ += ",";
|
||||||
|
writeCommentAfterValueOnSameLine( childValue );
|
||||||
|
}
|
||||||
|
unindent();
|
||||||
|
writeWithIndent( "}" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StyledWriter::writeArrayValue( const Value &value )
|
||||||
|
{
|
||||||
|
unsigned size = value.size();
|
||||||
|
if ( size == 0 )
|
||||||
|
pushValue( "[]" );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool isArrayMultiLine = isMultineArray( value );
|
||||||
|
if ( isArrayMultiLine )
|
||||||
|
{
|
||||||
|
writeWithIndent( "[" );
|
||||||
|
indent();
|
||||||
|
bool hasChildValue = !childValues_.empty();
|
||||||
|
unsigned index =0;
|
||||||
|
while ( true )
|
||||||
|
{
|
||||||
|
const Value &childValue = value[index];
|
||||||
|
writeCommentBeforeValue( childValue );
|
||||||
|
if ( hasChildValue )
|
||||||
|
writeWithIndent( childValues_[index] );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writeIndent();
|
||||||
|
writeValue( childValue );
|
||||||
|
}
|
||||||
|
if ( ++index == size )
|
||||||
|
{
|
||||||
|
writeCommentAfterValueOnSameLine( childValue );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
document_ += ",";
|
||||||
|
writeCommentAfterValueOnSameLine( childValue );
|
||||||
|
}
|
||||||
|
unindent();
|
||||||
|
writeWithIndent( "]" );
|
||||||
|
}
|
||||||
|
else // output on a single line
|
||||||
|
{
|
||||||
|
assert( childValues_.size() == size );
|
||||||
|
document_ += "[ ";
|
||||||
|
for ( unsigned index =0; index < size; ++index )
|
||||||
|
{
|
||||||
|
if ( index > 0 )
|
||||||
|
document_ += ", ";
|
||||||
|
document_ += childValues_[index];
|
||||||
|
}
|
||||||
|
document_ += " ]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
StyledWriter::isMultineArray( const Value &value )
|
||||||
|
{
|
||||||
|
int size = value.size();
|
||||||
|
bool isMultiLine = size*3 >= rightMargin_ ;
|
||||||
|
childValues_.clear();
|
||||||
|
for ( int index =0; index < size && !isMultiLine; ++index )
|
||||||
|
{
|
||||||
|
const Value &childValue = value[index];
|
||||||
|
isMultiLine = isMultiLine ||
|
||||||
|
( (childValue.isArray() || childValue.isObject()) &&
|
||||||
|
childValue.size() > 0 );
|
||||||
|
}
|
||||||
|
if ( !isMultiLine ) // check if line length > max line length
|
||||||
|
{
|
||||||
|
childValues_.reserve( size );
|
||||||
|
addChildValues_ = true;
|
||||||
|
int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
|
||||||
|
for ( int index =0; index < size && !isMultiLine; ++index )
|
||||||
|
{
|
||||||
|
writeValue( value[index] );
|
||||||
|
lineLength += int( childValues_[index].length() );
|
||||||
|
isMultiLine = isMultiLine && hasCommentForValue( value[index] );
|
||||||
|
}
|
||||||
|
addChildValues_ = false;
|
||||||
|
isMultiLine = isMultiLine || lineLength >= rightMargin_;
|
||||||
|
}
|
||||||
|
return isMultiLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StyledWriter::pushValue( const std::string &value )
|
||||||
|
{
|
||||||
|
if ( addChildValues_ )
|
||||||
|
childValues_.push_back( value );
|
||||||
|
else
|
||||||
|
document_ += value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StyledWriter::writeIndent()
|
||||||
|
{
|
||||||
|
if ( !document_.empty() )
|
||||||
|
{
|
||||||
|
char last = document_[document_.length()-1];
|
||||||
|
if ( last == ' ' ) // already indented
|
||||||
|
return;
|
||||||
|
if ( last != '\n' ) // Comments may add new-line
|
||||||
|
document_ += '\n';
|
||||||
|
}
|
||||||
|
document_ += indentString_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StyledWriter::writeWithIndent( const std::string &value )
|
||||||
|
{
|
||||||
|
writeIndent();
|
||||||
|
document_ += value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StyledWriter::indent()
|
||||||
|
{
|
||||||
|
indentString_ += std::string( indentSize_, ' ' );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StyledWriter::unindent()
|
||||||
|
{
|
||||||
|
assert( int(indentString_.size()) >= indentSize_ );
|
||||||
|
indentString_.resize( indentString_.size() - indentSize_ );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StyledWriter::writeCommentBeforeValue( const Value &root )
|
||||||
|
{
|
||||||
|
if ( !root.hasComment( commentBefore ) )
|
||||||
|
return;
|
||||||
|
document_ += normalizeEOL( root.getComment( commentBefore ) );
|
||||||
|
document_ += "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StyledWriter::writeCommentAfterValueOnSameLine( const Value &root )
|
||||||
|
{
|
||||||
|
if ( root.hasComment( commentAfterOnSameLine ) )
|
||||||
|
document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
|
||||||
|
|
||||||
|
if ( root.hasComment( commentAfter ) )
|
||||||
|
{
|
||||||
|
document_ += "\n";
|
||||||
|
document_ += normalizeEOL( root.getComment( commentAfter ) );
|
||||||
|
document_ += "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
StyledWriter::hasCommentForValue( const Value &value )
|
||||||
|
{
|
||||||
|
return value.hasComment( commentBefore )
|
||||||
|
|| value.hasComment( commentAfterOnSameLine )
|
||||||
|
|| value.hasComment( commentAfter );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string
|
||||||
|
StyledWriter::normalizeEOL( const std::string &text )
|
||||||
|
{
|
||||||
|
std::string normalized;
|
||||||
|
normalized.reserve( text.length() );
|
||||||
|
const char *begin = text.c_str();
|
||||||
|
const char *end = begin + text.length();
|
||||||
|
const char *current = begin;
|
||||||
|
while ( current != end )
|
||||||
|
{
|
||||||
|
char c = *current++;
|
||||||
|
if ( c == '\r' ) // mac or dos EOL
|
||||||
|
{
|
||||||
|
if ( *current == '\n' ) // convert dos EOL
|
||||||
|
++current;
|
||||||
|
normalized += '\n';
|
||||||
|
}
|
||||||
|
else // handle unix EOL & other char
|
||||||
|
normalized += c;
|
||||||
|
}
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Class StyledStreamWriter
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
StyledStreamWriter::StyledStreamWriter( std::string indentation )
|
||||||
|
: document_(NULL)
|
||||||
|
, rightMargin_( 74 )
|
||||||
|
, indentation_( indentation )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StyledStreamWriter::write( std::ostream &out, const Value &root )
|
||||||
|
{
|
||||||
|
document_ = &out;
|
||||||
|
addChildValues_ = false;
|
||||||
|
indentString_ = "";
|
||||||
|
writeCommentBeforeValue( root );
|
||||||
|
writeValue( root );
|
||||||
|
writeCommentAfterValueOnSameLine( root );
|
||||||
|
*document_ << "\n";
|
||||||
|
document_ = NULL; // Forget the stream, for safety.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StyledStreamWriter::writeValue( const Value &value )
|
||||||
|
{
|
||||||
|
switch ( value.type() )
|
||||||
|
{
|
||||||
|
case nullValue:
|
||||||
|
pushValue( "null" );
|
||||||
|
break;
|
||||||
|
case intValue:
|
||||||
|
pushValue( valueToString( value.asInt() ) );
|
||||||
|
break;
|
||||||
|
case uintValue:
|
||||||
|
pushValue( valueToString( value.asUInt() ) );
|
||||||
|
break;
|
||||||
|
case realValue:
|
||||||
|
pushValue( valueToString( value.asDouble() ) );
|
||||||
|
break;
|
||||||
|
case stringValue:
|
||||||
|
pushValue( valueToQuotedString( value.asCString() ) );
|
||||||
|
break;
|
||||||
|
case booleanValue:
|
||||||
|
pushValue( valueToString( value.asBool() ) );
|
||||||
|
break;
|
||||||
|
case arrayValue:
|
||||||
|
writeArrayValue( value);
|
||||||
|
break;
|
||||||
|
case objectValue:
|
||||||
|
{
|
||||||
|
Value::Members members( value.getMemberNames() );
|
||||||
|
if ( members.empty() )
|
||||||
|
pushValue( "{}" );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writeWithIndent( "{" );
|
||||||
|
indent();
|
||||||
|
Value::Members::iterator it = members.begin();
|
||||||
|
while ( true )
|
||||||
|
{
|
||||||
|
const std::string &name = *it;
|
||||||
|
const Value &childValue = value[name];
|
||||||
|
writeCommentBeforeValue( childValue );
|
||||||
|
writeWithIndent( valueToQuotedString( name.c_str() ) );
|
||||||
|
*document_ << " : ";
|
||||||
|
writeValue( childValue );
|
||||||
|
if ( ++it == members.end() )
|
||||||
|
{
|
||||||
|
writeCommentAfterValueOnSameLine( childValue );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*document_ << ",";
|
||||||
|
writeCommentAfterValueOnSameLine( childValue );
|
||||||
|
}
|
||||||
|
unindent();
|
||||||
|
writeWithIndent( "}" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StyledStreamWriter::writeArrayValue( const Value &value )
|
||||||
|
{
|
||||||
|
unsigned size = value.size();
|
||||||
|
if ( size == 0 )
|
||||||
|
pushValue( "[]" );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool isArrayMultiLine = isMultineArray( value );
|
||||||
|
if ( isArrayMultiLine )
|
||||||
|
{
|
||||||
|
writeWithIndent( "[" );
|
||||||
|
indent();
|
||||||
|
bool hasChildValue = !childValues_.empty();
|
||||||
|
unsigned index =0;
|
||||||
|
while ( true )
|
||||||
|
{
|
||||||
|
const Value &childValue = value[index];
|
||||||
|
writeCommentBeforeValue( childValue );
|
||||||
|
if ( hasChildValue )
|
||||||
|
writeWithIndent( childValues_[index] );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writeIndent();
|
||||||
|
writeValue( childValue );
|
||||||
|
}
|
||||||
|
if ( ++index == size )
|
||||||
|
{
|
||||||
|
writeCommentAfterValueOnSameLine( childValue );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*document_ << ",";
|
||||||
|
writeCommentAfterValueOnSameLine( childValue );
|
||||||
|
}
|
||||||
|
unindent();
|
||||||
|
writeWithIndent( "]" );
|
||||||
|
}
|
||||||
|
else // output on a single line
|
||||||
|
{
|
||||||
|
assert( childValues_.size() == size );
|
||||||
|
*document_ << "[ ";
|
||||||
|
for ( unsigned index =0; index < size; ++index )
|
||||||
|
{
|
||||||
|
if ( index > 0 )
|
||||||
|
*document_ << ", ";
|
||||||
|
*document_ << childValues_[index];
|
||||||
|
}
|
||||||
|
*document_ << " ]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
StyledStreamWriter::isMultineArray( const Value &value )
|
||||||
|
{
|
||||||
|
int size = value.size();
|
||||||
|
bool isMultiLine = size*3 >= rightMargin_ ;
|
||||||
|
childValues_.clear();
|
||||||
|
for ( int index =0; index < size && !isMultiLine; ++index )
|
||||||
|
{
|
||||||
|
const Value &childValue = value[index];
|
||||||
|
isMultiLine = isMultiLine ||
|
||||||
|
( (childValue.isArray() || childValue.isObject()) &&
|
||||||
|
childValue.size() > 0 );
|
||||||
|
}
|
||||||
|
if ( !isMultiLine ) // check if line length > max line length
|
||||||
|
{
|
||||||
|
childValues_.reserve( size );
|
||||||
|
addChildValues_ = true;
|
||||||
|
int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
|
||||||
|
for ( int index =0; index < size && !isMultiLine; ++index )
|
||||||
|
{
|
||||||
|
writeValue( value[index] );
|
||||||
|
lineLength += int( childValues_[index].length() );
|
||||||
|
isMultiLine = isMultiLine && hasCommentForValue( value[index] );
|
||||||
|
}
|
||||||
|
addChildValues_ = false;
|
||||||
|
isMultiLine = isMultiLine || lineLength >= rightMargin_;
|
||||||
|
}
|
||||||
|
return isMultiLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StyledStreamWriter::pushValue( const std::string &value )
|
||||||
|
{
|
||||||
|
if ( addChildValues_ )
|
||||||
|
childValues_.push_back( value );
|
||||||
|
else
|
||||||
|
*document_ << value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StyledStreamWriter::writeIndent()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Some comments in this method would have been nice. ;-)
|
||||||
|
|
||||||
|
if ( !document_.empty() )
|
||||||
|
{
|
||||||
|
char last = document_[document_.length()-1];
|
||||||
|
if ( last == ' ' ) // already indented
|
||||||
|
return;
|
||||||
|
if ( last != '\n' ) // Comments may add new-line
|
||||||
|
*document_ << '\n';
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
*document_ << '\n' << indentString_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StyledStreamWriter::writeWithIndent( const std::string &value )
|
||||||
|
{
|
||||||
|
writeIndent();
|
||||||
|
*document_ << value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StyledStreamWriter::indent()
|
||||||
|
{
|
||||||
|
indentString_ += indentation_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StyledStreamWriter::unindent()
|
||||||
|
{
|
||||||
|
assert( indentString_.size() >= indentation_.size() );
|
||||||
|
indentString_.resize( indentString_.size() - indentation_.size() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StyledStreamWriter::writeCommentBeforeValue( const Value &root )
|
||||||
|
{
|
||||||
|
if ( !root.hasComment( commentBefore ) )
|
||||||
|
return;
|
||||||
|
*document_ << normalizeEOL( root.getComment( commentBefore ) );
|
||||||
|
*document_ << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root )
|
||||||
|
{
|
||||||
|
if ( root.hasComment( commentAfterOnSameLine ) )
|
||||||
|
*document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
|
||||||
|
|
||||||
|
if ( root.hasComment( commentAfter ) )
|
||||||
|
{
|
||||||
|
*document_ << "\n";
|
||||||
|
*document_ << normalizeEOL( root.getComment( commentAfter ) );
|
||||||
|
*document_ << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
StyledStreamWriter::hasCommentForValue( const Value &value )
|
||||||
|
{
|
||||||
|
return value.hasComment( commentBefore )
|
||||||
|
|| value.hasComment( commentAfterOnSameLine )
|
||||||
|
|| value.hasComment( commentAfter );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string
|
||||||
|
StyledStreamWriter::normalizeEOL( const std::string &text )
|
||||||
|
{
|
||||||
|
std::string normalized;
|
||||||
|
normalized.reserve( text.length() );
|
||||||
|
const char *begin = text.c_str();
|
||||||
|
const char *end = begin + text.length();
|
||||||
|
const char *current = begin;
|
||||||
|
while ( current != end )
|
||||||
|
{
|
||||||
|
char c = *current++;
|
||||||
|
if ( c == '\r' ) // mac or dos EOL
|
||||||
|
{
|
||||||
|
if ( *current == '\n' ) // convert dos EOL
|
||||||
|
++current;
|
||||||
|
normalized += '\n';
|
||||||
|
}
|
||||||
|
else // handle unix EOL & other char
|
||||||
|
normalized += c;
|
||||||
|
}
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::ostream& operator<<( std::ostream &sout, const Value &root )
|
||||||
|
{
|
||||||
|
Json::StyledStreamWriter writer;
|
||||||
|
writer.write(sout, root);
|
||||||
|
return sout;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Json
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,130 @@
|
|||||||
|
//#include <windows.h>
|
||||||
|
//#include <winsock2.h>
|
||||||
|
//ws2_32.lib·¢ËÍhttpÇëÇóÀà¿â
|
||||||
|
#pragma comment(lib,"ws2_32.lib")
|
||||||
|
#include "autolink.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "features.h"
|
||||||
|
#include "forwards.h"
|
||||||
|
#include "json.h"
|
||||||
|
#include "reader.h"
|
||||||
|
#include "value.h"
|
||||||
|
#include "writer.h"
|
||||||
|
#include <lov\lov.h>
|
||||||
|
|
||||||
|
#include <ics\ics.h>
|
||||||
|
#include <ict/ict_userservice.h>
|
||||||
|
#include <atlstr.h>
|
||||||
|
#include <ATLComTime.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <tc\tc_macros.h>
|
||||||
|
#include <tc\emh.h>
|
||||||
|
#include <tc\preferences.h>
|
||||||
|
#include <property\propdesc.h>
|
||||||
|
#include <epm\epm.h>
|
||||||
|
#include <epm\epm_toolkit_tc_utils.h>
|
||||||
|
#include <tccore\item.h>
|
||||||
|
#include <tccore\grmtype.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
#include <tccore\grm.h>
|
||||||
|
//#include <tccore\imantype.h>
|
||||||
|
#include <sa\am.h>
|
||||||
|
#include <sa\sa.h>
|
||||||
|
#include <tccore\aom.h>
|
||||||
|
#include <tccore\aom_prop.h>
|
||||||
|
#include <property\prop_errors.h>
|
||||||
|
#include <tccore\workspaceobject.h>
|
||||||
|
#include <qry\qry.h>
|
||||||
|
#include <bom\bom_attr.h>
|
||||||
|
#include <bom\bom.h>
|
||||||
|
#include <epm\signoff.h>
|
||||||
|
#include <pom\pom\pom.h>
|
||||||
|
#include <pom\pom\pom_errors.h>
|
||||||
|
#include <fclasses\tc_date.h>
|
||||||
|
#include <epm\cr.h>
|
||||||
|
#include <cfm\cfm.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <ae/ae.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include <iterator>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <vector>
|
||||||
|
#include <sstream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <res\reservation.h>
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <io.h>
|
||||||
|
#include <direct.h>
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DOFREE(obj) \
|
||||||
|
{ \
|
||||||
|
if(obj) \
|
||||||
|
{ \
|
||||||
|
MEM_free(obj); \
|
||||||
|
obj = NULL; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int POM_AM__set_application_bypass(logical bypass);
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
bool copyFile(const char *SRC, const char* DEST);
|
||||||
|
|
||||||
|
void initUserDir(char *userId);
|
||||||
|
int export_dataset_file_to_dir(bool debug,tag_t dataset, const char *ref_name,const char* temp_path, char *ext, char **filename, char **original_name);
|
||||||
|
void CreateLogFile(char* FunctionName, char *userId, char **fullname);
|
||||||
|
int CreateTempFile(logical debug,const char* temp_path, char *file_name, char* ext, char **fullname,FILE **file);
|
||||||
|
int CreateTempFile(logical debug,const char* temp_path, char *file_name, char* user_id, char* ext, char **fullname,FILE **file);
|
||||||
|
void CloseLog(void);
|
||||||
|
void WriteLog2(logical debug, const char* format, ...);
|
||||||
|
void WriteLog(logical debug, const char* format, ...);
|
||||||
|
void set_bypass(logical bypass);
|
||||||
|
char* G2U(const char* gb2312);
|
||||||
|
char* U2G(const char* utf8);
|
||||||
|
int getPrefStrings(const char *preference, TC_preference_search_scope_t scope, vector<string> &pref_vec);
|
||||||
|
int export_dataset_file(bool debug, tag_t dataset,const char *ref_name,char *userId, char *ext, char **filename, char **original_name);
|
||||||
|
int GetBomView(tag_t rev_tag, char* viewtype, tag_t *bomView, tag_t *bomBVR, bool debug);
|
||||||
|
int GetBomLinePropString(bool debug, tag_t line, char* propName, int errCode, char** attr_val);
|
||||||
|
void Split(string strArg, char spliter, vector<string> &ans);
|
||||||
|
void Split(string strArg, string spliter, vector<string> &ans);
|
||||||
|
int getPrefStrings2(const char *preference, TC_preference_search_scope_t scope, char splitter, vector<string> &pref_vec);
|
||||||
|
int import_dataset_file(tag_t dataset, const char *ref_name, char *ext, char *fullfilename, char *original_name);
|
||||||
|
int import_dataset_file_binary(tag_t dataset, const char* temp_path, const char *ref_name, char *ext, char *fullfilename, char *original_name);
|
||||||
|
int readError(bool debug, char *errFilePath, int errCode);
|
||||||
|
void deleteFile(bool debug, char *path);
|
||||||
|
bool CheckType(string config, char* type, char spliter);
|
||||||
|
bool propExist(bool debug, tag_t obj, const char *propName);
|
||||||
|
bool isRev(char* object_type);
|
||||||
|
int GetProcessTargets(bool debug, int att_cnt, tag_t *attachments, vector<tag_t> &targets,char* formType,char splitter);
|
||||||
|
bool inArray(vector<string> types, string type);
|
||||||
|
int getIndexInArray(vector<string> types, string type);
|
||||||
|
int findUser(bool debug,string userStr,tag_t *user_tag);
|
||||||
|
bool isType(tag_t item,char* type);
|
||||||
|
int CreateUserFile(logical debug,char* FunctionName, char *userId, char **fullname,FILE **file);
|
||||||
|
int WriteToFile(logical debug,FILE* file, const char* format, ...);
|
||||||
|
bool isTypeOf(tag_t objtag, const char * type_name);
|
||||||
|
int connor_set_prop_value(char* propname, const char* propvalue, tag_t &tag_instance);
|
||||||
|
int getLast2Year(char* &year);
|
||||||
|
void getCurrentTime(date_t * now);
|
||||||
|
bool find_prop(int prop_cnt, char** props, const char* prop);
|
||||||
|
string readFileIntoString(char * filename);
|
||||||
|
map<string, string> jsonstr2map(const string& json);
|
||||||
|
bool exists_test0(const std::string& name);
|
||||||
|
int export_dataset_file(tag_t dataset, char *ref_name, char *ext, char **filename, char **original_name);
|
||||||
|
bool is_str_utf8(const char* str);
|
||||||
|
int write_string_to_file_append(const std::string & file_string, const std::string str);
|
||||||
|
char* getfileall(const char* fname);
|
||||||
|
//BOOL GetIpByDomainName(char *szHost, char* szIp);
|
||||||
|
//void sendGetRequest();
|
||||||
@ -0,0 +1,99 @@
|
|||||||
|
#pragma once
|
||||||
|
/*=====================================================================================================================
|
||||||
|
Copyright(c) 2012 ORIGIN.
|
||||||
|
Unpublished - All rights reserved
|
||||||
|
=======================================================================================================================
|
||||||
|
File description:
|
||||||
|
|
||||||
|
Filename: ocilib.h
|
||||||
|
Module : OCI
|
||||||
|
|
||||||
|
This Header file of OCI library Package.
|
||||||
|
|
||||||
|
=======================================================================================================================
|
||||||
|
Date Name Description of Change
|
||||||
|
1-Feb-2015 Ray Initialize creation
|
||||||
|
$HISTORY$
|
||||||
|
=====================================================================================================================*/
|
||||||
|
#include <oci.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <memory.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
//#include <limits.h>
|
||||||
|
|
||||||
|
#define OCI_FAIL 1
|
||||||
|
#define OCI_OK 0
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
/**
|
||||||
|
* 连接数据库.
|
||||||
|
* @param username - <I> 用户名
|
||||||
|
* @param password - <I> 密码
|
||||||
|
* @param dbname - <I> 数据库SID
|
||||||
|
* @return - OCI_OK or error code
|
||||||
|
*
|
||||||
|
* ORACLE 数据库的连接与封装函数
|
||||||
|
*/
|
||||||
|
extern int ConnServer(char* username, char* password, char* dbname);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 不带输入参数的执行SQL语句.
|
||||||
|
* @param SQL - <I> SQL语句
|
||||||
|
* @return - OCI_OK or error code
|
||||||
|
*
|
||||||
|
* ORACLE 数据库的连接与封装函数
|
||||||
|
*/
|
||||||
|
extern int ExecuteSQLNoInputParam(char* SQL);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 带输入参数的执行SQL语句.
|
||||||
|
* @param SQL - <I> SQL语句
|
||||||
|
* @param inputValueCount - <I> 输入参数数量
|
||||||
|
* @param inputValue - <I> 输入参数值
|
||||||
|
* @return - OCI_OK or error code
|
||||||
|
*
|
||||||
|
* ORACLE 数据库的连接与封装函数
|
||||||
|
*/
|
||||||
|
extern int ExecuteSQL(char* SQL, int inputValueCount, char** inputValue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 不带输入参数的查询SQL语句.
|
||||||
|
* @param SQL - <I> SQL语句
|
||||||
|
* @param outputColumn - <O> 输出表的列的数量
|
||||||
|
* @param outputValueCount - <O> 输出表的行的数量
|
||||||
|
* @param outputValue - <O> 输出表内容
|
||||||
|
* @return - OCI_OK or error code
|
||||||
|
*
|
||||||
|
* ORACLE 数据库的连接与封装函数
|
||||||
|
*/
|
||||||
|
extern int QuerySQLNoInputParam(char* SQL, int* outputColumn, int* outputValueCount, char**** outputValue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 带输入参数的查询SQL语句.
|
||||||
|
* @param SQL - <I> SQL语句
|
||||||
|
* @param inputValueCount - <I> 输入参数数量
|
||||||
|
* @param inputValue - <I> 输入参数值
|
||||||
|
* @param outputColumn - <O> 输出表的列的数量
|
||||||
|
* @param outputValueCount - <O> 输出表的行的数量
|
||||||
|
* @param outputValue - <O> 输出表内容
|
||||||
|
* @return - OCI_OK or error code
|
||||||
|
*
|
||||||
|
* ORACLE 数据库的连接与封装函数
|
||||||
|
*/
|
||||||
|
extern int QuerySQL(char* SQL, int inputValueCount, char** inputValue, int* outputColumn, int* outputValueCount, char**** outputValue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 断开数据库连接.
|
||||||
|
*
|
||||||
|
* ORACLE 数据库的连接与封装函数
|
||||||
|
*/
|
||||||
|
extern void DisConnServer();
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
#include <server_exits/user_server_exits.h>
|
||||||
|
#include <tccore/custom.h>
|
||||||
|
#include <tc/tc_macros.h>
|
||||||
|
#include <tccore/tc_msg.h>
|
||||||
|
#include <epm\epm.h>
|
||||||
|
|
||||||
|
extern DLLAPI int K_register_handlers(int *, va_list);
|
||||||
|
extern DLLAPI int K_register_methods();
|
||||||
@ -0,0 +1,196 @@
|
|||||||
|
#ifndef CPPTL_JSON_READER_H_INCLUDED
|
||||||
|
# define CPPTL_JSON_READER_H_INCLUDED
|
||||||
|
|
||||||
|
# include "features.h"
|
||||||
|
# include "value.h"
|
||||||
|
# include <deque>
|
||||||
|
# include <stack>
|
||||||
|
# include <string>
|
||||||
|
# include <iostream>
|
||||||
|
|
||||||
|
namespace Json {
|
||||||
|
|
||||||
|
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a Value.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class JSON_API Reader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef char Char;
|
||||||
|
typedef const Char *Location;
|
||||||
|
|
||||||
|
/** \brief Constructs a Reader allowing all features
|
||||||
|
* for parsing.
|
||||||
|
*/
|
||||||
|
Reader();
|
||||||
|
|
||||||
|
/** \brief Constructs a Reader allowing the specified feature set
|
||||||
|
* for parsing.
|
||||||
|
*/
|
||||||
|
Reader( const Features &features );
|
||||||
|
|
||||||
|
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
|
||||||
|
* \param document UTF-8 encoded string containing the document to read.
|
||||||
|
* \param root [out] Contains the root value of the document if it was
|
||||||
|
* successfully parsed.
|
||||||
|
* \param collectComments \c true to collect comment and allow writing them back during
|
||||||
|
* serialization, \c false to discard comments.
|
||||||
|
* This parameter is ignored if Features::allowComments_
|
||||||
|
* is \c false.
|
||||||
|
* \return \c true if the document was successfully parsed, \c false if an error occurred.
|
||||||
|
*/
|
||||||
|
bool parse( const std::string &document,
|
||||||
|
Value &root,
|
||||||
|
bool collectComments = true );
|
||||||
|
|
||||||
|
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
|
||||||
|
* \param document UTF-8 encoded string containing the document to read.
|
||||||
|
* \param root [out] Contains the root value of the document if it was
|
||||||
|
* successfully parsed.
|
||||||
|
* \param collectComments \c true to collect comment and allow writing them back during
|
||||||
|
* serialization, \c false to discard comments.
|
||||||
|
* This parameter is ignored if Features::allowComments_
|
||||||
|
* is \c false.
|
||||||
|
* \return \c true if the document was successfully parsed, \c false if an error occurred.
|
||||||
|
*/
|
||||||
|
bool parse( const char *beginDoc, const char *endDoc,
|
||||||
|
Value &root,
|
||||||
|
bool collectComments = true );
|
||||||
|
|
||||||
|
/// \brief Parse from input stream.
|
||||||
|
/// \see Json::operator>>(std::istream&, Json::Value&).
|
||||||
|
bool parse( std::istream &is,
|
||||||
|
Value &root,
|
||||||
|
bool collectComments = true );
|
||||||
|
|
||||||
|
/** \brief Returns a user friendly string that list errors in the parsed document.
|
||||||
|
* \return Formatted error message with the list of errors with their location in
|
||||||
|
* the parsed document. An empty string is returned if no error occurred
|
||||||
|
* during parsing.
|
||||||
|
*/
|
||||||
|
std::string getFormatedErrorMessages() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum TokenType
|
||||||
|
{
|
||||||
|
tokenEndOfStream = 0,
|
||||||
|
tokenObjectBegin,
|
||||||
|
tokenObjectEnd,
|
||||||
|
tokenArrayBegin,
|
||||||
|
tokenArrayEnd,
|
||||||
|
tokenString,
|
||||||
|
tokenNumber,
|
||||||
|
tokenTrue,
|
||||||
|
tokenFalse,
|
||||||
|
tokenNull,
|
||||||
|
tokenArraySeparator,
|
||||||
|
tokenMemberSeparator,
|
||||||
|
tokenComment,
|
||||||
|
tokenError
|
||||||
|
};
|
||||||
|
|
||||||
|
class Token
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TokenType type_;
|
||||||
|
Location start_;
|
||||||
|
Location end_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ErrorInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Token token_;
|
||||||
|
std::string message_;
|
||||||
|
Location extra_;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::deque<ErrorInfo> Errors;
|
||||||
|
|
||||||
|
bool expectToken( TokenType type, Token &token, const char *message );
|
||||||
|
bool readToken( Token &token );
|
||||||
|
void skipSpaces();
|
||||||
|
bool match( Location pattern,
|
||||||
|
int patternLength );
|
||||||
|
bool readComment();
|
||||||
|
bool readCStyleComment();
|
||||||
|
bool readCppStyleComment();
|
||||||
|
bool readString();
|
||||||
|
void readNumber();
|
||||||
|
bool readValue();
|
||||||
|
bool readObject( Token &token );
|
||||||
|
bool readArray( Token &token );
|
||||||
|
bool decodeNumber( Token &token );
|
||||||
|
bool decodeString( Token &token );
|
||||||
|
bool decodeString( Token &token, std::string &decoded );
|
||||||
|
bool decodeDouble( Token &token );
|
||||||
|
bool decodeUnicodeCodePoint( Token &token,
|
||||||
|
Location ¤t,
|
||||||
|
Location end,
|
||||||
|
unsigned int &unicode );
|
||||||
|
bool decodeUnicodeEscapeSequence( Token &token,
|
||||||
|
Location ¤t,
|
||||||
|
Location end,
|
||||||
|
unsigned int &unicode );
|
||||||
|
bool addError( const std::string &message,
|
||||||
|
Token &token,
|
||||||
|
Location extra = 0 );
|
||||||
|
bool recoverFromError( TokenType skipUntilToken );
|
||||||
|
bool addErrorAndRecover( const std::string &message,
|
||||||
|
Token &token,
|
||||||
|
TokenType skipUntilToken );
|
||||||
|
void skipUntilSpace();
|
||||||
|
Value ¤tValue();
|
||||||
|
Char getNextChar();
|
||||||
|
void getLocationLineAndColumn( Location location,
|
||||||
|
int &line,
|
||||||
|
int &column ) const;
|
||||||
|
std::string getLocationLineAndColumn( Location location ) const;
|
||||||
|
void addComment( Location begin,
|
||||||
|
Location end,
|
||||||
|
CommentPlacement placement );
|
||||||
|
void skipCommentTokens( Token &token );
|
||||||
|
|
||||||
|
typedef std::stack<Value *> Nodes;
|
||||||
|
Nodes nodes_;
|
||||||
|
Errors errors_;
|
||||||
|
std::string document_;
|
||||||
|
Location begin_;
|
||||||
|
Location end_;
|
||||||
|
Location current_;
|
||||||
|
Location lastValueEnd_;
|
||||||
|
Value *lastValue_;
|
||||||
|
std::string commentsBefore_;
|
||||||
|
Features features_;
|
||||||
|
bool collectComments_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief Read from 'sin' into 'root'.
|
||||||
|
|
||||||
|
Always keep comments from the input JSON.
|
||||||
|
|
||||||
|
This can be used to read a file into a particular sub-object.
|
||||||
|
For example:
|
||||||
|
\code
|
||||||
|
Json::Value root;
|
||||||
|
cin >> root["dir"]["file"];
|
||||||
|
cout << root;
|
||||||
|
\endcode
|
||||||
|
Result:
|
||||||
|
\verbatim
|
||||||
|
{
|
||||||
|
"dir": {
|
||||||
|
"file": {
|
||||||
|
// The input stream JSON would be nested here.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
\endverbatim
|
||||||
|
\throw std::exception on parse error.
|
||||||
|
\see Json::operator<<()
|
||||||
|
*/
|
||||||
|
std::istream& operator>>( std::istream&, Value& );
|
||||||
|
|
||||||
|
} // namespace Json
|
||||||
|
|
||||||
|
#endif // CPPTL_JSON_READER_H_INCLUDED
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
Import( 'env buildLibrary' )
|
||||||
|
|
||||||
|
buildLibrary( env, Split( """
|
||||||
|
json_reader.cpp
|
||||||
|
json_value.cpp
|
||||||
|
json_writer.cpp
|
||||||
|
""" ),
|
||||||
|
'json' )
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,174 @@
|
|||||||
|
#ifndef JSON_WRITER_H_INCLUDED
|
||||||
|
# define JSON_WRITER_H_INCLUDED
|
||||||
|
|
||||||
|
# include "value.h"
|
||||||
|
# include <vector>
|
||||||
|
# include <string>
|
||||||
|
# include <iostream>
|
||||||
|
|
||||||
|
namespace Json {
|
||||||
|
|
||||||
|
class Value;
|
||||||
|
|
||||||
|
/** \brief Abstract class for writers.
|
||||||
|
*/
|
||||||
|
class JSON_API Writer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~Writer();
|
||||||
|
|
||||||
|
virtual std::string write( const Value &root ) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format without formatting (not human friendly).
|
||||||
|
*
|
||||||
|
* The JSON document is written in a single line. It is not intended for 'human' consumption,
|
||||||
|
* but may be usefull to support feature such as RPC where bandwith is limited.
|
||||||
|
* \sa Reader, Value
|
||||||
|
*/
|
||||||
|
class JSON_API FastWriter : public Writer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FastWriter();
|
||||||
|
virtual ~FastWriter(){}
|
||||||
|
|
||||||
|
void enableYAMLCompatibility();
|
||||||
|
|
||||||
|
public: // overridden from Writer
|
||||||
|
virtual std::string write( const Value &root );
|
||||||
|
|
||||||
|
private:
|
||||||
|
void writeValue( const Value &value );
|
||||||
|
|
||||||
|
std::string document_;
|
||||||
|
bool yamlCompatiblityEnabled_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way.
|
||||||
|
*
|
||||||
|
* The rules for line break and indent are as follow:
|
||||||
|
* - Object value:
|
||||||
|
* - if empty then print {} without indent and line break
|
||||||
|
* - if not empty the print '{', line break & indent, print one value per line
|
||||||
|
* and then unindent and line break and print '}'.
|
||||||
|
* - Array value:
|
||||||
|
* - if empty then print [] without indent and line break
|
||||||
|
* - if the array contains no object value, empty array or some other value types,
|
||||||
|
* and all the values fit on one lines, then print the array on a single line.
|
||||||
|
* - otherwise, it the values do not fit on one line, or the array contains
|
||||||
|
* object or non empty array, then print one value per line.
|
||||||
|
*
|
||||||
|
* If the Value have comments then they are outputed according to their #CommentPlacement.
|
||||||
|
*
|
||||||
|
* \sa Reader, Value, Value::setComment()
|
||||||
|
*/
|
||||||
|
class JSON_API StyledWriter: public Writer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StyledWriter();
|
||||||
|
virtual ~StyledWriter(){}
|
||||||
|
|
||||||
|
public: // overridden from Writer
|
||||||
|
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
|
||||||
|
* \param root Value to serialize.
|
||||||
|
* \return String containing the JSON document that represents the root value.
|
||||||
|
*/
|
||||||
|
virtual std::string write( const Value &root );
|
||||||
|
|
||||||
|
private:
|
||||||
|
void writeValue( const Value &value );
|
||||||
|
void writeArrayValue( const Value &value );
|
||||||
|
bool isMultineArray( const Value &value );
|
||||||
|
void pushValue( const std::string &value );
|
||||||
|
void writeIndent();
|
||||||
|
void writeWithIndent( const std::string &value );
|
||||||
|
void indent();
|
||||||
|
void unindent();
|
||||||
|
void writeCommentBeforeValue( const Value &root );
|
||||||
|
void writeCommentAfterValueOnSameLine( const Value &root );
|
||||||
|
bool hasCommentForValue( const Value &value );
|
||||||
|
static std::string normalizeEOL( const std::string &text );
|
||||||
|
|
||||||
|
typedef std::vector<std::string> ChildValues;
|
||||||
|
|
||||||
|
ChildValues childValues_;
|
||||||
|
std::string document_;
|
||||||
|
std::string indentString_;
|
||||||
|
int rightMargin_;
|
||||||
|
int indentSize_;
|
||||||
|
bool addChildValues_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way,
|
||||||
|
to a stream rather than to a string.
|
||||||
|
*
|
||||||
|
* The rules for line break and indent are as follow:
|
||||||
|
* - Object value:
|
||||||
|
* - if empty then print {} without indent and line break
|
||||||
|
* - if not empty the print '{', line break & indent, print one value per line
|
||||||
|
* and then unindent and line break and print '}'.
|
||||||
|
* - Array value:
|
||||||
|
* - if empty then print [] without indent and line break
|
||||||
|
* - if the array contains no object value, empty array or some other value types,
|
||||||
|
* and all the values fit on one lines, then print the array on a single line.
|
||||||
|
* - otherwise, it the values do not fit on one line, or the array contains
|
||||||
|
* object or non empty array, then print one value per line.
|
||||||
|
*
|
||||||
|
* If the Value have comments then they are outputed according to their #CommentPlacement.
|
||||||
|
*
|
||||||
|
* \param indentation Each level will be indented by this amount extra.
|
||||||
|
* \sa Reader, Value, Value::setComment()
|
||||||
|
*/
|
||||||
|
class JSON_API StyledStreamWriter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StyledStreamWriter( std::string indentation="\t" );
|
||||||
|
~StyledStreamWriter(){}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
|
||||||
|
* \param out Stream to write to. (Can be ostringstream, e.g.)
|
||||||
|
* \param root Value to serialize.
|
||||||
|
* \note There is no point in deriving from Writer, since write() should not return a value.
|
||||||
|
*/
|
||||||
|
void write( std::ostream &out, const Value &root );
|
||||||
|
|
||||||
|
private:
|
||||||
|
void writeValue( const Value &value );
|
||||||
|
void writeArrayValue( const Value &value );
|
||||||
|
bool isMultineArray( const Value &value );
|
||||||
|
void pushValue( const std::string &value );
|
||||||
|
void writeIndent();
|
||||||
|
void writeWithIndent( const std::string &value );
|
||||||
|
void indent();
|
||||||
|
void unindent();
|
||||||
|
void writeCommentBeforeValue( const Value &root );
|
||||||
|
void writeCommentAfterValueOnSameLine( const Value &root );
|
||||||
|
bool hasCommentForValue( const Value &value );
|
||||||
|
static std::string normalizeEOL( const std::string &text );
|
||||||
|
|
||||||
|
typedef std::vector<std::string> ChildValues;
|
||||||
|
|
||||||
|
ChildValues childValues_;
|
||||||
|
std::ostream* document_;
|
||||||
|
std::string indentString_;
|
||||||
|
int rightMargin_;
|
||||||
|
std::string indentation_;
|
||||||
|
bool addChildValues_;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string JSON_API valueToString( Int value );
|
||||||
|
std::string JSON_API valueToString( UInt value );
|
||||||
|
std::string JSON_API valueToString( double value );
|
||||||
|
std::string JSON_API valueToString( bool value );
|
||||||
|
std::string JSON_API valueToQuotedString( const char *value );
|
||||||
|
|
||||||
|
/// \brief Output using the StyledStreamWriter.
|
||||||
|
/// \see Json::operator>>()
|
||||||
|
std::ostream& operator<<( std::ostream&, const Value &root );
|
||||||
|
|
||||||
|
} // namespace Json
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JSON_WRITER_H_INCLUDED
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,19 @@
|
|||||||
|
c:\users\89512\desktop\美菱\meling_itk\connor_signature\x64\release\vc140.pdb
|
||||||
|
c:\users\89512\desktop\美菱\meling_itk\connor_signature\x64\release\qf8_handlers.obj
|
||||||
|
c:\users\89512\desktop\美菱\meling_itk\connor_signature\x64\release\kutil.obj
|
||||||
|
c:\users\89512\desktop\美菱\meling_itk\connor_signature\x64\release\connor_sign_pre_revision.obj
|
||||||
|
c:\users\89512\desktop\美菱\meling_itk\connor_signature\x64\release\connor_sign_master.obj
|
||||||
|
c:\users\89512\desktop\美菱\meling_itk\connor_signature\x64\release\connor_sign_dataset.obj
|
||||||
|
c:\users\89512\desktop\美菱\meling_itk\connor_signature\x64\release\connor_signature.obj
|
||||||
|
c:\users\89512\desktop\美菱\meling_itk\connor_signature\x64\release\connor_revise_clear_master.obj
|
||||||
|
c:\users\89512\desktop\美菱\meling_itk\connor_signature\x64\release\connor_avic_catiasign.obj
|
||||||
|
c:\users\89512\desktop\美菱\meling_itk\connor_signature\x64\release\connor_add_release_status.obj
|
||||||
|
c:\users\89512\desktop\美菱\meling_itk\connor_signature\x64\release\ado.obj
|
||||||
|
c:\users\89512\desktop\美菱\meling_itk\connor_signature\x64\release\msado15.tli
|
||||||
|
c:\users\89512\desktop\美菱\meling_itk\connor_signature\x64\release\msado15.tlh
|
||||||
|
c:\users\89512\desktop\美菱\meling_itk\connor_signature\x64\release\connor_signature.tlog\cl.command.1.tlog
|
||||||
|
c:\users\89512\desktop\美菱\meling_itk\connor_signature\x64\release\connor_signature.tlog\cl.read.1.tlog
|
||||||
|
c:\users\89512\desktop\美菱\meling_itk\connor_signature\x64\release\connor_signature.tlog\cl.write.1.tlog
|
||||||
|
c:\users\89512\desktop\美菱\meling_itk\connor_signature\x64\release\connor_signature.tlog\link.command.1.tlog
|
||||||
|
c:\users\89512\desktop\美菱\meling_itk\connor_signature\x64\release\connor_signature.tlog\link.read.1.tlog
|
||||||
|
c:\users\89512\desktop\美菱\meling_itk\connor_signature\x64\release\connor_signature.tlog\link.write.1.tlog
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
#v4.0:v110:false
|
||||||
|
Release|x64|C:\code\connor_signature\|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,2 @@
|
|||||||
|
#TargetFrameworkVersion=v4.0:PlatformToolSet=v140:EnableManagedIncrementalBuild=false:VCToolArchitecture=Native32Bit:WindowsTargetPlatformVersion=8.1
|
||||||
|
Release|x64|C:\Users\89512\Desktop\美菱\meling_itk\|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,43 @@
|
|||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\vc142.pdb
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\ocilib.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\ld_taskassignmentdate.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\ld_sendecrecn_tosapmes.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\ld_senddjjdd_to_mes.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\ld_partcompflag.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\ld_partchange.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\ld_gylxfrozen.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\ld_formattrtoexcel.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\ld_completiondate.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\ld_ecn01_setcicnformproperty.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\ld_autoassign.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\connor_elevatetask.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\json_writer.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\json_value.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\json_reader.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\connor_review_person.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\connor_allow_workflow.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\ado.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\addlb.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\a.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\upgradetask.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\test.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\sh_plm_email.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\send_sap_material.cpp.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\send_sap_bom.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\kutil.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\raycus_itk.obj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\x64\release\ld_itk_c.lib
|
||||||
|
d:\source\联德\itk\ld_itk(1)\x64\release\ld_itk_c.exp
|
||||||
|
d:\source\联德\itk\ld_itk(1)\x64\release\ld_itk_c.dll
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\ld_itk_c.ipdb
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\ld_itk_c.iobj
|
||||||
|
d:\source\联德\itk\ld_itk(1)\x64\release\ld_itk_c.pdb
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\msado15.tli
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\msado15.tlh
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\ld_itk_c.tlog\cl.command.1.tlog
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\ld_itk_c.tlog\cl.read.1.tlog
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\ld_itk_c.tlog\cl.write.1.tlog
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\ld_itk_c.tlog\ld_itk_c.write.1u.tlog
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\ld_itk_c.tlog\link.command.1.tlog
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\ld_itk_c.tlog\link.read.1.tlog
|
||||||
|
d:\source\联德\itk\ld_itk(1)\connor_signature\x64\release\ld_itk_c.tlog\link.write.1.tlog
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project>
|
||||||
|
<ProjectOutputs>
|
||||||
|
<ProjectOutput>
|
||||||
|
<FullPath>D:\source\联德\itk\ld_itk(1)\x64\Release\ld_itk_c.dll</FullPath>
|
||||||
|
</ProjectOutput>
|
||||||
|
</ProjectOutputs>
|
||||||
|
<ContentFiles />
|
||||||
|
<SatelliteDlls />
|
||||||
|
<NonRecipeFileRefs />
|
||||||
|
</Project>
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue