11111
This commit is contained in:
parent
19206ab763
commit
bfb9be65b5
|
|
@ -0,0 +1,309 @@
|
||||||
|
#pragma once
|
||||||
|
#include "frida-gum.h"
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <mutex>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// HookFunc
|
||||||
|
struct _ExampleListener
|
||||||
|
{
|
||||||
|
GObject parent;
|
||||||
|
guint num_calls;
|
||||||
|
std::vector<std::string> ArgumentCount;
|
||||||
|
std::string RetType;
|
||||||
|
HSQOBJECT CallBackOnEnter;
|
||||||
|
HSQOBJECT CallBackOnLeave;
|
||||||
|
};
|
||||||
|
enum _ExampleHookId
|
||||||
|
{
|
||||||
|
EXAMPLE_HOOK_OPEN,
|
||||||
|
EXAMPLE_HOOK_CLOSE
|
||||||
|
};
|
||||||
|
typedef struct _ExampleListener ExampleListener;
|
||||||
|
typedef enum _ExampleHookId ExampleHookId;
|
||||||
|
|
||||||
|
static void example_listener_iface_init(gpointer g_iface, gpointer iface_data);
|
||||||
|
|
||||||
|
static GumInterceptor* interceptor;
|
||||||
|
|
||||||
|
#define EXAMPLE_TYPE_LISTENER (example_listener_get_type())
|
||||||
|
G_DECLARE_FINAL_TYPE(ExampleListener, example_listener, EXAMPLE, LISTENER, GObject)
|
||||||
|
G_DEFINE_TYPE_EXTENDED(ExampleListener, example_listener, G_TYPE_OBJECT, 0, G_IMPLEMENT_INTERFACE(GUM_TYPE_INVOCATION_LISTENER, example_listener_iface_init))
|
||||||
|
|
||||||
|
static SQInteger L_HookFunc(HSQUIRRELVM v)
|
||||||
|
{
|
||||||
|
static bool InitFlag = false;
|
||||||
|
if (!InitFlag)
|
||||||
|
{
|
||||||
|
InitFlag = true;
|
||||||
|
|
||||||
|
gum_init_embedded();
|
||||||
|
|
||||||
|
interceptor = gum_interceptor_obtain();
|
||||||
|
}
|
||||||
|
|
||||||
|
GumInvocationListener* listener = (GumInvocationListener*)g_object_new(EXAMPLE_TYPE_LISTENER, NULL);
|
||||||
|
// 得到函数地址
|
||||||
|
SQInteger FuncAddressbuf;
|
||||||
|
Sq_getinteger(v, 2, &FuncAddressbuf);
|
||||||
|
|
||||||
|
void* FuncAddress = (void*)FuncAddressbuf;
|
||||||
|
|
||||||
|
// 遍历参数类型数组
|
||||||
|
std::vector<std::string> ParameterType;
|
||||||
|
sq_pushnull(v); // null iterator
|
||||||
|
while (SQ_SUCCEEDED(sq_next(v, 3)))
|
||||||
|
{
|
||||||
|
const SQChar* path;
|
||||||
|
Sq_getstring(v, -1, &path);
|
||||||
|
char* OutPutText2 = DNFTOOL::SquirrelU2W(path);
|
||||||
|
std::string Realpath(OutPutText2);
|
||||||
|
delete[]OutPutText2;
|
||||||
|
ParameterType.push_back(Realpath);
|
||||||
|
Sq_pop(v, 2);
|
||||||
|
}
|
||||||
|
Sq_pop(v, 1);
|
||||||
|
|
||||||
|
// 得到入口回调函数
|
||||||
|
HSQOBJECT CallBackOnEnter;
|
||||||
|
sq_getstackobj(v, 4, &CallBackOnEnter);
|
||||||
|
// 必须增加一次引用一会记得删除 不然这个函数会被释放
|
||||||
|
sq_addref(v, &CallBackOnEnter);
|
||||||
|
|
||||||
|
// 得到出口回调函数
|
||||||
|
HSQOBJECT CallBackOnLeave;
|
||||||
|
sq_getstackobj(v, 5, &CallBackOnLeave);
|
||||||
|
// 必须增加一次引用一会记得删除 不然这个函数会被释放
|
||||||
|
sq_addref(v, &CallBackOnLeave);
|
||||||
|
|
||||||
|
EXAMPLE_LISTENER(listener)->ArgumentCount = ParameterType;
|
||||||
|
// EXAMPLE_LISTENER(listener)->RetType = std::string(RetBuf);
|
||||||
|
EXAMPLE_LISTENER(listener)->CallBackOnEnter = CallBackOnEnter;
|
||||||
|
EXAMPLE_LISTENER(listener)->CallBackOnLeave = CallBackOnLeave;
|
||||||
|
|
||||||
|
gum_interceptor_begin_transaction(interceptor);
|
||||||
|
gum_interceptor_attach(interceptor, GSIZE_TO_POINTER(FuncAddress), listener, GSIZE_TO_POINTER(FuncAddress));
|
||||||
|
gum_interceptor_end_transaction(interceptor);
|
||||||
|
|
||||||
|
Sq_pushuserpointer(v, listener);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SQInteger L_DeHookFunc(HSQUIRRELVM v)
|
||||||
|
{
|
||||||
|
// 得到函数地址
|
||||||
|
SQUserPointer FuncAddress;
|
||||||
|
Sq_getuserpointer(v, 2, &FuncAddress);
|
||||||
|
|
||||||
|
GumInvocationListener* listener = (GumInvocationListener*)FuncAddress;
|
||||||
|
gum_interceptor_detach(interceptor, listener);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void example_listener_on_enter(GumInvocationListener* listener, GumInvocationContext* ic)
|
||||||
|
{
|
||||||
|
ExampleListener* self = EXAMPLE_LISTENER(listener);
|
||||||
|
|
||||||
|
HSQUIRRELVM v = *(HSQUIRRELVM*)0x1AF3544;
|
||||||
|
// 执行虚拟机Main函数
|
||||||
|
SQInteger top = sq_gettop(v); // saves the stack size before the call
|
||||||
|
sq_pushobject(v, self->CallBackOnEnter);
|
||||||
|
Sq_pushroottable(v);
|
||||||
|
sq_newarray(v, 0);
|
||||||
|
for (size_t i = 0; i < self->ArgumentCount.size() - 1; i++)
|
||||||
|
{
|
||||||
|
void* Abuf = gum_invocation_context_get_nth_argument(ic, i);
|
||||||
|
|
||||||
|
if (CONTAINS_STRING(self->ArgumentCount[i], "int"))
|
||||||
|
Sq_pushinteger(v, (int)Abuf);
|
||||||
|
else if (CONTAINS_STRING(self->ArgumentCount[i], "float"))
|
||||||
|
{
|
||||||
|
SQFloat* a = reinterpret_cast<float*>(&Abuf);
|
||||||
|
Sq_pushfloat(v, *(SQFloat*)a);
|
||||||
|
}
|
||||||
|
else if (CONTAINS_STRING(self->ArgumentCount[i], "bool"))
|
||||||
|
Sq_pushbool(v, (bool)Abuf);
|
||||||
|
else if (CONTAINS_STRING(self->ArgumentCount[i], "string")) {
|
||||||
|
wchar_t* ss = DNFTOOL::charTowchar_t((char*)Abuf);
|
||||||
|
Sq_pushstring(v, ss, -1);
|
||||||
|
delete[]ss;
|
||||||
|
}
|
||||||
|
else if (CONTAINS_STRING(self->ArgumentCount[i], "pointer"))
|
||||||
|
Sq_pushuserpointer(v, (void*)Abuf);
|
||||||
|
else if (CONTAINS_STRING(self->ArgumentCount[i], "short"))
|
||||||
|
Sq_pushinteger(v, (int)Abuf);
|
||||||
|
else if (CONTAINS_STRING(self->ArgumentCount[i], "char"))
|
||||||
|
Sq_pushinteger(v, (int)Abuf);
|
||||||
|
else
|
||||||
|
Sq_pushuserpointer(v, (void*)Abuf);
|
||||||
|
sq_arrayappend(v, -2);
|
||||||
|
}
|
||||||
|
Sq_call(v, 2, SQTrue, SQTrue); // calls the function
|
||||||
|
if (sq_gettype(v, -1) == OT_ARRAY)
|
||||||
|
{
|
||||||
|
sq_pushnull(v); // null iterator
|
||||||
|
int Idx = 0;
|
||||||
|
while (SQ_SUCCEEDED(sq_next(v, -2)))
|
||||||
|
{
|
||||||
|
if (CONTAINS_STRING(self->ArgumentCount[Idx], "int"))
|
||||||
|
{
|
||||||
|
SQInteger Abuf;
|
||||||
|
Sq_getinteger(v, -1, &Abuf);
|
||||||
|
gum_invocation_context_replace_nth_argument(ic, Idx, (void*)Abuf);
|
||||||
|
}
|
||||||
|
else if (CONTAINS_STRING(self->ArgumentCount[Idx], "float"))
|
||||||
|
{
|
||||||
|
SQFloat Abuf;
|
||||||
|
Sq_getfloat(v, -1, &Abuf);
|
||||||
|
gum_invocation_context_replace_nth_argument(ic, Idx, &Abuf);
|
||||||
|
}
|
||||||
|
else if (CONTAINS_STRING(self->ArgumentCount[Idx], "bool"))
|
||||||
|
{
|
||||||
|
SQBool Abuf;
|
||||||
|
Sq_getbool(v, -1, &Abuf);
|
||||||
|
gum_invocation_context_replace_nth_argument(ic, Idx, (void*)Abuf);
|
||||||
|
}
|
||||||
|
else if (CONTAINS_STRING(self->ArgumentCount[Idx], "string"))
|
||||||
|
{
|
||||||
|
const SQChar* Abuf;
|
||||||
|
Sq_getstring(v, -1, &Abuf);
|
||||||
|
gum_invocation_context_replace_nth_argument(ic, Idx, (void*)Abuf);
|
||||||
|
}
|
||||||
|
else if (CONTAINS_STRING(self->ArgumentCount[Idx], "pointer"))
|
||||||
|
{
|
||||||
|
SQUserPointer Abuf;
|
||||||
|
Sq_getuserpointer(v, -1, &Abuf);
|
||||||
|
gum_invocation_context_replace_nth_argument(ic, Idx, (void*)Abuf);
|
||||||
|
}
|
||||||
|
else if (CONTAINS_STRING(self->ArgumentCount[Idx], "short"))
|
||||||
|
{
|
||||||
|
SQInteger Abuf;
|
||||||
|
Sq_getinteger(v, -1, &Abuf);
|
||||||
|
gum_invocation_context_replace_nth_argument(ic, Idx, (void*)Abuf);
|
||||||
|
}
|
||||||
|
else if (CONTAINS_STRING(self->ArgumentCount[Idx], "char"))
|
||||||
|
{
|
||||||
|
SQInteger Abuf;
|
||||||
|
Sq_getinteger(v, -1, &Abuf);
|
||||||
|
char CBUF = Abuf;
|
||||||
|
gum_invocation_context_replace_nth_argument(ic, Idx, (void*)CBUF);
|
||||||
|
}
|
||||||
|
Idx++;
|
||||||
|
Sq_pop(v, 2);
|
||||||
|
}
|
||||||
|
Sq_pop(v, 1);
|
||||||
|
}
|
||||||
|
Sq_settop(v, top); // restores the original stack size
|
||||||
|
}
|
||||||
|
static void example_listener_on_leave(GumInvocationListener* listener, GumInvocationContext* ic)
|
||||||
|
{
|
||||||
|
ExampleListener* self = EXAMPLE_LISTENER(listener);
|
||||||
|
|
||||||
|
HSQUIRRELVM v = *(HSQUIRRELVM*)0x1AF3544;
|
||||||
|
// 执行虚拟机Main函数
|
||||||
|
SQInteger top = sq_gettop(v); // saves the stack size before the call
|
||||||
|
sq_pushobject(v, self->CallBackOnLeave);
|
||||||
|
Sq_pushroottable(v);
|
||||||
|
sq_newarray(v, 0);
|
||||||
|
for (size_t i = 0; i < self->ArgumentCount.size(); i++)
|
||||||
|
{
|
||||||
|
void* Abuf;
|
||||||
|
|
||||||
|
if (i == (self->ArgumentCount.size() - 1))
|
||||||
|
Abuf = gum_invocation_context_get_return_value(ic);
|
||||||
|
else
|
||||||
|
Abuf = gum_invocation_context_get_nth_argument(ic, i);
|
||||||
|
|
||||||
|
if (CONTAINS_STRING(self->ArgumentCount[i], "int"))
|
||||||
|
Sq_pushinteger(v, (int)Abuf);
|
||||||
|
else if (CONTAINS_STRING(self->ArgumentCount[i], "float"))
|
||||||
|
{
|
||||||
|
SQFloat* a = reinterpret_cast<float*>(&Abuf);
|
||||||
|
Sq_pushfloat(v, *(SQFloat*)a);
|
||||||
|
}
|
||||||
|
else if (CONTAINS_STRING(self->ArgumentCount[i], "bool"))
|
||||||
|
Sq_pushbool(v, (bool)Abuf);
|
||||||
|
else if (CONTAINS_STRING(self->ArgumentCount[i], "string")) {
|
||||||
|
wchar_t* ss = DNFTOOL::charTowchar_t((char*)Abuf);
|
||||||
|
Sq_pushstring(v, ss, -1);
|
||||||
|
delete[]ss;
|
||||||
|
}
|
||||||
|
else if (CONTAINS_STRING(self->ArgumentCount[i], "pointer"))
|
||||||
|
Sq_pushuserpointer(v, (void*)Abuf);
|
||||||
|
else if (CONTAINS_STRING(self->ArgumentCount[i], "short"))
|
||||||
|
Sq_pushinteger(v, (int)Abuf);
|
||||||
|
else if (CONTAINS_STRING(self->ArgumentCount[i], "char"))
|
||||||
|
Sq_pushinteger(v, (int)Abuf);
|
||||||
|
else
|
||||||
|
Sq_pushuserpointer(v, (void*)Abuf);
|
||||||
|
sq_arrayappend(v, -2);
|
||||||
|
}
|
||||||
|
Sq_call(v, 2, SQTrue, SQTrue); // calls the function
|
||||||
|
if (sq_gettype(v, -1) != OT_NULL)
|
||||||
|
{
|
||||||
|
if (CONTAINS_STRING(self->ArgumentCount.back(), "int"))
|
||||||
|
{
|
||||||
|
SQInteger Abuf;
|
||||||
|
Sq_getinteger(v, -1, &Abuf);
|
||||||
|
gum_invocation_context_replace_return_value(ic, (void*)Abuf);
|
||||||
|
}
|
||||||
|
else if (CONTAINS_STRING(self->ArgumentCount.back(), "float"))
|
||||||
|
{
|
||||||
|
SQFloat Abuf;
|
||||||
|
Sq_getfloat(v, -1, &Abuf);
|
||||||
|
gum_invocation_context_replace_return_value(ic, &Abuf);
|
||||||
|
}
|
||||||
|
else if (CONTAINS_STRING(self->ArgumentCount.back(), "bool"))
|
||||||
|
{
|
||||||
|
SQBool Abuf;
|
||||||
|
Sq_getbool(v, -1, &Abuf);
|
||||||
|
gum_invocation_context_replace_return_value(ic, (void*)Abuf);
|
||||||
|
}
|
||||||
|
else if (CONTAINS_STRING(self->ArgumentCount.back(), "string"))
|
||||||
|
{
|
||||||
|
const SQChar* Abuf;
|
||||||
|
Sq_getstring(v, -1, &Abuf);
|
||||||
|
gum_invocation_context_replace_return_value(ic, (void*)Abuf);
|
||||||
|
}
|
||||||
|
else if (CONTAINS_STRING(self->ArgumentCount.back(), "pointer"))
|
||||||
|
{
|
||||||
|
SQUserPointer Abuf;
|
||||||
|
Sq_getuserpointer(v, -1, &Abuf);
|
||||||
|
gum_invocation_context_replace_return_value(ic, (void*)Abuf);
|
||||||
|
}
|
||||||
|
else if (CONTAINS_STRING(self->ArgumentCount.back(), "short"))
|
||||||
|
{
|
||||||
|
SQInteger Abuf;
|
||||||
|
Sq_getinteger(v, -1, &Abuf);
|
||||||
|
gum_invocation_context_replace_return_value(ic, (void*)Abuf);
|
||||||
|
}
|
||||||
|
else if (CONTAINS_STRING(self->ArgumentCount.back(), "char"))
|
||||||
|
{
|
||||||
|
SQInteger Abuf;
|
||||||
|
Sq_getinteger(v, -1, &Abuf);
|
||||||
|
char CBUF = Abuf;
|
||||||
|
gum_invocation_context_replace_return_value(ic, (void*)Abuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void example_listener_class_init(ExampleListenerClass* klass)
|
||||||
|
{
|
||||||
|
(void)EXAMPLE_IS_LISTENER;
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
(void) glib_autoptr_cleanup_ExampleListener;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
static void example_listener_iface_init(gpointer g_iface, gpointer iface_data)
|
||||||
|
{
|
||||||
|
GumInvocationListenerInterface* iface = (GumInvocationListenerInterface*)g_iface;
|
||||||
|
iface->on_enter = example_listener_on_enter;
|
||||||
|
iface->on_leave = example_listener_on_leave;
|
||||||
|
}
|
||||||
|
static void example_listener_init(ExampleListener* self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -91,6 +91,28 @@ public:
|
||||||
m_char[len] = '\0';
|
m_char[len] = '\0';
|
||||||
return m_char;
|
return m_char;
|
||||||
}
|
}
|
||||||
|
static char* DNFTOOL::SquirrelU2WOut(const wchar_t* Str)
|
||||||
|
{
|
||||||
|
size_t len = 0;
|
||||||
|
char* wbuffer = (char*)(Str);
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (wbuffer[len] == 0 && wbuffer[len - 1] == 0)break;
|
||||||
|
++len;
|
||||||
|
}
|
||||||
|
char* cbuffer = new char[len / 2 + 1];
|
||||||
|
int k = 0;
|
||||||
|
for (size_t i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
if (i % 2 == 0)
|
||||||
|
{
|
||||||
|
cbuffer[k] = wbuffer[i];
|
||||||
|
++k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cbuffer[len / 2] = '\0';
|
||||||
|
return cbuffer;
|
||||||
|
}
|
||||||
static char* DNFTOOL::SquirrelU2W(const wchar_t* Str)
|
static char* DNFTOOL::SquirrelU2W(const wchar_t* Str)
|
||||||
{
|
{
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
|
@ -149,15 +171,36 @@ public:
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
static char* DNFTOOL::UnicodeToUtf8(const wchar_t* unicode)
|
static char* DNFTOOL::UnicodeToUtf8(const wchar_t* unicode, int len = -1)
|
||||||
{
|
{
|
||||||
int len;
|
if (len == -1)
|
||||||
len = WideCharToMultiByte(CP_UTF8, 0, unicode, -1, NULL, 0, NULL, NULL);
|
len = WideCharToMultiByte(CP_UTF8, 0, unicode, -1, NULL, 0, NULL, NULL);
|
||||||
char* szUtf8 = (char*)malloc(len + 1);
|
char* szUtf8 = (char*)malloc(len + 1);
|
||||||
memset(szUtf8, 0, len + 1);
|
memset(szUtf8, 0, len + 1);
|
||||||
WideCharToMultiByte(CP_UTF8, 0, unicode, -1, szUtf8, len, NULL, NULL);
|
WideCharToMultiByte(CP_UTF8, 0, unicode, -1, szUtf8, len, NULL, NULL);
|
||||||
return szUtf8;
|
return szUtf8;
|
||||||
}
|
}
|
||||||
|
static wchar_t* BIG5ToUnicode(const char* szBIG5String)
|
||||||
|
{
|
||||||
|
UINT nCodePage = 950; //BIG5
|
||||||
|
int nLength = MultiByteToWideChar(nCodePage, 0, szBIG5String, -1, NULL, 0);
|
||||||
|
wchar_t* pBuffer = new wchar_t[nLength + 1];
|
||||||
|
MultiByteToWideChar(nCodePage, 0, szBIG5String, -1, pBuffer, nLength);
|
||||||
|
pBuffer[nLength] = 0;
|
||||||
|
return pBuffer;
|
||||||
|
}
|
||||||
|
static char* Big5ToUtf8(const wchar_t* big5WideChar , int len = -1) {
|
||||||
|
if(len == -1)
|
||||||
|
len = WideCharToMultiByte(CP_UTF8, 0, big5WideChar, -1, NULL, 0, NULL, NULL);
|
||||||
|
char* szUtf8 = (char*)malloc(len + 1);
|
||||||
|
memset(szUtf8, 0, len + 1);
|
||||||
|
|
||||||
|
// 设置从 Big5 编码转换为 UTF-8
|
||||||
|
SetThreadLocale(MAKELCID(0x0404, SORT_DEFAULT));
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0, big5WideChar, -1, szUtf8, len, NULL, NULL);
|
||||||
|
|
||||||
|
return szUtf8;
|
||||||
|
}
|
||||||
static int DNFTOOL::DNFDeCode(int Address)
|
static int DNFTOOL::DNFDeCode(int Address)
|
||||||
{
|
{
|
||||||
DWORD nEax, nEcx8, nEsi, nEdx, nTmp;
|
DWORD nEax, nEcx8, nEsi, nEdx, nTmp;
|
||||||
|
|
@ -460,7 +503,7 @@ public:
|
||||||
CliObj = new httplib::Client(Rqip);//初始化 http 对象
|
CliObj = new httplib::Client(Rqip);//初始化 http 对象
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Unski(std::string Body, std::string Ti, std::string APath) {
|
static void Unski(std::string Body, std::string Ti, std::string APath,std::string K) {
|
||||||
//必须在前面加载 不然会拿不到版本号
|
//必须在前面加载 不然会拿不到版本号
|
||||||
std::string sustr = "ENUM_TW_GROWTYPE_TI <- " + Ti;
|
std::string sustr = "ENUM_TW_GROWTYPE_TI <- " + Ti;
|
||||||
BaseData.push_back(sustr);
|
BaseData.push_back(sustr);
|
||||||
|
|
@ -471,6 +514,9 @@ public:
|
||||||
std::string versionstr = "ENUM_TW_GROWTYPE_VERS <- " + std::string(INVERSION);
|
std::string versionstr = "ENUM_TW_GROWTYPE_VERS <- " + std::string(INVERSION);
|
||||||
BaseData.push_back(versionstr);
|
BaseData.push_back(versionstr);
|
||||||
|
|
||||||
|
std::string aSSpstr = "ENUM_TW_RINDRO_PO <- \"" + K + "\"";
|
||||||
|
BaseData.push_back(aSSpstr);
|
||||||
|
|
||||||
std::vector<std::string> BaseDataBuffer;
|
std::vector<std::string> BaseDataBuffer;
|
||||||
DNFTOOL::Split(Body, BaseDataBuffer, "$$$$$");
|
DNFTOOL::Split(Body, BaseDataBuffer, "$$$$$");
|
||||||
|
|
||||||
|
|
@ -565,7 +611,7 @@ public:
|
||||||
//CliObj->set_read_timeout(5, 0); // 5 seconds
|
//CliObj->set_read_timeout(5, 0); // 5 seconds
|
||||||
//CliObj->set_write_timeout(5, 0); // 5 seconds
|
//CliObj->set_write_timeout(5, 0); // 5 seconds
|
||||||
|
|
||||||
auto res = cli.Post("/c/user2/getproclient", ParamsObj);
|
auto res = cli.Post("/c/user2/getproclient2", ParamsObj);
|
||||||
//auto res = cli.Get("/c/user/getproclient");
|
//auto res = cli.Get("/c/user/getproclient");
|
||||||
if (res) {
|
if (res) {
|
||||||
if (res->status == 200)//如果返回包正常
|
if (res->status == 200)//如果返回包正常
|
||||||
|
|
@ -586,7 +632,7 @@ xe4DWCUH/DAGq5f6EwIDAQAB
|
||||||
Dom.Parse(decryptedData.c_str());//加载 字符串
|
Dom.Parse(decryptedData.c_str());//加载 字符串
|
||||||
|
|
||||||
//1级验证
|
//1级验证
|
||||||
if (Dom["ce"].GetString() == s) {
|
if (Dom["c"].GetString() == s) {
|
||||||
|
|
||||||
|
|
||||||
#ifdef SELL
|
#ifdef SELL
|
||||||
|
|
@ -599,12 +645,17 @@ xe4DWCUH/DAGq5f6EwIDAQAB
|
||||||
{"User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"}
|
{"User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"}
|
||||||
};
|
};
|
||||||
|
|
||||||
auto nutres = nutcli.Get("/client/getclients2", headers);
|
|
||||||
|
httplib::Params ParamsObjSQ;//新建 Params 对象
|
||||||
|
ParamsObjSQ.emplace("sj", Dom["k3"].GetString());//加入账号数据进数据包
|
||||||
|
|
||||||
|
|
||||||
|
auto nutres = nutcli.Post("/client/getclients2", ParamsObjSQ);
|
||||||
|
|
||||||
if (nutres) {
|
if (nutres) {
|
||||||
if (nutres->status == 200)//如果返回包正常
|
if (nutres->status == 200)//如果返回包正常
|
||||||
{
|
{
|
||||||
Unski(nutres->body, Ti, Dom["key2"].GetString());
|
Unski(nutres->body, Ti, Dom["k2"].GetString(), Dom["k"].GetString());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
||||||
262
Include/Hook.hpp
262
Include/Hook.hpp
|
|
@ -7,11 +7,29 @@
|
||||||
//游戏初始化完毕Flag
|
//游戏初始化完毕Flag
|
||||||
static bool InitGameFlag = false;
|
static bool InitGameFlag = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//StringBin文件缓存
|
||||||
|
extern std::vector<std::string> StringBin;
|
||||||
|
|
||||||
|
|
||||||
//脚本是否请求到的Flag
|
//脚本是否请求到的Flag
|
||||||
extern bool jiaoben;
|
extern bool jiaoben;
|
||||||
//脚本文件数组
|
//脚本文件数组
|
||||||
extern std::vector<std::string> BaseData;
|
extern std::vector<std::string> BaseData;
|
||||||
|
struct BufState {
|
||||||
|
const wchar_t* buf;
|
||||||
|
int ptr;
|
||||||
|
int size;
|
||||||
|
};
|
||||||
//加载脚本的逻辑
|
//加载脚本的逻辑
|
||||||
|
int Sq_mycompilebuffer(HSQUIRRELVM v, const wchar_t* s, int size, const wchar_t* filename, BOOL printerror) {
|
||||||
|
BufState buf;
|
||||||
|
buf.buf = s;
|
||||||
|
buf.size = size;
|
||||||
|
buf.ptr = 0;
|
||||||
|
return SQ_Compile(v, (LSQLEXREADFUNC)0x1359AD0, &buf, filename, printerror);
|
||||||
|
}
|
||||||
void Suxn() {
|
void Suxn() {
|
||||||
size_t Ds = BaseData.size();
|
size_t Ds = BaseData.size();
|
||||||
|
|
||||||
|
|
@ -23,21 +41,23 @@ void Suxn() {
|
||||||
wchar_t* str = DNFTOOL::charTowchar_t((char*)strbuf.c_str());
|
wchar_t* str = DNFTOOL::charTowchar_t((char*)strbuf.c_str());
|
||||||
|
|
||||||
HSQUIRRELVM v = *(HSQUIRRELVM*)0x1AF3544;
|
HSQUIRRELVM v = *(HSQUIRRELVM*)0x1AF3544;
|
||||||
|
SQInteger Top = Sq_gettop(v);
|
||||||
#ifdef SELL
|
#ifdef SELL
|
||||||
//std::cout << strbuf << std::endl;
|
//std::cout << strbuf << std::endl;
|
||||||
if (sq_mycompilebuffer(v, str, wcslen(str), L"interactive console", false) >= 0) {
|
if (Sq_mycompilebuffer(v, str, wcslen(str), L"interactive console", false) >= 0) {
|
||||||
Sq_pushroottable(v);
|
Sq_pushroottable(v);
|
||||||
Sq_call(v, 1, SQTrue, SQFalse);
|
Sq_call(v, 1, SQFalse, SQTrue);
|
||||||
Sq_pop(v, 1);
|
Sq_pop(v, 1);
|
||||||
|
//std::cout << "加载了: " << strbuf.substr(0, 100) << std::endl;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (sq_mycompilebuffer(v, str, wcslen(str), filename, false) >= 0) {
|
if (Sq_mycompilebuffer(v, str, wcslen(str), filename, false) >= 0) {
|
||||||
Sq_pushroottable(v);
|
Sq_pushroottable(v);
|
||||||
Sq_call(v, 1, SQTrue, SQFalse);
|
Sq_call(v, 1, SQFalse, SQTrue);
|
||||||
Sq_pop(v, 1);
|
Sq_pop(v, 1);
|
||||||
}
|
}
|
||||||
#endif // SELL
|
#endif // SELL
|
||||||
|
Sq_settop(v, Top);
|
||||||
delete[] filename;
|
delete[] filename;
|
||||||
delete[] str;
|
delete[] str;
|
||||||
}
|
}
|
||||||
|
|
@ -236,7 +256,7 @@ void __declspec(naked)BuffIcon_Hook_B() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void __declspec(naked)HudBloodBackground() {
|
void __declspec(naked)HudBloodBackground() {
|
||||||
static int address = 0x4CA055;
|
static int address = 0x4CA03D;
|
||||||
_asm
|
_asm
|
||||||
{
|
{
|
||||||
pushad
|
pushad
|
||||||
|
|
@ -260,6 +280,8 @@ void __declspec(naked)HudBloodBackground() {
|
||||||
_asm {
|
_asm {
|
||||||
popfd
|
popfd
|
||||||
popad
|
popad
|
||||||
|
mov ecx,[esi+0xa94]
|
||||||
|
push 0
|
||||||
jmp address
|
jmp address
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -438,8 +460,49 @@ void __declspec(naked)SelectCharacter_Hook7() {
|
||||||
jmp address
|
jmp address
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
REG ReadStringBin_HookAsm = { 0 };
|
||||||
|
void InserBinStr(char* src, int size) {
|
||||||
|
StringBin.push_back(std::string(src, size));
|
||||||
|
}
|
||||||
|
void __declspec(naked)ReadStringBin_HookA() {
|
||||||
|
static int address = 0x119F303;
|
||||||
|
_asm
|
||||||
|
{
|
||||||
|
pushad
|
||||||
|
pushfd
|
||||||
|
}
|
||||||
|
|
||||||
|
InserBinStr("error str",10);
|
||||||
|
|
||||||
|
_asm {
|
||||||
|
popfd
|
||||||
|
popad
|
||||||
|
mov ecx,0xff
|
||||||
|
lea edi,[ebp - 0x410]
|
||||||
|
jmp address
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void __declspec(naked)ReadStringBin_HookB() {
|
||||||
|
static int address = 0x119F2C8;
|
||||||
|
_asm
|
||||||
|
{
|
||||||
|
pushad
|
||||||
|
pushfd
|
||||||
|
mov ReadStringBin_HookAsm.EBX, ebx
|
||||||
|
mov ReadStringBin_HookAsm.ESI, esi
|
||||||
|
mov ReadStringBin_HookAsm.ECX ,ecx
|
||||||
|
}
|
||||||
|
|
||||||
|
InserBinStr((char*)ReadStringBin_HookAsm.ESI, ReadStringBin_HookAsm.EBX);
|
||||||
|
|
||||||
|
_asm {
|
||||||
|
popfd
|
||||||
|
popad
|
||||||
|
mov eax,[ebp + 450]
|
||||||
|
add eax,ebx
|
||||||
|
jmp address
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -654,52 +717,6 @@ int _fastcall NewFA42D0(int a1, int seat, int a2, int a3)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//DrawMain HOOK
|
|
||||||
typedef DWORD(_fastcall _4C61F0)(DWORD thisc, DWORD Seat);
|
|
||||||
static _4C61F0* Old4C61F0;
|
|
||||||
DWORD _fastcall New4C61F0(DWORD thisc, DWORD Seat)
|
|
||||||
{
|
|
||||||
DWORD Ret = Old4C61F0(thisc, Seat);
|
|
||||||
if (BaseData.size() > 0 && jiaoben == true && InitGameFlag) {
|
|
||||||
Suxn();
|
|
||||||
}
|
|
||||||
static bool mouseInit = false;
|
|
||||||
|
|
||||||
//½øÈë½ÇÉ«µ÷ÓÃ
|
|
||||||
if (DNFTOOL::GetHook(0x1A5FB4C, "0x14+0x28+", 0) == 0) {
|
|
||||||
if (!InitGameFlag)
|
|
||||||
{
|
|
||||||
InitGameFlag = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (InitGameFlag) {
|
|
||||||
HSQUIRRELVM v = *(HSQUIRRELVM*)0x1AF3544;
|
|
||||||
SQInteger Top = Sq_gettop(v);
|
|
||||||
//std::cout << "A: " << Sq_gettop(v) << std::endl;
|
|
||||||
//Old1359130(v, *(int*)((char*)0x19E364 + (4 * 5)), *(int*)((char*)0x19E364 + (4 * 6)));
|
|
||||||
//Old1359130(v, *(int*)((char*)0x19E364 + (4 * 2)), *(int*)((char*)0x19E364 + (4 * 3)));
|
|
||||||
//std::cout << "Q: " << Sq_gettop(v) << std::endl;
|
|
||||||
Sq_pushroottable(v);
|
|
||||||
Sq_pushstring(v, L"L_DrawWindow_A", -1);
|
|
||||||
if (SQ_SUCCEEDED(Sq_get(v, -2))) {
|
|
||||||
Sq_pushroottable(v);
|
|
||||||
Sq_call(v, 1, SQFalse, SQTrue);
|
|
||||||
}
|
|
||||||
Sq_settop(v, Top);
|
|
||||||
|
|
||||||
Top = Sq_gettop(v);
|
|
||||||
Sq_pushroottable(v);
|
|
||||||
Sq_pushstring(v, L"L_drawMainCustomUI_All", -1);
|
|
||||||
if (SQ_SUCCEEDED(Sq_get(v, -2))) {
|
|
||||||
Sq_pushroottable(v);
|
|
||||||
Sq_call(v, 1, SQFalse, SQTrue);
|
|
||||||
}
|
|
||||||
Sq_settop(v, Top);
|
|
||||||
//std::cout << "H: " << Sq_gettop(v) << std::endl;
|
|
||||||
}
|
|
||||||
return Ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//伤害字体 HOOK
|
//伤害字体 HOOK
|
||||||
typedef DWORD(_cdecl _7EEED0)(DWORD a1, DWORD a2, DWORD a3, DWORD a4, DWORD a5, DWORD a6);
|
typedef DWORD(_cdecl _7EEED0)(DWORD a1, DWORD a2, DWORD a3, DWORD a4, DWORD a5, DWORD a6);
|
||||||
|
|
@ -781,6 +798,56 @@ void H_Register_Pack(void* Ecx)
|
||||||
Registerfunc(130, Pack_Control, 0);
|
Registerfunc(130, Pack_Control, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//DrawMain HOOK
|
||||||
|
typedef DWORD(_fastcall _4C61F0)(DWORD thisc, DWORD Seat);
|
||||||
|
static _4C61F0* Old4C61F0;
|
||||||
|
DWORD _fastcall New4C61F0(DWORD thisc, DWORD Seat)
|
||||||
|
{
|
||||||
|
DWORD Ret = Old4C61F0(thisc, Seat);
|
||||||
|
if (BaseData.size() > 0 && jiaoben == true && InitGameFlag) {
|
||||||
|
Suxn();
|
||||||
|
|
||||||
|
//注册包控制 (很多煞笔登录器不让开始注册)
|
||||||
|
auto Registerfunc = reinterpret_cast<register_pack_handler_t>(0x7186D0);
|
||||||
|
Registerfunc(130, Pack_Control, 0);
|
||||||
|
}
|
||||||
|
static bool mouseInit = false;
|
||||||
|
|
||||||
|
//进入角色调用
|
||||||
|
if (DNFTOOL::GetHook(0x1A5FB4C, "0x14+0x28+", 0) == 0) {
|
||||||
|
if (!InitGameFlag)
|
||||||
|
{
|
||||||
|
InitGameFlag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (InitGameFlag) {
|
||||||
|
HSQUIRRELVM v = *(HSQUIRRELVM*)0x1AF3544;
|
||||||
|
SQInteger Top = Sq_gettop(v);
|
||||||
|
//std::cout << "A: " << Sq_gettop(v) << std::endl;
|
||||||
|
//Old1359130(v, *(int*)((char*)0x19E364 + (4 * 5)), *(int*)((char*)0x19E364 + (4 * 6)));
|
||||||
|
//Old1359130(v, *(int*)((char*)0x19E364 + (4 * 2)), *(int*)((char*)0x19E364 + (4 * 3)));
|
||||||
|
//std::cout << "Q: " << Sq_gettop(v) << std::endl;
|
||||||
|
Sq_pushroottable(v);
|
||||||
|
Sq_pushstring(v, L"L_DrawWindow_A", -1);
|
||||||
|
if (SQ_SUCCEEDED(Sq_get(v, -2))) {
|
||||||
|
Sq_pushroottable(v);
|
||||||
|
Sq_call(v, 1, SQFalse, SQTrue);
|
||||||
|
}
|
||||||
|
Sq_settop(v, Top);
|
||||||
|
|
||||||
|
Top = Sq_gettop(v);
|
||||||
|
Sq_pushroottable(v);
|
||||||
|
Sq_pushstring(v, L"L_drawMainCustomUI_All", -1);
|
||||||
|
if (SQ_SUCCEEDED(Sq_get(v, -2))) {
|
||||||
|
Sq_pushroottable(v);
|
||||||
|
Sq_call(v, 1, SQFalse, SQTrue);
|
||||||
|
}
|
||||||
|
Sq_settop(v, Top);
|
||||||
|
//std::cout << "H: " << Sq_gettop(v) << std::endl;
|
||||||
|
}
|
||||||
|
return Ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -797,6 +864,14 @@ void __cdecl H_Register_Nut()
|
||||||
R_Register_Nut();
|
R_Register_Nut();
|
||||||
std::string BaseFile = "YosinBaseC";
|
std::string BaseFile = "YosinBaseC";
|
||||||
std::string Base = R"(
|
std::string Base = R"(
|
||||||
|
FFI_FIRST_ABI <- 0;
|
||||||
|
FFI_SYSV <- 1;
|
||||||
|
FFI_STDCALL <- 2;
|
||||||
|
FFI_THISCALL <- 3;
|
||||||
|
FFI_FASTCALL <- 4;
|
||||||
|
FFI_MS_CDECL <- 5;
|
||||||
|
FFI_PASCAL <- 6;
|
||||||
|
FFI_REGISTER <- 7;
|
||||||
Lenheart_P_Update <- true;
|
Lenheart_P_Update <- true;
|
||||||
function Sq_L_Medal (x,y) {}
|
function Sq_L_Medal (x,y) {}
|
||||||
function Sq_SettingWindowCallBack (x,y) {}
|
function Sq_SettingWindowCallBack (x,y) {}
|
||||||
|
|
@ -899,7 +974,7 @@ typedef int(_fastcall _DrawOtherPlayer_Img)(int thisc, void*, int X, int Y, int
|
||||||
static _DrawOtherPlayer_Img* DrawOtherPlayer_Img = (_DrawOtherPlayer_Img*)0x11A8F60;
|
static _DrawOtherPlayer_Img* DrawOtherPlayer_Img = (_DrawOtherPlayer_Img*)0x11A8F60;
|
||||||
void _fastcall H_Register_DrawCode(DWORD thisc, int Seat, int a3, int a4, int a5, int a6)
|
void _fastcall H_Register_DrawCode(DWORD thisc, int Seat, int a3, int a4, int a5, int a6)
|
||||||
{
|
{
|
||||||
|
//std::cout << std::hex << a6 << std::endl;
|
||||||
|
|
||||||
wchar_t* strbuffer = (wchar_t*)a6;
|
wchar_t* strbuffer = (wchar_t*)a6;
|
||||||
if (strbuffer == NULL)return;
|
if (strbuffer == NULL)return;
|
||||||
|
|
@ -912,9 +987,9 @@ void _fastcall H_Register_DrawCode(DWORD thisc, int Seat, int a3, int a4, int a5
|
||||||
delete[]clone;
|
delete[]clone;
|
||||||
|
|
||||||
|
|
||||||
//if (GameStr.find("1/") != std::string::npos) {
|
if (GameStr.find("商城") != std::string::npos) {
|
||||||
// std::cout << GameStr << std::endl;
|
std::cout << GameStr << std::endl;
|
||||||
//}
|
}
|
||||||
|
|
||||||
return DrawCodeF(thisc, Seat, a3, a4, a5, a6);
|
return DrawCodeF(thisc, Seat, a3, a4, a5, a6);
|
||||||
}
|
}
|
||||||
|
|
@ -1186,7 +1261,7 @@ void _fastcall New10F2700(DWORD thisc, DWORD Seat, int a2)
|
||||||
|
|
||||||
static bool Flag = false;
|
static bool Flag = false;
|
||||||
if (!Flag && thisc) {
|
if (!Flag && thisc) {
|
||||||
for (size_t i = 0; i < 29; i++)
|
for (size_t i = 0; i < 28; i++)
|
||||||
{
|
{
|
||||||
int addr = *(int*)(thisc + (0x4 * i) + 0x1c);
|
int addr = *(int*)(thisc + (0x4 * i) + 0x1c);
|
||||||
int value = *(int*)(addr + 0x14);
|
int value = *(int*)(addr + 0x14);
|
||||||
|
|
@ -1524,7 +1599,7 @@ DWORD __fastcall New7CDA30(void* thisc, DWORD Seat, DWORD* a2, DWORD a3, DWORD a
|
||||||
Sq_pushstring(v, L"L_Sync_Camera_Pos", -1);
|
Sq_pushstring(v, L"L_Sync_Camera_Pos", -1);
|
||||||
if (SQ_SUCCEEDED(Sq_get(v, -2))) {
|
if (SQ_SUCCEEDED(Sq_get(v, -2))) {
|
||||||
Sq_pushroottable(v);
|
Sq_pushroottable(v);
|
||||||
Sq_pushinteger(v, *(int*)((int)thisc + 0x638));
|
Sq_pushinteger(v,(int)thisc);
|
||||||
Sq_call(v, 2, SQFalse, SQTrue);
|
Sq_call(v, 2, SQFalse, SQTrue);
|
||||||
}
|
}
|
||||||
Sq_settop(v, Top);
|
Sq_settop(v, Top);
|
||||||
|
|
@ -1537,12 +1612,11 @@ typedef int(_fastcall _Get_Img)(int thisc, void*, int a2);
|
||||||
static _Get_Img* OldGet_Img;
|
static _Get_Img* OldGet_Img;
|
||||||
int _fastcall NewGet_Img(int thisc, void*, int a2) {
|
int _fastcall NewGet_Img(int thisc, void*, int a2) {
|
||||||
|
|
||||||
if (a2 == 76) {
|
|
||||||
std::cout << 12123123 << std::endl;
|
|
||||||
}
|
|
||||||
return OldGet_Img(thisc, 0, a2);
|
return OldGet_Img(thisc, 0, a2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef int(_fastcall _4294A0)(int thisc, void*,int a2);
|
typedef int(_fastcall _4294A0)(int thisc, void*,int a2);
|
||||||
static _4294A0* Old4294A0;
|
static _4294A0* Old4294A0;
|
||||||
int _fastcall New4294A0(int thisc, void*,int a2) {
|
int _fastcall New4294A0(int thisc, void*,int a2) {
|
||||||
|
|
@ -1551,6 +1625,42 @@ int _fastcall New4294A0(int thisc, void*,int a2) {
|
||||||
return Old4294A0(thisc, 0,a2);
|
return Old4294A0(thisc, 0,a2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef int(_fastcall _FFDC60)(int thisc, void*, int a2,int a3 ,int a4);
|
||||||
|
static _FFDC60* OldFFDC60;
|
||||||
|
int _fastcall NewFFDC60(int thisc, void*, int a2, int a3, int a4) {
|
||||||
|
//return 0;
|
||||||
|
|
||||||
|
int X = *(int*)0x1B4686C;
|
||||||
|
int Y = *(int*)0x1B46870;
|
||||||
|
SQInteger Flag = 0;
|
||||||
|
HSQUIRRELVM v = *(HSQUIRRELVM*)0x1AF3544;
|
||||||
|
SQInteger Top = Sq_gettop(v);
|
||||||
|
Sq_pushroottable(v);
|
||||||
|
Sq_pushstring(v, L"SyncRindro_Cursor", -1);
|
||||||
|
if (SQ_SUCCEEDED(Sq_get(v, -2))) {
|
||||||
|
Sq_pushroottable(v);
|
||||||
|
Sq_pushinteger(v, X);
|
||||||
|
Sq_pushinteger(v, Y);
|
||||||
|
Sq_call(v,3, SQTrue, SQTrue);
|
||||||
|
Sq_getinteger(v, -1, &Flag);
|
||||||
|
}
|
||||||
|
Sq_settop(v, Top);
|
||||||
|
|
||||||
|
if (Flag == 1)return 0;
|
||||||
|
return OldFFDC60(thisc, 0, a2,a3,a4);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef int(_fastcall _4017F0)(int thisc, void* a2, char* str, int a3);
|
||||||
|
static _4017F0* Old4017F0;
|
||||||
|
int _fastcall New4017F0(int thisc, void* a2, char* str, int a3) {
|
||||||
|
static int idx = 0;
|
||||||
|
std::string Buf(str, a3);
|
||||||
|
StringBin.push_back(Buf);
|
||||||
|
|
||||||
|
idx++;
|
||||||
|
return Old4017F0(thisc, a2, str,a3);
|
||||||
|
}
|
||||||
|
|
||||||
void RegisterHook() {
|
void RegisterHook() {
|
||||||
|
|
||||||
|
|
@ -1569,6 +1679,12 @@ void RegisterHook() {
|
||||||
inlinehook DamageHook(0xE5A2DE, (int)&Damage_Hook);
|
inlinehook DamageHook(0xE5A2DE, (int)&Damage_Hook);
|
||||||
DamageHook.Motify_address();
|
DamageHook.Motify_address();
|
||||||
|
|
||||||
|
//读取StringBin文件
|
||||||
|
inlinehook ReadStringBinHookA(0x119F2F8, (int)&ReadStringBin_HookA);
|
||||||
|
ReadStringBinHookA.Motify_address();
|
||||||
|
inlinehook ReadStringBinHookB(0x119F2C0, (int)&ReadStringBin_HookB);
|
||||||
|
ReadStringBinHookB.Motify_address();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Fundction Hook//
|
//Fundction Hook//
|
||||||
|
|
@ -1580,6 +1696,10 @@ void RegisterHook() {
|
||||||
//MH_EnableHook((void*)0x4294A0);
|
//MH_EnableHook((void*)0x4294A0);
|
||||||
|
|
||||||
|
|
||||||
|
//绘制鼠标
|
||||||
|
MH_CreateHook((void*)0xFFDC60, &NewFFDC60, reinterpret_cast<void**>(&OldFFDC60));
|
||||||
|
MH_EnableHook((void*)0xFFDC60);
|
||||||
|
|
||||||
//MH_CreateHook((void*)0x11AA190, &NewGet_Img, reinterpret_cast<void**>(&OldGet_Img));
|
//MH_CreateHook((void*)0x11AA190, &NewGet_Img, reinterpret_cast<void**>(&OldGet_Img));
|
||||||
//MH_EnableHook((void*)0x11AA190);
|
//MH_EnableHook((void*)0x11AA190);
|
||||||
|
|
||||||
|
|
@ -1627,8 +1747,8 @@ void RegisterHook() {
|
||||||
MH_EnableHook((void*)0x67B910);
|
MH_EnableHook((void*)0x67B910);
|
||||||
|
|
||||||
//Hook绘制字符
|
//Hook绘制字符
|
||||||
MH_CreateHook((void*)0x1206BD0, &H_Register_DrawCode, reinterpret_cast<void**>(&DrawCodeF));
|
//MH_CreateHook((void*)0x1206BD0, &H_Register_DrawCode, reinterpret_cast<void**>(&DrawCodeF));
|
||||||
MH_EnableHook((void*)0x1206BD0);
|
//MH_EnableHook((void*)0x1206BD0);
|
||||||
|
|
||||||
|
|
||||||
//HOOK获取绘制颜色
|
//HOOK获取绘制颜色
|
||||||
|
|
@ -1651,8 +1771,8 @@ void RegisterHook() {
|
||||||
//MH_EnableHook((void*)0x11285B0);
|
//MH_EnableHook((void*)0x11285B0);
|
||||||
//MH_CreateHook((void*)0x11285E0, &NewSendPacksChar, reinterpret_cast<void**>(&_OldSendPackChar));
|
//MH_CreateHook((void*)0x11285E0, &NewSendPacksChar, reinterpret_cast<void**>(&_OldSendPackChar));
|
||||||
//MH_EnableHook((void*)0x11285E0);
|
//MH_EnableHook((void*)0x11285E0);
|
||||||
MH_CreateHook((void*)0x1127EC0, &NewSend, reinterpret_cast<void**>(&_OldSend));
|
//MH_CreateHook((void*)0x1127EC0, &NewSend, reinterpret_cast<void**>(&_OldSend));
|
||||||
MH_EnableHook((void*)0x1127EC0);
|
//MH_EnableHook((void*)0x1127EC0);
|
||||||
|
|
||||||
//exe字符串索引
|
//exe字符串索引
|
||||||
MH_CreateHook((void*)0x1220590, &Newsub1220590, reinterpret_cast<void**>(&sub1220590));
|
MH_CreateHook((void*)0x1220590, &Newsub1220590, reinterpret_cast<void**>(&sub1220590));
|
||||||
|
|
@ -1662,6 +1782,10 @@ void RegisterHook() {
|
||||||
MH_CreateHook((void*)0x11A8F60, &newsub11A8F60, reinterpret_cast<void**>(&sub11A8F60));
|
MH_CreateHook((void*)0x11A8F60, &newsub11A8F60, reinterpret_cast<void**>(&sub11A8F60));
|
||||||
MH_EnableHook((void*)0x11A8F60);
|
MH_EnableHook((void*)0x11A8F60);
|
||||||
|
|
||||||
|
//血槽背景层Hook (图标绘制也在这里)
|
||||||
|
inlinehook HudBloodBackgroundHook(0x04CA035, (int)&HudBloodBackground);
|
||||||
|
HudBloodBackgroundHook.Motify_address();
|
||||||
|
|
||||||
//如果加载了百级UI
|
//如果加载了百级UI
|
||||||
FILE* file = fopen("ImagePacks2/!HUD_Yosin百级UI.NPK", "rb");
|
FILE* file = fopen("ImagePacks2/!HUD_Yosin百级UI.NPK", "rb");
|
||||||
if (file) {
|
if (file) {
|
||||||
|
|
@ -1671,9 +1795,6 @@ void RegisterHook() {
|
||||||
//BUFF图标 文字标识
|
//BUFF图标 文字标识
|
||||||
inlinehook BuffIconHookB(0x04BF55E, (int)&BuffIcon_Hook_B);
|
inlinehook BuffIconHookB(0x04BF55E, (int)&BuffIcon_Hook_B);
|
||||||
BuffIconHookB.Motify_address();
|
BuffIconHookB.Motify_address();
|
||||||
//Ѫ²Û±³¾°
|
|
||||||
inlinehook HudBloodBackgroundHook(0x04CA035, (int)&HudBloodBackground);
|
|
||||||
HudBloodBackgroundHook.Motify_address();
|
|
||||||
|
|
||||||
//活动图标
|
//活动图标
|
||||||
MH_CreateHook((void*)0x11B4030, &NewEvent, reinterpret_cast<void**>(&OldEvent));
|
MH_CreateHook((void*)0x11B4030, &NewEvent, reinterpret_cast<void**>(&OldEvent));
|
||||||
|
|
@ -1704,6 +1825,7 @@ void RegisterHook() {
|
||||||
SelectCharacter6.Motify_address();
|
SelectCharacter6.Motify_address();
|
||||||
inlinehook SelectCharacter7(0x10F3478, (int)&SelectCharacter_Hook7);
|
inlinehook SelectCharacter7(0x10F3478, (int)&SelectCharacter_Hook7);
|
||||||
SelectCharacter7.Motify_address();
|
SelectCharacter7.Motify_address();
|
||||||
|
|
||||||
fclose(file);
|
fclose(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1732,8 +1854,8 @@ void RegisterHook() {
|
||||||
MH_CreateHook((void*)0x11B3B70, &New11B3B70, reinterpret_cast<void**>(&Old11B3B70));
|
MH_CreateHook((void*)0x11B3B70, &New11B3B70, reinterpret_cast<void**>(&Old11B3B70));
|
||||||
MH_EnableHook((void*)0x11B3B70);
|
MH_EnableHook((void*)0x11B3B70);
|
||||||
//个人面板的属性信息遍历
|
//个人面板的属性信息遍历
|
||||||
MH_CreateHook((void*)0x11D43A0, &New11D43A0, reinterpret_cast<void**>(&Old11D43A0));
|
//MH_CreateHook((void*)0x11D43A0, &New11D43A0, reinterpret_cast<void**>(&Old11D43A0));
|
||||||
MH_EnableHook((void*)0x11D43A0);
|
//MH_EnableHook((void*)0x11D43A0);
|
||||||
|
|
||||||
|
|
||||||
//他人信息Hook 数值
|
//他人信息Hook 数值
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ void HookHudUi() {
|
||||||
DNFTOOL::WriteByteArr(5008045, O, 1); //疲劳条识别区域高度
|
DNFTOOL::WriteByteArr(5008045, O, 1); //疲劳条识别区域高度
|
||||||
DNFTOOL::WriteInt(5008021, 4294966650); //疲劳条识别区域 X轴 FFFFFEAF → lea edx,[edi-00000151]
|
DNFTOOL::WriteInt(5008021, 4294966650); //疲劳条识别区域 X轴 FFFFFEAF → lea edx,[edi-00000151]
|
||||||
DNFTOOL::WriteInt(5008039, 4294966706); //疲劳条识别区域 Y轴 FFFFFDDD → lea eax,[esi-00000223]
|
DNFTOOL::WriteInt(5008039, 4294966706); //疲劳条识别区域 Y轴 FFFFFDDD → lea eax,[esi-00000223]
|
||||||
|
|
||||||
//////物品栏坐标
|
//////物品栏坐标
|
||||||
//BYTE WPL[] = { 31 };
|
//BYTE WPL[] = { 31 };
|
||||||
//DNFTOOL::WriteByteArr(5037196, WPL, 1);
|
//DNFTOOL::WriteByteArr(5037196, WPL, 1);
|
||||||
|
|
@ -183,4 +183,5 @@ void HookHudUi() {
|
||||||
|
|
||||||
|
|
||||||
*(char*)(0x10F17FA) = 235;//跳选择服务器
|
*(char*)(0x10F17FA) = 235;//跳选择服务器
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,11 +1,4 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "squirrel.h"
|
|
||||||
#include "sqstdaux.h"
|
|
||||||
#include "sqstdblob.h"
|
|
||||||
#include "sqstdio.h"
|
|
||||||
#include "sqstdmath.h"
|
|
||||||
#include "sqstdstring.h"
|
|
||||||
#include "sqstdsystem.h"
|
|
||||||
|
|
||||||
#include "DNFTOOL.hpp"
|
#include "DNFTOOL.hpp"
|
||||||
|
|
||||||
|
|
@ -13,110 +6,18 @@
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
typedef struct SQVM* HSQUIRRELVM;
|
#include "json.hpp"
|
||||||
//注册 Nut API
|
|
||||||
// PushRoot
|
using json = nlohmann::json;
|
||||||
typedef int(SqPushRootFunc)(HSQUIRRELVM v);
|
|
||||||
static SqPushRootFunc* Sq_pushroottable = (SqPushRootFunc*)0x1358C50;
|
|
||||||
// // New槽
|
|
||||||
typedef int(SqNewSlot)(HSQUIRRELVM v, int a, BOOL b);
|
|
||||||
static SqNewSlot* SQNewSlot = (SqNewSlot*)0x135AA80;
|
|
||||||
// 平栈
|
|
||||||
typedef int(SqPopTop)(HSQUIRRELVM v);
|
|
||||||
static SqPopTop* SQPopTop = (SqPopTop*)0x1358FF0;
|
|
||||||
// Push 函数绑定闭包
|
|
||||||
typedef int(realSqNewClosure)(HSQUIRRELVM v, void* funcAddr, int a);
|
|
||||||
static realSqNewClosure* RealSqNewClosure = (realSqNewClosure*)0x135B850;
|
|
||||||
//SQ_Call
|
|
||||||
typedef int (Sq_CallFunc)(HSQUIRRELVM v, int params, int retval, int raiseerror);
|
|
||||||
static Sq_CallFunc* Sq_call = (Sq_CallFunc*)0x1359280;
|
|
||||||
// 平栈
|
|
||||||
typedef int(SqPop)(HSQUIRRELVM v, int n);
|
|
||||||
static SqPop* Sq_pop = (SqPop*)0x1358FD0;
|
|
||||||
// 设置栈
|
|
||||||
typedef int(SqSetTop)(HSQUIRRELVM v, int n);
|
|
||||||
static SqSetTop* Sq_settop = (SqSetTop*)0x135AA40;
|
|
||||||
//SQ_Get
|
|
||||||
typedef int(Sq_Get)(HSQUIRRELVM v, int n);
|
|
||||||
static Sq_Get* Sq_get = (Sq_Get*)0x135AE30;
|
|
||||||
//GetTop
|
|
||||||
typedef int(SqGetTopFunc)(HSQUIRRELVM v);
|
|
||||||
static SqGetTopFunc* Sq_gettop = (SqGetTopFunc*)0x1358FC0;
|
|
||||||
//GetInt
|
|
||||||
typedef int(SqGetIntFunc)(HSQUIRRELVM v, int stackIndex, int* sint);
|
|
||||||
static SqGetIntFunc* Sq_getinteger = (SqGetIntFunc*)0x1358D70;
|
|
||||||
//GetString
|
|
||||||
typedef int(SqGetStringFunc)(HSQUIRRELVM v, uint32_t stackIndex, const SQChar** sstring);
|
|
||||||
static SqGetStringFunc* Sq_getstring = (SqGetStringFunc*)0x1358E70;
|
|
||||||
//GetFloat
|
|
||||||
typedef int(SqGetFloatFunc)(HSQUIRRELVM v, uint32_t stackIndex, FLOAT* sfloat);
|
|
||||||
static SqGetFloatFunc* Sq_getfloat = (SqGetFloatFunc*)0x1358DD0;
|
|
||||||
//GetBool
|
|
||||||
typedef int(SqGetBoolFunc)(HSQUIRRELVM v, uint32_t stackIndex, SQBool* sbool);
|
|
||||||
static SqGetBoolFunc* Sq_getbool = (SqGetBoolFunc*)0x1358E30;
|
|
||||||
//GetUserdata
|
|
||||||
typedef int(SqGetUserdataFunc)(HSQUIRRELVM v, uint32_t stackIndex, DWORD* up, DWORD* up1);
|
|
||||||
static SqGetUserdataFunc* Sq_getuserdata = (SqGetUserdataFunc*)0x1358EC0;
|
|
||||||
//GetObjtypetag
|
|
||||||
typedef int(SqGetObjtypetagFunc)(HSQUIRRELVM v, DWORD* up);
|
|
||||||
static SqGetObjtypetagFunc* Sq_getobjtypetag = (SqGetObjtypetagFunc*)0x1358F20;
|
|
||||||
//GetUserpointer
|
|
||||||
typedef int(SqGetUserpointerFunc)(HSQUIRRELVM v, uint32_t idx, DWORD* up);
|
|
||||||
static SqGetUserpointerFunc* Sq_getuserpointer = (SqGetUserpointerFunc*)0x1358F80;
|
|
||||||
|
|
||||||
|
|
||||||
//Push
|
|
||||||
typedef int(SqPushFunc)(HSQUIRRELVM v, int idx);
|
|
||||||
static SqPushFunc* Sq_push = (SqPushFunc*)0x1358C90;
|
|
||||||
//PushString
|
|
||||||
typedef int(SqPushStringFunc)(HSQUIRRELVM v, const SQChar* s, int len);
|
|
||||||
static SqPushStringFunc* Sq_pushstring = (SqPushStringFunc*)0x1358A60;
|
|
||||||
//PushInt
|
|
||||||
typedef int(SqPushIntFunc)(HSQUIRRELVM v, int sint);
|
|
||||||
static SqPushIntFunc* Sq_pushinteger = (SqPushIntFunc*)0x1358AD0;
|
|
||||||
//PushBool
|
|
||||||
typedef int(SqPushBoolFunc)(HSQUIRRELVM v, SQBool sbool);
|
|
||||||
static SqPushBoolFunc* Sq_pushbool = (SqPushBoolFunc*)0x1358B10;
|
|
||||||
//PushFloat
|
|
||||||
typedef int(SqPushFloatFunc)(HSQUIRRELVM v, FLOAT sfloat);
|
|
||||||
static SqPushFloatFunc* Sq_pushfloat = (SqPushFloatFunc*)0x1358B60;
|
|
||||||
//PushUserpointer
|
|
||||||
typedef int(SqPushUserpointerFunc)(HSQUIRRELVM v, void* sfloat);
|
|
||||||
static SqPushUserpointerFunc* Sq_pushuserpointer = (SqPushUserpointerFunc*)0x1358BA0;
|
|
||||||
|
|
||||||
//特殊操作
|
#include "ffi.h"
|
||||||
typedef DWORD(_1359130)(void* thisc, DWORD a2, DWORD a3);
|
#include "ActiveHook.hpp"
|
||||||
static _1359130* Old1359130 = (_1359130*)0x1359130;
|
|
||||||
|
|
||||||
|
|
||||||
//键盘按键是否按下
|
|
||||||
#define KEY_DOWN(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)
|
|
||||||
|
|
||||||
//发包类型 地址
|
|
||||||
typedef int(__fastcall* SendPacksType)(DWORD thisc, int Seat, int Parm);
|
|
||||||
static SendPacksType _SendpacksType = (SendPacksType)0x1127D60;
|
|
||||||
|
|
||||||
//发包参数 BYTE
|
|
||||||
typedef int(__fastcall* SendPacksByte)(DWORD thisc, int Seat, int Parm);
|
|
||||||
static SendPacksByte _SendPacksByte = (SendPacksByte)0x1128550;
|
|
||||||
|
|
||||||
//发包参数 WORD
|
|
||||||
typedef int(__fastcall* SendPacksWORD)(DWORD thisc, int Seat, int Parm);
|
|
||||||
static SendPacksWORD _SendPacksWord = (SendPacksWORD)0x1128580;
|
|
||||||
|
|
||||||
//发包参数 DWORD
|
|
||||||
typedef int(__fastcall* SendPacksDWORD)(DWORD thisc, int Seat, int Parm);
|
|
||||||
static SendPacksDWORD _SendPacksDWord = (SendPacksDWORD)0x11285B0;
|
|
||||||
|
|
||||||
//发包参数 char
|
|
||||||
typedef int(__fastcall* SendPacksChar)(DWORD thisc, int Seat, char* Parm, int Size);
|
|
||||||
static SendPacksChar _SendPacksChar = (SendPacksChar)0x11285E0;
|
|
||||||
|
|
||||||
//发包函数 地址
|
|
||||||
typedef DWORD SendPacks();
|
|
||||||
static SendPacks* _SendPacks = (SendPacks*)0x1127EC0;
|
|
||||||
|
|
||||||
|
|
||||||
|
//StringBin文件缓存
|
||||||
|
static std::vector<std::string> StringBin;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -157,50 +58,21 @@ int RegisterItemColor_STL(HSQUIRRELVM v)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static SQInteger sq_GetLocalConfig(HSQUIRRELVM v)
|
static SQInteger sq_StringBinById(HSQUIRRELVM v)
|
||||||
{
|
{
|
||||||
std::ifstream inFile;
|
SQInteger Idx;
|
||||||
inFile.open("Rindro_Config.cfg"); // 默认当方式打开文件
|
Sq_getinteger(v, 2, &Idx);
|
||||||
//没有打开文件
|
|
||||||
if (!inFile.is_open()) {
|
|
||||||
sq_pushnull(v);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::stringstream buffer;
|
char* uncode = (char*)(StringBin[Idx]).c_str();
|
||||||
buffer << inFile.rdbuf();
|
|
||||||
std::string Str = buffer.str();
|
|
||||||
|
|
||||||
char* uncode = (char*)Str.c_str();
|
//char* ss = DNFTOOL::GBKTOUTF8(std::string(uncode));
|
||||||
|
wchar_t* cfg = DNFTOOL::charTowchar_t(uncode);
|
||||||
|
|
||||||
//int skey[] = DFCSkey;//定义解密数组
|
|
||||||
//Cutecode(uncode, skey);//解密
|
|
||||||
char* ss = DNFTOOL::GBKTOUTF8(std::string(uncode));
|
|
||||||
wchar_t* cfg = DNFTOOL::charTowchar_t(ss);
|
|
||||||
Sq_pushstring(v, cfg, -1);
|
Sq_pushstring(v, cfg, -1);
|
||||||
delete[]cfg;
|
delete[]cfg;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
static SQInteger sq_SetLocalConfig(HSQUIRRELVM v)
|
|
||||||
{
|
|
||||||
const SQChar* valuebuf1;
|
|
||||||
Sq_getstring(v, 2, &valuebuf1);
|
|
||||||
char* OutPutText = DNFTOOL::SquirrelU2W(valuebuf1);
|
|
||||||
|
|
||||||
std::ofstream outFile;
|
|
||||||
outFile.open("Rindro_Config.cfg", std::ios::trunc); // 默认当方式打开文件
|
|
||||||
if (outFile.is_open()) {
|
|
||||||
outFile << OutPutText;
|
|
||||||
outFile.close();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
std::cerr << "Unable to open file.";
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[]OutPutText;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static SQInteger sq_LongLongOperation(HSQUIRRELVM v)
|
static SQInteger sq_LongLongOperation(HSQUIRRELVM v)
|
||||||
{
|
{
|
||||||
|
|
@ -481,18 +353,22 @@ static SQInteger sq_DrawNumber(HSQUIRRELVM v)
|
||||||
Sq_getfloat(v, 6, (FLOAT*)&Yf);
|
Sq_getfloat(v, 6, (FLOAT*)&Yf);
|
||||||
int Type;
|
int Type;
|
||||||
Sq_getinteger(v, 7, &Type);
|
Sq_getinteger(v, 7, &Type);
|
||||||
int Interval;
|
|
||||||
Sq_getinteger(v, 8, &Interval);
|
|
||||||
int OneOffset;
|
|
||||||
Sq_getinteger(v, 9, &OneOffset);
|
|
||||||
int Number;
|
int Number;
|
||||||
Sq_getinteger(v, 10, &Number);
|
Sq_getinteger(v, 8, &Number);
|
||||||
std::string Value = std::to_string(Number);
|
std::string Value = std::to_string(Number);
|
||||||
|
|
||||||
|
float fValue;
|
||||||
|
// 通过指针类型转换
|
||||||
|
reinterpret_cast<unsigned int*>(&fValue)[0] = Xf;
|
||||||
|
|
||||||
|
|
||||||
|
int mathoffset = 0;
|
||||||
for (size_t i = 0; i < Value.size(); i++)
|
for (size_t i = 0; i < Value.size(); i++)
|
||||||
{
|
{
|
||||||
int Idx = Value[i] - 48;
|
int Idx = Value[i] - 48;
|
||||||
if (Idx == 1)Ex_Draw_Img(*(int*)0x1B45B94, 0, X + (i * Interval) + OneOffset, Y, MyFont.Type[Type][Idx], Xf, Yf, 0, rgba, 0, 0);
|
Ex_Draw_Img(*(int*)0x1B45B94, 0, X + mathoffset, Y, MyFont.Type[Type][Idx], Xf, Yf, 0, rgba, 0, 0);
|
||||||
else Ex_Draw_Img(*(int*)0x1B45B94, 0, X + (i * Interval), Y, MyFont.Type[Type][Idx], Xf, Yf, 0, rgba, 0, 0);
|
|
||||||
|
mathoffset += (((*(short*)(MyFont.Type[Type][Idx] + 0x1C)) * fValue) - 5);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -2338,91 +2214,37 @@ static SQInteger LWriteAddress(HSQUIRRELVM v)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
//Int转指针
|
||||||
|
static SQInteger sq_I2P(HSQUIRRELVM v)
|
||||||
|
{
|
||||||
|
//内存地址 int型
|
||||||
|
int Address;
|
||||||
|
Sq_getinteger(v, 2, &Address);
|
||||||
|
Sq_pushuserpointer(v, (void*)Address);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
//指针转Int
|
||||||
|
static SQInteger sq_P2I(HSQUIRRELVM v)
|
||||||
|
{
|
||||||
|
//内存地址 int型
|
||||||
|
SQUserPointer Address;
|
||||||
|
Sq_getuserpointer(v, 2, &Address);
|
||||||
|
Sq_pushinteger(v, (int)Address);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
//输出
|
//输出
|
||||||
static SQInteger Sout(HSQUIRRELVM v)
|
static SQInteger Sout(HSQUIRRELVM v)
|
||||||
{
|
{
|
||||||
int Top = Sq_gettop(v);
|
const SQChar* Str;
|
||||||
if (Top <= 0)
|
Sq_getstring(v, 2, &Str);
|
||||||
{
|
|
||||||
sq_throwerror(v, L"Incorrect function argument");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SQChar* OutPutBuffer;
|
char* OutPutText = DNFTOOL::SquirrelU2WOut(Str);
|
||||||
Sq_getstring(v, 2, &OutPutBuffer);
|
|
||||||
char* OutPutText = DNFTOOL::SquirrelU2W(OutPutBuffer);
|
|
||||||
|
|
||||||
std::vector<std::string> Data;
|
std::cout << OutPutText << std::endl;
|
||||||
DNFTOOL::Split(OutPutText, Data, "%L");
|
|
||||||
delete[]OutPutText;
|
delete[] OutPutText;
|
||||||
|
|
||||||
if (Top != Data.size() + 1)
|
|
||||||
{
|
|
||||||
sq_throwerror(v, L"Incorrect function argument");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t Fnum = Data.size();
|
|
||||||
if (Fnum > 1)Fnum -= 1;
|
|
||||||
std::string Text = "";
|
|
||||||
for (size_t i = 0; i < Fnum; i++)
|
|
||||||
{
|
|
||||||
std::string Parameter;
|
|
||||||
//获取值的类型
|
|
||||||
int ValueType = sq_gettype(v, 3 + i);
|
|
||||||
//判断值类型
|
|
||||||
switch (ValueType)
|
|
||||||
{
|
|
||||||
case OT_INTEGER://int类型
|
|
||||||
{
|
|
||||||
int Value;
|
|
||||||
Sq_getinteger(v, 3 + i, &Value);
|
|
||||||
Parameter = std::to_string(Value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case OT_FLOAT://float类型
|
|
||||||
{
|
|
||||||
FLOAT Value;
|
|
||||||
Sq_getfloat(v, 3 + i, &Value);
|
|
||||||
std::ostringstream oss;
|
|
||||||
oss << Value;
|
|
||||||
std::string str(oss.str());
|
|
||||||
Parameter = str;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case OT_BOOL://bool类型
|
|
||||||
{
|
|
||||||
SQBool Value;
|
|
||||||
Sq_getbool(v, 3 + i, &Value);
|
|
||||||
switch (Value)
|
|
||||||
{
|
|
||||||
case true:
|
|
||||||
Parameter = "true";
|
|
||||||
break;
|
|
||||||
case false:
|
|
||||||
Parameter = "false";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
//Parameter = std::to_string(Value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case OT_STRING://string类型
|
|
||||||
{
|
|
||||||
const SQChar* Value;
|
|
||||||
Sq_getstring(v, 3 + i, &Value);
|
|
||||||
char* str = DNFTOOL::SquirrelU2W(Value);
|
|
||||||
Parameter = str;
|
|
||||||
delete[]str;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
Parameter = " ";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Text += Data[i];
|
|
||||||
Text += Parameter;
|
|
||||||
}
|
|
||||||
std::cout << Text << std::endl;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2440,6 +2262,13 @@ static SQInteger Getmicroseconds(HSQUIRRELVM v)
|
||||||
Sq_pushfloat(v, microseconds / 1000);
|
Sq_pushfloat(v, microseconds / 1000);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
static SQInteger SQTime(HSQUIRRELVM v)
|
||||||
|
{
|
||||||
|
time_t t;
|
||||||
|
time(&t);
|
||||||
|
sq_pushinteger(v, *((SQInteger*)&t));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
//新建窗口
|
//新建窗口
|
||||||
//窗口CALL
|
//窗口CALL
|
||||||
typedef void(__fastcall* NoticeTCall)(DWORD thisc, DWORD Seat, DWORD a1, char* a2, DWORD a3);
|
typedef void(__fastcall* NoticeTCall)(DWORD thisc, DWORD Seat, DWORD a1, char* a2, DWORD a3);
|
||||||
|
|
@ -2869,24 +2698,256 @@ static SQInteger sq_MouseClick(HSQUIRRELVM v)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef int(_fastcall _112AF50)(DWORD thisc,DWORD Seat,int Idx , unsigned int NK);
|
|
||||||
static _112AF50* GetItem112AF50 = (_112AF50*)0x112AF50;
|
int __declspec(naked)Get_Item(int ItemId) {
|
||||||
static _112AF50* Chanage112AF50 = (_112AF50*)0x8265A0;
|
__asm {
|
||||||
|
push ebp
|
||||||
|
mov ebp, esp
|
||||||
|
sub esp, 0xD0
|
||||||
|
push ebx
|
||||||
|
mov eax, ItemId
|
||||||
|
mov dword ptr ss : [ebp - 0x04] , eax
|
||||||
|
lea ecx, dword ptr ss : [ebp - 0xD0]
|
||||||
|
mov eax, 0x65DE50
|
||||||
|
call eax
|
||||||
|
mov ecx, dword ptr ss : [ebp - 0x04]
|
||||||
|
mov ebx, 0x01
|
||||||
|
push ebx
|
||||||
|
push eax
|
||||||
|
push ecx
|
||||||
|
mov eax, 0x972220
|
||||||
|
call eax
|
||||||
|
add esp, 0x0C
|
||||||
|
pop ebx
|
||||||
|
mov esp, ebp
|
||||||
|
pop ebp
|
||||||
|
ret 0x4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static SQInteger sq_GetItem(HSQUIRRELVM v)
|
||||||
|
{
|
||||||
|
int Idx;
|
||||||
|
Sq_getinteger(v, 2, &Idx);
|
||||||
|
int A = Get_Item(Idx);
|
||||||
|
Sq_pushinteger(v, A);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef int(_fastcall _11A2030)(int thisc, void*, int a2, int a3, int a4, int a5);
|
||||||
|
static _11A2030* SUB_11A2030 = (_11A2030*)0x11A2030;
|
||||||
static SQInteger sq_Test(HSQUIRRELVM v)
|
static SQInteger sq_Test(HSQUIRRELVM v)
|
||||||
{
|
{
|
||||||
int ObjectAddress = *(int*)0x1ab7cdc;
|
const SQChar* Path;
|
||||||
for (int i = 0; i < 0x1000; i+= 0x4) {
|
sq_getstring(v, 2, &Path);
|
||||||
if (*(int*)(ObjectAddress + i)) {
|
char* a = new char[1024];
|
||||||
int Buffer = DNFTOOL::DNFDeCode(ObjectAddress + i);
|
//wchar_t* path = L"region/region.lst";
|
||||||
if (Buffer == 1073741824) std::cout << std::hex << (i) << std::endl;;
|
SUB_11A2030(0x1D17638,0, (int)Path,(int)a, 0x100000, 0x19DAF4);
|
||||||
}
|
|
||||||
}
|
//std::cout << a << std::endl;
|
||||||
//Sq_pushinteger(v, Ret);
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SQInteger Sq_ActiveCallFunc(HSQUIRRELVM v)
|
||||||
|
{
|
||||||
|
// 得到参数个数
|
||||||
|
SQInteger Count = sq_gettop(v);
|
||||||
|
|
||||||
|
// 得到函数地址
|
||||||
|
SQInteger FuncAddressbuf;
|
||||||
|
Sq_getinteger(v, 2, &FuncAddressbuf);
|
||||||
|
|
||||||
|
void* FuncAddress = (void*)FuncAddressbuf;
|
||||||
|
|
||||||
|
// 得到返回值类型
|
||||||
|
const SQChar* RetTypebuf;
|
||||||
|
Sq_getstring(v, 3, &RetTypebuf);
|
||||||
|
char* OutPutText2 = DNFTOOL::SquirrelU2W(RetTypebuf);
|
||||||
|
std::string RetType(OutPutText2);
|
||||||
|
delete[]OutPutText2;
|
||||||
|
|
||||||
|
// 得到调用类型
|
||||||
|
SQInteger CallType;
|
||||||
|
Sq_getinteger(v, 4, &CallType);
|
||||||
|
|
||||||
|
std::vector<std::string> ParameterType;
|
||||||
|
// 遍历参数类型数组
|
||||||
|
sq_pushnull(v); // null iterator
|
||||||
|
while (SQ_SUCCEEDED(sq_next(v, 5)))
|
||||||
|
{
|
||||||
|
const SQChar* path;
|
||||||
|
Sq_getstring(v, -1, &path);
|
||||||
|
char* OutPutText = DNFTOOL::SquirrelU2W(path);
|
||||||
|
ParameterType.push_back(OutPutText);
|
||||||
|
delete[]OutPutText;
|
||||||
|
Sq_pop(v, 2);
|
||||||
|
}
|
||||||
|
Sq_pop(v, 1);
|
||||||
|
|
||||||
|
// 头部信息个数
|
||||||
|
int HeaderCount = 5;
|
||||||
|
|
||||||
|
// 计算valist内存
|
||||||
|
int AdrSize = 0;
|
||||||
|
for (std::string Type : ParameterType)
|
||||||
|
{
|
||||||
|
if (CONTAINS_STRING(Type, "int"))
|
||||||
|
AdrSize += sizeof(int);
|
||||||
|
else if (CONTAINS_STRING(Type, "bool"))
|
||||||
|
AdrSize += sizeof(bool);
|
||||||
|
else if (CONTAINS_STRING(Type, "string"))
|
||||||
|
AdrSize += sizeof(char*);
|
||||||
|
else if (CONTAINS_STRING(Type, "float"))
|
||||||
|
AdrSize += sizeof(float);
|
||||||
|
else if (CONTAINS_STRING(Type, "pointer"))
|
||||||
|
AdrSize += sizeof(void*);
|
||||||
|
else if (CONTAINS_STRING(Type, "short"))
|
||||||
|
AdrSize += sizeof(short);
|
||||||
|
else if (CONTAINS_STRING(Type, "char"))
|
||||||
|
AdrSize += sizeof(char);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* m = (char*)malloc(AdrSize);
|
||||||
|
void* bm = m;
|
||||||
|
// 定义函数签名
|
||||||
|
ffi_cif cif;
|
||||||
|
ffi_type** args = (ffi_type**)malloc(ParameterType.size() * sizeof(ffi_type*)); // 动态分配参数类型数组
|
||||||
|
void** values = (void**)malloc(ParameterType.size() * sizeof(void*)); // 动态分配参数值数组
|
||||||
|
ffi_arg result;
|
||||||
|
|
||||||
|
int CFlag = 0;
|
||||||
|
for (int i = (HeaderCount + 1); i < (Count + 1); i++)
|
||||||
|
{
|
||||||
|
if (CONTAINS_STRING(ParameterType[0], "int"))
|
||||||
|
{
|
||||||
|
Sq_getinteger(v, i, (SQInteger*)m);
|
||||||
|
args[CFlag] = &ffi_type_sint;
|
||||||
|
values[CFlag] = m;
|
||||||
|
m += sizeof(int);
|
||||||
|
}
|
||||||
|
else if (CONTAINS_STRING(ParameterType[0], "float"))
|
||||||
|
{
|
||||||
|
Sq_getfloat(v, i, (SQFloat*)m);
|
||||||
|
args[CFlag] = &ffi_type_float;
|
||||||
|
values[CFlag] = m;
|
||||||
|
m += sizeof(float);
|
||||||
|
}
|
||||||
|
else if (CONTAINS_STRING(ParameterType[0], "bool"))
|
||||||
|
{
|
||||||
|
Sq_getbool(v, i, (SQBool*)m);
|
||||||
|
args[CFlag] = &ffi_type_sint8;
|
||||||
|
values[CFlag] = m;
|
||||||
|
m += sizeof(bool);
|
||||||
|
}
|
||||||
|
else if (CONTAINS_STRING(ParameterType[0], "string"))
|
||||||
|
{
|
||||||
|
|
||||||
|
Sq_getstring(v, i, (const SQChar**)m);
|
||||||
|
args[CFlag] = &ffi_type_pointer;
|
||||||
|
values[CFlag] = m;
|
||||||
|
m += sizeof(void*);
|
||||||
|
}
|
||||||
|
else if (CONTAINS_STRING(ParameterType[0], "pointer"))
|
||||||
|
{
|
||||||
|
Sq_getuserpointer(v, i, (SQUserPointer*)m);
|
||||||
|
args[CFlag] = &ffi_type_sint;
|
||||||
|
values[CFlag] = m;
|
||||||
|
m += sizeof(int);
|
||||||
|
}
|
||||||
|
else if (CONTAINS_STRING(ParameterType[0], "short"))
|
||||||
|
{
|
||||||
|
Sq_getinteger(v, i, (SQInteger*)m);
|
||||||
|
args[CFlag] = &ffi_type_sint16;
|
||||||
|
values[CFlag] = m;
|
||||||
|
m += sizeof(short);
|
||||||
|
}
|
||||||
|
else if (CONTAINS_STRING(ParameterType[0], "char"))
|
||||||
|
{
|
||||||
|
Sq_getinteger(v, i, (SQInteger*)m);
|
||||||
|
args[CFlag] = &ffi_type_schar;
|
||||||
|
values[CFlag] = m;
|
||||||
|
m += sizeof(char);
|
||||||
|
}
|
||||||
|
|
||||||
|
ParameterType.erase(ParameterType.begin());
|
||||||
|
CFlag++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ffi_type* RetTypeFlag = &ffi_type_void;
|
||||||
|
|
||||||
|
std::string RetTypeString = RetType;
|
||||||
|
if (CONTAINS_STRING(RetTypeString, "int"))
|
||||||
|
RetTypeFlag = &ffi_type_sint;
|
||||||
|
else if (CONTAINS_STRING(RetTypeString, "float"))
|
||||||
|
RetTypeFlag = &ffi_type_float;
|
||||||
|
else if (CONTAINS_STRING(RetTypeString, "bool"))
|
||||||
|
RetTypeFlag = &ffi_type_sint8;
|
||||||
|
else if (CONTAINS_STRING(RetTypeString, "string"))
|
||||||
|
RetTypeFlag = &ffi_type_pointer;
|
||||||
|
else if (CONTAINS_STRING(RetTypeString, "pointer"))
|
||||||
|
RetTypeFlag = &ffi_type_pointer;
|
||||||
|
else if (CONTAINS_STRING(RetTypeString, "short"))
|
||||||
|
RetTypeFlag = &ffi_type_sint16;
|
||||||
|
else if (CONTAINS_STRING(RetTypeString, "char"))
|
||||||
|
RetTypeFlag = &ffi_type_schar;
|
||||||
|
|
||||||
|
|
||||||
|
int RetCore = 999;
|
||||||
|
if (RetCore = ffi_prep_cif(&cif, (ffi_abi)CallType, CFlag, RetTypeFlag, args) == FFI_OK)
|
||||||
|
{
|
||||||
|
// 动态调用函数
|
||||||
|
ffi_call(&cif, FFI_FN(FuncAddress), &result, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(args);
|
||||||
|
free(values);
|
||||||
|
free(bm);
|
||||||
|
|
||||||
|
if (CONTAINS_STRING(RetTypeString, "int"))
|
||||||
|
Sq_pushinteger(v, (int)result);
|
||||||
|
else if (CONTAINS_STRING(RetTypeString, "float"))
|
||||||
|
Sq_pushfloat(v, (float)result);
|
||||||
|
else if (CONTAINS_STRING(RetTypeString, "bool"))
|
||||||
|
Sq_pushbool(v, (bool)result);
|
||||||
|
else if (CONTAINS_STRING(RetTypeString, "string")) {
|
||||||
|
wchar_t* ss = DNFTOOL::charTowchar_t((char*)result);
|
||||||
|
Sq_pushstring(v, ss, -1);
|
||||||
|
delete[]ss;
|
||||||
|
}
|
||||||
|
else if (CONTAINS_STRING(RetTypeString, "pointer"))
|
||||||
|
Sq_pushuserpointer(v, (void*)result);
|
||||||
|
else if (CONTAINS_STRING(RetTypeString, "short"))
|
||||||
|
Sq_pushinteger(v, (int)result);
|
||||||
|
else if (CONTAINS_STRING(RetTypeString, "char"))
|
||||||
|
Sq_pushinteger(v, (int)result);
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static SQInteger Sq_GetExportByName(HSQUIRRELVM v)
|
||||||
|
{
|
||||||
|
//获取函数符号名
|
||||||
|
const SQChar* FuncNamebuf;
|
||||||
|
Sq_getstring(v, 2, &FuncNamebuf);
|
||||||
|
char* OutPutText2 = DNFTOOL::SquirrelU2W(FuncNamebuf);
|
||||||
|
std::string FuncName(OutPutText2);
|
||||||
|
delete[]OutPutText2;
|
||||||
|
|
||||||
|
HMODULE hModule = GetModuleHandle(NULL);
|
||||||
|
if (!hModule)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
FARPROC funcPtr = GetProcAddress(hModule, FuncName.c_str());
|
||||||
|
if (!funcPtr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
Sq_pushinteger(v, (int)funcPtr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
void RegisterMyNutApi(wchar_t* funcName, SQFUNCTION funcAddr)
|
void RegisterMyNutApi(wchar_t* funcName, SQFUNCTION funcAddr)
|
||||||
{
|
{
|
||||||
|
|
@ -2899,12 +2960,234 @@ void RegisterMyNutApi(wchar_t* funcName, SQFUNCTION funcAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static SQInteger L_Str_Ptr(HSQUIRRELVM v)
|
||||||
|
{
|
||||||
|
const SQChar* str;
|
||||||
|
Sq_getstring(v, 2, &str);
|
||||||
|
Sq_pushuserpointer(v, (void*)str);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
static SQInteger New_Point(HSQUIRRELVM v)
|
||||||
|
{
|
||||||
|
SQInteger Len;
|
||||||
|
Sq_getinteger(v, 2, &Len);
|
||||||
|
void* P = malloc(Len);
|
||||||
|
Sq_pushuserpointer(v, P);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
static SQInteger _file_releasehook(SQUserPointer p, SQInteger a)
|
||||||
|
{
|
||||||
|
free((void*)p);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// 注册析构函数
|
||||||
|
static SQInteger Register_Destruction(HSQUIRRELVM v)
|
||||||
|
{
|
||||||
|
// 析构函数测试
|
||||||
|
SQUserPointer P;
|
||||||
|
sq_getuserpointer(v, 2, &P);
|
||||||
|
|
||||||
|
sq_setinstanceup(v, 3, P);
|
||||||
|
sq_setreleasehook(v, 3, _file_releasehook);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// 写字节数组
|
||||||
|
static SQInteger Memory_WriteByteArr(HSQUIRRELVM v)
|
||||||
|
{
|
||||||
|
SQUserPointer P;
|
||||||
|
Sq_getuserpointer(v, 2, &P);
|
||||||
|
char* Address = (char*)P;
|
||||||
|
|
||||||
|
size_t Idx = 0;
|
||||||
|
sq_pushnull(v); // null iterator
|
||||||
|
while (SQ_SUCCEEDED(sq_next(v, 3)))
|
||||||
|
{
|
||||||
|
SQInteger Buf;
|
||||||
|
Sq_getinteger(v, -1, &Buf);
|
||||||
|
*(BYTE*)(Address + Idx) = (BYTE)Buf;
|
||||||
|
// 这里-1是值,-2是键
|
||||||
|
Sq_pop(v, 2); // 在下一次迭代之前弹出键和值
|
||||||
|
Idx++;
|
||||||
|
}
|
||||||
|
Sq_pop(v, 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读内存字符串
|
||||||
|
static SQInteger Memory_ReadString(HSQUIRRELVM v)
|
||||||
|
{
|
||||||
|
// 内存地址
|
||||||
|
SQUserPointer Address;
|
||||||
|
// 获取地址
|
||||||
|
Sq_getuserpointer(v, 2, &Address);
|
||||||
|
if (Sq_gettop(v) == 3)
|
||||||
|
{
|
||||||
|
SQInteger Length;
|
||||||
|
Sq_getinteger(v, 3, &Length);
|
||||||
|
|
||||||
|
char* str = DNFTOOL::UnicodeToUtf8((wchar_t*)Address);
|
||||||
|
wchar_t* name = DNFTOOL::charTowchar_t(str);
|
||||||
|
free(str);
|
||||||
|
Sq_pushstring(v, name, Length);
|
||||||
|
delete[]name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char* str = DNFTOOL::UnicodeToUtf8((wchar_t*)Address);
|
||||||
|
wchar_t* name = DNFTOOL::charTowchar_t(str);
|
||||||
|
free(str);
|
||||||
|
Sq_pushstring(v, name, -1);
|
||||||
|
delete[]name;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// 读内存字符串
|
||||||
|
static SQInteger Memory_ReadStringByUtf8(HSQUIRRELVM v)
|
||||||
|
{
|
||||||
|
// 内存地址
|
||||||
|
SQUserPointer Address;
|
||||||
|
// 获取地址
|
||||||
|
Sq_getuserpointer(v, 2, &Address);
|
||||||
|
if (Sq_gettop(v) == 3)
|
||||||
|
{
|
||||||
|
SQInteger Length;
|
||||||
|
Sq_getinteger(v, 3, &Length);
|
||||||
|
|
||||||
|
wchar_t* name = DNFTOOL::charTowchar_t((char*)Address);
|
||||||
|
Sq_pushstring(v, name, Length);
|
||||||
|
delete[]name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wchar_t* name = DNFTOOL::charTowchar_t((char*)Address);
|
||||||
|
Sq_pushstring(v, name, -1);
|
||||||
|
delete[]name;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// 读内存字符串
|
||||||
|
static SQInteger Memory_ReadStringByBig5(HSQUIRRELVM v)
|
||||||
|
{
|
||||||
|
// 内存地址
|
||||||
|
SQUserPointer Address;
|
||||||
|
// 获取地址
|
||||||
|
Sq_getuserpointer(v, 2, &Address);
|
||||||
|
if (Sq_gettop(v) == 3)
|
||||||
|
{
|
||||||
|
SQInteger Length;
|
||||||
|
Sq_getinteger(v, 3, &Length);
|
||||||
|
|
||||||
|
wchar_t* newadd = DNFTOOL::charTowchar_t((char*)Address);
|
||||||
|
char* str = DNFTOOL::Big5ToUtf8(newadd);
|
||||||
|
wchar_t* name = DNFTOOL::charTowchar_t(str);
|
||||||
|
free(str);
|
||||||
|
Sq_pushstring(v, name, Length);
|
||||||
|
delete[]name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wchar_t* newadd = DNFTOOL::charTowchar_t((char*)Address);
|
||||||
|
char* str = DNFTOOL::Big5ToUtf8(newadd);
|
||||||
|
wchar_t* name = DNFTOOL::charTowchar_t(str);
|
||||||
|
free(str);
|
||||||
|
Sq_pushstring(v, name, -1);
|
||||||
|
delete[]name;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// 转换字符串
|
||||||
|
static SQInteger ConvertWideChar(HSQUIRRELVM v)
|
||||||
|
{
|
||||||
|
const SQChar* Str;
|
||||||
|
Sq_getstring(v, 2, &Str);
|
||||||
|
|
||||||
|
const SQChar* olgcodepage;
|
||||||
|
Sq_getstring(v, 3, &olgcodepage);
|
||||||
|
char* OutPutText1 = DNFTOOL::SquirrelU2W(olgcodepage);
|
||||||
|
std::string fromEncoding = OutPutText1;
|
||||||
|
delete[]OutPutText1;
|
||||||
|
|
||||||
|
|
||||||
|
if (CONTAINS_STRING(fromEncoding, "big5")) {
|
||||||
|
|
||||||
|
char* csa = DNFTOOL::wchar_tTochar((wchar_t*) Str);
|
||||||
|
wchar_t* name = DNFTOOL::BIG5ToUnicode(csa);
|
||||||
|
char* str = DNFTOOL::UnicodeToUtf8(name);
|
||||||
|
wchar_t* realname = DNFTOOL::charTowchar_t(str);
|
||||||
|
free(str);
|
||||||
|
|
||||||
|
Sq_pushstring(v, realname, -1);
|
||||||
|
delete[]csa;
|
||||||
|
delete[]name;
|
||||||
|
delete[]realname;
|
||||||
|
}
|
||||||
|
else if (CONTAINS_STRING(fromEncoding, "unicode")) {
|
||||||
|
char* str = DNFTOOL::UnicodeToUtf8((wchar_t*)Str);
|
||||||
|
wchar_t* name = DNFTOOL::charTowchar_t(str);
|
||||||
|
free(str);
|
||||||
|
Sq_pushstring(v, name, -1);
|
||||||
|
delete[]name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 指针转Blob
|
||||||
|
static SQInteger L_Point2Blob(HSQUIRRELVM v)
|
||||||
|
{
|
||||||
|
SQInteger P;
|
||||||
|
sq_getinteger(v, 2, &P);
|
||||||
|
SQInteger Count;
|
||||||
|
sq_getinteger(v, 3, &Count);
|
||||||
|
|
||||||
|
char* Address = (char*)P;
|
||||||
|
SQUserPointer Blobobj = sqstd_createblob(v, Count);
|
||||||
|
memcpy(Blobobj, Address, Count);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SQInteger OutPutTable(HSQUIRRELVM v)
|
||||||
|
{
|
||||||
|
const SQChar* Str;
|
||||||
|
sq_getstring(v, 2, &Str);
|
||||||
|
|
||||||
|
char* OutPutText = DNFTOOL::wchar_tTochar((wchar_t*)Str);
|
||||||
|
std::string str = OutPutText;
|
||||||
|
delete[]OutPutText;
|
||||||
|
|
||||||
|
nlohmann::json ex1 = nlohmann::json::parse(str);
|
||||||
|
|
||||||
|
std::cout << std::setw(4) << ex1 << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void R_Register_Nut() {
|
void R_Register_Nut() {
|
||||||
|
|
||||||
RegisterMyNutApi(L"L_sq_Test", sq_Test);//zlib解压
|
RegisterMyNutApi(L"L_sq_Test", sq_Test);//zlib解压
|
||||||
|
|
||||||
RegisterMyNutApi(L"L_sq_GetLocalConfig", sq_GetLocalConfig);//获取本地配置
|
|
||||||
RegisterMyNutApi(L"L_sq_SetLocalConfig", sq_SetLocalConfig);//设置本地配置
|
RegisterMyNutApi(L"Sq_OutPutTable", OutPutTable);
|
||||||
|
RegisterMyNutApi(L"Sq_HookFunc", L_HookFunc);
|
||||||
|
RegisterMyNutApi(L"Sq_DeHookFunc", L_DeHookFunc);
|
||||||
|
RegisterMyNutApi(L"Str_Ptr", L_Str_Ptr);
|
||||||
|
RegisterMyNutApi(L"Sq_New_Point", New_Point);
|
||||||
|
RegisterMyNutApi(L"Register_Destruction", Register_Destruction);
|
||||||
|
RegisterMyNutApi(L"Sq_Memory_WriteByteArr", Memory_WriteByteArr);
|
||||||
|
RegisterMyNutApi(L"Sq_Memory_ReadString", Memory_ReadString);
|
||||||
|
RegisterMyNutApi(L"Sq_Memory_ReadStringByUtf8", Memory_ReadStringByUtf8);
|
||||||
|
RegisterMyNutApi(L"Sq_Memory_ReadStringByBig5", Memory_ReadStringByBig5);
|
||||||
|
RegisterMyNutApi(L"Sq_ConvertWideChar", ConvertWideChar);
|
||||||
|
RegisterMyNutApi(L"Sq_Point2Blob", L_Point2Blob);
|
||||||
|
RegisterMyNutApi(L"L_Sq_CallFunc", Sq_ActiveCallFunc);//动态Call
|
||||||
|
RegisterMyNutApi(L"L_Sq_GetExportByName", Sq_GetExportByName);//动态Call
|
||||||
|
|
||||||
|
RegisterMyNutApi(L"L_sq_GetItem", sq_GetItem);//获取Item
|
||||||
|
|
||||||
|
RegisterMyNutApi(L"L_sq_StringBinById", sq_StringBinById);//获取字符串在StringBin中
|
||||||
RegisterMyNutApi(L"L_sq_LongLongOperation", sq_LongLongOperation);//longlong类型运算
|
RegisterMyNutApi(L"L_sq_LongLongOperation", sq_LongLongOperation);//longlong类型运算
|
||||||
RegisterMyNutApi(L"L_sq_Dezlib", sq_Dezlib);//zlib解压
|
RegisterMyNutApi(L"L_sq_Dezlib", sq_Dezlib);//zlib解压
|
||||||
RegisterMyNutApi(L"L_sq_DrawImg", sq_DrawImg);//绘制Img
|
RegisterMyNutApi(L"L_sq_DrawImg", sq_DrawImg);//绘制Img
|
||||||
|
|
@ -2987,9 +3270,14 @@ void R_Register_Nut() {
|
||||||
RegisterMyNutApi(L"L_sq_RAB", LReadAddressB);//读内存
|
RegisterMyNutApi(L"L_sq_RAB", LReadAddressB);//读内存
|
||||||
RegisterMyNutApi(L"L_sq_WAB", LWriteAddressB);//写内存
|
RegisterMyNutApi(L"L_sq_WAB", LWriteAddressB);//写内存
|
||||||
|
|
||||||
RegisterMyNutApi(L"Sout", Sout);//输出
|
RegisterMyNutApi(L"L_sq_I2P", sq_I2P);//int转指针
|
||||||
|
RegisterMyNutApi(L"L_sq_P2I", sq_P2I);//指针转int
|
||||||
|
|
||||||
|
RegisterMyNutApi(L"printf", Sout);//输出
|
||||||
|
//RegisterMyNutApi(L"L_ReplaceInString", ReplaceInString);//输出
|
||||||
RegisterMyNutApi(L"Clock", Clock);//输出
|
RegisterMyNutApi(L"Clock", Clock);//输出
|
||||||
RegisterMyNutApi(L"L_Getmicroseconds", Getmicroseconds);//获取微秒级
|
RegisterMyNutApi(L"L_Getmicroseconds", Getmicroseconds);//获取微秒级
|
||||||
|
RegisterMyNutApi(L"Sq_Time", SQTime);
|
||||||
|
|
||||||
RegisterMyNutApi(L"L_NewWindows", NewWindows);//创建窗口
|
RegisterMyNutApi(L"L_NewWindows", NewWindows);//创建窗口
|
||||||
RegisterMyNutApi(L"L_Cmd", sq_Cmd);//执行Cmd命令
|
RegisterMyNutApi(L"L_Cmd", sq_Cmd);//执行Cmd命令
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,531 @@
|
||||||
|
/* -----------------------------------------------------------------*-C-*-
|
||||||
|
libffi 3.4.4
|
||||||
|
- Copyright (c) 2011, 2014, 2019, 2021, 2022 Anthony Green
|
||||||
|
- Copyright (c) 1996-2003, 2007, 2008 Red Hat, Inc.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person
|
||||||
|
obtaining a copy of this software and associated documentation
|
||||||
|
files (the ``Software''), to deal in the Software without
|
||||||
|
restriction, including without limitation the rights to use, copy,
|
||||||
|
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------
|
||||||
|
Most of the API is documented in doc/libffi.texi.
|
||||||
|
|
||||||
|
The raw API is designed to bypass some of the argument packing and
|
||||||
|
unpacking on architectures for which it can be avoided. Routines
|
||||||
|
are provided to emulate the raw API if the underlying platform
|
||||||
|
doesn't allow faster implementation.
|
||||||
|
|
||||||
|
More details on the raw API can be found in:
|
||||||
|
|
||||||
|
http://gcc.gnu.org/ml/java/1999-q3/msg00138.html
|
||||||
|
|
||||||
|
and
|
||||||
|
|
||||||
|
http://gcc.gnu.org/ml/java/1999-q3/msg00174.html
|
||||||
|
-------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#ifndef LIBFFI_H
|
||||||
|
#define LIBFFI_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Specify which architecture libffi is configured for. */
|
||||||
|
#ifndef X86_WIN32
|
||||||
|
#define X86_WIN32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ---- System configuration information --------------------------------- */
|
||||||
|
|
||||||
|
/* If these change, update src/mips/ffitarget.h. */
|
||||||
|
#define FFI_TYPE_VOID 0
|
||||||
|
#define FFI_TYPE_INT 1
|
||||||
|
#define FFI_TYPE_FLOAT 2
|
||||||
|
#define FFI_TYPE_DOUBLE 3
|
||||||
|
#if 0
|
||||||
|
#define FFI_TYPE_LONGDOUBLE 4
|
||||||
|
#else
|
||||||
|
#define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE
|
||||||
|
#endif
|
||||||
|
#define FFI_TYPE_UINT8 5
|
||||||
|
#define FFI_TYPE_SINT8 6
|
||||||
|
#define FFI_TYPE_UINT16 7
|
||||||
|
#define FFI_TYPE_SINT16 8
|
||||||
|
#define FFI_TYPE_UINT32 9
|
||||||
|
#define FFI_TYPE_SINT32 10
|
||||||
|
#define FFI_TYPE_UINT64 11
|
||||||
|
#define FFI_TYPE_SINT64 12
|
||||||
|
#define FFI_TYPE_STRUCT 13
|
||||||
|
#define FFI_TYPE_POINTER 14
|
||||||
|
#define FFI_TYPE_COMPLEX 15
|
||||||
|
|
||||||
|
/* This should always refer to the last type code (for sanity checks). */
|
||||||
|
#define FFI_TYPE_LAST FFI_TYPE_COMPLEX
|
||||||
|
|
||||||
|
#include <ffitarget.h>
|
||||||
|
|
||||||
|
#ifndef LIBFFI_ASM
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||||||
|
#define __attribute__(X)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
/* LONG_LONG_MAX is not always defined (not if STRICT_ANSI, for example).
|
||||||
|
But we can find it either under the correct ANSI name, or under GNU
|
||||||
|
C's internal name. */
|
||||||
|
|
||||||
|
#define FFI_64_BIT_MAX 9223372036854775807
|
||||||
|
|
||||||
|
#ifdef LONG_LONG_MAX
|
||||||
|
# define FFI_LONG_LONG_MAX LONG_LONG_MAX
|
||||||
|
#else
|
||||||
|
# ifdef LLONG_MAX
|
||||||
|
# define FFI_LONG_LONG_MAX LLONG_MAX
|
||||||
|
# ifdef _AIX52 /* or newer has C99 LLONG_MAX */
|
||||||
|
# undef FFI_64_BIT_MAX
|
||||||
|
# define FFI_64_BIT_MAX 9223372036854775807LL
|
||||||
|
# endif /* _AIX52 or newer */
|
||||||
|
# else
|
||||||
|
# ifdef __GNUC__
|
||||||
|
# define FFI_LONG_LONG_MAX __LONG_LONG_MAX__
|
||||||
|
# endif
|
||||||
|
# ifdef _AIX /* AIX 5.1 and earlier have LONGLONG_MAX */
|
||||||
|
# ifndef __PPC64__
|
||||||
|
# if defined (__IBMC__) || defined (__IBMCPP__)
|
||||||
|
# define FFI_LONG_LONG_MAX LONGLONG_MAX
|
||||||
|
# endif
|
||||||
|
# endif /* __PPC64__ */
|
||||||
|
# undef FFI_64_BIT_MAX
|
||||||
|
# define FFI_64_BIT_MAX 9223372036854775807LL
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The closure code assumes that this works on pointers, i.e. a size_t
|
||||||
|
can hold a pointer. */
|
||||||
|
|
||||||
|
typedef struct _ffi_type
|
||||||
|
{
|
||||||
|
size_t size;
|
||||||
|
unsigned short alignment;
|
||||||
|
unsigned short type;
|
||||||
|
struct _ffi_type **elements;
|
||||||
|
} ffi_type;
|
||||||
|
|
||||||
|
/* Need minimal decorations for DLLs to work on Windows. GCC has
|
||||||
|
autoimport and autoexport. Always mark externally visible symbols
|
||||||
|
as dllimport for MSVC clients, even if it means an extra indirection
|
||||||
|
when using the static version of the library.
|
||||||
|
Besides, as a workaround, they can define FFI_BUILDING if they
|
||||||
|
*know* they are going to link with the static library. */
|
||||||
|
#if defined _MSC_VER
|
||||||
|
# if defined FFI_BUILDING_DLL /* Building libffi.DLL with msvcc.sh */
|
||||||
|
# define FFI_API __declspec(dllexport)
|
||||||
|
# elif !defined FFI_BUILDING /* Importing libffi.DLL */
|
||||||
|
# define FFI_API __declspec(dllimport)
|
||||||
|
# else /* Building/linking static library */
|
||||||
|
# define FFI_API
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define FFI_API
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The externally visible type declarations also need the MSVC DLL
|
||||||
|
decorations, or they will not be exported from the object file. */
|
||||||
|
#if defined LIBFFI_HIDE_BASIC_TYPES
|
||||||
|
# define FFI_EXTERN FFI_API
|
||||||
|
#else
|
||||||
|
# define FFI_EXTERN extern FFI_API
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LIBFFI_HIDE_BASIC_TYPES
|
||||||
|
#if SCHAR_MAX == 127
|
||||||
|
# define ffi_type_uchar ffi_type_uint8
|
||||||
|
# define ffi_type_schar ffi_type_sint8
|
||||||
|
#else
|
||||||
|
#error "char size not supported"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SHRT_MAX == 32767
|
||||||
|
# define ffi_type_ushort ffi_type_uint16
|
||||||
|
# define ffi_type_sshort ffi_type_sint16
|
||||||
|
#elif SHRT_MAX == 2147483647
|
||||||
|
# define ffi_type_ushort ffi_type_uint32
|
||||||
|
# define ffi_type_sshort ffi_type_sint32
|
||||||
|
#else
|
||||||
|
#error "short size not supported"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if INT_MAX == 32767
|
||||||
|
# define ffi_type_uint ffi_type_uint16
|
||||||
|
# define ffi_type_sint ffi_type_sint16
|
||||||
|
#elif INT_MAX == 2147483647
|
||||||
|
# define ffi_type_uint ffi_type_uint32
|
||||||
|
# define ffi_type_sint ffi_type_sint32
|
||||||
|
#elif INT_MAX == 9223372036854775807
|
||||||
|
# define ffi_type_uint ffi_type_uint64
|
||||||
|
# define ffi_type_sint ffi_type_sint64
|
||||||
|
#else
|
||||||
|
#error "int size not supported"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LONG_MAX == 2147483647
|
||||||
|
# if FFI_LONG_LONG_MAX != FFI_64_BIT_MAX
|
||||||
|
#error "no 64-bit data type supported"
|
||||||
|
# endif
|
||||||
|
#elif LONG_MAX != FFI_64_BIT_MAX
|
||||||
|
#error "long size not supported"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LONG_MAX == 2147483647
|
||||||
|
# define ffi_type_ulong ffi_type_uint32
|
||||||
|
# define ffi_type_slong ffi_type_sint32
|
||||||
|
#elif LONG_MAX == FFI_64_BIT_MAX
|
||||||
|
# define ffi_type_ulong ffi_type_uint64
|
||||||
|
# define ffi_type_slong ffi_type_sint64
|
||||||
|
#else
|
||||||
|
#error "long size not supported"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* These are defined in types.c. */
|
||||||
|
FFI_EXTERN ffi_type ffi_type_void;
|
||||||
|
FFI_EXTERN ffi_type ffi_type_uint8;
|
||||||
|
FFI_EXTERN ffi_type ffi_type_sint8;
|
||||||
|
FFI_EXTERN ffi_type ffi_type_uint16;
|
||||||
|
FFI_EXTERN ffi_type ffi_type_sint16;
|
||||||
|
FFI_EXTERN ffi_type ffi_type_uint32;
|
||||||
|
FFI_EXTERN ffi_type ffi_type_sint32;
|
||||||
|
FFI_EXTERN ffi_type ffi_type_uint64;
|
||||||
|
FFI_EXTERN ffi_type ffi_type_sint64;
|
||||||
|
FFI_EXTERN ffi_type ffi_type_float;
|
||||||
|
FFI_EXTERN ffi_type ffi_type_double;
|
||||||
|
FFI_EXTERN ffi_type ffi_type_pointer;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
FFI_EXTERN ffi_type ffi_type_longdouble;
|
||||||
|
#else
|
||||||
|
#define ffi_type_longdouble ffi_type_double
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef FFI_TARGET_HAS_COMPLEX_TYPE
|
||||||
|
FFI_EXTERN ffi_type ffi_type_complex_float;
|
||||||
|
FFI_EXTERN ffi_type ffi_type_complex_double;
|
||||||
|
#if 0
|
||||||
|
FFI_EXTERN ffi_type ffi_type_complex_longdouble;
|
||||||
|
#else
|
||||||
|
#define ffi_type_complex_longdouble ffi_type_complex_double
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif /* LIBFFI_HIDE_BASIC_TYPES */
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FFI_OK = 0,
|
||||||
|
FFI_BAD_TYPEDEF,
|
||||||
|
FFI_BAD_ABI,
|
||||||
|
FFI_BAD_ARGTYPE
|
||||||
|
} ffi_status;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ffi_abi abi;
|
||||||
|
unsigned nargs;
|
||||||
|
ffi_type **arg_types;
|
||||||
|
ffi_type *rtype;
|
||||||
|
unsigned bytes;
|
||||||
|
unsigned flags;
|
||||||
|
#ifdef FFI_EXTRA_CIF_FIELDS
|
||||||
|
FFI_EXTRA_CIF_FIELDS;
|
||||||
|
#endif
|
||||||
|
} ffi_cif;
|
||||||
|
|
||||||
|
/* ---- Definitions for the raw API -------------------------------------- */
|
||||||
|
|
||||||
|
#ifndef FFI_SIZEOF_ARG
|
||||||
|
# if LONG_MAX == 2147483647
|
||||||
|
# define FFI_SIZEOF_ARG 4
|
||||||
|
# elif LONG_MAX == FFI_64_BIT_MAX
|
||||||
|
# define FFI_SIZEOF_ARG 8
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FFI_SIZEOF_JAVA_RAW
|
||||||
|
# define FFI_SIZEOF_JAVA_RAW FFI_SIZEOF_ARG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
ffi_sarg sint;
|
||||||
|
ffi_arg uint;
|
||||||
|
float flt;
|
||||||
|
char data[FFI_SIZEOF_ARG];
|
||||||
|
void* ptr;
|
||||||
|
} ffi_raw;
|
||||||
|
|
||||||
|
#if FFI_SIZEOF_JAVA_RAW == 4 && FFI_SIZEOF_ARG == 8
|
||||||
|
/* This is a special case for mips64/n32 ABI (and perhaps others) where
|
||||||
|
sizeof(void *) is 4 and FFI_SIZEOF_ARG is 8. */
|
||||||
|
typedef union {
|
||||||
|
signed int sint;
|
||||||
|
unsigned int uint;
|
||||||
|
float flt;
|
||||||
|
char data[FFI_SIZEOF_JAVA_RAW];
|
||||||
|
void* ptr;
|
||||||
|
} ffi_java_raw;
|
||||||
|
#else
|
||||||
|
typedef ffi_raw ffi_java_raw;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
FFI_API
|
||||||
|
void ffi_raw_call (ffi_cif *cif,
|
||||||
|
void (*fn)(void),
|
||||||
|
void *rvalue,
|
||||||
|
ffi_raw *avalue);
|
||||||
|
|
||||||
|
FFI_API void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw);
|
||||||
|
FFI_API void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args);
|
||||||
|
FFI_API size_t ffi_raw_size (ffi_cif *cif);
|
||||||
|
|
||||||
|
/* This is analogous to the raw API, except it uses Java parameter
|
||||||
|
packing, even on 64-bit machines. I.e. on 64-bit machines longs
|
||||||
|
and doubles are followed by an empty 64-bit word. */
|
||||||
|
|
||||||
|
#if !FFI_NATIVE_RAW_API
|
||||||
|
FFI_API
|
||||||
|
void ffi_java_raw_call (ffi_cif *cif,
|
||||||
|
void (*fn)(void),
|
||||||
|
void *rvalue,
|
||||||
|
ffi_java_raw *avalue) __attribute__((deprecated));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FFI_API
|
||||||
|
void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw) __attribute__((deprecated));
|
||||||
|
FFI_API
|
||||||
|
void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args) __attribute__((deprecated));
|
||||||
|
FFI_API
|
||||||
|
size_t ffi_java_raw_size (ffi_cif *cif) __attribute__((deprecated));
|
||||||
|
|
||||||
|
/* ---- Definitions for closures ----------------------------------------- */
|
||||||
|
|
||||||
|
#if FFI_CLOSURES
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
__declspec(align(8))
|
||||||
|
#endif
|
||||||
|
typedef struct {
|
||||||
|
#if 0
|
||||||
|
void *trampoline_table;
|
||||||
|
void *trampoline_table_entry;
|
||||||
|
#else
|
||||||
|
union {
|
||||||
|
char tramp[FFI_TRAMPOLINE_SIZE];
|
||||||
|
void *ftramp;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
ffi_cif *cif;
|
||||||
|
void (*fun)(ffi_cif*,void*,void**,void*);
|
||||||
|
void *user_data;
|
||||||
|
#if defined(_MSC_VER) && defined(_M_IX86)
|
||||||
|
void *padding;
|
||||||
|
#endif
|
||||||
|
} ffi_closure
|
||||||
|
#ifdef __GNUC__
|
||||||
|
__attribute__((aligned (8)))
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
|
||||||
|
#ifndef __GNUC__
|
||||||
|
# ifdef __sgi
|
||||||
|
# pragma pack 0
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FFI_API void *ffi_closure_alloc (size_t size, void **code);
|
||||||
|
FFI_API void ffi_closure_free (void *);
|
||||||
|
|
||||||
|
#if defined(PA_LINUX) || defined(PA_HPUX)
|
||||||
|
#define FFI_CLOSURE_PTR(X) ((void *)((unsigned int)(X) | 2))
|
||||||
|
#define FFI_RESTORE_PTR(X) ((void *)((unsigned int)(X) & ~3))
|
||||||
|
#else
|
||||||
|
#define FFI_CLOSURE_PTR(X) (X)
|
||||||
|
#define FFI_RESTORE_PTR(X) (X)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FFI_API ffi_status
|
||||||
|
ffi_prep_closure (ffi_closure*,
|
||||||
|
ffi_cif *,
|
||||||
|
void (*fun)(ffi_cif*,void*,void**,void*),
|
||||||
|
void *user_data)
|
||||||
|
#if defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 405)
|
||||||
|
__attribute__((deprecated ("use ffi_prep_closure_loc instead")))
|
||||||
|
#elif defined(__GNUC__) && __GNUC__ >= 3
|
||||||
|
__attribute__((deprecated))
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
|
||||||
|
FFI_API ffi_status
|
||||||
|
ffi_prep_closure_loc (ffi_closure*,
|
||||||
|
ffi_cif *,
|
||||||
|
void (*fun)(ffi_cif*,void*,void**,void*),
|
||||||
|
void *user_data,
|
||||||
|
void *codeloc);
|
||||||
|
|
||||||
|
#ifdef __sgi
|
||||||
|
# pragma pack 8
|
||||||
|
#endif
|
||||||
|
typedef struct {
|
||||||
|
#if 0
|
||||||
|
void *trampoline_table;
|
||||||
|
void *trampoline_table_entry;
|
||||||
|
#else
|
||||||
|
char tramp[FFI_TRAMPOLINE_SIZE];
|
||||||
|
#endif
|
||||||
|
ffi_cif *cif;
|
||||||
|
|
||||||
|
#if !FFI_NATIVE_RAW_API
|
||||||
|
|
||||||
|
/* If this is enabled, then a raw closure has the same layout
|
||||||
|
as a regular closure. We use this to install an intermediate
|
||||||
|
handler to do the translation, void** -> ffi_raw*. */
|
||||||
|
|
||||||
|
void (*translate_args)(ffi_cif*,void*,void**,void*);
|
||||||
|
void *this_closure;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void (*fun)(ffi_cif*,void*,ffi_raw*,void*);
|
||||||
|
void *user_data;
|
||||||
|
|
||||||
|
} ffi_raw_closure;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
#if 0
|
||||||
|
void *trampoline_table;
|
||||||
|
void *trampoline_table_entry;
|
||||||
|
#else
|
||||||
|
char tramp[FFI_TRAMPOLINE_SIZE];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ffi_cif *cif;
|
||||||
|
|
||||||
|
#if !FFI_NATIVE_RAW_API
|
||||||
|
|
||||||
|
/* If this is enabled, then a raw closure has the same layout
|
||||||
|
as a regular closure. We use this to install an intermediate
|
||||||
|
handler to do the translation, void** -> ffi_raw*. */
|
||||||
|
|
||||||
|
void (*translate_args)(ffi_cif*,void*,void**,void*);
|
||||||
|
void *this_closure;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*);
|
||||||
|
void *user_data;
|
||||||
|
|
||||||
|
} ffi_java_raw_closure;
|
||||||
|
|
||||||
|
FFI_API ffi_status
|
||||||
|
ffi_prep_raw_closure (ffi_raw_closure*,
|
||||||
|
ffi_cif *cif,
|
||||||
|
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
|
FFI_API ffi_status
|
||||||
|
ffi_prep_raw_closure_loc (ffi_raw_closure*,
|
||||||
|
ffi_cif *cif,
|
||||||
|
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
|
||||||
|
void *user_data,
|
||||||
|
void *codeloc);
|
||||||
|
|
||||||
|
#if !FFI_NATIVE_RAW_API
|
||||||
|
FFI_API ffi_status
|
||||||
|
ffi_prep_java_raw_closure (ffi_java_raw_closure*,
|
||||||
|
ffi_cif *cif,
|
||||||
|
void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*),
|
||||||
|
void *user_data) __attribute__((deprecated));
|
||||||
|
|
||||||
|
FFI_API ffi_status
|
||||||
|
ffi_prep_java_raw_closure_loc (ffi_java_raw_closure*,
|
||||||
|
ffi_cif *cif,
|
||||||
|
void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*),
|
||||||
|
void *user_data,
|
||||||
|
void *codeloc) __attribute__((deprecated));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* FFI_CLOSURES */
|
||||||
|
|
||||||
|
#if FFI_GO_CLOSURES
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void *tramp;
|
||||||
|
ffi_cif *cif;
|
||||||
|
void (*fun)(ffi_cif*,void*,void**,void*);
|
||||||
|
} ffi_go_closure;
|
||||||
|
|
||||||
|
FFI_API ffi_status ffi_prep_go_closure (ffi_go_closure*, ffi_cif *,
|
||||||
|
void (*fun)(ffi_cif*,void*,void**,void*));
|
||||||
|
|
||||||
|
FFI_API void ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
|
||||||
|
void **avalue, void *closure);
|
||||||
|
|
||||||
|
#endif /* FFI_GO_CLOSURES */
|
||||||
|
|
||||||
|
/* ---- Public interface definition -------------------------------------- */
|
||||||
|
|
||||||
|
FFI_API
|
||||||
|
ffi_status ffi_prep_cif(ffi_cif *cif,
|
||||||
|
ffi_abi abi,
|
||||||
|
unsigned int nargs,
|
||||||
|
ffi_type *rtype,
|
||||||
|
ffi_type **atypes);
|
||||||
|
|
||||||
|
FFI_API
|
||||||
|
ffi_status ffi_prep_cif_var(ffi_cif *cif,
|
||||||
|
ffi_abi abi,
|
||||||
|
unsigned int nfixedargs,
|
||||||
|
unsigned int ntotalargs,
|
||||||
|
ffi_type *rtype,
|
||||||
|
ffi_type **atypes);
|
||||||
|
|
||||||
|
FFI_API
|
||||||
|
void ffi_call(ffi_cif *cif,
|
||||||
|
void (*fn)(void),
|
||||||
|
void *rvalue,
|
||||||
|
void **avalue);
|
||||||
|
|
||||||
|
FFI_API
|
||||||
|
ffi_status ffi_get_struct_offsets (ffi_abi abi, ffi_type *struct_type,
|
||||||
|
size_t *offsets);
|
||||||
|
|
||||||
|
/* Useful for eliminating compiler warnings. */
|
||||||
|
#define FFI_FN(f) ((void (*)(void))f)
|
||||||
|
|
||||||
|
/* ---- Definitions shared with assembly code ---------------------------- */
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,164 @@
|
||||||
|
/* -----------------------------------------------------------------*-C-*-
|
||||||
|
ffitarget.h - Copyright (c) 2012, 2014, 2018 Anthony Green
|
||||||
|
Copyright (c) 1996-2003, 2010 Red Hat, Inc.
|
||||||
|
Copyright (C) 2008 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
Target configuration macros for x86 and x86-64.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
``Software''), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included
|
||||||
|
in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#ifndef LIBFFI_TARGET_H
|
||||||
|
#define LIBFFI_TARGET_H
|
||||||
|
|
||||||
|
#ifndef LIBFFI_H
|
||||||
|
#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ---- System specific configurations ----------------------------------- */
|
||||||
|
|
||||||
|
/* For code common to all platforms on x86 and x86_64. */
|
||||||
|
#define X86_ANY
|
||||||
|
|
||||||
|
#if defined (X86_64) && defined (__i386__)
|
||||||
|
#undef X86_64
|
||||||
|
#warning ******************************************************
|
||||||
|
#warning ********** X86 IS DEFINED ****************************
|
||||||
|
#warning ******************************************************
|
||||||
|
#define X86
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef X86_WIN64
|
||||||
|
#define FFI_SIZEOF_ARG 8
|
||||||
|
#define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#define FFI_TARGET_HAS_COMPLEX_TYPE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ---- Generic type definitions ----------------------------------------- */
|
||||||
|
|
||||||
|
#ifndef LIBFFI_ASM
|
||||||
|
#ifdef X86_WIN64
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
typedef unsigned __int64 ffi_arg;
|
||||||
|
typedef __int64 ffi_sarg;
|
||||||
|
#else
|
||||||
|
typedef unsigned long long ffi_arg;
|
||||||
|
typedef long long ffi_sarg;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#if defined __x86_64__ && defined __ILP32__
|
||||||
|
#define FFI_SIZEOF_ARG 8
|
||||||
|
#define FFI_SIZEOF_JAVA_RAW 4
|
||||||
|
typedef unsigned long long ffi_arg;
|
||||||
|
typedef long long ffi_sarg;
|
||||||
|
#else
|
||||||
|
typedef unsigned long ffi_arg;
|
||||||
|
typedef signed long ffi_sarg;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum ffi_abi {
|
||||||
|
#if defined(X86_WIN64)
|
||||||
|
FFI_FIRST_ABI = 0,
|
||||||
|
FFI_WIN64, /* sizeof(long double) == 8 - microsoft compilers */
|
||||||
|
FFI_GNUW64, /* sizeof(long double) == 16 - GNU compilers */
|
||||||
|
FFI_LAST_ABI,
|
||||||
|
#ifdef __GNUC__
|
||||||
|
FFI_DEFAULT_ABI = FFI_GNUW64
|
||||||
|
#else
|
||||||
|
FFI_DEFAULT_ABI = FFI_WIN64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(X86_64) || (defined (__x86_64__) && defined (X86_DARWIN))
|
||||||
|
FFI_FIRST_ABI = 1,
|
||||||
|
FFI_UNIX64,
|
||||||
|
FFI_WIN64,
|
||||||
|
FFI_EFI64 = FFI_WIN64,
|
||||||
|
FFI_GNUW64,
|
||||||
|
FFI_LAST_ABI,
|
||||||
|
FFI_DEFAULT_ABI = FFI_UNIX64
|
||||||
|
|
||||||
|
#elif defined(X86_WIN32)
|
||||||
|
FFI_FIRST_ABI = 0,
|
||||||
|
FFI_SYSV = 1,
|
||||||
|
FFI_STDCALL = 2,
|
||||||
|
FFI_THISCALL = 3,
|
||||||
|
FFI_FASTCALL = 4,
|
||||||
|
FFI_MS_CDECL = 5,
|
||||||
|
FFI_PASCAL = 6,
|
||||||
|
FFI_REGISTER = 7,
|
||||||
|
FFI_LAST_ABI,
|
||||||
|
FFI_DEFAULT_ABI = FFI_MS_CDECL
|
||||||
|
#else
|
||||||
|
FFI_FIRST_ABI = 0,
|
||||||
|
FFI_SYSV = 1,
|
||||||
|
FFI_THISCALL = 3,
|
||||||
|
FFI_FASTCALL = 4,
|
||||||
|
FFI_STDCALL = 5,
|
||||||
|
FFI_PASCAL = 6,
|
||||||
|
FFI_REGISTER = 7,
|
||||||
|
FFI_MS_CDECL = 8,
|
||||||
|
FFI_LAST_ABI,
|
||||||
|
FFI_DEFAULT_ABI = FFI_SYSV
|
||||||
|
#endif
|
||||||
|
} ffi_abi;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ---- Definitions for closures ----------------------------------------- */
|
||||||
|
|
||||||
|
#define FFI_CLOSURES 1
|
||||||
|
#define FFI_GO_CLOSURES 1
|
||||||
|
|
||||||
|
#define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1)
|
||||||
|
#define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2)
|
||||||
|
#define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3)
|
||||||
|
#define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4)
|
||||||
|
|
||||||
|
#if defined (X86_64) || defined(X86_WIN64) \
|
||||||
|
|| (defined (__x86_64__) && defined (X86_DARWIN))
|
||||||
|
/* 4 bytes of ENDBR64 + 7 bytes of LEA + 6 bytes of JMP + 7 bytes of NOP
|
||||||
|
+ 8 bytes of pointer. */
|
||||||
|
# define FFI_TRAMPOLINE_SIZE 32
|
||||||
|
# define FFI_NATIVE_RAW_API 0
|
||||||
|
#else
|
||||||
|
/* 4 bytes of ENDBR32 + 5 bytes of MOV + 5 bytes of JMP + 2 unused
|
||||||
|
bytes. */
|
||||||
|
# define FFI_TRAMPOLINE_SIZE 16
|
||||||
|
# define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(GENERATE_LIBFFI_MAP) && defined(__CET__)
|
||||||
|
# include <cet.h>
|
||||||
|
# if (__CET__ & 1) != 0
|
||||||
|
# define ENDBR_PRESENT
|
||||||
|
# endif
|
||||||
|
# define _CET_NOTRACK notrack
|
||||||
|
#else
|
||||||
|
# define _CET_ENDBR
|
||||||
|
# define _CET_NOTRACK
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,241 @@
|
||||||
|
/* Copyright (C) 1999-2022 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU LIBICONV Library.
|
||||||
|
|
||||||
|
The GNU LIBICONV Library is free software; you can redistribute it
|
||||||
|
and/or modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either version 2.1
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU LIBICONV Library is distributed in the hope that it will be
|
||||||
|
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU LIBICONV Library; see the file COPYING.LIB.
|
||||||
|
If not, see <https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
/* When installed, this file is called "iconv.h". */
|
||||||
|
|
||||||
|
#ifndef _LIBICONV_H
|
||||||
|
#define _LIBICONV_H
|
||||||
|
|
||||||
|
#define _LIBICONV_VERSION 0x0111 /* version number: (major<<8) + minor */
|
||||||
|
extern int _libiconv_version; /* Likewise */
|
||||||
|
|
||||||
|
/* We would like to #include any system header file which could define
|
||||||
|
iconv_t, 1. in order to eliminate the risk that the user gets compilation
|
||||||
|
errors because some other system header file includes /usr/include/iconv.h
|
||||||
|
which defines iconv_t or declares iconv after this file, 2. when compiling
|
||||||
|
for LIBICONV_PLUG, we need the proper iconv_t type in order to produce
|
||||||
|
binary compatible code.
|
||||||
|
But gcc's #include_next is not portable. Thus, once libiconv's iconv.h
|
||||||
|
has been installed in /usr/local/include, there is no way any more to
|
||||||
|
include the original /usr/include/iconv.h. We simply have to get away
|
||||||
|
without it.
|
||||||
|
Ad 1. The risk that a system header file does
|
||||||
|
#include "iconv.h" or #include_next "iconv.h"
|
||||||
|
is small. They all do #include <iconv.h>.
|
||||||
|
Ad 2. The iconv_t type is a pointer type in all cases I have seen. (It
|
||||||
|
has to be a scalar type because (iconv_t)(-1) is a possible return value
|
||||||
|
from iconv_open().) */
|
||||||
|
|
||||||
|
/* Define iconv_t ourselves. */
|
||||||
|
#undef iconv_t
|
||||||
|
#define iconv_t libiconv_t
|
||||||
|
typedef void* iconv_t;
|
||||||
|
|
||||||
|
/* Get size_t declaration.
|
||||||
|
Get wchar_t declaration if it exists. */
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/* Get errno declaration and values. */
|
||||||
|
#include <errno.h>
|
||||||
|
/* Some systems, like SunOS 4, don't have EILSEQ. Some systems, like BSD/OS,
|
||||||
|
have EILSEQ in a different header. On these systems, define EILSEQ
|
||||||
|
ourselves. */
|
||||||
|
#ifndef EILSEQ
|
||||||
|
#define EILSEQ
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Allocates descriptor for code conversion from encoding ‘fromcode’ to
|
||||||
|
encoding ‘tocode’. */
|
||||||
|
#ifndef LIBICONV_PLUG
|
||||||
|
#define iconv_open libiconv_open
|
||||||
|
#endif
|
||||||
|
extern iconv_t iconv_open (const char* tocode, const char* fromcode);
|
||||||
|
|
||||||
|
/* Converts, using conversion descriptor ‘cd’, at most ‘*inbytesleft’ bytes
|
||||||
|
starting at ‘*inbuf’, writing at most ‘*outbytesleft’ bytes starting at
|
||||||
|
‘*outbuf’.
|
||||||
|
Decrements ‘*inbytesleft’ and increments ‘*inbuf’ by the same amount.
|
||||||
|
Decrements ‘*outbytesleft’ and increments ‘*outbuf’ by the same amount. */
|
||||||
|
#ifndef LIBICONV_PLUG
|
||||||
|
#define iconv libiconv
|
||||||
|
#endif
|
||||||
|
extern size_t iconv (iconv_t cd, char* * inbuf, size_t *inbytesleft, char* * outbuf, size_t *outbytesleft);
|
||||||
|
|
||||||
|
/* Frees resources allocated for conversion descriptor ‘cd’. */
|
||||||
|
#ifndef LIBICONV_PLUG
|
||||||
|
#define iconv_close libiconv_close
|
||||||
|
#endif
|
||||||
|
extern int iconv_close (iconv_t cd);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef LIBICONV_PLUG
|
||||||
|
|
||||||
|
/* Nonstandard extensions. */
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
#if 0
|
||||||
|
/* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before
|
||||||
|
<wchar.h>.
|
||||||
|
BSD/OS 4.0.1 has a bug: <stddef.h>, <stdio.h> and <time.h> must be
|
||||||
|
included before <wchar.h>. */
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
|
#endif
|
||||||
|
#include <wchar.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* A type that holds all memory needed by a conversion descriptor.
|
||||||
|
A pointer to such an object can be used as an iconv_t. */
|
||||||
|
typedef struct {
|
||||||
|
void* dummy1[28];
|
||||||
|
#if 1
|
||||||
|
mbstate_t dummy2;
|
||||||
|
#endif
|
||||||
|
} iconv_allocation_t;
|
||||||
|
|
||||||
|
/* Allocates descriptor for code conversion from encoding ‘fromcode’ to
|
||||||
|
encoding ‘tocode’ into preallocated memory. Returns an error indicator
|
||||||
|
(0 or -1 with errno set). */
|
||||||
|
#define iconv_open_into libiconv_open_into
|
||||||
|
extern int iconv_open_into (const char* tocode, const char* fromcode,
|
||||||
|
iconv_allocation_t* resultp);
|
||||||
|
|
||||||
|
/* Control of attributes. */
|
||||||
|
#define iconvctl libiconvctl
|
||||||
|
extern int iconvctl (iconv_t cd, int request, void* argument);
|
||||||
|
|
||||||
|
/* Hook performed after every successful conversion of a Unicode character. */
|
||||||
|
typedef void (*iconv_unicode_char_hook) (unsigned int uc, void* data);
|
||||||
|
/* Hook performed after every successful conversion of a wide character. */
|
||||||
|
typedef void (*iconv_wide_char_hook) (wchar_t wc, void* data);
|
||||||
|
/* Set of hooks. */
|
||||||
|
struct iconv_hooks {
|
||||||
|
iconv_unicode_char_hook uc_hook;
|
||||||
|
iconv_wide_char_hook wc_hook;
|
||||||
|
void* data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Fallback function. Invoked when a small number of bytes could not be
|
||||||
|
converted to a Unicode character. This function should process all
|
||||||
|
bytes from inbuf and may produce replacement Unicode characters by calling
|
||||||
|
the write_replacement callback repeatedly. */
|
||||||
|
typedef void (*iconv_unicode_mb_to_uc_fallback)
|
||||||
|
(const char* inbuf, size_t inbufsize,
|
||||||
|
void (*write_replacement) (const unsigned int *buf, size_t buflen,
|
||||||
|
void* callback_arg),
|
||||||
|
void* callback_arg,
|
||||||
|
void* data);
|
||||||
|
/* Fallback function. Invoked when a Unicode character could not be converted
|
||||||
|
to the target encoding. This function should process the character and
|
||||||
|
may produce replacement bytes (in the target encoding) by calling the
|
||||||
|
write_replacement callback repeatedly. */
|
||||||
|
typedef void (*iconv_unicode_uc_to_mb_fallback)
|
||||||
|
(unsigned int code,
|
||||||
|
void (*write_replacement) (const char *buf, size_t buflen,
|
||||||
|
void* callback_arg),
|
||||||
|
void* callback_arg,
|
||||||
|
void* data);
|
||||||
|
#if 1
|
||||||
|
/* Fallback function. Invoked when a number of bytes could not be converted to
|
||||||
|
a wide character. This function should process all bytes from inbuf and may
|
||||||
|
produce replacement wide characters by calling the write_replacement
|
||||||
|
callback repeatedly. */
|
||||||
|
typedef void (*iconv_wchar_mb_to_wc_fallback)
|
||||||
|
(const char* inbuf, size_t inbufsize,
|
||||||
|
void (*write_replacement) (const wchar_t *buf, size_t buflen,
|
||||||
|
void* callback_arg),
|
||||||
|
void* callback_arg,
|
||||||
|
void* data);
|
||||||
|
/* Fallback function. Invoked when a wide character could not be converted to
|
||||||
|
the target encoding. This function should process the character and may
|
||||||
|
produce replacement bytes (in the target encoding) by calling the
|
||||||
|
write_replacement callback repeatedly. */
|
||||||
|
typedef void (*iconv_wchar_wc_to_mb_fallback)
|
||||||
|
(wchar_t code,
|
||||||
|
void (*write_replacement) (const char *buf, size_t buflen,
|
||||||
|
void* callback_arg),
|
||||||
|
void* callback_arg,
|
||||||
|
void* data);
|
||||||
|
#else
|
||||||
|
/* If the wchar_t type does not exist, these two fallback functions are never
|
||||||
|
invoked. Their argument list therefore does not matter. */
|
||||||
|
typedef void (*iconv_wchar_mb_to_wc_fallback) ();
|
||||||
|
typedef void (*iconv_wchar_wc_to_mb_fallback) ();
|
||||||
|
#endif
|
||||||
|
/* Set of fallbacks. */
|
||||||
|
struct iconv_fallbacks {
|
||||||
|
iconv_unicode_mb_to_uc_fallback mb_to_uc_fallback;
|
||||||
|
iconv_unicode_uc_to_mb_fallback uc_to_mb_fallback;
|
||||||
|
iconv_wchar_mb_to_wc_fallback mb_to_wc_fallback;
|
||||||
|
iconv_wchar_wc_to_mb_fallback wc_to_mb_fallback;
|
||||||
|
void* data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Requests for iconvctl. */
|
||||||
|
#define ICONV_TRIVIALP 0 /* int *argument */
|
||||||
|
#define ICONV_GET_TRANSLITERATE 1 /* int *argument */
|
||||||
|
#define ICONV_SET_TRANSLITERATE 2 /* const int *argument */
|
||||||
|
#define ICONV_GET_DISCARD_ILSEQ 3 /* int *argument */
|
||||||
|
#define ICONV_SET_DISCARD_ILSEQ 4 /* const int *argument */
|
||||||
|
#define ICONV_SET_HOOKS 5 /* const struct iconv_hooks *argument */
|
||||||
|
#define ICONV_SET_FALLBACKS 6 /* const struct iconv_fallbacks *argument */
|
||||||
|
|
||||||
|
/* Listing of locale independent encodings. */
|
||||||
|
#define iconvlist libiconvlist
|
||||||
|
extern void iconvlist (int (*do_one) (unsigned int namescount,
|
||||||
|
const char * const * names,
|
||||||
|
void* data),
|
||||||
|
void* data);
|
||||||
|
|
||||||
|
/* Canonicalize an encoding name.
|
||||||
|
The result is either a canonical encoding name, or name itself. */
|
||||||
|
extern const char * iconv_canonicalize (const char * name);
|
||||||
|
|
||||||
|
/* Support for relocatable packages. */
|
||||||
|
|
||||||
|
/* Sets the original and the current installation prefix of the package.
|
||||||
|
Relocation simply replaces a pathname starting with the original prefix
|
||||||
|
by the corresponding pathname with the current prefix instead. Both
|
||||||
|
prefixes should be directory names without trailing slash (i.e. use ""
|
||||||
|
instead of "/"). */
|
||||||
|
extern void libiconv_set_relocation_prefix (const char *orig_prefix,
|
||||||
|
const char *curr_prefix);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _LIBICONV_H */
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
/* Copyright (C) 2003 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU CHARSET Library.
|
||||||
|
|
||||||
|
The GNU CHARSET Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public License as
|
||||||
|
published by the Free Software Foundation; either version 2 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU CHARSET Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with the GNU CHARSET Library; see the file COPYING.LIB. If not,
|
||||||
|
see <https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef _LIBCHARSET_H
|
||||||
|
#define _LIBCHARSET_H
|
||||||
|
|
||||||
|
#include <localcharset.h>
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Support for relocatable packages. */
|
||||||
|
|
||||||
|
/* Sets the original and the current installation prefix of the package.
|
||||||
|
Relocation simply replaces a pathname starting with the original prefix
|
||||||
|
by the corresponding pathname with the current prefix instead. Both
|
||||||
|
prefixes should be directory names without trailing slash (i.e. use ""
|
||||||
|
instead of "/"). */
|
||||||
|
extern void LIBCHARSET_DLL_EXPORTED libcharset_set_relocation_prefix (const char *orig_prefix,
|
||||||
|
const char *curr_prefix);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _LIBCHARSET_H */
|
||||||
|
|
@ -0,0 +1,137 @@
|
||||||
|
/* Determine a canonical name for the current locale's character encoding.
|
||||||
|
Copyright (C) 2000-2003, 2009-2019 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU CHARSET Library.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published
|
||||||
|
by the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program; if not, see <https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef _LOCALCHARSET_H
|
||||||
|
#define _LOCALCHARSET_H
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Determine the current locale's character encoding, and canonicalize it
|
||||||
|
into one of the canonical names listed below.
|
||||||
|
The result must not be freed; it is statically allocated. The result
|
||||||
|
becomes invalid when setlocale() is used to change the global locale, or
|
||||||
|
when the value of one of the environment variables LC_ALL, LC_CTYPE, LANG
|
||||||
|
is changed; threads in multithreaded programs should not do this.
|
||||||
|
If the canonical name cannot be determined, the result is a non-canonical
|
||||||
|
name. */
|
||||||
|
extern const char * locale_charset (void);
|
||||||
|
|
||||||
|
/* About GNU canonical names for character encodings:
|
||||||
|
|
||||||
|
Every canonical name must be supported by GNU libiconv. Support by GNU libc
|
||||||
|
is also desirable.
|
||||||
|
|
||||||
|
The name is case insensitive. Usually an upper case MIME charset name is
|
||||||
|
preferred.
|
||||||
|
|
||||||
|
The current list of these GNU canonical names is:
|
||||||
|
|
||||||
|
name MIME? used by which systems
|
||||||
|
(darwin = Mac OS X, windows = native Windows)
|
||||||
|
|
||||||
|
ASCII, ANSI_X3.4-1968 glibc solaris freebsd netbsd darwin minix cygwin
|
||||||
|
ISO-8859-1 Y glibc aix hpux irix osf solaris freebsd netbsd openbsd darwin cygwin zos
|
||||||
|
ISO-8859-2 Y glibc aix hpux irix osf solaris freebsd netbsd openbsd darwin cygwin zos
|
||||||
|
ISO-8859-3 Y glibc solaris cygwin
|
||||||
|
ISO-8859-4 Y hpux osf solaris freebsd netbsd openbsd darwin
|
||||||
|
ISO-8859-5 Y glibc aix hpux irix osf solaris freebsd netbsd openbsd darwin cygwin zos
|
||||||
|
ISO-8859-6 Y glibc aix hpux solaris cygwin
|
||||||
|
ISO-8859-7 Y glibc aix hpux irix osf solaris freebsd netbsd openbsd darwin cygwin zos
|
||||||
|
ISO-8859-8 Y glibc aix hpux osf solaris cygwin zos
|
||||||
|
ISO-8859-9 Y glibc aix hpux irix osf solaris freebsd darwin cygwin zos
|
||||||
|
ISO-8859-13 glibc hpux solaris freebsd netbsd openbsd darwin cygwin
|
||||||
|
ISO-8859-14 glibc cygwin
|
||||||
|
ISO-8859-15 glibc aix irix osf solaris freebsd netbsd openbsd darwin cygwin
|
||||||
|
KOI8-R Y glibc hpux solaris freebsd netbsd openbsd darwin
|
||||||
|
KOI8-U Y glibc freebsd netbsd openbsd darwin cygwin
|
||||||
|
KOI8-T glibc
|
||||||
|
CP437 dos
|
||||||
|
CP775 dos
|
||||||
|
CP850 aix osf dos
|
||||||
|
CP852 dos
|
||||||
|
CP855 dos
|
||||||
|
CP856 aix
|
||||||
|
CP857 dos
|
||||||
|
CP861 dos
|
||||||
|
CP862 dos
|
||||||
|
CP864 dos
|
||||||
|
CP865 dos
|
||||||
|
CP866 freebsd netbsd openbsd darwin dos
|
||||||
|
CP869 dos
|
||||||
|
CP874 windows dos
|
||||||
|
CP922 aix
|
||||||
|
CP932 aix cygwin windows dos
|
||||||
|
CP943 aix zos
|
||||||
|
CP949 osf darwin windows dos
|
||||||
|
CP950 windows dos
|
||||||
|
CP1046 aix
|
||||||
|
CP1124 aix
|
||||||
|
CP1125 dos
|
||||||
|
CP1129 aix
|
||||||
|
CP1131 freebsd darwin
|
||||||
|
CP1250 windows
|
||||||
|
CP1251 glibc hpux solaris freebsd netbsd openbsd darwin cygwin windows
|
||||||
|
CP1252 aix windows
|
||||||
|
CP1253 windows
|
||||||
|
CP1254 windows
|
||||||
|
CP1255 glibc windows
|
||||||
|
CP1256 windows
|
||||||
|
CP1257 windows
|
||||||
|
GB2312 Y glibc aix hpux irix solaris freebsd netbsd darwin cygwin zos
|
||||||
|
EUC-JP Y glibc aix hpux irix osf solaris freebsd netbsd darwin cygwin
|
||||||
|
EUC-KR Y glibc aix hpux irix osf solaris freebsd netbsd darwin cygwin zos
|
||||||
|
EUC-TW glibc aix hpux irix osf solaris netbsd
|
||||||
|
BIG5 Y glibc aix hpux osf solaris freebsd netbsd darwin cygwin zos
|
||||||
|
BIG5-HKSCS glibc hpux solaris netbsd darwin
|
||||||
|
GBK glibc aix osf solaris freebsd darwin cygwin windows dos
|
||||||
|
GB18030 glibc hpux solaris freebsd netbsd darwin
|
||||||
|
SHIFT_JIS Y hpux osf solaris freebsd netbsd darwin
|
||||||
|
JOHAB glibc solaris windows
|
||||||
|
TIS-620 glibc aix hpux osf solaris cygwin zos
|
||||||
|
VISCII Y glibc
|
||||||
|
TCVN5712-1 glibc
|
||||||
|
ARMSCII-8 glibc freebsd netbsd darwin
|
||||||
|
GEORGIAN-PS glibc cygwin
|
||||||
|
PT154 glibc netbsd cygwin
|
||||||
|
HP-ROMAN8 hpux
|
||||||
|
HP-ARABIC8 hpux
|
||||||
|
HP-GREEK8 hpux
|
||||||
|
HP-HEBREW8 hpux
|
||||||
|
HP-TURKISH8 hpux
|
||||||
|
HP-KANA8 hpux
|
||||||
|
DEC-KANJI osf
|
||||||
|
DEC-HANYU osf
|
||||||
|
UTF-8 Y glibc aix hpux osf solaris netbsd darwin cygwin zos
|
||||||
|
|
||||||
|
Note: Names which are not marked as being a MIME name should not be used in
|
||||||
|
Internet protocols for information interchange (mail, news, etc.).
|
||||||
|
|
||||||
|
Note: ASCII and ANSI_X3.4-1968 are synonymous canonical names. Applications
|
||||||
|
must understand both names and treat them as equivalent.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _LOCALCHARSET_H */
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <nlohmann/detail/abi_macros.hpp>
|
||||||
|
#include <nlohmann/detail/conversions/from_json.hpp>
|
||||||
|
#include <nlohmann/detail/conversions/to_json.hpp>
|
||||||
|
#include <nlohmann/detail/meta/identity_tag.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/// @sa https://json.nlohmann.me/api/adl_serializer/
|
||||||
|
template<typename ValueType, typename>
|
||||||
|
struct adl_serializer
|
||||||
|
{
|
||||||
|
/// @brief convert a JSON value to any value type
|
||||||
|
/// @sa https://json.nlohmann.me/api/adl_serializer/from_json/
|
||||||
|
template<typename BasicJsonType, typename TargetType = ValueType>
|
||||||
|
static auto from_json(BasicJsonType && j, TargetType& val) noexcept(
|
||||||
|
noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val)))
|
||||||
|
-> decltype(::nlohmann::from_json(std::forward<BasicJsonType>(j), val), void())
|
||||||
|
{
|
||||||
|
::nlohmann::from_json(std::forward<BasicJsonType>(j), val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief convert a JSON value to any value type
|
||||||
|
/// @sa https://json.nlohmann.me/api/adl_serializer/from_json/
|
||||||
|
template<typename BasicJsonType, typename TargetType = ValueType>
|
||||||
|
static auto from_json(BasicJsonType && j) noexcept(
|
||||||
|
noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {})))
|
||||||
|
-> decltype(::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {}))
|
||||||
|
{
|
||||||
|
return ::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief convert any value type to a JSON value
|
||||||
|
/// @sa https://json.nlohmann.me/api/adl_serializer/to_json/
|
||||||
|
template<typename BasicJsonType, typename TargetType = ValueType>
|
||||||
|
static auto to_json(BasicJsonType& j, TargetType && val) noexcept(
|
||||||
|
noexcept(::nlohmann::to_json(j, std::forward<TargetType>(val))))
|
||||||
|
-> decltype(::nlohmann::to_json(j, std::forward<TargetType>(val)), void())
|
||||||
|
{
|
||||||
|
::nlohmann::to_json(j, std::forward<TargetType>(val));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint> // uint8_t, uint64_t
|
||||||
|
#include <tuple> // tie
|
||||||
|
#include <utility> // move
|
||||||
|
|
||||||
|
#include <nlohmann/detail/abi_macros.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/// @brief an internal type for a backed binary type
|
||||||
|
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/
|
||||||
|
template<typename BinaryType>
|
||||||
|
class byte_container_with_subtype : public BinaryType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using container_type = BinaryType;
|
||||||
|
using subtype_type = std::uint64_t;
|
||||||
|
|
||||||
|
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
|
||||||
|
byte_container_with_subtype() noexcept(noexcept(container_type()))
|
||||||
|
: container_type()
|
||||||
|
{}
|
||||||
|
|
||||||
|
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
|
||||||
|
byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b)))
|
||||||
|
: container_type(b)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
|
||||||
|
byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b))))
|
||||||
|
: container_type(std::move(b))
|
||||||
|
{}
|
||||||
|
|
||||||
|
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
|
||||||
|
byte_container_with_subtype(const container_type& b, subtype_type subtype_) noexcept(noexcept(container_type(b)))
|
||||||
|
: container_type(b)
|
||||||
|
, m_subtype(subtype_)
|
||||||
|
, m_has_subtype(true)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
|
||||||
|
byte_container_with_subtype(container_type&& b, subtype_type subtype_) noexcept(noexcept(container_type(std::move(b))))
|
||||||
|
: container_type(std::move(b))
|
||||||
|
, m_subtype(subtype_)
|
||||||
|
, m_has_subtype(true)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool operator==(const byte_container_with_subtype& rhs) const
|
||||||
|
{
|
||||||
|
return std::tie(static_cast<const BinaryType&>(*this), m_subtype, m_has_subtype) ==
|
||||||
|
std::tie(static_cast<const BinaryType&>(rhs), rhs.m_subtype, rhs.m_has_subtype);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const byte_container_with_subtype& rhs) const
|
||||||
|
{
|
||||||
|
return !(rhs == *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief sets the binary subtype
|
||||||
|
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/set_subtype/
|
||||||
|
void set_subtype(subtype_type subtype_) noexcept
|
||||||
|
{
|
||||||
|
m_subtype = subtype_;
|
||||||
|
m_has_subtype = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief return the binary subtype
|
||||||
|
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/subtype/
|
||||||
|
constexpr subtype_type subtype() const noexcept
|
||||||
|
{
|
||||||
|
return m_has_subtype ? m_subtype : static_cast<subtype_type>(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief return whether the value has a subtype
|
||||||
|
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/has_subtype/
|
||||||
|
constexpr bool has_subtype() const noexcept
|
||||||
|
{
|
||||||
|
return m_has_subtype;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief clears the binary subtype
|
||||||
|
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/clear_subtype/
|
||||||
|
void clear_subtype() noexcept
|
||||||
|
{
|
||||||
|
m_subtype = 0;
|
||||||
|
m_has_subtype = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
subtype_type m_subtype = 0;
|
||||||
|
bool m_has_subtype = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// This file contains all macro definitions affecting or depending on the ABI
|
||||||
|
|
||||||
|
#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK
|
||||||
|
#if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH)
|
||||||
|
#if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 3
|
||||||
|
#warning "Already included a different version of the library!"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum)
|
||||||
|
#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum)
|
||||||
|
#define NLOHMANN_JSON_VERSION_PATCH 3 // NOLINT(modernize-macro-to-enum)
|
||||||
|
|
||||||
|
#ifndef JSON_DIAGNOSTICS
|
||||||
|
#define JSON_DIAGNOSTICS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||||
|
#define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if JSON_DIAGNOSTICS
|
||||||
|
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag
|
||||||
|
#else
|
||||||
|
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||||
|
#define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp
|
||||||
|
#else
|
||||||
|
#define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
|
||||||
|
#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Construct the namespace ABI tags component
|
||||||
|
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b
|
||||||
|
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \
|
||||||
|
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b)
|
||||||
|
|
||||||
|
#define NLOHMANN_JSON_ABI_TAGS \
|
||||||
|
NLOHMANN_JSON_ABI_TAGS_CONCAT( \
|
||||||
|
NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \
|
||||||
|
NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON)
|
||||||
|
|
||||||
|
// Construct the namespace version component
|
||||||
|
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
|
||||||
|
_v ## major ## _ ## minor ## _ ## patch
|
||||||
|
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \
|
||||||
|
NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch)
|
||||||
|
|
||||||
|
#if NLOHMANN_JSON_NAMESPACE_NO_VERSION
|
||||||
|
#define NLOHMANN_JSON_NAMESPACE_VERSION
|
||||||
|
#else
|
||||||
|
#define NLOHMANN_JSON_NAMESPACE_VERSION \
|
||||||
|
NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \
|
||||||
|
NLOHMANN_JSON_VERSION_MINOR, \
|
||||||
|
NLOHMANN_JSON_VERSION_PATCH)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Combine namespace components
|
||||||
|
#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b
|
||||||
|
#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \
|
||||||
|
NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b)
|
||||||
|
|
||||||
|
#ifndef NLOHMANN_JSON_NAMESPACE
|
||||||
|
#define NLOHMANN_JSON_NAMESPACE \
|
||||||
|
nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \
|
||||||
|
NLOHMANN_JSON_ABI_TAGS, \
|
||||||
|
NLOHMANN_JSON_NAMESPACE_VERSION)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
#define NLOHMANN_JSON_NAMESPACE_BEGIN \
|
||||||
|
namespace nlohmann \
|
||||||
|
{ \
|
||||||
|
inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \
|
||||||
|
NLOHMANN_JSON_ABI_TAGS, \
|
||||||
|
NLOHMANN_JSON_NAMESPACE_VERSION) \
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
#define NLOHMANN_JSON_NAMESPACE_END \
|
||||||
|
} /* namespace (inline namespace) NOLINT(readability/namespace) */ \
|
||||||
|
} // namespace nlohmann
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,497 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm> // transform
|
||||||
|
#include <array> // array
|
||||||
|
#include <forward_list> // forward_list
|
||||||
|
#include <iterator> // inserter, front_inserter, end
|
||||||
|
#include <map> // map
|
||||||
|
#include <string> // string
|
||||||
|
#include <tuple> // tuple, make_tuple
|
||||||
|
#include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible
|
||||||
|
#include <unordered_map> // unordered_map
|
||||||
|
#include <utility> // pair, declval
|
||||||
|
#include <valarray> // valarray
|
||||||
|
|
||||||
|
#include <nlohmann/detail/exceptions.hpp>
|
||||||
|
#include <nlohmann/detail/macro_scope.hpp>
|
||||||
|
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||||
|
#include <nlohmann/detail/meta/identity_tag.hpp>
|
||||||
|
#include <nlohmann/detail/meta/std_fs.hpp>
|
||||||
|
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||||
|
#include <nlohmann/detail/string_concat.hpp>
|
||||||
|
#include <nlohmann/detail/value_t.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
inline void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!j.is_null()))
|
||||||
|
{
|
||||||
|
JSON_THROW(type_error::create(302, concat("type must be null, but is ", j.type_name()), &j));
|
||||||
|
}
|
||||||
|
n = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// overloads for basic_json template parameters
|
||||||
|
template < typename BasicJsonType, typename ArithmeticType,
|
||||||
|
enable_if_t < std::is_arithmetic<ArithmeticType>::value&&
|
||||||
|
!std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
|
||||||
|
int > = 0 >
|
||||||
|
void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
|
||||||
|
{
|
||||||
|
switch (static_cast<value_t>(j))
|
||||||
|
{
|
||||||
|
case value_t::number_unsigned:
|
||||||
|
{
|
||||||
|
val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case value_t::number_integer:
|
||||||
|
{
|
||||||
|
val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case value_t::number_float:
|
||||||
|
{
|
||||||
|
val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::null:
|
||||||
|
case value_t::object:
|
||||||
|
case value_t::array:
|
||||||
|
case value_t::string:
|
||||||
|
case value_t::boolean:
|
||||||
|
case value_t::binary:
|
||||||
|
case value_t::discarded:
|
||||||
|
default:
|
||||||
|
JSON_THROW(type_error::create(302, concat("type must be number, but is ", j.type_name()), &j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
inline void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!j.is_boolean()))
|
||||||
|
{
|
||||||
|
JSON_THROW(type_error::create(302, concat("type must be boolean, but is ", j.type_name()), &j));
|
||||||
|
}
|
||||||
|
b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
inline void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
|
||||||
|
{
|
||||||
|
JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
|
||||||
|
}
|
||||||
|
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename BasicJsonType, typename StringType,
|
||||||
|
enable_if_t <
|
||||||
|
std::is_assignable<StringType&, const typename BasicJsonType::string_t>::value
|
||||||
|
&& is_detected_exact<typename BasicJsonType::string_t::value_type, value_type_t, StringType>::value
|
||||||
|
&& !std::is_same<typename BasicJsonType::string_t, StringType>::value
|
||||||
|
&& !is_json_ref<StringType>::value, int > = 0 >
|
||||||
|
inline void from_json(const BasicJsonType& j, StringType& s)
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
|
||||||
|
{
|
||||||
|
JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
|
||||||
|
}
|
||||||
|
|
||||||
|
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)
|
||||||
|
{
|
||||||
|
get_arithmetic_value(j, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val)
|
||||||
|
{
|
||||||
|
get_arithmetic_value(j, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val)
|
||||||
|
{
|
||||||
|
get_arithmetic_value(j, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !JSON_DISABLE_ENUM_SERIALIZATION
|
||||||
|
template<typename BasicJsonType, typename EnumType,
|
||||||
|
enable_if_t<std::is_enum<EnumType>::value, int> = 0>
|
||||||
|
inline void from_json(const BasicJsonType& j, EnumType& e)
|
||||||
|
{
|
||||||
|
typename std::underlying_type<EnumType>::type val;
|
||||||
|
get_arithmetic_value(j, val);
|
||||||
|
e = static_cast<EnumType>(val);
|
||||||
|
}
|
||||||
|
#endif // JSON_DISABLE_ENUM_SERIALIZATION
|
||||||
|
|
||||||
|
// forward_list doesn't have an insert method
|
||||||
|
template<typename BasicJsonType, typename T, typename Allocator,
|
||||||
|
enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
|
||||||
|
inline void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||||
|
{
|
||||||
|
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
|
||||||
|
}
|
||||||
|
l.clear();
|
||||||
|
std::transform(j.rbegin(), j.rend(),
|
||||||
|
std::front_inserter(l), [](const BasicJsonType & i)
|
||||||
|
{
|
||||||
|
return i.template get<T>();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// valarray doesn't have an insert method
|
||||||
|
template<typename BasicJsonType, typename T,
|
||||||
|
enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
|
||||||
|
inline void from_json(const BasicJsonType& j, std::valarray<T>& l)
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||||
|
{
|
||||||
|
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
|
||||||
|
}
|
||||||
|
l.resize(j.size());
|
||||||
|
std::transform(j.begin(), j.end(), std::begin(l),
|
||||||
|
[](const BasicJsonType & elem)
|
||||||
|
{
|
||||||
|
return elem.template get<T>();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename T, std::size_t N>
|
||||||
|
auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||||
|
-> decltype(j.template get<T>(), void())
|
||||||
|
{
|
||||||
|
for (std::size_t i = 0; i < N; ++i)
|
||||||
|
{
|
||||||
|
arr[i] = j.at(i).template get<T>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
inline void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)
|
||||||
|
{
|
||||||
|
arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename T, std::size_t N>
|
||||||
|
auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,
|
||||||
|
priority_tag<2> /*unused*/)
|
||||||
|
-> decltype(j.template get<T>(), void())
|
||||||
|
{
|
||||||
|
for (std::size_t i = 0; i < N; ++i)
|
||||||
|
{
|
||||||
|
arr[i] = j.at(i).template get<T>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename ConstructibleArrayType,
|
||||||
|
enable_if_t<
|
||||||
|
std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value,
|
||||||
|
int> = 0>
|
||||||
|
auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/)
|
||||||
|
-> decltype(
|
||||||
|
arr.reserve(std::declval<typename ConstructibleArrayType::size_type>()),
|
||||||
|
j.template get<typename ConstructibleArrayType::value_type>(),
|
||||||
|
void())
|
||||||
|
{
|
||||||
|
using std::end;
|
||||||
|
|
||||||
|
ConstructibleArrayType ret;
|
||||||
|
ret.reserve(j.size());
|
||||||
|
std::transform(j.begin(), j.end(),
|
||||||
|
std::inserter(ret, end(ret)), [](const BasicJsonType & i)
|
||||||
|
{
|
||||||
|
// get<BasicJsonType>() returns *this, this won't call a from_json
|
||||||
|
// method when value_type is BasicJsonType
|
||||||
|
return i.template get<typename ConstructibleArrayType::value_type>();
|
||||||
|
});
|
||||||
|
arr = std::move(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename ConstructibleArrayType,
|
||||||
|
enable_if_t<
|
||||||
|
std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value,
|
||||||
|
int> = 0>
|
||||||
|
inline void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr,
|
||||||
|
priority_tag<0> /*unused*/)
|
||||||
|
{
|
||||||
|
using std::end;
|
||||||
|
|
||||||
|
ConstructibleArrayType ret;
|
||||||
|
std::transform(
|
||||||
|
j.begin(), j.end(), std::inserter(ret, end(ret)),
|
||||||
|
[](const BasicJsonType & i)
|
||||||
|
{
|
||||||
|
// get<BasicJsonType>() returns *this, this won't call a from_json
|
||||||
|
// method when value_type is BasicJsonType
|
||||||
|
return i.template get<typename ConstructibleArrayType::value_type>();
|
||||||
|
});
|
||||||
|
arr = std::move(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename BasicJsonType, typename ConstructibleArrayType,
|
||||||
|
enable_if_t <
|
||||||
|
is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||||
|
!is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||||
|
!is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||||
|
!std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value&&
|
||||||
|
!is_basic_json<ConstructibleArrayType>::value,
|
||||||
|
int > = 0 >
|
||||||
|
auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)
|
||||||
|
-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}),
|
||||||
|
j.template get<typename ConstructibleArrayType::value_type>(),
|
||||||
|
void())
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||||
|
{
|
||||||
|
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
|
||||||
|
}
|
||||||
|
|
||||||
|
from_json_array_impl(j, arr, priority_tag<3> {});
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename BasicJsonType, typename T, std::size_t... Idx >
|
||||||
|
std::array<T, sizeof...(Idx)> from_json_inplace_array_impl(BasicJsonType&& j,
|
||||||
|
identity_tag<std::array<T, sizeof...(Idx)>> /*unused*/, index_sequence<Idx...> /*unused*/)
|
||||||
|
{
|
||||||
|
return { { std::forward<BasicJsonType>(j).at(Idx).template get<T>()... } };
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename BasicJsonType, typename T, std::size_t N >
|
||||||
|
auto from_json(BasicJsonType&& j, identity_tag<std::array<T, N>> tag)
|
||||||
|
-> decltype(from_json_inplace_array_impl(std::forward<BasicJsonType>(j), tag, make_index_sequence<N> {}))
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||||
|
{
|
||||||
|
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
|
||||||
|
}
|
||||||
|
|
||||||
|
return from_json_inplace_array_impl(std::forward<BasicJsonType>(j), tag, make_index_sequence<N> {});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
inline void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin)
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!j.is_binary()))
|
||||||
|
{
|
||||||
|
JSON_THROW(type_error::create(302, concat("type must be binary, but is ", j.type_name()), &j));
|
||||||
|
}
|
||||||
|
|
||||||
|
bin = *j.template get_ptr<const typename BasicJsonType::binary_t*>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename ConstructibleObjectType,
|
||||||
|
enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>
|
||||||
|
inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
|
||||||
|
{
|
||||||
|
JSON_THROW(type_error::create(302, concat("type must be object, but is ", j.type_name()), &j));
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstructibleObjectType ret;
|
||||||
|
const auto* inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
|
||||||
|
using value_type = typename ConstructibleObjectType::value_type;
|
||||||
|
std::transform(
|
||||||
|
inner_object->begin(), inner_object->end(),
|
||||||
|
std::inserter(ret, ret.begin()),
|
||||||
|
[](typename BasicJsonType::object_t::value_type const & p)
|
||||||
|
{
|
||||||
|
return value_type(p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>());
|
||||||
|
});
|
||||||
|
obj = std::move(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
// overload for arithmetic types, not chosen for basic_json template arguments
|
||||||
|
// (BooleanType, etc..); note: Is it really necessary to provide explicit
|
||||||
|
// overloads for boolean_t etc. in case of a custom BooleanType which is not
|
||||||
|
// an arithmetic type?
|
||||||
|
template < typename BasicJsonType, typename ArithmeticType,
|
||||||
|
enable_if_t <
|
||||||
|
std::is_arithmetic<ArithmeticType>::value&&
|
||||||
|
!std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value&&
|
||||||
|
!std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value&&
|
||||||
|
!std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value&&
|
||||||
|
!std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
|
||||||
|
int > = 0 >
|
||||||
|
inline void from_json(const BasicJsonType& j, ArithmeticType& val)
|
||||||
|
{
|
||||||
|
switch (static_cast<value_t>(j))
|
||||||
|
{
|
||||||
|
case value_t::number_unsigned:
|
||||||
|
{
|
||||||
|
val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case value_t::number_integer:
|
||||||
|
{
|
||||||
|
val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case value_t::number_float:
|
||||||
|
{
|
||||||
|
val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case value_t::boolean:
|
||||||
|
{
|
||||||
|
val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::boolean_t*>());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::null:
|
||||||
|
case value_t::object:
|
||||||
|
case value_t::array:
|
||||||
|
case value_t::string:
|
||||||
|
case value_t::binary:
|
||||||
|
case value_t::discarded:
|
||||||
|
default:
|
||||||
|
JSON_THROW(type_error::create(302, concat("type must be number, but is ", j.type_name()), &j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename... Args, std::size_t... Idx>
|
||||||
|
std::tuple<Args...> from_json_tuple_impl_base(BasicJsonType&& j, index_sequence<Idx...> /*unused*/)
|
||||||
|
{
|
||||||
|
return std::make_tuple(std::forward<BasicJsonType>(j).at(Idx).template get<Args>()...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename BasicJsonType, class A1, class A2 >
|
||||||
|
std::pair<A1, A2> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::pair<A1, A2>> /*unused*/, priority_tag<0> /*unused*/)
|
||||||
|
{
|
||||||
|
return {std::forward<BasicJsonType>(j).at(0).template get<A1>(),
|
||||||
|
std::forward<BasicJsonType>(j).at(1).template get<A2>()};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename A1, typename A2>
|
||||||
|
inline void from_json_tuple_impl(BasicJsonType&& j, std::pair<A1, A2>& p, priority_tag<1> /*unused*/)
|
||||||
|
{
|
||||||
|
p = from_json_tuple_impl(std::forward<BasicJsonType>(j), identity_tag<std::pair<A1, A2>> {}, priority_tag<0> {});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename... Args>
|
||||||
|
std::tuple<Args...> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::tuple<Args...>> /*unused*/, priority_tag<2> /*unused*/)
|
||||||
|
{
|
||||||
|
return from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename... Args>
|
||||||
|
inline void from_json_tuple_impl(BasicJsonType&& j, std::tuple<Args...>& t, priority_tag<3> /*unused*/)
|
||||||
|
{
|
||||||
|
t = from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename TupleRelated>
|
||||||
|
auto from_json(BasicJsonType&& j, TupleRelated&& t)
|
||||||
|
-> decltype(from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {}))
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||||
|
{
|
||||||
|
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
|
||||||
|
}
|
||||||
|
|
||||||
|
return from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {});
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,
|
||||||
|
typename = enable_if_t < !std::is_constructible <
|
||||||
|
typename BasicJsonType::string_t, Key >::value >>
|
||||||
|
inline void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||||
|
{
|
||||||
|
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
|
||||||
|
}
|
||||||
|
m.clear();
|
||||||
|
for (const auto& p : j)
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!p.is_array()))
|
||||||
|
{
|
||||||
|
JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &j));
|
||||||
|
}
|
||||||
|
m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,
|
||||||
|
typename = enable_if_t < !std::is_constructible <
|
||||||
|
typename BasicJsonType::string_t, Key >::value >>
|
||||||
|
inline void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||||
|
{
|
||||||
|
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
|
||||||
|
}
|
||||||
|
m.clear();
|
||||||
|
for (const auto& p : j)
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!p.is_array()))
|
||||||
|
{
|
||||||
|
JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &j));
|
||||||
|
}
|
||||||
|
m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
inline void from_json(const BasicJsonType& j, std_fs::path& p)
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
|
||||||
|
{
|
||||||
|
JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
|
||||||
|
}
|
||||||
|
p = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct from_json_fn
|
||||||
|
{
|
||||||
|
template<typename BasicJsonType, typename T>
|
||||||
|
auto operator()(const BasicJsonType& j, T&& val) const
|
||||||
|
noexcept(noexcept(from_json(j, std::forward<T>(val))))
|
||||||
|
-> decltype(from_json(j, std::forward<T>(val)))
|
||||||
|
{
|
||||||
|
return from_json(j, std::forward<T>(val));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
#ifndef JSON_HAS_CPP_17
|
||||||
|
/// namespace to hold default `from_json` function
|
||||||
|
/// to see why this is required:
|
||||||
|
/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html
|
||||||
|
namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces)
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
JSON_INLINE_VARIABLE constexpr const auto& from_json = // NOLINT(misc-definitions-in-headers)
|
||||||
|
detail::static_const<detail::from_json_fn>::value;
|
||||||
|
#ifndef JSON_HAS_CPP_17
|
||||||
|
} // namespace
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,447 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm> // copy
|
||||||
|
#include <iterator> // begin, end
|
||||||
|
#include <string> // string
|
||||||
|
#include <tuple> // tuple, get
|
||||||
|
#include <type_traits> // is_same, is_constructible, is_floating_point, is_enum, underlying_type
|
||||||
|
#include <utility> // move, forward, declval, pair
|
||||||
|
#include <valarray> // valarray
|
||||||
|
#include <vector> // vector
|
||||||
|
|
||||||
|
#include <nlohmann/detail/iterators/iteration_proxy.hpp>
|
||||||
|
#include <nlohmann/detail/macro_scope.hpp>
|
||||||
|
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||||
|
#include <nlohmann/detail/meta/std_fs.hpp>
|
||||||
|
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||||
|
#include <nlohmann/detail/value_t.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
//////////////////
|
||||||
|
// constructors //
|
||||||
|
//////////////////
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note all external_constructor<>::construct functions need to call
|
||||||
|
* j.m_data.m_value.destroy(j.m_data.m_type) to avoid a memory leak in case j contains an
|
||||||
|
* allocated value (e.g., a string). See bug issue
|
||||||
|
* https://github.com/nlohmann/json/issues/2865 for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template<value_t> struct external_constructor;
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct external_constructor<value_t::boolean>
|
||||||
|
{
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept
|
||||||
|
{
|
||||||
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
|
j.m_data.m_type = value_t::boolean;
|
||||||
|
j.m_data.m_value = b;
|
||||||
|
j.assert_invariant();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct external_constructor<value_t::string>
|
||||||
|
{
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)
|
||||||
|
{
|
||||||
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
|
j.m_data.m_type = value_t::string;
|
||||||
|
j.m_data.m_value = s;
|
||||||
|
j.assert_invariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s)
|
||||||
|
{
|
||||||
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
|
j.m_data.m_type = value_t::string;
|
||||||
|
j.m_data.m_value = std::move(s);
|
||||||
|
j.assert_invariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename BasicJsonType, typename CompatibleStringType,
|
||||||
|
enable_if_t < !std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value,
|
||||||
|
int > = 0 >
|
||||||
|
static void construct(BasicJsonType& j, const CompatibleStringType& str)
|
||||||
|
{
|
||||||
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
|
j.m_data.m_type = value_t::string;
|
||||||
|
j.m_data.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
|
||||||
|
j.assert_invariant();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct external_constructor<value_t::binary>
|
||||||
|
{
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b)
|
||||||
|
{
|
||||||
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
|
j.m_data.m_type = value_t::binary;
|
||||||
|
j.m_data.m_value = typename BasicJsonType::binary_t(b);
|
||||||
|
j.assert_invariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b)
|
||||||
|
{
|
||||||
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
|
j.m_data.m_type = value_t::binary;
|
||||||
|
j.m_data.m_value = typename BasicJsonType::binary_t(std::move(b));
|
||||||
|
j.assert_invariant();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct external_constructor<value_t::number_float>
|
||||||
|
{
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept
|
||||||
|
{
|
||||||
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
|
j.m_data.m_type = value_t::number_float;
|
||||||
|
j.m_data.m_value = val;
|
||||||
|
j.assert_invariant();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct external_constructor<value_t::number_unsigned>
|
||||||
|
{
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept
|
||||||
|
{
|
||||||
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
|
j.m_data.m_type = value_t::number_unsigned;
|
||||||
|
j.m_data.m_value = val;
|
||||||
|
j.assert_invariant();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct external_constructor<value_t::number_integer>
|
||||||
|
{
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept
|
||||||
|
{
|
||||||
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
|
j.m_data.m_type = value_t::number_integer;
|
||||||
|
j.m_data.m_value = val;
|
||||||
|
j.assert_invariant();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct external_constructor<value_t::array>
|
||||||
|
{
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)
|
||||||
|
{
|
||||||
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
|
j.m_data.m_type = value_t::array;
|
||||||
|
j.m_data.m_value = arr;
|
||||||
|
j.set_parents();
|
||||||
|
j.assert_invariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
|
||||||
|
{
|
||||||
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
|
j.m_data.m_type = value_t::array;
|
||||||
|
j.m_data.m_value = std::move(arr);
|
||||||
|
j.set_parents();
|
||||||
|
j.assert_invariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename BasicJsonType, typename CompatibleArrayType,
|
||||||
|
enable_if_t < !std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value,
|
||||||
|
int > = 0 >
|
||||||
|
static void construct(BasicJsonType& j, const CompatibleArrayType& arr)
|
||||||
|
{
|
||||||
|
using std::begin;
|
||||||
|
using std::end;
|
||||||
|
|
||||||
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
|
j.m_data.m_type = value_t::array;
|
||||||
|
j.m_data.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
|
||||||
|
j.set_parents();
|
||||||
|
j.assert_invariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
static void construct(BasicJsonType& j, const std::vector<bool>& arr)
|
||||||
|
{
|
||||||
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
|
j.m_data.m_type = value_t::array;
|
||||||
|
j.m_data.m_value = value_t::array;
|
||||||
|
j.m_data.m_value.array->reserve(arr.size());
|
||||||
|
for (const bool x : arr)
|
||||||
|
{
|
||||||
|
j.m_data.m_value.array->push_back(x);
|
||||||
|
j.set_parent(j.m_data.m_value.array->back());
|
||||||
|
}
|
||||||
|
j.assert_invariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename T,
|
||||||
|
enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
|
||||||
|
static void construct(BasicJsonType& j, const std::valarray<T>& arr)
|
||||||
|
{
|
||||||
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
|
j.m_data.m_type = value_t::array;
|
||||||
|
j.m_data.m_value = value_t::array;
|
||||||
|
j.m_data.m_value.array->resize(arr.size());
|
||||||
|
if (arr.size() > 0)
|
||||||
|
{
|
||||||
|
std::copy(std::begin(arr), std::end(arr), j.m_data.m_value.array->begin());
|
||||||
|
}
|
||||||
|
j.set_parents();
|
||||||
|
j.assert_invariant();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct external_constructor<value_t::object>
|
||||||
|
{
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)
|
||||||
|
{
|
||||||
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
|
j.m_data.m_type = value_t::object;
|
||||||
|
j.m_data.m_value = obj;
|
||||||
|
j.set_parents();
|
||||||
|
j.assert_invariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
|
||||||
|
{
|
||||||
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
|
j.m_data.m_type = value_t::object;
|
||||||
|
j.m_data.m_value = std::move(obj);
|
||||||
|
j.set_parents();
|
||||||
|
j.assert_invariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename BasicJsonType, typename CompatibleObjectType,
|
||||||
|
enable_if_t < !std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int > = 0 >
|
||||||
|
static void construct(BasicJsonType& j, const CompatibleObjectType& obj)
|
||||||
|
{
|
||||||
|
using std::begin;
|
||||||
|
using std::end;
|
||||||
|
|
||||||
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
|
j.m_data.m_type = value_t::object;
|
||||||
|
j.m_data.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
|
||||||
|
j.set_parents();
|
||||||
|
j.assert_invariant();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/////////////
|
||||||
|
// to_json //
|
||||||
|
/////////////
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename T,
|
||||||
|
enable_if_t<std::is_same<T, typename BasicJsonType::boolean_t>::value, int> = 0>
|
||||||
|
inline void to_json(BasicJsonType& j, T b) noexcept
|
||||||
|
{
|
||||||
|
external_constructor<value_t::boolean>::construct(j, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename BasicJsonType, typename BoolRef,
|
||||||
|
enable_if_t <
|
||||||
|
((std::is_same<std::vector<bool>::reference, BoolRef>::value
|
||||||
|
&& !std::is_same <std::vector<bool>::reference, typename BasicJsonType::boolean_t&>::value)
|
||||||
|
|| (std::is_same<std::vector<bool>::const_reference, BoolRef>::value
|
||||||
|
&& !std::is_same <detail::uncvref_t<std::vector<bool>::const_reference>,
|
||||||
|
typename BasicJsonType::boolean_t >::value))
|
||||||
|
&& std::is_convertible<const BoolRef&, typename BasicJsonType::boolean_t>::value, int > = 0 >
|
||||||
|
inline void to_json(BasicJsonType& j, const BoolRef& b) noexcept
|
||||||
|
{
|
||||||
|
external_constructor<value_t::boolean>::construct(j, static_cast<typename BasicJsonType::boolean_t>(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename CompatibleString,
|
||||||
|
enable_if_t<std::is_constructible<typename BasicJsonType::string_t, CompatibleString>::value, int> = 0>
|
||||||
|
inline void to_json(BasicJsonType& j, const CompatibleString& s)
|
||||||
|
{
|
||||||
|
external_constructor<value_t::string>::construct(j, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
inline void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s)
|
||||||
|
{
|
||||||
|
external_constructor<value_t::string>::construct(j, std::move(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename FloatType,
|
||||||
|
enable_if_t<std::is_floating_point<FloatType>::value, int> = 0>
|
||||||
|
inline void to_json(BasicJsonType& j, FloatType val) noexcept
|
||||||
|
{
|
||||||
|
external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename CompatibleNumberUnsignedType,
|
||||||
|
enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t, CompatibleNumberUnsignedType>::value, int> = 0>
|
||||||
|
inline void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept
|
||||||
|
{
|
||||||
|
external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename CompatibleNumberIntegerType,
|
||||||
|
enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_integer_t, CompatibleNumberIntegerType>::value, int> = 0>
|
||||||
|
inline void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept
|
||||||
|
{
|
||||||
|
external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !JSON_DISABLE_ENUM_SERIALIZATION
|
||||||
|
template<typename BasicJsonType, typename EnumType,
|
||||||
|
enable_if_t<std::is_enum<EnumType>::value, int> = 0>
|
||||||
|
inline void to_json(BasicJsonType& j, EnumType e) noexcept
|
||||||
|
{
|
||||||
|
using underlying_type = typename std::underlying_type<EnumType>::type;
|
||||||
|
static constexpr value_t integral_value_t = std::is_unsigned<underlying_type>::value ? value_t::number_unsigned : value_t::number_integer;
|
||||||
|
external_constructor<integral_value_t>::construct(j, static_cast<underlying_type>(e));
|
||||||
|
}
|
||||||
|
#endif // JSON_DISABLE_ENUM_SERIALIZATION
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
inline void to_json(BasicJsonType& j, const std::vector<bool>& e)
|
||||||
|
{
|
||||||
|
external_constructor<value_t::array>::construct(j, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename BasicJsonType, typename CompatibleArrayType,
|
||||||
|
enable_if_t < is_compatible_array_type<BasicJsonType,
|
||||||
|
CompatibleArrayType>::value&&
|
||||||
|
!is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value&&
|
||||||
|
!is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value&&
|
||||||
|
!std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value&&
|
||||||
|
!is_basic_json<CompatibleArrayType>::value,
|
||||||
|
int > = 0 >
|
||||||
|
inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
|
||||||
|
{
|
||||||
|
external_constructor<value_t::array>::construct(j, arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
inline void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin)
|
||||||
|
{
|
||||||
|
external_constructor<value_t::binary>::construct(j, bin);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename T,
|
||||||
|
enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
|
||||||
|
inline void to_json(BasicJsonType& j, const std::valarray<T>& arr)
|
||||||
|
{
|
||||||
|
external_constructor<value_t::array>::construct(j, std::move(arr));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
inline void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
|
||||||
|
{
|
||||||
|
external_constructor<value_t::array>::construct(j, std::move(arr));
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename BasicJsonType, typename CompatibleObjectType,
|
||||||
|
enable_if_t < is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value&& !is_basic_json<CompatibleObjectType>::value, int > = 0 >
|
||||||
|
inline void to_json(BasicJsonType& j, const CompatibleObjectType& obj)
|
||||||
|
{
|
||||||
|
external_constructor<value_t::object>::construct(j, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
inline void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
|
||||||
|
{
|
||||||
|
external_constructor<value_t::object>::construct(j, std::move(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename BasicJsonType, typename T, std::size_t N,
|
||||||
|
enable_if_t < !std::is_constructible<typename BasicJsonType::string_t,
|
||||||
|
const T(&)[N]>::value, // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||||
|
int > = 0 >
|
||||||
|
inline void to_json(BasicJsonType& j, const T(&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||||
|
{
|
||||||
|
external_constructor<value_t::array>::construct(j, arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename BasicJsonType, typename T1, typename T2, enable_if_t < std::is_constructible<BasicJsonType, T1>::value&& std::is_constructible<BasicJsonType, T2>::value, int > = 0 >
|
||||||
|
inline void to_json(BasicJsonType& j, const std::pair<T1, T2>& p)
|
||||||
|
{
|
||||||
|
j = { p.first, p.second };
|
||||||
|
}
|
||||||
|
|
||||||
|
// for https://github.com/nlohmann/json/pull/1134
|
||||||
|
template<typename BasicJsonType, typename T,
|
||||||
|
enable_if_t<std::is_same<T, iteration_proxy_value<typename BasicJsonType::iterator>>::value, int> = 0>
|
||||||
|
inline void to_json(BasicJsonType& j, const T& b)
|
||||||
|
{
|
||||||
|
j = { {b.key(), b.value()} };
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename Tuple, std::size_t... Idx>
|
||||||
|
inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...> /*unused*/)
|
||||||
|
{
|
||||||
|
j = { std::get<Idx>(t)... };
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename T, enable_if_t<is_constructible_tuple<BasicJsonType, T>::value, int > = 0>
|
||||||
|
inline void to_json(BasicJsonType& j, const T& t)
|
||||||
|
{
|
||||||
|
to_json_tuple_impl(j, t, make_index_sequence<std::tuple_size<T>::value> {});
|
||||||
|
}
|
||||||
|
|
||||||
|
#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
inline void to_json(BasicJsonType& j, const std_fs::path& p)
|
||||||
|
{
|
||||||
|
j = p.string();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct to_json_fn
|
||||||
|
{
|
||||||
|
template<typename BasicJsonType, typename T>
|
||||||
|
auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward<T>(val))))
|
||||||
|
-> decltype(to_json(j, std::forward<T>(val)), void())
|
||||||
|
{
|
||||||
|
return to_json(j, std::forward<T>(val));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
#ifndef JSON_HAS_CPP_17
|
||||||
|
/// namespace to hold default `to_json` function
|
||||||
|
/// to see why this is required:
|
||||||
|
/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html
|
||||||
|
namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces)
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
JSON_INLINE_VARIABLE constexpr const auto& to_json = // NOLINT(misc-definitions-in-headers)
|
||||||
|
detail::static_const<detail::to_json_fn>::value;
|
||||||
|
#ifndef JSON_HAS_CPP_17
|
||||||
|
} // namespace
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,257 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef> // nullptr_t
|
||||||
|
#include <exception> // exception
|
||||||
|
#if JSON_DIAGNOSTICS
|
||||||
|
#include <numeric> // accumulate
|
||||||
|
#endif
|
||||||
|
#include <stdexcept> // runtime_error
|
||||||
|
#include <string> // to_string
|
||||||
|
#include <vector> // vector
|
||||||
|
|
||||||
|
#include <nlohmann/detail/value_t.hpp>
|
||||||
|
#include <nlohmann/detail/string_escape.hpp>
|
||||||
|
#include <nlohmann/detail/input/position_t.hpp>
|
||||||
|
#include <nlohmann/detail/macro_scope.hpp>
|
||||||
|
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||||
|
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||||
|
#include <nlohmann/detail/string_concat.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
////////////////
|
||||||
|
// exceptions //
|
||||||
|
////////////////
|
||||||
|
|
||||||
|
/// @brief general exception of the @ref basic_json class
|
||||||
|
/// @sa https://json.nlohmann.me/api/basic_json/exception/
|
||||||
|
class exception : public std::exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// returns the explanatory string
|
||||||
|
const char* what() const noexcept override
|
||||||
|
{
|
||||||
|
return m.what();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// the id of the exception
|
||||||
|
const int id; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes)
|
||||||
|
|
||||||
|
protected:
|
||||||
|
JSON_HEDLEY_NON_NULL(3)
|
||||||
|
exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} // NOLINT(bugprone-throw-keyword-missing)
|
||||||
|
|
||||||
|
static std::string name(const std::string& ename, int id_)
|
||||||
|
{
|
||||||
|
return concat("[json.exception.", ename, '.', std::to_string(id_), "] ");
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string diagnostics(std::nullptr_t /*leaf_element*/)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
static std::string diagnostics(const BasicJsonType* leaf_element)
|
||||||
|
{
|
||||||
|
#if JSON_DIAGNOSTICS
|
||||||
|
std::vector<std::string> tokens;
|
||||||
|
for (const auto* current = leaf_element; current != nullptr && current->m_parent != nullptr; current = current->m_parent)
|
||||||
|
{
|
||||||
|
switch (current->m_parent->type())
|
||||||
|
{
|
||||||
|
case value_t::array:
|
||||||
|
{
|
||||||
|
for (std::size_t i = 0; i < current->m_parent->m_data.m_value.array->size(); ++i)
|
||||||
|
{
|
||||||
|
if (¤t->m_parent->m_data.m_value.array->operator[](i) == current)
|
||||||
|
{
|
||||||
|
tokens.emplace_back(std::to_string(i));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::object:
|
||||||
|
{
|
||||||
|
for (const auto& element : *current->m_parent->m_data.m_value.object)
|
||||||
|
{
|
||||||
|
if (&element.second == current)
|
||||||
|
{
|
||||||
|
tokens.emplace_back(element.first.c_str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::null: // LCOV_EXCL_LINE
|
||||||
|
case value_t::string: // LCOV_EXCL_LINE
|
||||||
|
case value_t::boolean: // LCOV_EXCL_LINE
|
||||||
|
case value_t::number_integer: // LCOV_EXCL_LINE
|
||||||
|
case value_t::number_unsigned: // LCOV_EXCL_LINE
|
||||||
|
case value_t::number_float: // LCOV_EXCL_LINE
|
||||||
|
case value_t::binary: // LCOV_EXCL_LINE
|
||||||
|
case value_t::discarded: // LCOV_EXCL_LINE
|
||||||
|
default: // LCOV_EXCL_LINE
|
||||||
|
break; // LCOV_EXCL_LINE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tokens.empty())
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto str = std::accumulate(tokens.rbegin(), tokens.rend(), std::string{},
|
||||||
|
[](const std::string & a, const std::string & b)
|
||||||
|
{
|
||||||
|
return concat(a, '/', detail::escape(b));
|
||||||
|
});
|
||||||
|
return concat('(', str, ") ");
|
||||||
|
#else
|
||||||
|
static_cast<void>(leaf_element);
|
||||||
|
return "";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// an exception object as storage for error messages
|
||||||
|
std::runtime_error m;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief exception indicating a parse error
|
||||||
|
/// @sa https://json.nlohmann.me/api/basic_json/parse_error/
|
||||||
|
class parse_error : public exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
@brief create a parse error exception
|
||||||
|
@param[in] id_ the id of the exception
|
||||||
|
@param[in] pos the position where the error occurred (or with
|
||||||
|
chars_read_total=0 if the position cannot be
|
||||||
|
determined)
|
||||||
|
@param[in] what_arg the explanatory string
|
||||||
|
@return parse_error object
|
||||||
|
*/
|
||||||
|
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
|
||||||
|
static parse_error create(int id_, const position_t& pos, const std::string& what_arg, BasicJsonContext context)
|
||||||
|
{
|
||||||
|
const std::string w = concat(exception::name("parse_error", id_), "parse error",
|
||||||
|
position_string(pos), ": ", exception::diagnostics(context), what_arg);
|
||||||
|
return {id_, pos.chars_read_total, w.c_str()};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
|
||||||
|
static parse_error create(int id_, std::size_t byte_, const std::string& what_arg, BasicJsonContext context)
|
||||||
|
{
|
||||||
|
const std::string w = concat(exception::name("parse_error", id_), "parse error",
|
||||||
|
(byte_ != 0 ? (concat(" at byte ", std::to_string(byte_))) : ""),
|
||||||
|
": ", exception::diagnostics(context), what_arg);
|
||||||
|
return {id_, byte_, w.c_str()};
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief byte index of the parse error
|
||||||
|
|
||||||
|
The byte index of the last read character in the input file.
|
||||||
|
|
||||||
|
@note For an input with n bytes, 1 is the index of the first character and
|
||||||
|
n+1 is the index of the terminating null byte or the end of file.
|
||||||
|
This also holds true when reading a byte vector (CBOR or MessagePack).
|
||||||
|
*/
|
||||||
|
const std::size_t byte;
|
||||||
|
|
||||||
|
private:
|
||||||
|
parse_error(int id_, std::size_t byte_, const char* what_arg)
|
||||||
|
: exception(id_, what_arg), byte(byte_) {}
|
||||||
|
|
||||||
|
static std::string position_string(const position_t& pos)
|
||||||
|
{
|
||||||
|
return concat(" at line ", std::to_string(pos.lines_read + 1),
|
||||||
|
", column ", std::to_string(pos.chars_read_current_line));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief exception indicating errors with iterators
|
||||||
|
/// @sa https://json.nlohmann.me/api/basic_json/invalid_iterator/
|
||||||
|
class invalid_iterator : public exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
|
||||||
|
static invalid_iterator create(int id_, const std::string& what_arg, BasicJsonContext context)
|
||||||
|
{
|
||||||
|
const std::string w = concat(exception::name("invalid_iterator", id_), exception::diagnostics(context), what_arg);
|
||||||
|
return {id_, w.c_str()};
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
JSON_HEDLEY_NON_NULL(3)
|
||||||
|
invalid_iterator(int id_, const char* what_arg)
|
||||||
|
: exception(id_, what_arg) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief exception indicating executing a member function with a wrong type
|
||||||
|
/// @sa https://json.nlohmann.me/api/basic_json/type_error/
|
||||||
|
class type_error : public exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
|
||||||
|
static type_error create(int id_, const std::string& what_arg, BasicJsonContext context)
|
||||||
|
{
|
||||||
|
const std::string w = concat(exception::name("type_error", id_), exception::diagnostics(context), what_arg);
|
||||||
|
return {id_, w.c_str()};
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
JSON_HEDLEY_NON_NULL(3)
|
||||||
|
type_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief exception indicating access out of the defined range
|
||||||
|
/// @sa https://json.nlohmann.me/api/basic_json/out_of_range/
|
||||||
|
class out_of_range : public exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
|
||||||
|
static out_of_range create(int id_, const std::string& what_arg, BasicJsonContext context)
|
||||||
|
{
|
||||||
|
const std::string w = concat(exception::name("out_of_range", id_), exception::diagnostics(context), what_arg);
|
||||||
|
return {id_, w.c_str()};
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
JSON_HEDLEY_NON_NULL(3)
|
||||||
|
out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief exception indicating other library errors
|
||||||
|
/// @sa https://json.nlohmann.me/api/basic_json/other_error/
|
||||||
|
class other_error : public exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
|
||||||
|
static other_error create(int id_, const std::string& what_arg, BasicJsonContext context)
|
||||||
|
{
|
||||||
|
const std::string w = concat(exception::name("other_error", id_), exception::diagnostics(context), what_arg);
|
||||||
|
return {id_, w.c_str()};
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
JSON_HEDLEY_NON_NULL(3)
|
||||||
|
other_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,129 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint> // uint8_t
|
||||||
|
#include <cstddef> // size_t
|
||||||
|
#include <functional> // hash
|
||||||
|
|
||||||
|
#include <nlohmann/detail/abi_macros.hpp>
|
||||||
|
#include <nlohmann/detail/value_t.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
// boost::hash_combine
|
||||||
|
inline std::size_t combine(std::size_t seed, std::size_t h) noexcept
|
||||||
|
{
|
||||||
|
seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U);
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief hash a JSON value
|
||||||
|
|
||||||
|
The hash function tries to rely on std::hash where possible. Furthermore, the
|
||||||
|
type of the JSON value is taken into account to have different hash values for
|
||||||
|
null, 0, 0U, and false, etc.
|
||||||
|
|
||||||
|
@tparam BasicJsonType basic_json specialization
|
||||||
|
@param j JSON value to hash
|
||||||
|
@return hash value of j
|
||||||
|
*/
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
std::size_t hash(const BasicJsonType& j)
|
||||||
|
{
|
||||||
|
using string_t = typename BasicJsonType::string_t;
|
||||||
|
using number_integer_t = typename BasicJsonType::number_integer_t;
|
||||||
|
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
||||||
|
using number_float_t = typename BasicJsonType::number_float_t;
|
||||||
|
|
||||||
|
const auto type = static_cast<std::size_t>(j.type());
|
||||||
|
switch (j.type())
|
||||||
|
{
|
||||||
|
case BasicJsonType::value_t::null:
|
||||||
|
case BasicJsonType::value_t::discarded:
|
||||||
|
{
|
||||||
|
return combine(type, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
case BasicJsonType::value_t::object:
|
||||||
|
{
|
||||||
|
auto seed = combine(type, j.size());
|
||||||
|
for (const auto& element : j.items())
|
||||||
|
{
|
||||||
|
const auto h = std::hash<string_t> {}(element.key());
|
||||||
|
seed = combine(seed, h);
|
||||||
|
seed = combine(seed, hash(element.value()));
|
||||||
|
}
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
case BasicJsonType::value_t::array:
|
||||||
|
{
|
||||||
|
auto seed = combine(type, j.size());
|
||||||
|
for (const auto& element : j)
|
||||||
|
{
|
||||||
|
seed = combine(seed, hash(element));
|
||||||
|
}
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
case BasicJsonType::value_t::string:
|
||||||
|
{
|
||||||
|
const auto h = std::hash<string_t> {}(j.template get_ref<const string_t&>());
|
||||||
|
return combine(type, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
case BasicJsonType::value_t::boolean:
|
||||||
|
{
|
||||||
|
const auto h = std::hash<bool> {}(j.template get<bool>());
|
||||||
|
return combine(type, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
case BasicJsonType::value_t::number_integer:
|
||||||
|
{
|
||||||
|
const auto h = std::hash<number_integer_t> {}(j.template get<number_integer_t>());
|
||||||
|
return combine(type, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
case BasicJsonType::value_t::number_unsigned:
|
||||||
|
{
|
||||||
|
const auto h = std::hash<number_unsigned_t> {}(j.template get<number_unsigned_t>());
|
||||||
|
return combine(type, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
case BasicJsonType::value_t::number_float:
|
||||||
|
{
|
||||||
|
const auto h = std::hash<number_float_t> {}(j.template get<number_float_t>());
|
||||||
|
return combine(type, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
case BasicJsonType::value_t::binary:
|
||||||
|
{
|
||||||
|
auto seed = combine(type, j.get_binary().size());
|
||||||
|
const auto h = std::hash<bool> {}(j.get_binary().has_subtype());
|
||||||
|
seed = combine(seed, h);
|
||||||
|
seed = combine(seed, static_cast<std::size_t>(j.get_binary().subtype()));
|
||||||
|
for (const auto byte : j.get_binary())
|
||||||
|
{
|
||||||
|
seed = combine(seed, std::hash<std::uint8_t> {}(byte));
|
||||||
|
}
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: // LCOV_EXCL_LINE
|
||||||
|
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
|
||||||
|
return 0; // LCOV_EXCL_LINE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,492 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array> // array
|
||||||
|
#include <cstddef> // size_t
|
||||||
|
#include <cstring> // strlen
|
||||||
|
#include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next
|
||||||
|
#include <memory> // shared_ptr, make_shared, addressof
|
||||||
|
#include <numeric> // accumulate
|
||||||
|
#include <string> // string, char_traits
|
||||||
|
#include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer
|
||||||
|
#include <utility> // pair, declval
|
||||||
|
|
||||||
|
#ifndef JSON_NO_IO
|
||||||
|
#include <cstdio> // FILE *
|
||||||
|
#include <istream> // istream
|
||||||
|
#endif // JSON_NO_IO
|
||||||
|
|
||||||
|
#include <nlohmann/detail/iterators/iterator_traits.hpp>
|
||||||
|
#include <nlohmann/detail/macro_scope.hpp>
|
||||||
|
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
/// the supported input formats
|
||||||
|
enum class input_format_t { json, cbor, msgpack, ubjson, bson, bjdata };
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
// input adapters //
|
||||||
|
////////////////////
|
||||||
|
|
||||||
|
#ifndef JSON_NO_IO
|
||||||
|
/*!
|
||||||
|
Input adapter for stdio file access. This adapter read only 1 byte and do not use any
|
||||||
|
buffer. This adapter is a very low level adapter.
|
||||||
|
*/
|
||||||
|
class file_input_adapter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using char_type = char;
|
||||||
|
|
||||||
|
JSON_HEDLEY_NON_NULL(2)
|
||||||
|
explicit file_input_adapter(std::FILE* f) noexcept
|
||||||
|
: m_file(f)
|
||||||
|
{
|
||||||
|
JSON_ASSERT(m_file != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// make class move-only
|
||||||
|
file_input_adapter(const file_input_adapter&) = delete;
|
||||||
|
file_input_adapter(file_input_adapter&&) noexcept = default;
|
||||||
|
file_input_adapter& operator=(const file_input_adapter&) = delete;
|
||||||
|
file_input_adapter& operator=(file_input_adapter&&) = delete;
|
||||||
|
~file_input_adapter() = default;
|
||||||
|
|
||||||
|
std::char_traits<char>::int_type get_character() noexcept
|
||||||
|
{
|
||||||
|
return std::fgetc(m_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// the file pointer to read from
|
||||||
|
std::FILE* m_file;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at
|
||||||
|
beginning of input. Does not support changing the underlying std::streambuf
|
||||||
|
in mid-input. Maintains underlying std::istream and std::streambuf to support
|
||||||
|
subsequent use of standard std::istream operations to process any input
|
||||||
|
characters following those used in parsing the JSON input. Clears the
|
||||||
|
std::istream flags; any input errors (e.g., EOF) will be detected by the first
|
||||||
|
subsequent call for input from the std::istream.
|
||||||
|
*/
|
||||||
|
class input_stream_adapter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using char_type = char;
|
||||||
|
|
||||||
|
~input_stream_adapter()
|
||||||
|
{
|
||||||
|
// clear stream flags; we use underlying streambuf I/O, do not
|
||||||
|
// maintain ifstream flags, except eof
|
||||||
|
if (is != nullptr)
|
||||||
|
{
|
||||||
|
is->clear(is->rdstate() & std::ios::eofbit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit input_stream_adapter(std::istream& i)
|
||||||
|
: is(&i), sb(i.rdbuf())
|
||||||
|
{}
|
||||||
|
|
||||||
|
// delete because of pointer members
|
||||||
|
input_stream_adapter(const input_stream_adapter&) = delete;
|
||||||
|
input_stream_adapter& operator=(input_stream_adapter&) = delete;
|
||||||
|
input_stream_adapter& operator=(input_stream_adapter&&) = delete;
|
||||||
|
|
||||||
|
input_stream_adapter(input_stream_adapter&& rhs) noexcept
|
||||||
|
: is(rhs.is), sb(rhs.sb)
|
||||||
|
{
|
||||||
|
rhs.is = nullptr;
|
||||||
|
rhs.sb = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::istream/std::streambuf use std::char_traits<char>::to_int_type, to
|
||||||
|
// ensure that std::char_traits<char>::eof() and the character 0xFF do not
|
||||||
|
// end up as the same value, e.g. 0xFFFFFFFF.
|
||||||
|
std::char_traits<char>::int_type get_character()
|
||||||
|
{
|
||||||
|
auto res = sb->sbumpc();
|
||||||
|
// set eof manually, as we don't use the istream interface.
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(res == std::char_traits<char>::eof()))
|
||||||
|
{
|
||||||
|
is->clear(is->rdstate() | std::ios::eofbit);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// the associated input stream
|
||||||
|
std::istream* is = nullptr;
|
||||||
|
std::streambuf* sb = nullptr;
|
||||||
|
};
|
||||||
|
#endif // JSON_NO_IO
|
||||||
|
|
||||||
|
// General-purpose iterator-based adapter. It might not be as fast as
|
||||||
|
// theoretically possible for some containers, but it is extremely versatile.
|
||||||
|
template<typename IteratorType>
|
||||||
|
class iterator_input_adapter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using char_type = typename std::iterator_traits<IteratorType>::value_type;
|
||||||
|
|
||||||
|
iterator_input_adapter(IteratorType first, IteratorType last)
|
||||||
|
: current(std::move(first)), end(std::move(last))
|
||||||
|
{}
|
||||||
|
|
||||||
|
typename char_traits<char_type>::int_type get_character()
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_LIKELY(current != end))
|
||||||
|
{
|
||||||
|
auto result = char_traits<char_type>::to_int_type(*current);
|
||||||
|
std::advance(current, 1);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return char_traits<char_type>::eof();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
IteratorType current;
|
||||||
|
IteratorType end;
|
||||||
|
|
||||||
|
template<typename BaseInputAdapter, size_t T>
|
||||||
|
friend struct wide_string_input_helper;
|
||||||
|
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return current == end;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename BaseInputAdapter, size_t T>
|
||||||
|
struct wide_string_input_helper;
|
||||||
|
|
||||||
|
template<typename BaseInputAdapter>
|
||||||
|
struct wide_string_input_helper<BaseInputAdapter, 4>
|
||||||
|
{
|
||||||
|
// UTF-32
|
||||||
|
static void fill_buffer(BaseInputAdapter& input,
|
||||||
|
std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,
|
||||||
|
size_t& utf8_bytes_index,
|
||||||
|
size_t& utf8_bytes_filled)
|
||||||
|
{
|
||||||
|
utf8_bytes_index = 0;
|
||||||
|
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(input.empty()))
|
||||||
|
{
|
||||||
|
utf8_bytes[0] = std::char_traits<char>::eof();
|
||||||
|
utf8_bytes_filled = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// get the current character
|
||||||
|
const auto wc = input.get_character();
|
||||||
|
|
||||||
|
// UTF-32 to UTF-8 encoding
|
||||||
|
if (wc < 0x80)
|
||||||
|
{
|
||||||
|
utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
|
||||||
|
utf8_bytes_filled = 1;
|
||||||
|
}
|
||||||
|
else if (wc <= 0x7FF)
|
||||||
|
{
|
||||||
|
utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((static_cast<unsigned int>(wc) >> 6u) & 0x1Fu));
|
||||||
|
utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
|
||||||
|
utf8_bytes_filled = 2;
|
||||||
|
}
|
||||||
|
else if (wc <= 0xFFFF)
|
||||||
|
{
|
||||||
|
utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u) & 0x0Fu));
|
||||||
|
utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));
|
||||||
|
utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
|
||||||
|
utf8_bytes_filled = 3;
|
||||||
|
}
|
||||||
|
else if (wc <= 0x10FFFF)
|
||||||
|
{
|
||||||
|
utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | ((static_cast<unsigned int>(wc) >> 18u) & 0x07u));
|
||||||
|
utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 12u) & 0x3Fu));
|
||||||
|
utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));
|
||||||
|
utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
|
||||||
|
utf8_bytes_filled = 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// unknown character
|
||||||
|
utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
|
||||||
|
utf8_bytes_filled = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename BaseInputAdapter>
|
||||||
|
struct wide_string_input_helper<BaseInputAdapter, 2>
|
||||||
|
{
|
||||||
|
// UTF-16
|
||||||
|
static void fill_buffer(BaseInputAdapter& input,
|
||||||
|
std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,
|
||||||
|
size_t& utf8_bytes_index,
|
||||||
|
size_t& utf8_bytes_filled)
|
||||||
|
{
|
||||||
|
utf8_bytes_index = 0;
|
||||||
|
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(input.empty()))
|
||||||
|
{
|
||||||
|
utf8_bytes[0] = std::char_traits<char>::eof();
|
||||||
|
utf8_bytes_filled = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// get the current character
|
||||||
|
const auto wc = input.get_character();
|
||||||
|
|
||||||
|
// UTF-16 to UTF-8 encoding
|
||||||
|
if (wc < 0x80)
|
||||||
|
{
|
||||||
|
utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
|
||||||
|
utf8_bytes_filled = 1;
|
||||||
|
}
|
||||||
|
else if (wc <= 0x7FF)
|
||||||
|
{
|
||||||
|
utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((static_cast<unsigned int>(wc) >> 6u)));
|
||||||
|
utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
|
||||||
|
utf8_bytes_filled = 2;
|
||||||
|
}
|
||||||
|
else if (0xD800 > wc || wc >= 0xE000)
|
||||||
|
{
|
||||||
|
utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u)));
|
||||||
|
utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));
|
||||||
|
utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
|
||||||
|
utf8_bytes_filled = 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!input.empty()))
|
||||||
|
{
|
||||||
|
const auto wc2 = static_cast<unsigned int>(input.get_character());
|
||||||
|
const auto charcode = 0x10000u + (((static_cast<unsigned int>(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu));
|
||||||
|
utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | (charcode >> 18u));
|
||||||
|
utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu));
|
||||||
|
utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu));
|
||||||
|
utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (charcode & 0x3Fu));
|
||||||
|
utf8_bytes_filled = 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
|
||||||
|
utf8_bytes_filled = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Wraps another input adapter to convert wide character types into individual bytes.
|
||||||
|
template<typename BaseInputAdapter, typename WideCharType>
|
||||||
|
class wide_string_input_adapter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using char_type = char;
|
||||||
|
|
||||||
|
wide_string_input_adapter(BaseInputAdapter base)
|
||||||
|
: base_adapter(base) {}
|
||||||
|
|
||||||
|
typename std::char_traits<char>::int_type get_character() noexcept
|
||||||
|
{
|
||||||
|
// check if buffer needs to be filled
|
||||||
|
if (utf8_bytes_index == utf8_bytes_filled)
|
||||||
|
{
|
||||||
|
fill_buffer<sizeof(WideCharType)>();
|
||||||
|
|
||||||
|
JSON_ASSERT(utf8_bytes_filled > 0);
|
||||||
|
JSON_ASSERT(utf8_bytes_index == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// use buffer
|
||||||
|
JSON_ASSERT(utf8_bytes_filled > 0);
|
||||||
|
JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled);
|
||||||
|
return utf8_bytes[utf8_bytes_index++];
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BaseInputAdapter base_adapter;
|
||||||
|
|
||||||
|
template<size_t T>
|
||||||
|
void fill_buffer()
|
||||||
|
{
|
||||||
|
wide_string_input_helper<BaseInputAdapter, T>::fill_buffer(base_adapter, utf8_bytes, utf8_bytes_index, utf8_bytes_filled);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// a buffer for UTF-8 bytes
|
||||||
|
std::array<std::char_traits<char>::int_type, 4> utf8_bytes = {{0, 0, 0, 0}};
|
||||||
|
|
||||||
|
/// index to the utf8_codes array for the next valid byte
|
||||||
|
std::size_t utf8_bytes_index = 0;
|
||||||
|
/// number of valid bytes in the utf8_codes array
|
||||||
|
std::size_t utf8_bytes_filled = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename IteratorType, typename Enable = void>
|
||||||
|
struct iterator_input_adapter_factory
|
||||||
|
{
|
||||||
|
using iterator_type = IteratorType;
|
||||||
|
using char_type = typename std::iterator_traits<iterator_type>::value_type;
|
||||||
|
using adapter_type = iterator_input_adapter<iterator_type>;
|
||||||
|
|
||||||
|
static adapter_type create(IteratorType first, IteratorType last)
|
||||||
|
{
|
||||||
|
return adapter_type(std::move(first), std::move(last));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct is_iterator_of_multibyte
|
||||||
|
{
|
||||||
|
using value_type = typename std::iterator_traits<T>::value_type;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
value = sizeof(value_type) > 1
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename IteratorType>
|
||||||
|
struct iterator_input_adapter_factory<IteratorType, enable_if_t<is_iterator_of_multibyte<IteratorType>::value>>
|
||||||
|
{
|
||||||
|
using iterator_type = IteratorType;
|
||||||
|
using char_type = typename std::iterator_traits<iterator_type>::value_type;
|
||||||
|
using base_adapter_type = iterator_input_adapter<iterator_type>;
|
||||||
|
using adapter_type = wide_string_input_adapter<base_adapter_type, char_type>;
|
||||||
|
|
||||||
|
static adapter_type create(IteratorType first, IteratorType last)
|
||||||
|
{
|
||||||
|
return adapter_type(base_adapter_type(std::move(first), std::move(last)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// General purpose iterator-based input
|
||||||
|
template<typename IteratorType>
|
||||||
|
typename iterator_input_adapter_factory<IteratorType>::adapter_type input_adapter(IteratorType first, IteratorType last)
|
||||||
|
{
|
||||||
|
using factory_type = iterator_input_adapter_factory<IteratorType>;
|
||||||
|
return factory_type::create(first, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convenience shorthand from container to iterator
|
||||||
|
// Enables ADL on begin(container) and end(container)
|
||||||
|
// Encloses the using declarations in namespace for not to leak them to outside scope
|
||||||
|
|
||||||
|
namespace container_input_adapter_factory_impl
|
||||||
|
{
|
||||||
|
|
||||||
|
using std::begin;
|
||||||
|
using std::end;
|
||||||
|
|
||||||
|
template<typename ContainerType, typename Enable = void>
|
||||||
|
struct container_input_adapter_factory {};
|
||||||
|
|
||||||
|
template<typename ContainerType>
|
||||||
|
struct container_input_adapter_factory< ContainerType,
|
||||||
|
void_t<decltype(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>()))>>
|
||||||
|
{
|
||||||
|
using adapter_type = decltype(input_adapter(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>())));
|
||||||
|
|
||||||
|
static adapter_type create(const ContainerType& container)
|
||||||
|
{
|
||||||
|
return input_adapter(begin(container), end(container));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace container_input_adapter_factory_impl
|
||||||
|
|
||||||
|
template<typename ContainerType>
|
||||||
|
typename container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::adapter_type input_adapter(const ContainerType& container)
|
||||||
|
{
|
||||||
|
return container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::create(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef JSON_NO_IO
|
||||||
|
// Special cases with fast paths
|
||||||
|
inline file_input_adapter input_adapter(std::FILE* file)
|
||||||
|
{
|
||||||
|
return file_input_adapter(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline input_stream_adapter input_adapter(std::istream& stream)
|
||||||
|
{
|
||||||
|
return input_stream_adapter(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline input_stream_adapter input_adapter(std::istream&& stream)
|
||||||
|
{
|
||||||
|
return input_stream_adapter(stream);
|
||||||
|
}
|
||||||
|
#endif // JSON_NO_IO
|
||||||
|
|
||||||
|
using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval<const char*>(), std::declval<const char*>()));
|
||||||
|
|
||||||
|
// Null-delimited strings, and the like.
|
||||||
|
template < typename CharT,
|
||||||
|
typename std::enable_if <
|
||||||
|
std::is_pointer<CharT>::value&&
|
||||||
|
!std::is_array<CharT>::value&&
|
||||||
|
std::is_integral<typename std::remove_pointer<CharT>::type>::value&&
|
||||||
|
sizeof(typename std::remove_pointer<CharT>::type) == 1,
|
||||||
|
int >::type = 0 >
|
||||||
|
contiguous_bytes_input_adapter input_adapter(CharT b)
|
||||||
|
{
|
||||||
|
auto length = std::strlen(reinterpret_cast<const char*>(b));
|
||||||
|
const auto* ptr = reinterpret_cast<const char*>(b);
|
||||||
|
return input_adapter(ptr, ptr + length);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, std::size_t N>
|
||||||
|
auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||||
|
{
|
||||||
|
return input_adapter(array, array + N);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This class only handles inputs of input_buffer_adapter type.
|
||||||
|
// It's required so that expressions like {ptr, len} can be implicitly cast
|
||||||
|
// to the correct adapter.
|
||||||
|
class span_input_adapter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template < typename CharT,
|
||||||
|
typename std::enable_if <
|
||||||
|
std::is_pointer<CharT>::value&&
|
||||||
|
std::is_integral<typename std::remove_pointer<CharT>::type>::value&&
|
||||||
|
sizeof(typename std::remove_pointer<CharT>::type) == 1,
|
||||||
|
int >::type = 0 >
|
||||||
|
span_input_adapter(CharT b, std::size_t l)
|
||||||
|
: ia(reinterpret_cast<const char*>(b), reinterpret_cast<const char*>(b) + l) {}
|
||||||
|
|
||||||
|
template<class IteratorType,
|
||||||
|
typename std::enable_if<
|
||||||
|
std::is_same<typename iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value,
|
||||||
|
int>::type = 0>
|
||||||
|
span_input_adapter(IteratorType first, IteratorType last)
|
||||||
|
: ia(input_adapter(first, last)) {}
|
||||||
|
|
||||||
|
contiguous_bytes_input_adapter&& get()
|
||||||
|
{
|
||||||
|
return std::move(ia); // NOLINT(hicpp-move-const-arg,performance-move-const-arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
contiguous_bytes_input_adapter ia;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,727 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <string> // string
|
||||||
|
#include <utility> // move
|
||||||
|
#include <vector> // vector
|
||||||
|
|
||||||
|
#include <nlohmann/detail/exceptions.hpp>
|
||||||
|
#include <nlohmann/detail/macro_scope.hpp>
|
||||||
|
#include <nlohmann/detail/string_concat.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief SAX interface
|
||||||
|
|
||||||
|
This class describes the SAX interface used by @ref nlohmann::json::sax_parse.
|
||||||
|
Each function is called in different situations while the input is parsed. The
|
||||||
|
boolean return value informs the parser whether to continue processing the
|
||||||
|
input.
|
||||||
|
*/
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
struct json_sax
|
||||||
|
{
|
||||||
|
using number_integer_t = typename BasicJsonType::number_integer_t;
|
||||||
|
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
||||||
|
using number_float_t = typename BasicJsonType::number_float_t;
|
||||||
|
using string_t = typename BasicJsonType::string_t;
|
||||||
|
using binary_t = typename BasicJsonType::binary_t;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief a null value was read
|
||||||
|
@return whether parsing should proceed
|
||||||
|
*/
|
||||||
|
virtual bool null() = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief a boolean value was read
|
||||||
|
@param[in] val boolean value
|
||||||
|
@return whether parsing should proceed
|
||||||
|
*/
|
||||||
|
virtual bool boolean(bool val) = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief an integer number was read
|
||||||
|
@param[in] val integer value
|
||||||
|
@return whether parsing should proceed
|
||||||
|
*/
|
||||||
|
virtual bool number_integer(number_integer_t val) = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief an unsigned integer number was read
|
||||||
|
@param[in] val unsigned integer value
|
||||||
|
@return whether parsing should proceed
|
||||||
|
*/
|
||||||
|
virtual bool number_unsigned(number_unsigned_t val) = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief a floating-point number was read
|
||||||
|
@param[in] val floating-point value
|
||||||
|
@param[in] s raw token value
|
||||||
|
@return whether parsing should proceed
|
||||||
|
*/
|
||||||
|
virtual bool number_float(number_float_t val, const string_t& s) = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief a string value was read
|
||||||
|
@param[in] val string value
|
||||||
|
@return whether parsing should proceed
|
||||||
|
@note It is safe to move the passed string value.
|
||||||
|
*/
|
||||||
|
virtual bool string(string_t& val) = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief a binary value was read
|
||||||
|
@param[in] val binary value
|
||||||
|
@return whether parsing should proceed
|
||||||
|
@note It is safe to move the passed binary value.
|
||||||
|
*/
|
||||||
|
virtual bool binary(binary_t& val) = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief the beginning of an object was read
|
||||||
|
@param[in] elements number of object elements or -1 if unknown
|
||||||
|
@return whether parsing should proceed
|
||||||
|
@note binary formats may report the number of elements
|
||||||
|
*/
|
||||||
|
virtual bool start_object(std::size_t elements) = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief an object key was read
|
||||||
|
@param[in] val object key
|
||||||
|
@return whether parsing should proceed
|
||||||
|
@note It is safe to move the passed string.
|
||||||
|
*/
|
||||||
|
virtual bool key(string_t& val) = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief the end of an object was read
|
||||||
|
@return whether parsing should proceed
|
||||||
|
*/
|
||||||
|
virtual bool end_object() = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief the beginning of an array was read
|
||||||
|
@param[in] elements number of array elements or -1 if unknown
|
||||||
|
@return whether parsing should proceed
|
||||||
|
@note binary formats may report the number of elements
|
||||||
|
*/
|
||||||
|
virtual bool start_array(std::size_t elements) = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief the end of an array was read
|
||||||
|
@return whether parsing should proceed
|
||||||
|
*/
|
||||||
|
virtual bool end_array() = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief a parse error occurred
|
||||||
|
@param[in] position the position in the input where the error occurs
|
||||||
|
@param[in] last_token the last read token
|
||||||
|
@param[in] ex an exception object describing the error
|
||||||
|
@return whether parsing should proceed (must return false)
|
||||||
|
*/
|
||||||
|
virtual bool parse_error(std::size_t position,
|
||||||
|
const std::string& last_token,
|
||||||
|
const detail::exception& ex) = 0;
|
||||||
|
|
||||||
|
json_sax() = default;
|
||||||
|
json_sax(const json_sax&) = default;
|
||||||
|
json_sax(json_sax&&) noexcept = default;
|
||||||
|
json_sax& operator=(const json_sax&) = default;
|
||||||
|
json_sax& operator=(json_sax&&) noexcept = default;
|
||||||
|
virtual ~json_sax() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
/*!
|
||||||
|
@brief SAX implementation to create a JSON value from SAX events
|
||||||
|
|
||||||
|
This class implements the @ref json_sax interface and processes the SAX events
|
||||||
|
to create a JSON value which makes it basically a DOM parser. The structure or
|
||||||
|
hierarchy of the JSON value is managed by the stack `ref_stack` which contains
|
||||||
|
a pointer to the respective array or object for each recursion depth.
|
||||||
|
|
||||||
|
After successful parsing, the value that is passed by reference to the
|
||||||
|
constructor contains the parsed value.
|
||||||
|
|
||||||
|
@tparam BasicJsonType the JSON type
|
||||||
|
*/
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
class json_sax_dom_parser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using number_integer_t = typename BasicJsonType::number_integer_t;
|
||||||
|
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
||||||
|
using number_float_t = typename BasicJsonType::number_float_t;
|
||||||
|
using string_t = typename BasicJsonType::string_t;
|
||||||
|
using binary_t = typename BasicJsonType::binary_t;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@param[in,out] r reference to a JSON value that is manipulated while
|
||||||
|
parsing
|
||||||
|
@param[in] allow_exceptions_ whether parse errors yield exceptions
|
||||||
|
*/
|
||||||
|
explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true)
|
||||||
|
: root(r), allow_exceptions(allow_exceptions_)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// make class move-only
|
||||||
|
json_sax_dom_parser(const json_sax_dom_parser&) = delete;
|
||||||
|
json_sax_dom_parser(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
|
||||||
|
json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete;
|
||||||
|
json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
|
||||||
|
~json_sax_dom_parser() = default;
|
||||||
|
|
||||||
|
bool null()
|
||||||
|
{
|
||||||
|
handle_value(nullptr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool boolean(bool val)
|
||||||
|
{
|
||||||
|
handle_value(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_integer(number_integer_t val)
|
||||||
|
{
|
||||||
|
handle_value(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_unsigned(number_unsigned_t val)
|
||||||
|
{
|
||||||
|
handle_value(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_float(number_float_t val, const string_t& /*unused*/)
|
||||||
|
{
|
||||||
|
handle_value(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool string(string_t& val)
|
||||||
|
{
|
||||||
|
handle_value(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool binary(binary_t& val)
|
||||||
|
{
|
||||||
|
handle_value(std::move(val));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool start_object(std::size_t len)
|
||||||
|
{
|
||||||
|
ref_stack.push_back(handle_value(BasicJsonType::value_t::object));
|
||||||
|
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
|
||||||
|
{
|
||||||
|
JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool key(string_t& val)
|
||||||
|
{
|
||||||
|
JSON_ASSERT(!ref_stack.empty());
|
||||||
|
JSON_ASSERT(ref_stack.back()->is_object());
|
||||||
|
|
||||||
|
// add null at given key and store the reference for later
|
||||||
|
object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool end_object()
|
||||||
|
{
|
||||||
|
JSON_ASSERT(!ref_stack.empty());
|
||||||
|
JSON_ASSERT(ref_stack.back()->is_object());
|
||||||
|
|
||||||
|
ref_stack.back()->set_parents();
|
||||||
|
ref_stack.pop_back();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool start_array(std::size_t len)
|
||||||
|
{
|
||||||
|
ref_stack.push_back(handle_value(BasicJsonType::value_t::array));
|
||||||
|
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
|
||||||
|
{
|
||||||
|
JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool end_array()
|
||||||
|
{
|
||||||
|
JSON_ASSERT(!ref_stack.empty());
|
||||||
|
JSON_ASSERT(ref_stack.back()->is_array());
|
||||||
|
|
||||||
|
ref_stack.back()->set_parents();
|
||||||
|
ref_stack.pop_back();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Exception>
|
||||||
|
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
|
||||||
|
const Exception& ex)
|
||||||
|
{
|
||||||
|
errored = true;
|
||||||
|
static_cast<void>(ex);
|
||||||
|
if (allow_exceptions)
|
||||||
|
{
|
||||||
|
JSON_THROW(ex);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool is_errored() const
|
||||||
|
{
|
||||||
|
return errored;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*!
|
||||||
|
@invariant If the ref stack is empty, then the passed value will be the new
|
||||||
|
root.
|
||||||
|
@invariant If the ref stack contains a value, then it is an array or an
|
||||||
|
object to which we can add elements
|
||||||
|
*/
|
||||||
|
template<typename Value>
|
||||||
|
JSON_HEDLEY_RETURNS_NON_NULL
|
||||||
|
BasicJsonType* handle_value(Value&& v)
|
||||||
|
{
|
||||||
|
if (ref_stack.empty())
|
||||||
|
{
|
||||||
|
root = BasicJsonType(std::forward<Value>(v));
|
||||||
|
return &root;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());
|
||||||
|
|
||||||
|
if (ref_stack.back()->is_array())
|
||||||
|
{
|
||||||
|
ref_stack.back()->m_data.m_value.array->emplace_back(std::forward<Value>(v));
|
||||||
|
return &(ref_stack.back()->m_data.m_value.array->back());
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_ASSERT(ref_stack.back()->is_object());
|
||||||
|
JSON_ASSERT(object_element);
|
||||||
|
*object_element = BasicJsonType(std::forward<Value>(v));
|
||||||
|
return object_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// the parsed JSON value
|
||||||
|
BasicJsonType& root;
|
||||||
|
/// stack to model hierarchy of values
|
||||||
|
std::vector<BasicJsonType*> ref_stack {};
|
||||||
|
/// helper to hold the reference for the next object element
|
||||||
|
BasicJsonType* object_element = nullptr;
|
||||||
|
/// whether a syntax error occurred
|
||||||
|
bool errored = false;
|
||||||
|
/// whether to throw exceptions in case of errors
|
||||||
|
const bool allow_exceptions = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
class json_sax_dom_callback_parser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using number_integer_t = typename BasicJsonType::number_integer_t;
|
||||||
|
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
||||||
|
using number_float_t = typename BasicJsonType::number_float_t;
|
||||||
|
using string_t = typename BasicJsonType::string_t;
|
||||||
|
using binary_t = typename BasicJsonType::binary_t;
|
||||||
|
using parser_callback_t = typename BasicJsonType::parser_callback_t;
|
||||||
|
using parse_event_t = typename BasicJsonType::parse_event_t;
|
||||||
|
|
||||||
|
json_sax_dom_callback_parser(BasicJsonType& r,
|
||||||
|
const parser_callback_t cb,
|
||||||
|
const bool allow_exceptions_ = true)
|
||||||
|
: root(r), callback(cb), allow_exceptions(allow_exceptions_)
|
||||||
|
{
|
||||||
|
keep_stack.push_back(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// make class move-only
|
||||||
|
json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete;
|
||||||
|
json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
|
||||||
|
json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete;
|
||||||
|
json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
|
||||||
|
~json_sax_dom_callback_parser() = default;
|
||||||
|
|
||||||
|
bool null()
|
||||||
|
{
|
||||||
|
handle_value(nullptr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool boolean(bool val)
|
||||||
|
{
|
||||||
|
handle_value(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_integer(number_integer_t val)
|
||||||
|
{
|
||||||
|
handle_value(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_unsigned(number_unsigned_t val)
|
||||||
|
{
|
||||||
|
handle_value(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_float(number_float_t val, const string_t& /*unused*/)
|
||||||
|
{
|
||||||
|
handle_value(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool string(string_t& val)
|
||||||
|
{
|
||||||
|
handle_value(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool binary(binary_t& val)
|
||||||
|
{
|
||||||
|
handle_value(std::move(val));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool start_object(std::size_t len)
|
||||||
|
{
|
||||||
|
// check callback for object start
|
||||||
|
const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::object_start, discarded);
|
||||||
|
keep_stack.push_back(keep);
|
||||||
|
|
||||||
|
auto val = handle_value(BasicJsonType::value_t::object, true);
|
||||||
|
ref_stack.push_back(val.second);
|
||||||
|
|
||||||
|
// check object limit
|
||||||
|
if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
|
||||||
|
{
|
||||||
|
JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool key(string_t& val)
|
||||||
|
{
|
||||||
|
BasicJsonType k = BasicJsonType(val);
|
||||||
|
|
||||||
|
// check callback for key
|
||||||
|
const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::key, k);
|
||||||
|
key_keep_stack.push_back(keep);
|
||||||
|
|
||||||
|
// add discarded value at given key and store the reference for later
|
||||||
|
if (keep && ref_stack.back())
|
||||||
|
{
|
||||||
|
object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val) = discarded);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool end_object()
|
||||||
|
{
|
||||||
|
if (ref_stack.back())
|
||||||
|
{
|
||||||
|
if (!callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))
|
||||||
|
{
|
||||||
|
// discard object
|
||||||
|
*ref_stack.back() = discarded;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ref_stack.back()->set_parents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_ASSERT(!ref_stack.empty());
|
||||||
|
JSON_ASSERT(!keep_stack.empty());
|
||||||
|
ref_stack.pop_back();
|
||||||
|
keep_stack.pop_back();
|
||||||
|
|
||||||
|
if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured())
|
||||||
|
{
|
||||||
|
// remove discarded value
|
||||||
|
for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it)
|
||||||
|
{
|
||||||
|
if (it->is_discarded())
|
||||||
|
{
|
||||||
|
ref_stack.back()->erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool start_array(std::size_t len)
|
||||||
|
{
|
||||||
|
const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::array_start, discarded);
|
||||||
|
keep_stack.push_back(keep);
|
||||||
|
|
||||||
|
auto val = handle_value(BasicJsonType::value_t::array, true);
|
||||||
|
ref_stack.push_back(val.second);
|
||||||
|
|
||||||
|
// check array limit
|
||||||
|
if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
|
||||||
|
{
|
||||||
|
JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool end_array()
|
||||||
|
{
|
||||||
|
bool keep = true;
|
||||||
|
|
||||||
|
if (ref_stack.back())
|
||||||
|
{
|
||||||
|
keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());
|
||||||
|
if (keep)
|
||||||
|
{
|
||||||
|
ref_stack.back()->set_parents();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// discard array
|
||||||
|
*ref_stack.back() = discarded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_ASSERT(!ref_stack.empty());
|
||||||
|
JSON_ASSERT(!keep_stack.empty());
|
||||||
|
ref_stack.pop_back();
|
||||||
|
keep_stack.pop_back();
|
||||||
|
|
||||||
|
// remove discarded value
|
||||||
|
if (!keep && !ref_stack.empty() && ref_stack.back()->is_array())
|
||||||
|
{
|
||||||
|
ref_stack.back()->m_data.m_value.array->pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Exception>
|
||||||
|
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
|
||||||
|
const Exception& ex)
|
||||||
|
{
|
||||||
|
errored = true;
|
||||||
|
static_cast<void>(ex);
|
||||||
|
if (allow_exceptions)
|
||||||
|
{
|
||||||
|
JSON_THROW(ex);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool is_errored() const
|
||||||
|
{
|
||||||
|
return errored;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*!
|
||||||
|
@param[in] v value to add to the JSON value we build during parsing
|
||||||
|
@param[in] skip_callback whether we should skip calling the callback
|
||||||
|
function; this is required after start_array() and
|
||||||
|
start_object() SAX events, because otherwise we would call the
|
||||||
|
callback function with an empty array or object, respectively.
|
||||||
|
|
||||||
|
@invariant If the ref stack is empty, then the passed value will be the new
|
||||||
|
root.
|
||||||
|
@invariant If the ref stack contains a value, then it is an array or an
|
||||||
|
object to which we can add elements
|
||||||
|
|
||||||
|
@return pair of boolean (whether value should be kept) and pointer (to the
|
||||||
|
passed value in the ref_stack hierarchy; nullptr if not kept)
|
||||||
|
*/
|
||||||
|
template<typename Value>
|
||||||
|
std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false)
|
||||||
|
{
|
||||||
|
JSON_ASSERT(!keep_stack.empty());
|
||||||
|
|
||||||
|
// do not handle this value if we know it would be added to a discarded
|
||||||
|
// container
|
||||||
|
if (!keep_stack.back())
|
||||||
|
{
|
||||||
|
return {false, nullptr};
|
||||||
|
}
|
||||||
|
|
||||||
|
// create value
|
||||||
|
auto value = BasicJsonType(std::forward<Value>(v));
|
||||||
|
|
||||||
|
// check callback
|
||||||
|
const bool keep = skip_callback || callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);
|
||||||
|
|
||||||
|
// do not handle this value if we just learnt it shall be discarded
|
||||||
|
if (!keep)
|
||||||
|
{
|
||||||
|
return {false, nullptr};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ref_stack.empty())
|
||||||
|
{
|
||||||
|
root = std::move(value);
|
||||||
|
return {true, & root};
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip this value if we already decided to skip the parent
|
||||||
|
// (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)
|
||||||
|
if (!ref_stack.back())
|
||||||
|
{
|
||||||
|
return {false, nullptr};
|
||||||
|
}
|
||||||
|
|
||||||
|
// we now only expect arrays and objects
|
||||||
|
JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());
|
||||||
|
|
||||||
|
// array
|
||||||
|
if (ref_stack.back()->is_array())
|
||||||
|
{
|
||||||
|
ref_stack.back()->m_data.m_value.array->emplace_back(std::move(value));
|
||||||
|
return {true, & (ref_stack.back()->m_data.m_value.array->back())};
|
||||||
|
}
|
||||||
|
|
||||||
|
// object
|
||||||
|
JSON_ASSERT(ref_stack.back()->is_object());
|
||||||
|
// check if we should store an element for the current key
|
||||||
|
JSON_ASSERT(!key_keep_stack.empty());
|
||||||
|
const bool store_element = key_keep_stack.back();
|
||||||
|
key_keep_stack.pop_back();
|
||||||
|
|
||||||
|
if (!store_element)
|
||||||
|
{
|
||||||
|
return {false, nullptr};
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_ASSERT(object_element);
|
||||||
|
*object_element = std::move(value);
|
||||||
|
return {true, object_element};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// the parsed JSON value
|
||||||
|
BasicJsonType& root;
|
||||||
|
/// stack to model hierarchy of values
|
||||||
|
std::vector<BasicJsonType*> ref_stack {};
|
||||||
|
/// stack to manage which values to keep
|
||||||
|
std::vector<bool> keep_stack {}; // NOLINT(readability-redundant-member-init)
|
||||||
|
/// stack to manage which object keys to keep
|
||||||
|
std::vector<bool> key_keep_stack {}; // NOLINT(readability-redundant-member-init)
|
||||||
|
/// helper to hold the reference for the next object element
|
||||||
|
BasicJsonType* object_element = nullptr;
|
||||||
|
/// whether a syntax error occurred
|
||||||
|
bool errored = false;
|
||||||
|
/// callback function
|
||||||
|
const parser_callback_t callback = nullptr;
|
||||||
|
/// whether to throw exceptions in case of errors
|
||||||
|
const bool allow_exceptions = true;
|
||||||
|
/// a discarded value for the callback
|
||||||
|
BasicJsonType discarded = BasicJsonType::value_t::discarded;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
class json_sax_acceptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using number_integer_t = typename BasicJsonType::number_integer_t;
|
||||||
|
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
||||||
|
using number_float_t = typename BasicJsonType::number_float_t;
|
||||||
|
using string_t = typename BasicJsonType::string_t;
|
||||||
|
using binary_t = typename BasicJsonType::binary_t;
|
||||||
|
|
||||||
|
bool null()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool boolean(bool /*unused*/)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_integer(number_integer_t /*unused*/)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_unsigned(number_unsigned_t /*unused*/)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_float(number_float_t /*unused*/, const string_t& /*unused*/)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool string(string_t& /*unused*/)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool binary(binary_t& /*unused*/)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool start_object(std::size_t /*unused*/ = static_cast<std::size_t>(-1))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool key(string_t& /*unused*/)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool end_object()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool start_array(std::size_t /*unused*/ = static_cast<std::size_t>(-1))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool end_array()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,519 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cmath> // isfinite
|
||||||
|
#include <cstdint> // uint8_t
|
||||||
|
#include <functional> // function
|
||||||
|
#include <string> // string
|
||||||
|
#include <utility> // move
|
||||||
|
#include <vector> // vector
|
||||||
|
|
||||||
|
#include <nlohmann/detail/exceptions.hpp>
|
||||||
|
#include <nlohmann/detail/input/input_adapters.hpp>
|
||||||
|
#include <nlohmann/detail/input/json_sax.hpp>
|
||||||
|
#include <nlohmann/detail/input/lexer.hpp>
|
||||||
|
#include <nlohmann/detail/macro_scope.hpp>
|
||||||
|
#include <nlohmann/detail/meta/is_sax.hpp>
|
||||||
|
#include <nlohmann/detail/string_concat.hpp>
|
||||||
|
#include <nlohmann/detail/value_t.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
////////////
|
||||||
|
// parser //
|
||||||
|
////////////
|
||||||
|
|
||||||
|
enum class parse_event_t : std::uint8_t
|
||||||
|
{
|
||||||
|
/// the parser read `{` and started to process a JSON object
|
||||||
|
object_start,
|
||||||
|
/// the parser read `}` and finished processing a JSON object
|
||||||
|
object_end,
|
||||||
|
/// the parser read `[` and started to process a JSON array
|
||||||
|
array_start,
|
||||||
|
/// the parser read `]` and finished processing a JSON array
|
||||||
|
array_end,
|
||||||
|
/// the parser read a key of a value in an object
|
||||||
|
key,
|
||||||
|
/// the parser finished reading a JSON value
|
||||||
|
value
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
using parser_callback_t =
|
||||||
|
std::function<bool(int /*depth*/, parse_event_t /*event*/, BasicJsonType& /*parsed*/)>;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief syntax analysis
|
||||||
|
|
||||||
|
This class implements a recursive descent parser.
|
||||||
|
*/
|
||||||
|
template<typename BasicJsonType, typename InputAdapterType>
|
||||||
|
class parser
|
||||||
|
{
|
||||||
|
using number_integer_t = typename BasicJsonType::number_integer_t;
|
||||||
|
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
||||||
|
using number_float_t = typename BasicJsonType::number_float_t;
|
||||||
|
using string_t = typename BasicJsonType::string_t;
|
||||||
|
using lexer_t = lexer<BasicJsonType, InputAdapterType>;
|
||||||
|
using token_type = typename lexer_t::token_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// a parser reading from an input adapter
|
||||||
|
explicit parser(InputAdapterType&& adapter,
|
||||||
|
const parser_callback_t<BasicJsonType> cb = nullptr,
|
||||||
|
const bool allow_exceptions_ = true,
|
||||||
|
const bool skip_comments = false)
|
||||||
|
: callback(cb)
|
||||||
|
, m_lexer(std::move(adapter), skip_comments)
|
||||||
|
, allow_exceptions(allow_exceptions_)
|
||||||
|
{
|
||||||
|
// read first token
|
||||||
|
get_token();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief public parser interface
|
||||||
|
|
||||||
|
@param[in] strict whether to expect the last token to be EOF
|
||||||
|
@param[in,out] result parsed JSON value
|
||||||
|
|
||||||
|
@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
|
||||||
|
*/
|
||||||
|
void parse(const bool strict, BasicJsonType& result)
|
||||||
|
{
|
||||||
|
if (callback)
|
||||||
|
{
|
||||||
|
json_sax_dom_callback_parser<BasicJsonType> sdp(result, callback, allow_exceptions);
|
||||||
|
sax_parse_internal(&sdp);
|
||||||
|
|
||||||
|
// in strict mode, input must be completely read
|
||||||
|
if (strict && (get_token() != token_type::end_of_input))
|
||||||
|
{
|
||||||
|
sdp.parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(),
|
||||||
|
exception_message(token_type::end_of_input, "value"), nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// in case of an error, return discarded value
|
||||||
|
if (sdp.is_errored())
|
||||||
|
{
|
||||||
|
result = value_t::discarded;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set top-level value to null if it was discarded by the callback
|
||||||
|
// function
|
||||||
|
if (result.is_discarded())
|
||||||
|
{
|
||||||
|
result = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
json_sax_dom_parser<BasicJsonType> sdp(result, allow_exceptions);
|
||||||
|
sax_parse_internal(&sdp);
|
||||||
|
|
||||||
|
// in strict mode, input must be completely read
|
||||||
|
if (strict && (get_token() != token_type::end_of_input))
|
||||||
|
{
|
||||||
|
sdp.parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// in case of an error, return discarded value
|
||||||
|
if (sdp.is_errored())
|
||||||
|
{
|
||||||
|
result = value_t::discarded;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.assert_invariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief public accept interface
|
||||||
|
|
||||||
|
@param[in] strict whether to expect the last token to be EOF
|
||||||
|
@return whether the input is a proper JSON text
|
||||||
|
*/
|
||||||
|
bool accept(const bool strict = true)
|
||||||
|
{
|
||||||
|
json_sax_acceptor<BasicJsonType> sax_acceptor;
|
||||||
|
return sax_parse(&sax_acceptor, strict);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename SAX>
|
||||||
|
JSON_HEDLEY_NON_NULL(2)
|
||||||
|
bool sax_parse(SAX* sax, const bool strict = true)
|
||||||
|
{
|
||||||
|
(void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};
|
||||||
|
const bool result = sax_parse_internal(sax);
|
||||||
|
|
||||||
|
// strict mode: next byte must be EOF
|
||||||
|
if (result && strict && (get_token() != token_type::end_of_input))
|
||||||
|
{
|
||||||
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename SAX>
|
||||||
|
JSON_HEDLEY_NON_NULL(2)
|
||||||
|
bool sax_parse_internal(SAX* sax)
|
||||||
|
{
|
||||||
|
// stack to remember the hierarchy of structured values we are parsing
|
||||||
|
// true = array; false = object
|
||||||
|
std::vector<bool> states;
|
||||||
|
// value to avoid a goto (see comment where set to true)
|
||||||
|
bool skip_to_state_evaluation = false;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (!skip_to_state_evaluation)
|
||||||
|
{
|
||||||
|
// invariant: get_token() was called before each iteration
|
||||||
|
switch (last_token)
|
||||||
|
{
|
||||||
|
case token_type::begin_object:
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1))))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// closing } -> we are done
|
||||||
|
if (get_token() == token_type::end_object)
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse key
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string))
|
||||||
|
{
|
||||||
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr));
|
||||||
|
}
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse separator (:)
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))
|
||||||
|
{
|
||||||
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// remember we are now inside an object
|
||||||
|
states.push_back(false);
|
||||||
|
|
||||||
|
// parse values
|
||||||
|
get_token();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
case token_type::begin_array:
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1))))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// closing ] -> we are done
|
||||||
|
if (get_token() == token_type::end_array)
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!sax->end_array()))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remember we are now inside an array
|
||||||
|
states.push_back(true);
|
||||||
|
|
||||||
|
// parse values (no need to call get_token)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
case token_type::value_float:
|
||||||
|
{
|
||||||
|
const auto res = m_lexer.get_number_float();
|
||||||
|
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!std::isfinite(res)))
|
||||||
|
{
|
||||||
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
out_of_range::create(406, concat("number overflow parsing '", m_lexer.get_token_string(), '\''), nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string())))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case token_type::literal_false:
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!sax->boolean(false)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case token_type::literal_null:
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!sax->null()))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case token_type::literal_true:
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!sax->boolean(true)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case token_type::value_integer:
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!sax->number_integer(m_lexer.get_number_integer())))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case token_type::value_string:
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!sax->string(m_lexer.get_string())))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case token_type::value_unsigned:
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(m_lexer.get_number_unsigned())))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case token_type::parse_error:
|
||||||
|
{
|
||||||
|
// using "uninitialized" to avoid "expected" message
|
||||||
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, "value"), nullptr));
|
||||||
|
}
|
||||||
|
case token_type::end_of_input:
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(m_lexer.get_position().chars_read_total == 1))
|
||||||
|
{
|
||||||
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(),
|
||||||
|
"attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr));
|
||||||
|
}
|
||||||
|
case token_type::uninitialized:
|
||||||
|
case token_type::end_array:
|
||||||
|
case token_type::end_object:
|
||||||
|
case token_type::name_separator:
|
||||||
|
case token_type::value_separator:
|
||||||
|
case token_type::literal_or_value:
|
||||||
|
default: // the last token was unexpected
|
||||||
|
{
|
||||||
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
skip_to_state_evaluation = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we reached this line after we successfully parsed a value
|
||||||
|
if (states.empty())
|
||||||
|
{
|
||||||
|
// empty stack: we reached the end of the hierarchy: done
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (states.back()) // array
|
||||||
|
{
|
||||||
|
// comma -> next value
|
||||||
|
if (get_token() == token_type::value_separator)
|
||||||
|
{
|
||||||
|
// parse a new value
|
||||||
|
get_token();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// closing ]
|
||||||
|
if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array))
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!sax->end_array()))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are done with this array. Before we can parse a
|
||||||
|
// new value, we need to evaluate the new state first.
|
||||||
|
// By setting skip_to_state_evaluation to false, we
|
||||||
|
// are effectively jumping to the beginning of this if.
|
||||||
|
JSON_ASSERT(!states.empty());
|
||||||
|
states.pop_back();
|
||||||
|
skip_to_state_evaluation = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array, "array"), nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// states.back() is false -> object
|
||||||
|
|
||||||
|
// comma -> next value
|
||||||
|
if (get_token() == token_type::value_separator)
|
||||||
|
{
|
||||||
|
// parse key
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string))
|
||||||
|
{
|
||||||
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse separator (:)
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))
|
||||||
|
{
|
||||||
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse values
|
||||||
|
get_token();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// closing }
|
||||||
|
if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object))
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are done with this object. Before we can parse a
|
||||||
|
// new value, we need to evaluate the new state first.
|
||||||
|
// By setting skip_to_state_evaluation to false, we
|
||||||
|
// are effectively jumping to the beginning of this if.
|
||||||
|
JSON_ASSERT(!states.empty());
|
||||||
|
states.pop_back();
|
||||||
|
skip_to_state_evaluation = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object, "object"), nullptr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get next token from lexer
|
||||||
|
token_type get_token()
|
||||||
|
{
|
||||||
|
return last_token = m_lexer.scan();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string exception_message(const token_type expected, const std::string& context)
|
||||||
|
{
|
||||||
|
std::string error_msg = "syntax error ";
|
||||||
|
|
||||||
|
if (!context.empty())
|
||||||
|
{
|
||||||
|
error_msg += concat("while parsing ", context, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
error_msg += "- ";
|
||||||
|
|
||||||
|
if (last_token == token_type::parse_error)
|
||||||
|
{
|
||||||
|
error_msg += concat(m_lexer.get_error_message(), "; last read: '",
|
||||||
|
m_lexer.get_token_string(), '\'');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error_msg += concat("unexpected ", lexer_t::token_type_name(last_token));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expected != token_type::uninitialized)
|
||||||
|
{
|
||||||
|
error_msg += concat("; expected ", lexer_t::token_type_name(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
return error_msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// callback function
|
||||||
|
const parser_callback_t<BasicJsonType> callback = nullptr;
|
||||||
|
/// the type of the last read token
|
||||||
|
token_type last_token = token_type::uninitialized;
|
||||||
|
/// the lexer
|
||||||
|
lexer_t m_lexer;
|
||||||
|
/// whether to throw exceptions in case of errors
|
||||||
|
const bool allow_exceptions = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef> // size_t
|
||||||
|
|
||||||
|
#include <nlohmann/detail/abi_macros.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
/// struct to capture the start position of the current token
|
||||||
|
struct position_t
|
||||||
|
{
|
||||||
|
/// the total number of characters read
|
||||||
|
std::size_t chars_read_total = 0;
|
||||||
|
/// the number of characters read in the current line
|
||||||
|
std::size_t chars_read_current_line = 0;
|
||||||
|
/// the number of lines read
|
||||||
|
std::size_t lines_read = 0;
|
||||||
|
|
||||||
|
/// conversion to size_t to preserve SAX interface
|
||||||
|
constexpr operator size_t() const
|
||||||
|
{
|
||||||
|
return chars_read_total;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <nlohmann/detail/abi_macros.hpp>
|
||||||
|
#include <nlohmann/detail/iterators/primitive_iterator.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief an iterator value
|
||||||
|
|
||||||
|
@note This structure could easily be a union, but MSVC currently does not allow
|
||||||
|
unions members with complex constructors, see https://github.com/nlohmann/json/pull/105.
|
||||||
|
*/
|
||||||
|
template<typename BasicJsonType> struct internal_iterator
|
||||||
|
{
|
||||||
|
/// iterator for JSON objects
|
||||||
|
typename BasicJsonType::object_t::iterator object_iterator {};
|
||||||
|
/// iterator for JSON arrays
|
||||||
|
typename BasicJsonType::array_t::iterator array_iterator {};
|
||||||
|
/// generic iterator for all other types
|
||||||
|
primitive_iterator_t primitive_iterator {};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,751 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next
|
||||||
|
#include <type_traits> // conditional, is_const, remove_const
|
||||||
|
|
||||||
|
#include <nlohmann/detail/exceptions.hpp>
|
||||||
|
#include <nlohmann/detail/iterators/internal_iterator.hpp>
|
||||||
|
#include <nlohmann/detail/iterators/primitive_iterator.hpp>
|
||||||
|
#include <nlohmann/detail/macro_scope.hpp>
|
||||||
|
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||||
|
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||||
|
#include <nlohmann/detail/value_t.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
// forward declare, to be able to friend it later on
|
||||||
|
template<typename IteratorType> class iteration_proxy;
|
||||||
|
template<typename IteratorType> class iteration_proxy_value;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief a template for a bidirectional iterator for the @ref basic_json class
|
||||||
|
This class implements a both iterators (iterator and const_iterator) for the
|
||||||
|
@ref basic_json class.
|
||||||
|
@note An iterator is called *initialized* when a pointer to a JSON value has
|
||||||
|
been set (e.g., by a constructor or a copy assignment). If the iterator is
|
||||||
|
default-constructed, it is *uninitialized* and most methods are undefined.
|
||||||
|
**The library uses assertions to detect calls on uninitialized iterators.**
|
||||||
|
@requirement The class satisfies the following concept requirements:
|
||||||
|
-
|
||||||
|
[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):
|
||||||
|
The iterator that can be moved can be moved in both directions (i.e.
|
||||||
|
incremented and decremented).
|
||||||
|
@since version 1.0.0, simplified in version 2.0.9, change to bidirectional
|
||||||
|
iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593)
|
||||||
|
*/
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
|
||||||
|
{
|
||||||
|
/// the iterator with BasicJsonType of different const-ness
|
||||||
|
using other_iter_impl = iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;
|
||||||
|
/// allow basic_json to access private members
|
||||||
|
friend other_iter_impl;
|
||||||
|
friend BasicJsonType;
|
||||||
|
friend iteration_proxy<iter_impl>;
|
||||||
|
friend iteration_proxy_value<iter_impl>;
|
||||||
|
|
||||||
|
using object_t = typename BasicJsonType::object_t;
|
||||||
|
using array_t = typename BasicJsonType::array_t;
|
||||||
|
// make sure BasicJsonType is basic_json or const basic_json
|
||||||
|
static_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value,
|
||||||
|
"iter_impl only accepts (const) basic_json");
|
||||||
|
// superficial check for the LegacyBidirectionalIterator named requirement
|
||||||
|
static_assert(std::is_base_of<std::bidirectional_iterator_tag, std::bidirectional_iterator_tag>::value
|
||||||
|
&& std::is_base_of<std::bidirectional_iterator_tag, typename std::iterator_traits<typename array_t::iterator>::iterator_category>::value,
|
||||||
|
"basic_json iterator assumes array and object type iterators satisfy the LegacyBidirectionalIterator named requirement.");
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17.
|
||||||
|
/// The C++ Standard has never required user-defined iterators to derive from std::iterator.
|
||||||
|
/// A user-defined iterator should provide publicly accessible typedefs named
|
||||||
|
/// iterator_category, value_type, difference_type, pointer, and reference.
|
||||||
|
/// Note that value_type is required to be non-const, even for constant iterators.
|
||||||
|
using iterator_category = std::bidirectional_iterator_tag;
|
||||||
|
|
||||||
|
/// the type of the values when the iterator is dereferenced
|
||||||
|
using value_type = typename BasicJsonType::value_type;
|
||||||
|
/// a type to represent differences between iterators
|
||||||
|
using difference_type = typename BasicJsonType::difference_type;
|
||||||
|
/// defines a pointer to the type iterated over (value_type)
|
||||||
|
using pointer = typename std::conditional<std::is_const<BasicJsonType>::value,
|
||||||
|
typename BasicJsonType::const_pointer,
|
||||||
|
typename BasicJsonType::pointer>::type;
|
||||||
|
/// defines a reference to the type iterated over (value_type)
|
||||||
|
using reference =
|
||||||
|
typename std::conditional<std::is_const<BasicJsonType>::value,
|
||||||
|
typename BasicJsonType::const_reference,
|
||||||
|
typename BasicJsonType::reference>::type;
|
||||||
|
|
||||||
|
iter_impl() = default;
|
||||||
|
~iter_impl() = default;
|
||||||
|
iter_impl(iter_impl&&) noexcept = default;
|
||||||
|
iter_impl& operator=(iter_impl&&) noexcept = default;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief constructor for a given JSON instance
|
||||||
|
@param[in] object pointer to a JSON object for this iterator
|
||||||
|
@pre object != nullptr
|
||||||
|
@post The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
explicit iter_impl(pointer object) noexcept : m_object(object)
|
||||||
|
{
|
||||||
|
JSON_ASSERT(m_object != nullptr);
|
||||||
|
|
||||||
|
switch (m_object->m_data.m_type)
|
||||||
|
{
|
||||||
|
case value_t::object:
|
||||||
|
{
|
||||||
|
m_it.object_iterator = typename object_t::iterator();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
{
|
||||||
|
m_it.array_iterator = typename array_t::iterator();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::null:
|
||||||
|
case value_t::string:
|
||||||
|
case value_t::boolean:
|
||||||
|
case value_t::number_integer:
|
||||||
|
case value_t::number_unsigned:
|
||||||
|
case value_t::number_float:
|
||||||
|
case value_t::binary:
|
||||||
|
case value_t::discarded:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
m_it.primitive_iterator = primitive_iterator_t();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@note The conventional copy constructor and copy assignment are implicitly
|
||||||
|
defined. Combined with the following converting constructor and
|
||||||
|
assignment, they support: (1) copy from iterator to iterator, (2)
|
||||||
|
copy from const iterator to const iterator, and (3) conversion from
|
||||||
|
iterator to const iterator. However conversion from const iterator
|
||||||
|
to iterator is not defined.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief const copy constructor
|
||||||
|
@param[in] other const iterator to copy from
|
||||||
|
@note This copy constructor had to be defined explicitly to circumvent a bug
|
||||||
|
occurring on msvc v19.0 compiler (VS 2015) debug build. For more
|
||||||
|
information refer to: https://github.com/nlohmann/json/issues/1608
|
||||||
|
*/
|
||||||
|
iter_impl(const iter_impl<const BasicJsonType>& other) noexcept
|
||||||
|
: m_object(other.m_object), m_it(other.m_it)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief converting assignment
|
||||||
|
@param[in] other const iterator to copy from
|
||||||
|
@return const/non-const iterator
|
||||||
|
@note It is not checked whether @a other is initialized.
|
||||||
|
*/
|
||||||
|
iter_impl& operator=(const iter_impl<const BasicJsonType>& other) noexcept
|
||||||
|
{
|
||||||
|
if (&other != this)
|
||||||
|
{
|
||||||
|
m_object = other.m_object;
|
||||||
|
m_it = other.m_it;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief converting constructor
|
||||||
|
@param[in] other non-const iterator to copy from
|
||||||
|
@note It is not checked whether @a other is initialized.
|
||||||
|
*/
|
||||||
|
iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept
|
||||||
|
: m_object(other.m_object), m_it(other.m_it)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief converting assignment
|
||||||
|
@param[in] other non-const iterator to copy from
|
||||||
|
@return const/non-const iterator
|
||||||
|
@note It is not checked whether @a other is initialized.
|
||||||
|
*/
|
||||||
|
iter_impl& operator=(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept // NOLINT(cert-oop54-cpp)
|
||||||
|
{
|
||||||
|
m_object = other.m_object;
|
||||||
|
m_it = other.m_it;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_PRIVATE_UNLESS_TESTED:
|
||||||
|
/*!
|
||||||
|
@brief set the iterator to the first value
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
void set_begin() noexcept
|
||||||
|
{
|
||||||
|
JSON_ASSERT(m_object != nullptr);
|
||||||
|
|
||||||
|
switch (m_object->m_data.m_type)
|
||||||
|
{
|
||||||
|
case value_t::object:
|
||||||
|
{
|
||||||
|
m_it.object_iterator = m_object->m_data.m_value.object->begin();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
{
|
||||||
|
m_it.array_iterator = m_object->m_data.m_value.array->begin();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::null:
|
||||||
|
{
|
||||||
|
// set to end so begin()==end() is true: null is empty
|
||||||
|
m_it.primitive_iterator.set_end();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::string:
|
||||||
|
case value_t::boolean:
|
||||||
|
case value_t::number_integer:
|
||||||
|
case value_t::number_unsigned:
|
||||||
|
case value_t::number_float:
|
||||||
|
case value_t::binary:
|
||||||
|
case value_t::discarded:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
m_it.primitive_iterator.set_begin();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief set the iterator past the last value
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
void set_end() noexcept
|
||||||
|
{
|
||||||
|
JSON_ASSERT(m_object != nullptr);
|
||||||
|
|
||||||
|
switch (m_object->m_data.m_type)
|
||||||
|
{
|
||||||
|
case value_t::object:
|
||||||
|
{
|
||||||
|
m_it.object_iterator = m_object->m_data.m_value.object->end();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
{
|
||||||
|
m_it.array_iterator = m_object->m_data.m_value.array->end();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::null:
|
||||||
|
case value_t::string:
|
||||||
|
case value_t::boolean:
|
||||||
|
case value_t::number_integer:
|
||||||
|
case value_t::number_unsigned:
|
||||||
|
case value_t::number_float:
|
||||||
|
case value_t::binary:
|
||||||
|
case value_t::discarded:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
m_it.primitive_iterator.set_end();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
@brief return a reference to the value pointed to by the iterator
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
reference operator*() const
|
||||||
|
{
|
||||||
|
JSON_ASSERT(m_object != nullptr);
|
||||||
|
|
||||||
|
switch (m_object->m_data.m_type)
|
||||||
|
{
|
||||||
|
case value_t::object:
|
||||||
|
{
|
||||||
|
JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end());
|
||||||
|
return m_it.object_iterator->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
{
|
||||||
|
JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end());
|
||||||
|
return *m_it.array_iterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::null:
|
||||||
|
JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
|
||||||
|
|
||||||
|
case value_t::string:
|
||||||
|
case value_t::boolean:
|
||||||
|
case value_t::number_integer:
|
||||||
|
case value_t::number_unsigned:
|
||||||
|
case value_t::number_float:
|
||||||
|
case value_t::binary:
|
||||||
|
case value_t::discarded:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))
|
||||||
|
{
|
||||||
|
return *m_object;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief dereference the iterator
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
pointer operator->() const
|
||||||
|
{
|
||||||
|
JSON_ASSERT(m_object != nullptr);
|
||||||
|
|
||||||
|
switch (m_object->m_data.m_type)
|
||||||
|
{
|
||||||
|
case value_t::object:
|
||||||
|
{
|
||||||
|
JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end());
|
||||||
|
return &(m_it.object_iterator->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
{
|
||||||
|
JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end());
|
||||||
|
return &*m_it.array_iterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::null:
|
||||||
|
case value_t::string:
|
||||||
|
case value_t::boolean:
|
||||||
|
case value_t::number_integer:
|
||||||
|
case value_t::number_unsigned:
|
||||||
|
case value_t::number_float:
|
||||||
|
case value_t::binary:
|
||||||
|
case value_t::discarded:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))
|
||||||
|
{
|
||||||
|
return m_object;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief post-increment (it++)
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
iter_impl operator++(int)& // NOLINT(cert-dcl21-cpp)
|
||||||
|
{
|
||||||
|
auto result = *this;
|
||||||
|
++(*this);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief pre-increment (++it)
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
iter_impl& operator++()
|
||||||
|
{
|
||||||
|
JSON_ASSERT(m_object != nullptr);
|
||||||
|
|
||||||
|
switch (m_object->m_data.m_type)
|
||||||
|
{
|
||||||
|
case value_t::object:
|
||||||
|
{
|
||||||
|
std::advance(m_it.object_iterator, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
{
|
||||||
|
std::advance(m_it.array_iterator, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::null:
|
||||||
|
case value_t::string:
|
||||||
|
case value_t::boolean:
|
||||||
|
case value_t::number_integer:
|
||||||
|
case value_t::number_unsigned:
|
||||||
|
case value_t::number_float:
|
||||||
|
case value_t::binary:
|
||||||
|
case value_t::discarded:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
++m_it.primitive_iterator;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief post-decrement (it--)
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
iter_impl operator--(int)& // NOLINT(cert-dcl21-cpp)
|
||||||
|
{
|
||||||
|
auto result = *this;
|
||||||
|
--(*this);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief pre-decrement (--it)
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
iter_impl& operator--()
|
||||||
|
{
|
||||||
|
JSON_ASSERT(m_object != nullptr);
|
||||||
|
|
||||||
|
switch (m_object->m_data.m_type)
|
||||||
|
{
|
||||||
|
case value_t::object:
|
||||||
|
{
|
||||||
|
std::advance(m_it.object_iterator, -1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
{
|
||||||
|
std::advance(m_it.array_iterator, -1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::null:
|
||||||
|
case value_t::string:
|
||||||
|
case value_t::boolean:
|
||||||
|
case value_t::number_integer:
|
||||||
|
case value_t::number_unsigned:
|
||||||
|
case value_t::number_float:
|
||||||
|
case value_t::binary:
|
||||||
|
case value_t::discarded:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
--m_it.primitive_iterator;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief comparison: equal
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr >
|
||||||
|
bool operator==(const IterImpl& other) const
|
||||||
|
{
|
||||||
|
// if objects are not the same, the comparison is undefined
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
|
||||||
|
{
|
||||||
|
JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_ASSERT(m_object != nullptr);
|
||||||
|
|
||||||
|
switch (m_object->m_data.m_type)
|
||||||
|
{
|
||||||
|
case value_t::object:
|
||||||
|
return (m_it.object_iterator == other.m_it.object_iterator);
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
return (m_it.array_iterator == other.m_it.array_iterator);
|
||||||
|
|
||||||
|
case value_t::null:
|
||||||
|
case value_t::string:
|
||||||
|
case value_t::boolean:
|
||||||
|
case value_t::number_integer:
|
||||||
|
case value_t::number_unsigned:
|
||||||
|
case value_t::number_float:
|
||||||
|
case value_t::binary:
|
||||||
|
case value_t::discarded:
|
||||||
|
default:
|
||||||
|
return (m_it.primitive_iterator == other.m_it.primitive_iterator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief comparison: not equal
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr >
|
||||||
|
bool operator!=(const IterImpl& other) const
|
||||||
|
{
|
||||||
|
return !operator==(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief comparison: smaller
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
bool operator<(const iter_impl& other) const
|
||||||
|
{
|
||||||
|
// if objects are not the same, the comparison is undefined
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
|
||||||
|
{
|
||||||
|
JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_ASSERT(m_object != nullptr);
|
||||||
|
|
||||||
|
switch (m_object->m_data.m_type)
|
||||||
|
{
|
||||||
|
case value_t::object:
|
||||||
|
JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators", m_object));
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
return (m_it.array_iterator < other.m_it.array_iterator);
|
||||||
|
|
||||||
|
case value_t::null:
|
||||||
|
case value_t::string:
|
||||||
|
case value_t::boolean:
|
||||||
|
case value_t::number_integer:
|
||||||
|
case value_t::number_unsigned:
|
||||||
|
case value_t::number_float:
|
||||||
|
case value_t::binary:
|
||||||
|
case value_t::discarded:
|
||||||
|
default:
|
||||||
|
return (m_it.primitive_iterator < other.m_it.primitive_iterator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief comparison: less than or equal
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
bool operator<=(const iter_impl& other) const
|
||||||
|
{
|
||||||
|
return !other.operator < (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief comparison: greater than
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
bool operator>(const iter_impl& other) const
|
||||||
|
{
|
||||||
|
return !operator<=(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief comparison: greater than or equal
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
bool operator>=(const iter_impl& other) const
|
||||||
|
{
|
||||||
|
return !operator<(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief add to iterator
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
iter_impl& operator+=(difference_type i)
|
||||||
|
{
|
||||||
|
JSON_ASSERT(m_object != nullptr);
|
||||||
|
|
||||||
|
switch (m_object->m_data.m_type)
|
||||||
|
{
|
||||||
|
case value_t::object:
|
||||||
|
JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object));
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
{
|
||||||
|
std::advance(m_it.array_iterator, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::null:
|
||||||
|
case value_t::string:
|
||||||
|
case value_t::boolean:
|
||||||
|
case value_t::number_integer:
|
||||||
|
case value_t::number_unsigned:
|
||||||
|
case value_t::number_float:
|
||||||
|
case value_t::binary:
|
||||||
|
case value_t::discarded:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
m_it.primitive_iterator += i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief subtract from iterator
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
iter_impl& operator-=(difference_type i)
|
||||||
|
{
|
||||||
|
return operator+=(-i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief add to iterator
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
iter_impl operator+(difference_type i) const
|
||||||
|
{
|
||||||
|
auto result = *this;
|
||||||
|
result += i;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief addition of distance and iterator
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
friend iter_impl operator+(difference_type i, const iter_impl& it)
|
||||||
|
{
|
||||||
|
auto result = it;
|
||||||
|
result += i;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief subtract from iterator
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
iter_impl operator-(difference_type i) const
|
||||||
|
{
|
||||||
|
auto result = *this;
|
||||||
|
result -= i;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief return difference
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
difference_type operator-(const iter_impl& other) const
|
||||||
|
{
|
||||||
|
JSON_ASSERT(m_object != nullptr);
|
||||||
|
|
||||||
|
switch (m_object->m_data.m_type)
|
||||||
|
{
|
||||||
|
case value_t::object:
|
||||||
|
JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object));
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
return m_it.array_iterator - other.m_it.array_iterator;
|
||||||
|
|
||||||
|
case value_t::null:
|
||||||
|
case value_t::string:
|
||||||
|
case value_t::boolean:
|
||||||
|
case value_t::number_integer:
|
||||||
|
case value_t::number_unsigned:
|
||||||
|
case value_t::number_float:
|
||||||
|
case value_t::binary:
|
||||||
|
case value_t::discarded:
|
||||||
|
default:
|
||||||
|
return m_it.primitive_iterator - other.m_it.primitive_iterator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief access to successor
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
reference operator[](difference_type n) const
|
||||||
|
{
|
||||||
|
JSON_ASSERT(m_object != nullptr);
|
||||||
|
|
||||||
|
switch (m_object->m_data.m_type)
|
||||||
|
{
|
||||||
|
case value_t::object:
|
||||||
|
JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators", m_object));
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
return *std::next(m_it.array_iterator, n);
|
||||||
|
|
||||||
|
case value_t::null:
|
||||||
|
JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
|
||||||
|
|
||||||
|
case value_t::string:
|
||||||
|
case value_t::boolean:
|
||||||
|
case value_t::number_integer:
|
||||||
|
case value_t::number_unsigned:
|
||||||
|
case value_t::number_float:
|
||||||
|
case value_t::binary:
|
||||||
|
case value_t::discarded:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.get_value() == -n))
|
||||||
|
{
|
||||||
|
return *m_object;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief return the key of an object iterator
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
const typename object_t::key_type& key() const
|
||||||
|
{
|
||||||
|
JSON_ASSERT(m_object != nullptr);
|
||||||
|
|
||||||
|
if (JSON_HEDLEY_LIKELY(m_object->is_object()))
|
||||||
|
{
|
||||||
|
return m_it.object_iterator->first;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators", m_object));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief return the value of an iterator
|
||||||
|
@pre The iterator is initialized; i.e. `m_object != nullptr`.
|
||||||
|
*/
|
||||||
|
reference value() const
|
||||||
|
{
|
||||||
|
return operator*();
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_PRIVATE_UNLESS_TESTED:
|
||||||
|
/// associated JSON instance
|
||||||
|
pointer m_object = nullptr;
|
||||||
|
/// the actual iterator of the associated instance
|
||||||
|
internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it {};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,242 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef> // size_t
|
||||||
|
#include <iterator> // input_iterator_tag
|
||||||
|
#include <string> // string, to_string
|
||||||
|
#include <tuple> // tuple_size, get, tuple_element
|
||||||
|
#include <utility> // move
|
||||||
|
|
||||||
|
#if JSON_HAS_RANGES
|
||||||
|
#include <ranges> // enable_borrowed_range
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <nlohmann/detail/abi_macros.hpp>
|
||||||
|
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||||
|
#include <nlohmann/detail/value_t.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename string_type>
|
||||||
|
void int_to_string( string_type& target, std::size_t value )
|
||||||
|
{
|
||||||
|
// For ADL
|
||||||
|
using std::to_string;
|
||||||
|
target = to_string(value);
|
||||||
|
}
|
||||||
|
template<typename IteratorType> class iteration_proxy_value
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using value_type = iteration_proxy_value;
|
||||||
|
using pointer = value_type *;
|
||||||
|
using reference = value_type &;
|
||||||
|
using iterator_category = std::input_iterator_tag;
|
||||||
|
using string_type = typename std::remove_cv< typename std::remove_reference<decltype( std::declval<IteratorType>().key() ) >::type >::type;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// the iterator
|
||||||
|
IteratorType anchor{};
|
||||||
|
/// an index for arrays (used to create key names)
|
||||||
|
std::size_t array_index = 0;
|
||||||
|
/// last stringified array index
|
||||||
|
mutable std::size_t array_index_last = 0;
|
||||||
|
/// a string representation of the array index
|
||||||
|
mutable string_type array_index_str = "0";
|
||||||
|
/// an empty string (to return a reference for primitive values)
|
||||||
|
string_type empty_str{};
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit iteration_proxy_value() = default;
|
||||||
|
explicit iteration_proxy_value(IteratorType it, std::size_t array_index_ = 0)
|
||||||
|
noexcept(std::is_nothrow_move_constructible<IteratorType>::value
|
||||||
|
&& std::is_nothrow_default_constructible<string_type>::value)
|
||||||
|
: anchor(std::move(it))
|
||||||
|
, array_index(array_index_)
|
||||||
|
{}
|
||||||
|
|
||||||
|
iteration_proxy_value(iteration_proxy_value const&) = default;
|
||||||
|
iteration_proxy_value& operator=(iteration_proxy_value const&) = default;
|
||||||
|
// older GCCs are a bit fussy and require explicit noexcept specifiers on defaulted functions
|
||||||
|
iteration_proxy_value(iteration_proxy_value&&)
|
||||||
|
noexcept(std::is_nothrow_move_constructible<IteratorType>::value
|
||||||
|
&& std::is_nothrow_move_constructible<string_type>::value) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor,cppcoreguidelines-noexcept-move-operations)
|
||||||
|
iteration_proxy_value& operator=(iteration_proxy_value&&)
|
||||||
|
noexcept(std::is_nothrow_move_assignable<IteratorType>::value
|
||||||
|
&& std::is_nothrow_move_assignable<string_type>::value) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor,cppcoreguidelines-noexcept-move-operations)
|
||||||
|
~iteration_proxy_value() = default;
|
||||||
|
|
||||||
|
/// dereference operator (needed for range-based for)
|
||||||
|
const iteration_proxy_value& operator*() const
|
||||||
|
{
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// increment operator (needed for range-based for)
|
||||||
|
iteration_proxy_value& operator++()
|
||||||
|
{
|
||||||
|
++anchor;
|
||||||
|
++array_index;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
iteration_proxy_value operator++(int)& // NOLINT(cert-dcl21-cpp)
|
||||||
|
{
|
||||||
|
auto tmp = iteration_proxy_value(anchor, array_index);
|
||||||
|
++anchor;
|
||||||
|
++array_index;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// equality operator (needed for InputIterator)
|
||||||
|
bool operator==(const iteration_proxy_value& o) const
|
||||||
|
{
|
||||||
|
return anchor == o.anchor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// inequality operator (needed for range-based for)
|
||||||
|
bool operator!=(const iteration_proxy_value& o) const
|
||||||
|
{
|
||||||
|
return anchor != o.anchor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// return key of the iterator
|
||||||
|
const string_type& key() const
|
||||||
|
{
|
||||||
|
JSON_ASSERT(anchor.m_object != nullptr);
|
||||||
|
|
||||||
|
switch (anchor.m_object->type())
|
||||||
|
{
|
||||||
|
// use integer array index as key
|
||||||
|
case value_t::array:
|
||||||
|
{
|
||||||
|
if (array_index != array_index_last)
|
||||||
|
{
|
||||||
|
int_to_string( array_index_str, array_index );
|
||||||
|
array_index_last = array_index;
|
||||||
|
}
|
||||||
|
return array_index_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// use key from the object
|
||||||
|
case value_t::object:
|
||||||
|
return anchor.key();
|
||||||
|
|
||||||
|
// use an empty key for all primitive types
|
||||||
|
case value_t::null:
|
||||||
|
case value_t::string:
|
||||||
|
case value_t::boolean:
|
||||||
|
case value_t::number_integer:
|
||||||
|
case value_t::number_unsigned:
|
||||||
|
case value_t::number_float:
|
||||||
|
case value_t::binary:
|
||||||
|
case value_t::discarded:
|
||||||
|
default:
|
||||||
|
return empty_str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// return value of the iterator
|
||||||
|
typename IteratorType::reference value() const
|
||||||
|
{
|
||||||
|
return anchor.value();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// proxy class for the items() function
|
||||||
|
template<typename IteratorType> class iteration_proxy
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/// the container to iterate
|
||||||
|
typename IteratorType::pointer container = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit iteration_proxy() = default;
|
||||||
|
|
||||||
|
/// construct iteration proxy from a container
|
||||||
|
explicit iteration_proxy(typename IteratorType::reference cont) noexcept
|
||||||
|
: container(&cont) {}
|
||||||
|
|
||||||
|
iteration_proxy(iteration_proxy const&) = default;
|
||||||
|
iteration_proxy& operator=(iteration_proxy const&) = default;
|
||||||
|
iteration_proxy(iteration_proxy&&) noexcept = default;
|
||||||
|
iteration_proxy& operator=(iteration_proxy&&) noexcept = default;
|
||||||
|
~iteration_proxy() = default;
|
||||||
|
|
||||||
|
/// return iterator begin (needed for range-based for)
|
||||||
|
iteration_proxy_value<IteratorType> begin() const noexcept
|
||||||
|
{
|
||||||
|
return iteration_proxy_value<IteratorType>(container->begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// return iterator end (needed for range-based for)
|
||||||
|
iteration_proxy_value<IteratorType> end() const noexcept
|
||||||
|
{
|
||||||
|
return iteration_proxy_value<IteratorType>(container->end());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Structured Bindings Support
|
||||||
|
// For further reference see https://blog.tartanllama.xyz/structured-bindings/
|
||||||
|
// And see https://github.com/nlohmann/json/pull/1391
|
||||||
|
template<std::size_t N, typename IteratorType, enable_if_t<N == 0, int> = 0>
|
||||||
|
auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.key())
|
||||||
|
{
|
||||||
|
return i.key();
|
||||||
|
}
|
||||||
|
// Structured Bindings Support
|
||||||
|
// For further reference see https://blog.tartanllama.xyz/structured-bindings/
|
||||||
|
// And see https://github.com/nlohmann/json/pull/1391
|
||||||
|
template<std::size_t N, typename IteratorType, enable_if_t<N == 1, int> = 0>
|
||||||
|
auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.value())
|
||||||
|
{
|
||||||
|
return i.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
||||||
|
// The Addition to the STD Namespace is required to add
|
||||||
|
// Structured Bindings Support to the iteration_proxy_value class
|
||||||
|
// For further reference see https://blog.tartanllama.xyz/structured-bindings/
|
||||||
|
// And see https://github.com/nlohmann/json/pull/1391
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
// Fix: https://github.com/nlohmann/json/issues/1401
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wmismatched-tags"
|
||||||
|
#endif
|
||||||
|
template<typename IteratorType>
|
||||||
|
class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>> // NOLINT(cert-dcl58-cpp)
|
||||||
|
: public std::integral_constant<std::size_t, 2> {};
|
||||||
|
|
||||||
|
template<std::size_t N, typename IteratorType>
|
||||||
|
class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >> // NOLINT(cert-dcl58-cpp)
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using type = decltype(
|
||||||
|
get<N>(std::declval <
|
||||||
|
::nlohmann::detail::iteration_proxy_value<IteratorType >> ()));
|
||||||
|
};
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace std
|
||||||
|
|
||||||
|
#if JSON_HAS_RANGES
|
||||||
|
template <typename IteratorType>
|
||||||
|
inline constexpr bool ::std::ranges::enable_borrowed_range<::nlohmann::detail::iteration_proxy<IteratorType>> = true;
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <iterator> // random_access_iterator_tag
|
||||||
|
|
||||||
|
#include <nlohmann/detail/abi_macros.hpp>
|
||||||
|
#include <nlohmann/detail/meta/void_t.hpp>
|
||||||
|
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename It, typename = void>
|
||||||
|
struct iterator_types {};
|
||||||
|
|
||||||
|
template<typename It>
|
||||||
|
struct iterator_types <
|
||||||
|
It,
|
||||||
|
void_t<typename It::difference_type, typename It::value_type, typename It::pointer,
|
||||||
|
typename It::reference, typename It::iterator_category >>
|
||||||
|
{
|
||||||
|
using difference_type = typename It::difference_type;
|
||||||
|
using value_type = typename It::value_type;
|
||||||
|
using pointer = typename It::pointer;
|
||||||
|
using reference = typename It::reference;
|
||||||
|
using iterator_category = typename It::iterator_category;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is required as some compilers implement std::iterator_traits in a way that
|
||||||
|
// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341.
|
||||||
|
template<typename T, typename = void>
|
||||||
|
struct iterator_traits
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct iterator_traits < T, enable_if_t < !std::is_pointer<T>::value >>
|
||||||
|
: iterator_types<T>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct iterator_traits<T*, enable_if_t<std::is_object<T>::value>>
|
||||||
|
{
|
||||||
|
using iterator_category = std::random_access_iterator_tag;
|
||||||
|
using value_type = T;
|
||||||
|
using difference_type = ptrdiff_t;
|
||||||
|
using pointer = T*;
|
||||||
|
using reference = T&;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,130 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef> // ptrdiff_t
|
||||||
|
#include <iterator> // reverse_iterator
|
||||||
|
#include <utility> // declval
|
||||||
|
|
||||||
|
#include <nlohmann/detail/abi_macros.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
//////////////////////
|
||||||
|
// reverse_iterator //
|
||||||
|
//////////////////////
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief a template for a reverse iterator class
|
||||||
|
|
||||||
|
@tparam Base the base iterator type to reverse. Valid types are @ref
|
||||||
|
iterator (to create @ref reverse_iterator) and @ref const_iterator (to
|
||||||
|
create @ref const_reverse_iterator).
|
||||||
|
|
||||||
|
@requirement The class satisfies the following concept requirements:
|
||||||
|
-
|
||||||
|
[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):
|
||||||
|
The iterator that can be moved can be moved in both directions (i.e.
|
||||||
|
incremented and decremented).
|
||||||
|
- [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator):
|
||||||
|
It is possible to write to the pointed-to element (only if @a Base is
|
||||||
|
@ref iterator).
|
||||||
|
|
||||||
|
@since version 1.0.0
|
||||||
|
*/
|
||||||
|
template<typename Base>
|
||||||
|
class json_reverse_iterator : public std::reverse_iterator<Base>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
/// shortcut to the reverse iterator adapter
|
||||||
|
using base_iterator = std::reverse_iterator<Base>;
|
||||||
|
/// the reference type for the pointed-to element
|
||||||
|
using reference = typename Base::reference;
|
||||||
|
|
||||||
|
/// create reverse iterator from iterator
|
||||||
|
explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept
|
||||||
|
: base_iterator(it) {}
|
||||||
|
|
||||||
|
/// create reverse iterator from base class
|
||||||
|
explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {}
|
||||||
|
|
||||||
|
/// post-increment (it++)
|
||||||
|
json_reverse_iterator operator++(int)& // NOLINT(cert-dcl21-cpp)
|
||||||
|
{
|
||||||
|
return static_cast<json_reverse_iterator>(base_iterator::operator++(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// pre-increment (++it)
|
||||||
|
json_reverse_iterator& operator++()
|
||||||
|
{
|
||||||
|
return static_cast<json_reverse_iterator&>(base_iterator::operator++());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// post-decrement (it--)
|
||||||
|
json_reverse_iterator operator--(int)& // NOLINT(cert-dcl21-cpp)
|
||||||
|
{
|
||||||
|
return static_cast<json_reverse_iterator>(base_iterator::operator--(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// pre-decrement (--it)
|
||||||
|
json_reverse_iterator& operator--()
|
||||||
|
{
|
||||||
|
return static_cast<json_reverse_iterator&>(base_iterator::operator--());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// add to iterator
|
||||||
|
json_reverse_iterator& operator+=(difference_type i)
|
||||||
|
{
|
||||||
|
return static_cast<json_reverse_iterator&>(base_iterator::operator+=(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// add to iterator
|
||||||
|
json_reverse_iterator operator+(difference_type i) const
|
||||||
|
{
|
||||||
|
return static_cast<json_reverse_iterator>(base_iterator::operator+(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// subtract from iterator
|
||||||
|
json_reverse_iterator operator-(difference_type i) const
|
||||||
|
{
|
||||||
|
return static_cast<json_reverse_iterator>(base_iterator::operator-(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// return difference
|
||||||
|
difference_type operator-(const json_reverse_iterator& other) const
|
||||||
|
{
|
||||||
|
return base_iterator(*this) - base_iterator(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// access to successor
|
||||||
|
reference operator[](difference_type n) const
|
||||||
|
{
|
||||||
|
return *(this->operator+(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// return the key of an object iterator
|
||||||
|
auto key() const -> decltype(std::declval<Base>().key())
|
||||||
|
{
|
||||||
|
auto it = --this->base();
|
||||||
|
return it.key();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// return the value of an iterator
|
||||||
|
reference value() const
|
||||||
|
{
|
||||||
|
auto it = --this->base();
|
||||||
|
return it.operator * ();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,132 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef> // ptrdiff_t
|
||||||
|
#include <limits> // numeric_limits
|
||||||
|
|
||||||
|
#include <nlohmann/detail/macro_scope.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
@brief an iterator for primitive JSON types
|
||||||
|
|
||||||
|
This class models an iterator for primitive JSON types (boolean, number,
|
||||||
|
string). It's only purpose is to allow the iterator/const_iterator classes
|
||||||
|
to "iterate" over primitive values. Internally, the iterator is modeled by
|
||||||
|
a `difference_type` variable. Value begin_value (`0`) models the begin,
|
||||||
|
end_value (`1`) models past the end.
|
||||||
|
*/
|
||||||
|
class primitive_iterator_t
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
static constexpr difference_type begin_value = 0;
|
||||||
|
static constexpr difference_type end_value = begin_value + 1;
|
||||||
|
|
||||||
|
JSON_PRIVATE_UNLESS_TESTED:
|
||||||
|
/// iterator as signed integer type
|
||||||
|
difference_type m_it = (std::numeric_limits<std::ptrdiff_t>::min)();
|
||||||
|
|
||||||
|
public:
|
||||||
|
constexpr difference_type get_value() const noexcept
|
||||||
|
{
|
||||||
|
return m_it;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// set iterator to a defined beginning
|
||||||
|
void set_begin() noexcept
|
||||||
|
{
|
||||||
|
m_it = begin_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// set iterator to a defined past the end
|
||||||
|
void set_end() noexcept
|
||||||
|
{
|
||||||
|
m_it = end_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// return whether the iterator can be dereferenced
|
||||||
|
constexpr bool is_begin() const noexcept
|
||||||
|
{
|
||||||
|
return m_it == begin_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// return whether the iterator is at end
|
||||||
|
constexpr bool is_end() const noexcept
|
||||||
|
{
|
||||||
|
return m_it == end_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
|
||||||
|
{
|
||||||
|
return lhs.m_it == rhs.m_it;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
|
||||||
|
{
|
||||||
|
return lhs.m_it < rhs.m_it;
|
||||||
|
}
|
||||||
|
|
||||||
|
primitive_iterator_t operator+(difference_type n) noexcept
|
||||||
|
{
|
||||||
|
auto result = *this;
|
||||||
|
result += n;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
|
||||||
|
{
|
||||||
|
return lhs.m_it - rhs.m_it;
|
||||||
|
}
|
||||||
|
|
||||||
|
primitive_iterator_t& operator++() noexcept
|
||||||
|
{
|
||||||
|
++m_it;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
primitive_iterator_t operator++(int)& noexcept // NOLINT(cert-dcl21-cpp)
|
||||||
|
{
|
||||||
|
auto result = *this;
|
||||||
|
++m_it;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
primitive_iterator_t& operator--() noexcept
|
||||||
|
{
|
||||||
|
--m_it;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
primitive_iterator_t operator--(int)& noexcept // NOLINT(cert-dcl21-cpp)
|
||||||
|
{
|
||||||
|
auto result = *this;
|
||||||
|
--m_it;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
primitive_iterator_t& operator+=(difference_type n) noexcept
|
||||||
|
{
|
||||||
|
m_it += n;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
primitive_iterator_t& operator-=(difference_type n) noexcept
|
||||||
|
{
|
||||||
|
m_it -= n;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <type_traits> // conditional, is_same
|
||||||
|
|
||||||
|
#include <nlohmann/detail/abi_macros.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief Default base class of the @ref basic_json class.
|
||||||
|
|
||||||
|
So that the correct implementations of the copy / move ctors / assign operators
|
||||||
|
of @ref basic_json do not require complex case distinctions
|
||||||
|
(no base class / custom base class used as customization point),
|
||||||
|
@ref basic_json always has a base class.
|
||||||
|
By default, this class is used because it is empty and thus has no effect
|
||||||
|
on the behavior of @ref basic_json.
|
||||||
|
*/
|
||||||
|
struct json_default_base {};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
using json_base_class = typename std::conditional <
|
||||||
|
std::is_same<T, void>::value,
|
||||||
|
json_default_base,
|
||||||
|
T
|
||||||
|
>::type;
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,988 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm> // all_of
|
||||||
|
#include <cctype> // isdigit
|
||||||
|
#include <cerrno> // errno, ERANGE
|
||||||
|
#include <cstdlib> // strtoull
|
||||||
|
#ifndef JSON_NO_IO
|
||||||
|
#include <iosfwd> // ostream
|
||||||
|
#endif // JSON_NO_IO
|
||||||
|
#include <limits> // max
|
||||||
|
#include <numeric> // accumulate
|
||||||
|
#include <string> // string
|
||||||
|
#include <utility> // move
|
||||||
|
#include <vector> // vector
|
||||||
|
|
||||||
|
#include <nlohmann/detail/exceptions.hpp>
|
||||||
|
#include <nlohmann/detail/macro_scope.hpp>
|
||||||
|
#include <nlohmann/detail/string_concat.hpp>
|
||||||
|
#include <nlohmann/detail/string_escape.hpp>
|
||||||
|
#include <nlohmann/detail/value_t.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document
|
||||||
|
/// @sa https://json.nlohmann.me/api/json_pointer/
|
||||||
|
template<typename RefStringType>
|
||||||
|
class json_pointer
|
||||||
|
{
|
||||||
|
// allow basic_json to access private members
|
||||||
|
NLOHMANN_BASIC_JSON_TPL_DECLARATION
|
||||||
|
friend class basic_json;
|
||||||
|
|
||||||
|
template<typename>
|
||||||
|
friend class json_pointer;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct string_t_helper
|
||||||
|
{
|
||||||
|
using type = T;
|
||||||
|
};
|
||||||
|
|
||||||
|
NLOHMANN_BASIC_JSON_TPL_DECLARATION
|
||||||
|
struct string_t_helper<NLOHMANN_BASIC_JSON_TPL>
|
||||||
|
{
|
||||||
|
using type = StringType;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
// for backwards compatibility accept BasicJsonType
|
||||||
|
using string_t = typename string_t_helper<RefStringType>::type;
|
||||||
|
|
||||||
|
/// @brief create JSON pointer
|
||||||
|
/// @sa https://json.nlohmann.me/api/json_pointer/json_pointer/
|
||||||
|
explicit json_pointer(const string_t& s = "")
|
||||||
|
: reference_tokens(split(s))
|
||||||
|
{}
|
||||||
|
|
||||||
|
/// @brief return a string representation of the JSON pointer
|
||||||
|
/// @sa https://json.nlohmann.me/api/json_pointer/to_string/
|
||||||
|
string_t to_string() const
|
||||||
|
{
|
||||||
|
return std::accumulate(reference_tokens.begin(), reference_tokens.end(),
|
||||||
|
string_t{},
|
||||||
|
[](const string_t& a, const string_t& b)
|
||||||
|
{
|
||||||
|
return detail::concat(a, '/', detail::escape(b));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief return a string representation of the JSON pointer
|
||||||
|
/// @sa https://json.nlohmann.me/api/json_pointer/operator_string/
|
||||||
|
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, to_string())
|
||||||
|
operator string_t() const
|
||||||
|
{
|
||||||
|
return to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef JSON_NO_IO
|
||||||
|
/// @brief write string representation of the JSON pointer to stream
|
||||||
|
/// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/
|
||||||
|
friend std::ostream& operator<<(std::ostream& o, const json_pointer& ptr)
|
||||||
|
{
|
||||||
|
o << ptr.to_string();
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// @brief append another JSON pointer at the end of this JSON pointer
|
||||||
|
/// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/
|
||||||
|
json_pointer& operator/=(const json_pointer& ptr)
|
||||||
|
{
|
||||||
|
reference_tokens.insert(reference_tokens.end(),
|
||||||
|
ptr.reference_tokens.begin(),
|
||||||
|
ptr.reference_tokens.end());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief append an unescaped reference token at the end of this JSON pointer
|
||||||
|
/// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/
|
||||||
|
json_pointer& operator/=(string_t token)
|
||||||
|
{
|
||||||
|
push_back(std::move(token));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief append an array index at the end of this JSON pointer
|
||||||
|
/// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/
|
||||||
|
json_pointer& operator/=(std::size_t array_idx)
|
||||||
|
{
|
||||||
|
return *this /= std::to_string(array_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer
|
||||||
|
/// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/
|
||||||
|
friend json_pointer operator/(const json_pointer& lhs,
|
||||||
|
const json_pointer& rhs)
|
||||||
|
{
|
||||||
|
return json_pointer(lhs) /= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer
|
||||||
|
/// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/
|
||||||
|
friend json_pointer operator/(const json_pointer& lhs, string_t token) // NOLINT(performance-unnecessary-value-param)
|
||||||
|
{
|
||||||
|
return json_pointer(lhs) /= std::move(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer
|
||||||
|
/// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/
|
||||||
|
friend json_pointer operator/(const json_pointer& lhs, std::size_t array_idx)
|
||||||
|
{
|
||||||
|
return json_pointer(lhs) /= array_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief returns the parent of this JSON pointer
|
||||||
|
/// @sa https://json.nlohmann.me/api/json_pointer/parent_pointer/
|
||||||
|
json_pointer parent_pointer() const
|
||||||
|
{
|
||||||
|
if (empty())
|
||||||
|
{
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
json_pointer res = *this;
|
||||||
|
res.pop_back();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief remove last reference token
|
||||||
|
/// @sa https://json.nlohmann.me/api/json_pointer/pop_back/
|
||||||
|
void pop_back()
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(empty()))
|
||||||
|
{
|
||||||
|
JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
reference_tokens.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief return last reference token
|
||||||
|
/// @sa https://json.nlohmann.me/api/json_pointer/back/
|
||||||
|
const string_t& back() const
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(empty()))
|
||||||
|
{
|
||||||
|
JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
return reference_tokens.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief append an unescaped token at the end of the reference pointer
|
||||||
|
/// @sa https://json.nlohmann.me/api/json_pointer/push_back/
|
||||||
|
void push_back(const string_t& token)
|
||||||
|
{
|
||||||
|
reference_tokens.push_back(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief append an unescaped token at the end of the reference pointer
|
||||||
|
/// @sa https://json.nlohmann.me/api/json_pointer/push_back/
|
||||||
|
void push_back(string_t&& token)
|
||||||
|
{
|
||||||
|
reference_tokens.push_back(std::move(token));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief return whether pointer points to the root document
|
||||||
|
/// @sa https://json.nlohmann.me/api/json_pointer/empty/
|
||||||
|
bool empty() const noexcept
|
||||||
|
{
|
||||||
|
return reference_tokens.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*!
|
||||||
|
@param[in] s reference token to be converted into an array index
|
||||||
|
|
||||||
|
@return integer representation of @a s
|
||||||
|
|
||||||
|
@throw parse_error.106 if an array index begins with '0'
|
||||||
|
@throw parse_error.109 if an array index begins not with a digit
|
||||||
|
@throw out_of_range.404 if string @a s could not be converted to an integer
|
||||||
|
@throw out_of_range.410 if an array index exceeds size_type
|
||||||
|
*/
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
static typename BasicJsonType::size_type array_index(const string_t& s)
|
||||||
|
{
|
||||||
|
using size_type = typename BasicJsonType::size_type;
|
||||||
|
|
||||||
|
// error condition (cf. RFC 6901, Sect. 4)
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0'))
|
||||||
|
{
|
||||||
|
JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// error condition (cf. RFC 6901, Sect. 4)
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9')))
|
||||||
|
{
|
||||||
|
JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", s, "' is not a number"), nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* p = s.c_str();
|
||||||
|
char* p_end = nullptr;
|
||||||
|
errno = 0; // strtoull doesn't reset errno
|
||||||
|
const unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int)
|
||||||
|
if (p == p_end // invalid input or empty string
|
||||||
|
|| errno == ERANGE // out of range
|
||||||
|
|| JSON_HEDLEY_UNLIKELY(static_cast<std::size_t>(p_end - p) != s.size())) // incomplete read
|
||||||
|
{
|
||||||
|
JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", s, "'"), nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// only triggered on special platforms (like 32bit), see also
|
||||||
|
// https://github.com/nlohmann/json/pull/2203
|
||||||
|
if (res >= static_cast<unsigned long long>((std::numeric_limits<size_type>::max)())) // NOLINT(runtime/int)
|
||||||
|
{
|
||||||
|
JSON_THROW(detail::out_of_range::create(410, detail::concat("array index ", s, " exceeds size_type"), nullptr)); // LCOV_EXCL_LINE
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<size_type>(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_PRIVATE_UNLESS_TESTED:
|
||||||
|
json_pointer top() const
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(empty()))
|
||||||
|
{
|
||||||
|
JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
json_pointer result = *this;
|
||||||
|
result.reference_tokens = {reference_tokens[0]};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*!
|
||||||
|
@brief create and return a reference to the pointed to value
|
||||||
|
|
||||||
|
@complexity Linear in the number of reference tokens.
|
||||||
|
|
||||||
|
@throw parse_error.109 if array index is not a number
|
||||||
|
@throw type_error.313 if value cannot be unflattened
|
||||||
|
*/
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
BasicJsonType& get_and_create(BasicJsonType& j) const
|
||||||
|
{
|
||||||
|
auto* result = &j;
|
||||||
|
|
||||||
|
// in case no reference tokens exist, return a reference to the JSON value
|
||||||
|
// j which will be overwritten by a primitive value
|
||||||
|
for (const auto& reference_token : reference_tokens)
|
||||||
|
{
|
||||||
|
switch (result->type())
|
||||||
|
{
|
||||||
|
case detail::value_t::null:
|
||||||
|
{
|
||||||
|
if (reference_token == "0")
|
||||||
|
{
|
||||||
|
// start a new array if reference token is 0
|
||||||
|
result = &result->operator[](0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// start a new object otherwise
|
||||||
|
result = &result->operator[](reference_token);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case detail::value_t::object:
|
||||||
|
{
|
||||||
|
// create an entry in the object
|
||||||
|
result = &result->operator[](reference_token);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case detail::value_t::array:
|
||||||
|
{
|
||||||
|
// create an entry in the array
|
||||||
|
result = &result->operator[](array_index<BasicJsonType>(reference_token));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
The following code is only reached if there exists a reference
|
||||||
|
token _and_ the current value is primitive. In this case, we have
|
||||||
|
an error situation, because primitive values may only occur as
|
||||||
|
single value; that is, with an empty list of reference tokens.
|
||||||
|
*/
|
||||||
|
case detail::value_t::string:
|
||||||
|
case detail::value_t::boolean:
|
||||||
|
case detail::value_t::number_integer:
|
||||||
|
case detail::value_t::number_unsigned:
|
||||||
|
case detail::value_t::number_float:
|
||||||
|
case detail::value_t::binary:
|
||||||
|
case detail::value_t::discarded:
|
||||||
|
default:
|
||||||
|
JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", &j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief return a reference to the pointed to value
|
||||||
|
|
||||||
|
@note This version does not throw if a value is not present, but tries to
|
||||||
|
create nested values instead. For instance, calling this function
|
||||||
|
with pointer `"/this/that"` on a null value is equivalent to calling
|
||||||
|
`operator[]("this").operator[]("that")` on that value, effectively
|
||||||
|
changing the null value to an object.
|
||||||
|
|
||||||
|
@param[in] ptr a JSON value
|
||||||
|
|
||||||
|
@return reference to the JSON value pointed to by the JSON pointer
|
||||||
|
|
||||||
|
@complexity Linear in the length of the JSON pointer.
|
||||||
|
|
||||||
|
@throw parse_error.106 if an array index begins with '0'
|
||||||
|
@throw parse_error.109 if an array index was not a number
|
||||||
|
@throw out_of_range.404 if the JSON pointer can not be resolved
|
||||||
|
*/
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
BasicJsonType& get_unchecked(BasicJsonType* ptr) const
|
||||||
|
{
|
||||||
|
for (const auto& reference_token : reference_tokens)
|
||||||
|
{
|
||||||
|
// convert null values to arrays or objects before continuing
|
||||||
|
if (ptr->is_null())
|
||||||
|
{
|
||||||
|
// check if reference token is a number
|
||||||
|
const bool nums =
|
||||||
|
std::all_of(reference_token.begin(), reference_token.end(),
|
||||||
|
[](const unsigned char x)
|
||||||
|
{
|
||||||
|
return std::isdigit(x);
|
||||||
|
});
|
||||||
|
|
||||||
|
// change value to array for numbers or "-" or to object otherwise
|
||||||
|
*ptr = (nums || reference_token == "-")
|
||||||
|
? detail::value_t::array
|
||||||
|
: detail::value_t::object;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ptr->type())
|
||||||
|
{
|
||||||
|
case detail::value_t::object:
|
||||||
|
{
|
||||||
|
// use unchecked object access
|
||||||
|
ptr = &ptr->operator[](reference_token);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case detail::value_t::array:
|
||||||
|
{
|
||||||
|
if (reference_token == "-")
|
||||||
|
{
|
||||||
|
// explicitly treat "-" as index beyond the end
|
||||||
|
ptr = &ptr->operator[](ptr->m_data.m_value.array->size());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// convert array index to number; unchecked access
|
||||||
|
ptr = &ptr->operator[](array_index<BasicJsonType>(reference_token));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case detail::value_t::null:
|
||||||
|
case detail::value_t::string:
|
||||||
|
case detail::value_t::boolean:
|
||||||
|
case detail::value_t::number_integer:
|
||||||
|
case detail::value_t::number_unsigned:
|
||||||
|
case detail::value_t::number_float:
|
||||||
|
case detail::value_t::binary:
|
||||||
|
case detail::value_t::discarded:
|
||||||
|
default:
|
||||||
|
JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@throw parse_error.106 if an array index begins with '0'
|
||||||
|
@throw parse_error.109 if an array index was not a number
|
||||||
|
@throw out_of_range.402 if the array index '-' is used
|
||||||
|
@throw out_of_range.404 if the JSON pointer can not be resolved
|
||||||
|
*/
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
BasicJsonType& get_checked(BasicJsonType* ptr) const
|
||||||
|
{
|
||||||
|
for (const auto& reference_token : reference_tokens)
|
||||||
|
{
|
||||||
|
switch (ptr->type())
|
||||||
|
{
|
||||||
|
case detail::value_t::object:
|
||||||
|
{
|
||||||
|
// note: at performs range check
|
||||||
|
ptr = &ptr->at(reference_token);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case detail::value_t::array:
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
|
||||||
|
{
|
||||||
|
// "-" always fails the range check
|
||||||
|
JSON_THROW(detail::out_of_range::create(402, detail::concat(
|
||||||
|
"array index '-' (", std::to_string(ptr->m_data.m_value.array->size()),
|
||||||
|
") is out of range"), ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// note: at performs range check
|
||||||
|
ptr = &ptr->at(array_index<BasicJsonType>(reference_token));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case detail::value_t::null:
|
||||||
|
case detail::value_t::string:
|
||||||
|
case detail::value_t::boolean:
|
||||||
|
case detail::value_t::number_integer:
|
||||||
|
case detail::value_t::number_unsigned:
|
||||||
|
case detail::value_t::number_float:
|
||||||
|
case detail::value_t::binary:
|
||||||
|
case detail::value_t::discarded:
|
||||||
|
default:
|
||||||
|
JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief return a const reference to the pointed to value
|
||||||
|
|
||||||
|
@param[in] ptr a JSON value
|
||||||
|
|
||||||
|
@return const reference to the JSON value pointed to by the JSON
|
||||||
|
pointer
|
||||||
|
|
||||||
|
@throw parse_error.106 if an array index begins with '0'
|
||||||
|
@throw parse_error.109 if an array index was not a number
|
||||||
|
@throw out_of_range.402 if the array index '-' is used
|
||||||
|
@throw out_of_range.404 if the JSON pointer can not be resolved
|
||||||
|
*/
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const
|
||||||
|
{
|
||||||
|
for (const auto& reference_token : reference_tokens)
|
||||||
|
{
|
||||||
|
switch (ptr->type())
|
||||||
|
{
|
||||||
|
case detail::value_t::object:
|
||||||
|
{
|
||||||
|
// use unchecked object access
|
||||||
|
ptr = &ptr->operator[](reference_token);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case detail::value_t::array:
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
|
||||||
|
{
|
||||||
|
// "-" cannot be used for const access
|
||||||
|
JSON_THROW(detail::out_of_range::create(402, detail::concat("array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), ") is out of range"), ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// use unchecked array access
|
||||||
|
ptr = &ptr->operator[](array_index<BasicJsonType>(reference_token));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case detail::value_t::null:
|
||||||
|
case detail::value_t::string:
|
||||||
|
case detail::value_t::boolean:
|
||||||
|
case detail::value_t::number_integer:
|
||||||
|
case detail::value_t::number_unsigned:
|
||||||
|
case detail::value_t::number_float:
|
||||||
|
case detail::value_t::binary:
|
||||||
|
case detail::value_t::discarded:
|
||||||
|
default:
|
||||||
|
JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@throw parse_error.106 if an array index begins with '0'
|
||||||
|
@throw parse_error.109 if an array index was not a number
|
||||||
|
@throw out_of_range.402 if the array index '-' is used
|
||||||
|
@throw out_of_range.404 if the JSON pointer can not be resolved
|
||||||
|
*/
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
const BasicJsonType& get_checked(const BasicJsonType* ptr) const
|
||||||
|
{
|
||||||
|
for (const auto& reference_token : reference_tokens)
|
||||||
|
{
|
||||||
|
switch (ptr->type())
|
||||||
|
{
|
||||||
|
case detail::value_t::object:
|
||||||
|
{
|
||||||
|
// note: at performs range check
|
||||||
|
ptr = &ptr->at(reference_token);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case detail::value_t::array:
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
|
||||||
|
{
|
||||||
|
// "-" always fails the range check
|
||||||
|
JSON_THROW(detail::out_of_range::create(402, detail::concat(
|
||||||
|
"array index '-' (", std::to_string(ptr->m_data.m_value.array->size()),
|
||||||
|
") is out of range"), ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// note: at performs range check
|
||||||
|
ptr = &ptr->at(array_index<BasicJsonType>(reference_token));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case detail::value_t::null:
|
||||||
|
case detail::value_t::string:
|
||||||
|
case detail::value_t::boolean:
|
||||||
|
case detail::value_t::number_integer:
|
||||||
|
case detail::value_t::number_unsigned:
|
||||||
|
case detail::value_t::number_float:
|
||||||
|
case detail::value_t::binary:
|
||||||
|
case detail::value_t::discarded:
|
||||||
|
default:
|
||||||
|
JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@throw parse_error.106 if an array index begins with '0'
|
||||||
|
@throw parse_error.109 if an array index was not a number
|
||||||
|
*/
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
bool contains(const BasicJsonType* ptr) const
|
||||||
|
{
|
||||||
|
for (const auto& reference_token : reference_tokens)
|
||||||
|
{
|
||||||
|
switch (ptr->type())
|
||||||
|
{
|
||||||
|
case detail::value_t::object:
|
||||||
|
{
|
||||||
|
if (!ptr->contains(reference_token))
|
||||||
|
{
|
||||||
|
// we did not find the key in the object
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = &ptr->operator[](reference_token);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case detail::value_t::array:
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
|
||||||
|
{
|
||||||
|
// "-" always fails the range check
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9")))
|
||||||
|
{
|
||||||
|
// invalid char
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1))
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9')))
|
||||||
|
{
|
||||||
|
// first char should be between '1' and '9'
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (std::size_t i = 1; i < reference_token.size(); i++)
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9')))
|
||||||
|
{
|
||||||
|
// other char should be between '0' and '9'
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto idx = array_index<BasicJsonType>(reference_token);
|
||||||
|
if (idx >= ptr->size())
|
||||||
|
{
|
||||||
|
// index out of range
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = &ptr->operator[](idx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case detail::value_t::null:
|
||||||
|
case detail::value_t::string:
|
||||||
|
case detail::value_t::boolean:
|
||||||
|
case detail::value_t::number_integer:
|
||||||
|
case detail::value_t::number_unsigned:
|
||||||
|
case detail::value_t::number_float:
|
||||||
|
case detail::value_t::binary:
|
||||||
|
case detail::value_t::discarded:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// we do not expect primitive values if there is still a
|
||||||
|
// reference token to process
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no reference token left means we found a primitive value
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief split the string input to reference tokens
|
||||||
|
|
||||||
|
@note This function is only called by the json_pointer constructor.
|
||||||
|
All exceptions below are documented there.
|
||||||
|
|
||||||
|
@throw parse_error.107 if the pointer is not empty or begins with '/'
|
||||||
|
@throw parse_error.108 if character '~' is not followed by '0' or '1'
|
||||||
|
*/
|
||||||
|
static std::vector<string_t> split(const string_t& reference_string)
|
||||||
|
{
|
||||||
|
std::vector<string_t> result;
|
||||||
|
|
||||||
|
// special case: empty reference string -> no reference tokens
|
||||||
|
if (reference_string.empty())
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if nonempty reference string begins with slash
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/'))
|
||||||
|
{
|
||||||
|
JSON_THROW(detail::parse_error::create(107, 1, detail::concat("JSON pointer must be empty or begin with '/' - was: '", reference_string, "'"), nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract the reference tokens:
|
||||||
|
// - slash: position of the last read slash (or end of string)
|
||||||
|
// - start: position after the previous slash
|
||||||
|
for (
|
||||||
|
// search for the first slash after the first character
|
||||||
|
std::size_t slash = reference_string.find_first_of('/', 1),
|
||||||
|
// set the beginning of the first reference token
|
||||||
|
start = 1;
|
||||||
|
// we can stop if start == 0 (if slash == string_t::npos)
|
||||||
|
start != 0;
|
||||||
|
// set the beginning of the next reference token
|
||||||
|
// (will eventually be 0 if slash == string_t::npos)
|
||||||
|
start = (slash == string_t::npos) ? 0 : slash + 1,
|
||||||
|
// find next slash
|
||||||
|
slash = reference_string.find_first_of('/', start))
|
||||||
|
{
|
||||||
|
// use the text between the beginning of the reference token
|
||||||
|
// (start) and the last slash (slash).
|
||||||
|
auto reference_token = reference_string.substr(start, slash - start);
|
||||||
|
|
||||||
|
// check reference tokens are properly escaped
|
||||||
|
for (std::size_t pos = reference_token.find_first_of('~');
|
||||||
|
pos != string_t::npos;
|
||||||
|
pos = reference_token.find_first_of('~', pos + 1))
|
||||||
|
{
|
||||||
|
JSON_ASSERT(reference_token[pos] == '~');
|
||||||
|
|
||||||
|
// ~ must be followed by 0 or 1
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 ||
|
||||||
|
(reference_token[pos + 1] != '0' &&
|
||||||
|
reference_token[pos + 1] != '1')))
|
||||||
|
{
|
||||||
|
JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'", nullptr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// finally, store the reference token
|
||||||
|
detail::unescape(reference_token);
|
||||||
|
result.push_back(reference_token);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*!
|
||||||
|
@param[in] reference_string the reference string to the current value
|
||||||
|
@param[in] value the value to consider
|
||||||
|
@param[in,out] result the result object to insert values to
|
||||||
|
|
||||||
|
@note Empty objects or arrays are flattened to `null`.
|
||||||
|
*/
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
static void flatten(const string_t& reference_string,
|
||||||
|
const BasicJsonType& value,
|
||||||
|
BasicJsonType& result)
|
||||||
|
{
|
||||||
|
switch (value.type())
|
||||||
|
{
|
||||||
|
case detail::value_t::array:
|
||||||
|
{
|
||||||
|
if (value.m_data.m_value.array->empty())
|
||||||
|
{
|
||||||
|
// flatten empty array as null
|
||||||
|
result[reference_string] = nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// iterate array and use index as reference string
|
||||||
|
for (std::size_t i = 0; i < value.m_data.m_value.array->size(); ++i)
|
||||||
|
{
|
||||||
|
flatten(detail::concat(reference_string, '/', std::to_string(i)),
|
||||||
|
value.m_data.m_value.array->operator[](i), result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case detail::value_t::object:
|
||||||
|
{
|
||||||
|
if (value.m_data.m_value.object->empty())
|
||||||
|
{
|
||||||
|
// flatten empty object as null
|
||||||
|
result[reference_string] = nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// iterate object and use keys as reference string
|
||||||
|
for (const auto& element : *value.m_data.m_value.object)
|
||||||
|
{
|
||||||
|
flatten(detail::concat(reference_string, '/', detail::escape(element.first)), element.second, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case detail::value_t::null:
|
||||||
|
case detail::value_t::string:
|
||||||
|
case detail::value_t::boolean:
|
||||||
|
case detail::value_t::number_integer:
|
||||||
|
case detail::value_t::number_unsigned:
|
||||||
|
case detail::value_t::number_float:
|
||||||
|
case detail::value_t::binary:
|
||||||
|
case detail::value_t::discarded:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// add primitive value with its reference string
|
||||||
|
result[reference_string] = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@param[in] value flattened JSON
|
||||||
|
|
||||||
|
@return unflattened JSON
|
||||||
|
|
||||||
|
@throw parse_error.109 if array index is not a number
|
||||||
|
@throw type_error.314 if value is not an object
|
||||||
|
@throw type_error.315 if object values are not primitive
|
||||||
|
@throw type_error.313 if value cannot be unflattened
|
||||||
|
*/
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
static BasicJsonType
|
||||||
|
unflatten(const BasicJsonType& value)
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!value.is_object()))
|
||||||
|
{
|
||||||
|
JSON_THROW(detail::type_error::create(314, "only objects can be unflattened", &value));
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicJsonType result;
|
||||||
|
|
||||||
|
// iterate the JSON object values
|
||||||
|
for (const auto& element : *value.m_data.m_value.object)
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive()))
|
||||||
|
{
|
||||||
|
JSON_THROW(detail::type_error::create(315, "values in object must be primitive", &element.second));
|
||||||
|
}
|
||||||
|
|
||||||
|
// assign value to reference pointed to by JSON pointer; Note that if
|
||||||
|
// the JSON pointer is "" (i.e., points to the whole value), function
|
||||||
|
// get_and_create returns a reference to result itself. An assignment
|
||||||
|
// will then create a primitive value.
|
||||||
|
json_pointer(element.first).get_and_create(result) = element.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// can't use conversion operator because of ambiguity
|
||||||
|
json_pointer<string_t> convert() const&
|
||||||
|
{
|
||||||
|
json_pointer<string_t> result;
|
||||||
|
result.reference_tokens = reference_tokens;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
json_pointer<string_t> convert()&&
|
||||||
|
{
|
||||||
|
json_pointer<string_t> result;
|
||||||
|
result.reference_tokens = std::move(reference_tokens);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
#if JSON_HAS_THREE_WAY_COMPARISON
|
||||||
|
/// @brief compares two JSON pointers for equality
|
||||||
|
/// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
|
||||||
|
template<typename RefStringTypeRhs>
|
||||||
|
bool operator==(const json_pointer<RefStringTypeRhs>& rhs) const noexcept
|
||||||
|
{
|
||||||
|
return reference_tokens == rhs.reference_tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief compares JSON pointer and string for equality
|
||||||
|
/// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
|
||||||
|
JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer))
|
||||||
|
bool operator==(const string_t& rhs) const
|
||||||
|
{
|
||||||
|
return *this == json_pointer(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 3-way compares two JSON pointers
|
||||||
|
template<typename RefStringTypeRhs>
|
||||||
|
std::strong_ordering operator<=>(const json_pointer<RefStringTypeRhs>& rhs) const noexcept // *NOPAD*
|
||||||
|
{
|
||||||
|
return reference_tokens <=> rhs.reference_tokens; // *NOPAD*
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/// @brief compares two JSON pointers for equality
|
||||||
|
/// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
|
||||||
|
template<typename RefStringTypeLhs, typename RefStringTypeRhs>
|
||||||
|
// NOLINTNEXTLINE(readability-redundant-declaration)
|
||||||
|
friend bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
|
||||||
|
const json_pointer<RefStringTypeRhs>& rhs) noexcept;
|
||||||
|
|
||||||
|
/// @brief compares JSON pointer and string for equality
|
||||||
|
/// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
|
||||||
|
template<typename RefStringTypeLhs, typename StringType>
|
||||||
|
// NOLINTNEXTLINE(readability-redundant-declaration)
|
||||||
|
friend bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
|
||||||
|
const StringType& rhs);
|
||||||
|
|
||||||
|
/// @brief compares string and JSON pointer for equality
|
||||||
|
/// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
|
||||||
|
template<typename RefStringTypeRhs, typename StringType>
|
||||||
|
// NOLINTNEXTLINE(readability-redundant-declaration)
|
||||||
|
friend bool operator==(const StringType& lhs,
|
||||||
|
const json_pointer<RefStringTypeRhs>& rhs);
|
||||||
|
|
||||||
|
/// @brief compares two JSON pointers for inequality
|
||||||
|
/// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/
|
||||||
|
template<typename RefStringTypeLhs, typename RefStringTypeRhs>
|
||||||
|
// NOLINTNEXTLINE(readability-redundant-declaration)
|
||||||
|
friend bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
|
||||||
|
const json_pointer<RefStringTypeRhs>& rhs) noexcept;
|
||||||
|
|
||||||
|
/// @brief compares JSON pointer and string for inequality
|
||||||
|
/// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/
|
||||||
|
template<typename RefStringTypeLhs, typename StringType>
|
||||||
|
// NOLINTNEXTLINE(readability-redundant-declaration)
|
||||||
|
friend bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
|
||||||
|
const StringType& rhs);
|
||||||
|
|
||||||
|
/// @brief compares string and JSON pointer for inequality
|
||||||
|
/// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/
|
||||||
|
template<typename RefStringTypeRhs, typename StringType>
|
||||||
|
// NOLINTNEXTLINE(readability-redundant-declaration)
|
||||||
|
friend bool operator!=(const StringType& lhs,
|
||||||
|
const json_pointer<RefStringTypeRhs>& rhs);
|
||||||
|
|
||||||
|
/// @brief compares two JSON pointer for less-than
|
||||||
|
template<typename RefStringTypeLhs, typename RefStringTypeRhs>
|
||||||
|
// NOLINTNEXTLINE(readability-redundant-declaration)
|
||||||
|
friend bool operator<(const json_pointer<RefStringTypeLhs>& lhs,
|
||||||
|
const json_pointer<RefStringTypeRhs>& rhs) noexcept;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// the reference tokens
|
||||||
|
std::vector<string_t> reference_tokens;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if !JSON_HAS_THREE_WAY_COMPARISON
|
||||||
|
// functions cannot be defined inside class due to ODR violations
|
||||||
|
template<typename RefStringTypeLhs, typename RefStringTypeRhs>
|
||||||
|
inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
|
||||||
|
const json_pointer<RefStringTypeRhs>& rhs) noexcept
|
||||||
|
{
|
||||||
|
return lhs.reference_tokens == rhs.reference_tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename RefStringTypeLhs,
|
||||||
|
typename StringType = typename json_pointer<RefStringTypeLhs>::string_t>
|
||||||
|
JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer))
|
||||||
|
inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
|
||||||
|
const StringType& rhs)
|
||||||
|
{
|
||||||
|
return lhs == json_pointer<RefStringTypeLhs>(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename RefStringTypeRhs,
|
||||||
|
typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>
|
||||||
|
JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer))
|
||||||
|
inline bool operator==(const StringType& lhs,
|
||||||
|
const json_pointer<RefStringTypeRhs>& rhs)
|
||||||
|
{
|
||||||
|
return json_pointer<RefStringTypeRhs>(lhs) == rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename RefStringTypeLhs, typename RefStringTypeRhs>
|
||||||
|
inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
|
||||||
|
const json_pointer<RefStringTypeRhs>& rhs) noexcept
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename RefStringTypeLhs,
|
||||||
|
typename StringType = typename json_pointer<RefStringTypeLhs>::string_t>
|
||||||
|
JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer))
|
||||||
|
inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
|
||||||
|
const StringType& rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename RefStringTypeRhs,
|
||||||
|
typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>
|
||||||
|
JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer))
|
||||||
|
inline bool operator!=(const StringType& lhs,
|
||||||
|
const json_pointer<RefStringTypeRhs>& rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename RefStringTypeLhs, typename RefStringTypeRhs>
|
||||||
|
inline bool operator<(const json_pointer<RefStringTypeLhs>& lhs,
|
||||||
|
const json_pointer<RefStringTypeRhs>& rhs) noexcept
|
||||||
|
{
|
||||||
|
return lhs.reference_tokens < rhs.reference_tokens;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <nlohmann/detail/abi_macros.hpp>
|
||||||
|
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
class json_ref
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using value_type = BasicJsonType;
|
||||||
|
|
||||||
|
json_ref(value_type&& value)
|
||||||
|
: owned_value(std::move(value))
|
||||||
|
{}
|
||||||
|
|
||||||
|
json_ref(const value_type& value)
|
||||||
|
: value_ref(&value)
|
||||||
|
{}
|
||||||
|
|
||||||
|
json_ref(std::initializer_list<json_ref> init)
|
||||||
|
: owned_value(init)
|
||||||
|
{}
|
||||||
|
|
||||||
|
template <
|
||||||
|
class... Args,
|
||||||
|
enable_if_t<std::is_constructible<value_type, Args...>::value, int> = 0 >
|
||||||
|
json_ref(Args && ... args)
|
||||||
|
: owned_value(std::forward<Args>(args)...)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// class should be movable only
|
||||||
|
json_ref(json_ref&&) noexcept = default;
|
||||||
|
json_ref(const json_ref&) = delete;
|
||||||
|
json_ref& operator=(const json_ref&) = delete;
|
||||||
|
json_ref& operator=(json_ref&&) = delete;
|
||||||
|
~json_ref() = default;
|
||||||
|
|
||||||
|
value_type moved_or_copied() const
|
||||||
|
{
|
||||||
|
if (value_ref == nullptr)
|
||||||
|
{
|
||||||
|
return std::move(owned_value);
|
||||||
|
}
|
||||||
|
return *value_ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
value_type const& operator*() const
|
||||||
|
{
|
||||||
|
return value_ref ? *value_ref : owned_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
value_type const* operator->() const
|
||||||
|
{
|
||||||
|
return &** this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable value_type owned_value = nullptr;
|
||||||
|
value_type const* value_ref = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,482 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <utility> // declval, pair
|
||||||
|
#include <nlohmann/detail/meta/detected.hpp>
|
||||||
|
#include <nlohmann/thirdparty/hedley/hedley.hpp>
|
||||||
|
|
||||||
|
// This file contains all internal macro definitions (except those affecting ABI)
|
||||||
|
// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them
|
||||||
|
|
||||||
|
#include <nlohmann/detail/abi_macros.hpp>
|
||||||
|
|
||||||
|
// exclude unsupported compilers
|
||||||
|
#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK)
|
||||||
|
#if defined(__clang__)
|
||||||
|
#if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400
|
||||||
|
#error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers"
|
||||||
|
#endif
|
||||||
|
#elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER))
|
||||||
|
#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800
|
||||||
|
#error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// C++ language standard detection
|
||||||
|
// if the user manually specified the used c++ version this is skipped
|
||||||
|
#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11)
|
||||||
|
#if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
|
||||||
|
#define JSON_HAS_CPP_20
|
||||||
|
#define JSON_HAS_CPP_17
|
||||||
|
#define JSON_HAS_CPP_14
|
||||||
|
#elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
|
||||||
|
#define JSON_HAS_CPP_17
|
||||||
|
#define JSON_HAS_CPP_14
|
||||||
|
#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)
|
||||||
|
#define JSON_HAS_CPP_14
|
||||||
|
#endif
|
||||||
|
// the cpp 11 flag is always specified because it is the minimal required version
|
||||||
|
#define JSON_HAS_CPP_11
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __has_include
|
||||||
|
#if __has_include(<version>)
|
||||||
|
#include <version>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM)
|
||||||
|
#ifdef JSON_HAS_CPP_17
|
||||||
|
#if defined(__cpp_lib_filesystem)
|
||||||
|
#define JSON_HAS_FILESYSTEM 1
|
||||||
|
#elif defined(__cpp_lib_experimental_filesystem)
|
||||||
|
#define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1
|
||||||
|
#elif !defined(__has_include)
|
||||||
|
#define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1
|
||||||
|
#elif __has_include(<filesystem>)
|
||||||
|
#define JSON_HAS_FILESYSTEM 1
|
||||||
|
#elif __has_include(<experimental/filesystem>)
|
||||||
|
#define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/
|
||||||
|
#if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8
|
||||||
|
#undef JSON_HAS_FILESYSTEM
|
||||||
|
#undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support
|
||||||
|
#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 8
|
||||||
|
#undef JSON_HAS_FILESYSTEM
|
||||||
|
#undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support
|
||||||
|
#if defined(__clang_major__) && __clang_major__ < 7
|
||||||
|
#undef JSON_HAS_FILESYSTEM
|
||||||
|
#undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER < 1914
|
||||||
|
#undef JSON_HAS_FILESYSTEM
|
||||||
|
#undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// no filesystem support before iOS 13
|
||||||
|
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000
|
||||||
|
#undef JSON_HAS_FILESYSTEM
|
||||||
|
#undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// no filesystem support before macOS Catalina
|
||||||
|
#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500
|
||||||
|
#undef JSON_HAS_FILESYSTEM
|
||||||
|
#undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||||
|
#define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef JSON_HAS_FILESYSTEM
|
||||||
|
#define JSON_HAS_FILESYSTEM 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef JSON_HAS_THREE_WAY_COMPARISON
|
||||||
|
#if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L \
|
||||||
|
&& defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L
|
||||||
|
#define JSON_HAS_THREE_WAY_COMPARISON 1
|
||||||
|
#else
|
||||||
|
#define JSON_HAS_THREE_WAY_COMPARISON 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef JSON_HAS_RANGES
|
||||||
|
// ranges header shipping in GCC 11.1.0 (released 2021-04-27) has syntax error
|
||||||
|
#if defined(__GLIBCXX__) && __GLIBCXX__ == 20210427
|
||||||
|
#define JSON_HAS_RANGES 0
|
||||||
|
#elif defined(__cpp_lib_ranges)
|
||||||
|
#define JSON_HAS_RANGES 1
|
||||||
|
#else
|
||||||
|
#define JSON_HAS_RANGES 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef JSON_HAS_STATIC_RTTI
|
||||||
|
#if !defined(_HAS_STATIC_RTTI) || _HAS_STATIC_RTTI != 0
|
||||||
|
#define JSON_HAS_STATIC_RTTI 1
|
||||||
|
#else
|
||||||
|
#define JSON_HAS_STATIC_RTTI 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef JSON_HAS_CPP_17
|
||||||
|
#define JSON_INLINE_VARIABLE inline
|
||||||
|
#else
|
||||||
|
#define JSON_INLINE_VARIABLE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if JSON_HEDLEY_HAS_ATTRIBUTE(no_unique_address)
|
||||||
|
#define JSON_NO_UNIQUE_ADDRESS [[no_unique_address]]
|
||||||
|
#else
|
||||||
|
#define JSON_NO_UNIQUE_ADDRESS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// disable documentation warnings on clang
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wdocumentation"
|
||||||
|
#pragma clang diagnostic ignored "-Wdocumentation-unknown-command"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// allow disabling exceptions
|
||||||
|
#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)
|
||||||
|
#define JSON_THROW(exception) throw exception
|
||||||
|
#define JSON_TRY try
|
||||||
|
#define JSON_CATCH(exception) catch(exception)
|
||||||
|
#define JSON_INTERNAL_CATCH(exception) catch(exception)
|
||||||
|
#else
|
||||||
|
#include <cstdlib>
|
||||||
|
#define JSON_THROW(exception) std::abort()
|
||||||
|
#define JSON_TRY if(true)
|
||||||
|
#define JSON_CATCH(exception) if(false)
|
||||||
|
#define JSON_INTERNAL_CATCH(exception) if(false)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// override exception macros
|
||||||
|
#if defined(JSON_THROW_USER)
|
||||||
|
#undef JSON_THROW
|
||||||
|
#define JSON_THROW JSON_THROW_USER
|
||||||
|
#endif
|
||||||
|
#if defined(JSON_TRY_USER)
|
||||||
|
#undef JSON_TRY
|
||||||
|
#define JSON_TRY JSON_TRY_USER
|
||||||
|
#endif
|
||||||
|
#if defined(JSON_CATCH_USER)
|
||||||
|
#undef JSON_CATCH
|
||||||
|
#define JSON_CATCH JSON_CATCH_USER
|
||||||
|
#undef JSON_INTERNAL_CATCH
|
||||||
|
#define JSON_INTERNAL_CATCH JSON_CATCH_USER
|
||||||
|
#endif
|
||||||
|
#if defined(JSON_INTERNAL_CATCH_USER)
|
||||||
|
#undef JSON_INTERNAL_CATCH
|
||||||
|
#define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// allow overriding assert
|
||||||
|
#if !defined(JSON_ASSERT)
|
||||||
|
#include <cassert> // assert
|
||||||
|
#define JSON_ASSERT(x) assert(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// allow to access some private functions (needed by the test suite)
|
||||||
|
#if defined(JSON_TESTS_PRIVATE)
|
||||||
|
#define JSON_PRIVATE_UNLESS_TESTED public
|
||||||
|
#else
|
||||||
|
#define JSON_PRIVATE_UNLESS_TESTED private
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief macro to briefly define a mapping between an enum and JSON
|
||||||
|
@def NLOHMANN_JSON_SERIALIZE_ENUM
|
||||||
|
@since version 3.4.0
|
||||||
|
*/
|
||||||
|
#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \
|
||||||
|
template<typename BasicJsonType> \
|
||||||
|
inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \
|
||||||
|
{ \
|
||||||
|
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
|
||||||
|
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
|
||||||
|
auto it = std::find_if(std::begin(m), std::end(m), \
|
||||||
|
[e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
|
||||||
|
{ \
|
||||||
|
return ej_pair.first == e; \
|
||||||
|
}); \
|
||||||
|
j = ((it != std::end(m)) ? it : std::begin(m))->second; \
|
||||||
|
} \
|
||||||
|
template<typename BasicJsonType> \
|
||||||
|
inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \
|
||||||
|
{ \
|
||||||
|
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
|
||||||
|
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
|
||||||
|
auto it = std::find_if(std::begin(m), std::end(m), \
|
||||||
|
[&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
|
||||||
|
{ \
|
||||||
|
return ej_pair.second == j; \
|
||||||
|
}); \
|
||||||
|
e = ((it != std::end(m)) ? it : std::begin(m))->first; \
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ugly macros to avoid uglier copy-paste when specializing basic_json. They
|
||||||
|
// may be removed in the future once the class is split.
|
||||||
|
|
||||||
|
#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \
|
||||||
|
template<template<typename, typename, typename...> class ObjectType, \
|
||||||
|
template<typename, typename...> class ArrayType, \
|
||||||
|
class StringType, class BooleanType, class NumberIntegerType, \
|
||||||
|
class NumberUnsignedType, class NumberFloatType, \
|
||||||
|
template<typename> class AllocatorType, \
|
||||||
|
template<typename, typename = void> class JSONSerializer, \
|
||||||
|
class BinaryType, \
|
||||||
|
class CustomBaseClass>
|
||||||
|
|
||||||
|
#define NLOHMANN_BASIC_JSON_TPL \
|
||||||
|
basic_json<ObjectType, ArrayType, StringType, BooleanType, \
|
||||||
|
NumberIntegerType, NumberUnsignedType, NumberFloatType, \
|
||||||
|
AllocatorType, JSONSerializer, BinaryType, CustomBaseClass>
|
||||||
|
|
||||||
|
// Macros to simplify conversion from/to types
|
||||||
|
|
||||||
|
#define NLOHMANN_JSON_EXPAND( x ) x
|
||||||
|
#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME
|
||||||
|
#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \
|
||||||
|
NLOHMANN_JSON_PASTE64, \
|
||||||
|
NLOHMANN_JSON_PASTE63, \
|
||||||
|
NLOHMANN_JSON_PASTE62, \
|
||||||
|
NLOHMANN_JSON_PASTE61, \
|
||||||
|
NLOHMANN_JSON_PASTE60, \
|
||||||
|
NLOHMANN_JSON_PASTE59, \
|
||||||
|
NLOHMANN_JSON_PASTE58, \
|
||||||
|
NLOHMANN_JSON_PASTE57, \
|
||||||
|
NLOHMANN_JSON_PASTE56, \
|
||||||
|
NLOHMANN_JSON_PASTE55, \
|
||||||
|
NLOHMANN_JSON_PASTE54, \
|
||||||
|
NLOHMANN_JSON_PASTE53, \
|
||||||
|
NLOHMANN_JSON_PASTE52, \
|
||||||
|
NLOHMANN_JSON_PASTE51, \
|
||||||
|
NLOHMANN_JSON_PASTE50, \
|
||||||
|
NLOHMANN_JSON_PASTE49, \
|
||||||
|
NLOHMANN_JSON_PASTE48, \
|
||||||
|
NLOHMANN_JSON_PASTE47, \
|
||||||
|
NLOHMANN_JSON_PASTE46, \
|
||||||
|
NLOHMANN_JSON_PASTE45, \
|
||||||
|
NLOHMANN_JSON_PASTE44, \
|
||||||
|
NLOHMANN_JSON_PASTE43, \
|
||||||
|
NLOHMANN_JSON_PASTE42, \
|
||||||
|
NLOHMANN_JSON_PASTE41, \
|
||||||
|
NLOHMANN_JSON_PASTE40, \
|
||||||
|
NLOHMANN_JSON_PASTE39, \
|
||||||
|
NLOHMANN_JSON_PASTE38, \
|
||||||
|
NLOHMANN_JSON_PASTE37, \
|
||||||
|
NLOHMANN_JSON_PASTE36, \
|
||||||
|
NLOHMANN_JSON_PASTE35, \
|
||||||
|
NLOHMANN_JSON_PASTE34, \
|
||||||
|
NLOHMANN_JSON_PASTE33, \
|
||||||
|
NLOHMANN_JSON_PASTE32, \
|
||||||
|
NLOHMANN_JSON_PASTE31, \
|
||||||
|
NLOHMANN_JSON_PASTE30, \
|
||||||
|
NLOHMANN_JSON_PASTE29, \
|
||||||
|
NLOHMANN_JSON_PASTE28, \
|
||||||
|
NLOHMANN_JSON_PASTE27, \
|
||||||
|
NLOHMANN_JSON_PASTE26, \
|
||||||
|
NLOHMANN_JSON_PASTE25, \
|
||||||
|
NLOHMANN_JSON_PASTE24, \
|
||||||
|
NLOHMANN_JSON_PASTE23, \
|
||||||
|
NLOHMANN_JSON_PASTE22, \
|
||||||
|
NLOHMANN_JSON_PASTE21, \
|
||||||
|
NLOHMANN_JSON_PASTE20, \
|
||||||
|
NLOHMANN_JSON_PASTE19, \
|
||||||
|
NLOHMANN_JSON_PASTE18, \
|
||||||
|
NLOHMANN_JSON_PASTE17, \
|
||||||
|
NLOHMANN_JSON_PASTE16, \
|
||||||
|
NLOHMANN_JSON_PASTE15, \
|
||||||
|
NLOHMANN_JSON_PASTE14, \
|
||||||
|
NLOHMANN_JSON_PASTE13, \
|
||||||
|
NLOHMANN_JSON_PASTE12, \
|
||||||
|
NLOHMANN_JSON_PASTE11, \
|
||||||
|
NLOHMANN_JSON_PASTE10, \
|
||||||
|
NLOHMANN_JSON_PASTE9, \
|
||||||
|
NLOHMANN_JSON_PASTE8, \
|
||||||
|
NLOHMANN_JSON_PASTE7, \
|
||||||
|
NLOHMANN_JSON_PASTE6, \
|
||||||
|
NLOHMANN_JSON_PASTE5, \
|
||||||
|
NLOHMANN_JSON_PASTE4, \
|
||||||
|
NLOHMANN_JSON_PASTE3, \
|
||||||
|
NLOHMANN_JSON_PASTE2, \
|
||||||
|
NLOHMANN_JSON_PASTE1)(__VA_ARGS__))
|
||||||
|
#define NLOHMANN_JSON_PASTE2(func, v1) func(v1)
|
||||||
|
#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2)
|
||||||
|
#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3)
|
||||||
|
#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4)
|
||||||
|
#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5)
|
||||||
|
#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6)
|
||||||
|
#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7)
|
||||||
|
#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8)
|
||||||
|
#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9)
|
||||||
|
#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10)
|
||||||
|
#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)
|
||||||
|
#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12)
|
||||||
|
#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13)
|
||||||
|
#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14)
|
||||||
|
#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15)
|
||||||
|
#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16)
|
||||||
|
#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17)
|
||||||
|
#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18)
|
||||||
|
#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19)
|
||||||
|
#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20)
|
||||||
|
#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21)
|
||||||
|
#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22)
|
||||||
|
#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23)
|
||||||
|
#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24)
|
||||||
|
#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25)
|
||||||
|
#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26)
|
||||||
|
#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27)
|
||||||
|
#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28)
|
||||||
|
#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29)
|
||||||
|
#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30)
|
||||||
|
#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31)
|
||||||
|
#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32)
|
||||||
|
#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33)
|
||||||
|
#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34)
|
||||||
|
#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35)
|
||||||
|
#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36)
|
||||||
|
#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37)
|
||||||
|
#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38)
|
||||||
|
#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39)
|
||||||
|
#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40)
|
||||||
|
#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41)
|
||||||
|
#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42)
|
||||||
|
#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43)
|
||||||
|
#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44)
|
||||||
|
#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45)
|
||||||
|
#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46)
|
||||||
|
#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47)
|
||||||
|
#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48)
|
||||||
|
#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49)
|
||||||
|
#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50)
|
||||||
|
#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51)
|
||||||
|
#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52)
|
||||||
|
#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53)
|
||||||
|
#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54)
|
||||||
|
#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55)
|
||||||
|
#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56)
|
||||||
|
#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57)
|
||||||
|
#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58)
|
||||||
|
#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59)
|
||||||
|
#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60)
|
||||||
|
#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61)
|
||||||
|
#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62)
|
||||||
|
#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63)
|
||||||
|
|
||||||
|
#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1;
|
||||||
|
#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1);
|
||||||
|
#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief macro
|
||||||
|
@def NLOHMANN_DEFINE_TYPE_INTRUSIVE
|
||||||
|
@since version 3.9.0
|
||||||
|
*/
|
||||||
|
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \
|
||||||
|
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
|
||||||
|
friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
|
||||||
|
|
||||||
|
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \
|
||||||
|
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
|
||||||
|
friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
|
||||||
|
|
||||||
|
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \
|
||||||
|
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief macro
|
||||||
|
@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
|
||||||
|
@since version 3.9.0
|
||||||
|
*/
|
||||||
|
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \
|
||||||
|
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
|
||||||
|
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
|
||||||
|
|
||||||
|
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \
|
||||||
|
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }
|
||||||
|
|
||||||
|
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \
|
||||||
|
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
|
||||||
|
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
|
||||||
|
|
||||||
|
// inspired from https://stackoverflow.com/a/26745591
|
||||||
|
// allows to call any std function as if (e.g. with begin):
|
||||||
|
// using std::begin; begin(x);
|
||||||
|
//
|
||||||
|
// it allows using the detected idiom to retrieve the return type
|
||||||
|
// of such an expression
|
||||||
|
#define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name) \
|
||||||
|
namespace detail { \
|
||||||
|
using std::std_name; \
|
||||||
|
\
|
||||||
|
template<typename... T> \
|
||||||
|
using result_of_##std_name = decltype(std_name(std::declval<T>()...)); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
namespace detail2 { \
|
||||||
|
struct std_name##_tag \
|
||||||
|
{ \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
template<typename... T> \
|
||||||
|
std_name##_tag std_name(T&&...); \
|
||||||
|
\
|
||||||
|
template<typename... T> \
|
||||||
|
using result_of_##std_name = decltype(std_name(std::declval<T>()...)); \
|
||||||
|
\
|
||||||
|
template<typename... T> \
|
||||||
|
struct would_call_std_##std_name \
|
||||||
|
{ \
|
||||||
|
static constexpr auto const value = ::nlohmann::detail:: \
|
||||||
|
is_detected_exact<std_name##_tag, result_of_##std_name, T...>::value; \
|
||||||
|
}; \
|
||||||
|
} /* namespace detail2 */ \
|
||||||
|
\
|
||||||
|
template<typename... T> \
|
||||||
|
struct would_call_std_##std_name : detail2::would_call_std_##std_name<T...> \
|
||||||
|
{ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef JSON_USE_IMPLICIT_CONVERSIONS
|
||||||
|
#define JSON_USE_IMPLICIT_CONVERSIONS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if JSON_USE_IMPLICIT_CONVERSIONS
|
||||||
|
#define JSON_EXPLICIT
|
||||||
|
#else
|
||||||
|
#define JSON_EXPLICIT explicit
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef JSON_DISABLE_ENUM_SERIALIZATION
|
||||||
|
#define JSON_DISABLE_ENUM_SERIALIZATION 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef JSON_USE_GLOBAL_UDLS
|
||||||
|
#define JSON_USE_GLOBAL_UDLS 1
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// restore clang diagnostic settings
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// clean up
|
||||||
|
#undef JSON_ASSERT
|
||||||
|
#undef JSON_INTERNAL_CATCH
|
||||||
|
#undef JSON_THROW
|
||||||
|
#undef JSON_PRIVATE_UNLESS_TESTED
|
||||||
|
#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION
|
||||||
|
#undef NLOHMANN_BASIC_JSON_TPL
|
||||||
|
#undef JSON_EXPLICIT
|
||||||
|
#undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL
|
||||||
|
#undef JSON_INLINE_VARIABLE
|
||||||
|
#undef JSON_NO_UNIQUE_ADDRESS
|
||||||
|
#undef JSON_DISABLE_ENUM_SERIALIZATION
|
||||||
|
#undef JSON_USE_GLOBAL_UDLS
|
||||||
|
|
||||||
|
#ifndef JSON_TEST_KEEP_MACROS
|
||||||
|
#undef JSON_CATCH
|
||||||
|
#undef JSON_TRY
|
||||||
|
#undef JSON_HAS_CPP_11
|
||||||
|
#undef JSON_HAS_CPP_14
|
||||||
|
#undef JSON_HAS_CPP_17
|
||||||
|
#undef JSON_HAS_CPP_20
|
||||||
|
#undef JSON_HAS_FILESYSTEM
|
||||||
|
#undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||||
|
#undef JSON_HAS_THREE_WAY_COMPARISON
|
||||||
|
#undef JSON_HAS_RANGES
|
||||||
|
#undef JSON_HAS_STATIC_RTTI
|
||||||
|
#undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <nlohmann/thirdparty/hedley/hedley_undef.hpp>
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <nlohmann/detail/macro_scope.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin);
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <nlohmann/detail/macro_scope.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end);
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,171 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-FileCopyrightText: 2018 The Abseil Authors
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array> // array
|
||||||
|
#include <cstddef> // size_t
|
||||||
|
#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type
|
||||||
|
#include <utility> // index_sequence, make_index_sequence, index_sequence_for
|
||||||
|
|
||||||
|
#include <nlohmann/detail/macro_scope.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
|
||||||
|
|
||||||
|
#ifdef JSON_HAS_CPP_14
|
||||||
|
|
||||||
|
// the following utilities are natively available in C++14
|
||||||
|
using std::enable_if_t;
|
||||||
|
using std::index_sequence;
|
||||||
|
using std::make_index_sequence;
|
||||||
|
using std::index_sequence_for;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// alias templates to reduce boilerplate
|
||||||
|
template<bool B, typename T = void>
|
||||||
|
using enable_if_t = typename std::enable_if<B, T>::type;
|
||||||
|
|
||||||
|
// The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h
|
||||||
|
// which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0.
|
||||||
|
|
||||||
|
//// START OF CODE FROM GOOGLE ABSEIL
|
||||||
|
|
||||||
|
// integer_sequence
|
||||||
|
//
|
||||||
|
// Class template representing a compile-time integer sequence. An instantiation
|
||||||
|
// of `integer_sequence<T, Ints...>` has a sequence of integers encoded in its
|
||||||
|
// type through its template arguments (which is a common need when
|
||||||
|
// working with C++11 variadic templates). `absl::integer_sequence` is designed
|
||||||
|
// to be a drop-in replacement for C++14's `std::integer_sequence`.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// template< class T, T... Ints >
|
||||||
|
// void user_function(integer_sequence<T, Ints...>);
|
||||||
|
//
|
||||||
|
// int main()
|
||||||
|
// {
|
||||||
|
// // user_function's `T` will be deduced to `int` and `Ints...`
|
||||||
|
// // will be deduced to `0, 1, 2, 3, 4`.
|
||||||
|
// user_function(make_integer_sequence<int, 5>());
|
||||||
|
// }
|
||||||
|
template <typename T, T... Ints>
|
||||||
|
struct integer_sequence
|
||||||
|
{
|
||||||
|
using value_type = T;
|
||||||
|
static constexpr std::size_t size() noexcept
|
||||||
|
{
|
||||||
|
return sizeof...(Ints);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// index_sequence
|
||||||
|
//
|
||||||
|
// A helper template for an `integer_sequence` of `size_t`,
|
||||||
|
// `absl::index_sequence` is designed to be a drop-in replacement for C++14's
|
||||||
|
// `std::index_sequence`.
|
||||||
|
template <size_t... Ints>
|
||||||
|
using index_sequence = integer_sequence<size_t, Ints...>;
|
||||||
|
|
||||||
|
namespace utility_internal
|
||||||
|
{
|
||||||
|
|
||||||
|
template <typename Seq, size_t SeqSize, size_t Rem>
|
||||||
|
struct Extend;
|
||||||
|
|
||||||
|
// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency.
|
||||||
|
template <typename T, T... Ints, size_t SeqSize>
|
||||||
|
struct Extend<integer_sequence<T, Ints...>, SeqSize, 0>
|
||||||
|
{
|
||||||
|
using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, T... Ints, size_t SeqSize>
|
||||||
|
struct Extend<integer_sequence<T, Ints...>, SeqSize, 1>
|
||||||
|
{
|
||||||
|
using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Recursion helper for 'make_integer_sequence<T, N>'.
|
||||||
|
// 'Gen<T, N>::type' is an alias for 'integer_sequence<T, 0, 1, ... N-1>'.
|
||||||
|
template <typename T, size_t N>
|
||||||
|
struct Gen
|
||||||
|
{
|
||||||
|
using type =
|
||||||
|
typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct Gen<T, 0>
|
||||||
|
{
|
||||||
|
using type = integer_sequence<T>;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace utility_internal
|
||||||
|
|
||||||
|
// Compile-time sequences of integers
|
||||||
|
|
||||||
|
// make_integer_sequence
|
||||||
|
//
|
||||||
|
// This template alias is equivalent to
|
||||||
|
// `integer_sequence<int, 0, 1, ..., N-1>`, and is designed to be a drop-in
|
||||||
|
// replacement for C++14's `std::make_integer_sequence`.
|
||||||
|
template <typename T, T N>
|
||||||
|
using make_integer_sequence = typename utility_internal::Gen<T, N>::type;
|
||||||
|
|
||||||
|
// make_index_sequence
|
||||||
|
//
|
||||||
|
// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`,
|
||||||
|
// and is designed to be a drop-in replacement for C++14's
|
||||||
|
// `std::make_index_sequence`.
|
||||||
|
template <size_t N>
|
||||||
|
using make_index_sequence = make_integer_sequence<size_t, N>;
|
||||||
|
|
||||||
|
// index_sequence_for
|
||||||
|
//
|
||||||
|
// Converts a typename pack into an index sequence of the same length, and
|
||||||
|
// is designed to be a drop-in replacement for C++14's
|
||||||
|
// `std::index_sequence_for()`
|
||||||
|
template <typename... Ts>
|
||||||
|
using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
|
||||||
|
|
||||||
|
//// END OF CODE FROM GOOGLE ABSEIL
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// dispatch utility (taken from ranges-v3)
|
||||||
|
template<unsigned N> struct priority_tag : priority_tag < N - 1 > {};
|
||||||
|
template<> struct priority_tag<0> {};
|
||||||
|
|
||||||
|
// taken from ranges-v3
|
||||||
|
template<typename T>
|
||||||
|
struct static_const
|
||||||
|
{
|
||||||
|
static JSON_INLINE_VARIABLE constexpr T value{};
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef JSON_HAS_CPP_17
|
||||||
|
template<typename T>
|
||||||
|
constexpr T static_const<T>::value;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<typename T, typename... Args>
|
||||||
|
inline constexpr std::array<T, sizeof...(Args)> make_array(Args&& ... args)
|
||||||
|
{
|
||||||
|
return std::array<T, sizeof...(Args)> {{static_cast<T>(std::forward<Args>(args))...}};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include <nlohmann/detail/meta/void_t.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
// https://en.cppreference.com/w/cpp/experimental/is_detected
|
||||||
|
struct nonesuch
|
||||||
|
{
|
||||||
|
nonesuch() = delete;
|
||||||
|
~nonesuch() = delete;
|
||||||
|
nonesuch(nonesuch const&) = delete;
|
||||||
|
nonesuch(nonesuch const&&) = delete;
|
||||||
|
void operator=(nonesuch const&) = delete;
|
||||||
|
void operator=(nonesuch&&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Default,
|
||||||
|
class AlwaysVoid,
|
||||||
|
template<class...> class Op,
|
||||||
|
class... Args>
|
||||||
|
struct detector
|
||||||
|
{
|
||||||
|
using value_t = std::false_type;
|
||||||
|
using type = Default;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Default, template<class...> class Op, class... Args>
|
||||||
|
struct detector<Default, void_t<Op<Args...>>, Op, Args...>
|
||||||
|
{
|
||||||
|
using value_t = std::true_type;
|
||||||
|
using type = Op<Args...>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<template<class...> class Op, class... Args>
|
||||||
|
using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t;
|
||||||
|
|
||||||
|
template<template<class...> class Op, class... Args>
|
||||||
|
struct is_detected_lazy : is_detected<Op, Args...> { };
|
||||||
|
|
||||||
|
template<template<class...> class Op, class... Args>
|
||||||
|
using detected_t = typename detector<nonesuch, void, Op, Args...>::type;
|
||||||
|
|
||||||
|
template<class Default, template<class...> class Op, class... Args>
|
||||||
|
using detected_or = detector<Default, void, Op, Args...>;
|
||||||
|
|
||||||
|
template<class Default, template<class...> class Op, class... Args>
|
||||||
|
using detected_or_t = typename detected_or<Default, Op, Args...>::type;
|
||||||
|
|
||||||
|
template<class Expected, template<class...> class Op, class... Args>
|
||||||
|
using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
|
||||||
|
|
||||||
|
template<class To, template<class...> class Op, class... Args>
|
||||||
|
using is_detected_convertible =
|
||||||
|
std::is_convertible<detected_t<Op, Args...>, To>;
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <nlohmann/detail/abi_macros.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
// dispatching helper struct
|
||||||
|
template <class T> struct identity_tag {};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,159 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint> // size_t
|
||||||
|
#include <utility> // declval
|
||||||
|
#include <string> // string
|
||||||
|
|
||||||
|
#include <nlohmann/detail/abi_macros.hpp>
|
||||||
|
#include <nlohmann/detail/meta/detected.hpp>
|
||||||
|
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using null_function_t = decltype(std::declval<T&>().null());
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using boolean_function_t =
|
||||||
|
decltype(std::declval<T&>().boolean(std::declval<bool>()));
|
||||||
|
|
||||||
|
template<typename T, typename Integer>
|
||||||
|
using number_integer_function_t =
|
||||||
|
decltype(std::declval<T&>().number_integer(std::declval<Integer>()));
|
||||||
|
|
||||||
|
template<typename T, typename Unsigned>
|
||||||
|
using number_unsigned_function_t =
|
||||||
|
decltype(std::declval<T&>().number_unsigned(std::declval<Unsigned>()));
|
||||||
|
|
||||||
|
template<typename T, typename Float, typename String>
|
||||||
|
using number_float_function_t = decltype(std::declval<T&>().number_float(
|
||||||
|
std::declval<Float>(), std::declval<const String&>()));
|
||||||
|
|
||||||
|
template<typename T, typename String>
|
||||||
|
using string_function_t =
|
||||||
|
decltype(std::declval<T&>().string(std::declval<String&>()));
|
||||||
|
|
||||||
|
template<typename T, typename Binary>
|
||||||
|
using binary_function_t =
|
||||||
|
decltype(std::declval<T&>().binary(std::declval<Binary&>()));
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using start_object_function_t =
|
||||||
|
decltype(std::declval<T&>().start_object(std::declval<std::size_t>()));
|
||||||
|
|
||||||
|
template<typename T, typename String>
|
||||||
|
using key_function_t =
|
||||||
|
decltype(std::declval<T&>().key(std::declval<String&>()));
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using end_object_function_t = decltype(std::declval<T&>().end_object());
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using start_array_function_t =
|
||||||
|
decltype(std::declval<T&>().start_array(std::declval<std::size_t>()));
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using end_array_function_t = decltype(std::declval<T&>().end_array());
|
||||||
|
|
||||||
|
template<typename T, typename Exception>
|
||||||
|
using parse_error_function_t = decltype(std::declval<T&>().parse_error(
|
||||||
|
std::declval<std::size_t>(), std::declval<const std::string&>(),
|
||||||
|
std::declval<const Exception&>()));
|
||||||
|
|
||||||
|
template<typename SAX, typename BasicJsonType>
|
||||||
|
struct is_sax
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static_assert(is_basic_json<BasicJsonType>::value,
|
||||||
|
"BasicJsonType must be of type basic_json<...>");
|
||||||
|
|
||||||
|
using number_integer_t = typename BasicJsonType::number_integer_t;
|
||||||
|
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
||||||
|
using number_float_t = typename BasicJsonType::number_float_t;
|
||||||
|
using string_t = typename BasicJsonType::string_t;
|
||||||
|
using binary_t = typename BasicJsonType::binary_t;
|
||||||
|
using exception_t = typename BasicJsonType::exception;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr bool value =
|
||||||
|
is_detected_exact<bool, null_function_t, SAX>::value &&
|
||||||
|
is_detected_exact<bool, boolean_function_t, SAX>::value &&
|
||||||
|
is_detected_exact<bool, number_integer_function_t, SAX, number_integer_t>::value &&
|
||||||
|
is_detected_exact<bool, number_unsigned_function_t, SAX, number_unsigned_t>::value &&
|
||||||
|
is_detected_exact<bool, number_float_function_t, SAX, number_float_t, string_t>::value &&
|
||||||
|
is_detected_exact<bool, string_function_t, SAX, string_t>::value &&
|
||||||
|
is_detected_exact<bool, binary_function_t, SAX, binary_t>::value &&
|
||||||
|
is_detected_exact<bool, start_object_function_t, SAX>::value &&
|
||||||
|
is_detected_exact<bool, key_function_t, SAX, string_t>::value &&
|
||||||
|
is_detected_exact<bool, end_object_function_t, SAX>::value &&
|
||||||
|
is_detected_exact<bool, start_array_function_t, SAX>::value &&
|
||||||
|
is_detected_exact<bool, end_array_function_t, SAX>::value &&
|
||||||
|
is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename SAX, typename BasicJsonType>
|
||||||
|
struct is_sax_static_asserts
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static_assert(is_basic_json<BasicJsonType>::value,
|
||||||
|
"BasicJsonType must be of type basic_json<...>");
|
||||||
|
|
||||||
|
using number_integer_t = typename BasicJsonType::number_integer_t;
|
||||||
|
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
||||||
|
using number_float_t = typename BasicJsonType::number_float_t;
|
||||||
|
using string_t = typename BasicJsonType::string_t;
|
||||||
|
using binary_t = typename BasicJsonType::binary_t;
|
||||||
|
using exception_t = typename BasicJsonType::exception;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static_assert(is_detected_exact<bool, null_function_t, SAX>::value,
|
||||||
|
"Missing/invalid function: bool null()");
|
||||||
|
static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
|
||||||
|
"Missing/invalid function: bool boolean(bool)");
|
||||||
|
static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
|
||||||
|
"Missing/invalid function: bool boolean(bool)");
|
||||||
|
static_assert(
|
||||||
|
is_detected_exact<bool, number_integer_function_t, SAX,
|
||||||
|
number_integer_t>::value,
|
||||||
|
"Missing/invalid function: bool number_integer(number_integer_t)");
|
||||||
|
static_assert(
|
||||||
|
is_detected_exact<bool, number_unsigned_function_t, SAX,
|
||||||
|
number_unsigned_t>::value,
|
||||||
|
"Missing/invalid function: bool number_unsigned(number_unsigned_t)");
|
||||||
|
static_assert(is_detected_exact<bool, number_float_function_t, SAX,
|
||||||
|
number_float_t, string_t>::value,
|
||||||
|
"Missing/invalid function: bool number_float(number_float_t, const string_t&)");
|
||||||
|
static_assert(
|
||||||
|
is_detected_exact<bool, string_function_t, SAX, string_t>::value,
|
||||||
|
"Missing/invalid function: bool string(string_t&)");
|
||||||
|
static_assert(
|
||||||
|
is_detected_exact<bool, binary_function_t, SAX, binary_t>::value,
|
||||||
|
"Missing/invalid function: bool binary(binary_t&)");
|
||||||
|
static_assert(is_detected_exact<bool, start_object_function_t, SAX>::value,
|
||||||
|
"Missing/invalid function: bool start_object(std::size_t)");
|
||||||
|
static_assert(is_detected_exact<bool, key_function_t, SAX, string_t>::value,
|
||||||
|
"Missing/invalid function: bool key(string_t&)");
|
||||||
|
static_assert(is_detected_exact<bool, end_object_function_t, SAX>::value,
|
||||||
|
"Missing/invalid function: bool end_object()");
|
||||||
|
static_assert(is_detected_exact<bool, start_array_function_t, SAX>::value,
|
||||||
|
"Missing/invalid function: bool start_array(std::size_t)");
|
||||||
|
static_assert(is_detected_exact<bool, end_array_function_t, SAX>::value,
|
||||||
|
"Missing/invalid function: bool end_array()");
|
||||||
|
static_assert(
|
||||||
|
is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value,
|
||||||
|
"Missing/invalid function: bool parse_error(std::size_t, const "
|
||||||
|
"std::string&, const exception&)");
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <nlohmann/detail/macro_scope.hpp>
|
||||||
|
|
||||||
|
#if JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||||
|
#include <experimental/filesystem>
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
namespace std_fs = std::experimental::filesystem;
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
#elif JSON_HAS_FILESYSTEM
|
||||||
|
#include <filesystem>
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
namespace std_fs = std::filesystem;
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,795 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <limits> // numeric_limits
|
||||||
|
#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
|
||||||
|
#include <utility> // declval
|
||||||
|
#include <tuple> // tuple
|
||||||
|
#include <string> // char_traits
|
||||||
|
|
||||||
|
#include <nlohmann/detail/iterators/iterator_traits.hpp>
|
||||||
|
#include <nlohmann/detail/macro_scope.hpp>
|
||||||
|
#include <nlohmann/detail/meta/call_std/begin.hpp>
|
||||||
|
#include <nlohmann/detail/meta/call_std/end.hpp>
|
||||||
|
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||||
|
#include <nlohmann/detail/meta/detected.hpp>
|
||||||
|
#include <nlohmann/json_fwd.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
/*!
|
||||||
|
@brief detail namespace with internal helper functions
|
||||||
|
|
||||||
|
This namespace collects functions that should not be exposed,
|
||||||
|
implementations of some @ref basic_json methods, and meta-programming helpers.
|
||||||
|
|
||||||
|
@since version 2.1.0
|
||||||
|
*/
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
/////////////
|
||||||
|
// helpers //
|
||||||
|
/////////////
|
||||||
|
|
||||||
|
// Note to maintainers:
|
||||||
|
//
|
||||||
|
// Every trait in this file expects a non CV-qualified type.
|
||||||
|
// The only exceptions are in the 'aliases for detected' section
|
||||||
|
// (i.e. those of the form: decltype(T::member_function(std::declval<T>())))
|
||||||
|
//
|
||||||
|
// In this case, T has to be properly CV-qualified to constraint the function arguments
|
||||||
|
// (e.g. to_json(BasicJsonType&, const T&))
|
||||||
|
|
||||||
|
template<typename> struct is_basic_json : std::false_type {};
|
||||||
|
|
||||||
|
NLOHMANN_BASIC_JSON_TPL_DECLARATION
|
||||||
|
struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {};
|
||||||
|
|
||||||
|
// used by exceptions create() member functions
|
||||||
|
// true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t
|
||||||
|
// false_type otherwise
|
||||||
|
template<typename BasicJsonContext>
|
||||||
|
struct is_basic_json_context :
|
||||||
|
std::integral_constant < bool,
|
||||||
|
is_basic_json<typename std::remove_cv<typename std::remove_pointer<BasicJsonContext>::type>::type>::value
|
||||||
|
|| std::is_same<BasicJsonContext, std::nullptr_t>::value >
|
||||||
|
{};
|
||||||
|
|
||||||
|
//////////////////////
|
||||||
|
// json_ref helpers //
|
||||||
|
//////////////////////
|
||||||
|
|
||||||
|
template<typename>
|
||||||
|
class json_ref;
|
||||||
|
|
||||||
|
template<typename>
|
||||||
|
struct is_json_ref : std::false_type {};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct is_json_ref<json_ref<T>> : std::true_type {};
|
||||||
|
|
||||||
|
//////////////////////////
|
||||||
|
// aliases for detected //
|
||||||
|
//////////////////////////
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using mapped_type_t = typename T::mapped_type;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using key_type_t = typename T::key_type;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using value_type_t = typename T::value_type;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using difference_type_t = typename T::difference_type;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using pointer_t = typename T::pointer;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using reference_t = typename T::reference;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using iterator_category_t = typename T::iterator_category;
|
||||||
|
|
||||||
|
template<typename T, typename... Args>
|
||||||
|
using to_json_function = decltype(T::to_json(std::declval<Args>()...));
|
||||||
|
|
||||||
|
template<typename T, typename... Args>
|
||||||
|
using from_json_function = decltype(T::from_json(std::declval<Args>()...));
|
||||||
|
|
||||||
|
template<typename T, typename U>
|
||||||
|
using get_template_function = decltype(std::declval<T>().template get<U>());
|
||||||
|
|
||||||
|
// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
|
||||||
|
template<typename BasicJsonType, typename T, typename = void>
|
||||||
|
struct has_from_json : std::false_type {};
|
||||||
|
|
||||||
|
// trait checking if j.get<T> is valid
|
||||||
|
// use this trait instead of std::is_constructible or std::is_convertible,
|
||||||
|
// both rely on, or make use of implicit conversions, and thus fail when T
|
||||||
|
// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958)
|
||||||
|
template <typename BasicJsonType, typename T>
|
||||||
|
struct is_getable
|
||||||
|
{
|
||||||
|
static constexpr bool value = is_detected<get_template_function, const BasicJsonType&, T>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename T>
|
||||||
|
struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
|
||||||
|
{
|
||||||
|
using serializer = typename BasicJsonType::template json_serializer<T, void>;
|
||||||
|
|
||||||
|
static constexpr bool value =
|
||||||
|
is_detected_exact<void, from_json_function, serializer,
|
||||||
|
const BasicJsonType&, T&>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This trait checks if JSONSerializer<T>::from_json(json const&) exists
|
||||||
|
// this overload is used for non-default-constructible user-defined-types
|
||||||
|
template<typename BasicJsonType, typename T, typename = void>
|
||||||
|
struct has_non_default_from_json : std::false_type {};
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename T>
|
||||||
|
struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
|
||||||
|
{
|
||||||
|
using serializer = typename BasicJsonType::template json_serializer<T, void>;
|
||||||
|
|
||||||
|
static constexpr bool value =
|
||||||
|
is_detected_exact<T, from_json_function, serializer,
|
||||||
|
const BasicJsonType&>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This trait checks if BasicJsonType::json_serializer<T>::to_json exists
|
||||||
|
// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion.
|
||||||
|
template<typename BasicJsonType, typename T, typename = void>
|
||||||
|
struct has_to_json : std::false_type {};
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename T>
|
||||||
|
struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
|
||||||
|
{
|
||||||
|
using serializer = typename BasicJsonType::template json_serializer<T, void>;
|
||||||
|
|
||||||
|
static constexpr bool value =
|
||||||
|
is_detected_exact<void, to_json_function, serializer, BasicJsonType&,
|
||||||
|
T>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using detect_key_compare = typename T::key_compare;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct has_key_compare : std::integral_constant<bool, is_detected<detect_key_compare, T>::value> {};
|
||||||
|
|
||||||
|
// obtains the actual object key comparator
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
struct actual_object_comparator
|
||||||
|
{
|
||||||
|
using object_t = typename BasicJsonType::object_t;
|
||||||
|
using object_comparator_t = typename BasicJsonType::default_object_comparator_t;
|
||||||
|
using type = typename std::conditional < has_key_compare<object_t>::value,
|
||||||
|
typename object_t::key_compare, object_comparator_t>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
using actual_object_comparator_t = typename actual_object_comparator<BasicJsonType>::type;
|
||||||
|
|
||||||
|
/////////////////
|
||||||
|
// char_traits //
|
||||||
|
/////////////////
|
||||||
|
|
||||||
|
// Primary template of char_traits calls std char_traits
|
||||||
|
template<typename T>
|
||||||
|
struct char_traits : std::char_traits<T>
|
||||||
|
{};
|
||||||
|
|
||||||
|
// Explicitly define char traits for unsigned char since it is not standard
|
||||||
|
template<>
|
||||||
|
struct char_traits<unsigned char> : std::char_traits<char>
|
||||||
|
{
|
||||||
|
using char_type = unsigned char;
|
||||||
|
using int_type = uint64_t;
|
||||||
|
|
||||||
|
// Redefine to_int_type function
|
||||||
|
static int_type to_int_type(char_type c) noexcept
|
||||||
|
{
|
||||||
|
return static_cast<int_type>(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char_type to_char_type(int_type i) noexcept
|
||||||
|
{
|
||||||
|
return static_cast<char_type>(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr int_type eof() noexcept
|
||||||
|
{
|
||||||
|
return static_cast<int_type>(EOF);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Explicitly define char traits for signed char since it is not standard
|
||||||
|
template<>
|
||||||
|
struct char_traits<signed char> : std::char_traits<char>
|
||||||
|
{
|
||||||
|
using char_type = signed char;
|
||||||
|
using int_type = uint64_t;
|
||||||
|
|
||||||
|
// Redefine to_int_type function
|
||||||
|
static int_type to_int_type(char_type c) noexcept
|
||||||
|
{
|
||||||
|
return static_cast<int_type>(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char_type to_char_type(int_type i) noexcept
|
||||||
|
{
|
||||||
|
return static_cast<char_type>(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr int_type eof() noexcept
|
||||||
|
{
|
||||||
|
return static_cast<int_type>(EOF);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////
|
||||||
|
// is_ functions //
|
||||||
|
///////////////////
|
||||||
|
|
||||||
|
// https://en.cppreference.com/w/cpp/types/conjunction
|
||||||
|
template<class...> struct conjunction : std::true_type { };
|
||||||
|
template<class B> struct conjunction<B> : B { };
|
||||||
|
template<class B, class... Bn>
|
||||||
|
struct conjunction<B, Bn...>
|
||||||
|
: std::conditional<static_cast<bool>(B::value), conjunction<Bn...>, B>::type {};
|
||||||
|
|
||||||
|
// https://en.cppreference.com/w/cpp/types/negation
|
||||||
|
template<class B> struct negation : std::integral_constant < bool, !B::value > { };
|
||||||
|
|
||||||
|
// Reimplementation of is_constructible and is_default_constructible, due to them being broken for
|
||||||
|
// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367).
|
||||||
|
// This causes compile errors in e.g. clang 3.5 or gcc 4.9.
|
||||||
|
template <typename T>
|
||||||
|
struct is_default_constructible : std::is_default_constructible<T> {};
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
struct is_default_constructible<std::pair<T1, T2>>
|
||||||
|
: conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {};
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
struct is_default_constructible<const std::pair<T1, T2>>
|
||||||
|
: conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {};
|
||||||
|
|
||||||
|
template <typename... Ts>
|
||||||
|
struct is_default_constructible<std::tuple<Ts...>>
|
||||||
|
: conjunction<is_default_constructible<Ts>...> {};
|
||||||
|
|
||||||
|
template <typename... Ts>
|
||||||
|
struct is_default_constructible<const std::tuple<Ts...>>
|
||||||
|
: conjunction<is_default_constructible<Ts>...> {};
|
||||||
|
|
||||||
|
template <typename T, typename... Args>
|
||||||
|
struct is_constructible : std::is_constructible<T, Args...> {};
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
struct is_constructible<std::pair<T1, T2>> : is_default_constructible<std::pair<T1, T2>> {};
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
struct is_constructible<const std::pair<T1, T2>> : is_default_constructible<const std::pair<T1, T2>> {};
|
||||||
|
|
||||||
|
template <typename... Ts>
|
||||||
|
struct is_constructible<std::tuple<Ts...>> : is_default_constructible<std::tuple<Ts...>> {};
|
||||||
|
|
||||||
|
template <typename... Ts>
|
||||||
|
struct is_constructible<const std::tuple<Ts...>> : is_default_constructible<const std::tuple<Ts...>> {};
|
||||||
|
|
||||||
|
template<typename T, typename = void>
|
||||||
|
struct is_iterator_traits : std::false_type {};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct is_iterator_traits<iterator_traits<T>>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
using traits = iterator_traits<T>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr auto value =
|
||||||
|
is_detected<value_type_t, traits>::value &&
|
||||||
|
is_detected<difference_type_t, traits>::value &&
|
||||||
|
is_detected<pointer_t, traits>::value &&
|
||||||
|
is_detected<iterator_category_t, traits>::value &&
|
||||||
|
is_detected<reference_t, traits>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct is_range
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
using t_ref = typename std::add_lvalue_reference<T>::type;
|
||||||
|
|
||||||
|
using iterator = detected_t<result_of_begin, t_ref>;
|
||||||
|
using sentinel = detected_t<result_of_end, t_ref>;
|
||||||
|
|
||||||
|
// to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator
|
||||||
|
// and https://en.cppreference.com/w/cpp/iterator/sentinel_for
|
||||||
|
// but reimplementing these would be too much work, as a lot of other concepts are used underneath
|
||||||
|
static constexpr auto is_iterator_begin =
|
||||||
|
is_iterator_traits<iterator_traits<iterator>>::value;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr bool value = !std::is_same<iterator, nonesuch>::value && !std::is_same<sentinel, nonesuch>::value && is_iterator_begin;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename R>
|
||||||
|
using iterator_t = enable_if_t<is_range<R>::value, result_of_begin<decltype(std::declval<R&>())>>;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using range_value_t = value_type_t<iterator_traits<iterator_t<T>>>;
|
||||||
|
|
||||||
|
// The following implementation of is_complete_type is taken from
|
||||||
|
// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/
|
||||||
|
// and is written by Xiang Fan who agreed to using it in this library.
|
||||||
|
|
||||||
|
template<typename T, typename = void>
|
||||||
|
struct is_complete_type : std::false_type {};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename CompatibleObjectType,
|
||||||
|
typename = void>
|
||||||
|
struct is_compatible_object_type_impl : std::false_type {};
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename CompatibleObjectType>
|
||||||
|
struct is_compatible_object_type_impl <
|
||||||
|
BasicJsonType, CompatibleObjectType,
|
||||||
|
enable_if_t < is_detected<mapped_type_t, CompatibleObjectType>::value&&
|
||||||
|
is_detected<key_type_t, CompatibleObjectType>::value >>
|
||||||
|
{
|
||||||
|
using object_t = typename BasicJsonType::object_t;
|
||||||
|
|
||||||
|
// macOS's is_constructible does not play well with nonesuch...
|
||||||
|
static constexpr bool value =
|
||||||
|
is_constructible<typename object_t::key_type,
|
||||||
|
typename CompatibleObjectType::key_type>::value &&
|
||||||
|
is_constructible<typename object_t::mapped_type,
|
||||||
|
typename CompatibleObjectType::mapped_type>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename CompatibleObjectType>
|
||||||
|
struct is_compatible_object_type
|
||||||
|
: is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {};
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename ConstructibleObjectType,
|
||||||
|
typename = void>
|
||||||
|
struct is_constructible_object_type_impl : std::false_type {};
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename ConstructibleObjectType>
|
||||||
|
struct is_constructible_object_type_impl <
|
||||||
|
BasicJsonType, ConstructibleObjectType,
|
||||||
|
enable_if_t < is_detected<mapped_type_t, ConstructibleObjectType>::value&&
|
||||||
|
is_detected<key_type_t, ConstructibleObjectType>::value >>
|
||||||
|
{
|
||||||
|
using object_t = typename BasicJsonType::object_t;
|
||||||
|
|
||||||
|
static constexpr bool value =
|
||||||
|
(is_default_constructible<ConstructibleObjectType>::value &&
|
||||||
|
(std::is_move_assignable<ConstructibleObjectType>::value ||
|
||||||
|
std::is_copy_assignable<ConstructibleObjectType>::value) &&
|
||||||
|
(is_constructible<typename ConstructibleObjectType::key_type,
|
||||||
|
typename object_t::key_type>::value &&
|
||||||
|
std::is_same <
|
||||||
|
typename object_t::mapped_type,
|
||||||
|
typename ConstructibleObjectType::mapped_type >::value)) ||
|
||||||
|
(has_from_json<BasicJsonType,
|
||||||
|
typename ConstructibleObjectType::mapped_type>::value ||
|
||||||
|
has_non_default_from_json <
|
||||||
|
BasicJsonType,
|
||||||
|
typename ConstructibleObjectType::mapped_type >::value);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename ConstructibleObjectType>
|
||||||
|
struct is_constructible_object_type
|
||||||
|
: is_constructible_object_type_impl<BasicJsonType,
|
||||||
|
ConstructibleObjectType> {};
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename CompatibleStringType>
|
||||||
|
struct is_compatible_string_type
|
||||||
|
{
|
||||||
|
static constexpr auto value =
|
||||||
|
is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename ConstructibleStringType>
|
||||||
|
struct is_constructible_string_type
|
||||||
|
{
|
||||||
|
// launder type through decltype() to fix compilation failure on ICPC
|
||||||
|
#ifdef __INTEL_COMPILER
|
||||||
|
using laundered_type = decltype(std::declval<ConstructibleStringType>());
|
||||||
|
#else
|
||||||
|
using laundered_type = ConstructibleStringType;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static constexpr auto value =
|
||||||
|
conjunction <
|
||||||
|
is_constructible<laundered_type, typename BasicJsonType::string_t>,
|
||||||
|
is_detected_exact<typename BasicJsonType::string_t::value_type,
|
||||||
|
value_type_t, laundered_type >>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename CompatibleArrayType, typename = void>
|
||||||
|
struct is_compatible_array_type_impl : std::false_type {};
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename CompatibleArrayType>
|
||||||
|
struct is_compatible_array_type_impl <
|
||||||
|
BasicJsonType, CompatibleArrayType,
|
||||||
|
enable_if_t <
|
||||||
|
is_detected<iterator_t, CompatibleArrayType>::value&&
|
||||||
|
is_iterator_traits<iterator_traits<detected_t<iterator_t, CompatibleArrayType>>>::value&&
|
||||||
|
// special case for types like std::filesystem::path whose iterator's value_type are themselves
|
||||||
|
// c.f. https://github.com/nlohmann/json/pull/3073
|
||||||
|
!std::is_same<CompatibleArrayType, detected_t<range_value_t, CompatibleArrayType>>::value >>
|
||||||
|
{
|
||||||
|
static constexpr bool value =
|
||||||
|
is_constructible<BasicJsonType,
|
||||||
|
range_value_t<CompatibleArrayType>>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename CompatibleArrayType>
|
||||||
|
struct is_compatible_array_type
|
||||||
|
: is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename ConstructibleArrayType, typename = void>
|
||||||
|
struct is_constructible_array_type_impl : std::false_type {};
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename ConstructibleArrayType>
|
||||||
|
struct is_constructible_array_type_impl <
|
||||||
|
BasicJsonType, ConstructibleArrayType,
|
||||||
|
enable_if_t<std::is_same<ConstructibleArrayType,
|
||||||
|
typename BasicJsonType::value_type>::value >>
|
||||||
|
: std::true_type {};
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename ConstructibleArrayType>
|
||||||
|
struct is_constructible_array_type_impl <
|
||||||
|
BasicJsonType, ConstructibleArrayType,
|
||||||
|
enable_if_t < !std::is_same<ConstructibleArrayType,
|
||||||
|
typename BasicJsonType::value_type>::value&&
|
||||||
|
!is_compatible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||||
|
is_default_constructible<ConstructibleArrayType>::value&&
|
||||||
|
(std::is_move_assignable<ConstructibleArrayType>::value ||
|
||||||
|
std::is_copy_assignable<ConstructibleArrayType>::value)&&
|
||||||
|
is_detected<iterator_t, ConstructibleArrayType>::value&&
|
||||||
|
is_iterator_traits<iterator_traits<detected_t<iterator_t, ConstructibleArrayType>>>::value&&
|
||||||
|
is_detected<range_value_t, ConstructibleArrayType>::value&&
|
||||||
|
// special case for types like std::filesystem::path whose iterator's value_type are themselves
|
||||||
|
// c.f. https://github.com/nlohmann/json/pull/3073
|
||||||
|
!std::is_same<ConstructibleArrayType, detected_t<range_value_t, ConstructibleArrayType>>::value&&
|
||||||
|
is_complete_type <
|
||||||
|
detected_t<range_value_t, ConstructibleArrayType >>::value >>
|
||||||
|
{
|
||||||
|
using value_type = range_value_t<ConstructibleArrayType>;
|
||||||
|
|
||||||
|
static constexpr bool value =
|
||||||
|
std::is_same<value_type,
|
||||||
|
typename BasicJsonType::array_t::value_type>::value ||
|
||||||
|
has_from_json<BasicJsonType,
|
||||||
|
value_type>::value ||
|
||||||
|
has_non_default_from_json <
|
||||||
|
BasicJsonType,
|
||||||
|
value_type >::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename ConstructibleArrayType>
|
||||||
|
struct is_constructible_array_type
|
||||||
|
: is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {};
|
||||||
|
|
||||||
|
template<typename RealIntegerType, typename CompatibleNumberIntegerType,
|
||||||
|
typename = void>
|
||||||
|
struct is_compatible_integer_type_impl : std::false_type {};
|
||||||
|
|
||||||
|
template<typename RealIntegerType, typename CompatibleNumberIntegerType>
|
||||||
|
struct is_compatible_integer_type_impl <
|
||||||
|
RealIntegerType, CompatibleNumberIntegerType,
|
||||||
|
enable_if_t < std::is_integral<RealIntegerType>::value&&
|
||||||
|
std::is_integral<CompatibleNumberIntegerType>::value&&
|
||||||
|
!std::is_same<bool, CompatibleNumberIntegerType>::value >>
|
||||||
|
{
|
||||||
|
// is there an assert somewhere on overflows?
|
||||||
|
using RealLimits = std::numeric_limits<RealIntegerType>;
|
||||||
|
using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
|
||||||
|
|
||||||
|
static constexpr auto value =
|
||||||
|
is_constructible<RealIntegerType,
|
||||||
|
CompatibleNumberIntegerType>::value &&
|
||||||
|
CompatibleLimits::is_integer &&
|
||||||
|
RealLimits::is_signed == CompatibleLimits::is_signed;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename RealIntegerType, typename CompatibleNumberIntegerType>
|
||||||
|
struct is_compatible_integer_type
|
||||||
|
: is_compatible_integer_type_impl<RealIntegerType,
|
||||||
|
CompatibleNumberIntegerType> {};
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename CompatibleType, typename = void>
|
||||||
|
struct is_compatible_type_impl: std::false_type {};
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename CompatibleType>
|
||||||
|
struct is_compatible_type_impl <
|
||||||
|
BasicJsonType, CompatibleType,
|
||||||
|
enable_if_t<is_complete_type<CompatibleType>::value >>
|
||||||
|
{
|
||||||
|
static constexpr bool value =
|
||||||
|
has_to_json<BasicJsonType, CompatibleType>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename CompatibleType>
|
||||||
|
struct is_compatible_type
|
||||||
|
: is_compatible_type_impl<BasicJsonType, CompatibleType> {};
|
||||||
|
|
||||||
|
template<typename T1, typename T2>
|
||||||
|
struct is_constructible_tuple : std::false_type {};
|
||||||
|
|
||||||
|
template<typename T1, typename... Args>
|
||||||
|
struct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<is_constructible<T1, Args>...> {};
|
||||||
|
|
||||||
|
template<typename BasicJsonType, typename T>
|
||||||
|
struct is_json_iterator_of : std::false_type {};
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::iterator> : std::true_type {};
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::const_iterator> : std::true_type
|
||||||
|
{};
|
||||||
|
|
||||||
|
// checks if a given type T is a template specialization of Primary
|
||||||
|
template<template <typename...> class Primary, typename T>
|
||||||
|
struct is_specialization_of : std::false_type {};
|
||||||
|
|
||||||
|
template<template <typename...> class Primary, typename... Args>
|
||||||
|
struct is_specialization_of<Primary, Primary<Args...>> : std::true_type {};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using is_json_pointer = is_specialization_of<::nlohmann::json_pointer, uncvref_t<T>>;
|
||||||
|
|
||||||
|
// checks if A and B are comparable using Compare functor
|
||||||
|
template<typename Compare, typename A, typename B, typename = void>
|
||||||
|
struct is_comparable : std::false_type {};
|
||||||
|
|
||||||
|
template<typename Compare, typename A, typename B>
|
||||||
|
struct is_comparable<Compare, A, B, void_t<
|
||||||
|
decltype(std::declval<Compare>()(std::declval<A>(), std::declval<B>())),
|
||||||
|
decltype(std::declval<Compare>()(std::declval<B>(), std::declval<A>()))
|
||||||
|
>> : std::true_type {};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using detect_is_transparent = typename T::is_transparent;
|
||||||
|
|
||||||
|
// type trait to check if KeyType can be used as object key (without a BasicJsonType)
|
||||||
|
// see is_usable_as_basic_json_key_type below
|
||||||
|
template<typename Comparator, typename ObjectKeyType, typename KeyTypeCVRef, bool RequireTransparentComparator = true,
|
||||||
|
bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>>
|
||||||
|
using is_usable_as_key_type = typename std::conditional <
|
||||||
|
is_comparable<Comparator, ObjectKeyType, KeyTypeCVRef>::value
|
||||||
|
&& !(ExcludeObjectKeyType && std::is_same<KeyType,
|
||||||
|
ObjectKeyType>::value)
|
||||||
|
&& (!RequireTransparentComparator
|
||||||
|
|| is_detected <detect_is_transparent, Comparator>::value)
|
||||||
|
&& !is_json_pointer<KeyType>::value,
|
||||||
|
std::true_type,
|
||||||
|
std::false_type >::type;
|
||||||
|
|
||||||
|
// type trait to check if KeyType can be used as object key
|
||||||
|
// true if:
|
||||||
|
// - KeyType is comparable with BasicJsonType::object_t::key_type
|
||||||
|
// - if ExcludeObjectKeyType is true, KeyType is not BasicJsonType::object_t::key_type
|
||||||
|
// - the comparator is transparent or RequireTransparentComparator is false
|
||||||
|
// - KeyType is not a JSON iterator or json_pointer
|
||||||
|
template<typename BasicJsonType, typename KeyTypeCVRef, bool RequireTransparentComparator = true,
|
||||||
|
bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>>
|
||||||
|
using is_usable_as_basic_json_key_type = typename std::conditional <
|
||||||
|
is_usable_as_key_type<typename BasicJsonType::object_comparator_t,
|
||||||
|
typename BasicJsonType::object_t::key_type, KeyTypeCVRef,
|
||||||
|
RequireTransparentComparator, ExcludeObjectKeyType>::value
|
||||||
|
&& !is_json_iterator_of<BasicJsonType, KeyType>::value,
|
||||||
|
std::true_type,
|
||||||
|
std::false_type >::type;
|
||||||
|
|
||||||
|
template<typename ObjectType, typename KeyType>
|
||||||
|
using detect_erase_with_key_type = decltype(std::declval<ObjectType&>().erase(std::declval<KeyType>()));
|
||||||
|
|
||||||
|
// type trait to check if object_t has an erase() member functions accepting KeyType
|
||||||
|
template<typename BasicJsonType, typename KeyType>
|
||||||
|
using has_erase_with_key_type = typename std::conditional <
|
||||||
|
is_detected <
|
||||||
|
detect_erase_with_key_type,
|
||||||
|
typename BasicJsonType::object_t, KeyType >::value,
|
||||||
|
std::true_type,
|
||||||
|
std::false_type >::type;
|
||||||
|
|
||||||
|
// a naive helper to check if a type is an ordered_map (exploits the fact that
|
||||||
|
// ordered_map inherits capacity() from std::vector)
|
||||||
|
template <typename T>
|
||||||
|
struct is_ordered_map
|
||||||
|
{
|
||||||
|
using one = char;
|
||||||
|
|
||||||
|
struct two
|
||||||
|
{
|
||||||
|
char x[2]; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename C> static one test( decltype(&C::capacity) ) ;
|
||||||
|
template <typename C> static two test(...);
|
||||||
|
|
||||||
|
enum { value = sizeof(test<T>(nullptr)) == sizeof(char) }; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||||
|
};
|
||||||
|
|
||||||
|
// to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324)
|
||||||
|
template < typename T, typename U, enable_if_t < !std::is_same<T, U>::value, int > = 0 >
|
||||||
|
T conditional_static_cast(U value)
|
||||||
|
{
|
||||||
|
return static_cast<T>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename U, enable_if_t<std::is_same<T, U>::value, int> = 0>
|
||||||
|
T conditional_static_cast(U value)
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Types>
|
||||||
|
using all_integral = conjunction<std::is_integral<Types>...>;
|
||||||
|
|
||||||
|
template<typename... Types>
|
||||||
|
using all_signed = conjunction<std::is_signed<Types>...>;
|
||||||
|
|
||||||
|
template<typename... Types>
|
||||||
|
using all_unsigned = conjunction<std::is_unsigned<Types>...>;
|
||||||
|
|
||||||
|
// there's a disjunction trait in another PR; replace when merged
|
||||||
|
template<typename... Types>
|
||||||
|
using same_sign = std::integral_constant < bool,
|
||||||
|
all_signed<Types...>::value || all_unsigned<Types...>::value >;
|
||||||
|
|
||||||
|
template<typename OfType, typename T>
|
||||||
|
using never_out_of_range = std::integral_constant < bool,
|
||||||
|
(std::is_signed<OfType>::value && (sizeof(T) < sizeof(OfType)))
|
||||||
|
|| (same_sign<OfType, T>::value && sizeof(OfType) == sizeof(T)) >;
|
||||||
|
|
||||||
|
template<typename OfType, typename T,
|
||||||
|
bool OfTypeSigned = std::is_signed<OfType>::value,
|
||||||
|
bool TSigned = std::is_signed<T>::value>
|
||||||
|
struct value_in_range_of_impl2;
|
||||||
|
|
||||||
|
template<typename OfType, typename T>
|
||||||
|
struct value_in_range_of_impl2<OfType, T, false, false>
|
||||||
|
{
|
||||||
|
static constexpr bool test(T val)
|
||||||
|
{
|
||||||
|
using CommonType = typename std::common_type<OfType, T>::type;
|
||||||
|
return static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename OfType, typename T>
|
||||||
|
struct value_in_range_of_impl2<OfType, T, true, false>
|
||||||
|
{
|
||||||
|
static constexpr bool test(T val)
|
||||||
|
{
|
||||||
|
using CommonType = typename std::common_type<OfType, T>::type;
|
||||||
|
return static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename OfType, typename T>
|
||||||
|
struct value_in_range_of_impl2<OfType, T, false, true>
|
||||||
|
{
|
||||||
|
static constexpr bool test(T val)
|
||||||
|
{
|
||||||
|
using CommonType = typename std::common_type<OfType, T>::type;
|
||||||
|
return val >= 0 && static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename OfType, typename T>
|
||||||
|
struct value_in_range_of_impl2<OfType, T, true, true>
|
||||||
|
{
|
||||||
|
static constexpr bool test(T val)
|
||||||
|
{
|
||||||
|
using CommonType = typename std::common_type<OfType, T>::type;
|
||||||
|
return static_cast<CommonType>(val) >= static_cast<CommonType>((std::numeric_limits<OfType>::min)())
|
||||||
|
&& static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename OfType, typename T,
|
||||||
|
bool NeverOutOfRange = never_out_of_range<OfType, T>::value,
|
||||||
|
typename = detail::enable_if_t<all_integral<OfType, T>::value>>
|
||||||
|
struct value_in_range_of_impl1;
|
||||||
|
|
||||||
|
template<typename OfType, typename T>
|
||||||
|
struct value_in_range_of_impl1<OfType, T, false>
|
||||||
|
{
|
||||||
|
static constexpr bool test(T val)
|
||||||
|
{
|
||||||
|
return value_in_range_of_impl2<OfType, T>::test(val);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename OfType, typename T>
|
||||||
|
struct value_in_range_of_impl1<OfType, T, true>
|
||||||
|
{
|
||||||
|
static constexpr bool test(T /*val*/)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename OfType, typename T>
|
||||||
|
inline constexpr bool value_in_range_of(T val)
|
||||||
|
{
|
||||||
|
return value_in_range_of_impl1<OfType, T>::test(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool Value>
|
||||||
|
using bool_constant = std::integral_constant<bool, Value>;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// is_c_string
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
namespace impl
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline constexpr bool is_c_string()
|
||||||
|
{
|
||||||
|
using TUnExt = typename std::remove_extent<T>::type;
|
||||||
|
using TUnCVExt = typename std::remove_cv<TUnExt>::type;
|
||||||
|
using TUnPtr = typename std::remove_pointer<T>::type;
|
||||||
|
using TUnCVPtr = typename std::remove_cv<TUnPtr>::type;
|
||||||
|
return
|
||||||
|
(std::is_array<T>::value && std::is_same<TUnCVExt, char>::value)
|
||||||
|
|| (std::is_pointer<T>::value && std::is_same<TUnCVPtr, char>::value);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace impl
|
||||||
|
|
||||||
|
// checks whether T is a [cv] char */[cv] char[] C string
|
||||||
|
template<typename T>
|
||||||
|
struct is_c_string : bool_constant<impl::is_c_string<T>()> {};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using is_c_string_uncvref = is_c_string<uncvref_t<T>>;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// is_transparent
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
namespace impl
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline constexpr bool is_transparent()
|
||||||
|
{
|
||||||
|
return is_detected<detect_is_transparent, T>::value;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace impl
|
||||||
|
|
||||||
|
// checks whether T has a member named is_transparent
|
||||||
|
template<typename T>
|
||||||
|
struct is_transparent : bool_constant<impl::is_transparent<T>()> {};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <nlohmann/detail/abi_macros.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename ...Ts> struct make_void
|
||||||
|
{
|
||||||
|
using type = void;
|
||||||
|
};
|
||||||
|
template<typename ...Ts> using void_t = typename make_void<Ts...>::type;
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,147 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm> // copy
|
||||||
|
#include <cstddef> // size_t
|
||||||
|
#include <iterator> // back_inserter
|
||||||
|
#include <memory> // shared_ptr, make_shared
|
||||||
|
#include <string> // basic_string
|
||||||
|
#include <vector> // vector
|
||||||
|
|
||||||
|
#ifndef JSON_NO_IO
|
||||||
|
#include <ios> // streamsize
|
||||||
|
#include <ostream> // basic_ostream
|
||||||
|
#endif // JSON_NO_IO
|
||||||
|
|
||||||
|
#include <nlohmann/detail/macro_scope.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
/// abstract output adapter interface
|
||||||
|
template<typename CharType> struct output_adapter_protocol
|
||||||
|
{
|
||||||
|
virtual void write_character(CharType c) = 0;
|
||||||
|
virtual void write_characters(const CharType* s, std::size_t length) = 0;
|
||||||
|
virtual ~output_adapter_protocol() = default;
|
||||||
|
|
||||||
|
output_adapter_protocol() = default;
|
||||||
|
output_adapter_protocol(const output_adapter_protocol&) = default;
|
||||||
|
output_adapter_protocol(output_adapter_protocol&&) noexcept = default;
|
||||||
|
output_adapter_protocol& operator=(const output_adapter_protocol&) = default;
|
||||||
|
output_adapter_protocol& operator=(output_adapter_protocol&&) noexcept = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// a type to simplify interfaces
|
||||||
|
template<typename CharType>
|
||||||
|
using output_adapter_t = std::shared_ptr<output_adapter_protocol<CharType>>;
|
||||||
|
|
||||||
|
/// output adapter for byte vectors
|
||||||
|
template<typename CharType, typename AllocatorType = std::allocator<CharType>>
|
||||||
|
class output_vector_adapter : public output_adapter_protocol<CharType>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit output_vector_adapter(std::vector<CharType, AllocatorType>& vec) noexcept
|
||||||
|
: v(vec)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void write_character(CharType c) override
|
||||||
|
{
|
||||||
|
v.push_back(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_HEDLEY_NON_NULL(2)
|
||||||
|
void write_characters(const CharType* s, std::size_t length) override
|
||||||
|
{
|
||||||
|
v.insert(v.end(), s, s + length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<CharType, AllocatorType>& v;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef JSON_NO_IO
|
||||||
|
/// output adapter for output streams
|
||||||
|
template<typename CharType>
|
||||||
|
class output_stream_adapter : public output_adapter_protocol<CharType>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit output_stream_adapter(std::basic_ostream<CharType>& s) noexcept
|
||||||
|
: stream(s)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void write_character(CharType c) override
|
||||||
|
{
|
||||||
|
stream.put(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_HEDLEY_NON_NULL(2)
|
||||||
|
void write_characters(const CharType* s, std::size_t length) override
|
||||||
|
{
|
||||||
|
stream.write(s, static_cast<std::streamsize>(length));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::basic_ostream<CharType>& stream;
|
||||||
|
};
|
||||||
|
#endif // JSON_NO_IO
|
||||||
|
|
||||||
|
/// output adapter for basic_string
|
||||||
|
template<typename CharType, typename StringType = std::basic_string<CharType>>
|
||||||
|
class output_string_adapter : public output_adapter_protocol<CharType>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit output_string_adapter(StringType& s) noexcept
|
||||||
|
: str(s)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void write_character(CharType c) override
|
||||||
|
{
|
||||||
|
str.push_back(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_HEDLEY_NON_NULL(2)
|
||||||
|
void write_characters(const CharType* s, std::size_t length) override
|
||||||
|
{
|
||||||
|
str.append(s, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
StringType& str;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename CharType, typename StringType = std::basic_string<CharType>>
|
||||||
|
class output_adapter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<typename AllocatorType = std::allocator<CharType>>
|
||||||
|
output_adapter(std::vector<CharType, AllocatorType>& vec)
|
||||||
|
: oa(std::make_shared<output_vector_adapter<CharType, AllocatorType>>(vec)) {}
|
||||||
|
|
||||||
|
#ifndef JSON_NO_IO
|
||||||
|
output_adapter(std::basic_ostream<CharType>& s)
|
||||||
|
: oa(std::make_shared<output_stream_adapter<CharType>>(s)) {}
|
||||||
|
#endif // JSON_NO_IO
|
||||||
|
|
||||||
|
output_adapter(StringType& s)
|
||||||
|
: oa(std::make_shared<output_string_adapter<CharType, StringType>>(s)) {}
|
||||||
|
|
||||||
|
operator output_adapter_t<CharType>()
|
||||||
|
{
|
||||||
|
return oa;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
output_adapter_t<CharType> oa = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,988 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2008-2009 Björn Hoehrmann <bjoern@hoehrmann.de>
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm> // reverse, remove, fill, find, none_of
|
||||||
|
#include <array> // array
|
||||||
|
#include <clocale> // localeconv, lconv
|
||||||
|
#include <cmath> // labs, isfinite, isnan, signbit
|
||||||
|
#include <cstddef> // size_t, ptrdiff_t
|
||||||
|
#include <cstdint> // uint8_t
|
||||||
|
#include <cstdio> // snprintf
|
||||||
|
#include <limits> // numeric_limits
|
||||||
|
#include <string> // string, char_traits
|
||||||
|
#include <iomanip> // setfill, setw
|
||||||
|
#include <type_traits> // is_same
|
||||||
|
#include <utility> // move
|
||||||
|
|
||||||
|
#include <nlohmann/detail/conversions/to_chars.hpp>
|
||||||
|
#include <nlohmann/detail/exceptions.hpp>
|
||||||
|
#include <nlohmann/detail/macro_scope.hpp>
|
||||||
|
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||||
|
#include <nlohmann/detail/output/binary_writer.hpp>
|
||||||
|
#include <nlohmann/detail/output/output_adapters.hpp>
|
||||||
|
#include <nlohmann/detail/string_concat.hpp>
|
||||||
|
#include <nlohmann/detail/value_t.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
///////////////////
|
||||||
|
// serialization //
|
||||||
|
///////////////////
|
||||||
|
|
||||||
|
/// how to treat decoding errors
|
||||||
|
enum class error_handler_t
|
||||||
|
{
|
||||||
|
strict, ///< throw a type_error exception in case of invalid UTF-8
|
||||||
|
replace, ///< replace invalid UTF-8 sequences with U+FFFD
|
||||||
|
ignore ///< ignore invalid UTF-8 sequences
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
class serializer
|
||||||
|
{
|
||||||
|
using string_t = typename BasicJsonType::string_t;
|
||||||
|
using number_float_t = typename BasicJsonType::number_float_t;
|
||||||
|
using number_integer_t = typename BasicJsonType::number_integer_t;
|
||||||
|
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
|
||||||
|
using binary_char_t = typename BasicJsonType::binary_t::value_type;
|
||||||
|
static constexpr std::uint8_t UTF8_ACCEPT = 0;
|
||||||
|
static constexpr std::uint8_t UTF8_REJECT = 1;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
@param[in] s output stream to serialize to
|
||||||
|
@param[in] ichar indentation character to use
|
||||||
|
@param[in] error_handler_ how to react on decoding errors
|
||||||
|
*/
|
||||||
|
serializer(output_adapter_t<char> s, const char ichar,
|
||||||
|
error_handler_t error_handler_ = error_handler_t::strict)
|
||||||
|
: o(std::move(s))
|
||||||
|
, loc(std::localeconv())
|
||||||
|
, thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->thousands_sep)))
|
||||||
|
, decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->decimal_point)))
|
||||||
|
, indent_char(ichar)
|
||||||
|
, indent_string(512, indent_char)
|
||||||
|
, error_handler(error_handler_)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// delete because of pointer members
|
||||||
|
serializer(const serializer&) = delete;
|
||||||
|
serializer& operator=(const serializer&) = delete;
|
||||||
|
serializer(serializer&&) = delete;
|
||||||
|
serializer& operator=(serializer&&) = delete;
|
||||||
|
~serializer() = default;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief internal implementation of the serialization function
|
||||||
|
|
||||||
|
This function is called by the public member function dump and organizes
|
||||||
|
the serialization internally. The indentation level is propagated as
|
||||||
|
additional parameter. In case of arrays and objects, the function is
|
||||||
|
called recursively.
|
||||||
|
|
||||||
|
- strings and object keys are escaped using `escape_string()`
|
||||||
|
- integer numbers are converted implicitly via `operator<<`
|
||||||
|
- floating-point numbers are converted to a string using `"%g"` format
|
||||||
|
- binary values are serialized as objects containing the subtype and the
|
||||||
|
byte array
|
||||||
|
|
||||||
|
@param[in] val value to serialize
|
||||||
|
@param[in] pretty_print whether the output shall be pretty-printed
|
||||||
|
@param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters
|
||||||
|
in the output are escaped with `\uXXXX` sequences, and the result consists
|
||||||
|
of ASCII characters only.
|
||||||
|
@param[in] indent_step the indent level
|
||||||
|
@param[in] current_indent the current indent level (only used internally)
|
||||||
|
*/
|
||||||
|
void dump(const BasicJsonType& val,
|
||||||
|
const bool pretty_print,
|
||||||
|
const bool ensure_ascii,
|
||||||
|
const unsigned int indent_step,
|
||||||
|
const unsigned int current_indent = 0)
|
||||||
|
{
|
||||||
|
switch (val.m_data.m_type)
|
||||||
|
{
|
||||||
|
case value_t::object:
|
||||||
|
{
|
||||||
|
if (val.m_data.m_value.object->empty())
|
||||||
|
{
|
||||||
|
o->write_characters("{}", 2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pretty_print)
|
||||||
|
{
|
||||||
|
o->write_characters("{\n", 2);
|
||||||
|
|
||||||
|
// variable to hold indentation for recursive calls
|
||||||
|
const auto new_indent = current_indent + indent_step;
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
|
||||||
|
{
|
||||||
|
indent_string.resize(indent_string.size() * 2, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
// first n-1 elements
|
||||||
|
auto i = val.m_data.m_value.object->cbegin();
|
||||||
|
for (std::size_t cnt = 0; cnt < val.m_data.m_value.object->size() - 1; ++cnt, ++i)
|
||||||
|
{
|
||||||
|
o->write_characters(indent_string.c_str(), new_indent);
|
||||||
|
o->write_character('\"');
|
||||||
|
dump_escaped(i->first, ensure_ascii);
|
||||||
|
o->write_characters("\": ", 3);
|
||||||
|
dump(i->second, true, ensure_ascii, indent_step, new_indent);
|
||||||
|
o->write_characters(",\n", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// last element
|
||||||
|
JSON_ASSERT(i != val.m_data.m_value.object->cend());
|
||||||
|
JSON_ASSERT(std::next(i) == val.m_data.m_value.object->cend());
|
||||||
|
o->write_characters(indent_string.c_str(), new_indent);
|
||||||
|
o->write_character('\"');
|
||||||
|
dump_escaped(i->first, ensure_ascii);
|
||||||
|
o->write_characters("\": ", 3);
|
||||||
|
dump(i->second, true, ensure_ascii, indent_step, new_indent);
|
||||||
|
|
||||||
|
o->write_character('\n');
|
||||||
|
o->write_characters(indent_string.c_str(), current_indent);
|
||||||
|
o->write_character('}');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
o->write_character('{');
|
||||||
|
|
||||||
|
// first n-1 elements
|
||||||
|
auto i = val.m_data.m_value.object->cbegin();
|
||||||
|
for (std::size_t cnt = 0; cnt < val.m_data.m_value.object->size() - 1; ++cnt, ++i)
|
||||||
|
{
|
||||||
|
o->write_character('\"');
|
||||||
|
dump_escaped(i->first, ensure_ascii);
|
||||||
|
o->write_characters("\":", 2);
|
||||||
|
dump(i->second, false, ensure_ascii, indent_step, current_indent);
|
||||||
|
o->write_character(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
// last element
|
||||||
|
JSON_ASSERT(i != val.m_data.m_value.object->cend());
|
||||||
|
JSON_ASSERT(std::next(i) == val.m_data.m_value.object->cend());
|
||||||
|
o->write_character('\"');
|
||||||
|
dump_escaped(i->first, ensure_ascii);
|
||||||
|
o->write_characters("\":", 2);
|
||||||
|
dump(i->second, false, ensure_ascii, indent_step, current_indent);
|
||||||
|
|
||||||
|
o->write_character('}');
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
{
|
||||||
|
if (val.m_data.m_value.array->empty())
|
||||||
|
{
|
||||||
|
o->write_characters("[]", 2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pretty_print)
|
||||||
|
{
|
||||||
|
o->write_characters("[\n", 2);
|
||||||
|
|
||||||
|
// variable to hold indentation for recursive calls
|
||||||
|
const auto new_indent = current_indent + indent_step;
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
|
||||||
|
{
|
||||||
|
indent_string.resize(indent_string.size() * 2, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
// first n-1 elements
|
||||||
|
for (auto i = val.m_data.m_value.array->cbegin();
|
||||||
|
i != val.m_data.m_value.array->cend() - 1; ++i)
|
||||||
|
{
|
||||||
|
o->write_characters(indent_string.c_str(), new_indent);
|
||||||
|
dump(*i, true, ensure_ascii, indent_step, new_indent);
|
||||||
|
o->write_characters(",\n", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// last element
|
||||||
|
JSON_ASSERT(!val.m_data.m_value.array->empty());
|
||||||
|
o->write_characters(indent_string.c_str(), new_indent);
|
||||||
|
dump(val.m_data.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);
|
||||||
|
|
||||||
|
o->write_character('\n');
|
||||||
|
o->write_characters(indent_string.c_str(), current_indent);
|
||||||
|
o->write_character(']');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
o->write_character('[');
|
||||||
|
|
||||||
|
// first n-1 elements
|
||||||
|
for (auto i = val.m_data.m_value.array->cbegin();
|
||||||
|
i != val.m_data.m_value.array->cend() - 1; ++i)
|
||||||
|
{
|
||||||
|
dump(*i, false, ensure_ascii, indent_step, current_indent);
|
||||||
|
o->write_character(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
// last element
|
||||||
|
JSON_ASSERT(!val.m_data.m_value.array->empty());
|
||||||
|
dump(val.m_data.m_value.array->back(), false, ensure_ascii, indent_step, current_indent);
|
||||||
|
|
||||||
|
o->write_character(']');
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::string:
|
||||||
|
{
|
||||||
|
o->write_character('\"');
|
||||||
|
dump_escaped(*val.m_data.m_value.string, ensure_ascii);
|
||||||
|
o->write_character('\"');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::binary:
|
||||||
|
{
|
||||||
|
if (pretty_print)
|
||||||
|
{
|
||||||
|
o->write_characters("{\n", 2);
|
||||||
|
|
||||||
|
// variable to hold indentation for recursive calls
|
||||||
|
const auto new_indent = current_indent + indent_step;
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
|
||||||
|
{
|
||||||
|
indent_string.resize(indent_string.size() * 2, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
o->write_characters(indent_string.c_str(), new_indent);
|
||||||
|
|
||||||
|
o->write_characters("\"bytes\": [", 10);
|
||||||
|
|
||||||
|
if (!val.m_data.m_value.binary->empty())
|
||||||
|
{
|
||||||
|
for (auto i = val.m_data.m_value.binary->cbegin();
|
||||||
|
i != val.m_data.m_value.binary->cend() - 1; ++i)
|
||||||
|
{
|
||||||
|
dump_integer(*i);
|
||||||
|
o->write_characters(", ", 2);
|
||||||
|
}
|
||||||
|
dump_integer(val.m_data.m_value.binary->back());
|
||||||
|
}
|
||||||
|
|
||||||
|
o->write_characters("],\n", 3);
|
||||||
|
o->write_characters(indent_string.c_str(), new_indent);
|
||||||
|
|
||||||
|
o->write_characters("\"subtype\": ", 11);
|
||||||
|
if (val.m_data.m_value.binary->has_subtype())
|
||||||
|
{
|
||||||
|
dump_integer(val.m_data.m_value.binary->subtype());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
o->write_characters("null", 4);
|
||||||
|
}
|
||||||
|
o->write_character('\n');
|
||||||
|
o->write_characters(indent_string.c_str(), current_indent);
|
||||||
|
o->write_character('}');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
o->write_characters("{\"bytes\":[", 10);
|
||||||
|
|
||||||
|
if (!val.m_data.m_value.binary->empty())
|
||||||
|
{
|
||||||
|
for (auto i = val.m_data.m_value.binary->cbegin();
|
||||||
|
i != val.m_data.m_value.binary->cend() - 1; ++i)
|
||||||
|
{
|
||||||
|
dump_integer(*i);
|
||||||
|
o->write_character(',');
|
||||||
|
}
|
||||||
|
dump_integer(val.m_data.m_value.binary->back());
|
||||||
|
}
|
||||||
|
|
||||||
|
o->write_characters("],\"subtype\":", 12);
|
||||||
|
if (val.m_data.m_value.binary->has_subtype())
|
||||||
|
{
|
||||||
|
dump_integer(val.m_data.m_value.binary->subtype());
|
||||||
|
o->write_character('}');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
o->write_characters("null}", 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::boolean:
|
||||||
|
{
|
||||||
|
if (val.m_data.m_value.boolean)
|
||||||
|
{
|
||||||
|
o->write_characters("true", 4);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
o->write_characters("false", 5);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::number_integer:
|
||||||
|
{
|
||||||
|
dump_integer(val.m_data.m_value.number_integer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::number_unsigned:
|
||||||
|
{
|
||||||
|
dump_integer(val.m_data.m_value.number_unsigned);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::number_float:
|
||||||
|
{
|
||||||
|
dump_float(val.m_data.m_value.number_float);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::discarded:
|
||||||
|
{
|
||||||
|
o->write_characters("<discarded>", 11);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::null:
|
||||||
|
{
|
||||||
|
o->write_characters("null", 4);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: // LCOV_EXCL_LINE
|
||||||
|
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_PRIVATE_UNLESS_TESTED:
|
||||||
|
/*!
|
||||||
|
@brief dump escaped string
|
||||||
|
|
||||||
|
Escape a string by replacing certain special characters by a sequence of an
|
||||||
|
escape character (backslash) and another character and other control
|
||||||
|
characters by a sequence of "\u" followed by a four-digit hex
|
||||||
|
representation. The escaped string is written to output stream @a o.
|
||||||
|
|
||||||
|
@param[in] s the string to escape
|
||||||
|
@param[in] ensure_ascii whether to escape non-ASCII characters with
|
||||||
|
\uXXXX sequences
|
||||||
|
|
||||||
|
@complexity Linear in the length of string @a s.
|
||||||
|
*/
|
||||||
|
void dump_escaped(const string_t& s, const bool ensure_ascii)
|
||||||
|
{
|
||||||
|
std::uint32_t codepoint{};
|
||||||
|
std::uint8_t state = UTF8_ACCEPT;
|
||||||
|
std::size_t bytes = 0; // number of bytes written to string_buffer
|
||||||
|
|
||||||
|
// number of bytes written at the point of the last valid byte
|
||||||
|
std::size_t bytes_after_last_accept = 0;
|
||||||
|
std::size_t undumped_chars = 0;
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < s.size(); ++i)
|
||||||
|
{
|
||||||
|
const auto byte = static_cast<std::uint8_t>(s[i]);
|
||||||
|
|
||||||
|
switch (decode(state, codepoint, byte))
|
||||||
|
{
|
||||||
|
case UTF8_ACCEPT: // decode found a new code point
|
||||||
|
{
|
||||||
|
switch (codepoint)
|
||||||
|
{
|
||||||
|
case 0x08: // backspace
|
||||||
|
{
|
||||||
|
string_buffer[bytes++] = '\\';
|
||||||
|
string_buffer[bytes++] = 'b';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0x09: // horizontal tab
|
||||||
|
{
|
||||||
|
string_buffer[bytes++] = '\\';
|
||||||
|
string_buffer[bytes++] = 't';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0x0A: // newline
|
||||||
|
{
|
||||||
|
string_buffer[bytes++] = '\\';
|
||||||
|
string_buffer[bytes++] = 'n';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0x0C: // formfeed
|
||||||
|
{
|
||||||
|
string_buffer[bytes++] = '\\';
|
||||||
|
string_buffer[bytes++] = 'f';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0x0D: // carriage return
|
||||||
|
{
|
||||||
|
string_buffer[bytes++] = '\\';
|
||||||
|
string_buffer[bytes++] = 'r';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0x22: // quotation mark
|
||||||
|
{
|
||||||
|
string_buffer[bytes++] = '\\';
|
||||||
|
string_buffer[bytes++] = '\"';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0x5C: // reverse solidus
|
||||||
|
{
|
||||||
|
string_buffer[bytes++] = '\\';
|
||||||
|
string_buffer[bytes++] = '\\';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// escape control characters (0x00..0x1F) or, if
|
||||||
|
// ensure_ascii parameter is used, non-ASCII characters
|
||||||
|
if ((codepoint <= 0x1F) || (ensure_ascii && (codepoint >= 0x7F)))
|
||||||
|
{
|
||||||
|
if (codepoint <= 0xFFFF)
|
||||||
|
{
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||||
|
static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x",
|
||||||
|
static_cast<std::uint16_t>(codepoint)));
|
||||||
|
bytes += 6;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||||
|
static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x",
|
||||||
|
static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)),
|
||||||
|
static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu))));
|
||||||
|
bytes += 12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// copy byte to buffer (all previous bytes
|
||||||
|
// been copied have in default case above)
|
||||||
|
string_buffer[bytes++] = s[i];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// write buffer and reset index; there must be 13 bytes
|
||||||
|
// left, as this is the maximal number of bytes to be
|
||||||
|
// written ("\uxxxx\uxxxx\0") for one code point
|
||||||
|
if (string_buffer.size() - bytes < 13)
|
||||||
|
{
|
||||||
|
o->write_characters(string_buffer.data(), bytes);
|
||||||
|
bytes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remember the byte position of this accept
|
||||||
|
bytes_after_last_accept = bytes;
|
||||||
|
undumped_chars = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case UTF8_REJECT: // decode found invalid UTF-8 byte
|
||||||
|
{
|
||||||
|
switch (error_handler)
|
||||||
|
{
|
||||||
|
case error_handler_t::strict:
|
||||||
|
{
|
||||||
|
JSON_THROW(type_error::create(316, concat("invalid UTF-8 byte at index ", std::to_string(i), ": 0x", hex_bytes(byte | 0)), nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
case error_handler_t::ignore:
|
||||||
|
case error_handler_t::replace:
|
||||||
|
{
|
||||||
|
// in case we saw this character the first time, we
|
||||||
|
// would like to read it again, because the byte
|
||||||
|
// may be OK for itself, but just not OK for the
|
||||||
|
// previous sequence
|
||||||
|
if (undumped_chars > 0)
|
||||||
|
{
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset length buffer to the last accepted index;
|
||||||
|
// thus removing/ignoring the invalid characters
|
||||||
|
bytes = bytes_after_last_accept;
|
||||||
|
|
||||||
|
if (error_handler == error_handler_t::replace)
|
||||||
|
{
|
||||||
|
// add a replacement character
|
||||||
|
if (ensure_ascii)
|
||||||
|
{
|
||||||
|
string_buffer[bytes++] = '\\';
|
||||||
|
string_buffer[bytes++] = 'u';
|
||||||
|
string_buffer[bytes++] = 'f';
|
||||||
|
string_buffer[bytes++] = 'f';
|
||||||
|
string_buffer[bytes++] = 'f';
|
||||||
|
string_buffer[bytes++] = 'd';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xEF');
|
||||||
|
string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBF');
|
||||||
|
string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBD');
|
||||||
|
}
|
||||||
|
|
||||||
|
// write buffer and reset index; there must be 13 bytes
|
||||||
|
// left, as this is the maximal number of bytes to be
|
||||||
|
// written ("\uxxxx\uxxxx\0") for one code point
|
||||||
|
if (string_buffer.size() - bytes < 13)
|
||||||
|
{
|
||||||
|
o->write_characters(string_buffer.data(), bytes);
|
||||||
|
bytes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes_after_last_accept = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
undumped_chars = 0;
|
||||||
|
|
||||||
|
// continue processing the string
|
||||||
|
state = UTF8_ACCEPT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: // LCOV_EXCL_LINE
|
||||||
|
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: // decode found yet incomplete multi-byte code point
|
||||||
|
{
|
||||||
|
if (!ensure_ascii)
|
||||||
|
{
|
||||||
|
// code point will not be escaped - copy byte to buffer
|
||||||
|
string_buffer[bytes++] = s[i];
|
||||||
|
}
|
||||||
|
++undumped_chars;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// we finished processing the string
|
||||||
|
if (JSON_HEDLEY_LIKELY(state == UTF8_ACCEPT))
|
||||||
|
{
|
||||||
|
// write buffer
|
||||||
|
if (bytes > 0)
|
||||||
|
{
|
||||||
|
o->write_characters(string_buffer.data(), bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we finish reading, but do not accept: string was incomplete
|
||||||
|
switch (error_handler)
|
||||||
|
{
|
||||||
|
case error_handler_t::strict:
|
||||||
|
{
|
||||||
|
JSON_THROW(type_error::create(316, concat("incomplete UTF-8 string; last byte: 0x", hex_bytes(static_cast<std::uint8_t>(s.back() | 0))), nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
case error_handler_t::ignore:
|
||||||
|
{
|
||||||
|
// write all accepted bytes
|
||||||
|
o->write_characters(string_buffer.data(), bytes_after_last_accept);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case error_handler_t::replace:
|
||||||
|
{
|
||||||
|
// write all accepted bytes
|
||||||
|
o->write_characters(string_buffer.data(), bytes_after_last_accept);
|
||||||
|
// add a replacement character
|
||||||
|
if (ensure_ascii)
|
||||||
|
{
|
||||||
|
o->write_characters("\\ufffd", 6);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
o->write_characters("\xEF\xBF\xBD", 3);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: // LCOV_EXCL_LINE
|
||||||
|
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*!
|
||||||
|
@brief count digits
|
||||||
|
|
||||||
|
Count the number of decimal (base 10) digits for an input unsigned integer.
|
||||||
|
|
||||||
|
@param[in] x unsigned integer number to count its digits
|
||||||
|
@return number of decimal digits
|
||||||
|
*/
|
||||||
|
inline unsigned int count_digits(number_unsigned_t x) noexcept
|
||||||
|
{
|
||||||
|
unsigned int n_digits = 1;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (x < 10)
|
||||||
|
{
|
||||||
|
return n_digits;
|
||||||
|
}
|
||||||
|
if (x < 100)
|
||||||
|
{
|
||||||
|
return n_digits + 1;
|
||||||
|
}
|
||||||
|
if (x < 1000)
|
||||||
|
{
|
||||||
|
return n_digits + 2;
|
||||||
|
}
|
||||||
|
if (x < 10000)
|
||||||
|
{
|
||||||
|
return n_digits + 3;
|
||||||
|
}
|
||||||
|
x = x / 10000u;
|
||||||
|
n_digits += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief convert a byte to a uppercase hex representation
|
||||||
|
* @param[in] byte byte to represent
|
||||||
|
* @return representation ("00".."FF")
|
||||||
|
*/
|
||||||
|
static std::string hex_bytes(std::uint8_t byte)
|
||||||
|
{
|
||||||
|
std::string result = "FF";
|
||||||
|
constexpr const char* nibble_to_hex = "0123456789ABCDEF";
|
||||||
|
result[0] = nibble_to_hex[byte / 16];
|
||||||
|
result[1] = nibble_to_hex[byte % 16];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// templates to avoid warnings about useless casts
|
||||||
|
template <typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0>
|
||||||
|
bool is_negative_number(NumberType x)
|
||||||
|
{
|
||||||
|
return x < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename NumberType, enable_if_t <std::is_unsigned<NumberType>::value, int > = 0 >
|
||||||
|
bool is_negative_number(NumberType /*unused*/)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief dump an integer
|
||||||
|
|
||||||
|
Dump a given integer to output stream @a o. Works internally with
|
||||||
|
@a number_buffer.
|
||||||
|
|
||||||
|
@param[in] x integer number (signed or unsigned) to dump
|
||||||
|
@tparam NumberType either @a number_integer_t or @a number_unsigned_t
|
||||||
|
*/
|
||||||
|
template < typename NumberType, detail::enable_if_t <
|
||||||
|
std::is_integral<NumberType>::value ||
|
||||||
|
std::is_same<NumberType, number_unsigned_t>::value ||
|
||||||
|
std::is_same<NumberType, number_integer_t>::value ||
|
||||||
|
std::is_same<NumberType, binary_char_t>::value,
|
||||||
|
int > = 0 >
|
||||||
|
void dump_integer(NumberType x)
|
||||||
|
{
|
||||||
|
static constexpr std::array<std::array<char, 2>, 100> digits_to_99
|
||||||
|
{
|
||||||
|
{
|
||||||
|
{{'0', '0'}}, {{'0', '1'}}, {{'0', '2'}}, {{'0', '3'}}, {{'0', '4'}}, {{'0', '5'}}, {{'0', '6'}}, {{'0', '7'}}, {{'0', '8'}}, {{'0', '9'}},
|
||||||
|
{{'1', '0'}}, {{'1', '1'}}, {{'1', '2'}}, {{'1', '3'}}, {{'1', '4'}}, {{'1', '5'}}, {{'1', '6'}}, {{'1', '7'}}, {{'1', '8'}}, {{'1', '9'}},
|
||||||
|
{{'2', '0'}}, {{'2', '1'}}, {{'2', '2'}}, {{'2', '3'}}, {{'2', '4'}}, {{'2', '5'}}, {{'2', '6'}}, {{'2', '7'}}, {{'2', '8'}}, {{'2', '9'}},
|
||||||
|
{{'3', '0'}}, {{'3', '1'}}, {{'3', '2'}}, {{'3', '3'}}, {{'3', '4'}}, {{'3', '5'}}, {{'3', '6'}}, {{'3', '7'}}, {{'3', '8'}}, {{'3', '9'}},
|
||||||
|
{{'4', '0'}}, {{'4', '1'}}, {{'4', '2'}}, {{'4', '3'}}, {{'4', '4'}}, {{'4', '5'}}, {{'4', '6'}}, {{'4', '7'}}, {{'4', '8'}}, {{'4', '9'}},
|
||||||
|
{{'5', '0'}}, {{'5', '1'}}, {{'5', '2'}}, {{'5', '3'}}, {{'5', '4'}}, {{'5', '5'}}, {{'5', '6'}}, {{'5', '7'}}, {{'5', '8'}}, {{'5', '9'}},
|
||||||
|
{{'6', '0'}}, {{'6', '1'}}, {{'6', '2'}}, {{'6', '3'}}, {{'6', '4'}}, {{'6', '5'}}, {{'6', '6'}}, {{'6', '7'}}, {{'6', '8'}}, {{'6', '9'}},
|
||||||
|
{{'7', '0'}}, {{'7', '1'}}, {{'7', '2'}}, {{'7', '3'}}, {{'7', '4'}}, {{'7', '5'}}, {{'7', '6'}}, {{'7', '7'}}, {{'7', '8'}}, {{'7', '9'}},
|
||||||
|
{{'8', '0'}}, {{'8', '1'}}, {{'8', '2'}}, {{'8', '3'}}, {{'8', '4'}}, {{'8', '5'}}, {{'8', '6'}}, {{'8', '7'}}, {{'8', '8'}}, {{'8', '9'}},
|
||||||
|
{{'9', '0'}}, {{'9', '1'}}, {{'9', '2'}}, {{'9', '3'}}, {{'9', '4'}}, {{'9', '5'}}, {{'9', '6'}}, {{'9', '7'}}, {{'9', '8'}}, {{'9', '9'}},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// special case for "0"
|
||||||
|
if (x == 0)
|
||||||
|
{
|
||||||
|
o->write_character('0');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// use a pointer to fill the buffer
|
||||||
|
auto buffer_ptr = number_buffer.begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto,cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||||
|
|
||||||
|
number_unsigned_t abs_value;
|
||||||
|
|
||||||
|
unsigned int n_chars{};
|
||||||
|
|
||||||
|
if (is_negative_number(x))
|
||||||
|
{
|
||||||
|
*buffer_ptr = '-';
|
||||||
|
abs_value = remove_sign(static_cast<number_integer_t>(x));
|
||||||
|
|
||||||
|
// account one more byte for the minus sign
|
||||||
|
n_chars = 1 + count_digits(abs_value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
abs_value = static_cast<number_unsigned_t>(x);
|
||||||
|
n_chars = count_digits(abs_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// spare 1 byte for '\0'
|
||||||
|
JSON_ASSERT(n_chars < number_buffer.size() - 1);
|
||||||
|
|
||||||
|
// jump to the end to generate the string from backward,
|
||||||
|
// so we later avoid reversing the result
|
||||||
|
buffer_ptr += n_chars;
|
||||||
|
|
||||||
|
// Fast int2ascii implementation inspired by "Fastware" talk by Andrei Alexandrescu
|
||||||
|
// See: https://www.youtube.com/watch?v=o4-CwDo2zpg
|
||||||
|
while (abs_value >= 100)
|
||||||
|
{
|
||||||
|
const auto digits_index = static_cast<unsigned>((abs_value % 100));
|
||||||
|
abs_value /= 100;
|
||||||
|
*(--buffer_ptr) = digits_to_99[digits_index][1];
|
||||||
|
*(--buffer_ptr) = digits_to_99[digits_index][0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (abs_value >= 10)
|
||||||
|
{
|
||||||
|
const auto digits_index = static_cast<unsigned>(abs_value);
|
||||||
|
*(--buffer_ptr) = digits_to_99[digits_index][1];
|
||||||
|
*(--buffer_ptr) = digits_to_99[digits_index][0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*(--buffer_ptr) = static_cast<char>('0' + abs_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
o->write_characters(number_buffer.data(), n_chars);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief dump a floating-point number
|
||||||
|
|
||||||
|
Dump a given floating-point number to output stream @a o. Works internally
|
||||||
|
with @a number_buffer.
|
||||||
|
|
||||||
|
@param[in] x floating-point number to dump
|
||||||
|
*/
|
||||||
|
void dump_float(number_float_t x)
|
||||||
|
{
|
||||||
|
// NaN / inf
|
||||||
|
if (!std::isfinite(x))
|
||||||
|
{
|
||||||
|
o->write_characters("null", 4);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If number_float_t is an IEEE-754 single or double precision number,
|
||||||
|
// use the Grisu2 algorithm to produce short numbers which are
|
||||||
|
// guaranteed to round-trip, using strtof and strtod, resp.
|
||||||
|
//
|
||||||
|
// NB: The test below works if <long double> == <double>.
|
||||||
|
static constexpr bool is_ieee_single_or_double
|
||||||
|
= (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 24 && std::numeric_limits<number_float_t>::max_exponent == 128) ||
|
||||||
|
(std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 53 && std::numeric_limits<number_float_t>::max_exponent == 1024);
|
||||||
|
|
||||||
|
dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>());
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/)
|
||||||
|
{
|
||||||
|
auto* begin = number_buffer.data();
|
||||||
|
auto* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x);
|
||||||
|
|
||||||
|
o->write_characters(begin, static_cast<size_t>(end - begin));
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/)
|
||||||
|
{
|
||||||
|
// get number of digits for a float -> text -> float round-trip
|
||||||
|
static constexpr auto d = std::numeric_limits<number_float_t>::max_digits10;
|
||||||
|
|
||||||
|
// the actual conversion
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||||
|
std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x);
|
||||||
|
|
||||||
|
// negative value indicates an error
|
||||||
|
JSON_ASSERT(len > 0);
|
||||||
|
// check if buffer was large enough
|
||||||
|
JSON_ASSERT(static_cast<std::size_t>(len) < number_buffer.size());
|
||||||
|
|
||||||
|
// erase thousands separator
|
||||||
|
if (thousands_sep != '\0')
|
||||||
|
{
|
||||||
|
// NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::remove returns an iterator, see https://github.com/nlohmann/json/issues/3081
|
||||||
|
const auto end = std::remove(number_buffer.begin(), number_buffer.begin() + len, thousands_sep);
|
||||||
|
std::fill(end, number_buffer.end(), '\0');
|
||||||
|
JSON_ASSERT((end - number_buffer.begin()) <= len);
|
||||||
|
len = (end - number_buffer.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert decimal point to '.'
|
||||||
|
if (decimal_point != '\0' && decimal_point != '.')
|
||||||
|
{
|
||||||
|
// NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::find returns an iterator, see https://github.com/nlohmann/json/issues/3081
|
||||||
|
const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point);
|
||||||
|
if (dec_pos != number_buffer.end())
|
||||||
|
{
|
||||||
|
*dec_pos = '.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
o->write_characters(number_buffer.data(), static_cast<std::size_t>(len));
|
||||||
|
|
||||||
|
// determine if we need to append ".0"
|
||||||
|
const bool value_is_int_like =
|
||||||
|
std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1,
|
||||||
|
[](char c)
|
||||||
|
{
|
||||||
|
return c == '.' || c == 'e';
|
||||||
|
});
|
||||||
|
|
||||||
|
if (value_is_int_like)
|
||||||
|
{
|
||||||
|
o->write_characters(".0", 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief check whether a string is UTF-8 encoded
|
||||||
|
|
||||||
|
The function checks each byte of a string whether it is UTF-8 encoded. The
|
||||||
|
result of the check is stored in the @a state parameter. The function must
|
||||||
|
be called initially with state 0 (accept). State 1 means the string must
|
||||||
|
be rejected, because the current byte is not allowed. If the string is
|
||||||
|
completely processed, but the state is non-zero, the string ended
|
||||||
|
prematurely; that is, the last byte indicated more bytes should have
|
||||||
|
followed.
|
||||||
|
|
||||||
|
@param[in,out] state the state of the decoding
|
||||||
|
@param[in,out] codep codepoint (valid only if resulting state is UTF8_ACCEPT)
|
||||||
|
@param[in] byte next byte to decode
|
||||||
|
@return new state
|
||||||
|
|
||||||
|
@note The function has been edited: a std::array is used.
|
||||||
|
|
||||||
|
@copyright Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
|
||||||
|
@sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
|
||||||
|
*/
|
||||||
|
static std::uint8_t decode(std::uint8_t& state, std::uint32_t& codep, const std::uint8_t byte) noexcept
|
||||||
|
{
|
||||||
|
static const std::array<std::uint8_t, 400> utf8d =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF
|
||||||
|
8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF
|
||||||
|
0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF
|
||||||
|
0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF
|
||||||
|
0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2
|
||||||
|
1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4
|
||||||
|
1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6
|
||||||
|
1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
JSON_ASSERT(byte < utf8d.size());
|
||||||
|
const std::uint8_t type = utf8d[byte];
|
||||||
|
|
||||||
|
codep = (state != UTF8_ACCEPT)
|
||||||
|
? (byte & 0x3fu) | (codep << 6u)
|
||||||
|
: (0xFFu >> type) & (byte);
|
||||||
|
|
||||||
|
const std::size_t index = 256u + static_cast<size_t>(state) * 16u + static_cast<size_t>(type);
|
||||||
|
JSON_ASSERT(index < utf8d.size());
|
||||||
|
state = utf8d[index];
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Overload to make the compiler happy while it is instantiating
|
||||||
|
* dump_integer for number_unsigned_t.
|
||||||
|
* Must never be called.
|
||||||
|
*/
|
||||||
|
number_unsigned_t remove_sign(number_unsigned_t x)
|
||||||
|
{
|
||||||
|
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
|
||||||
|
return x; // LCOV_EXCL_LINE
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper function for dump_integer
|
||||||
|
*
|
||||||
|
* This function takes a negative signed integer and returns its absolute
|
||||||
|
* value as unsigned integer. The plus/minus shuffling is necessary as we can
|
||||||
|
* not directly remove the sign of an arbitrary signed integer as the
|
||||||
|
* absolute values of INT_MIN and INT_MAX are usually not the same. See
|
||||||
|
* #1708 for details.
|
||||||
|
*/
|
||||||
|
inline number_unsigned_t remove_sign(number_integer_t x) noexcept
|
||||||
|
{
|
||||||
|
JSON_ASSERT(x < 0 && x < (std::numeric_limits<number_integer_t>::max)()); // NOLINT(misc-redundant-expression)
|
||||||
|
return static_cast<number_unsigned_t>(-(x + 1)) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// the output of the serializer
|
||||||
|
output_adapter_t<char> o = nullptr;
|
||||||
|
|
||||||
|
/// a (hopefully) large enough character buffer
|
||||||
|
std::array<char, 64> number_buffer{{}};
|
||||||
|
|
||||||
|
/// the locale
|
||||||
|
const std::lconv* loc = nullptr;
|
||||||
|
/// the locale's thousand separator character
|
||||||
|
const char thousands_sep = '\0';
|
||||||
|
/// the locale's decimal point character
|
||||||
|
const char decimal_point = '\0';
|
||||||
|
|
||||||
|
/// string buffer
|
||||||
|
std::array<char, 512> string_buffer{{}};
|
||||||
|
|
||||||
|
/// the indentation character
|
||||||
|
const char indent_char;
|
||||||
|
/// the indentation string
|
||||||
|
string_t indent_string;
|
||||||
|
|
||||||
|
/// error_handler how to react on decoding errors
|
||||||
|
const error_handler_t error_handler;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,146 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstring> // strlen
|
||||||
|
#include <string> // string
|
||||||
|
#include <utility> // forward
|
||||||
|
|
||||||
|
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||||
|
#include <nlohmann/detail/meta/detected.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
inline std::size_t concat_length()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
inline std::size_t concat_length(const char* cstr, const Args& ... rest);
|
||||||
|
|
||||||
|
template<typename StringType, typename... Args>
|
||||||
|
inline std::size_t concat_length(const StringType& str, const Args& ... rest);
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
inline std::size_t concat_length(const char /*c*/, const Args& ... rest)
|
||||||
|
{
|
||||||
|
return 1 + concat_length(rest...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
inline std::size_t concat_length(const char* cstr, const Args& ... rest)
|
||||||
|
{
|
||||||
|
// cppcheck-suppress ignoredReturnValue
|
||||||
|
return ::strlen(cstr) + concat_length(rest...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename StringType, typename... Args>
|
||||||
|
inline std::size_t concat_length(const StringType& str, const Args& ... rest)
|
||||||
|
{
|
||||||
|
return str.size() + concat_length(rest...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename OutStringType>
|
||||||
|
inline void concat_into(OutStringType& /*out*/)
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<typename StringType, typename Arg>
|
||||||
|
using string_can_append = decltype(std::declval<StringType&>().append(std::declval < Arg && > ()));
|
||||||
|
|
||||||
|
template<typename StringType, typename Arg>
|
||||||
|
using detect_string_can_append = is_detected<string_can_append, StringType, Arg>;
|
||||||
|
|
||||||
|
template<typename StringType, typename Arg>
|
||||||
|
using string_can_append_op = decltype(std::declval<StringType&>() += std::declval < Arg && > ());
|
||||||
|
|
||||||
|
template<typename StringType, typename Arg>
|
||||||
|
using detect_string_can_append_op = is_detected<string_can_append_op, StringType, Arg>;
|
||||||
|
|
||||||
|
template<typename StringType, typename Arg>
|
||||||
|
using string_can_append_iter = decltype(std::declval<StringType&>().append(std::declval<const Arg&>().begin(), std::declval<const Arg&>().end()));
|
||||||
|
|
||||||
|
template<typename StringType, typename Arg>
|
||||||
|
using detect_string_can_append_iter = is_detected<string_can_append_iter, StringType, Arg>;
|
||||||
|
|
||||||
|
template<typename StringType, typename Arg>
|
||||||
|
using string_can_append_data = decltype(std::declval<StringType&>().append(std::declval<const Arg&>().data(), std::declval<const Arg&>().size()));
|
||||||
|
|
||||||
|
template<typename StringType, typename Arg>
|
||||||
|
using detect_string_can_append_data = is_detected<string_can_append_data, StringType, Arg>;
|
||||||
|
|
||||||
|
template < typename OutStringType, typename Arg, typename... Args,
|
||||||
|
enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
|
||||||
|
&& detect_string_can_append_op<OutStringType, Arg>::value, int > = 0 >
|
||||||
|
inline void concat_into(OutStringType& out, Arg && arg, Args && ... rest);
|
||||||
|
|
||||||
|
template < typename OutStringType, typename Arg, typename... Args,
|
||||||
|
enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
|
||||||
|
&& !detect_string_can_append_op<OutStringType, Arg>::value
|
||||||
|
&& detect_string_can_append_iter<OutStringType, Arg>::value, int > = 0 >
|
||||||
|
inline void concat_into(OutStringType& out, const Arg& arg, Args && ... rest);
|
||||||
|
|
||||||
|
template < typename OutStringType, typename Arg, typename... Args,
|
||||||
|
enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
|
||||||
|
&& !detect_string_can_append_op<OutStringType, Arg>::value
|
||||||
|
&& !detect_string_can_append_iter<OutStringType, Arg>::value
|
||||||
|
&& detect_string_can_append_data<OutStringType, Arg>::value, int > = 0 >
|
||||||
|
inline void concat_into(OutStringType& out, const Arg& arg, Args && ... rest);
|
||||||
|
|
||||||
|
template<typename OutStringType, typename Arg, typename... Args,
|
||||||
|
enable_if_t<detect_string_can_append<OutStringType, Arg>::value, int> = 0>
|
||||||
|
inline void concat_into(OutStringType& out, Arg && arg, Args && ... rest)
|
||||||
|
{
|
||||||
|
out.append(std::forward<Arg>(arg));
|
||||||
|
concat_into(out, std::forward<Args>(rest)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename OutStringType, typename Arg, typename... Args,
|
||||||
|
enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
|
||||||
|
&& detect_string_can_append_op<OutStringType, Arg>::value, int > >
|
||||||
|
inline void concat_into(OutStringType& out, Arg&& arg, Args&& ... rest)
|
||||||
|
{
|
||||||
|
out += std::forward<Arg>(arg);
|
||||||
|
concat_into(out, std::forward<Args>(rest)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename OutStringType, typename Arg, typename... Args,
|
||||||
|
enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
|
||||||
|
&& !detect_string_can_append_op<OutStringType, Arg>::value
|
||||||
|
&& detect_string_can_append_iter<OutStringType, Arg>::value, int > >
|
||||||
|
inline void concat_into(OutStringType& out, const Arg& arg, Args&& ... rest)
|
||||||
|
{
|
||||||
|
out.append(arg.begin(), arg.end());
|
||||||
|
concat_into(out, std::forward<Args>(rest)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename OutStringType, typename Arg, typename... Args,
|
||||||
|
enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
|
||||||
|
&& !detect_string_can_append_op<OutStringType, Arg>::value
|
||||||
|
&& !detect_string_can_append_iter<OutStringType, Arg>::value
|
||||||
|
&& detect_string_can_append_data<OutStringType, Arg>::value, int > >
|
||||||
|
inline void concat_into(OutStringType& out, const Arg& arg, Args&& ... rest)
|
||||||
|
{
|
||||||
|
out.append(arg.data(), arg.size());
|
||||||
|
concat_into(out, std::forward<Args>(rest)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename OutStringType = std::string, typename... Args>
|
||||||
|
inline OutStringType concat(Args && ... args)
|
||||||
|
{
|
||||||
|
OutStringType str;
|
||||||
|
str.reserve(concat_length(args...));
|
||||||
|
concat_into(str, std::forward<Args>(args)...);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <nlohmann/detail/abi_macros.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief replace all occurrences of a substring by another string
|
||||||
|
|
||||||
|
@param[in,out] s the string to manipulate; changed so that all
|
||||||
|
occurrences of @a f are replaced with @a t
|
||||||
|
@param[in] f the substring to replace with @a t
|
||||||
|
@param[in] t the string to replace @a f
|
||||||
|
|
||||||
|
@pre The search string @a f must not be empty. **This precondition is
|
||||||
|
enforced with an assertion.**
|
||||||
|
|
||||||
|
@since version 2.0.0
|
||||||
|
*/
|
||||||
|
template<typename StringType>
|
||||||
|
inline void replace_substring(StringType& s, const StringType& f,
|
||||||
|
const StringType& t)
|
||||||
|
{
|
||||||
|
JSON_ASSERT(!f.empty());
|
||||||
|
for (auto pos = s.find(f); // find first occurrence of f
|
||||||
|
pos != StringType::npos; // make sure f was found
|
||||||
|
s.replace(pos, f.size(), t), // replace with t, and
|
||||||
|
pos = s.find(f, pos + t.size())) // find next occurrence of f
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief string escaping as described in RFC 6901 (Sect. 4)
|
||||||
|
* @param[in] s string to escape
|
||||||
|
* @return escaped string
|
||||||
|
*
|
||||||
|
* Note the order of escaping "~" to "~0" and "/" to "~1" is important.
|
||||||
|
*/
|
||||||
|
template<typename StringType>
|
||||||
|
inline StringType escape(StringType s)
|
||||||
|
{
|
||||||
|
replace_substring(s, StringType{"~"}, StringType{"~0"});
|
||||||
|
replace_substring(s, StringType{"/"}, StringType{"~1"});
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief string unescaping as described in RFC 6901 (Sect. 4)
|
||||||
|
* @param[in] s string to unescape
|
||||||
|
* @return unescaped string
|
||||||
|
*
|
||||||
|
* Note the order of escaping "~1" to "/" and "~0" to "~" is important.
|
||||||
|
*/
|
||||||
|
template<typename StringType>
|
||||||
|
static void unescape(StringType& s)
|
||||||
|
{
|
||||||
|
replace_substring(s, StringType{"~1"}, StringType{"/"});
|
||||||
|
replace_substring(s, StringType{"~0"}, StringType{"~"});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,118 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array> // array
|
||||||
|
#include <cstddef> // size_t
|
||||||
|
#include <cstdint> // uint8_t
|
||||||
|
#include <string> // string
|
||||||
|
|
||||||
|
#include <nlohmann/detail/macro_scope.hpp>
|
||||||
|
#if JSON_HAS_THREE_WAY_COMPARISON
|
||||||
|
#include <compare> // partial_ordering
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
///////////////////////////
|
||||||
|
// JSON type enumeration //
|
||||||
|
///////////////////////////
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief the JSON type enumeration
|
||||||
|
|
||||||
|
This enumeration collects the different JSON types. It is internally used to
|
||||||
|
distinguish the stored values, and the functions @ref basic_json::is_null(),
|
||||||
|
@ref basic_json::is_object(), @ref basic_json::is_array(),
|
||||||
|
@ref basic_json::is_string(), @ref basic_json::is_boolean(),
|
||||||
|
@ref basic_json::is_number() (with @ref basic_json::is_number_integer(),
|
||||||
|
@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()),
|
||||||
|
@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and
|
||||||
|
@ref basic_json::is_structured() rely on it.
|
||||||
|
|
||||||
|
@note There are three enumeration entries (number_integer, number_unsigned, and
|
||||||
|
number_float), because the library distinguishes these three types for numbers:
|
||||||
|
@ref basic_json::number_unsigned_t is used for unsigned integers,
|
||||||
|
@ref basic_json::number_integer_t is used for signed integers, and
|
||||||
|
@ref basic_json::number_float_t is used for floating-point numbers or to
|
||||||
|
approximate integers which do not fit in the limits of their respective type.
|
||||||
|
|
||||||
|
@sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON
|
||||||
|
value with the default value for a given type
|
||||||
|
|
||||||
|
@since version 1.0.0
|
||||||
|
*/
|
||||||
|
enum class value_t : std::uint8_t
|
||||||
|
{
|
||||||
|
null, ///< null value
|
||||||
|
object, ///< object (unordered set of name/value pairs)
|
||||||
|
array, ///< array (ordered collection of values)
|
||||||
|
string, ///< string value
|
||||||
|
boolean, ///< boolean value
|
||||||
|
number_integer, ///< number value (signed integer)
|
||||||
|
number_unsigned, ///< number value (unsigned integer)
|
||||||
|
number_float, ///< number value (floating-point)
|
||||||
|
binary, ///< binary array (ordered collection of bytes)
|
||||||
|
discarded ///< discarded by the parser callback function
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief comparison operator for JSON types
|
||||||
|
|
||||||
|
Returns an ordering that is similar to Python:
|
||||||
|
- order: null < boolean < number < object < array < string < binary
|
||||||
|
- furthermore, each type is not smaller than itself
|
||||||
|
- discarded values are not comparable
|
||||||
|
- binary is represented as a b"" string in python and directly comparable to a
|
||||||
|
string; however, making a binary array directly comparable with a string would
|
||||||
|
be surprising behavior in a JSON file.
|
||||||
|
|
||||||
|
@since version 1.0.0
|
||||||
|
*/
|
||||||
|
#if JSON_HAS_THREE_WAY_COMPARISON
|
||||||
|
inline std::partial_ordering operator<=>(const value_t lhs, const value_t rhs) noexcept // *NOPAD*
|
||||||
|
#else
|
||||||
|
inline bool operator<(const value_t lhs, const value_t rhs) noexcept
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
static constexpr std::array<std::uint8_t, 9> order = {{
|
||||||
|
0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */,
|
||||||
|
1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */,
|
||||||
|
6 /* binary */
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto l_index = static_cast<std::size_t>(lhs);
|
||||||
|
const auto r_index = static_cast<std::size_t>(rhs);
|
||||||
|
#if JSON_HAS_THREE_WAY_COMPARISON
|
||||||
|
if (l_index < order.size() && r_index < order.size())
|
||||||
|
{
|
||||||
|
return order[l_index] <=> order[r_index]; // *NOPAD*
|
||||||
|
}
|
||||||
|
return std::partial_ordering::unordered;
|
||||||
|
#else
|
||||||
|
return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// GCC selects the built-in operator< over an operator rewritten from
|
||||||
|
// a user-defined spaceship operator
|
||||||
|
// Clang, MSVC, and ICC select the rewritten candidate
|
||||||
|
// (see GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105200)
|
||||||
|
#if JSON_HAS_THREE_WAY_COMPARISON && defined(__GNUC__)
|
||||||
|
inline bool operator<(const value_t lhs, const value_t rhs) noexcept
|
||||||
|
{
|
||||||
|
return std::is_lt(lhs <=> rhs); // *NOPAD*
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,75 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
||||||
|
#define INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
||||||
|
|
||||||
|
#include <cstdint> // int64_t, uint64_t
|
||||||
|
#include <map> // map
|
||||||
|
#include <memory> // allocator
|
||||||
|
#include <string> // string
|
||||||
|
#include <vector> // vector
|
||||||
|
|
||||||
|
#include <nlohmann/detail/abi_macros.hpp>
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief namespace for Niels Lohmann
|
||||||
|
@see https://github.com/nlohmann
|
||||||
|
@since version 1.0.0
|
||||||
|
*/
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief default JSONSerializer template argument
|
||||||
|
|
||||||
|
This serializer ignores the template arguments and uses ADL
|
||||||
|
([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl))
|
||||||
|
for serialization.
|
||||||
|
*/
|
||||||
|
template<typename T = void, typename SFINAE = void>
|
||||||
|
struct adl_serializer;
|
||||||
|
|
||||||
|
/// a class to store JSON values
|
||||||
|
/// @sa https://json.nlohmann.me/api/basic_json/
|
||||||
|
template<template<typename U, typename V, typename... Args> class ObjectType =
|
||||||
|
std::map,
|
||||||
|
template<typename U, typename... Args> class ArrayType = std::vector,
|
||||||
|
class StringType = std::string, class BooleanType = bool,
|
||||||
|
class NumberIntegerType = std::int64_t,
|
||||||
|
class NumberUnsignedType = std::uint64_t,
|
||||||
|
class NumberFloatType = double,
|
||||||
|
template<typename U> class AllocatorType = std::allocator,
|
||||||
|
template<typename T, typename SFINAE = void> class JSONSerializer =
|
||||||
|
adl_serializer,
|
||||||
|
class BinaryType = std::vector<std::uint8_t>, // cppcheck-suppress syntaxError
|
||||||
|
class CustomBaseClass = void>
|
||||||
|
class basic_json;
|
||||||
|
|
||||||
|
/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document
|
||||||
|
/// @sa https://json.nlohmann.me/api/json_pointer/
|
||||||
|
template<typename RefStringType>
|
||||||
|
class json_pointer;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief default specialization
|
||||||
|
@sa https://json.nlohmann.me/api/json/
|
||||||
|
*/
|
||||||
|
using json = basic_json<>;
|
||||||
|
|
||||||
|
/// @brief a minimal map-like container that preserves insertion order
|
||||||
|
/// @sa https://json.nlohmann.me/api/ordered_map/
|
||||||
|
template<class Key, class T, class IgnoredLess, class Allocator>
|
||||||
|
struct ordered_map;
|
||||||
|
|
||||||
|
/// @brief specialization that maintains the insertion order of object keys
|
||||||
|
/// @sa https://json.nlohmann.me/api/ordered_json/
|
||||||
|
using ordered_json = basic_json<nlohmann::ordered_map>;
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
||||||
|
|
@ -0,0 +1,359 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional> // equal_to, less
|
||||||
|
#include <initializer_list> // initializer_list
|
||||||
|
#include <iterator> // input_iterator_tag, iterator_traits
|
||||||
|
#include <memory> // allocator
|
||||||
|
#include <stdexcept> // for out_of_range
|
||||||
|
#include <type_traits> // enable_if, is_convertible
|
||||||
|
#include <utility> // pair
|
||||||
|
#include <vector> // vector
|
||||||
|
|
||||||
|
#include <nlohmann/detail/macro_scope.hpp>
|
||||||
|
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/// ordered_map: a minimal map-like container that preserves insertion order
|
||||||
|
/// for use within nlohmann::basic_json<ordered_map>
|
||||||
|
template <class Key, class T, class IgnoredLess = std::less<Key>,
|
||||||
|
class Allocator = std::allocator<std::pair<const Key, T>>>
|
||||||
|
struct ordered_map : std::vector<std::pair<const Key, T>, Allocator>
|
||||||
|
{
|
||||||
|
using key_type = Key;
|
||||||
|
using mapped_type = T;
|
||||||
|
using Container = std::vector<std::pair<const Key, T>, Allocator>;
|
||||||
|
using iterator = typename Container::iterator;
|
||||||
|
using const_iterator = typename Container::const_iterator;
|
||||||
|
using size_type = typename Container::size_type;
|
||||||
|
using value_type = typename Container::value_type;
|
||||||
|
#ifdef JSON_HAS_CPP_14
|
||||||
|
using key_compare = std::equal_to<>;
|
||||||
|
#else
|
||||||
|
using key_compare = std::equal_to<Key>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Explicit constructors instead of `using Container::Container`
|
||||||
|
// otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4)
|
||||||
|
ordered_map() noexcept(noexcept(Container())) : Container{} {}
|
||||||
|
explicit ordered_map(const Allocator& alloc) noexcept(noexcept(Container(alloc))) : Container{alloc} {}
|
||||||
|
template <class It>
|
||||||
|
ordered_map(It first, It last, const Allocator& alloc = Allocator())
|
||||||
|
: Container{first, last, alloc} {}
|
||||||
|
ordered_map(std::initializer_list<value_type> init, const Allocator& alloc = Allocator() )
|
||||||
|
: Container{init, alloc} {}
|
||||||
|
|
||||||
|
std::pair<iterator, bool> emplace(const key_type& key, T&& t)
|
||||||
|
{
|
||||||
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
|
{
|
||||||
|
if (m_compare(it->first, key))
|
||||||
|
{
|
||||||
|
return {it, false};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Container::emplace_back(key, std::forward<T>(t));
|
||||||
|
return {std::prev(this->end()), true};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class KeyType, detail::enable_if_t<
|
||||||
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
|
std::pair<iterator, bool> emplace(KeyType && key, T && t)
|
||||||
|
{
|
||||||
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
|
{
|
||||||
|
if (m_compare(it->first, key))
|
||||||
|
{
|
||||||
|
return {it, false};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Container::emplace_back(std::forward<KeyType>(key), std::forward<T>(t));
|
||||||
|
return {std::prev(this->end()), true};
|
||||||
|
}
|
||||||
|
|
||||||
|
T& operator[](const key_type& key)
|
||||||
|
{
|
||||||
|
return emplace(key, T{}).first->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class KeyType, detail::enable_if_t<
|
||||||
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
|
T & operator[](KeyType && key)
|
||||||
|
{
|
||||||
|
return emplace(std::forward<KeyType>(key), T{}).first->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
const T& operator[](const key_type& key) const
|
||||||
|
{
|
||||||
|
return at(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class KeyType, detail::enable_if_t<
|
||||||
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
|
const T & operator[](KeyType && key) const
|
||||||
|
{
|
||||||
|
return at(std::forward<KeyType>(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
T& at(const key_type& key)
|
||||||
|
{
|
||||||
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
|
{
|
||||||
|
if (m_compare(it->first, key))
|
||||||
|
{
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_THROW(std::out_of_range("key not found"));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class KeyType, detail::enable_if_t<
|
||||||
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
|
T & at(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
|
||||||
|
{
|
||||||
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
|
{
|
||||||
|
if (m_compare(it->first, key))
|
||||||
|
{
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_THROW(std::out_of_range("key not found"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const T& at(const key_type& key) const
|
||||||
|
{
|
||||||
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
|
{
|
||||||
|
if (m_compare(it->first, key))
|
||||||
|
{
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_THROW(std::out_of_range("key not found"));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class KeyType, detail::enable_if_t<
|
||||||
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
|
const T & at(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
|
||||||
|
{
|
||||||
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
|
{
|
||||||
|
if (m_compare(it->first, key))
|
||||||
|
{
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_THROW(std::out_of_range("key not found"));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type erase(const key_type& key)
|
||||||
|
{
|
||||||
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
|
{
|
||||||
|
if (m_compare(it->first, key))
|
||||||
|
{
|
||||||
|
// Since we cannot move const Keys, re-construct them in place
|
||||||
|
for (auto next = it; ++next != this->end(); ++it)
|
||||||
|
{
|
||||||
|
it->~value_type(); // Destroy but keep allocation
|
||||||
|
new (&*it) value_type{std::move(*next)};
|
||||||
|
}
|
||||||
|
Container::pop_back();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class KeyType, detail::enable_if_t<
|
||||||
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
|
size_type erase(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
|
||||||
|
{
|
||||||
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
|
{
|
||||||
|
if (m_compare(it->first, key))
|
||||||
|
{
|
||||||
|
// Since we cannot move const Keys, re-construct them in place
|
||||||
|
for (auto next = it; ++next != this->end(); ++it)
|
||||||
|
{
|
||||||
|
it->~value_type(); // Destroy but keep allocation
|
||||||
|
new (&*it) value_type{std::move(*next)};
|
||||||
|
}
|
||||||
|
Container::pop_back();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator erase(iterator pos)
|
||||||
|
{
|
||||||
|
return erase(pos, std::next(pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator erase(iterator first, iterator last)
|
||||||
|
{
|
||||||
|
if (first == last)
|
||||||
|
{
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto elements_affected = std::distance(first, last);
|
||||||
|
const auto offset = std::distance(Container::begin(), first);
|
||||||
|
|
||||||
|
// This is the start situation. We need to delete elements_affected
|
||||||
|
// elements (3 in this example: e, f, g), and need to return an
|
||||||
|
// iterator past the last deleted element (h in this example).
|
||||||
|
// Note that offset is the distance from the start of the vector
|
||||||
|
// to first. We will need this later.
|
||||||
|
|
||||||
|
// [ a, b, c, d, e, f, g, h, i, j ]
|
||||||
|
// ^ ^
|
||||||
|
// first last
|
||||||
|
|
||||||
|
// Since we cannot move const Keys, we re-construct them in place.
|
||||||
|
// We start at first and re-construct (viz. copy) the elements from
|
||||||
|
// the back of the vector. Example for first iteration:
|
||||||
|
|
||||||
|
// ,--------.
|
||||||
|
// v | destroy e and re-construct with h
|
||||||
|
// [ a, b, c, d, e, f, g, h, i, j ]
|
||||||
|
// ^ ^
|
||||||
|
// it it + elements_affected
|
||||||
|
|
||||||
|
for (auto it = first; std::next(it, elements_affected) != Container::end(); ++it)
|
||||||
|
{
|
||||||
|
it->~value_type(); // destroy but keep allocation
|
||||||
|
new (&*it) value_type{std::move(*std::next(it, elements_affected))}; // "move" next element to it
|
||||||
|
}
|
||||||
|
|
||||||
|
// [ a, b, c, d, h, i, j, h, i, j ]
|
||||||
|
// ^ ^
|
||||||
|
// first last
|
||||||
|
|
||||||
|
// remove the unneeded elements at the end of the vector
|
||||||
|
Container::resize(this->size() - static_cast<size_type>(elements_affected));
|
||||||
|
|
||||||
|
// [ a, b, c, d, h, i, j ]
|
||||||
|
// ^ ^
|
||||||
|
// first last
|
||||||
|
|
||||||
|
// first is now pointing past the last deleted element, but we cannot
|
||||||
|
// use this iterator, because it may have been invalidated by the
|
||||||
|
// resize call. Instead, we can return begin() + offset.
|
||||||
|
return Container::begin() + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type count(const key_type& key) const
|
||||||
|
{
|
||||||
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
|
{
|
||||||
|
if (m_compare(it->first, key))
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class KeyType, detail::enable_if_t<
|
||||||
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
|
size_type count(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
|
||||||
|
{
|
||||||
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
|
{
|
||||||
|
if (m_compare(it->first, key))
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator find(const key_type& key)
|
||||||
|
{
|
||||||
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
|
{
|
||||||
|
if (m_compare(it->first, key))
|
||||||
|
{
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Container::end();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class KeyType, detail::enable_if_t<
|
||||||
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
|
iterator find(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
|
||||||
|
{
|
||||||
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
|
{
|
||||||
|
if (m_compare(it->first, key))
|
||||||
|
{
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Container::end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator find(const key_type& key) const
|
||||||
|
{
|
||||||
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
|
{
|
||||||
|
if (m_compare(it->first, key))
|
||||||
|
{
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Container::end();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<iterator, bool> insert( value_type&& value )
|
||||||
|
{
|
||||||
|
return emplace(value.first, std::move(value.second));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<iterator, bool> insert( const value_type& value )
|
||||||
|
{
|
||||||
|
for (auto it = this->begin(); it != this->end(); ++it)
|
||||||
|
{
|
||||||
|
if (m_compare(it->first, value.first))
|
||||||
|
{
|
||||||
|
return {it, false};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Container::push_back(value);
|
||||||
|
return {--this->end(), true};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename InputIt>
|
||||||
|
using require_input_iter = typename std::enable_if<std::is_convertible<typename std::iterator_traits<InputIt>::iterator_category,
|
||||||
|
std::input_iterator_tag>::value>::type;
|
||||||
|
|
||||||
|
template<typename InputIt, typename = require_input_iter<InputIt>>
|
||||||
|
void insert(InputIt first, InputIt last)
|
||||||
|
{
|
||||||
|
for (auto it = first; it != last; ++it)
|
||||||
|
{
|
||||||
|
insert(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
JSON_NO_UNIQUE_ADDRESS key_compare m_compare = key_compare();
|
||||||
|
};
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,158 @@
|
||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++
|
||||||
|
// | | |__ | | | | | | version 3.11.3
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#undef JSON_HEDLEY_ALWAYS_INLINE
|
||||||
|
#undef JSON_HEDLEY_ARM_VERSION
|
||||||
|
#undef JSON_HEDLEY_ARM_VERSION_CHECK
|
||||||
|
#undef JSON_HEDLEY_ARRAY_PARAM
|
||||||
|
#undef JSON_HEDLEY_ASSUME
|
||||||
|
#undef JSON_HEDLEY_BEGIN_C_DECLS
|
||||||
|
#undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE
|
||||||
|
#undef JSON_HEDLEY_CLANG_HAS_BUILTIN
|
||||||
|
#undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE
|
||||||
|
#undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE
|
||||||
|
#undef JSON_HEDLEY_CLANG_HAS_EXTENSION
|
||||||
|
#undef JSON_HEDLEY_CLANG_HAS_FEATURE
|
||||||
|
#undef JSON_HEDLEY_CLANG_HAS_WARNING
|
||||||
|
#undef JSON_HEDLEY_COMPCERT_VERSION
|
||||||
|
#undef JSON_HEDLEY_COMPCERT_VERSION_CHECK
|
||||||
|
#undef JSON_HEDLEY_CONCAT
|
||||||
|
#undef JSON_HEDLEY_CONCAT3
|
||||||
|
#undef JSON_HEDLEY_CONCAT3_EX
|
||||||
|
#undef JSON_HEDLEY_CONCAT_EX
|
||||||
|
#undef JSON_HEDLEY_CONST
|
||||||
|
#undef JSON_HEDLEY_CONSTEXPR
|
||||||
|
#undef JSON_HEDLEY_CONST_CAST
|
||||||
|
#undef JSON_HEDLEY_CPP_CAST
|
||||||
|
#undef JSON_HEDLEY_CRAY_VERSION
|
||||||
|
#undef JSON_HEDLEY_CRAY_VERSION_CHECK
|
||||||
|
#undef JSON_HEDLEY_C_DECL
|
||||||
|
#undef JSON_HEDLEY_DEPRECATED
|
||||||
|
#undef JSON_HEDLEY_DEPRECATED_FOR
|
||||||
|
#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL
|
||||||
|
#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_
|
||||||
|
#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
|
||||||
|
#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES
|
||||||
|
#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS
|
||||||
|
#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION
|
||||||
|
#undef JSON_HEDLEY_DIAGNOSTIC_POP
|
||||||
|
#undef JSON_HEDLEY_DIAGNOSTIC_PUSH
|
||||||
|
#undef JSON_HEDLEY_DMC_VERSION
|
||||||
|
#undef JSON_HEDLEY_DMC_VERSION_CHECK
|
||||||
|
#undef JSON_HEDLEY_EMPTY_BASES
|
||||||
|
#undef JSON_HEDLEY_EMSCRIPTEN_VERSION
|
||||||
|
#undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK
|
||||||
|
#undef JSON_HEDLEY_END_C_DECLS
|
||||||
|
#undef JSON_HEDLEY_FLAGS
|
||||||
|
#undef JSON_HEDLEY_FLAGS_CAST
|
||||||
|
#undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE
|
||||||
|
#undef JSON_HEDLEY_GCC_HAS_BUILTIN
|
||||||
|
#undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE
|
||||||
|
#undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE
|
||||||
|
#undef JSON_HEDLEY_GCC_HAS_EXTENSION
|
||||||
|
#undef JSON_HEDLEY_GCC_HAS_FEATURE
|
||||||
|
#undef JSON_HEDLEY_GCC_HAS_WARNING
|
||||||
|
#undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK
|
||||||
|
#undef JSON_HEDLEY_GCC_VERSION
|
||||||
|
#undef JSON_HEDLEY_GCC_VERSION_CHECK
|
||||||
|
#undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE
|
||||||
|
#undef JSON_HEDLEY_GNUC_HAS_BUILTIN
|
||||||
|
#undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE
|
||||||
|
#undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE
|
||||||
|
#undef JSON_HEDLEY_GNUC_HAS_EXTENSION
|
||||||
|
#undef JSON_HEDLEY_GNUC_HAS_FEATURE
|
||||||
|
#undef JSON_HEDLEY_GNUC_HAS_WARNING
|
||||||
|
#undef JSON_HEDLEY_GNUC_VERSION
|
||||||
|
#undef JSON_HEDLEY_GNUC_VERSION_CHECK
|
||||||
|
#undef JSON_HEDLEY_HAS_ATTRIBUTE
|
||||||
|
#undef JSON_HEDLEY_HAS_BUILTIN
|
||||||
|
#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE
|
||||||
|
#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS
|
||||||
|
#undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE
|
||||||
|
#undef JSON_HEDLEY_HAS_EXTENSION
|
||||||
|
#undef JSON_HEDLEY_HAS_FEATURE
|
||||||
|
#undef JSON_HEDLEY_HAS_WARNING
|
||||||
|
#undef JSON_HEDLEY_IAR_VERSION
|
||||||
|
#undef JSON_HEDLEY_IAR_VERSION_CHECK
|
||||||
|
#undef JSON_HEDLEY_IBM_VERSION
|
||||||
|
#undef JSON_HEDLEY_IBM_VERSION_CHECK
|
||||||
|
#undef JSON_HEDLEY_IMPORT
|
||||||
|
#undef JSON_HEDLEY_INLINE
|
||||||
|
#undef JSON_HEDLEY_INTEL_CL_VERSION
|
||||||
|
#undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK
|
||||||
|
#undef JSON_HEDLEY_INTEL_VERSION
|
||||||
|
#undef JSON_HEDLEY_INTEL_VERSION_CHECK
|
||||||
|
#undef JSON_HEDLEY_IS_CONSTANT
|
||||||
|
#undef JSON_HEDLEY_IS_CONSTEXPR_
|
||||||
|
#undef JSON_HEDLEY_LIKELY
|
||||||
|
#undef JSON_HEDLEY_MALLOC
|
||||||
|
#undef JSON_HEDLEY_MCST_LCC_VERSION
|
||||||
|
#undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK
|
||||||
|
#undef JSON_HEDLEY_MESSAGE
|
||||||
|
#undef JSON_HEDLEY_MSVC_VERSION
|
||||||
|
#undef JSON_HEDLEY_MSVC_VERSION_CHECK
|
||||||
|
#undef JSON_HEDLEY_NEVER_INLINE
|
||||||
|
#undef JSON_HEDLEY_NON_NULL
|
||||||
|
#undef JSON_HEDLEY_NO_ESCAPE
|
||||||
|
#undef JSON_HEDLEY_NO_RETURN
|
||||||
|
#undef JSON_HEDLEY_NO_THROW
|
||||||
|
#undef JSON_HEDLEY_NULL
|
||||||
|
#undef JSON_HEDLEY_PELLES_VERSION
|
||||||
|
#undef JSON_HEDLEY_PELLES_VERSION_CHECK
|
||||||
|
#undef JSON_HEDLEY_PGI_VERSION
|
||||||
|
#undef JSON_HEDLEY_PGI_VERSION_CHECK
|
||||||
|
#undef JSON_HEDLEY_PREDICT
|
||||||
|
#undef JSON_HEDLEY_PRINTF_FORMAT
|
||||||
|
#undef JSON_HEDLEY_PRIVATE
|
||||||
|
#undef JSON_HEDLEY_PUBLIC
|
||||||
|
#undef JSON_HEDLEY_PURE
|
||||||
|
#undef JSON_HEDLEY_REINTERPRET_CAST
|
||||||
|
#undef JSON_HEDLEY_REQUIRE
|
||||||
|
#undef JSON_HEDLEY_REQUIRE_CONSTEXPR
|
||||||
|
#undef JSON_HEDLEY_REQUIRE_MSG
|
||||||
|
#undef JSON_HEDLEY_RESTRICT
|
||||||
|
#undef JSON_HEDLEY_RETURNS_NON_NULL
|
||||||
|
#undef JSON_HEDLEY_SENTINEL
|
||||||
|
#undef JSON_HEDLEY_STATIC_ASSERT
|
||||||
|
#undef JSON_HEDLEY_STATIC_CAST
|
||||||
|
#undef JSON_HEDLEY_STRINGIFY
|
||||||
|
#undef JSON_HEDLEY_STRINGIFY_EX
|
||||||
|
#undef JSON_HEDLEY_SUNPRO_VERSION
|
||||||
|
#undef JSON_HEDLEY_SUNPRO_VERSION_CHECK
|
||||||
|
#undef JSON_HEDLEY_TINYC_VERSION
|
||||||
|
#undef JSON_HEDLEY_TINYC_VERSION_CHECK
|
||||||
|
#undef JSON_HEDLEY_TI_ARMCL_VERSION
|
||||||
|
#undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK
|
||||||
|
#undef JSON_HEDLEY_TI_CL2000_VERSION
|
||||||
|
#undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK
|
||||||
|
#undef JSON_HEDLEY_TI_CL430_VERSION
|
||||||
|
#undef JSON_HEDLEY_TI_CL430_VERSION_CHECK
|
||||||
|
#undef JSON_HEDLEY_TI_CL6X_VERSION
|
||||||
|
#undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK
|
||||||
|
#undef JSON_HEDLEY_TI_CL7X_VERSION
|
||||||
|
#undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK
|
||||||
|
#undef JSON_HEDLEY_TI_CLPRU_VERSION
|
||||||
|
#undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK
|
||||||
|
#undef JSON_HEDLEY_TI_VERSION
|
||||||
|
#undef JSON_HEDLEY_TI_VERSION_CHECK
|
||||||
|
#undef JSON_HEDLEY_UNAVAILABLE
|
||||||
|
#undef JSON_HEDLEY_UNLIKELY
|
||||||
|
#undef JSON_HEDLEY_UNPREDICTABLE
|
||||||
|
#undef JSON_HEDLEY_UNREACHABLE
|
||||||
|
#undef JSON_HEDLEY_UNREACHABLE_RETURN
|
||||||
|
#undef JSON_HEDLEY_VERSION
|
||||||
|
#undef JSON_HEDLEY_VERSION_DECODE_MAJOR
|
||||||
|
#undef JSON_HEDLEY_VERSION_DECODE_MINOR
|
||||||
|
#undef JSON_HEDLEY_VERSION_DECODE_REVISION
|
||||||
|
#undef JSON_HEDLEY_VERSION_ENCODE
|
||||||
|
#undef JSON_HEDLEY_WARNING
|
||||||
|
#undef JSON_HEDLEY_WARN_UNUSED_RESULT
|
||||||
|
#undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG
|
||||||
|
#undef JSON_HEDLEY_FALL_THROUGH
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -9,6 +9,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibstatic", "..\..\..\Zlib
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "squirrel", "F:\nut\SQUIRREL2\squirrel\squirrel.vcxproj", "{055A88B6-E28D-4155-A0DB-B2B60DD6C7AE}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "squirrel", "F:\nut\SQUIRREL2\squirrel\squirrel.vcxproj", "{055A88B6-E28D-4155-A0DB-B2B60DD6C7AE}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sqstdlib", "F:\nut\SQUIRREL2\sqstdlib\sqstdlib.vcxproj", "{5B802548-C7C1-4993-B338-472AF8B11730}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ffi", "F:\zhuomian\Libffi-master\Libffi-master\build\ffi.vcxproj", "{E76C4B11-4165-3C69-89CE-954037C7BB5B}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|x64 = Debug|x64
|
Debug|x64 = Debug|x64
|
||||||
|
|
@ -83,6 +87,46 @@ Global
|
||||||
{055A88B6-E28D-4155-A0DB-B2B60DD6C7AE}.Template|x64.Build.0 = Template|Win32
|
{055A88B6-E28D-4155-A0DB-B2B60DD6C7AE}.Template|x64.Build.0 = Template|Win32
|
||||||
{055A88B6-E28D-4155-A0DB-B2B60DD6C7AE}.Template|x86.ActiveCfg = Template|Win32
|
{055A88B6-E28D-4155-A0DB-B2B60DD6C7AE}.Template|x86.ActiveCfg = Template|Win32
|
||||||
{055A88B6-E28D-4155-A0DB-B2B60DD6C7AE}.Template|x86.Build.0 = Template|Win32
|
{055A88B6-E28D-4155-A0DB-B2B60DD6C7AE}.Template|x86.Build.0 = Template|Win32
|
||||||
|
{5B802548-C7C1-4993-B338-472AF8B11730}.Debug|x64.ActiveCfg = Debug|Win32
|
||||||
|
{5B802548-C7C1-4993-B338-472AF8B11730}.Debug|x64.Build.0 = Debug|Win32
|
||||||
|
{5B802548-C7C1-4993-B338-472AF8B11730}.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{5B802548-C7C1-4993-B338-472AF8B11730}.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{5B802548-C7C1-4993-B338-472AF8B11730}.MinSizeRel|x64.ActiveCfg = Debug|Win32
|
||||||
|
{5B802548-C7C1-4993-B338-472AF8B11730}.MinSizeRel|x64.Build.0 = Debug|Win32
|
||||||
|
{5B802548-C7C1-4993-B338-472AF8B11730}.MinSizeRel|x86.ActiveCfg = Debug|Win32
|
||||||
|
{5B802548-C7C1-4993-B338-472AF8B11730}.MinSizeRel|x86.Build.0 = Debug|Win32
|
||||||
|
{5B802548-C7C1-4993-B338-472AF8B11730}.Release|x64.ActiveCfg = Release|Win32
|
||||||
|
{5B802548-C7C1-4993-B338-472AF8B11730}.Release|x64.Build.0 = Release|Win32
|
||||||
|
{5B802548-C7C1-4993-B338-472AF8B11730}.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{5B802548-C7C1-4993-B338-472AF8B11730}.Release|x86.Build.0 = Release|Win32
|
||||||
|
{5B802548-C7C1-4993-B338-472AF8B11730}.RelWithDebInfo|x64.ActiveCfg = Release|Win32
|
||||||
|
{5B802548-C7C1-4993-B338-472AF8B11730}.RelWithDebInfo|x64.Build.0 = Release|Win32
|
||||||
|
{5B802548-C7C1-4993-B338-472AF8B11730}.RelWithDebInfo|x86.ActiveCfg = Release|Win32
|
||||||
|
{5B802548-C7C1-4993-B338-472AF8B11730}.RelWithDebInfo|x86.Build.0 = Release|Win32
|
||||||
|
{5B802548-C7C1-4993-B338-472AF8B11730}.Template|x64.ActiveCfg = Template|Win32
|
||||||
|
{5B802548-C7C1-4993-B338-472AF8B11730}.Template|x64.Build.0 = Template|Win32
|
||||||
|
{5B802548-C7C1-4993-B338-472AF8B11730}.Template|x86.ActiveCfg = Template|Win32
|
||||||
|
{5B802548-C7C1-4993-B338-472AF8B11730}.Template|x86.Build.0 = Template|Win32
|
||||||
|
{E76C4B11-4165-3C69-89CE-954037C7BB5B}.Debug|x64.ActiveCfg = Debug|Win32
|
||||||
|
{E76C4B11-4165-3C69-89CE-954037C7BB5B}.Debug|x64.Build.0 = Debug|Win32
|
||||||
|
{E76C4B11-4165-3C69-89CE-954037C7BB5B}.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{E76C4B11-4165-3C69-89CE-954037C7BB5B}.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{E76C4B11-4165-3C69-89CE-954037C7BB5B}.MinSizeRel|x64.ActiveCfg = MinSizeRel|Win32
|
||||||
|
{E76C4B11-4165-3C69-89CE-954037C7BB5B}.MinSizeRel|x64.Build.0 = MinSizeRel|Win32
|
||||||
|
{E76C4B11-4165-3C69-89CE-954037C7BB5B}.MinSizeRel|x86.ActiveCfg = MinSizeRel|Win32
|
||||||
|
{E76C4B11-4165-3C69-89CE-954037C7BB5B}.MinSizeRel|x86.Build.0 = MinSizeRel|Win32
|
||||||
|
{E76C4B11-4165-3C69-89CE-954037C7BB5B}.Release|x64.ActiveCfg = Release|Win32
|
||||||
|
{E76C4B11-4165-3C69-89CE-954037C7BB5B}.Release|x64.Build.0 = Release|Win32
|
||||||
|
{E76C4B11-4165-3C69-89CE-954037C7BB5B}.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{E76C4B11-4165-3C69-89CE-954037C7BB5B}.Release|x86.Build.0 = Release|Win32
|
||||||
|
{E76C4B11-4165-3C69-89CE-954037C7BB5B}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|Win32
|
||||||
|
{E76C4B11-4165-3C69-89CE-954037C7BB5B}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|Win32
|
||||||
|
{E76C4B11-4165-3C69-89CE-954037C7BB5B}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|Win32
|
||||||
|
{E76C4B11-4165-3C69-89CE-954037C7BB5B}.RelWithDebInfo|x86.Build.0 = RelWithDebInfo|Win32
|
||||||
|
{E76C4B11-4165-3C69-89CE-954037C7BB5B}.Template|x64.ActiveCfg = Debug|Win32
|
||||||
|
{E76C4B11-4165-3C69-89CE-954037C7BB5B}.Template|x64.Build.0 = Debug|Win32
|
||||||
|
{E76C4B11-4165-3C69-89CE-954037C7BB5B}.Template|x86.ActiveCfg = Debug|Win32
|
||||||
|
{E76C4B11-4165-3C69-89CE-954037C7BB5B}.Template|x86.Build.0 = Debug|Win32
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<PropertyGroup Label="UserMacros" />
|
<PropertyGroup Label="UserMacros" />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
<IncludePath>H:\Zlib-win32;$(LocalDebuggerWorkingDirectory)OtherInc\openssl\include;$(LocalDebuggerWorkingDirectory)OtherInc;$(LocalDebuggerWorkingDirectory)Include;$(IncludePath)</IncludePath>
|
<IncludePath>H:\Zlib-win32;$(LocalDebuggerWorkingDirectory)OtherInc\nlohmann;$(LocalDebuggerWorkingDirectory)OtherInc\openssl\include;$(LocalDebuggerWorkingDirectory)OtherInc;$(LocalDebuggerWorkingDirectory)Include;$(IncludePath)</IncludePath>
|
||||||
<ExecutablePath>$(ExecutablePath)</ExecutablePath>
|
<ExecutablePath>$(ExecutablePath)</ExecutablePath>
|
||||||
<OutDir>I:\DOF\DNF-CC\Plugins\</OutDir>
|
<OutDir>I:\DOF\DNF-CC\Plugins\</OutDir>
|
||||||
<LibraryPath>$(LocalDebuggerWorkingDirectory)OtherLib;$(LibraryPath)</LibraryPath>
|
<LibraryPath>$(LocalDebuggerWorkingDirectory)OtherLib;$(LibraryPath)</LibraryPath>
|
||||||
|
|
@ -111,7 +111,7 @@
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<EnableUAC>false</EnableUAC>
|
<EnableUAC>false</EnableUAC>
|
||||||
<AdditionalDependencies>libMinHook.x86.lib;libcrypto.lib;libssl.lib;Imm32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>libMinHook.x86.lib;libcrypto.lib;libssl.lib;Imm32.lib;frida-gum.lib;iconv.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
<AdditionalLibraryDirectories>$(LocalDebuggerWorkingDirectory)OtherLib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
<AdditionalLibraryDirectories>$(LocalDebuggerWorkingDirectory)OtherLib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
<IgnoreSpecificDefaultLibraries>MSVCRT.lib</IgnoreSpecificDefaultLibraries>
|
<IgnoreSpecificDefaultLibraries>MSVCRT.lib</IgnoreSpecificDefaultLibraries>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
@ -151,6 +151,7 @@
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="ActiveHook.hpp" />
|
||||||
<ClInclude Include="framework.h" />
|
<ClInclude Include="framework.h" />
|
||||||
<ClInclude Include="Include\BASE64.h" />
|
<ClInclude Include="Include\BASE64.h" />
|
||||||
<ClInclude Include="Include\DNFTOOL.hpp" />
|
<ClInclude Include="Include\DNFTOOL.hpp" />
|
||||||
|
|
@ -175,9 +176,15 @@
|
||||||
<ProjectReference Include="..\..\..\Zlib-win32\build\zlibstatic.vcxproj">
|
<ProjectReference Include="..\..\..\Zlib-win32\build\zlibstatic.vcxproj">
|
||||||
<Project>{66d10fed-87a1-35ee-b07d-16325d3b1c7c}</Project>
|
<Project>{66d10fed-87a1-35ee-b07d-16325d3b1c7c}</Project>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="F:\nut\SQUIRREL2\sqstdlib\sqstdlib.vcxproj">
|
||||||
|
<Project>{5b802548-c7c1-4993-b338-472af8b11730}</Project>
|
||||||
|
</ProjectReference>
|
||||||
<ProjectReference Include="F:\nut\SQUIRREL2\squirrel\squirrel.vcxproj">
|
<ProjectReference Include="F:\nut\SQUIRREL2\squirrel\squirrel.vcxproj">
|
||||||
<Project>{055a88b6-e28d-4155-a0db-b2b60dd6c7ae}</Project>
|
<Project>{055a88b6-e28d-4155-a0db-b2b60dd6c7ae}</Project>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="F:\zhuomian\Libffi-master\Libffi-master\build\ffi.vcxproj">
|
||||||
|
<Project>{e76c4b11-4165-3c69-89ce-954037c7bb5b}</Project>
|
||||||
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,9 @@
|
||||||
<ClInclude Include="Include\RegisterSquirrel.hpp">
|
<ClInclude Include="Include\RegisterSquirrel.hpp">
|
||||||
<Filter>头文件</Filter>
|
<Filter>头文件</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="ActiveHook.hpp">
|
||||||
|
<Filter>头文件</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="dllmain.cpp">
|
<ClCompile Include="dllmain.cpp">
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,8 @@ void Init() {
|
||||||
|
|
||||||
//消息框黏贴
|
//消息框黏贴
|
||||||
*(WORD*)0x011C53B0 = 0x01B0;
|
*(WORD*)0x011C53B0 = 0x01B0;
|
||||||
|
//修复233
|
||||||
|
memcpy((void*)0x00727017, "\xEB\x11\x90\x90\x90\x90\x90", 7);
|
||||||
|
|
||||||
//注册HOOK
|
//注册HOOK
|
||||||
RegisterHook();
|
RegisterHook();
|
||||||
|
|
|
||||||
162
pch.h
162
pch.h
|
|
@ -10,6 +10,15 @@
|
||||||
// 添加要在此处预编译的标头
|
// 添加要在此处预编译的标头
|
||||||
#include "framework.h"
|
#include "framework.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "squirrel.h"
|
||||||
|
#include "sqstdaux.h"
|
||||||
|
#include "sqstdblob.h"
|
||||||
|
#include "sqstdio.h"
|
||||||
|
#include "sqstdmath.h"
|
||||||
|
#include "sqstdstring.h"
|
||||||
|
#include "sqstdsystem.h"
|
||||||
|
#include "iconv.h"
|
||||||
#endif //PCH_H
|
#endif //PCH_H
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -41,4 +50,155 @@ static void Cutecode(char* pstr, int* pkey, int len) {
|
||||||
if (len == -1)len = strlen(pstr);
|
if (len == -1)len = strlen(pstr);
|
||||||
for (int i = 0; i < len; i++)
|
for (int i = 0; i < len; i++)
|
||||||
*(pstr + i) = CutcodeChar(*(pstr + i), pkey[i % 5], pkey[(i + 18) % 5]);
|
*(pstr + i) = CutcodeChar(*(pstr + i), pkey[i % 5], pkey[(i + 18) % 5]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define CONTAINS_STRING(str, substr) (str == substr)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct SQVM* HSQUIRRELVM;
|
||||||
|
//注册 Nut API
|
||||||
|
typedef int(*LSQLEXREADFUNC)(int n);
|
||||||
|
static LSQLEXREADFUNC SQ_io_file_lexfeed_ASCII = (LSQLEXREADFUNC)0x1355F60;
|
||||||
|
static LSQLEXREADFUNC SQ_io_file_lexfeed_UCS2_BE = (LSQLEXREADFUNC)0x1356050;
|
||||||
|
static LSQLEXREADFUNC SQ_io_file_lexfeed_UCS2_LE = (LSQLEXREADFUNC)0x1356020;
|
||||||
|
static LSQLEXREADFUNC SQ_io_file_lexfeed_UTF8 = (LSQLEXREADFUNC)0x1355F90;
|
||||||
|
|
||||||
|
// PushRoot
|
||||||
|
typedef int(SqPushRootFunc)(HSQUIRRELVM v);
|
||||||
|
static SqPushRootFunc* Sq_pushroottable = (SqPushRootFunc*)0x1358C50;
|
||||||
|
// // New槽
|
||||||
|
typedef int(SqNewSlot)(HSQUIRRELVM v, int a, BOOL b);
|
||||||
|
static SqNewSlot* SQNewSlot = (SqNewSlot*)0x135AA80;
|
||||||
|
// 平栈
|
||||||
|
typedef int(SqPopTop)(HSQUIRRELVM v);
|
||||||
|
static SqPopTop* SQPopTop = (SqPopTop*)0x1358FF0;
|
||||||
|
// Push 函数绑定闭包
|
||||||
|
typedef int(realSqNewClosure)(HSQUIRRELVM v, void* funcAddr, int a);
|
||||||
|
static realSqNewClosure* RealSqNewClosure = (realSqNewClosure*)0x135B850;
|
||||||
|
//SQ_Call
|
||||||
|
typedef int (Sq_CallFunc)(HSQUIRRELVM v, int params, int retval, int raiseerror);
|
||||||
|
static Sq_CallFunc* Sq_call = (Sq_CallFunc*)0x1359280;
|
||||||
|
// 平栈
|
||||||
|
typedef int(SqPop)(HSQUIRRELVM v, int n);
|
||||||
|
static SqPop* Sq_pop = (SqPop*)0x1358FD0;
|
||||||
|
// 设置栈
|
||||||
|
typedef int(SqSetTop)(HSQUIRRELVM v, int n);
|
||||||
|
static SqSetTop* Sq_settop = (SqSetTop*)0x135AA40;
|
||||||
|
//SQ_Get
|
||||||
|
typedef int(Sq_Get)(HSQUIRRELVM v, int n);
|
||||||
|
static Sq_Get* Sq_get = (Sq_Get*)0x135AE30;
|
||||||
|
//GetTop
|
||||||
|
typedef int(SqGetTopFunc)(HSQUIRRELVM v);
|
||||||
|
static SqGetTopFunc* Sq_gettop = (SqGetTopFunc*)0x1358FC0;
|
||||||
|
//GetInt
|
||||||
|
typedef int(SqGetIntFunc)(HSQUIRRELVM v, int stackIndex, int* sint);
|
||||||
|
static SqGetIntFunc* Sq_getinteger = (SqGetIntFunc*)0x1358D70;
|
||||||
|
//GetString
|
||||||
|
typedef int(SqGetStringFunc)(HSQUIRRELVM v, uint32_t stackIndex, const SQChar** sstring);
|
||||||
|
static SqGetStringFunc* Sq_getstring = (SqGetStringFunc*)0x1358E70;
|
||||||
|
//GetFloat
|
||||||
|
typedef int(SqGetFloatFunc)(HSQUIRRELVM v, uint32_t stackIndex, FLOAT* sfloat);
|
||||||
|
static SqGetFloatFunc* Sq_getfloat = (SqGetFloatFunc*)0x1358DD0;
|
||||||
|
//GetBool
|
||||||
|
typedef int(SqGetBoolFunc)(HSQUIRRELVM v, uint32_t stackIndex, SQBool* sbool);
|
||||||
|
static SqGetBoolFunc* Sq_getbool = (SqGetBoolFunc*)0x1358E30;
|
||||||
|
//GetUserdata
|
||||||
|
typedef int(SqGetUserdataFunc)(HSQUIRRELVM v, uint32_t stackIndex, DWORD* up, DWORD* up1);
|
||||||
|
static SqGetUserdataFunc* Sq_getuserdata = (SqGetUserdataFunc*)0x1358EC0;
|
||||||
|
//GetObjtypetag
|
||||||
|
typedef int(SqGetObjtypetagFunc)(HSQUIRRELVM v, DWORD* up);
|
||||||
|
static SqGetObjtypetagFunc* Sq_getobjtypetag = (SqGetObjtypetagFunc*)0x1358F20;
|
||||||
|
//GetUserpointer
|
||||||
|
typedef int(SqGetUserpointerFunc)(HSQUIRRELVM v, uint32_t idx, SQUserPointer* up);
|
||||||
|
static SqGetUserpointerFunc* Sq_getuserpointer = (SqGetUserpointerFunc*)0x1358F80;
|
||||||
|
//SQ_Compile
|
||||||
|
typedef int(SQ_CompileFunc)(HSQUIRRELVM v, LSQLEXREADFUNC FUNC, void* file, const wchar_t* filename, BOOL printerror);
|
||||||
|
static SQ_CompileFunc* SQ_Compile = (SQ_CompileFunc*)0x135A390;
|
||||||
|
|
||||||
|
|
||||||
|
//Push
|
||||||
|
typedef int(SqPushFunc)(HSQUIRRELVM v, int idx);
|
||||||
|
static SqPushFunc* Sq_push = (SqPushFunc*)0x1358C90;
|
||||||
|
//PushString
|
||||||
|
typedef int(SqPushStringFunc)(HSQUIRRELVM v, const SQChar* s, int len);
|
||||||
|
static SqPushStringFunc* Sq_pushstring = (SqPushStringFunc*)0x1358A60;
|
||||||
|
//PushInt
|
||||||
|
typedef int(SqPushIntFunc)(HSQUIRRELVM v, int sint);
|
||||||
|
static SqPushIntFunc* Sq_pushinteger = (SqPushIntFunc*)0x1358AD0;
|
||||||
|
//PushBool
|
||||||
|
typedef int(SqPushBoolFunc)(HSQUIRRELVM v, SQBool sbool);
|
||||||
|
static SqPushBoolFunc* Sq_pushbool = (SqPushBoolFunc*)0x1358B10;
|
||||||
|
//PushFloat
|
||||||
|
typedef int(SqPushFloatFunc)(HSQUIRRELVM v, FLOAT sfloat);
|
||||||
|
static SqPushFloatFunc* Sq_pushfloat = (SqPushFloatFunc*)0x1358B60;
|
||||||
|
//PushUserpointer
|
||||||
|
typedef int(SqPushUserpointerFunc)(HSQUIRRELVM v, void* sfloat);
|
||||||
|
static SqPushUserpointerFunc* Sq_pushuserpointer = (SqPushUserpointerFunc*)0x1358BA0;
|
||||||
|
|
||||||
|
//特殊操作
|
||||||
|
typedef DWORD(_1359130)(void* thisc, DWORD a2, DWORD a3);
|
||||||
|
static _1359130* Old1359130 = (_1359130*)0x1359130;
|
||||||
|
|
||||||
|
|
||||||
|
//键盘按键是否按下
|
||||||
|
#define KEY_DOWN(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)
|
||||||
|
|
||||||
|
//发包类型 地址
|
||||||
|
typedef int(__fastcall* SendPacksType)(DWORD thisc, int Seat, int Parm);
|
||||||
|
static SendPacksType _SendpacksType = (SendPacksType)0x1127D60;
|
||||||
|
|
||||||
|
//发包参数 BYTE
|
||||||
|
typedef int(__fastcall* SendPacksByte)(DWORD thisc, int Seat, int Parm);
|
||||||
|
static SendPacksByte _SendPacksByte = (SendPacksByte)0x1128550;
|
||||||
|
|
||||||
|
//发包参数 WORD
|
||||||
|
typedef int(__fastcall* SendPacksWORD)(DWORD thisc, int Seat, int Parm);
|
||||||
|
static SendPacksWORD _SendPacksWord = (SendPacksWORD)0x1128580;
|
||||||
|
|
||||||
|
//发包参数 DWORD
|
||||||
|
typedef int(__fastcall* SendPacksDWORD)(DWORD thisc, int Seat, int Parm);
|
||||||
|
static SendPacksDWORD _SendPacksDWord = (SendPacksDWORD)0x11285B0;
|
||||||
|
|
||||||
|
//发包参数 char
|
||||||
|
typedef int(__fastcall* SendPacksChar)(DWORD thisc, int Seat, char* Parm, int Size);
|
||||||
|
static SendPacksChar _SendPacksChar = (SendPacksChar)0x11285E0;
|
||||||
|
|
||||||
|
//发包函数 地址
|
||||||
|
typedef DWORD SendPacks();
|
||||||
|
static SendPacks* _SendPacks = (SendPacks*)0x1127EC0;
|
||||||
Loading…
Reference in New Issue