698 lines
20 KiB
C++
698 lines
20 KiB
C++
#include "Json_Utilities.hpp"
|
|
|
|
extern "C"
|
|
{
|
|
#include "stdio.h"
|
|
#include "stdlib.h"
|
|
}
|
|
|
|
#include "functional"
|
|
|
|
/**
|
|
* @brief Json文件 格式检查
|
|
* @param path_to_file 文件路径串
|
|
* @return std::string 错误值
|
|
*/
|
|
std::string JsonFile_FormatCheck(const char *path_to_file)
|
|
{
|
|
// 尝试打开文件
|
|
FILE *pFile = fopen(path_to_file, "rb");
|
|
if (pFile == nullptr)
|
|
return "file \"" + std::string(path_to_file) + "\" open failed.";
|
|
|
|
// 行列计数
|
|
size_t rol_count = 1;
|
|
size_t column_count = 0;
|
|
std::string err_str;
|
|
|
|
// 跳过空白部分 return -> skip count
|
|
auto Lambda_skip_blank = [&](void) -> size_t
|
|
{
|
|
size_t read_count = 0;
|
|
while (true)
|
|
{
|
|
switch (fgetc(pFile))
|
|
{
|
|
case EOF:
|
|
return read_count;
|
|
case ' ':
|
|
column_count++;
|
|
read_count++;
|
|
break;
|
|
case '\r':
|
|
if (fgetc(pFile) == '\n')
|
|
{
|
|
read_count += 2;
|
|
rol_count++;
|
|
column_count = 0;
|
|
}
|
|
else
|
|
{
|
|
fseek(pFile, -2, SEEK_CUR);
|
|
return read_count;
|
|
}
|
|
break;
|
|
case '\n':
|
|
read_count++;
|
|
rol_count++;
|
|
column_count = 0;
|
|
break;
|
|
default:
|
|
fseek(pFile, -1, SEEK_CUR);
|
|
return read_count;
|
|
}
|
|
}
|
|
};
|
|
|
|
// 函数封装
|
|
std::function<std::string(void)> Check_Object;
|
|
std::function<std::string(void)> Check_Value;
|
|
std::function<std::string(void)> Check_Arry;
|
|
std::function<std::string(void)> Check_Pair;
|
|
|
|
// 函数定义
|
|
Check_Object = [&](void) -> std::string
|
|
{
|
|
Lambda_skip_blank();
|
|
|
|
char ch_get = fgetc(pFile);
|
|
if (ch_get != '{')
|
|
{
|
|
if (ch_get == EOF)
|
|
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
|
|
else
|
|
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected '" + ch_get + "'.";
|
|
}
|
|
column_count++;
|
|
|
|
while (true)
|
|
{
|
|
Lambda_skip_blank();
|
|
ch_get = fgetc(pFile);
|
|
column_count++;
|
|
|
|
switch (ch_get)
|
|
{
|
|
case '}':
|
|
return std::string();
|
|
case '\"':
|
|
fseek(pFile, -1, SEEK_CUR);
|
|
column_count--;
|
|
{
|
|
std::string err_str = Check_Pair();
|
|
if (!err_str.empty())
|
|
return err_str;
|
|
|
|
// 结束后读取段
|
|
size_t now_rol_count = rol_count;
|
|
size_t now_column_count = column_count;
|
|
|
|
Lambda_skip_blank();
|
|
char ch_get = fgetc(pFile);
|
|
if ((ch_get != '}') && (ch_get != ','))
|
|
{
|
|
if (ch_get == ']')
|
|
return std::string(path_to_file) + ':' + std::to_string(now_rol_count) + ':' + std::to_string(now_column_count) + ": Missing '}'.";
|
|
else if (ch_get == EOF)
|
|
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
|
|
else
|
|
return std::string(path_to_file) + ':' + std::to_string(now_rol_count) + ':' + std::to_string(now_column_count) + ": Missing comma.";
|
|
}
|
|
fseek(pFile, -1, SEEK_CUR);
|
|
}
|
|
break;
|
|
case ',':
|
|
{
|
|
size_t now_rol_count = rol_count;
|
|
size_t now_column_count = column_count;
|
|
|
|
Lambda_skip_blank();
|
|
|
|
if (fgetc(pFile) != '\"')
|
|
return std::string(path_to_file) + ':' + std::to_string(now_rol_count) + ':' + std::to_string(now_column_count) + ": Unexpected ','.";
|
|
fseek(pFile, -1, SEEK_CUR);
|
|
break;
|
|
}
|
|
case EOF:
|
|
return std::string(path_to_file) + ':' + std::to_string(rol_count - 1) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
|
|
default:
|
|
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected '" + ch_get + "'.";
|
|
}
|
|
}
|
|
};
|
|
|
|
Check_Value = [&](void) -> std::string
|
|
{
|
|
Lambda_skip_blank();
|
|
|
|
size_t begin_rol = rol_count;
|
|
size_t begin_column = column_count;
|
|
|
|
bool is_string = false;
|
|
char ch_get = fgetc(pFile);
|
|
|
|
// 判定第一个字符
|
|
switch (ch_get)
|
|
{
|
|
case EOF:
|
|
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
|
|
case '\"':
|
|
is_string = true;
|
|
break;
|
|
case '{':
|
|
fseek(pFile, -1, SEEK_CUR);
|
|
return Check_Object();
|
|
case '[':
|
|
fseek(pFile, -1, SEEK_CUR);
|
|
return Check_Arry();
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// 判定为字符串
|
|
if (is_string)
|
|
{
|
|
column_count++;
|
|
while (true)
|
|
{
|
|
ch_get = fgetc(pFile);
|
|
column_count++;
|
|
switch (ch_get)
|
|
{
|
|
case '\"':
|
|
return std::string();
|
|
case '\\': // 转义符
|
|
ch_get = fgetc(pFile);
|
|
if (ch_get != EOF)
|
|
{
|
|
column_count++;
|
|
continue;
|
|
}
|
|
case EOF:
|
|
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
|
|
case '\n':
|
|
return std::string(path_to_file) + ':' + std::to_string(begin_rol) + ':' + std::to_string(begin_column) + ": Unfinished string.";
|
|
default:
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
fseek(pFile, -1, SEEK_CUR);
|
|
|
|
// 识别有效数值
|
|
|
|
std::string segment_read;
|
|
while (true)
|
|
{
|
|
bool segment_finish = false;
|
|
|
|
ch_get = fgetc(pFile);
|
|
column_count++;
|
|
switch (ch_get)
|
|
{
|
|
case EOF:
|
|
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
|
|
case '\r':
|
|
case ',':
|
|
case '}':
|
|
case ']':
|
|
column_count--;
|
|
fseek(pFile, -1, SEEK_CUR);
|
|
case ' ':
|
|
case '\n':
|
|
segment_finish = true;
|
|
break;
|
|
default:
|
|
segment_read += ch_get;
|
|
}
|
|
|
|
if (segment_finish)
|
|
break;
|
|
}
|
|
|
|
if ((segment_read == "true") || (segment_read == "false") || (segment_read == "null"))
|
|
return std::string();
|
|
|
|
// 数值识别
|
|
{
|
|
char *end_ptr;
|
|
strtod(segment_read.c_str(), &end_ptr);
|
|
|
|
// 未被完全转化、出现先导0、先导+、尾缀小数点时非法
|
|
if ((size_t(end_ptr - segment_read.c_str()) < segment_read.size()) || ((segment_read.c_str()[0] == '0') && (segment_read.size() > 1)) || (segment_read.c_str()[0] == '+') || end_ptr[-1] == '.')
|
|
return std::string(path_to_file) + ':' + std::to_string(begin_rol) + ':' + std::to_string(begin_column) + ": Invalid value \"" + segment_read + "\".";
|
|
}
|
|
|
|
return std::string();
|
|
};
|
|
|
|
Check_Arry = [&](void) -> std::string
|
|
{
|
|
Lambda_skip_blank();
|
|
|
|
char ch_get = fgetc(pFile);
|
|
if (ch_get != '[')
|
|
{
|
|
if (ch_get == EOF)
|
|
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
|
|
else
|
|
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected '" + ch_get + "'.";
|
|
}
|
|
column_count++;
|
|
|
|
while (true)
|
|
{
|
|
Lambda_skip_blank();
|
|
ch_get = fgetc(pFile);
|
|
column_count++;
|
|
|
|
switch (ch_get)
|
|
{
|
|
case ']':
|
|
return std::string();
|
|
case ',':
|
|
{
|
|
size_t now_rol_count = rol_count;
|
|
size_t now_column_count = column_count;
|
|
|
|
Lambda_skip_blank();
|
|
|
|
if (fgetc(pFile) == ']')
|
|
return std::string(path_to_file) + ':' + std::to_string(now_rol_count) + ':' + std::to_string(now_column_count) + ": Unexpected ','.";
|
|
fseek(pFile, -1, SEEK_CUR);
|
|
break;
|
|
}
|
|
case EOF:
|
|
return std::string(path_to_file) + ':' + std::to_string(rol_count - 1) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
|
|
default:
|
|
{
|
|
column_count--;
|
|
fseek(pFile, -1, SEEK_CUR);
|
|
|
|
std::string err_str = Check_Value();
|
|
if (!err_str.empty())
|
|
return err_str;
|
|
|
|
// 结束后读取段
|
|
size_t now_rol_count = rol_count;
|
|
size_t now_column_count = column_count;
|
|
|
|
Lambda_skip_blank();
|
|
char ch_get = fgetc(pFile);
|
|
|
|
if ((ch_get != ',') && (ch_get != ']'))
|
|
{
|
|
if (ch_get == '}')
|
|
return std::string(path_to_file) + ':' + std::to_string(now_rol_count) + ':' + std::to_string(now_column_count) + ": Missing ']'.";
|
|
else if (ch_get == EOF)
|
|
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
|
|
else
|
|
return std::string(path_to_file) + ':' + std::to_string(now_rol_count) + ':' + std::to_string(now_column_count) + ": Missing comma.";
|
|
}
|
|
fseek(pFile, -1, SEEK_CUR);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
Check_Pair = [&](void) -> std::string
|
|
{
|
|
Lambda_skip_blank();
|
|
|
|
char ch_get = fgetc(pFile);
|
|
if (ch_get != '\"')
|
|
{
|
|
if (ch_get == EOF)
|
|
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
|
|
else
|
|
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected '" + ch_get + "'.";
|
|
}
|
|
column_count++;
|
|
|
|
// 遍历下一个引号
|
|
bool key_end = false;
|
|
while (true)
|
|
{
|
|
ch_get = fgetc(pFile);
|
|
column_count++;
|
|
|
|
switch (ch_get)
|
|
{
|
|
case '\"':
|
|
key_end = true;
|
|
break;
|
|
case '\n':
|
|
rol_count++;
|
|
column_count = 0;
|
|
break;
|
|
case EOF:
|
|
return std::string(path_to_file) + ':' + std::to_string(rol_count - 1) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
|
|
}
|
|
|
|
if (key_end)
|
|
break;
|
|
}
|
|
|
|
// 寻找键值对标记
|
|
Lambda_skip_blank();
|
|
ch_get = fgetc(pFile);
|
|
if (ch_get != ':')
|
|
{
|
|
if (ch_get == EOF)
|
|
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
|
|
else
|
|
return std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected '" + ch_get + "'. ':' is needed.";
|
|
}
|
|
column_count++;
|
|
|
|
return Check_Value();
|
|
};
|
|
|
|
// 跳过空白检查第一个字符
|
|
Lambda_skip_blank();
|
|
switch (fgetc(pFile))
|
|
{
|
|
case '[':
|
|
fseek(pFile, -1, SEEK_CUR);
|
|
err_str = Check_Arry();
|
|
break;
|
|
case '{':
|
|
fseek(pFile, -1, SEEK_CUR);
|
|
err_str = Check_Object();
|
|
break;
|
|
case EOF:
|
|
err_str = std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Unexpected EOF.";
|
|
break;
|
|
default:
|
|
err_str = std::string(path_to_file) + ':' + std::to_string(rol_count) + ':' + std::to_string(column_count) + ": Syntax error. Must begin with '{' or '['.";
|
|
}
|
|
|
|
// 关闭文件
|
|
fclose(pFile);
|
|
return err_str;
|
|
}
|
|
|
|
// std::string 构造
|
|
Json_Value::Json_Value(std::string str) : private_type(TYPE_STR), p_mem(malloc(sizeof(str)))
|
|
{
|
|
if (p_mem != nullptr)
|
|
new (p_mem) std::string(str);
|
|
else
|
|
this->private_type = TYPE_NULL;
|
|
}
|
|
|
|
// Json_Arry 构造
|
|
Json_Value::Json_Value(Json_Arry arry) : private_type(TYPE_ARRY), p_mem(malloc(sizeof(arry)))
|
|
{
|
|
if (p_mem != nullptr)
|
|
new (p_mem) Json_Arry(arry);
|
|
else
|
|
this->private_type = TYPE_NULL;
|
|
}
|
|
|
|
// Json_Object 构造
|
|
Json_Value::Json_Value(Json_Object object) : private_type(TYPE_OBJ), p_mem(malloc(sizeof(object)))
|
|
{
|
|
if (p_mem != nullptr)
|
|
new (p_mem) Json_Object(object);
|
|
else
|
|
this->private_type = TYPE_NULL;
|
|
}
|
|
|
|
// 整数值 构造
|
|
Json_Value::Json_Value(int64_t num_integer) : private_type(TYPE_NUM_INTEGER), p_mem(malloc(sizeof(num_integer)))
|
|
{
|
|
if (p_mem != nullptr)
|
|
*(decltype(num_integer) *)p_mem = num_integer;
|
|
else
|
|
this->private_type = TYPE_NULL;
|
|
}
|
|
|
|
// 浮点值 构造
|
|
Json_Value::Json_Value(double num_float) : private_type(TYPE_NUM_FLOAT), p_mem(malloc(sizeof(num_float)))
|
|
{
|
|
if (p_mem != nullptr)
|
|
*(decltype(num_float) *)p_mem = num_float;
|
|
else
|
|
this->private_type = TYPE_NULL;
|
|
}
|
|
|
|
// Boolean 逻辑值构造
|
|
Json_Value::Json_Value(bool boolean) : private_type(TYPE_BOOLEAN), p_mem(malloc(sizeof(boolean)))
|
|
{
|
|
if (p_mem != nullptr)
|
|
*(decltype(boolean) *)p_mem = boolean;
|
|
else
|
|
this->private_type = TYPE_NULL;
|
|
}
|
|
|
|
// 浅拷贝构造
|
|
Json_Value::Json_Value(const Json_Value &temp) : private_type(TYPE_NULL), p_mem(nullptr)
|
|
{
|
|
// 执行深拷贝
|
|
*this = temp;
|
|
}
|
|
|
|
// 深拷贝
|
|
Json_Value &Json_Value::operator=(const Json_Value &another)
|
|
{
|
|
if (this != &another)
|
|
{
|
|
// 先析构释放内存
|
|
this->~Json_Value();
|
|
|
|
// 重新赋值
|
|
this->private_type = another.type;
|
|
switch (another.type)
|
|
{
|
|
case TYPE_STR:
|
|
this->p_mem = malloc(sizeof(std::string));
|
|
if (this->p_mem != nullptr)
|
|
new (this->p_mem) std::string(*((std::string *)another.p_mem));
|
|
break;
|
|
case TYPE_ARRY:
|
|
this->p_mem = malloc(sizeof(Json_Arry));
|
|
if (this->p_mem != nullptr)
|
|
new (this->p_mem) Json_Arry(*((Json_Arry *)another.p_mem));
|
|
break;
|
|
case TYPE_OBJ:
|
|
this->p_mem = malloc(sizeof(Json_Object));
|
|
if (this->p_mem != nullptr)
|
|
new (this->p_mem) Json_Object(*((Json_Object *)another.p_mem));
|
|
break;
|
|
case TYPE_NUM_INTEGER:
|
|
this->p_mem = malloc(sizeof(int64_t));
|
|
if (this->p_mem != nullptr)
|
|
*((int64_t *)this->p_mem) = *((int64_t *)another.p_mem);
|
|
break;
|
|
case TYPE_NUM_FLOAT:
|
|
this->p_mem = malloc(sizeof(double));
|
|
if (this->p_mem != nullptr)
|
|
*((double *)this->p_mem) = *((double *)another.p_mem);
|
|
break;
|
|
case TYPE_BOOLEAN:
|
|
this->p_mem = malloc(sizeof(bool));
|
|
if (this->p_mem != nullptr)
|
|
*((bool *)this->p_mem) = *((bool *)another.p_mem);
|
|
break;
|
|
default:
|
|
this->p_mem = nullptr;
|
|
}
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
// 析构
|
|
Json_Value::~Json_Value()
|
|
{
|
|
this->private_type = TYPE_NULL;
|
|
|
|
if (this->p_mem != nullptr)
|
|
{
|
|
// 对象析构
|
|
switch (this->type)
|
|
{
|
|
case TYPE_STR:
|
|
((std::string *)p_mem)->~basic_string();
|
|
break;
|
|
case TYPE_ARRY:
|
|
((Json_Arry *)p_mem)->~Json_Arry();
|
|
break;
|
|
case TYPE_OBJ:
|
|
((Json_Object *)p_mem)->~Json_Object();
|
|
break;
|
|
default:
|
|
break;
|
|
};
|
|
|
|
// 释放内存
|
|
free(p_mem);
|
|
}
|
|
}
|
|
|
|
// 作为直接值获取
|
|
std::string Json_Value::asString(void)
|
|
{
|
|
if (this->type == TYPE_STR)
|
|
return *(std::string *)this->p_mem;
|
|
else
|
|
return std::string("");
|
|
}
|
|
|
|
// 作为 Json_Arry 获取
|
|
Json_Arry Json_Value::asArry(void)
|
|
{
|
|
if (this->type == TYPE_ARRY)
|
|
return *(Json_Arry *)this->p_mem;
|
|
else
|
|
return Json_Arry();
|
|
}
|
|
|
|
// 作为 Json_Object 获取
|
|
Json_Object Json_Value::asObject(void)
|
|
{
|
|
if (this->type == TYPE_OBJ)
|
|
return *(Json_Object *)this->p_mem;
|
|
else
|
|
return Json_Object();
|
|
}
|
|
|
|
// 作为 int64 获取
|
|
int64_t Json_Value::asInteger(void)
|
|
{
|
|
if (this->type == TYPE_NUM_INTEGER)
|
|
return *(int64_t *)this->p_mem;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
// 作为 double 获取
|
|
double Json_Value::asFloat(void)
|
|
{
|
|
if (this->type == TYPE_NUM_FLOAT)
|
|
return *(double *)this->p_mem;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
// 作为 Boolean 逻辑值获取
|
|
bool Json_Value::asBoolean(void)
|
|
{
|
|
if (this->type == TYPE_BOOLEAN)
|
|
return *(bool *)this->p_mem;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
// 是否为空
|
|
bool Json_Value::isNull(void)
|
|
{
|
|
return (this->private_type == TYPE_NULL);
|
|
}
|
|
|
|
// =================================================================================================
|
|
|
|
// 浅拷贝构造
|
|
Json_Pair::Json_Pair(const Json_Pair &temp)
|
|
{
|
|
*this = temp;
|
|
}
|
|
|
|
// 深拷贝
|
|
Json_Pair &Json_Pair::operator=(const Json_Pair &another)
|
|
{
|
|
if (this != &another)
|
|
{
|
|
this->Null_Flag = another.Null_Flag;
|
|
this->private_key_str = another.private_key_str;
|
|
this->private_value = another.private_value;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
// 空判定
|
|
bool Json_Pair::isNull()
|
|
{
|
|
return this->Null_Flag;
|
|
}
|
|
|
|
// =================================================================================================
|
|
|
|
// 深拷贝
|
|
Json_Arry &Json_Arry::operator=(const Json_Arry &another)
|
|
{
|
|
if (this != &another)
|
|
{
|
|
this->private_element_list = another.private_element_list;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
// 获取元素大小
|
|
size_t Json_Arry::size(void)
|
|
{
|
|
return this->private_element_list.size();
|
|
}
|
|
|
|
// 数组索引重载
|
|
Json_Value Json_Arry::operator[](size_t index)
|
|
{
|
|
if (index < this->private_element_list.size())
|
|
return this->private_element_list[index];
|
|
else
|
|
return Json_Value();
|
|
}
|
|
|
|
// 是否为空
|
|
bool Json_Arry::isNull(void)
|
|
{
|
|
return (this->private_element_list.size() == 0);
|
|
}
|
|
|
|
// =================================================================================================
|
|
|
|
// 深拷贝
|
|
Json_Object &Json_Object::operator=(const Json_Object &another)
|
|
{
|
|
if (this != &another)
|
|
{
|
|
this->private_element_list = another.private_element_list;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
// 获取元素大小
|
|
size_t Json_Object::size(void)
|
|
{
|
|
return this->private_element_list.size();
|
|
}
|
|
|
|
// 数组索引重载
|
|
Json_Pair Json_Object::operator[](size_t index)
|
|
{
|
|
if (index < this->private_element_list.size())
|
|
return this->private_element_list[index];
|
|
else
|
|
return Json_Pair();
|
|
}
|
|
|
|
// 由Key 查找值
|
|
Json_Value Json_Object::get(std::string key)
|
|
{
|
|
for (auto pair : this->private_element_list)
|
|
if (pair.key == key)
|
|
return pair.value;
|
|
|
|
return Json_Value();
|
|
}
|
|
|
|
// 是否为空
|
|
bool Json_Object::isNull(void)
|
|
{
|
|
return (this->private_element_list.size() == 0);
|
|
} |