diff --git a/Inc/Json_Utilities.hpp b/Inc/Json_Utilities.hpp index aca8ba7..955ac4a 100644 --- a/Inc/Json_Utilities.hpp +++ b/Inc/Json_Utilities.hpp @@ -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 { diff --git a/Src/Json_Utilities.cpp b/Src/Json_Utilities.cpp index f7e8e8c..78d62ac 100644 --- a/Src/Json_Utilities.cpp +++ b/Src/Json_Utilities.cpp @@ -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 Check_Object; + std::function Check_Value; + std::function Check_Arry; + std::function 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))) {