Implemented a JSON file format checking function.
This commit is contained in:
parent
057438652a
commit
b11e74e815
@ -3,8 +3,6 @@
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "stdio.h"
|
||||
#include "stdlib.h"
|
||||
#include "stdint.h"
|
||||
}
|
||||
|
||||
@ -16,6 +14,13 @@ class Json_Arry; // Json 数组 元素必须是值
|
||||
class Json_Object; // Json 对象 对象内必须是键值对序列
|
||||
class Json_Value; // Json 值(可以是数组、对象、字符串、浮点数值和整数值、逻辑值、NULL)
|
||||
|
||||
/**
|
||||
* @brief Json文件 格式检查
|
||||
* @param path_to_file 文件路径串
|
||||
* @return std::string 错误值
|
||||
*/
|
||||
std::string JsonFile_FormatCheck(const char *path_to_file);
|
||||
|
||||
// Json 数组
|
||||
class Json_Arry
|
||||
{
|
||||
|
||||
@ -1,5 +1,398 @@
|
||||
#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)))
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user