抛弃GdCpp*.dll/pdb历史重新建库。libhv和Sqlite的dll保留

This commit is contained in:
Zhang Jianjun
2026-02-02 16:09:02 +08:00
parent f148ca49e3
commit 4a2a284ac0
292 changed files with 350450 additions and 0 deletions

249
include/json/CJsonFile.h Normal file
View File

@@ -0,0 +1,249 @@
#ifndef CJSONFILE_H
#define CJSONFILE_H
#include "_nlohmann_json_wrapper.h"
#include <fstream>
#include <iomanip>
#include <filesystem>
#include <atlstr.h>
namespace fs = std::filesystem;
/** @addtogroup ksjson
* @{
* @addtogroup files
* @brief json/bson file classes.
* @{ */
/**
* @brief The CJsonFile class
*/
class CJsonFile // header only class
{
public:
CJsonFile()
:needSave(0)
{
}
/// \brief 构造函数
/// \param filepath 指定文件绝对路径,只保存了文件名,并没有打开文件。
/// 如果未设置后续必须通过setFilePath()指定文件的绝对路径
template<typename T>
CJsonFile(T filepath)
{
setFilePath(filepath);
}
/// 设置文件路径
/// \param path 文件的绝对路径
void setFilePath(const char* path) { _filePath = path; }
void setFilePath(const wchar_t* path) { _filePath = path; }
void setFilePath(const fs::path& path) { _filePath = path; }
#ifdef UNICODE
void setFilePath(const CString& path) { _filePath = (const wchar_t*)path; }
#endif
// 判断是否设置了路径,没有判断路径是否有效
bool hasFilePath() const { return !_filePath.empty(); }
bool exists() const { return !_filePath.empty() && fs::exists(_filePath); }
virtual ~CJsonFile() = default;
protected:
/// 参数文件完整路径。可以在构造函数里指定或用setPath()指定
fs::path _filePath;
public:
/// 文件内容与内存变量之间中转的json格式cache。
jsonobj cache;
/// 标记参数是否需要保存。
int needSave = 0;
// 错误字符串
std::string errStr;
/// 清空json缓存
void clearCache() { cache = jsonobj(); }
/// 获取文件路径
const fs::path& filePath() const { return _filePath; }
void reset() {
cache.clear();
_filePath.clear();
}
enum {
jFileNotExist=0,
jFileOk =1,
jFileFailOpenRead=-1,
jFileFailOpenWrite=-2,
jFileParseError=-3,
jFileNull=-4,
jFileOutputError=-5,
jfileJsonToStructError=-6,
jfileJsonFromStructError = -7,
};
// ----保存和加载的函数相关 -----
/// 从文件加载json/bson到cache加载后关闭文件。
/// 需要在构造函数中或用setFilePath()设置文件的完整路径
/// \return 1: 文件打开ok解析json正确0文件打开失败-1文件打开成功解析json出错
virtual int load()
{
// 调用处必须保证已经设置了路径
_ASSERT(!_filePath.empty());
if (!fs::exists(_filePath)) {
errStr = fmt::format("json文件不存在{}", _filePath.string());
return jFileNotExist;
}
std::ifstream in(_filePath);
if (in.is_open()) {
try {
in >> cache;
needSave = 0;
in.close();
return jFileOk;
}
catch (jsonobj::exception& e) {
//throw parse_error.101 in case of an unexpected token
//throw parse_error.102 if to_unicode fails or surrogate error
//throw parse_error.103 if to_unicode fails
errStr = fmt::format("解析json出错{}\n{}", _filePath.string(), e.what());
in.close();
return jFileParseError;
}
}
else {
errStr = fmt::format("json文件只读打开失败{}", _filePath.string());
return jFileFailOpenRead;
}
}
/// 保存cache到指定的文件覆盖文件内容写完后关闭文件但内存中保存json格式的cache。
/// 需要在构造函数中或用setFilePath()设置文件的完整路径。
/// \return 1: 文件保存成功0: 文件创建失败;-1: json中有字符串不是utf-8
virtual int save()
{
// 调用处必须保证已经设置了路径
_ASSERT(!_filePath.empty());
std::ofstream o(_filePath, std::ofstream::trunc);
if (o.is_open()) {
try {
o << std::setw(4) << cache << std::endl;
o.flush();
needSave = 0;
return jFileOk;
}
catch (jsonobj::exception& e) {
// throw type_error.316 if a string stored inside the JSON value is not UTF-8 encoded
errStr = fmt::format("转换json文本出错{}\n{}", _filePath.string(), e.what());
return jFileOutputError;
}
}
else {
errStr = fmt::format("json文件写入打开失败{}", _filePath.string());
return jFileFailOpenWrite;
}
}
template <typename T>
int save(const T& src, bool clearBeforeSave=false) {
if (clearBeforeSave) clearCache();
try {
to_json(cache, src);
}
catch (jsonobj::exception& e) {
errStr = fmt::format("json<= 结构体出错:{}\n{}", _filePath.string(), e.what());
return jfileJsonFromStructError;
}
return save();
}
template <typename T>
int load(T& dst) {
errStr.clear();
int ret = jFileOk;
do {
ret = load();
if (ret != 1) break;
if (cache.is_null()) {
errStr = fmt::format("读到的json是空的{}", _filePath.string());
ret = jFileNull;
break;
}
try {
from_json(cache, dst);
}
catch (jsonobj::exception& e) {
errStr = fmt::format("json => 结构体出错:{}\n{}", _filePath.string(), e.what());
ret = jfileJsonToStructError;
break;
}
return jFileOk;
} while (0);
alog->error(errStr);
return ret;
}
/// 将cache中名为name的部分转到结构体T的实例dst
template <typename T>
int copyToStruct(const char* name, T& dst)
{
if (cache.contains(name)) {
try {
cache[name].get_to<T>(dst);
}
catch (jsonobj::exception& e) {
errStr = fmt::format("json {} => 结构体出错:{}\n{}", name, _filePath.string(), e.what());
return jfileJsonToStructError;
}
return 1;
}
return 0;
}
/// 将结构体T的实例src内容转成json保存到cache中名为name的字段
template <typename T>
void saveToCache(const char* name, const T& src)
{
try {
cache[name] = src;
}
catch (jsonobj::exception& e) {
errStr = fmt::format("json {} <= 结构体出错:{}\n{}", name, _filePath.string(), e.what());
return jfileJsonFromStructError;
}
needSave++;
}
};
class CBsonFile : public CJsonFile
{
public:
/// 重载load函数将json改成bson。
virtual int load()
{
return 1;
}
/// 重载load函数将json改成bson。
virtual int save()
{
return 1;
}
};
/** @} files */
/** @} ksjson */
#endif // CJSONFILE_H

120
include/json/ParaHelper.h Normal file
View File

@@ -0,0 +1,120 @@
#ifndef PARAHELPER_H
#define PARAHELPER_H
/**
* \file ParaHelper.h
*
* \brief 定义一些帮助设置参数用的结构体,如\ref sParaRange
*
**/
#include "_nlohmann_json_wrapper.h"
#include "StringHelper.h"
#include "ParaHelper_core.h"
/** @addtogroup ksjson
* @{
* @addtogroup ParaHelper
* @brief 定义sParaRange结构体用于设置参数的缺省值、最小值、最大值已经步进值小数位数等属性。
* @{ */
#ifndef ConstExpr
/// 需要在一个类/结构体内部定义静态常量表达示时,
/// 将"static constexpr auto"简写为ConstExpr
#define ConstExpr static constexpr const auto
#endif
/// 给变量添加注释的宏。
/// var是变量
/// str1、str2是变量含义和详细描述。
/// 只支持const wchar_t*类型的字符串方便在UI显示。
#define ParaComment(var, str1, str2) \
ConstExpr var##_title = str1; \
ConstExpr var##_descr = str2;
static inline std::string combine_strs(const wchar_t* s1, const wchar_t* s2)
{
if (wcslen(s2))
return utf16_8(std::wstring(s1) + L": " + s2);
else
return utf16_8(s1);
}
// 变量转json并附加注释适用于可以直接转json的变量
#define TO_JSON_COMMENT(j, name, var) \
j[#name##"?"] = combine_strs(var##_title, var##_descr); \
j[#name] = var;
// wstring型变量转json并附加注释
#define TO_JSON_COMMENT_WSTR(j, name, var) \
j[#name##"?"] = combine_strs(var##_title, var##_descr); \
j[#name] = utf16_8(var);
// wstring型vector变量转json并附加注释
#define TO_JSON_COMMENT_WSTRVECTOR(j, name, var) {\
j[#name##"?"] = combine_strs(var##_title, var##_descr); \
jsonobj jarr=jsonobj::array(); \
for(auto& s : var) jarr.push_back(utf16_8(s)); \
j[#name] = jarr; \
}
// 类转json并附加注释适合自定义了to_json()函数的类或结构体
#define TO_JSON_COMMENT_CLASS(j, name, var) \
j[#name##"?"] = combine_strs(var##_title, var##_descr); \
to_json(j[#name], var);
/// sParaRange -> json
template <typename T>
void to_json(jsonobj& j, const sParaRange<T> & p) {
j["def"] = p.Def;
j["min"] = p.Min;
j["max"] = p.Max;
j["step"] = p.Step;
if(typeid (T) == typeid (float) || typeid (T) == typeid (double)){
//浮点型才保存Decimal
j["decimal"] = p.Decimal;
}
}
/// json -> sParaRange
/// 手写的json文件有两种格式
/// 一种每一项用key:value单独设置必须存在def,min,max;
/// 一种写成数组必须存在3项。
/// 程序写的json见to_json()
template <typename T>
void from_json(const jsonobj& j, sParaRange<T>& p) {
if(!j.is_array()){ //key:value方式单独设置各项
//注意def, min, max 必须存在,要不然这会抛异常的!
j["def" ].get_to<T>(p.Def);
j["min" ].get_to<T>(p.Min);
j["max" ].get_to<T>(p.Max);
// 判断step是否存在再读
auto it = j.find("step");
if(it!=j.end()) it->get_to<T>(p.Step);
// 判断decimal是否存在再读
it = j.find("decimal");
if(it!=j.end()) it->get_to<int>(p.Decimal);
}else{
//至少要有三项。TODO: 如何报错?
int size = int(j.size());
if(size<3) return;
j[0].get_to<T>(p.Def);
j[1].get_to<T>(p.Min);
j[2].get_to<T>(p.Max);
//有4项则读step
if(size >= 4) j[3].get_to<T>(p.Step);
//有5项则读decimal
if(size >= 5) p.Decimal = int(j[4].get<T>());
}
}
/** @} ParaHelper */
/** @} ksjson */
#endif // PARAHELPER_H

View File

@@ -0,0 +1,70 @@
#ifndef _PARAHELPER_CORE_H
#define _PARAHELPER_CORE_H
/// \brief 定义整形、浮点型参数的缺省值和取值范围类型T可以为8/16/32/64位的有符号或无符号数、float/double。
template <typename T>
struct sParaRange
{
/// 默认构造后不能直接使用必须正确设置Def/Min/Max参数才能使用
sParaRange() = default;
/// 带所有参数测构造函数。当所有参数都是常数或constexpr时构造的实例可以是constexpr
constexpr sParaRange(const T &def, const T & min, const T & max, const T& step=1, int dec=2)
: Def(def), Min(min), Max(max), Step(step)
, Decimal(dec)
{
}
/// 必须设的参数:缺省值, 最小值, 最大值。默认构造为0是没法使用的
T Def=0, Min=0, Max=0;
/// 可选设置的参数在UI控件中调整参数的步进值默认为1
T Step=1;
/// 小数位数仅用于float/double浮点型数据整形数据忽略此项
int Decimal=2;
/// 判断输入参数是否在[Min, Max]范围内
bool inRange(const T & val) const {
return (val>=Min && val <= Max);
}
/// @brief 校验参数如果小于Min设置为Min大于Max设置为Max
bool verify(T& val) const {
if (val < Min) { val = Min; return false; }
else if (val > Max) { val = Max; return false; }
else return true;
}
/// @brief 校验参数如果小于Min设置为Min大于Max设置为Max
/// @param err 误差值,多用于浮点数比较
bool verify(T& val, const T err) const {
if (val < Min-err) { val = Min; return false; }
else if (val > Max+err) { val = Max; return false; }
else return true;
}
/// @brief 校验参数,如果超出范围,设置为缺省值
bool verifyToDefault(T& val) const{
if (val <Min || val > Max) { val = Def; return false;}
else return true;
}
/// @brief 校验参数,如果超出范围,设置为缺省值
bool verifyToDefault(T& val, const T err) const {
if (val <Min-err || val > Max+err) { val = Def; return false; }
else return true;
}
sParaRange operator+(T d) const
{
return sParaRange(Def + d, Min + d, Max + d, Step, Decimal);
}
sParaRange operator-(T d) const
{
return sParaRange(Def - d, Min - d, Max - d, Step, Decimal);
}
};
#endif

View File

@@ -0,0 +1,41 @@
#ifndef NLOHMANN_JSON_WRAPPER_H
#define NLOHMANN_JSON_WRAPPER_H
#include "json.hpp"
#include "GdCPP_Exports.h"
/**
* @addtogroup ksjson
* @{
* @addtogroup nlohmann_json_wrapper
* @brief 引用nlohmann::json的类和异常等。
* @details
* @{
*/
/// \brief 将nlohmann::json定义为jsonobj简化掉namespace的访问。
///
/// 本来想用json但语义不够明确。因此采用了一个跟Qt的QJsonObject近似的名称
/// 表示可以替代QJsonObject实际上这个类的功能很强大可以完全替代QJsonObject、QJsonValue、QJsonArray
/// 可以替代QJsonDocument的部分功能甚至也能部分替代QVariant用。
using jsonobj = nlohmann::ordered_json;
// 以下定义用于简化json的异常类型的访问
using json_exception = nlohmann::json::exception;
using json_parse_err = nlohmann::json::parse_error;
using json_invalid_iterator = nlohmann::json::invalid_iterator;
using json_type_error = nlohmann::json::type_error;
using json_out_of_range = nlohmann::json::out_of_range;
using json_other_error = nlohmann::json::other_error;
// 判断数据类型是否可以做json的key
template <typename T> struct JsonKey;
template <> struct JsonKey<const std::string&> { typedef const std::string& Type; };
template <> struct JsonKey<const char * > { typedef const char* Type; };
// 判断类型是否可以做数组长度
template <typename T> struct ArraySizeT;
template <> struct ArraySizeT<int> { typedef int Type; };
template <> struct ArraySizeT<size_t> { typedef size_t Type; };
/** @} nlohmann_json_wrapper */
/** @} ksjson */
#endif // NLOHMANN_JSON_WRAPPER_H

View File

@@ -0,0 +1,16 @@
#pragma once
// opencv不是所有项目都包含按需要添加到pch.h
// 对应jsonCVWrapper.cpp源码添加到项目
#ifndef _JSON_OPENCV_WRAPPER_
#define _JSON_OPENCV_WRAPPER_
void to_json(jsonobj& j, const cv::Point& p);
void from_json(const jsonobj& j, cv::Point& p);
void to_json(jsonobj& j, const cv::Point2f& p);
void from_json(const jsonobj& j, cv::Point2f& p);
void to_json(jsonobj& j, const cv::Size& p);
void from_json(const jsonobj& j, cv::Size& p);
void to_json(jsonobj& j, const cv::Rect& p);
void from_json(const jsonobj& j, cv::Rect& p);
#endif //_JSON_OPENCV_WRAPPER_

View File

@@ -0,0 +1,421 @@
#ifndef JSONREADWITHVERIFY_H
#define JSONREADWITHVERIFY_H
#include "_nlohmann_json_wrapper.h"
#include "ParaHelper.h"
#include "alog.h"
/** @addtogroup ksjson
* @{
* @addtogroup readWithVerify
* @brief 从json转换到数值前判断key是否存在确认数值是否在一定[min, max]范围内,或在一个数组列表范围之内。
* @{
*/
/// \brief 尝试从obj读取键值为key的数据没找到不赋值返回false找到就给指针赋值并返回true。
/// \details 通常用于已经初始化为默认值的变量或结构体,找到就读,没找到就保持默认值。
/// 注意保存的格式要跟写入的格式一致别写个string当int读肯定会出问题的。这里就没法检验格式是否正确了。
///
/// \param obj nlohmann::json对象
/// \param key 键值类型KeyT支持类型const char *, std::string
/// \param dst 目标变量类型ValueT可以是所有支持的数据类型包括nlohmann::json标准的数据类型和定义了to_json和from_json的类型。
/// \return 没找到返回0找到返回1。
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT>
int tryRead(const jsonobj& obj, KeyT key, ValueT& dst)
{
auto it = obj.find(key);
if (it == obj.end() || it->is_null()) return 0; //没找到
it->template get_to<ValueT>(dst);
return 1;
}
/// 尝试从obj读取键值为key的数据没找到设置为缺省值并返回false找到就读取数值给指针赋值并返回true。
/// 类型ValueT可以是所有支持的数据类型包括nlohmann::json标准的数据类型和定义了to_json和from_json的类型。
/// \param obj nlohmann::json对象
/// \param dst 目标变量。
/// \param key 键值类型KeyT支持类型const char *, std::string
/// \param def 找不到键值使用的缺省值。def的数据类型ValueT2必须与dst的数据类型ValueT可以直接隐式转换或复制构造的
/// \return 没找到返回false找到返回true。
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT, typename ValueT2>
int readWithDefault(const jsonobj& obj, KeyT key, ValueT& dst, ValueT2 def)
{
auto it = obj.find(key);
if (it == obj.end() || it->is_null()) {//没找到
dst = def;
return 0;
}
it->template get_to<ValueT>(dst);
return 1;
}
/// \brief 在\ref readWithDefault 基础上增加了校验读到的值是否在[min, max]范围之内。
/// \details 类型ValueT通常是数值类型。其它支持的数据类型如果它支持用大于号/小于号比较的类型也行,估计很少会用到。
/// \param obj nlohmann::json对象
/// \param key 键值类型KeyT支持类型const char *, std::string
/// \param dst 目标变量。
/// \param def 找不到键值使用的缺省值。def的数据类型必须与dst的数据类型可以直接转换的
/// \param min 取值范围的下限min << value << max
/// \param max 取值范围的上限min << value << max
/// \return 返回读取状态。
/// 没找到返回0找到但数值超界返回-1找到并在有效范围内返回1。
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT, typename ValueT2, typename ValueT3>
int readInRange(const jsonobj& obj, KeyT key, ValueT& dst, const ValueT2& def, const ValueT3& min, const ValueT3& max)
{
auto it = obj.find(key);
if (it == obj.end() || it->is_null()) {//没找到
dst = ValueT(def);
return 0;
}
ValueT tmp = it->template get<ValueT>();
if (tmp < ValueT(min)) {
dst = ValueT(min);
return -1;
}
else if (tmp > ValueT(max)) {//超界
dst = ValueT(max);
return -1;
}
// 返回读取值
dst = tmp;
return 1;
}
/// \brief 重载\ref readInRange 用sParaRange<ValueT>做取值范围的校验。
/// \details 用sParaRange的成员变量Def, Min, Max替代\ref readInRange的def, min, max参数
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT>
inline int readInRange(const jsonobj& obj, KeyT key, ValueT& dst, const sParaRange<ValueT>& range)
{
return readInRange(obj, key, dst, range.Def, range.Min, range.Max);
}
/// \brief json --> ValueT并校验数值是否在数组list[num]范围类
/// \details
/// - 没找到返回值为0dst设置为def<br>
/// - 找到但数值布置在列表范围内:返回值-1dst设置为def<br>
/// - 找到并在列表范围内返回1dst设置为解析值。<br>
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT, typename NumT, typename = ArraySizeT<NumT>::Type>
int readInList(const jsonobj& obj, KeyT key, ValueT& dst, const ValueT& def, const ValueT* list, NumT num)
{
auto it = obj.find(key);
if (it == obj.end() || it->is_null()) {//没找到
dst = def;
return 0;
}
ValueT tmp = it->template get<ValueT>();
for (int i = 0; i < num; i++) { //不在列表中
if (tmp == list[i]) {
dst = tmp;
return 1;
}
}
dst = def;
return -1;
}
/// \brief json --> ValueT并校验数值是否在QVector<ValueT>列表范围类
/// \details
/// - 没找到返回值为0dst设置为def<br>
/// - 找到但数值布置在列表范围内:返回值-1dst设置为def<br>
/// - 找到并在列表范围内返回1dst设置为解析值。<br>
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT>
int readInList(const jsonobj& obj, KeyT key, ValueT& dst, const ValueT& def, std::vector<ValueT> list)
{
auto it = obj.find(key);
if (it == obj.end() || it->is_null()) {//没找到
dst = def;
return 0;
}
ValueT tmp = it->template get<ValueT>();
if (list.contains(tmp)) {
dst = tmp;
return 1;
}
dst = def;
return -1;
}
/// \brief json --> ValueT并校验数值是否在QList<ValueT>列表范围类
/// \details
/// - 没找到返回值为0dst设置为def<br>
/// - 找到但数值布置在列表范围内:返回值-1dst设置为def<br>
/// - 找到并在列表范围内返回1dst设置为解析值。<br>
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT>
int readInList(const jsonobj& obj, KeyT key, ValueT& dst, const ValueT& def, std::list<ValueT> list)
{
auto it = obj.find(key);
if (it == obj.end() || it->is_null()) {//没找到
dst = def;
return 0;
}
ValueT tmp = it->template get<ValueT>();
if (list.contains(tmp)) {
dst = tmp;
return 1;
}
dst = def;
return -1;
}
/// \brief 从json读入string, 与strlist里的字符串比较确定枚举值。
/// \details
/// \param strlist 字符串列表
/// \param num 字符串个数
/// \param vallist 枚举值列表。<br>
/// vallist可以为null代表枚举值如果是从0开始顺序递增的dst设置为strlist数组的下标。<br>
/// \return <br>
/// - 没找到返回值为0dst设置为def<br>
/// - 找到但字符串不在列表范围内:返回值-1dst设置为def<br>
/// - 找到并在列表范围内返回1。如果vallist为nulldst设置strlist数组的下表如果vallist非空dst设置为对于的数组。<br>
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT>
int readEnum(const jsonobj& obj, KeyT key, ValueT& dst, int def, const char* const* strlist, int num, const int* vallist = nullptr)
{
auto it = obj.find(key);
if (it == obj.end() || it->is_null()) {//没找到
alog->warn("readEnum 没找到{},返回缺省值", key);
dst = ValueT(def);
return 0;
}
if (it->is_string()) {
std::string str = it->template get<std::string>();
for (int i = 0; i < num; i++) {
if (str.compare(strlist[i]) == 0) {
if (vallist) dst = ValueT(vallist[i]);
else dst = ValueT(i);
return 1;
}
}
alog->warn("readEnum {}没有匹配到字符串{},返回缺省值", key);
dst = ValueT(def);
}
else if (it->is_number_integer()) {
int val = it->template get<int>();
if (vallist) {
for (int i = 0; i < num; i++) {
if (val == vallist[i]) {
dst = ValueT(val);
return 1;
}
}
alog->warn("readEnum {}数值不在列表中,返回缺省值", key);
dst = ValueT(def);
}
else {
if (val >= 0 && val < num) {
dst = ValueT(val);
return 1;
}
else {
alog->warn("readEnum {}数值超界,返回缺省值", key);
dst = ValueT(def);
}
}
}
else {
alog->error("{}的json类型错误应该是字符串或整形未修改结果", key);
}
return -1;
}
// 与上一版本的区别是没有缺省值
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT>
int readEnum(const jsonobj& obj, KeyT key, ValueT& dst, const char* const * strlist, int num, const int* vallist = nullptr)
{
auto it = obj.find(key);
if (it == obj.end() || it->is_null()) {//没找到
alog->warn("readEnum 没找到{},返回缺省值", key);
return 0;
}
if (it->is_string()) {
std::string str = it->template get<std::string>();
for (int i = 0; i < num; i++) {
if (str.compare(strlist[i]) == 0) {
if (vallist) dst = ValueT(vallist[i]);
else dst = ValueT(i);
return 1;
}
}
alog->warn("readEnum {}没有匹配到字符串{},未赋值", key);
}
else if (it->is_number_integer()) {
int val = it->template get<int>();
if (vallist) {
for (int i = 0; i < num; i++) {
if (val == vallist[i]) {
dst = ValueT(val);
return 1;
}
}
alog->warn("readEnum {}数值不在列表中,未赋值", key);
}
else {
if (val >= 0 && val < num) {
dst = ValueT(val);
return 1;
}
else {
alog->warn("readEnum {}数值超界,未赋值", key);
}
}
}
else {
alog->error("{}的json类型错误应该是字符串或整形未修改结果", key);
}
return -1;
}
/// \brief 从json读入string, 与strlist里的字符串比较确定枚举值。
/// \details
/// \param strlist 字符串列表
/// \param vallist 枚举值列表。<br>
/// \return <br>
/// - 没找到返回值为0dst设置为def<br>
/// - 找到但字符串不在列表范围内:返回值-1dst设置为def<br>
/// - 找到并在列表范围内返回1。如果vallist为nulldst设置strlist数组的下表如果vallist非空dst设置为对于的数组。<br>
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT, typename ValutT2>
int readEnum(const jsonobj& obj, KeyT key, ValueT& dst, ValutT2 def, const char** strlist, const std::vector<ValueT>& vallist)
{
auto it = obj.find(key);
if (it == obj.end() || it->is_null()) {//没找到
dst = ValueT(def);
return 0;
}
std::string str = it->template get<std::string>();
for (int i = 0; i < vallist.size(); i++) {
if (str.compare(strlist[i]) == 0) {
dst = vallist[i];
return 1;
}
}
dst = ValueT(def);
return -1;
}
/// 将C++枚举数组转换为字符串数组写入json
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT>
void writeEnumArray(jsonobj& obj, KeyT key, const char* const* strlist, int strnum, const std::vector<ValueT> &valuelist)
{
auto arr=jsonobj::array();
for(auto &val : valuelist) {
if (val < 0 || val >= strnum) {
alog->error("writeEnum {}数值超界", key);
return;
}
arr.push_back(strlist[val]);
}
obj[key] = arr;
}
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT>
int readEnumArray(const jsonobj& obj, KeyT key, std::vector<ValueT>& dst, const char* const* strlist, int num)
{
auto it = obj.find(key);
if (it == obj.end()) {//没找到
alog->warn("readEnumArray 没找到{}", key);
return 0;
}
if (!it->is_array()) {
alog->error("readEnumArray {} 不是数组", key);
return 0;
}
if (it->size() == 0) {
alog->error("readEnumArray {} 是空数组", key);
return 0;
}
dst.clear();
for (auto& x : *it) {
if (x.is_string()) {
std::string str=x.get<std::string >();
int i = 0;
for (; i < num; i++) {
if (str.compare(strlist[i]) == 0) {
dst.push_back(ValueT(i));
break;
}
}
if(i==num )alog->warn("readEnumArray {}没有匹配到字符串{},未赋值", key, str);
}
else {
alog->error("{}的json类型错误应该是字符串未修改结果", key);
}
}
return int(dst.size());
}
template <typename KeyT, typename = typename JsonKey<KeyT>::Type>
int readStr(const jsonobj& obj, const KeyT& key, char* dst, int dstsize)
{
auto it = obj.find(key);
if (it == obj.end() || it->is_null()) {//没找到,或空
memset(dst, 0, dstsize);
return 0;
}
if (!it->is_string()) { //不是字符串
return -1;
}
std::string str = it->template get<std::string>();
auto len = str.length();
if (len >= dstsize) {
return -2;
}
else if (len == 0) {
*dst = 0;
return 1;
}
else {
memcpy(dst, str.c_str(), len);
*(dst + len) = 0;
return 1;
}
}
/// <summary>
/// 读入char型数值如果长度刚好填满不用0结束
/// </summary>
/// <typeparam name="KeyT"></typeparam>
/// <param name="obj"></param>
/// <param name="key"></param>
/// <param name="dst"></param>
/// <param name="dstsize"></param>
/// <returns></returns>
template <typename KeyT, typename = typename JsonKey<KeyT>::Type>
int readCharArray(const jsonobj& obj, const KeyT& key, char* dst, int dstsize, char fill)
{
auto it = obj.find(key);
if (it == obj.end() || it->is_null()) {//没找到,或空
memset(dst, 0, dstsize);
return 0;
}
if (!it->is_string()) { //不是字符串
return -1;
}
std::string str = it->template get<std::string>();
auto len = str.length();
if (len > dstsize) {
return -2;
}
else {
memcpy(dst, str.c_str(), len);
if (len < dstsize) {
memset(dst + len, fill, dstsize - len);
}
return 1;
}
}
/** @} readWithCheck*/
/** @} json*/
#endif // JSONREADWITHVERIFY_H

View File

@@ -0,0 +1,573 @@
#ifndef JSON_VC_WRAPPER_H
#define JSON_VC_WRAPPER_H
#include "_nlohmann_json_wrapper.h"
#include <atlstr.h> // for CString
#include <atltypes.h> // for CPoint, CSize, CRect
#include "StringHelper.h"
// wchar_t定义to_json没用直接用j["keyname"] = utf16_8(wstr);
// GDCPP_API void to_json(jsonobj& j, const wchar_t * p);
// wstring定义to_json没用直接用j["keyname"] = utf16_8(wstr);
// GDCPP_API void to_json(jsonobj& j, const std::wstring& p);
// std::wstring用from_josn会报错用下面的toWstring
//GDCPP_API void from_json(const jsonobj& j, std::wstring& p);
bool toWstring(const jsonobj& j, std::wstring& dst);
template <typename KeyT, typename = typename JsonKey<KeyT>::Type>
int readWstring(const jsonobj& j, KeyT key, std::wstring& dst)
{
auto it = j.find(key);
if (it == j.end() || it->is_null()) {//没找到
return 0;
}
if (it->is_string()) { // 判断是否为string类型的数据避免get函数抛出异常
dst = utf8_16(it->get<std::string>());
return 1;
}
else {
return -1;
}
}
template <typename KeyT, typename = typename JsonKey<KeyT>::Type>
int readWstringVector(const jsonobj& j, KeyT key, std::vector<std::wstring>& dst, bool clearbeforeread)
{
if (clearbeforeread) {
dst.clear();
}
auto it = j.find(key);
if (it == j.end() || it->is_null()) {//没找到
return 0;
}
if (!it->is_array()) { //not array
return -1;
}
std::string str;
for (auto& i : *it) {
str = i.get<std::string>();
dst.push_back(utf8_16(str));
}
return int(it->size());
}
template <typename KeyT, typename = typename JsonKey<KeyT>::Type>
int readWstring(const jsonobj& j, KeyT key, std::wstring& dst, const std::wstring &def)
{
auto it = j.find(key);
if (it == j.end() || it->is_null()) {//没找到
dst = def;
return 0;
}
if (it->is_string()) { // 判断是否为string类型的数据避免get函数抛出异常
dst = utf8_16(it->get<std::string>());
return 1;
}
else {
return -1;
}
}
void to_json(jsonobj& j, const CString& p);
void from_json(const jsonobj& j, CString& p);
void to_json(jsonobj& j, const CPoint& p);
void from_json(const jsonobj& j, CPoint& p);
void to_json(jsonobj& j, const CSize& p);
void from_json(const jsonobj& j, CSize& p);
void to_json(jsonobj& j, const CRect& p);
void from_json(const jsonobj& j, CRect& p);
/** @addtogroup Vector
* @brief std::vector <---> jsonobj
* @{*/
/// \brief std::vector <T> -> jsonT不要是指针类型模板匹配有问题
/// \details 注意会先清空j如果j之前不是array也会强制变成array.
template <typename T>
void to_json(jsonobj& j, const std::vector <T>& p) {
j = jsonobj::array(); //先清空
int num = int(p.size());
for (int i = 0; i < num; i++) {
j.push_back(p.at(i));
}
}
/// \brief json -> std::vector <T>T不要是指针类型模板匹配有问题
/// \details 注意会先清空p不想清空就用\ref readVector
template <typename T>
void from_json(const jsonobj& j, std::vector <T>& p) {
p.clear(); //先清空
if (j.is_array()) {
size_t num = j.size();
for (size_t i = 0; i < num; i++) {
p.push_back(j.at(i).get<T>());
}
}
}
/// \brief json --> std::vector<ValueT>不会清除原有数据。注意没有判断json里的数据是否与ValueT类型匹配需要应用层保证
///
/// \param j nlohmann::json对象
/// \param key 键值类型KeyT支持类型const char *, std::string
/// \param dst 目标变量。
/// \return 没找到返回0找到但不是数组类型-1有数据返回读到的数据类型。
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename = JsonKey<KeyT>::Type, typename ValueT>
int readVector(const jsonobj& j, KeyT key, std::vector<ValueT>& dst)
{
auto it = j.find(key);
if (it == j.end() || it->is_null()) {//没找到
return 0;
}
if (!it->is_array()) { //not array
return -1;
}
int num = int(it->size());
for (int i = 0; i < num; i++) {
// 基础类不能用from_json只能用get_to
dst.push_back(it->at(i).template get<ValueT>());
}
return num;
}
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename = JsonKey<KeyT>::Type, typename ValueT>
int readVector2D(const jsonobj& j, std::vector< std::vector<ValueT>>& dst)
{
if (!j.is_array()) { //not array
return -1;
}
int num = int(j.size());
for (int i = 0; i < num; i++) {
std::vector<ValueT> sub;
readVector(j.at(i), sub);
dst.push_back(sub);
}
return num;
}
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename = JsonKey<KeyT>::Type, typename ValueT>
int readVector2D(const jsonobj& j, KeyT key, std::vector< std::vector<ValueT>>& dst)
{
auto it = j.find(key);
if (it == j.end() || it->is_null()) {//没找到
return 0;
}
if (!it->is_array()) { //not array
return -1;
}
int num = int(it->size());
for (int i = 0; i < num; i++) {
std::vector<ValueT> sub;
readVector(it->at(i), sub);
dst.push_back(sub);
}
return num;
}
/// \brief json --> std::vector<ValueT>不会清除原有数据。注意没有判断json里的数据是否与ValueT类型匹配需要应用层保证
///
/// \param j nlohmann::json对象
/// \param dst 目标变量。
/// \return 没找到返回0找到但不是数组类型-1有数据返回读到的数据类型。
template <typename ValueT>
int readVector(const jsonobj& j, std::vector<ValueT>& dst)
{
if (!j.is_array()) { //not array
return -1;
}
int num = int(j.size());
for (int i = 0; i < num; i++) {
ValueT tmp;
j.at(i).template get_to<ValueT>(tmp);
dst.push_back(tmp);
}
return num;
}
/// \brief json --> std::vector<ValueT*>不会清除原有数据。注意没有判断json里的数据是否与ValueT类型匹配需要应用层保证
///
/// \param j nlohmann::json对象
/// \param key 键值类型KeyT支持类型const char *, std::string
/// \param dst 目标变量。
/// \return 没找到返回0找到但不是数组类型-1有数据返回读到的数据类型。
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT>
int readPtrVector(const jsonobj& j, KeyT key, std::vector<ValueT*>& dst)
{
auto it = j.find(key);
if (it == j.end() || it->is_null()) {//没找到
return 0;
}
if (!it->is_array()) { //not array
return -1;
}
int num = int(it->size());
for (int i = 0; i < num; i++) {
auto* item = new ValueT();
it->at(i).template get_to<ValueT>(*item);
dst.push_back(item);
}
return num;
}
/// \brief json --> std::vector<ValueT*>不会清除原有数据。注意没有判断json里的数据是否与ValueT类型匹配需要应用层保证
///
/// \param j nlohmann::json对象
/// \param dst 目标变量。
/// \return 没找到返回0找到但不是数组类型-1有数据返回读到的数据类型。
template <typename ValueT>
int readPtrVector(const jsonobj& j, std::vector<ValueT*>& dst)
{
if (!j.is_array()) { //not array
return -1;
}
int num = int(j.size());
for (int i = 0; i < num; i++) {
auto* item = new ValueT();
j.at(i).template get_to<ValueT>(*item);
dst.push_back(item);
}
return num;
}
/// \brief std::vector<T> -> json
/// \details
template <typename T>
int writeVector(jsonobj& j, const std::vector<T>& p, bool clean=false) {
if (clean) {//写入前强制清空
j = jsonobj::array();
}else if (!j.is_array()) {
return -1;
}
int num = int(p.size());
for (int i = 0; i < num; i++) {
jsonobj x;
to_json(x, p.at(i));
j.push_back(x);
}
return num;
}
/// \brief std::vector<T> -> json
/// \details
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename T>
int writeVector(jsonobj& j, KeyT key, const std::vector<T>& p, bool clean = false) {
auto it = j.find(key);
if (it == j.end() || it->is_null() || clean) {//没找到或强制清空
j[key] = jsonobj::array(); //先清空
}
else if (!it->is_array()) {
return -1;
}
int num = int(p.size());
for (int i = 0; i < num; i++) {
jsonobj x;
to_json(x, p.at(i));
j[key].push_back(x);
}
return num;
}
/// \brief std::vector<T*> -> json
/// \details
template <typename T>
int writePtrVector(jsonobj& j, const std::vector<T*>& p, bool clean = false) {
if (clean) {//写入前强制清空
j = jsonobj::array();
}
else if (!j.is_array()) {
return -1;
}
int num = int(p.size());
for (int i = 0; i < num; i++) {
jsonobj x;
to_json(x, *p.at(i));
j.push_back(x);
}
return num;
}
/// \brief std::vector<T*> -> json
/// \details
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename T>
int writePtrVector(jsonobj& j, KeyT key, const std::vector<T*>& p, bool clean=false) {
auto it = j.find(key);
if (it == j.end() || it->is_null() || clean) {//没找到或强制清空
j[key] = jsonobj::array(); //先清空
}
else if (!it->is_array()) {
return -1;
}
int num = int(p.size());
for (int i = 0; i < num; i++) {
jsonobj x;
to_json(x, *p.at(i));
j[key].push_back(x);
}
return num;
}
/// \brief json --> std::vector<std::shared_ptr<ValueT>>不会清除原有数据。注意没有判断json里的数据是否与ValueT类型匹配需要应用层保证
///
/// \param j nlohmann::json对象
/// \param key 键值类型KeyT支持类型const char *, std::string
/// \param dst 目标变量。
/// \return 没找到返回0找到但不是数组类型-1有数据返回读到的数据类型。
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT>
int readSharedPtrVector(const jsonobj& j, KeyT key, std::vector<std::shared_ptr<ValueT>>& dst)
{
auto it = j.find(key);
if (it == j.end() || it->is_null()) {//没找到
return 0;
}
if (!it->is_array()) { //not array
return -1;
}
int num = int(it->size());
for (int i = 0; i < num; i++) {
auto item = std::shared_ptr<ValueT>::create();
it->at(i).template get_to<ValueT>(*item);
dst.append(item);
}
return num;
}
/// \brief json --> std::vector<std::shared_ptr<ValueT>>不会清除原有数据。注意没有判断json里的数据是否与ValueT类型匹配需要应用层保证
///
/// \param j nlohmann::json对象
/// \param dst 目标变量。
/// \return 没找到返回0找到但不是数组类型-1有数据返回读到的数据类型。
template <typename ValueT>
int readSharedPtrVector(const jsonobj& j, std::vector<std::shared_ptr<ValueT>>& dst)
{
if (!j.is_array()) { //not array
return -1;
}
int num = int(j.size());
for (int i = 0; i < num; i++) {
auto item = std::shared_ptr<ValueT>::create();
j.at(i).template get_to<ValueT>(*item);
dst.append(item);
}
return num;
}
/// \brief std::vector<std::shared_ptr<T>> -> json
/// \details
template <typename T>
int writeSharedPtrVector(jsonobj& j, const std::vector<std::shared_ptr<T>>& p) {
if (!j.is_array()) {
return -1;
}
int num = int(p.count());
for (int i = 0; i < num; i++) {
jsonobj x;
to_json(x, *p.at(i));
j.push_back(x);
}
return num;
}
/// \brief std::vector<std::shared_ptr<T>> -> json
/// \details
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename T>
int writeSharedPtrVector(jsonobj& j, KeyT key, const std::vector<std::shared_ptr<T>>& p) {
auto it = j.find(key);
if (it == j.end() || it->is_null()) {//没找到
j[key] = jsonobj::array(); //先清空
}
else if (!it->is_array()) {
return -1;
}
int num = int(p.count());
for (int i = 0; i < num; i++) {
jsonobj x;
to_json(x, *p.at(i));
j[key].push_back(x);
}
return num;
}
/** @} vector*/
/** @addtogroup Array
* @brief Array <---> jsonobj
* @{*/
/// \brief json --> 数组ValueT dst[maxnum]
/// 如果json中的数量超过maxnum只读maxnum个不报错。
/// \return 返回读到数据个数。<br>
/// 0表示没有找到key或数值为空<br>
/// -1表示json[key]不是数组,<br>
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT>
int readArray(const jsonobj &j, KeyT key, ValueT* dst, unsigned maxnum)
{
auto it = j.find(key);
if(it == j.end() || it->is_null()) {//没找到
return 0;
}
if(!it->is_array()){ //not array
return -1;
}
uint32_t num = uint32_t(it->size());
uint32_t readnum = (num > maxnum) ? maxnum : num;
for(uint32_t i=0; i< readnum; i++){
it->at(i).template get_to<ValueT>(dst[i]);
}
return int(readnum);
}
/// \brief json --> 数组ValueT dst[maxnum]
/// 如果json中的数量超过maxnum只读maxnum个不报错。
/// \return 返回读到数据个数。<br>
/// 0表示没有找到key或数值为空<br>
/// -1表示json[key]不是数组,<br>
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT>
int readAnyArray(const jsonobj& j, KeyT key, ValueT* dst, unsigned maxnum)
{
auto it = j.find(key);
if (it == j.end() || it->is_null()) {//没找到
return 0;
}
if (!it->is_array()) { //not array
return -1;
}
uint32_t num = uint32_t(it->size());
uint32_t readnum = (num > maxnum) ? maxnum : num;
for (uint32_t i = 0; i < readnum; i++) {
from_json(it->at(i), dst[i]);
}
return int(readnum);
}
template <typename KeyT, typename = typename JsonKey<KeyT>::Type>
int readWStringArray(const jsonobj& j, KeyT key, std::wstring* dst, unsigned maxnum)
{
auto it = j.find(key);
if (it == j.end() || it->is_null()) {//没找到
return 0;
}
if (!it->is_array()) { //not array
return -1;
}
uint32_t num = uint32_t(it->size());
uint32_t readnum = (num > maxnum) ? maxnum : num;
std::string str;
for (uint32_t i = 0; i < readnum; i++) {
it->at(i).get_to(str);
dst[i] = utf8_16(str);
}
return int(readnum);
}
///获取json中名为key的数组长度不存在或null返回0不是数组返回-1数组返回数组长度
template <typename KeyT, typename = typename JsonKey<KeyT>::Type>
int readArrayNum(const jsonobj &j, KeyT key)
{
auto it = j.find(key);
if(it == j.end() || it->is_null()) {//没找到
return 0;
}
if(!it->is_array()){ //not array
return -1;
}
return int(it->size());
}
/// \brief 数组 ValueT src[num] -> json
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT>
int writeArray(jsonobj &j, KeyT key, const ValueT* src, size_t num)
{
auto tmp = jsonobj::array();
for (size_t i = 0; i < num; i++) {
tmp.push_back(src[i]);
}
j[key] = tmp;
return int(num);
}
/// \brief 数组 ValueT src[num] -> json
template <typename KeyT, typename = typename JsonKey<KeyT>::Type, typename ValueT>
int writeAnyArray(jsonobj& j, KeyT key, const ValueT* src, size_t num)
{
auto tmp = jsonobj::array();
jsonobj sub;
for (size_t i = 0; i < num; i++) {
to_json(sub, src[i]);
tmp.push_back(sub);
}
j[key] = tmp;
return int(num);
}
template <typename KeyT, typename = typename JsonKey<KeyT>::Type>
int writeWStringArray(jsonobj& j, KeyT key, const std::wstring* src, size_t num)
{
j[key] = jsonobj::array();
auto& it = j[key];
std::string str;
for (size_t i = 0; i < num; i++) {
str=utf16_8(src[i]);
it.push_back(str);
}
return int(num);
}
/// \brief 数组 ValueT src[num] -> json
template <typename KeyT, typename = typename JsonKey<KeyT>::Type>
int writeArray(jsonobj& j, KeyT key, const wchar_t ** src, size_t num)
{
j[key] = jsonobj::array();
auto& it = j[key];
USES_CONVERSION;
for (size_t i = 0; i < num; i++) {
it.push_back(W2A(src[i]));
}
return int(num);
}
/// \brief 数组 ValueT src[num] -> json
template <typename KeyT, typename = typename JsonKey<KeyT>::Type>
int writeArray(jsonobj& j, KeyT key, const char** src, size_t num)
{
j[key] = jsonobj::array();
auto& it = j[key];
USES_CONVERSION;
for (size_t i = 0; i < num; i++) {
it.push_back(src[i]);
}
return int(num);
}
/** @} Array*/
#endif // JSON_VC_WRAPPER_H

29
include/json/ksjson.h Normal file
View File

@@ -0,0 +1,29 @@
#ifndef LIB_KS_JSON_H
#define LIB_KS_JSON_H
#include "ParaHelper.h"
/**
* @group ksjson
* @brief 在nlohmann::json C++类库的基础上扩展的类库。
* @details
*
* nlohmann::json来自https://github.com/nlohmann/json
* 简介: 目录nlohmann下README.md、nlohmann json.pdf
* 文档: https://nlohmann.github.io/json/
*
* 本模块主要实现以下功能:
* 1. 支持VC的数据类型如CString等
* 2. 支持从Qt资源文件加载json
* 3. json、bson文件接口
* 4. 读入参数是支持校验
*
*/
#include "jsonReadWithVerify.h"
#include "CJsonFile.h"
#include "jsonVCWrapper.h"
#endif // LIB_KS_JSON_H