整理初版

This commit is contained in:
2026-05-08 19:03:33 +08:00
parent a9af16962c
commit a605fb2bea
352 changed files with 0 additions and 7278 deletions

View File

@@ -1,465 +0,0 @@
#ifndef __DAKUANG_BASE64_H__
#define __DAKUANG_BASE64_H__
#include <string>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
namespace LenheartBase
{
class CBASE64
{
public:
// 生成RSA密钥结构
static void *__genKey(int nBits);
// 生成密钥对输出为PEM字符串
static bool genKeyStrings(std::string &strPrivateKeyPEMString, std::string &strPublicKeyPEMString);
// 执行BASE64编码操作
static std::string encode(const std::string &str);
// 执行BASE64解码操作
static std::string decode(const std::string &str);
// 执行RSA私匙解密操作
static std::string RsaPriDecrypt(const std::string &cipher_text, const std::string &pri_key);
// 执行RSA私匙加密操作
static std::string RsaPriEncrypt(const std::string &clear_text, const std::string &pri_key);
// 使用PEM私钥字符串加密
static bool encryptByPrivatePEMString(const std::string &strIn, std::string &strOut, const std::string &strKeyPEMString);
// 使用PEM公钥字符串加密
static bool encryptByPublicPEMString(const std::string &strIn, std::string &strOut, const std::string &strKeyPEMString);
// 使用PEM公钥字符串解密
static bool decryptByPublicPEMString(const std::string &strIn, std::string &strOut, const std::string &strKeyPEMString);
// 使用RSA执行加密或解密
static bool __encryptOrDecrypt(const std::string &strIn, std::string &strOut, const void *pRSA, const void *pFunc, bool bEncrypt);
private:
// 分组编码
static int __encode(unsigned char *pDest, const unsigned char *pSrc, size_t nSrcLen);
// 分组解码
static int __decode(unsigned char *pDest, const unsigned char *pSrc, size_t nSrcLen);
private:
// 编解码转换表
static unsigned char s_encTable[];
static unsigned char s_decTable[];
};
}
using namespace LenheartBase;
// 加解密函数签名
typedef int (*RSA_encryptOrDecrypt)(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding);
// 编解码转换表
unsigned char CBASE64::s_encTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
unsigned char CBASE64::s_decTable[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
// 执行BASE64编码操作
std::string CBASE64::encode(const std::string &str)
{
std::string strEncode;
strEncode.resize((str.size() / 3 + 1) * 4);
strEncode.resize(__encode((unsigned char *)strEncode.data(), (const unsigned char *)str.data(), str.size()));
return strEncode;
}
// 执行BASE64解码操作
std::string CBASE64::decode(const std::string &str)
{
std::string strDecode;
strDecode.resize(str.size());
strDecode.resize(__decode((unsigned char *)strDecode.data(), (const unsigned char *)str.data(), str.size()));
return strDecode;
}
// 分组编码
int CBASE64::__encode(unsigned char *pDest, const unsigned char *pSrc, size_t nSrcLen)
{
unsigned char *dst = pDest;
const unsigned char *src = pSrc;
size_t len = nSrcLen;
unsigned char *odst = dst;
unsigned long l = 0, m = 0, n = 0;
// 循环处理分组
size_t off = 0;
for (; off + 3 <= len; off += 3)
{
l = *src++;
m = *src++;
n = *src++;
*dst++ = s_encTable[(l >> 2) & 0x3F];
*dst++ = s_encTable[((l << 4) & 0x30) | ((m >> 4) & 0x0F)];
*dst++ = s_encTable[((m << 2) & 0x3C) | ((n >> 6) & 0x03)];
*dst++ = s_encTable[n & 0x3F];
}
// 处理余下的2个字节
if (off + 2 <= len)
{
l = *src++;
m = *src++;
*dst++ = s_encTable[(l >> 2) & 0x3F];
*dst++ = s_encTable[((l << 4) & 0x30) | ((m >> 4) & 0x0F)];
*dst++ = s_encTable[((m << 2) & 0x3C)];
*dst++ = '=';
}
// 处理余下的1个字节
else if (off + 1 <= len)
{
l = *src++;
*dst++ = s_encTable[(l >> 2) & 0x3F];
*dst++ = s_encTable[((l << 4) & 0x30)];
*dst++ = '=';
*dst++ = '=';
}
return (int)(dst - odst);
}
// 分组解码
int CBASE64::__decode(unsigned char *pDest, const unsigned char *pSrc, size_t nSrcLen)
{
unsigned char *dst = pDest;
const unsigned char *src = pSrc;
size_t len = nSrcLen;
unsigned char *odst = dst;
unsigned long l = 0, m = 0, n = 0, o = 0;
// 循环处理分组
size_t off = 0;
for (; off + 4 <= len; off += 4)
{
if ((src[0] > 0x7F) || (src[1] > 0x7F) || (src[2] > 0x7F) || (src[3] > 0x7F))
return (int)(dst - odst);
if ((src[0] == '=') || (src[1] == '=') || (src[2] == '=') || (src[3] == '='))
break;
l = s_decTable[*src++];
m = s_decTable[*src++];
n = s_decTable[*src++];
o = s_decTable[*src++];
*dst++ = (unsigned char)(((l << 2) & 0xFC) | ((m >> 4) & 0x03));
*dst++ = (unsigned char)(((m << 4) & 0xF0) | ((n >> 2) & 0x0F));
*dst++ = (unsigned char)(((n << 6) & 0xC0) | (o & 0x3F));
}
// 处理余下的3个字节
if (off + 3 <= len)
{
if ((src[0] != '=') && (src[1] != '='))
{
l = s_decTable[*src++];
m = s_decTable[*src++];
*dst++ = (unsigned char)(((l << 2) & 0xFC) | ((m >> 4) & 0x03));
}
if ((src[2] != '='))
{
n = s_decTable[*src++];
*dst++ = (unsigned char)(((m << 4) & 0xF0) | ((n >> 2) & 0x0F));
}
}
// 处理余下的两个字节
else if (off + 2 <= len)
{
if ((src[0] != '=') && (src[1] != '='))
{
l = s_decTable[*src++];
m = s_decTable[*src++];
*dst++ = (unsigned char)(((l << 2) & 0xFC) | ((m >> 4) & 0x03));
}
}
return (int)(dst - odst);
}
std::string CBASE64::RsaPriDecrypt(const std::string &cipher_text, const std::string &pri_key)
{
std::string decrypt_text;
RSA *rsa = RSA_new();
BIO *keybio;
keybio = BIO_new_mem_buf((unsigned char *)pri_key.c_str(), -1);
rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL);
if (rsa == nullptr)
{
unsigned long err = ERR_get_error(); // 获取错误号
char err_msg[1024] = {0};
ERR_error_string(err, err_msg); // 格式error:errId:库:函数:原因
return std::string();
}
// 获取RSA单次处理的最大长度
int key_len = RSA_size(rsa);
char *sub_text = new char[key_len + 1];
memset(sub_text, 0, key_len + 1);
int ret = 0;
std::string sub_str;
unsigned int pos = 0;
// 对密文进行分段解密
while (pos < cipher_text.length() - 1)
{
sub_str = cipher_text.substr(pos, key_len);
memset(sub_text, 0, key_len + 1);
ret = RSA_private_decrypt(sub_str.length(), (const unsigned char *)sub_str.c_str(), (unsigned char *)sub_text, rsa, 1);
if (ret >= 0)
{
decrypt_text.append(std::string(sub_text, ret));
// printf("pos:%d, Length: %d ,sub: %s\n", pos, cipher_text.length(),sub_text);
pos += key_len;
}
}
// 释放内存
delete[] sub_text;
BIO_free_all(keybio);
RSA_free(rsa);
return decrypt_text;
}
std::string CBASE64::RsaPriEncrypt(const std::string &clear_text, const std::string &pri_key)
{
std::string encrypt_text;
BIO *keybio = BIO_new_mem_buf((unsigned char *)pri_key.c_str(), -1);
RSA *rsa = RSA_new();
rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL);
if (!rsa)
{
BIO_free_all(keybio);
return std::string("");
}
// 获取RSA单次可以处理的数据块的最大长度
int key_len = RSA_size(rsa);
int block_len = key_len - 11; // 因为填充方式为RSA_PKCS1_PADDING, 所以要在key_len基础上减去11
// 申请内存:存贮加密后的密文数据
char *sub_text = new char[key_len + 1];
memset(sub_text, 0, key_len + 1);
int ret = 0;
unsigned int pos = 0;
std::string sub_str;
// 对数据进行分段加密(返回值是加密后数据的长度)
while (pos < clear_text.length())
{
sub_str = clear_text.substr(pos, block_len);
memset(sub_text, 0, key_len + 1);
ret = RSA_private_encrypt(sub_str.length(), (const unsigned char *)sub_str.c_str(), (unsigned char *)sub_text, rsa, RSA_PKCS1_PADDING);
if (ret >= 0)
{
encrypt_text.append(std::string(sub_text, ret));
}
pos += block_len;
}
// 释放内存
delete sub_text;
BIO_free_all(keybio);
RSA_free(rsa);
return encrypt_text;
}
// 生成RSA密钥结构
void *CBASE64::__genKey(int nBits)
{
RSA *rsa = RSA_new();
BIGNUM *bne = BN_new();
BN_set_word(bne, RSA_F4);
int ret = RSA_generate_key_ex(rsa, nBits, bne, NULL);
BN_free(bne);
if (ret != 1)
{
RSA_free(rsa);
return NULL;
}
return (void *)rsa;
}
// 生成密钥对输出为PEM字符串
bool CBASE64::genKeyStrings(std::string &strPrivateKeyPEMString, std::string &strPublicKeyPEMString)
{
// 生成RSA
RSA *rsa = (RSA *)__genKey(1024);
if (rsa == NULL)
return false;
// 输出私钥
{
BIO *bio = BIO_new(BIO_s_mem());
int ret = PEM_write_bio_RSAPrivateKey(bio, rsa, NULL, NULL, 0, NULL, NULL);
if (ret != 1)
{
BIO_free(bio);
RSA_free(rsa);
return false;
}
char sBuf[1024] = {0};
int bytes = BIO_read(bio, sBuf, 1024);
if (bytes <= 0)
{
BIO_free(bio);
RSA_free(rsa);
return false;
}
BIO_free(bio);
strPrivateKeyPEMString.assign(sBuf, bytes);
}
// 输出公钥
{
BIO *bio = BIO_new(BIO_s_mem());
int ret = PEM_write_bio_RSAPublicKey(bio, rsa);
if (ret != 1)
{
BIO_free(bio);
RSA_free(rsa);
return false;
}
char sBuf[1024] = {0};
int bytes = BIO_read(bio, sBuf, 1024);
if (bytes <= 0)
{
BIO_free(bio);
RSA_free(rsa);
return false;
}
BIO_free(bio);
strPublicKeyPEMString.assign(sBuf, bytes);
}
RSA_free(rsa);
return true;
}
// 使用PEM私钥字符串加密
bool CBASE64::encryptByPrivatePEMString(const std::string &strIn, std::string &strOut, const std::string &strKeyPEMString)
{
// 加载私钥
BIO *bio = BIO_new_mem_buf((const void *)strKeyPEMString.data(), strKeyPEMString.size());
RSA *rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
BIO_free(bio);
if (rsa == NULL)
return false;
// 使用私钥加密
bool b = __encryptOrDecrypt(strIn, strOut, rsa, (const void *)RSA_private_encrypt, true);
RSA_free(rsa);
return b;
}
// 使用RSA执行加密或解密
bool CBASE64::__encryptOrDecrypt(const std::string &strIn, std::string &strOut, const void *pRSA, const void *pFunc, bool bEncrypt)
{
const RSA_encryptOrDecrypt encryptOrDecrypt = (const RSA_encryptOrDecrypt)pFunc;
// 计算加密块大小
int nKeySize = RSA_size((RSA *)pRSA);
int nBlockSize = bEncrypt ? (nKeySize - RSA_PKCS1_PADDING_SIZE) : nKeySize;
const unsigned char *pIn = (const unsigned char *)strIn.data();
int nInSize = strIn.size();
unsigned char *pBuf = new unsigned char[nKeySize];
// 分组迭代加密
for (int i = 0; i < nInSize;)
{
int nBlockLen = (nInSize - i > nBlockSize ? nBlockSize : nInSize - i);
int ret = encryptOrDecrypt(nBlockLen, pIn + i, pBuf, (RSA *)pRSA, RSA_PKCS1_PADDING);
if (ret <= 0)
{
delete[] pBuf;
return false;
}
strOut.append((char *)pBuf, ret);
i += nBlockLen;
}
delete[] pBuf;
return true;
}
// 使用PEM公钥字符串加密
bool CBASE64::encryptByPublicPEMString(const std::string &strIn, std::string &strOut, const std::string &strKeyPEMString)
{
// 加载公钥
BIO *bio = BIO_new_mem_buf((const void *)strKeyPEMString.data(), strKeyPEMString.size());
RSA *rsa = PEM_read_bio_RSAPublicKey(bio, NULL, NULL, NULL);
BIO_free(bio);
if (rsa == NULL)
return false;
// 使用公钥加密
bool b = __encryptOrDecrypt(strIn, strOut, rsa, (const void *)RSA_public_encrypt, true);
RSA_free(rsa);
return b;
}
// 使用PEM公钥字符串解密
bool CBASE64::decryptByPublicPEMString(const std::string &strIn, std::string &strOut, const std::string &strKeyPEMString)
{
// 加载公钥
BIO *bio = BIO_new_mem_buf((const void *)strKeyPEMString.data(), strKeyPEMString.size());
RSA *rsa = PEM_read_bio_RSAPublicKey(bio, NULL, NULL, NULL);
BIO_free(bio);
if (rsa == NULL)
return false;
// 检查密文大小是否为分组的整数倍
int keySize = RSA_size(rsa);
int blockSize = keySize;
if ((strIn.size() % blockSize) != 0)
return false;
// 使用公钥解密
bool b = __encryptOrDecrypt(strIn, strOut, rsa, (const void *)RSA_public_decrypt, false);
RSA_free(rsa);
return b;
}
#endif

View File

@@ -1,90 +0,0 @@
#pragma once
#ifndef CCONNECT_POOL_H_2021
#define CCONNECT_POOL_H_2021
#include <stdio.h>
#include <stdlib.h>
#include <queue>
#include <set>
#include <pthread.h>
#include <unistd.h>
#include "mysql/mysql.h"
class CConnectPool
{
public:
struct Connect_Info
{
int MinConnectCount;
int MaxConnectCount;
const char *Host;
int Port;
const char *Account;
const char *Passwd;
const char* KName;
};
Connect_Info My_Info;
public:
/**
* @brief 创建连接池 \n
* 在主线程中创建连接池创建后需要调用FreePool予以释放
* 创建失败程序会打印错误信息并终止运行
*/
static void
CreatePool(int MinConnectCount, int MaxConnectCount, const char *Host, int Port, const char *Account, const char *Passwd);
/**
* @brief 释放连接池 \n
* 需要在主线程中调用该接口
*/
static void FreePool();
/**
* @brief 获取连接 \n
* 支持多线程使用完成后需调用PutConnect归还连接本函数为阻塞函数直到有可用连接才调用返回
* @return 返回数据库连接
* --NULL表示调用失败
*/
static MYSQL *GetConnect();
/**
* @brief 获取连接 \n
* 支持多线程使用完成后需调用PutConnect归还连接本函数调用后立刻返回若没有空闲连接则返回NULL
* @return 返回数据库连接
* --NULL表示调用失败
* */
static MYSQL *TryGetConnect();
/**
* @brief 向连接池归还连接 \n
* 支持多线程
* @param[in] pConn 需要归还的数据库连接
* */
static void PutConnect(MYSQL *pConn);
private:
CConnectPool();
~CConnectPool();
MYSQL *_GetConnect(bool bTry);
void _PutConnect(MYSQL *pConn);
// 真正创建连接
MYSQL *_CreateConnect();
static CConnectPool *s_pInstance;
std::queue<MYSQL *> m_queueFree; // 空闲队列
std::set<MYSQL *> m_setBusy; // 繁忙队列
pthread_mutex_t m_mutex;
pthread_cond_t m_cond;
};
#endif
/*
使用说明
CConnectPool::CreatePool();
MYSQL *sql = CConnectPool::GetConnect();
CConnectPool::PutConnect(sql);
CConnectPool::FreePool();
*/

View File

@@ -1,559 +0,0 @@
#ifndef DIO_HPP
#define DIO_HPP
#include <iostream>
#include <string>
#include <map>
#include <memory>
#include <functional>
#include <asio.hpp>
#include <asio/ssl.hpp>
#include <stdexcept>
#include <fstream>
#include <algorithm>
#include <cctype>
#include "Version.h"
// ???????????????????
using tcp = asio::ip::tcp;
class HttpsClient {
public:
// ?????????????
using ResponseCallback = std::function<void(
const std::string& response,
long status_code,
const std::string& error
)>;
// ????????????
struct SyncResponse {
std::string response; // ???
long status_code = 0; // ???
std::string error; // ???????????
};
// ???????????
struct FileDownloadResult {
long status_code = 0; // HTTP???
std::string error; // ????
size_t bytes_downloaded = 0;// ??????
};
// ????????io_context?SSL???
HttpsClient(asio::io_context& io_context)
: io_context_(io_context),
ssl_context_(asio::ssl::context::tlsv12_client) {
// ??????CentOS?????
// ssl_context_.set_default_verify_paths();
// ssl_context_.set_verify_mode(asio::ssl::verify_none);
// // ?? TLS 1.0/1.1/1.2/1.3 ??
// ssl_context_.set_options(
// asio::ssl::context::default_workarounds |
// asio::ssl::context::no_sslv2 |
// asio::ssl::context::no_sslv3 |
// asio::ssl::context::single_dh_use);
}
// ????
~HttpsClient() {
if (ssl_stream_) {
try {
ssl_stream_->lowest_layer().close();
}
catch (...) {}
}
}
// ???????GET/POST???
void setRequest(const std::string& host,
const std::string& path,
const std::string& method = "GET",
const std::string& body = "",
const std::map<std::string, std::string>& headers = {}) {
host_ = host;
path_ = path + "?ve=" + std::string(DPS_SCRIPT_VERSION);
method_ = method;
body_ = body;
headers_ = headers;
// std::cout << path_ << std::endl;
// headers_["ve"] = DPS_SCRIPT_VERSION;
}
// -------------------------- ???? --------------------------
SyncResponse sendRequestSync() {
SyncResponse result;
try {
// ????????
tcp::resolver resolver(io_context_);
tcp::resolver::results_type results = resolver.resolve(host_, "https");
// ?????????
ssl_stream_.reset(new asio::ssl::stream<tcp::socket>(io_context_, ssl_context_));
ssl_stream_->set_verify_mode(asio::ssl::verify_none);
ssl_stream_->set_verify_callback(asio::ssl::host_name_verification(host_));
asio::connect(ssl_stream_->lowest_layer(), results);
// SSL??????
ssl_stream_->handshake(asio::ssl::stream_base::client);
// ????????
std::string request = buildRequest();
asio::write(*ssl_stream_, asio::buffer(request));
// ?????
asio::streambuf response_buffer;
asio::error_code ec;
asio::read_until(*ssl_stream_, response_buffer, "\r\n\r\n", ec);
if (ec) throw std::runtime_error("Receive header error: " + ec.message());
// ?????
std::string header_data(
asio::buffers_begin(response_buffer.data()),
asio::buffers_end(response_buffer.data())
);
result.status_code = parseStatusCode(header_data);
// ????????????????
std::string header_lower = header_data;
std::transform(header_lower.begin(), header_lower.end(), header_lower.begin(), ::tolower);
// ??????
bool is_chunked = (header_lower.find("transfer-encoding: chunked") != std::string::npos);
// ?????????????????
size_t header_end = header_data.find("\r\n\r\n") + 4;
response_buffer.consume(header_end);
// ?????
if (is_chunked) {
// ???????????EOF?
std::string body;
asio::streambuf temp_buf;
while (true) {
size_t bytes_read = asio::read_until(*ssl_stream_, temp_buf, "\r\n", ec);
if (ec == asio::error::eof) break;
if (ec) throw std::runtime_error("Read chunk size failed: " + ec.message());
std::string chunk_size_str(
asio::buffers_begin(temp_buf.data()),
asio::buffers_begin(temp_buf.data()) + bytes_read - 2
);
temp_buf.consume(bytes_read);
chunk_size_str.erase(std::remove_if(chunk_size_str.begin(), chunk_size_str.end(), ::isspace), chunk_size_str.end());
size_t chunk_size = std::stoul(chunk_size_str, nullptr, 16);
if (chunk_size == 0) {
asio::read(*ssl_stream_, temp_buf, asio::transfer_exactly(2), ec); // ?????\r\n
break;
}
std::vector<char> chunk_data(chunk_size);
asio::read(*ssl_stream_, asio::buffer(chunk_data), asio::transfer_exactly(chunk_size), ec);
if (ec) throw std::runtime_error("Read chunk data failed: " + ec.message());
body.append(chunk_data.data(), chunk_size);
asio::read(*ssl_stream_, temp_buf, asio::transfer_exactly(2), ec);
temp_buf.consume(2);
}
result.response = body;
}
else {
// ??Content-Length
size_t content_length = 0;
size_t pos = header_lower.find("content-length:");
if (pos != std::string::npos) {
pos += 15;
while (pos < header_data.size() && std::isspace(header_data[pos])) pos++;
size_t end = header_data.find("\r\n", pos);
if (end == std::string::npos) end = header_data.size();
std::string len_str = header_data.substr(pos, end - pos);
len_str.erase(std::remove_if(len_str.begin(), len_str.end(), ::isspace), len_str.end());
if (!len_str.empty()) content_length = std::stoul(len_str);
}
// ????????EOF?
if (content_length > 0) {
std::vector<char> body_buffer(content_length);
size_t total_read = 0;
if (response_buffer.size() > 0) {
total_read = std::min(response_buffer.size(), content_length);
std::copy(
asio::buffers_begin(response_buffer.data()),
asio::buffers_begin(response_buffer.data()) + total_read,
body_buffer.data()
);
response_buffer.consume(total_read);
}
while (total_read < content_length) {
size_t bytes_read = ssl_stream_->read_some(asio::buffer(body_buffer.data() + total_read, content_length - total_read), ec);
if (ec == asio::error::eof) {
if (total_read == content_length) break;
else throw std::runtime_error("Incomplete body: expected " + std::to_string(content_length) + " bytes, got " + std::to_string(total_read));
}
if (ec) throw std::runtime_error("Read body failed: " + ec.message());
total_read += bytes_read;
}
result.response = std::string(body_buffer.begin(), body_buffer.end());
}
else {
// ?Content-Length??????????EOF
asio::read(*ssl_stream_, response_buffer, asio::transfer_all(), ec);
if (ec && ec != asio::error::eof) throw std::runtime_error("Read body failed: " + ec.message());
result.response = std::string(
asio::buffers_begin(response_buffer.data()),
asio::buffers_end(response_buffer.data())
);
}
}
}
catch (const std::exception& e) {
result.error = e.what();
}
// ????
try {
if (ssl_stream_) {
ssl_stream_->lowest_layer().close();
}
}
catch (...) {}
ssl_stream_.reset();
return result;
}
// -------------------------- ???????? --------------------------
FileDownloadResult downloadFileSync(const std::string& save_path) {
FileDownloadResult result;
std::ofstream file(save_path, std::ios::binary | std::ios::trunc);
if (!file.is_open()) {
result.error = "Failed to open file for writing: " + save_path;
return result;
}
try {
// ????????
tcp::resolver resolver(io_context_);
tcp::resolver::results_type results = resolver.resolve(host_, "https");
// ?????????
ssl_stream_.reset(new asio::ssl::stream<tcp::socket>(io_context_, ssl_context_));
ssl_stream_->set_verify_mode(asio::ssl::verify_none);
ssl_stream_->set_verify_callback(asio::ssl::host_name_verification(host_));
asio::connect(ssl_stream_->lowest_layer(), results);
// SSL??????
ssl_stream_->handshake(asio::ssl::stream_base::client);
// ????????
std::string request = buildRequest();
asio::write(*ssl_stream_, asio::buffer(request));
// ?????
asio::streambuf response_buffer;
asio::error_code ec;
asio::read_until(*ssl_stream_, response_buffer, "\r\n\r\n", ec);
if (ec) throw std::runtime_error("Receive header error: " + ec.message());
// ?????
std::string header_data(
asio::buffers_begin(response_buffer.data()),
asio::buffers_end(response_buffer.data())
);
result.status_code = parseStatusCode(header_data);
// ?????????
if (result.status_code < 200 || result.status_code >= 300) {
result.error = "HTTP request failed with status code: " + std::to_string(result.status_code);
file.close();
std::remove(save_path.c_str()); // ????????
return result;
}
// ????????????????
std::string header_lower = header_data;
std::transform(header_lower.begin(), header_lower.end(), header_lower.begin(), ::tolower);
// ??????
bool is_chunked = (header_lower.find("transfer-encoding: chunked") != std::string::npos);
// ?????????????????
size_t header_end = header_data.find("\r\n\r\n") + 4;
response_buffer.consume(header_end);
// ??????????????
if (response_buffer.size() > 0) {
result.bytes_downloaded += response_buffer.size();
// ??????????????
const char* data_ptr = asio::buffer_cast<const char*>(response_buffer.data());
file.write(data_ptr, static_cast<std::streamsize>(response_buffer.size()));
response_buffer.consume(response_buffer.size());
}
// ??????????
if (is_chunked) {
// ????????
asio::streambuf temp_buf;
char chunk_buffer[8192]; // 8KB???
while (true) {
// ?????
size_t bytes_read = asio::read_until(*ssl_stream_, temp_buf, "\r\n", ec);
if (ec == asio::error::eof) break;
if (ec) throw std::runtime_error("Read chunk size failed: " + ec.message());
std::string chunk_size_str(
asio::buffers_begin(temp_buf.data()),
asio::buffers_begin(temp_buf.data()) + bytes_read - 2
);
temp_buf.consume(bytes_read);
chunk_size_str.erase(std::remove_if(chunk_size_str.begin(), chunk_size_str.end(), ::isspace), chunk_size_str.end());
size_t chunk_size = std::stoul(chunk_size_str, nullptr, 16);
if (chunk_size == 0) {
asio::read(*ssl_stream_, temp_buf, asio::transfer_exactly(2), ec); // ?????\r\n
break;
}
// ??????????
size_t remaining = chunk_size;
while (remaining > 0) {
size_t to_read = std::min(remaining, sizeof(chunk_buffer));
size_t read_bytes = ssl_stream_->read_some(asio::buffer(chunk_buffer, to_read), ec);
if (ec) throw std::runtime_error("Read chunk data failed: " + ec.message());
file.write(chunk_buffer, static_cast<std::streamsize>(read_bytes));
result.bytes_downloaded += read_bytes;
remaining -= read_bytes;
}
// ??????\r\n
asio::read(*ssl_stream_, temp_buf, asio::transfer_exactly(2), ec);
temp_buf.consume(2);
}
}
else {
// ??Content-Length????
size_t content_length = 0;
size_t pos = header_lower.find("content-length:");
if (pos != std::string::npos) {
pos += 15;
while (pos < header_data.size() && std::isspace(header_data[pos])) pos++;
size_t end = header_data.find("\r\n", pos);
if (end == std::string::npos) end = header_data.size();
std::string len_str = header_data.substr(pos, end - pos);
len_str.erase(std::remove_if(len_str.begin(), len_str.end(), ::isspace), len_str.end());
if (!len_str.empty()) content_length = std::stoul(len_str);
}
// ??????
if (content_length > 0) {
size_t remaining = content_length - result.bytes_downloaded;
char buffer[8192]; // 8KB???
while (remaining > 0) {
size_t to_read = std::min(remaining, sizeof(buffer));
size_t bytes_read = ssl_stream_->read_some(asio::buffer(buffer, to_read), ec);
if (ec == asio::error::eof) {
if (remaining == 0) break;
else throw std::runtime_error("Connection closed prematurely");
}
if (ec) throw std::runtime_error("Read body failed: " + ec.message());
file.write(buffer, static_cast<std::streamsize>(bytes_read));
result.bytes_downloaded += bytes_read;
remaining -= bytes_read;
}
}
else {
// ?Content-Length??????????EOF
char buffer[8192];
while (true) {
size_t bytes_read = ssl_stream_->read_some(asio::buffer(buffer), ec);
if (ec == asio::error::eof) break;
if (ec) throw std::runtime_error("Read body failed: " + ec.message());
file.write(buffer, static_cast<std::streamsize>(bytes_read));
result.bytes_downloaded += bytes_read;
}
}
}
// ????????
file.flush();
file.close();
}
catch (const std::exception& e) {
result.error = e.what();
file.close();
std::remove(save_path.c_str()); // ???????
}
// ????
try {
if (ssl_stream_) {
ssl_stream_->lowest_layer().close();
}
}
catch (...) {}
ssl_stream_.reset();
return result;
}
private:
// C++11???make_unique??
template<typename T, typename... Args>
static std::unique_ptr<T> make_unique(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
// ????????GET/POST???
std::string buildRequest() const {
std::string request = method_ + " " + path_ + " HTTP/1.1\r\n";
request += "Host: " + host_ + "\r\n";
request += "Connection: close\r\n";
// ??????
for (const auto& header : headers_) {
request += header.first + ": " + header.second + "\r\n";
}
// ??body?????
if (!body_.empty()) {
request += "Content-Length: " + std::to_string(body_.size()) + "\r\n";
}
request += "\r\n" + body_;
return request;
}
// ???????
long parseStatusCode(const std::string& header_data) const {
size_t status_pos = header_data.find(" ") + 1;
if (status_pos != std::string::npos && status_pos + 3 <= header_data.size()) {
try {
return std::stol(header_data.substr(status_pos, 3));
}
catch (...) {}
}
return 0;
}
// -------------------------- ?????? --------------------------
void connectAsync(tcp::resolver::results_type endpoints) {
ssl_stream_.reset(new asio::ssl::stream<tcp::socket>(io_context_, ssl_context_));
ssl_stream_->set_verify_mode(asio::ssl::verify_peer);
ssl_stream_->set_verify_callback(asio::ssl::host_name_verification(host_));
asio::async_connect(
ssl_stream_->lowest_layer(), endpoints,
[this](const asio::error_code& ec, const tcp::endpoint&) {
if (ec) {
callback_("", 0, "Connect error: " + ec.message());
return;
}
handshakeAsync();
}
);
}
void handshakeAsync() {
ssl_stream_->async_handshake(
asio::ssl::stream_base::client,
[this](const asio::error_code& ec) {
if (ec) {
callback_("", 0, "Handshake error: " + ec.message());
return;
}
sendRequestDataAsync();
}
);
}
void sendRequestDataAsync() {
std::string request = buildRequest();
asio::async_write(
*ssl_stream_, asio::buffer(request),
[this](const asio::error_code& ec, std::size_t) {
if (ec) {
callback_("", 0, "Send error: " + ec.message());
return;
}
receiveResponseAsync();
}
);
}
void receiveResponseAsync() {
asio::async_read_until(
*ssl_stream_, response_buffer_, "\r\n\r\n",
[this](const asio::error_code& ec, std::size_t bytes_transferred) {
if (ec) {
callback_("", 0, "Receive header error: " + ec.message());
return;
}
// ?????
std::string header_data(asio::buffers_begin(response_buffer_.data()),
asio::buffers_begin(response_buffer_.data()) + bytes_transferred);
response_buffer_.consume(bytes_transferred);
long status_code = parseStatusCode(header_data);
// ?????
receiveBodyAsync(status_code);
}
);
}
void receiveBodyAsync(long status_code) {
asio::async_read(
*ssl_stream_, response_buffer_, asio::transfer_all(),
[this, status_code](const asio::error_code& ec, std::size_t) {
std::string response_body;
if (!ec) {
response_body = std::string(
asio::buffers_begin(response_buffer_.data()),
asio::buffers_end(response_buffer_.data())
);
}
else if (ec != asio::error::eof) {
callback_("", status_code, "Receive body error: " + ec.message());
return;
}
// ????
callback_(response_body, status_code, "");
// ????
try {
ssl_stream_->lowest_layer().close();
}
catch (...) {}
ssl_stream_.reset();
response_buffer_.consume(response_buffer_.size());
}
);
}
// ????
asio::io_context& io_context_;
asio::ssl::context ssl_context_;
std::unique_ptr<asio::ssl::stream<tcp::socket>> ssl_stream_;
asio::streambuf response_buffer_;
std::string host_;
std::string path_;
std::string method_;
std::string body_;
std::map<std::string, std::string> headers_;
ResponseCallback callback_;
};
#endif // DIO_HPP

View File

@@ -1,717 +0,0 @@
#pragma once
#include "controller.h"
typedef int (*fnCUser_CheckMoveTown)(void *CUser, unsigned int a2);
typedef int (*fnWongWork_CDungeonClear_getClearedDungeonDiff)(void *thisC, short a2);
typedef signed int (*fnCUser_use_stackable)(void *CUser, short a2, void *a3, int a4, int a5);
typedef int (*fnWongWork_CItemUpgrade_Separate__DoProcUpgrade)(void *thisC, void *CUser, void *a3, void *a4);
typedef int (*fnCUserCharacInfo_incCurCharacUsedFatigue)(void *thisC, unsigned short a2);
typedef int (*fnDisPatcher_BuyItem_get_data)(void *a1, void *a2, int a3, void *a4);
typedef bool (*fnDispatcher_BuyCeraShopItem_useCountDownCoinInFreeCoinDungeon)(int a1, void *CUser, int a3);
typedef int (*fnCParty_get_item)(void *thisC, void *CUser, int a4, bool a5, char a6, int *a7, unsigned char *a8, bool *a9);
typedef int (*fnCInventory_insertItemIntoInventory)(void **a1, __int64 a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10, int a11, int a12, int a13, int a14, int a15, char a16, int a17, unsigned char a18, unsigned char a19);
typedef int (*fnCParty__onGetItem)(void *thisC, void *a2, unsigned int a3, int a4);
typedef int (*fnCUser_get_unique_id)(void *thisC);
typedef int (*fnCHackLog_OverDamage_GetDungeonLimitDamageAndHackType)(void *a1, _DWORD *a2, _DWORD *a3);
typedef int (*fnCDungeon_get_index)(void *CDungeon);
typedef int (*fnCUserCharacInfo_get_charac_level)(void *thisC);
typedef int (*fnCParty_getMonsterTotalExp)(void *thisC, unsigned int a2, char a3, int a4, float a5, float a6, bool a7);
typedef char *(*fnCParty_set_clear_reward_exp_parameter)(long double ExpAffectRate, void *thisC, void *a3, int a4, void *a5);
typedef int (*fnBingoEvent_sendOneMatchLineReward)(void *thisC, void *a2);
typedef int (*fnBingoEvent_sendMaxMatchLineReward)(void *thisC, void *a2);
typedef int (*fnCBattle_Field_add_monsters_current_map)(void *a1, int a2, int a3, void *a4, _DWORD *a5, int *a6, _DWORD *a7);
typedef int (*fnCDungeon_get_standard_level)(void *thisC);
typedef int (*fnCUser_isHumanCertified)(void *CUser);
typedef void (*fnDispatcher_ChangeAnotherSkillTree_send)(void *thisC, void *a2, void *a3);
typedef void (*fnCUser_AddDailyItem)(void *thisC);
typedef int (*fnGameWorld_leave_game_world)(int a1, void *thisC, void *a3);
typedef int (*fnCGameManager_user_exit)(int a1, void *mutex, void **a3);
typedef void (*fnGameWorld_send_chat_msg)(void *a1, void *a2, char a3, unsigned short a4, int a5, char *dest, size_t n, void *src, size_t a9, int a10);
typedef int (*fnGameWorld_IsForbiddenChat)(void *thisC, char *s);
typedef void (*fnCUser_quest_action)(void **thisC, int a2, void *a3, int a4, int a5);
typedef int (*fnCParty_get_dungeon_clear_state)(void *thisC);
typedef int (*fnCParty_SetPlayResult)(void *thisC, void *a2);
typedef int (*fnBestClearTime_getBestClearTime)(void *thisC, char a2, int a3);
SUBHOOK_INIT(CUser_CheckMoveTown, 0x8678526);
SUBHOOK_INIT(WongWork_CDungeonClear_getClearedDungeonDiff, 0x85BF96C);
SUBHOOK_INIT(CUser_use_stackable, 0x865E0AE);
SUBHOOK_INIT(WongWork_CItemUpgrade_Separate__DoProcUpgrade, 0x811E468);
SUBHOOK_INIT(CUserCharacInfo_incCurCharacUsedFatigue, 0x8696422);
SUBHOOK_INIT(DisPatcher_BuyItem_get_data, 0x81BE658);
SUBHOOK_INIT(Dispatcher_BuyCeraShopItem_useCountDownCoinInFreeCoinDungeon, 0x81FE4B8);
SUBHOOK_INIT(CParty_get_item, 0x85A3B98);
SUBHOOK_INIT(CInventory_insertItemIntoInventory, 0x8502D86);
SUBHOOK_INIT(CParty__onGetItem, 0x85B949C);
SUBHOOK_INIT(CUser_get_unique_id, 0x80DA37C);
SUBHOOK_INIT(CHackLog_OverDamage_GetDungeonLimitDamageAndHackType, 0x8286790);
SUBHOOK_INIT(CDungeon_get_index, 0x80FDCF0);
SUBHOOK_INIT(CUserCharacInfo_get_charac_level, 0x80DA2B8);
SUBHOOK_INIT(CParty_getMonsterTotalExp, 0x85A23DC);
SUBHOOK_INIT(CParty_set_clear_reward_exp_parameter, 0x85ADB00);
SUBHOOK_INIT(BingoEvent_sendOneMatchLineReward, 0x80CA3D4);
SUBHOOK_INIT(BingoEvent_sendMaxMatchLineReward, 0x80CA622);
SUBHOOK_INIT(CBattle_Field_add_monsters_current_map, 0x830162E);
SUBHOOK_INIT(CDungeon_get_standard_level, 0x80F9810);
SUBHOOK_INIT(CUser_isHumanCertified, 0x823021A);
SUBHOOK_INIT(Dispatcher_ChangeAnotherSkillTree_send, 0x81D2134);
SUBHOOK_INIT(CUser_AddDailyItem, 0x8656CAA);
SUBHOOK_INIT(GameWorld_leave_game_world, 0x86C5288);
SUBHOOK_INIT(CGameManager_user_exit, 0x82985A8);
SUBHOOK_INIT(GameWorld_send_chat_msg, 0x86C975E);
SUBHOOK_INIT(GameWorld_IsForbiddenChat, 0x86CD908);
SUBHOOK_INIT(CUser_quest_action, 0x866DA8A);
SUBHOOK_INIT(CParty_get_dungeon_clear_state, 0x822D89C);
SUBHOOK_INIT(CParty_SetPlayResult, 0x85B2412);
SUBHOOK_INIT(BestClearTime_getBestClearTime, 0x80C8AC0);
int _CUser_CheckMoveTown(void *CUser, unsigned int a2)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
// 执行虚拟机 Main 函数
SQInteger Ret = -99;
SQInteger top = sq_gettop(v); // saves the stack size before the call
sq_pushroottable(v); // pushes the global table
sq_pushstring(v, _SC("Cb_CUser_CheckMoveTown"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{ // gets the fie123oo' from the global table
sq_pushroottable(v); // push the 'this' (in this case is the global table)
sq_pushuserpointer(v, CUser);
sq_pushinteger(v, a2);
sq_call(v, 3, SQTrue, SQTrue); // calls the function
sq_getinteger(v, -1, &Ret);
}
sq_settop(v, top); // restores the original stack size
if (Ret == -99)
return CUser_CheckMoveTown(CUser, a2);
else
return Ret;
}
int _WongWork_CDungeonClear_getClearedDungeonDiff(void *thisC, short a2)
{
int OldRet = WongWork_CDungeonClear_getClearedDungeonDiff(thisC, a2);
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
SQInteger Ret = -99;
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_WongWork_CDungeonClear_getClearedDungeonDiff"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, thisC);
sq_pushinteger(v, a2);
sq_pushinteger(v, OldRet);
sq_call(v, 4, SQTrue, SQTrue);
sq_getinteger(v, -1, &Ret);
}
sq_settop(v, top);
if (Ret == -99)
return OldRet;
else
return Ret;
}
signed int _CUser_use_stackable(void *CUser, short a2, void *a3, int a4, int a5)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_CUser_use_stackable"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, CUser);
sq_pushinteger(v, a2);
sq_pushuserpointer(v, a3);
sq_pushinteger(v, a4);
sq_pushinteger(v, a5);
sq_call(v, 6, SQFalse, SQTrue);
}
sq_settop(v, top);
return CUser_use_stackable(CUser, a2, a3, a4, a5);
}
int _WongWork_CItemUpgrade_Separate__DoProcUpgrade(void *thisC, void *CUser, void *a3, void *a4)
{
int OldRet = WongWork_CItemUpgrade_Separate__DoProcUpgrade(thisC, CUser, a3, a4);
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger Ret = -99;
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_WongWork_CItemUpgrade_Separate__DoProcUpgrade"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, thisC);
sq_pushuserpointer(v, CUser);
sq_pushinteger(v, OldRet);
sq_pushuserpointer(v, a3);
sq_pushuserpointer(v, a4);
sq_call(v, 6, SQTrue, SQTrue);
sq_getinteger(v, -1, &Ret);
}
sq_settop(v, top);
if (Ret == -99)
return OldRet;
else
return Ret;
}
int _CUserCharacInfo_incCurCharacUsedFatigue(void *thisC, unsigned short a2)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_CUserCharacInfo_incCurCharacUsedFatigue"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, thisC);
sq_pushinteger(v, a2);
sq_call(v, 3, SQFalse, SQTrue);
}
sq_settop(v, top);
return CUserCharacInfo_incCurCharacUsedFatigue(thisC, a2);
}
int _DisPatcher_BuyItem_get_data(void *a1, void *a2, int a3, void *a4)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_DisPatcher_BuyItem_get_data"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, a1);
sq_pushuserpointer(v, a2);
sq_pushinteger(v, a3);
sq_pushuserpointer(v, a4);
sq_call(v, 5, SQFalse, SQTrue);
}
sq_settop(v, top);
return DisPatcher_BuyItem_get_data(a1, a2, a3, a4);
}
bool _Dispatcher_BuyCeraShopItem_useCountDownCoinInFreeCoinDungeon(int a1, void *CUser, int a3)
{
int OldRet = Dispatcher_BuyCeraShopItem_useCountDownCoinInFreeCoinDungeon(a1, CUser, a3);
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger Ret = -99;
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_Dispatcher_BuyCeraShopItem_useCountDownCoinInFreeCoinDungeon"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushinteger(v, a1);
sq_pushuserpointer(v, CUser);
sq_pushinteger(v, a3);
sq_pushinteger(v, OldRet);
sq_call(v, 5, SQTrue, SQTrue);
sq_getinteger(v, -1, &Ret);
}
sq_settop(v, top);
if (Ret == -99)
return OldRet;
else
return Ret;
}
int _CParty_get_item(void *thisC, void *CUser, int a4, bool a5, char a6, int *a7, unsigned char *a8, bool *a9)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_CParty_get_item"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, thisC);
sq_pushuserpointer(v, CUser);
sq_pushinteger(v, a4);
sq_pushbool(v, a5);
sq_pushinteger(v, a6);
sq_pushuserpointer(v, a7);
sq_pushuserpointer(v, a8);
sq_pushuserpointer(v, a9);
sq_call(v, 9, SQFalse, SQTrue);
}
sq_settop(v, top);
return CParty_get_item(thisC, CUser, a4, a5, a6, a7, a8, a9);
}
int _CInventory_insertItemIntoInventory(void **a1, __int64 a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10, int a11, int a12, int a13, int a14, int a15, char a16, int a17, unsigned char a18, unsigned char a19)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_CInventory_insertItemIntoInventory"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, a1);
sq_pushinteger(v, a2);
sq_pushinteger(v, a3);
sq_pushinteger(v, a4);
sq_pushinteger(v, a5);
sq_pushinteger(v, a6);
sq_pushinteger(v, a7);
sq_pushinteger(v, a8);
sq_pushinteger(v, a9);
sq_pushinteger(v, a10);
sq_pushinteger(v, a11);
sq_pushinteger(v, a12);
sq_pushinteger(v, a13);
sq_pushinteger(v, a14);
sq_pushinteger(v, a15);
sq_pushinteger(v, a16);
sq_pushinteger(v, a17);
sq_pushinteger(v, a18);
sq_pushinteger(v, a19);
sq_call(v, 20, SQFalse, SQTrue);
}
sq_settop(v, top);
return CInventory_insertItemIntoInventory(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19);
}
int _CParty__onGetItem(void *thisC, void *a2, unsigned int a3, int a4)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_CParty__onGetItem"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, thisC);
sq_pushuserpointer(v, a2);
sq_pushinteger(v, a3);
sq_pushinteger(v, a4);
sq_call(v, 5, SQFalse, SQTrue);
}
sq_settop(v, top);
return CParty__onGetItem(thisC, a2, a3, a4);
}
int _CUser_get_unique_id(void *thisC)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_CUser_get_unique_id"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, thisC);
sq_call(v, 2, SQFalse, SQTrue);
}
sq_settop(v, top);
return CUser_get_unique_id(thisC);
}
int _CHackLog_OverDamage_GetDungeonLimitDamageAndHackType(void *a1, _DWORD *a2, _DWORD *a3)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_CHackLog_OverDamage_GetDungeonLimitDamageAndHackType"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, a1);
sq_pushuserpointer(v, a2);
sq_pushuserpointer(v, a3);
sq_call(v, 4, SQFalse, SQTrue);
}
sq_settop(v, top);
return CHackLog_OverDamage_GetDungeonLimitDamageAndHackType(a1, a2, a3);
}
int _CDungeon_get_index(void *CDungeon)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_CDungeon_get_index"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, CDungeon);
sq_call(v, 2, SQFalse, SQTrue);
}
sq_settop(v, top);
return CDungeon_get_index(CDungeon);
}
int _CUserCharacInfo_get_charac_level(void *thisC)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_CUserCharacInfo_get_charac_level"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, thisC);
sq_call(v, 2, SQFalse, SQTrue);
}
sq_settop(v, top);
return CUserCharacInfo_get_charac_level(thisC);
}
int _CParty_getMonsterTotalExp(void *thisC, unsigned int a2, char a3, int a4, float a5, float a6, bool a7)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_CParty_getMonsterTotalExp"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, thisC);
sq_pushinteger(v, a2);
sq_pushinteger(v, a3);
sq_pushinteger(v, a4);
sq_pushfloat(v, a5);
sq_pushfloat(v, a6);
sq_pushbool(v, a7);
sq_call(v, 8, SQFalse, SQTrue);
}
sq_settop(v, top);
return CParty_getMonsterTotalExp(thisC, a2, a3, a4, a5, a6, a7);
}
char *_CParty_set_clear_reward_exp_parameter(long double ExpAffectRate, void *thisC, void *a3, int a4, void *a5)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_CParty_set_clear_reward_exp_parameter"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushinteger(v, ExpAffectRate);
sq_pushuserpointer(v, thisC);
sq_pushuserpointer(v, a3);
sq_pushinteger(v, a4);
sq_pushuserpointer(v, a5);
sq_call(v, 6, SQFalse, SQTrue);
}
sq_settop(v, top);
return CParty_set_clear_reward_exp_parameter(ExpAffectRate, thisC, a3, a4, a5);
}
int _BingoEvent_sendOneMatchLineReward(void *thisC, void *a2)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_BingoEvent_sendOneMatchLineReward"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, thisC);
sq_pushuserpointer(v, a2);
sq_call(v, 3, SQFalse, SQTrue);
}
sq_settop(v, top);
return BingoEvent_sendOneMatchLineReward(thisC, a2);
}
int _BingoEvent_sendMaxMatchLineReward(void *thisC, void *a2)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_BingoEvent_sendMaxMatchLineReward"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, thisC);
sq_pushuserpointer(v, a2);
sq_call(v, 3, SQFalse, SQTrue);
}
sq_settop(v, top);
return BingoEvent_sendMaxMatchLineReward(thisC, a2);
}
int _CBattle_Field_add_monsters_current_map(void *a1, int a2, int a3, void *a4, _DWORD *a5, int *a6, _DWORD *a7)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_CBattle_Field_add_monsters_current_map"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, a1);
sq_pushinteger(v, a2);
sq_pushinteger(v, a3);
sq_pushuserpointer(v, a4);
sq_pushuserpointer(v, a5);
sq_pushuserpointer(v, a6);
sq_pushuserpointer(v, a7);
sq_call(v, 8, SQFalse, SQTrue);
}
sq_settop(v, top);
return CBattle_Field_add_monsters_current_map(a1, a2, a3, a4, a5, a6, a7);
}
int _CDungeon_get_standard_level(void *thisC)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_CDungeon_get_standard_level"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, thisC);
sq_call(v, 2, SQFalse, SQTrue);
}
sq_settop(v, top);
return CDungeon_get_standard_level(thisC);
}
int _CUser_isHumanCertified(void *CUser)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_CUser_isHumanCertified"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, CUser);
sq_call(v, 2, SQFalse, SQTrue);
}
sq_settop(v, top);
return CUser_isHumanCertified(CUser);
}
void _Dispatcher_ChangeAnotherSkillTree_send(void *thisC, void *a2, void *a3)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_Dispatcher_ChangeAnotherSkillTree_send"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, thisC);
sq_pushuserpointer(v, a2);
sq_pushuserpointer(v, a3);
sq_call(v, 4, SQFalse, SQTrue);
}
sq_settop(v, top);
Dispatcher_ChangeAnotherSkillTree_send(thisC, a2, a3);
return;
}
void _CUser_AddDailyItem(void *thisC)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_CUser_AddDailyItem"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, thisC);
sq_call(v, 2, SQFalse, SQTrue);
}
sq_settop(v, top);
CUser_AddDailyItem(thisC);
return;
}
int _GameWorld_leave_game_world(int a1, void *thisC, void *a3)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_GameWorld_leave_game_world"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushinteger(v, a1);
sq_pushuserpointer(v, thisC);
sq_pushuserpointer(v, a3);
sq_call(v, 4, SQFalse, SQTrue);
}
sq_settop(v, top);
return GameWorld_leave_game_world(a1, thisC, a3);
}
int _CGameManager_user_exit(int a1, void *mutex, void **a3)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_CGameManager_user_exit"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushinteger(v, a1);
sq_pushuserpointer(v, mutex);
sq_pushuserpointer(v, a3);
sq_call(v, 4, SQFalse, SQTrue);
}
sq_settop(v, top);
return CGameManager_user_exit(a1, mutex, a3);
}
void _GameWorld_send_chat_msg(void *a1, void *a2, char a3, unsigned __int16 a4, int a5, char *dest, size_t n, void *src, size_t a9, int a10)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_GameWorld_send_chat_msg"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, a1);
sq_pushuserpointer(v, a2);
sq_pushinteger(v, a3);
sq_pushinteger(v, a4);
sq_pushinteger(v, a5);
sq_pushuserpointer(v, dest);
sq_pushinteger(v, n);
sq_pushuserpointer(v, src);
sq_pushinteger(v, a9);
sq_pushinteger(v, a10);
sq_call(v, 11, SQFalse, SQTrue);
}
sq_settop(v, top);
GameWorld_send_chat_msg(a1, a2, a3, a4, a5, dest, n, src, a9, a10);
return;
}
int _GameWorld_IsForbiddenChat(void *thisC, char *s)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_GameWorld_IsForbiddenChat"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, thisC);
sq_pushstring(v, s, -1);
sq_call(v, 3, SQFalse, SQTrue);
}
sq_settop(v, top);
return GameWorld_IsForbiddenChat(thisC, s);
}
void _CUser_quest_action(void **thisC, int a2, void *a3, int a4, int a5)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_CUser_quest_action"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, thisC);
sq_pushinteger(v, a2);
sq_pushuserpointer(v, a3);
sq_pushinteger(v, a4);
sq_pushinteger(v, a5);
sq_call(v, 6, SQFalse, SQTrue);
}
sq_settop(v, top);
CUser_quest_action(thisC, a2, a3, a4, a5);
return;
}
int _CParty_get_dungeon_clear_state(void *thisC)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_CParty_get_dungeon_clear_state"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, thisC);
sq_call(v, 2, SQFalse, SQTrue);
}
sq_settop(v, top);
return CParty_get_dungeon_clear_state(thisC);
}
int _CParty_SetPlayResult(void *thisC, void *a2)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_CParty_SetPlayResult"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, thisC);
sq_pushuserpointer(v, a2);
sq_call(v, 3, SQFalse, SQTrue);
}
sq_settop(v, top);
return CParty_SetPlayResult(thisC, a2);
}
int _BestClearTime_getBestClearTime(void *thisC, char a2, int a3)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v, _SC("Cb_BestClearTime_getBestClearTime"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, thisC);
sq_pushinteger(v, a2);
sq_pushinteger(v, a3);
sq_call(v, 4, SQFalse, SQTrue);
}
sq_settop(v, top);
return BestClearTime_getBestClearTime(thisC, a2, a3);
}
void OpenHook1()
{
SUBHOOK_SETUP(CUser_CheckMoveTown);
SUBHOOK_SETUP(WongWork_CDungeonClear_getClearedDungeonDiff);
SUBHOOK_SETUP(CUser_use_stackable);
SUBHOOK_SETUP(WongWork_CItemUpgrade_Separate__DoProcUpgrade);
SUBHOOK_SETUP(CUserCharacInfo_incCurCharacUsedFatigue);
SUBHOOK_SETUP(DisPatcher_BuyItem_get_data);
SUBHOOK_SETUP(Dispatcher_BuyCeraShopItem_useCountDownCoinInFreeCoinDungeon);
SUBHOOK_SETUP(CParty_get_item);
SUBHOOK_SETUP(CInventory_insertItemIntoInventory);
SUBHOOK_SETUP(CParty__onGetItem);
// SUBHOOK_SETUP(CUser_get_unique_id);
SUBHOOK_SETUP(CHackLog_OverDamage_GetDungeonLimitDamageAndHackType);
SUBHOOK_SETUP(CDungeon_get_index);
SUBHOOK_SETUP(CUserCharacInfo_get_charac_level);
SUBHOOK_SETUP(CParty_getMonsterTotalExp);
SUBHOOK_SETUP(CParty_set_clear_reward_exp_parameter);
SUBHOOK_SETUP(BingoEvent_sendOneMatchLineReward);
SUBHOOK_SETUP(BingoEvent_sendMaxMatchLineReward);
SUBHOOK_SETUP(CBattle_Field_add_monsters_current_map);
SUBHOOK_SETUP(CDungeon_get_standard_level);
SUBHOOK_SETUP(CUser_isHumanCertified);
SUBHOOK_SETUP(Dispatcher_ChangeAnotherSkillTree_send);
SUBHOOK_SETUP(CUser_AddDailyItem);
SUBHOOK_SETUP(GameWorld_leave_game_world);
SUBHOOK_SETUP(CGameManager_user_exit);
SUBHOOK_SETUP(GameWorld_send_chat_msg);
SUBHOOK_SETUP(GameWorld_IsForbiddenChat);
SUBHOOK_SETUP(CUser_quest_action);
SUBHOOK_SETUP(CParty_get_dungeon_clear_state);
SUBHOOK_SETUP(CParty_SetPlayResult);
SUBHOOK_SETUP(BestClearTime_getBestClearTime);
}

View File

@@ -1,171 +0,0 @@
#pragma once
#include <iostream>
#include <fstream>
#include <cctype>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
// 定义宏用于注册获取不同类型值的函数
#define REGISTER_GET_FUNCTION(Type, FunctionName) \
Type Get##FunctionName() \
{ \
char buffer[sizeof(Type)]; \
read(buffer, sizeof(Type)); \
Type result; \
memcpy(&result, buffer, sizeof(Type)); \
return result; \
}
class IO_Ex
{
public:
// 原始数据
char *_Data;
// 最大长度
int _MaxLen = 0;
// 当前位置
int _CurPos = 0;
// 上一次读取的实际大小
int _LastReadSize = 0;
public:
IO_Ex(const char *filename)
{
fstream file(filename, std::ios::binary | std::ios::in);
if (file.is_open())
{
file.seekg(0, std::ios::end);
std::streampos length = file.tellg();
file.seekg(0, std::ios::beg);
_MaxLen = length;
_Data = new char[static_cast<size_t>(length)];
file.read(_Data, length);
file.close();
}
else
{
std::cerr << "无法打开文件。" << std::endl;
}
}
~IO_Ex();
public:
int tellg()
{
return _CurPos;
}
void read(char *ptr, int size)
{
if ((size + _CurPos) > _MaxLen)
{
size = _MaxLen - _CurPos;
}
memcpy(ptr, _Data + _CurPos, size);
_CurPos += size;
_LastReadSize = size;
}
int gcount()
{
return _LastReadSize;
}
void seek(int _jidx)
{
_CurPos = _jidx;
}
public:
unsigned int charPtrToInt(const char *bytes)
{
unsigned int result;
std::memcpy(&result, bytes, sizeof(int));
return result;
}
void CrcDecode(const int Length, const int crc32)
{
int num = 0x81A79011;
for (int i = 0; i < Length; i += 4)
{
int Pos = tellg();
char buffer[4];
read(buffer, 4);
unsigned int anInt = charPtrToInt(buffer);
unsigned int val = (anInt ^ num ^ crc32);
unsigned int jiemi = (val >> 6) | ((val << (32 - 6)) & 0xFFFFFFFF);
_Data[Pos] = ((jiemi >> 0) & 0xFF);
;
_Data[Pos + 1] = ((jiemi >> 8) & 0xFF);
_Data[Pos + 2] = ((jiemi >> 16) & 0xFF);
_Data[Pos + 3] = ((jiemi >> 24) & 0xFF);
}
}
std::string tolower(std::string str)
{
for (size_t i = 0; i < str.length(); ++i)
{
str[i] = std::tolower(str[i]);
}
return str;
}
std::vector<std::string> split(const std::string &str, const std::string &delimiter)
{
std::vector<std::string> tokens;
size_t pos = 0;
size_t found;
while ((found = str.find(delimiter, pos)) != std::string::npos)
{
tokens.push_back(str.substr(pos, found - pos));
pos = found + delimiter.length();
}
tokens.push_back(str.substr(pos));
return tokens;
}
public:
REGISTER_GET_FUNCTION(int, Int);
REGISTER_GET_FUNCTION(short, Short);
REGISTER_GET_FUNCTION(unsigned short, UShort);
std::string GetString(const int size)
{
char *buffer = new char[size + 1];
read(buffer, size);
buffer[size] = '\0';
if (gcount() != size)
{
std::cerr << "未能成功读取指定字节数的数据!" << std::endl;
delete[] buffer;
return "";
}
std::string result = buffer;
delete[] buffer;
return result;
}
std::string GetStringNormal(const int size)
{
char *buffer = new char[size + 1];
read(buffer, size);
buffer[size] = '\0';
if (gcount() != size)
{
std::cerr << "未能成功读取指定字节数的数据!" << std::endl;
delete[] buffer;
return "";
}
std::string result(buffer);
delete[] buffer;
return result;
}
private:
};
IO_Ex::~IO_Ex()
{
}

View File

@@ -1,226 +0,0 @@
#pragma once
#include "IO_Ex.hpp"
#include <iostream>
#include <map>
#include <cstdint>
#include "squirrel.h"
#include "sqstdaux.h"
#include "sqstdblob.h"
#include "sqstdio.h"
#include "sqstdmath.h"
#include "sqstdstring.h"
#include "sqstdsystem.h"
class PVF_IO : public IO_Ex
{
struct PvfFileInfo
{
int ROffset;
int Cr32;
int Length;
bool DecodeFlag = false;
};
private:
int StartPos = 0;
std::map<std::string, PvfFileInfo> FileInfo;
std::map<int, std::string> BinStringM;
std::map<std::string, std::map<std::string, std::string>> LoadStringM;
public:
// 构造函数
PVF_IO(const char *defaultFilename = "Script.pvf") : IO_Ex(defaultFilename) {}
// 析构函数在对象销毁时基类fstream的析构函数会自动被调用一般不需要额外特殊处理
~PVF_IO() {}
// 显式删除拷贝构造函数,禁止拷贝操作
PVF_IO(const PVF_IO &) = delete;
// 也可以考虑同时删除拷贝赋值运算符,保持一致的语义,避免误用
PVF_IO &operator=(const PVF_IO &) = delete;
public:
void Init()
{
// 读取头建立树
InitHeader();
// 读取bin文件
InitBin();
// 读取LoadString
InitLoadString();
}
void InitHeader()
{
// 读取UUID的长度
int UUID_LENGTH = GetInt();
// UUID 读 1 - 36位 构造 UTF8 string
std::string UUID = GetString(UUID_LENGTH);
// 版本号
int Version = GetInt();
// 文件路径数据的大小
int AlignedIndexHeaderSize = GetInt();
// 解密密钥
int IndexHeaderCrc = GetInt();
// 文件数量
int IndexSize = GetInt();
// 文件起始位置
int FristPos = tellg();
CrcDecode(AlignedIndexHeaderSize, IndexHeaderCrc);
int CurrPos = 0;
StartPos = AlignedIndexHeaderSize + 56;
// 建立pvf文件索引表
for (size_t i = 0; i < IndexSize; i++)
{
seek(FristPos + CurrPos);
int FileNumber = GetInt();
int FilePathLength = GetInt();
std::string FileName = tolower(GetString(FilePathLength));
int FileLength = GetInt();
int Cre32 = GetInt();
int RelativeOffset = GetInt();
if (FileLength > 0)
{
int RealFileLength = (FileLength + 3) & 4294967292;
PvfFileInfo Info;
Info.ROffset = RelativeOffset;
Info.Cr32 = Cre32;
Info.Length = RealFileLength;
Info.DecodeFlag = false;
FileInfo[FileName] = Info;
}
CurrPos += 20;
CurrPos += FilePathLength;
}
}
void InitBin()
{
if (FileInfo.count("stringtable.bin") == 0)
{
std::cout << "bin文件不存在" << std::endl;
return;
}
PvfFileInfo BinInfo = FileInfo["stringtable.bin"];
seek(StartPos + BinInfo.ROffset);
CrcDecode(BinInfo.Length, BinInfo.Cr32);
seek(StartPos + BinInfo.ROffset);
int FileHPos = tellg();
int Count = GetInt();
int CurrentIndex = 0;
for (int i = 0; i < Count; i++)
{
seek(FileHPos + CurrentIndex * 4 + 4);
int StartPos = GetInt();
int EndPos = GetInt();
int Len = EndPos - StartPos;
seek(FileHPos + StartPos + 4);
std::string Str = GetString(Len);
BinStringM[CurrentIndex] = Str;
CurrentIndex++;
}
}
void InitLoadString()
{
if (FileInfo.count("n_string.lst") == 0)
{
std::cout << "LoadString文件不存在" << std::endl;
return;
}
PvfFileInfo Info = FileInfo["n_string.lst"];
seek(StartPos + Info.ROffset);
CrcDecode(Info.Length, Info.Cr32);
seek(StartPos + Info.ROffset);
int FileHPos = tellg();
int Flag = GetShort();
int i = 2;
while (i < Info.Length)
{
if ((Info.Length - i) >= 10)
{
seek(FileHPos + i + 6);
int FindKey = GetInt();
std::string Key = GetBinString(FindKey);
std::string Type = tolower(Key.substr(0, Key.find("/")));
if (Key.length() > 0)
{
PvfFileInfo *FileInfo = GetFileInfo(Key);
if (FileInfo == nullptr)
continue;
seek(StartPos + FileInfo->ROffset);
CrcDecode(FileInfo->Length, FileInfo->Cr32);
seek(StartPos + FileInfo->ROffset);
std::string Str = GetStringNormal(FileInfo->Length);
std::vector<std::string> StrArr = split(Str, "\n");
for (auto it = StrArr.begin(); it != StrArr.end(); ++it)
{
std::string strobj = *it;
if (strobj.find(">") != std::string::npos)
{
std::vector<std::string> strobjarr = split(strobj, ">");
if (strobjarr.size() > 1)
{
LoadStringM[Type][strobjarr[0]] = strobjarr[1];
}
}
}
}
}
else
break;
i += 10;
}
}
public:
std::string GetBinString(int Key)
{
if (BinStringM.count(Key))
return BinStringM[Key];
return "";
}
std::string GetLoadString(std::string Type, std::string Key)
{
if (LoadStringM.count(Type) && LoadStringM[Type].count(Key))
return LoadStringM[Type][Key];
return "";
}
PvfFileInfo *GetFileInfo(std::string path)
{
path = tolower(path);
if (FileInfo.count(path))
return &FileInfo[path];
return nullptr;
}
void LoadFileToBlob(HSQUIRRELVM v, std::string path, SQUserPointer blobp)
{
path = tolower(path);
if (FileInfo.count(path))
{
seek(StartPos + FileInfo[path].ROffset);
if (FileInfo[path].DecodeFlag == false)
{
CrcDecode(FileInfo[path].Length, FileInfo[path].Cr32);
seek(StartPos + FileInfo[path].ROffset);
FileInfo[path].DecodeFlag = true;
}
read((char *)blobp, FileInfo[path].Length);
return;
}
sq_pushnull(v);
return;
}
};

View File

@@ -1,15 +0,0 @@
#ifndef __SINGLETON_H__RINDRO_
#define __SINGLETON_H__RINDRO_
//饿汉模式
#define RINDRO_SINGLETON_DEFINE_S(TypeName) \
static TypeName *Get() \
{ \
static TypeName type_rindro_instance; \
return &type_rindro_instance; \
} \
\
TypeName(const TypeName &) = delete; \
TypeName &operator=(const TypeName &) = delete
#endif // __SINGLETON_H__

View File

@@ -1,385 +0,0 @@
#pragma once
#include "frida-gum.h"
#include <fcntl.h>
#include <unistd.h>
#include "squirrel.h"
#include "sqstdaux.h"
#include "sqstdblob.h"
#include "sqstdio.h"
#include "sqstdmath.h"
#include "sqstdstring.h"
#include "sqstdsystem.h"
#include <mutex>
#include <iostream>
extern HSQUIRRELVM v;
extern std::recursive_mutex SqMtx;
#define CONTAINS_STRING(str, substr) (str == substr)
typedef struct {
const SQChar* name;
size_t offset;
} CpuContextMember;
// HookFunc
struct _ExampleListener
{
GObject parent;
guint num_calls;
std::vector<std::string> ArgumentCount;
std::string RetType;
HSQOBJECT CallBackOnEnter;
HSQOBJECT CallBackOnLeave;
SQUserPointer FuncAddress;
};
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;
static std::thread::id Zhuxianc = std::this_thread::get_id();
#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 void replacement_function(GumInvocationContext* context)
{
// 在这里执行你的逻辑
// gum_print("自定义逻辑已执行!\n");
// 跳过原函数,直接返回
// 如果需要修改返回值,可以通过 context->cpu_context 修改寄存器
}
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);
// 得到函数地址
SQUserPointer FuncAddress;
sq_getuserpointer(v, 2, &FuncAddress);
// 遍历参数类型数组
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);
ParameterType.push_back(path);
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;
EXAMPLE_LISTENER(listener)->FuncAddress = FuncAddress;
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)
{
gpointer ReturnAddress = gum_invocation_context_get_return_address(ic);
ExampleListener* self = EXAMPLE_LISTENER(listener);
// std::cout << "调用点: " << self->FuncAddress << std::endl;
std::lock_guard<std::recursive_mutex> lock(SqMtx);
// 执行虚拟机Main函数
SQInteger top = sq_gettop(v); // saves the stack size before the call
//传入返回地址
sq_pushroottable(v);
sq_pushstring(v, _SC("_Haker_SetNextReturnAddress"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushuserpointer(v, ReturnAddress);
sq_call(v, 2, SQFalse, SQTrue);
}
sq_settop(v, top);
//传入CPU上下文
sq_pushroottable(v);
sq_pushstring(v, _SC("_Haker_SetCpuContext"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_newtable(v);
struct TableEntry
{
const SQChar* key;
SQUserPointer value;
} entries[] = {
{_SC("eip"), (SQUserPointer)ic->cpu_context->eip},
{_SC("edi"), (SQUserPointer)ic->cpu_context->edi},
{_SC("esi"), (SQUserPointer)ic->cpu_context->esi},
{_SC("ebp"), (SQUserPointer)ic->cpu_context->ebp},
{_SC("esp"), (SQUserPointer)ic->cpu_context->esp},
{_SC("ebx"), (SQUserPointer)ic->cpu_context->ebx},
{_SC("edx"), (SQUserPointer)ic->cpu_context->edx},
{_SC("ecx"), (SQUserPointer)ic->cpu_context->ecx},
{_SC("eax"), (SQUserPointer)ic->cpu_context->eax},
};
for (const auto& entry : entries)
{
sq_pushstring(v, entry.key, -1);
sq_pushuserpointer(v, entry.value);
sq_newslot(v, -3, SQFalse);
}
sq_call(v, 2, SQFalse, SQTrue);
}
sq_settop(v, top);
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"))
sq_pushstring(v, (char*)Abuf, -1);
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
return;
}
sq_settop(v, top); // restores the original stack size
return;
}
static void example_listener_on_leave(GumInvocationListener* listener, GumInvocationContext* ic)
{
ExampleListener* self = EXAMPLE_LISTENER(listener);
std::lock_guard<std::recursive_mutex> lock(SqMtx);
// 执行虚拟机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"))
sq_pushstring(v, (char*)Abuf, -1);
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);
}
}
sq_settop(v, top);
}
static void example_listener_class_init(ExampleListenerClass* klass)
{
(void)EXAMPLE_IS_LISTENER;
(void)glib_autoptr_cleanup_ExampleListener;
}
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)
{
}
static void RegisterActiveHook(HSQUIRRELVM v)
{
register_World_func(v, L_HookFunc, _SC("Sq_HookFunc"));
register_World_func(v, L_DeHookFunc, _SC("Sq_DeHookFunc"));
}

View File

@@ -1,102 +0,0 @@
#pragma once
#include "PVF_IO.hpp"
static SQInteger Asset_LoadScript(HSQUIRRELVM v)
{
// 获得路径
const SQChar *Path;
sq_getstring(v, 2, &Path);
PVF_IO *pvf = new PVF_IO(Path);
pvf->Init();
sq_pushuserpointer(v, pvf);
return 1;
}
static SQInteger Asset_GetPvfFileSize(HSQUIRRELVM v)
{
// 获取PVF指针
SQUserPointer Pvfbuf;
// 获得路径
const SQChar *Path;
sq_getuserpointer(v, 2, &Pvfbuf);
sq_getstring(v, 3, &Path);
PVF_IO *Pvf = (PVF_IO *)Pvfbuf;
auto Info = Pvf->GetFileInfo(Path);
if (Info)
sq_pushinteger(v, Info->Length);
else
sq_pushnull(v);
return 1;
}
static SQInteger Asset_GetPvfFile(HSQUIRRELVM v)
{
// 获取PVF指针
SQUserPointer Pvfbuf, blobp;
// 获得路径
const SQChar *Path;
sq_getuserpointer(v, 2, &Pvfbuf);
sq_getstring(v, 3, &Path);
sqstd_getblob(v, 4, &blobp);
PVF_IO *Pvf = (PVF_IO *)Pvfbuf;
Pvf->LoadFileToBlob(v, Path, blobp);
return 0;
}
static SQInteger Asset_GetPvfBinString(HSQUIRRELVM v)
{
// 获取PVF指针
SQUserPointer Pvfbuf;
// 获得Key
SQInteger Key;
sq_getuserpointer(v, 2, &Pvfbuf);
sq_getinteger(v, 3, &Key);
PVF_IO *Pvf = (PVF_IO *)Pvfbuf;
std::string value = Pvf->GetBinString(Key);
sq_pushstring(v, value.c_str(), value.length());
return 1;
}
static SQInteger Asset_GetPvfLoadString(HSQUIRRELVM v)
{
// 获取PVF指针
SQUserPointer Pvfbuf;
// 获取类型
const SQChar *Type;
// 获得Key
const SQChar *Key;
sq_getuserpointer(v, 2, &Pvfbuf);
sq_getstring(v, 3, &Type);
sq_getstring(v, 4, &Key);
PVF_IO *Pvf = (PVF_IO *)Pvfbuf;
std::string value = Pvf->GetLoadString(Type, Key);
value = value.c_str();
sq_pushstring(v, value.c_str(), value.length());
return 1;
}
void RegisterAssetNutApi(const SQChar *funcName, SQFUNCTION funcAddr, HSQUIRRELVM v)
{
sq_pushroottable(v);
sq_pushstring(v, funcName, -1);
sq_newclosure(v, funcAddr, 0);
sq_newslot(v, -3, false);
sq_poptop(v);
}
void RegisterAsset(HSQUIRRELVM v)
{
RegisterAssetNutApi(_SC("Asset_LoadScript"), Asset_LoadScript, v);
RegisterAssetNutApi(_SC("Asset_GetPvfFileSize"), Asset_GetPvfFileSize, v);
RegisterAssetNutApi(_SC("Asset_GetPvfFile"), Asset_GetPvfFile, v);
RegisterAssetNutApi(_SC("Asset_GetPvfBinString"), Asset_GetPvfBinString, v);
RegisterAssetNutApi(_SC("Asset_GetPvfLoadString"), Asset_GetPvfLoadString, v);
}

View File

@@ -1,52 +0,0 @@
#pragma once
#include "squirrel.h"
#include "sqstdaux.h"
#include "sqstdblob.h"
#include "sqstdio.h"
#include "sqstdmath.h"
#include "sqstdstring.h"
#include "sqstdsystem.h"
#include <iostream>
template <typename R, typename A, typename... ARG>
R CallBattleField(A call_addr, const ARG... arguments)
{
if (!call_addr)
{
return R();
}
const auto control = reinterpret_cast<R (*)(ARG...)>(call_addr);
try
{
return control(arguments...);
}
catch (...)
{
}
return R();
}
// 获取副本对象
static SQInteger BattleField_GetDgn(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQUserPointer B = CallBattleField<void *>(0x80FDCFC, P);
sq_pushuserpointer(v, B);
return 1;
}
static SQInteger register_BattleField_func(HSQUIRRELVM v, SQFUNCTION f, const char *fname)
{
sq_pushroottable(v);
sq_pushstring(v, fname, -1);
sq_newclosure(v, f, 0); // create a new function
sq_newslot(v, -3, SQFalse);
sq_pop(v, 1); // pops the root table
}
static void RegisterBattleField(HSQUIRRELVM v)
{
// 获取副本对象
register_BattleField_func(v, BattleField_GetDgn, _SC("Sq_BattleField_GetDgn"));
}

View File

@@ -1,547 +0,0 @@
#pragma once
#include "squirrel.h"
#include "sqstdaux.h"
#include "sqstdblob.h"
#include "sqstdio.h"
#include "sqstdmath.h"
#include "sqstdstring.h"
#include "sqstdsystem.h"
#include <asio.hpp>
#include <asio/ssl.hpp>
#include <asio/basic_socket_streambuf.hpp>
#include <iostream>
#include <thread>
#include <atomic>
#include <unordered_map>
#include <mutex>
#include <memory> // 新增:用于 std::unique_ptr
#include <string>
#include <sstream>
#include <algorithm>
#include <cctype>
#include <stdint.h>
// 全局变量声明需在cpp文件中定义
extern HSQUIRRELVM v;
extern std::recursive_mutex SqMtx;
using tcp = asio::ip::tcp;
// ====================== 工具函数 ======================
// 字符串转小写
std::string to_lower(std::string s) {
std::transform(s.begin(), s.end(), s.begin(),
[](unsigned char c) { return std::tolower(c); });
return s;
}
// 修剪字符串两端空格
std::string trim(std::string s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(),
[](unsigned char c) { return !std::isspace(c); }));
s.erase(std::find_if(s.rbegin(), s.rend(),
[](unsigned char c) { return !std::isspace(c); }).base(), s.end());
return s;
}
// 解析 URL分离路径和查询参数
void parse_url(const std::string& url, std::string& path, std::string& query) {
size_t query_pos = url.find('?');
if (query_pos == std::string::npos) {
path = url;
query = "";
}
else {
path = url.substr(0, query_pos);
query = url.substr(query_pos + 1);
}
}
// ====================== HTTP 头解析结构体 ======================
struct HttpRequestHeader {
std::string method; // GET/POST/PUT/DELETE 等
std::string path; // 请求路径(如 /api/test
std::string version; // HTTP/1.1 / HTTP/1.0
std::string query_string; // URL 查询参数(如 ?id=1&name=test
// 头部键值对(统一转小写,避免大小写问题)
std::unordered_map<std::string, std::string> headers;
// 便捷获取头部值(兼容大小写)
std::string get_header(const std::string& key) const {
std::string lower_key = to_lower(key);
auto it = headers.find(lower_key);
return it != headers.end() ? it->second : "";
}
};
// ====================== HTTP 头解析函数 ======================
HttpRequestHeader parse_http_header(const std::string& raw_header) {
HttpRequestHeader result;
std::istringstream iss(raw_header);
std::string line;
bool first_line_parsed = false;
// 第一步:解析请求首行(仅解析第一行,避免重复)
while (std::getline(iss, line)) {
// 移除行尾的 \r
if (!line.empty() && line.back() == '\r') {
line.pop_back();
}
line = trim(line);
// 跳过空行
if (line.empty()) {
continue;
}
// 仅解析第一个非空行作为请求首行
if (!first_line_parsed) {
std::string url;
std::istringstream line_iss(line);
line_iss >> result.method >> url >> result.version;
parse_url(url, result.path, result.query_string);
std::transform(result.method.begin(), result.method.end(), result.method.begin(),
[](unsigned char c) { return std::toupper(c); });
first_line_parsed = true;
continue;
}
// 解析头部键值对
size_t colon_pos = line.find(':');
if (colon_pos == std::string::npos) {
continue;
}
std::string key = trim(line.substr(0, colon_pos));
std::string value = trim(line.substr(colon_pos + 1));
result.headers[to_lower(key)] = value;
}
return result;
}
// ====================== 读取完整原始请求 ======================
std::string read_full_raw_request(tcp::socket& socket, HttpRequestHeader& header_out) {
asio::streambuf buf;
std::string full_request;
asio::error_code ec;
try {
// 第一步:读取头部(直到 \r\n\r\n
size_t header_bytes = asio::read_until(socket, buf, "\r\n\r\n", ec);
if (ec) {
throw asio::system_error(ec);
}
// 提取头部内容
std::string header_str(asio::buffer_cast<const char*>(buf.data()), header_bytes);
full_request = header_str;
// 安全清理头部末尾的 \r\n\r\n核心修复先判断是否找到
size_t end_header_pos = header_str.find("\r\n\r\n"); // 用 find 而非 find_last_of精准匹配结束符
if (end_header_pos != std::string::npos) {
// 只保留头部内容,截断后面的空行
header_str = header_str.substr(0, end_header_pos);
}
// 解析头部
header_out = parse_http_header(header_str);
// 第二步:读取请求体(严格按 Content-Length 读取)
size_t content_len = 0;
std::string cl_str = header_out.get_header("Content-Length");
if (!cl_str.empty()) {
try {
content_len = std::stoul(cl_str);
}
catch (...) {
content_len = 0;
}
}
// 清空缓冲区中已读取的头部数据
buf.consume(header_bytes);
// 读取请求体(防越界)
if (content_len > 0) {
// 先检查剩余缓冲区是否足够,避免读取超限
size_t buf_available = buf.size();
if (buf_available < content_len) {
// 读取剩余需要的字节
asio::read(socket, buf, asio::transfer_exactly(content_len - buf_available), ec);
if (ec && ec != asio::error::eof) {
throw asio::system_error(ec);
}
}
// 提取请求体(防缓冲区数据不足)
size_t actual_read = std::min(buf.size(), content_len);
std::string body_str(asio::buffer_cast<const char*>(buf.data()), actual_read);
full_request += body_str;
// 清理缓冲区
buf.consume(actual_read);
}
}
catch (...) {
throw;
}
return full_request;
}
// ====================== 将 HttpRequestHeader 转为 Squirrel Table ======================
void push_http_header_to_squirrel(HSQUIRRELVM v, const HttpRequestHeader& header) {
// 1. 创建空 Table
sq_newtable(v);
// 2. 设置基础字段method/path/version/query_string
// method
sq_pushstring(v, _SC("method"), -1);
sq_pushstring(v, header.method.c_str(), -1);
sq_rawset(v, -3);
// path
sq_pushstring(v, _SC("path"), -1);
sq_pushstring(v, header.path.c_str(), -1);
sq_rawset(v, -3);
// version
sq_pushstring(v, _SC("version"), -1);
sq_pushstring(v, header.version.c_str(), -1);
sq_rawset(v, -3);
// query_string
sq_pushstring(v, _SC("query_string"), -1);
sq_pushstring(v, header.query_string.c_str(), -1);
sq_rawset(v, -3);
// 3. 创建 headers 子 Table
sq_pushstring(v, _SC("headers"), -1);
sq_newtable(v);
// 遍历头部键值对,写入子 Table
for (const auto& pair : header.headers) {
sq_pushstring(v, pair.first.c_str(), -1); // 键(小写)
sq_pushstring(v, pair.second.c_str(), -1); // 值
sq_rawset(v, -3);
}
// 将 headers 子 Table 写入主 Table
sq_rawset(v, -3);
}
// ====================== 处理客户端请求 ======================
void handle_client(tcp::socket* socket, HSQOBJECT HttpServerObject) {
if (!socket || !socket->is_open()) {
std::cerr << "无效的 socket 连接" << std::endl;
return;
}
try {
// 读取完整请求并解析头部
HttpRequestHeader header;
std::string full_request = read_full_raw_request(*socket, header);
// 加锁操作 Squirrel VMlock_guard 自动管理锁生命周期)
std::lock_guard<std::recursive_mutex> lock(SqMtx);
// 执行 Squirrel 的 Event 函数
SQInteger top = sq_gettop(v); // 保存栈状态
sq_pushobject(v, HttpServerObject);
sq_pushstring(v, _SC("Event"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2))) {
// 压入函数参数:
// 参数1HttpServerObjectthis
sq_pushobject(v, HttpServerObject);
// 参数2socket 指针userpointer
sq_pushuserpointer(v, socket);
// 参数3解析后的 header table
push_http_header_to_squirrel(v, header);
// 参数4完整原始请求字符串
size_t body_start_pos = full_request.find("\r\n\r\n");
std::string request_body = (body_start_pos != std::string::npos) ? full_request.substr(body_start_pos + 4) : "";
sq_pushstring(v, request_body.c_str(), request_body.size());
// 调用函数:参数数量=4无返回值开启错误捕获
sq_call(v, 4, SQFalse, SQTrue);
}
sq_settop(v, top); // 恢复栈状态
}
catch (const asio::system_error& e) {
std::cerr << "网络错误: " << e.what() << " (错误码: " << e.code() << ")" << std::endl;
}
catch (const std::exception& e) {
std::cerr << "处理请求错误: " << e.what() << std::endl;
}
catch (...) {
std::cerr << "未知错误" << std::endl;
}
}
// ====================== 服务器上下文(支持多实例) ======================
struct HttpServerCtx {
uint64_t server_id; // 唯一服务器ID多实例核心
std::atomic<bool> running{ true }; // 退出标志atomic不可拷贝
HSQUIRRELVM vm; // Squirrel VM
HSQOBJECT http_server_obj; // 保存的对象
asio::io_context* io_context = nullptr; // IO上下文用于停止
std::string host; // 记录主机(调试用)
std::string port; // 记录端口(调试用)
// 禁用拷贝构造和赋值(显式声明,避免误拷贝)
HttpServerCtx(const HttpServerCtx&) = delete;
HttpServerCtx& operator=(const HttpServerCtx&) = delete;
// 允许移动构造用于unique_ptr
HttpServerCtx(HttpServerCtx&&) = default;
HttpServerCtx& operator=(HttpServerCtx&&) = default;
// 构造函数
HttpServerCtx() = default;
HttpServerCtx(uint64_t id, HSQUIRRELVM vm_ptr, HSQOBJECT obj, const std::string& h, const std::string& p)
: server_id(id), vm(vm_ptr), http_server_obj(obj), host(h), port(p) {
}
};
// ====================== 全局服务器管理核心修复用unique_ptr存储避免拷贝 ======================
static std::unordered_map<uint64_t, std::unique_ptr<HttpServerCtx>> g_server_ctxs;
static std::atomic<uint64_t> g_next_server_id{ 1 }; // 自增唯一IDatomic不可拷贝直接用
static std::mutex g_server_mutex; // 保护全局容器
// ====================== 服务器主函数 ======================
void start_server(uint64_t server_id, const std::string& host, const std::string& port) {
// 查找上下文(加锁)
std::unique_lock<std::mutex> lock(g_server_mutex);
auto it = g_server_ctxs.find(server_id);
if (it == g_server_ctxs.end()) {
std::cerr << "服务器上下文不存在 (ID: " << server_id << ")" << std::endl;
return;
}
HttpServerCtx* ctx = it->second.get(); // 获取指针,不拷贝
lock.unlock(); // 手动解锁
asio::io_context io_context;
ctx->io_context = &io_context; // 关联IO上下文
try {
tcp::acceptor acceptor(io_context, tcp::endpoint(asio::ip::make_address(host), std::stoi(port)));
std::cout << "Server [" << server_id << "] listening on " << host << ":" << port << std::endl;
// 循环监听(支持退出)
while (ctx->running.load(std::memory_order_relaxed)) { // 原子操作读取
tcp::socket* socket = new tcp::socket(io_context);
try {
acceptor.accept(*socket);
// 启动客户端处理线程
std::thread(handle_client, std::move(socket), ctx->http_server_obj).detach();
}
catch (const asio::system_error& e) {
delete socket; // 中断时释放Socket
if (e.code() != asio::error::operation_aborted && ctx->running.load(std::memory_order_relaxed)) {
std::cerr << "Server [" << server_id << "] Accept error: " << e.what() << std::endl;
}
}
}
}
catch (const std::exception& e) {
std::cerr << "Server [" << server_id << "] error: " << e.what() << std::endl;
}
// 停止IO上下文
io_context.stop();
std::cout << "Server [" << server_id << "] stopped" << std::endl;
}
// ====================== Squirrel 绑定函数 - 创建HTTP客户端 ======================
static SQInteger CreateHttp(HSQUIRRELVM v) {
const SQChar* Host;
sq_getstring(v, 2, &Host);
const SQChar* Service;
sq_getstring(v, 3, &Service);
const SQChar* Content;
sq_getstring(v, 4, &Content);
try {
asio::io_context ioContext;
asio::ip::tcp::resolver resolver(ioContext);
auto endpoints = resolver.resolve(Host, Service);
asio::ip::tcp::socket socket(ioContext);
asio::connect(socket, endpoints);
// 发送HTTP请求
std::string request = Content;
asio::write(socket, asio::buffer(request));
// 读取响应
asio::streambuf response;
asio::error_code error;
while (asio::read(socket, response, asio::transfer_at_least(1), error)) {}
if (error && error != asio::error::eof) {
throw asio::system_error(error);
}
// 将响应内容返回
std::istream responseStream(&response);
std::ostringstream oss;
oss << responseStream.rdbuf();
sq_pushstring(v, oss.str().c_str(), -1);
return 1;
}
catch (const std::exception& e) {
return sq_throwerror(v, e.what());
}
catch (...) {
return sq_throwerror(v, _SC("Unknown error occurred"));
}
}
// ====================== Squirrel 绑定函数 - 创建HTTP服务器核心修复避免拷贝atomic ======================
static SQInteger CreateHttpServer(HSQUIRRELVM v) {
const SQChar* host = nullptr;
const SQChar* port = nullptr;
HSQOBJECT HttpServerObject;
// 1. 参数校验
if (SQ_FAILED(sq_getstring(v, 2, &host)) ||
SQ_FAILED(sq_getstring(v, 3, &port)) ||
SQ_FAILED(sq_getstackobj(v, 4, &HttpServerObject))) {
sq_pushstring(v, _SC("param error: need (host:str, port:str, obj:HSQOBJECT)"), -1);
return SQ_ERROR;
}
// 2. 生成唯一服务器ID
uint64_t server_id = g_next_server_id.fetch_add(1, std::memory_order_relaxed);
try {
// 3. 动态创建上下文(避免拷贝)
auto ctx_ptr = std::unique_ptr<HttpServerCtx>(new HttpServerCtx(server_id, v, HttpServerObject, std::string(host), std::string(port)));
sq_addref(v, &ctx_ptr->http_server_obj); // 增加引用
// 4. 加锁存入全局(移动语义,不拷贝)
std::lock_guard<std::mutex> lock(g_server_mutex);
g_server_ctxs[server_id] = std::move(ctx_ptr); // 移动unique_ptr不拷贝atomic
// 5. 启动服务器线程
std::thread server_thread(start_server, server_id, std::string(host), std::string(port));
server_thread.detach();
// 6. 返回唯一ID给Squirrel
sq_pushinteger(v, static_cast<SQInteger>(server_id));
return 1;
}
catch (...) {
// 异常清理
sq_release(v, &HttpServerObject); // 直接释放传入的对象
std::lock_guard<std::mutex> lock(g_server_mutex);
g_server_ctxs.erase(server_id);
sq_pushbool(v, false);
return 1;
}
}
// ====================== Squirrel 绑定函数 - 停止HTTP服务器 ======================
static SQInteger StopHttpServer(HSQUIRRELVM v) {
SQInteger server_id_int;
if (SQ_FAILED(sq_getinteger(v, 2, &server_id_int)) || server_id_int <= 0) {
sq_pushstring(v, _SC("invalid server ID"), -1);
return SQ_ERROR;
}
uint64_t server_id = static_cast<uint64_t>(server_id_int);
std::lock_guard<std::mutex> lock(g_server_mutex);
auto it = g_server_ctxs.find(server_id);
if (it == g_server_ctxs.end()) {
// 修正:拼接错误信息中的 server ID
std::string err_msg = "server instance not found (ID: " + std::to_string(server_id) + ")";
sq_pushstring(v, err_msg.c_str(), -1);
return SQ_ERROR;
}
HttpServerCtx* ctx = it->second.get();
// 1. 标记停止(原子操作)
ctx->running.store(false, std::memory_order_relaxed);
// 2. 强制停止 IO 上下文(中断所有异步操作)
if (ctx->io_context) {
ctx->io_context->stop();
}
// 3. 释放 Squirrel 引用
sq_release(ctx->vm, &ctx->http_server_obj);
// 4. 移除上下文unique_ptr 自动析构)
g_server_ctxs.erase(it);
sq_pushbool(v, true);
return 1;
}
// ====================== Squirrel 绑定函数 - 发送HTTP响应 ======================
static SQInteger HttpServerResponse_Write(HSQUIRRELVM v) {
SQUserPointer P;
if (SQ_FAILED(sq_getuserpointer(v, 2, &P))) {
return sq_throwerror(v, _SC("invalid socket pointer"));
}
tcp::socket* socket = static_cast<tcp::socket*>(P);
const SQChar* Content;
if (SQ_FAILED(sq_getstring(v, 3, &Content))) {
return sq_throwerror(v, _SC("invalid response content"));
}
try {
if (socket && socket->is_open()) {
std::string response = Content;
asio::write(*socket, asio::buffer(response));
}
}
catch (const std::exception& e) {
// 清理资源
if (socket) {
asio::error_code ec;
socket->close(ec);
delete socket;
}
return sq_throwerror(v, e.what());
}
catch (...) {
if (socket) {
asio::error_code ec;
socket->close(ec);
delete socket;
}
return sq_throwerror(v, _SC("Unknown error occurred"));
}
// 最后清理socket
if (socket) {
asio::error_code ec;
socket->close(ec);
delete socket;
}
return 0;
}
// ====================== 辅助函数 - 注册Squirrel函数 ======================
static SQInteger register_Dio_func(HSQUIRRELVM v, SQFUNCTION f, const char* fname) {
sq_pushroottable(v);
sq_pushstring(v, fname, -1);
sq_newclosure(v, f, 0);
sq_newslot(v, -3, SQFalse);
sq_pop(v, 1); // 弹出根表
return 0;
}
// ====================== 注册所有Dio函数 ======================
static void RegisterDio(HSQUIRRELVM v) {
// 创建HTTP客户端
register_Dio_func(v, CreateHttp, _SC("Sq_CreateHttp"));
// HTTP服务器相关
register_Dio_func(v, CreateHttpServer, _SC("Sq_CreateHttpServer"));
register_Dio_func(v, StopHttpServer, _SC("Sq_StopHttpServer"));
// 发送HTTP响应
register_Dio_func(v, HttpServerResponse_Write, _SC("Sq_HttpServerResponse_Write"));
}

View File

@@ -1,52 +0,0 @@
#pragma once
#include "squirrel.h"
#include "sqstdaux.h"
#include "sqstdblob.h"
#include "sqstdio.h"
#include "sqstdmath.h"
#include "sqstdstring.h"
#include "sqstdsystem.h"
#include <iostream>
template <typename R, typename A, typename... ARG>
R CallDungeon(A call_addr, const ARG... arguments)
{
if (!call_addr)
{
return R();
}
const auto control = reinterpret_cast<R (*)(ARG...)>(call_addr);
try
{
return control(arguments...);
}
catch (...)
{
}
return R();
}
// 获取副本编号
static SQInteger Dungeon_GetIdex(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Idx = CallDungeon<int>(0x80FDCF0, P);
sq_pushinteger(v, Idx);
return 1;
}
static SQInteger register_Dungeon_func(HSQUIRRELVM v, SQFUNCTION f, const char *fname)
{
sq_pushroottable(v);
sq_pushstring(v, fname, -1);
sq_newclosure(v, f, 0); // create a new function
sq_newslot(v, -3, SQFalse);
sq_pop(v, 1); // pops the root table
}
static void RegisterDungeon(HSQUIRRELVM v)
{
// 获取编号
register_Dungeon_func(v, Dungeon_GetIdex, _SC("Sq_Dungeon_GetIdex"));
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,163 +0,0 @@
#pragma once
#include "squirrel.h"
#include "sqstdaux.h"
#include "sqstdblob.h"
#include "sqstdio.h"
#include "sqstdmath.h"
#include "sqstdstring.h"
#include "sqstdsystem.h"
#include <iostream>
#include "frida-gum.h"
typedef void *(*__GetGameManagerVoid)();
static SQInteger GameManager_GameManager(HSQUIRRELVM v)
{
void *GameManager = ((__GetGameManagerVoid)0x080CC18E)();
sq_pushuserpointer(v, GameManager);
return 1;
}
typedef void *(*__GameManagerByThis)(void *GameManager);
static SQInteger GameManager_GetParty(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
void *CParty = ((__GameManagerByThis)0x08294E10)(P);
if (CParty)
sq_pushuserpointer(v, CParty);
else
sq_pushinteger(v, 0);
return 1;
}
typedef int (*cdeclCall2P)(int *a1, int a2);
static cdeclCall2P SkillSlot__get_skillslot_buf = (cdeclCall2P)0x086067DE;
static cdeclCall2P SkillSlot__gcheckComboSkillInsertQuickSlot = (cdeclCall2P)0x08608D58;
#define RDWORD(addr, offset) (*(DWORD *)((char *)(addr) + (offset)))
int __attribute__((cdecl)) hookCSkill__reform_ui_group_no(int *thisP, int *skillClassP, bool isTpSkill, int a4)
{
int p = (int)skillClassP;
if (RDWORD(skillClassP, -0x60) == 197)
{
// cout << " fix skill197 class to 4!" << endl;
*skillClassP = 4;
}
return 0;
}
int __attribute__((cdecl)) hookSkillSlot__get_skillslot_group(int *thisP, int slot)
{
// DWORD retAddr = (DWORD)gum_invocation_context_get_return_address(NULL);
// cout<< retAddr << " get_skillslot_group:" << slot << endl;
if (slot < 8 || slot >= 198)
return -1;
else if (slot >= 160)
return 4;
else if (slot >= 122)
return 3;
else if (slot >= 84)
return 2;
else if (slot >= 46)
return 1;
else
return 0;
}
int __attribute__((cdecl)) hookSkillSlot__get_skillslot_no(int *thisP, int skillId, int group, int slot, char is_active_skill)
{
if (!thisP || !*thisP)
return -1;
BYTE *buf = (BYTE *)SkillSlot__get_skillslot_buf(thisP, slot);
if (!buf)
return -1;
if (is_active_skill && SkillSlot__gcheckComboSkillInsertQuickSlot(thisP, skillId))
{
int end = skillId ? 7 : 5;
for (int i = 0; i <= end; ++i)
{
if (buf[2 * i] == skillId)
{
return i;
}
}
for (int i = 198; i <= 203; ++i)
{
if (buf[2 * i] == skillId)
{
return i;
}
}
}
int pos = 8 + group * 38;
for (int i = 0; i < 38; ++i)
{
if (buf[2 * (i + pos)] == skillId)
{
return i + pos;
}
}
return -1;
}
int __attribute__((cdecl)) hookSkillSlot__get_skillslot_no2(int *thisP, BYTE *buf, int skillId, int group, char is_active_skill)
{
if (!thisP || !*thisP || !buf)
return -1;
if (is_active_skill)
{
int end = skillId ? 7 : 5;
for (int i = 0; i <= end; ++i)
{
if (buf[2 * i] == skillId)
{
return i;
}
}
for (int i = 198; i <= 203; ++i)
{
if (buf[2 * i] == skillId)
{
return i;
}
}
}
int pos = 8 + group * 38;
for (int i = 0; i < 38; ++i)
{
if (buf[2 * (i + pos)] == skillId)
{
return i + pos;
}
}
return -1;
}
static SQInteger GameManager_FixA4Skill(HSQUIRRELVM vm)
{
GumInterceptor *v = gum_interceptor_obtain();
gum_interceptor_begin_transaction(v);
gum_interceptor_replace_fast(v, (gpointer)0x083507E8, (gpointer)hookCSkill__reform_ui_group_no, NULL);
gum_interceptor_replace_fast(v, (gpointer)0x086049FC, (gpointer)hookSkillSlot__get_skillslot_group, NULL);
gum_interceptor_replace_fast(v, (gpointer)0x08604A86, (gpointer)hookSkillSlot__get_skillslot_no, NULL);
gum_interceptor_replace_fast(v, (gpointer)0x08607DBA, (gpointer)hookSkillSlot__get_skillslot_no2, NULL);
gum_interceptor_end_transaction(v);
return 0;
}
static SQInteger register_GameManager_func(HSQUIRRELVM v, SQFUNCTION f, const char *fname)
{
sq_pushroottable(v);
sq_pushstring(v, fname, -1);
sq_newclosure(v, f, 0); // create a new function
sq_newslot(v, -3, SQFalse);
sq_pop(v, 1); // pops the root table
}
static void RegisterGameManager(HSQUIRRELVM v)
{
// 获得GameManager对象
register_GameManager_func(v, GameManager_GameManager, _SC("Sq_GameManager_GameManager"));
// 获得队伍对象
register_GameManager_func(v, GameManager_GetParty, _SC("Sq_GameManager_GetParty"));
// 修复A4技能
register_GameManager_func(v, GameManager_FixA4Skill, _SC("Sq_FixA4Skill"));
}

View File

@@ -1,114 +0,0 @@
#pragma once
#include "squirrel.h"
#include "sqstdaux.h"
#include "sqstdblob.h"
#include "sqstdio.h"
#include "sqstdmath.h"
#include "sqstdstring.h"
#include "sqstdsystem.h"
#include <iostream>
template <typename R, typename A, typename... ARG>
R CallInven(A call_addr, const ARG... arguments)
{
if (!call_addr)
{
return R();
}
const auto control = reinterpret_cast<R (*)(ARG...)>(call_addr);
try
{
return control(arguments...);
}
catch (...)
{
}
return R();
}
// 获取背包
static SQInteger Inven_GetInven(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
void *InvenP = CallInven<void *>(0x80DA28E, P);
sq_pushuserpointer(v, InvenP);
return 1;
}
// 获取背包中的项目
static SQInteger Inven_GetItem(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Type, Slot;
sq_getinteger(v, 3, &Type);
sq_getinteger(v, 4, &Slot);
void *ItemP = CallInven<void *>(0x84FC1DE, P, Type, Slot);
sq_pushuserpointer(v, ItemP);
return 1;
}
// 删除背包中的项目
static SQInteger Inven_RemoveItem(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
CallInven<void *>(0x080CB7D8, P);
return 0;
}
// 删除背包中的指定数量的项目
static SQInteger Inven_RemoveItemFormCount(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Type, Slot, Count, Ps, Log;
sq_getinteger(v, 3, &Type);
sq_getinteger(v, 4, &Slot);
sq_getinteger(v, 5, &Count);
sq_getinteger(v, 6, &Ps);
sq_getinteger(v, 7, &Log);
SQInteger Ret = CallInven<int>(0x850400C, P, Type, Slot, Count, Ps, Log);
sq_pushinteger(v, Ret);
return 1;
}
// 根据Id获取背包中的物品槽位
static SQInteger Inven_GetItemById(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Idx;
sq_getinteger(v, 3, &Idx);
SQInteger Slot = CallInven<int>(0x08505172, P, Idx);
sq_pushinteger(v, Slot);
return 1;
}
static SQInteger register_Inven_func(HSQUIRRELVM v, SQFUNCTION f, const char *fname)
{
sq_pushroottable(v);
sq_pushstring(v, fname, -1);
sq_newclosure(v, f, 0); // create a new function
sq_newslot(v, -3, SQFalse);
sq_pop(v, 1); // pops the root table
}
static void RegisterInven(HSQUIRRELVM v)
{
// 获取背包
register_Inven_func(v, Inven_GetInven, "Sq_Inven_GetInven");
// 获取背包中的道具
register_Inven_func(v, Inven_GetItem, "Sq_Inven_GetItem");
// 删除背包中的项目
register_Inven_func(v, Inven_RemoveItem, "Sq_Inven_RemoveItem");
// 根据Id获取背包中的物品槽位
register_Inven_func(v, Inven_RemoveItemFormCount, "Sq_Inven_RemoveItemFormCount");
// 根据Id获取背包中的物品槽位
register_Inven_func(v, Inven_GetItemById, "Sq_Inven_GetItemById");
}

View File

@@ -1,209 +0,0 @@
#pragma once
#include "squirrel.h"
#include "sqstdaux.h"
#include "sqstdblob.h"
#include "sqstdio.h"
#include "sqstdmath.h"
#include "sqstdstring.h"
#include "sqstdsystem.h"
#include "CConnectPool.h"
#include "inline_hook.h"
#include <iostream>
#include <functional>
#include <list>
#include <ffi.h>
#include <keystone/keystone.h>
static SQInteger _file_releasehook(SQUserPointer p, SQInteger SQ_UNUSED_ARG(size))
{
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 PointerOperation(HSQUIRRELVM v)
{
SQUserPointer Address;
sq_getuserpointer(v, 2, &Address);
SQInteger Offset;
sq_getinteger(v, 3, &Offset);
const SQChar* TypecharBuf;
sq_getstring(v, 4, &TypecharBuf);
std::string Type(TypecharBuf);
if (Type == "+")
{
sq_pushuserpointer(v, (void*)(Address + Offset));
}
else if (Type == "-")
{
sq_pushuserpointer(v, (void*)(Address - Offset));
}
return 1;
}
static SQInteger PointerOperationPointer(HSQUIRRELVM v)
{
SQUserPointer Address;
sq_getuserpointer(v, 2, &Address);
SQUserPointer Address2;
sq_getuserpointer(v, 3, &Address2);
const SQChar* TypecharBuf;
sq_getstring(v, 4, &TypecharBuf);
std::string Type(TypecharBuf);
if (Type == "+")
{
sq_pushuserpointer(v, (void*)((int)Address + (int)Address2));
}
else if (Type == "-")
{
sq_pushuserpointer(v, (void*)((int)Address - (int)Address2));
}
return 1;
}
// 写字节数组
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);
CMem::WriteUChar((Address + Idx), Buf);
// 这里-1是值-2是键
sq_pop(v, 2); // 在下一次迭代之前弹出键和值
Idx++;
}
sq_pop(v, 1);
return 0;
}
static SQInteger Memory_WriteBlob(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQUserPointer blob_data;
SQInteger blob_len = sqstd_getblobsize(v, 3);
sqstd_getblob(v, 3, &blob_data);
CMem::WriteBytes(P, blob_data, blob_len);
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);
sq_pushstring(v, (char*)(Address), Length);
}
else
{
sq_pushstring(v, (char*)(Address), -1);
}
return 1;
}
// 将汇编代码字符串转为字节码
static SQInteger Asmjit_Compile(HSQUIRRELVM v)
{
const SQChar* CharBuf;
sq_getstring(v, 2, &CharBuf);
std::string AsmCode(CharBuf);
SQUserPointer Address = 0;
if (sq_gettop(v) == 3)
{
sq_getuserpointer(v, 3, &Address);
}
ks_engine* ks;
ks_err err;
size_t count;
unsigned char* encode;
size_t size;
// 打开Keystone引擎使用x86-64架构和Intel语法
if (ks_open(KS_ARCH_X86, KS_MODE_32, &ks) != KS_ERR_OK)
{
// fprintf(stderr, "Failed to open Keystone\n");
return -1;
}
// 可选设置语法为Intel默认已经是Intel可省略
ks_option(ks, KS_OPT_SYNTAX, KS_OPT_SYNTAX_INTEL);
// 汇编指令
if (ks_asm(ks, AsmCode.c_str(), (uint64_t)Address, &encode, &size, &count) != KS_ERR_OK)
{
// fprintf(stderr, "Assembly error: %s\n", ks_strerror(ks_errno(ks)));
ks_close(ks);
return -1;
}
// 创建Squirrel数组
sq_newarray(v, 0);
// 将每个字节压入数组
for (size_t i = 0; i < size; ++i)
{
sq_pushinteger(v, encode[i]); // 压入字节值
sq_arrayappend(v, -2); // 添加到数组(-2是数组位置
}
// 释放资源
ks_free(encode);
ks_close(ks);
return 1; // 返回1表示有返回值
}
static SQInteger register_Memory_func(HSQUIRRELVM v, SQFUNCTION f, const char* fname)
{
sq_pushroottable(v);
sq_pushstring(v, fname, -1);
sq_newclosure(v, f, 0); // create a new function
sq_newslot(v, -3, SQFalse);
sq_pop(v, 1); // pops the root table
}
static void RegisterMemory(HSQUIRRELVM v)
{
// 析构函数
register_Memory_func(v, Register_Destruction, "Register_Destruction");
// 运算
register_Memory_func(v, PointerOperation, "Sq_PointerOperation");
register_Memory_func(v, PointerOperationPointer, "Sq_PointerOperationPointer");
// 写字节
register_Memory_func(v, Memory_WriteByteArr, "Sq_Memory_WriteByteArr");
// 读字符串
register_Memory_func(v, Memory_ReadString, "Sq_Memory_ReadString");
// 将汇编代码字符串转为字节码
register_Memory_func(v, Asmjit_Compile, "Sq_Asmjit_Compile");
// 写
register_Memory_func(v, Memory_WriteBlob, "Sq_Memory_WriteBlob");
}

View File

@@ -1,139 +0,0 @@
#pragma once
#include "squirrel.h"
#include "sqstdaux.h"
#include "sqstdblob.h"
#include "sqstdio.h"
#include "sqstdmath.h"
#include "sqstdstring.h"
#include "sqstdsystem.h"
#include "import.h"
#include "inline_hook.h"
#include "Singleton.h"
#include "./sdk/sdk_class.h"
#include "utils.h"
#include "GameDataManager.h"
#include "PacketBuf.h"
#include "User.h"
#include <iostream>
static SQInteger Packet_New(HSQUIRRELVM v)
{
InterfacePacketBuf *Pck = (InterfacePacketBuf *)PacketGuard::NewPacketGuard();
sq_pushuserpointer(v, Pck);
return 1;
}
static SQInteger Packet_Put_header(HSQUIRRELVM v)
{
SQUserPointer Buf;
sq_getuserpointer(v, 2, &Buf);
InterfacePacketBuf *Pck = (InterfacePacketBuf *)Buf;
SQInteger Header1;
sq_getinteger(v, 3, &Header1);
SQInteger Header2;
sq_getinteger(v, 4, &Header2);
Pck->put_header(Header1, Header2);
return 0;
}
static SQInteger Packet_Put_byte(HSQUIRRELVM v)
{
SQUserPointer Buf;
sq_getuserpointer(v, 2, &Buf);
InterfacePacketBuf *Pck = (InterfacePacketBuf *)Buf;
SQInteger Byte;
sq_getinteger(v, 3, &Byte);
Pck->put_byte(Byte);
return 0;
}
static SQInteger Packet_Put_short(HSQUIRRELVM v)
{
SQUserPointer Buf;
sq_getuserpointer(v, 2, &Buf);
InterfacePacketBuf *Pck = (InterfacePacketBuf *)Buf;
SQInteger Short;
sq_getinteger(v, 3, &Short);
Pck->put_short(Short);
return 0;
}
static SQInteger Packet_Put_int(HSQUIRRELVM v)
{
SQUserPointer Buf;
sq_getuserpointer(v, 2, &Buf);
InterfacePacketBuf *Pck = (InterfacePacketBuf *)Buf;
SQInteger Int;
sq_getinteger(v, 3, &Int);
Pck->put_int(Int);
return 0;
}
static SQInteger Packet_Put_binary(HSQUIRRELVM v)
{
SQUserPointer Buf;
sq_getuserpointer(v, 2, &Buf);
InterfacePacketBuf *Pck = (InterfacePacketBuf *)Buf;
const SQChar *Str;
sq_getstring(v, 3, &Str);
Pck->put_str((char *)Str, strlen(Str));
return 0;
}
static SQInteger Packet_Put_binaryex(HSQUIRRELVM v)
{
SQUserPointer Buf;
sq_getuserpointer(v, 2, &Buf);
InterfacePacketBuf *Pck = (InterfacePacketBuf *)Buf;
SQUserPointer Str;
sq_getuserpointer(v, 3, &Str);
SQInteger Len;
sq_getinteger(v, 4, &Len);
Pck->put_binary((char *)Str, Len);
return 0;
}
static SQInteger Packet_Finalize(HSQUIRRELVM v)
{
SQUserPointer Buf;
sq_getuserpointer(v, 2, &Buf);
InterfacePacketBuf *Pck = (InterfacePacketBuf *)Buf;
SQBool B;
sq_getbool(v, 3, &B);
Pck->finalize(B);
return 0;
}
static SQInteger Packet_Send(HSQUIRRELVM v)
{
SQUserPointer userbuf;
sq_getuserpointer(v, 2, &userbuf);
CUser *user = (CUser *)userbuf;
SQUserPointer Buf;
sq_getuserpointer(v, 3, &Buf);
user->Send((PacketGuard *)Buf);
return 0;
}
static SQInteger Packet_Delete(HSQUIRRELVM v)
{
SQUserPointer Buf;
sq_getuserpointer(v, 2, &Buf);
InterfacePacketBuf *Pck = (InterfacePacketBuf *)Buf;
InterfacePacketBuf::DelPacketBuf(Pck);
return 0;
}
static SQInteger register_Packet_func(HSQUIRRELVM v, SQFUNCTION f, const char *fname)
{
sq_pushroottable(v);
sq_pushstring(v, fname, -1);
sq_newclosure(v, f, 0); // create a new function
sq_newslot(v, -3, SQFalse);
sq_pop(v, 1); // pops the root table
}
static void RegisterPacket(HSQUIRRELVM v)
{
register_Packet_func(v, Packet_New, _SC("Sq_Packet_New"));
register_Packet_func(v, Packet_Put_header, _SC("Sq_Packet_Put_header"));
register_Packet_func(v, Packet_Put_byte, _SC("Sq_Packet_Put_byte"));
register_Packet_func(v, Packet_Put_short, _SC("Sq_Packet_Put_short"));
register_Packet_func(v, Packet_Put_int, _SC("Sq_Packet_Put_int"));
register_Packet_func(v, Packet_Put_binary, _SC("Sq_Packet_Put_binary"));
register_Packet_func(v, Packet_Put_binaryex, _SC("Sq_Packet_Put_binaryex"));
register_Packet_func(v, Packet_Finalize, _SC("Sq_Packet_Finalize"));
register_Packet_func(v, Packet_Send, _SC("Sq_Packet_Send"));
register_Packet_func(v, Packet_Delete, _SC("Sq_Packet_Delete"));
}

View File

@@ -1,95 +0,0 @@
#pragma once
#include "squirrel.h"
#include "sqstdaux.h"
#include "sqstdblob.h"
#include "sqstdio.h"
#include "sqstdmath.h"
#include "sqstdstring.h"
#include "sqstdsystem.h"
#include <iostream>
template <typename R, typename A, typename... ARG>
R CallParty(A call_addr, const ARG... arguments)
{
if (!call_addr)
{
return R();
}
const auto control = reinterpret_cast<R (*)(ARG...)>(call_addr);
try
{
return control(arguments...);
}
catch (...)
{
}
return R();
}
typedef int (*__CreateParty)(void *CParty, void *CUser);
static SQInteger Party_CreateParty(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQUserPointer User;
sq_getuserpointer(v, 3, &User);
((__CreateParty)0x0859B1BE)(P, User);
return 0;
}
typedef int (*__SetPartyInfoUI)(void *CParty, int code);
static SQInteger Party_SetPartyInfoUI(HSQUIRRELVM v) // 设置队伍信息UI可以不写 创出来空的 要写的话要搞个指针 写入很多参数
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
((__SetPartyInfoUI)0x0859B234)(P, 0x44d672e);
return 0;
}
typedef int (*__JoinParty)(void *CParty, void *CUser);
static SQInteger Party_JoinParty(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQUserPointer User;
sq_getuserpointer(v, 3, &User);
((__JoinParty)0x0859B2B6)(P, User);
return 0;
}
typedef int (*__SendPartyIpInfo)(void *CParty);
static SQInteger Party_SendPartyIpInfo(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
((__SendPartyIpInfo)0x0859CEA2)(P);
return 0;
}
// 获取战斗对象
static SQInteger Party_GetBattle_Field(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
sq_pushuserpointer(v, P + 2852);
return 1;
}
static SQInteger register_Party_func(HSQUIRRELVM v, SQFUNCTION f, const char *fname)
{
sq_pushroottable(v);
sq_pushstring(v, fname, -1);
sq_newclosure(v, f, 0); // create a new function
sq_newslot(v, -3, SQFalse);
sq_pop(v, 1); // pops the root table
}
static void RegisterParty(HSQUIRRELVM v)
{
// 创建队伍
register_Party_func(v, Party_CreateParty, _SC("Sq_Party_CreateParty"));
// 设置队伍信息UI
register_Party_func(v, Party_SetPartyInfoUI, _SC("Sq_Party_SetPartyInfoUI"));
// 让玩家加入队伍
register_Party_func(v, Party_JoinParty, _SC("Sq_Party_JoinParty"));
// 广播队伍玩家IP
register_Party_func(v, Party_SendPartyIpInfo, _SC("Sq_Party_SendPartyIpInfo"));
// 获取副本编号
register_Party_func(v, Party_GetBattle_Field, _SC("Sq_Party_GetBattle_Field"));
}

View File

@@ -1,247 +0,0 @@
#pragma once
#include "squirrel.h"
#include "sqstdaux.h"
#include "sqstdblob.h"
#include "sqstdio.h"
#include "sqstdmath.h"
#include "sqstdstring.h"
#include "sqstdsystem.h"
#include <iostream>
#include <fstream>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
// 错误信息打印函数
void print_openssl_error() {
char err_buf[256];
ERR_error_string_n(ERR_get_error(), err_buf, sizeof(err_buf));
std::cerr << "OpenSSL 错误: " << err_buf << std::endl;
}
// 生成 RSA 密钥对并保存到文件
// 生成 RSA 密钥对公钥X.509/PKCS#8 格式私钥PKCS#1 格式)
bool generate_rsa_key(const std::string& pub_key_path,
const std::string& pri_key_path,
int key_bits = 2048) {
// 1. 创建 RSA 对象并生成密钥对
RSA* rsa = RSA_new();
BIGNUM* bn = BN_new();
if (!rsa || !bn) {
std::cerr << "创建 RSA/BIGNUM 失败" << std::endl;
RSA_free(rsa);
BN_free(bn);
return false;
}
// 设置公钥指数65537
if (BN_set_word(bn, RSA_F4) != 1) {
std::cerr << "设置 BIGNUM 失败" << std::endl;
print_openssl_error();
RSA_free(rsa);
BN_free(bn);
return false;
}
// 生成 RSA 密钥对
if (RSA_generate_key_ex(rsa, key_bits, bn, nullptr) != 1) {
std::cerr << "生成 RSA 密钥对失败" << std::endl;
print_openssl_error();
RSA_free(rsa);
BN_free(bn);
return false;
}
// 2. 封装 RSA 到 EVP_PKEY用于生成 X.509/PKCS#8 公钥)
EVP_PKEY* evp_key = EVP_PKEY_new();
if (!evp_key || EVP_PKEY_assign_RSA(evp_key, rsa) != 1) {
std::cerr << "封装 EVP_PKEY 失败" << std::endl;
print_openssl_error();
EVP_PKEY_free(evp_key);
RSA_free(rsa);
BN_free(bn);
return false;
}
// 3. 保存 X.509/PKCS#8 格式公钥(-----BEGIN PUBLIC KEY-----
FILE* pub_file = fopen(pub_key_path.c_str(), "w");
if (!pub_file) {
std::cerr << "打开公钥文件失败: " << pub_key_path << std::endl;
EVP_PKEY_free(evp_key);
BN_free(bn);
return false;
}
if (PEM_write_PUBKEY(pub_file, evp_key) != 1) {
std::cerr << "写入 X.509 公钥失败" << std::endl;
print_openssl_error();
fclose(pub_file);
EVP_PKEY_free(evp_key);
BN_free(bn);
return false;
}
fclose(pub_file);
// 4. 保存 PKCS#1 格式私钥(-----BEGIN RSA PRIVATE KEY-----
FILE* pri_file = fopen(pri_key_path.c_str(), "w");
if (!pri_file) {
std::cerr << "打开私钥文件失败: " << pri_key_path << std::endl;
EVP_PKEY_free(evp_key);
BN_free(bn);
return false;
}
if (PEM_write_RSAPrivateKey(pri_file, rsa, nullptr, nullptr, 0, nullptr, nullptr) != 1) {
std::cerr << "写入私钥失败" << std::endl;
print_openssl_error();
fclose(pri_file);
EVP_PKEY_free(evp_key);
BN_free(bn);
return false;
}
fclose(pri_file);
// 5. 释放资源EVP_PKEY_free 会自动释放内部的 RSA 对象)
EVP_PKEY_free(evp_key);
BN_free(bn);
std::cout << "RSA 密钥生成成功!" << std::endl;
std::cout << "公钥X.509/PKCS#8 格式): " << pub_key_path << std::endl;
std::cout << "私钥PKCS#1 格式): " << pri_key_path << std::endl;
return true;
}
static SQInteger Rsa_GenerateKey(HSQUIRRELVM v)
{
// 初始化 OpenSSL 错误处理
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
// 生成 2048 位 RSA 密钥对(推荐使用 2048/4096 位)
bool ret = generate_rsa_key("public.pem", "private.pem", 2048);
// 清理 OpenSSL 资源
EVP_cleanup();
ERR_free_strings();
return 0;
}
// 从文件加载私钥PKCS#1 格式)
RSA* load_rsa_private_key(const std::string& pri_key_path) {
FILE* pri_file = fopen(pri_key_path.c_str(), "r");
if (!pri_file) {
std::cerr << "打开私钥文件失败: " << pri_key_path << std::endl;
return nullptr;
}
// 加载 PKCS#1 格式私钥
RSA* rsa = PEM_read_RSAPrivateKey(pri_file, nullptr, nullptr, nullptr);
fclose(pri_file);
if (!rsa) {
std::cerr << "加载私钥失败" << std::endl;
print_openssl_error();
}
return rsa;
}
// 新增:十六进制字符串转字节数组(核心补全)
bool hex_string_to_bytes(const std::string& hex_str, std::vector<unsigned char>& bytes) {
bytes.clear();
// 检查长度是否为偶数十六进制字符串必须2字符=1字节
if (hex_str.length() % 2 != 0) {
std::cerr << "十六进制字符串长度为奇数,无效" << std::endl;
return false;
}
for (size_t i = 0; i < hex_str.length(); i += 2) {
std::string byte_str = hex_str.substr(i, 2);
// 十六进制转字节处理0-9/a-f/A-F
unsigned char byte = static_cast<unsigned char>(strtol(byte_str.c_str(), nullptr, 16));
bytes.push_back(byte);
}
return true;
}
bool rsa_private_encrypt(const std::vector<unsigned char>& plaintext_bytes, RSA* rsa_pri, std::string& ciphertext) {
if (!rsa_pri || plaintext_bytes.empty()) return false;
int rsa_len = RSA_size(rsa_pri);
unsigned char* enc_buf = new unsigned char[rsa_len];
// 加密字节数组而非字符串的ASCII
int enc_len = RSA_private_encrypt(
plaintext_bytes.size(), // 明文长度(字节数)
plaintext_bytes.data(), // 明文字节数组
enc_buf, // 加密结果缓冲区
rsa_pri, // RSA私钥
RSA_PKCS1_PADDING // 填充方式和Java一致
);
if (enc_len > 0) {
ciphertext = std::string((char*)enc_buf, enc_len);
} else {
std::cerr << "私钥加密失败2048位RSA最多加密245字节" << std::endl;
print_openssl_error();
}
delete[] enc_buf;
return enc_len > 0;
}
static SQInteger Rsa_Private_Encrypt(HSQUIRRELVM v)
{
const SQChar* hex_str;
sq_getstring(v, 2, &hex_str); // 获取Squirrel传入的十六进制字符串
// 1. 加载RSA私钥
RSA* rsa_pri = load_rsa_private_key("privatekey.pem");
if (!rsa_pri) {
sq_pushnull(v);
return 1;
}
// 2. 核心十六进制字符串转字节数组对齐Java的toByteArray
std::vector<unsigned char> plaintext_bytes;
if (!hex_string_to_bytes(std::string(hex_str), plaintext_bytes)) {
RSA_free(rsa_pri);
sq_pushnull(v);
return 1;
}
// 3. 加密字节数组
std::string ciphertext;
bool success = rsa_private_encrypt(plaintext_bytes, rsa_pri, ciphertext);
// 4. 返回加密后的字节串Squirrel中以字符串形式承载二进制数据
if (success) {
sq_pushstring(v, ciphertext.c_str(), ciphertext.length());
} else {
sq_pushnull(v);
}
// 释放资源
RSA_free(rsa_pri);
return 1;
}
// ====================== 辅助函数 - 注册Squirrel函数 ======================
static SQInteger register_Rsa_func(HSQUIRRELVM v, SQFUNCTION f, const char* fname) {
sq_pushroottable(v);
sq_pushstring(v, fname, -1);
sq_newclosure(v, f, 0);
sq_newslot(v, -3, SQFalse);
sq_pop(v, 1); // 弹出根表
return 0;
}
// ====================== 注册所有Dio函数 ======================
static void RegisterRsa(HSQUIRRELVM v) {
register_Rsa_func(v, Rsa_GenerateKey, _SC("Sq_Rsa_GenerateKey"));
//使用私钥签名
register_Rsa_func(v, Rsa_Private_Encrypt, _SC("Sq_Rsa_Private_Encrypt"));
}

View File

@@ -1,543 +0,0 @@
#pragma once
#include "squirrel.h"
#include "sqstdaux.h"
#include "sqstdblob.h"
#include "sqstdio.h"
#include "sqstdmath.h"
#include "sqstdstring.h"
#include "sqstdsystem.h"
#include <vector>
#include <cstring>
#include <iostream>
template <typename R, typename A, typename... ARG>
R CallUser(A call_addr, const ARG... arguments)
{
if (!call_addr)
{
return R();
}
const auto control = reinterpret_cast<R (*)(ARG...)>(call_addr);
try
{
return control(arguments...);
}
catch (...)
{
}
return R();
}
typedef int (*__GetUserByThis)(void *CUser);
typedef int (*__GetUserArea)(void *CUser, bool a);
typedef int (*__SetUserByInt)(void *CUser, int Value);
static SQInteger CUser_GetPosX(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger X = int(((__GetUserByThis)0x0813492c)((void *)P));
sq_pushinteger(v, X);
return 1;
}
static SQInteger CUser_GetPosY(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Y = int(((__GetUserByThis)0x0813493c)((void *)P));
sq_pushinteger(v, Y);
return 1;
}
static SQInteger CUser_Direction(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Ret = int(((__GetUserByThis)0x0813494c)((void *)P));
sq_pushinteger(v, Ret);
return 1;
}
static SQInteger CUser_GetVill(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Vill = int(((__GetUserByThis)0x08645564)((void *)P));
sq_pushinteger(v, Vill);
return 1;
}
static SQInteger CUser_GetArea(HSQUIRRELVM v)
{
SQUserPointer P;
SQInteger Type = 0;
sq_getuserpointer(v, 2, &P);
if (sq_gettop(v) == 3)
{
sq_getinteger(v, 3, &Type);
}
SQInteger Area = int(((__GetUserArea)0x086813BE)((void *)P, Type));
sq_pushinteger(v, Area);
return 1;
}
static SQInteger CUser_GetState(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger State = int(((__GetUserByThis)0x080DA38C)((void *)P));
sq_pushinteger(v, State);
return 1;
}
static SQInteger CUser_GetCharacCount(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Count = int(((__GetUserByThis)0x082300E8)((void *)P));
sq_pushinteger(v, Count);
return 1;
}
static SQInteger CUser_GetUniqueId(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger UID = int(((__GetUserByThis)0x080DA37C)((void *)P));
sq_pushinteger(v, UID);
return 1;
}
static SQInteger CUser_GetAccId(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger UID = int(((__GetUserByThis)0x080DA36E)((void *)P));
sq_pushinteger(v, UID);
return 1;
}
static SQInteger CUser_GetCharacNo(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger CID = int(((__GetUserByThis)0x080CBC4E)((void *)P));
sq_pushinteger(v, CID);
return 1;
}
static SQInteger CUser_GetCharacJob(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Ret = int(((__GetUserByThis)0x080FDF20)((void *)P));
sq_pushinteger(v, Ret);
return 1;
}
static SQInteger CUser_GetCharacName(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Ret = int(((__GetUserByThis)0x08101028)((void *)P));
sq_pushstring(v, _SC((char *)Ret), -1);
return 1;
}
static SQInteger CUser_GetCharacLevel(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Ret = int(((__GetUserByThis)0x080DA2B8)((void *)P));
sq_pushinteger(v, Ret);
return 1;
}
static SQInteger CUser_SetCharacLevel(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Value;
sq_getinteger(v, 3, &Value);
char *a = new char[4];
CallUser<int>(0x822FC8E, a, P, Value);
return 0;
}
static SQInteger CUser_GetCharacGrowType(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Ret = int(((__GetUserByThis)0x0815741C)((void *)P));
sq_pushinteger(v, Ret);
return 1;
}
static SQInteger CUser_GetCharacSecondGrowType(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Ret = int(((__GetUserByThis)0x0822F23C)((void *)P));
sq_pushinteger(v, Ret);
return 1;
}
static SQInteger CUser_GetFatigue(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Ret = int(((__GetUserByThis)0x08657766)((void *)P));
sq_pushinteger(v, Ret);
return 1;
}
static SQInteger CUser_GetMaxFatigue(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Ret = int(((__GetUserByThis)0x08657804)((void *)P));
sq_pushinteger(v, Ret);
return 1;
}
typedef int (*__CUser_DisConnSig)(void *CUser, int type, int is, int err);
static SQInteger CUser_DisConnSig(HSQUIRRELVM v)
{
SQUserPointer P;
SQInteger Src;
SQInteger P2;
SQInteger P3;
sq_getuserpointer(v, 2, &P);
sq_getinteger(v, 3, &Src);
sq_getinteger(v, 4, &P2);
sq_getinteger(v, 5, &P3);
SQInteger Ret = int(((__CUser_DisConnSig)0x086489F4)((void *)P, Src, P2, P3));
sq_pushinteger(v, Ret);
return 1;
}
typedef void *(*__GetUserParty)(void *CUser);
static SQInteger CUser_GetParty(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQUserPointer Ret = (((__GetUserParty)0x0865514C)((void *)P));
sq_pushuserpointer(v, Ret);
return 1;
}
static SQInteger CUser_CheckInBossTower(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Ret = int(((__GetUserByThis)0x082a67e2)((void *)P));
sq_pushinteger(v, Ret);
return 1;
}
static SQInteger CUser_CheckInBlueMarble(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Ret = int(((__GetUserByThis)0x080da32a)((void *)P));
sq_pushinteger(v, Ret);
return 1;
}
static SQInteger CUser_IsGmMode(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Ret = int(((__GetUserByThis)0x0814589c)((void *)P));
sq_pushinteger(v, Ret);
return 1;
}
static SQInteger CUser_GetVisibleValues(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Ret = int(((__GetUserByThis)0x0868BDE4)((void *)P));
sq_pushinteger(v, Ret);
return 1;
}
static SQInteger CUser_GetCurCharacLastPlayTick(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Ret = int(((__GetUserByThis)0x082A66AA)((void *)P));
sq_pushinteger(v, Ret);
return 1;
}
typedef int (*__GiveUserItem)(void *CUser, int a2, int a3, int a4, int *a5, int a6);
typedef int (*__UserSendUpdateItemList)(void *CUser, int a2, int a3, int a4);
static SQInteger CUser_GiveUserItem(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger ItemId, ItemCount;
sq_getinteger(v, 3, &ItemId);
sq_getinteger(v, 4, &ItemCount);
int *ItemSpace = (int *)malloc(4);
int Slot = int(((__GiveUserItem)0x0867B6D4)((void *)P, ItemId, ItemCount, 6, ItemSpace, 0));
if (Slot >= 0)
{
sq_newarray(v, 0);
sq_pushinteger(v, *ItemSpace);
sq_arrayappend(v, -2);
sq_pushinteger(v, Slot);
sq_arrayappend(v, -2);
}
else
sq_pushnull(v);
return 1;
}
// 通知客户端更新道具信息
static SQInteger CUser_SendUpdateItemList(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Type, ItemSpace, Slot;
sq_getinteger(v, 3, &Type);
sq_getinteger(v, 4, &ItemSpace);
sq_getinteger(v, 5, &Slot);
CallUser<int>(0x867C65A, P, Type, ItemSpace, Slot);
return 0;
}
// 通知客户端更新背包栏
static SQInteger CUser_SendItemSpace(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger itemSpace;
sq_getinteger(v, 3, &itemSpace);
// std::cout << *(int *)P << std::endl;
CallUser<int>(0x865DB6C, P, itemSpace);
return 0;
}
// 发送邮件
static SQInteger CUser_SendMail(HSQUIRRELVM v)
{
SQInteger Cid;
sq_getinteger(v, 2, &Cid);
std::vector<std::pair<int, int>> List;
List.clear();
int ItemListLen = 0;
sq_pushnull(v); // null iterator
while (SQ_SUCCEEDED(sq_next(v, 3)))
{
SQInteger Index, Count;
sq_getinteger(v, -1, &Count);
sq_getinteger(v, -2, &Index);
std::pair<int, int> pair1 = std::make_pair(Index, Count);
List.push_back(pair1);
// 这里-1是值-2是键
sq_pop(v, 2); // 在下一次迭代之前弹出键和值
ItemListLen++;
}
sq_pop(v, 1);
void *addition_slots = malloc(1000);
for (int i = 0; i < 10; i++)
{
CallUser<void>(0x80CB854, addition_slots + (i * 61));
}
CallUser<int>(0x8556A14, List, addition_slots, 10);
SQInteger Gold;
sq_getinteger(v, 4, &Gold);
const SQChar *Title;
const SQChar *Text;
sq_getstring(v, 5, &Title);
sq_getstring(v, 6, &Text);
int TextLen = strlen(Text);
CallUser<int>(0x8556B68, Title, addition_slots, ItemListLen, Gold, Cid, Text, TextLen, 0, 99, 1);
return 0;
}
// 发送邮件
static SQInteger CUser_ChangeGrowType(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Base, Ex;
sq_getinteger(v, 3, &Base);
sq_getinteger(v, 4, &Ex);
CallUser<int>(0x867B048, P, Base, Ex);
return 0;
}
// 发送消息包
static SQInteger CUser_SendNotiPacket(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Type1, Type2, Type3;
sq_getinteger(v, 3, &Type1);
sq_getinteger(v, 4, &Type2);
sq_getinteger(v, 5, &Type3);
CallUser<int>(0x867BA5C, P, Type1, Type2, Type3);
return 0;
}
// 获取技能树
static SQInteger CUser_GetSkillW(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
void *S = CallUser<void *>(0x822F140, P);
sq_pushuserpointer(v, S);
return 1;
}
// 重置技能
static SQInteger CUser_InitSkillW(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger GrowType, IsAwa;
sq_getinteger(v, 3, &GrowType);
sq_getinteger(v, 4, &IsAwa);
CallUser<int>(0x8608120, P, GrowType, IsAwa);
return 0;
}
// 改变GM完成任务模式
static SQInteger CUser_ChangeGmQuestFlag(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Type;
sq_getinteger(v, 3, &Type);
CallUser<int>(0x822FC8E, P, Type);
return 0;
}
// 任务相关操作
static SQInteger CUser_QuestAction(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Type, QuestId, Reward, Flag;
sq_getinteger(v, 3, &Type);
sq_getinteger(v, 4, &QuestId);
sq_getinteger(v, 5, &Reward);
sq_getinteger(v, 6, &Flag);
CallUser<int>(0x0866DA8A, P, Type, QuestId, Reward, Flag);
return 0;
}
// 刷新上次任务完成时间
static SQInteger CUser_RefreshLastQuestTime(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
*(int *)((void *)P + 0x79644) = 0;
return 0;
}
// 充值点券
static SQInteger CUser_RechargeCoupons(HSQUIRRELVM v)
{
SQUserPointer User;
sq_getuserpointer(v, 2, &User);
SQInteger Amount;
sq_getinteger(v, 3, &Amount);
CallUser<int>(0x80FFCA4, *(uintptr_t *)0x941F734, User, 5, Amount, (void *)0x8C7FA20, (void *)0x8C7FA20, "Gm", (void *)0, (void *)0, (void *)0);
CallUser<int>(0x8100790, *(uintptr_t *)0x941F734, User);
return 0;
}
// 充值代币券
static SQInteger CUser_RechargeCouponsPoint(HSQUIRRELVM v)
{
SQUserPointer User;
sq_getuserpointer(v, 2, &User);
SQInteger Amount;
sq_getinteger(v, 3, &Amount);
CallUser<int>(0x80FFFC0, *(uintptr_t *)0x941F734, User, Amount, 4, (void *)0, (void *)0);
CallUser<int>(0x8100790, *(uintptr_t *)0x941F734, User);
return 0;
}
// 充值金币
static SQInteger CUser_RechargeMoney(HSQUIRRELVM v)
{
SQUserPointer User;
sq_getuserpointer(v, 2, &User);
SQInteger Amount;
sq_getinteger(v, 3, &Amount);
CallUser<int>(0x84FF29C, User, Amount, 0, 0, 0);
return 0;
}
static SQInteger register_User_func(HSQUIRRELVM v, SQFUNCTION f, const char *fname)
{
sq_pushroottable(v);
sq_pushstring(v, fname, -1);
sq_newclosure(v, f, 0); // create a new function
sq_newslot(v, -3, SQFalse);
sq_pop(v, 1); // pops the root table
}
static void RegisterUser(HSQUIRRELVM v)
{
// 获取X坐标
register_User_func(v, CUser_GetPosX, "Sq_CUser_GetPosX");
// 获取Y坐标
register_User_func(v, CUser_GetPosY, "Sq_CUser_GetPosY");
// 获取朝向
register_User_func(v, CUser_Direction, "Sq_CUser_Direction");
// 获取城镇编号
register_User_func(v, CUser_GetVill, "Sq_CUser_GetTownIndex");
// 获取区域编号
register_User_func(v, CUser_GetArea, "Sq_CUser_GetAreaIndex");
// 获取账号状态
register_User_func(v, CUser_GetState, "Sq_CUser_GetState");
// 获取角色数量
register_User_func(v, CUser_GetCharacCount, "Sq_CUser_GetCharacCount");
// 获取UID
register_User_func(v, CUser_GetAccId, "Sq_CUser_GetAccId");
// 获取UniqueId
register_User_func(v, CUser_GetUniqueId, "Sq_CUser_GetUniqueId");
// 获取CID
register_User_func(v, CUser_GetCharacNo, "Sq_CUser_GetCharacNo");
// 获取角色职业
register_User_func(v, CUser_GetCharacJob, "Sq_CUser_GetCharacJob");
// 获取角色名称
register_User_func(v, CUser_GetCharacName, "Sq_CUser_GetCharacName");
// 获取角色等级
register_User_func(v, CUser_GetCharacLevel, "Sq_CUser_GetCharacLevel");
// 设置角色等级
register_User_func(v, CUser_SetCharacLevel, "Sq_CUser_SetCharacLevel");
// 获取角色转职职业
register_User_func(v, CUser_GetCharacGrowType, "Sq_CUser_GetCharacGrowType");
// 获取角色觉醒职业
register_User_func(v, CUser_GetCharacSecondGrowType, "Sq_CUser_GetCharacSecondGrowType");
// 获取已用疲劳值
register_User_func(v, CUser_GetFatigue, "Sq_CUser_GetFatigue");
// 获取最大疲劳值
register_User_func(v, CUser_GetMaxFatigue, "Sq_CUser_GetMaxFatigue");
// 踢人
register_User_func(v, CUser_DisConnSig, "Sq_CUser_DisConnSig");
// 获取当前小队/副本
register_User_func(v, CUser_GetParty, "Sq_CUser_GetParty");
// 获是否在领主塔
register_User_func(v, CUser_CheckInBossTower, "Sq_CUser_CheckInBossTower");
// 获取是否在龙之路
register_User_func(v, CUser_CheckInBlueMarble, "Sq_CUser_CheckInBlueMarble");
// 是否开启GM权限
register_User_func(v, CUser_IsGmMode, "Sq_CUser_IsGmMode");
// 获取可见Values
register_User_func(v, CUser_GetVisibleValues, "Sq_CUser_GetVisibleValues");
// 获取账号上次退出游戏的时间
register_User_func(v, CUser_GetCurCharacLastPlayTick, "Sq_CUser_GetCurCharacLastPlayTick");
// 发送道具
register_User_func(v, CUser_GiveUserItem, "Sq_CUser_GiveUserItem");
// 通知客户端更新背包
register_User_func(v, CUser_SendItemSpace, "Sq_CUser_SendItemSpace");
// 通知客户端道具更新
register_User_func(v, CUser_SendUpdateItemList, "Sq_CUser_SendUpdateItemList");
// 发送GM邮件
register_User_func(v, CUser_SendMail, "Sq_CUser_SendMail");
// 更改职业
register_User_func(v, CUser_ChangeGrowType, "Sq_CUser_ChangeGrowType");
// 发送消息包
register_User_func(v, CUser_SendNotiPacket, "Sq_CUser_SendNotiPacket");
// 获取技能树
register_User_func(v, CUser_GetSkillW, "Sq_CUser_GetSkillW");
// 重置技能树
register_User_func(v, CUser_InitSkillW, "Sq_CUser_InitSkillW");
// 改变GM完成任务模式
register_User_func(v, CUser_ChangeGmQuestFlag, "Sq_CUser_ChangeGmQuestFlag");
// 任务相关操作
register_User_func(v, CUser_QuestAction, "Sq_CUser_QuestAction");
// 刷新上次任务完成时间
register_User_func(v, CUser_RefreshLastQuestTime, "Sq_CUser_RefreshLastQuestTime");
// 充值点券
register_User_func(v, CUser_RechargeCoupons, "Sq_CUser_RechargeCoupons");
// 充值代币券
register_User_func(v, CUser_RechargeCouponsPoint, "Sq_CUser_RechargeCouponsPoint");
// 充值金币
register_User_func(v, CUser_RechargeMoney, "Sq_CUser_RechargeMoney");
}

View File

@@ -1,177 +0,0 @@
#pragma once
#include "squirrel.h"
#include "sqstdaux.h"
#include "sqstdblob.h"
#include "sqstdio.h"
#include "sqstdmath.h"
#include "sqstdstring.h"
#include "sqstdsystem.h"
#include <iostream>
#include <map>
typedef void *(*__G_GameWorld)();
static SQInteger Get_GameWorld(HSQUIRRELVM v)
{
void *World = ((__G_GameWorld)0x080DA3A7)();
sq_pushuserpointer(v, World);
return 1;
}
typedef int (*__GetSessionByUid)(void *World, int Uid);
static SQInteger GameWorld_GetSessionByUid(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Uid;
sq_getinteger(v, 3, &Uid);
SQInteger Session = ((__GetSessionByUid)0x086C4C24)((void *)P, Uid);
sq_pushinteger(v, Session);
return 1;
}
typedef void *(*__GetUserBySession)(void *World, int Session);
static SQInteger GameWorld_GetUserBySession(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Session;
sq_getinteger(v, 3, &Session);
void *User = ((__GetUserBySession)0x086C4B9C)((void *)P, Session);
sq_pushuserpointer(v, User);
return 1;
}
typedef void *(*__GetUserByUid)(void *World, int Uid);
static SQInteger GameWorld_GetUserByUid(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Uid;
sq_getinteger(v, 3, &Uid);
void *User = ((__GetUserByUid)0x086C4D40)((void *)P, Uid);
sq_pushuserpointer(v, User);
return 1;
}
typedef void *(*__GetUserByName)(void *World, char *Name);
static SQInteger GameWorld_GetUserByName(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
const SQChar *Name;
sq_getstring(v, 3, &Name);
void *User = ((__GetUserByName)0x086C9464)((void *)P, (char *)Name);
sq_pushuserpointer(v, User);
return 1;
}
typedef int (*__GetUserCount)(void *World);
static SQInteger GameWorld_GetUserCount(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQInteger Count = ((__GetUserCount)0x086C4550)((void *)P);
sq_pushinteger(v, Count);
return 1;
}
typedef void (*__SendAll)(void *World, void *Pack);
static SQInteger GameWorld_SendAll(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQUserPointer Pck;
sq_getuserpointer(v, 3, &Pck);
((__SendAll)0x086C8C14)((void *)P, (void *)Pck);
return 0;
}
typedef void (*__SendPartyInfoToAll)(void *World, void *CParty, int code);
static SQInteger GameWorld_SendPartyInfoToAll(HSQUIRRELVM v)
{
SQUserPointer World;
sq_getuserpointer(v, 2, &World);
SQUserPointer CParty;
sq_getuserpointer(v, 3, &CParty);
((__SendPartyInfoToAll)0x086C878A)((void *)World, (void *)CParty, 0);
return 0;
}
// typedef std::map<int, std::string> (*__GetUserIdList)(&std::vector<unsigned short> a1, int a2);
// static SQInteger GetUserIdList(HSQUIRRELVM v)
// {
// SQInteger a1, a2;
// sq_getinteger(v, 2, &a1);
// sq_getinteger(v, 3, &a2);
// std::vector<unsigned short> Qs;
// std::map<int, std::string> Ret = ((__GetUserIdList)0x086C305E)(&Qs, a2);
// std::cout << Qs.size() << std::endl;
// std::cout << Ret.size() << std::endl;
// return 0;
// }
typedef void *(*__WorldMoveArea)(void *World, void *User, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10, int a11);
static SQInteger GameWorld_MoveArea(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQUserPointer Player;
sq_getuserpointer(v, 3, &Player);
SQInteger TownIndex, AreaIndex, Xpos, Ypos;
sq_getinteger(v, 4, &TownIndex);
sq_getinteger(v, 5, &AreaIndex);
sq_getinteger(v, 6, &Xpos);
sq_getinteger(v, 7, &Ypos);
((__WorldMoveArea)0x86C5A84)((void *)P, (void *)Player, TownIndex, AreaIndex, Xpos, Ypos, 0, 0, 0, 0, 0);
return 0;
}
typedef void *(*__SendDungeonInOut)(void *World, void *User, int a3, bool a4);
static SQInteger GameWorld_SendDungeonInOut(HSQUIRRELVM v)
{
SQUserPointer P;
sq_getuserpointer(v, 2, &P);
SQUserPointer Player;
sq_getuserpointer(v, 3, &Player);
SQInteger Index;
SQBool Model;
sq_getinteger(v, 4, &Index);
sq_getbool(v, 5, &Model);
((__SendDungeonInOut)0x86C8FC8)((void *)P, (void *)Player, Index, Model);
return 0;
}
static SQInteger register_World_func(HSQUIRRELVM v, SQFUNCTION f, const char *fname)
{
sq_pushroottable(v);
sq_pushstring(v, fname, -1);
sq_newclosure(v, f, 0); // create a new function
sq_newslot(v, -3, SQFalse);
sq_pop(v, 1); // pops the root table
}
static void RegisterWorld(HSQUIRRELVM v)
{
// 获取游戏世界
register_World_func(v, Get_GameWorld, _SC("Sq_Get_GameWorld"));
// 根据UID获取Session
register_World_func(v, GameWorld_GetSessionByUid, _SC("Sq_GameWorld_GetSessionByUid"));
// 根据Session获取玩家
register_World_func(v, GameWorld_GetUserBySession, _SC("Sq_GameWorld_GetUserBySession"));
// 根据UID获取玩家
register_World_func(v, GameWorld_GetUserByUid, _SC("Sq_GameWorld_GetUserByUid"));
// 根据名字获取玩家
register_World_func(v, GameWorld_GetUserByName, _SC("Sq_GameWorld_GetUserByName"));
// 获取玩家数量
register_World_func(v, GameWorld_GetUserCount, _SC("Sq_GameWorld_GetUserCount"));
// 给所有玩家发包
register_World_func(v, GameWorld_SendAll, _SC("Sq_GameWorld_SendAll"));
// 指定玩家移动
register_World_func(v, GameWorld_MoveArea, _SC("Sq_GameWorld_MoveArea"));
// 给所有玩家发送队伍包
register_World_func(v, GameWorld_SendPartyInfoToAll, _SC("Sq_GameWorld_SendPartyInfoToAll"));
// 副本开启或关闭消息
register_World_func(v, GameWorld_SendDungeonInOut, _SC("Sq_GameWorld_SendDungeonInOut"));
// register_World_func(v, GetUserIdList, _SC("Sq_GetUserIdList"));
}

View File

@@ -1,498 +0,0 @@
#pragma once
#include "BASE64.hpp"
#include "Version.h"
#include <asio.hpp>
#include <asio/basic_socket_streambuf.hpp>
#include <asio/ssl.hpp>
#include <chrono>
#include <ctime>
#include <iostream>
#include <sstream>
#include <zlib.h>
using namespace asio;
using asio::ip::tcp;
// 单个字符解密
static char CutcodeChar(char c, int key, int key2) {
char a = (((c - 1) ^ key) ^ key2) - key;
return a;
}
// 解密
void Cutecode(char *pstr, int *pkey, int len, int keyLength) {
if (len == -1)
len = strlen(pstr);
for (int i = 0; i < len; i++) {
*(pstr + i) = CutcodeChar(*(pstr + i), pkey[i % keyLength],
pkey[(i + 18) % keyLength]);
}
}
// 加密函数
static std::string r_encryptDecrypt(const std::string &input,
const std::string &key) {
std::string output = input;
for (size_t i = 0; i < input.size(); i++) {
output[i] = input[i] ^ key[i % key.size()]; // 使用异或运算进行加密
}
return output;
}
static std::string ReqScriptUrl(const std::vector<std::string> &domains) {
for (const auto &domain : domains) {
try {
asio::io_context io_context;
asio::ssl::context ctx(asio::ssl::context::tlsv12_client);
ctx.set_verify_mode(asio::ssl::verify_none);
// 启用 TLS 1.0/1.1/1.2/1.3 支持
ctx.set_options(asio::ssl::context::default_workarounds |
asio::ssl::context::no_sslv2 |
asio::ssl::context::no_sslv3 |
asio::ssl::context::single_dh_use);
asio::ssl::stream<asio::ip::tcp::socket> socket(io_context, ctx);
// 设置 SNI
if (!SSL_set_tlsext_host_name(socket.native_handle(), domain.c_str())) {
asio::error_code ec{static_cast<int>(::ERR_get_error()),
asio::error::get_ssl_category()};
throw asio::system_error{ec};
}
asio::ip::tcp::resolver resolver(io_context);
auto endpoints = resolver.resolve(domain, "https");
// 连接超时设置
bool connect_timeout = false;
asio::steady_timer connect_timer(io_context);
connect_timer.expires_from_now(std::chrono::seconds(10));
connect_timer.async_wait([&](const asio::error_code &ec) {
if (!ec) {
connect_timeout = true;
socket.lowest_layer().close();
}
});
asio::error_code connect_ec;
asio::async_connect(socket.lowest_layer(), endpoints,
[&](asio::error_code ec, asio::ip::tcp::endpoint) {
connect_ec = ec;
connect_timer.cancel();
});
io_context.run();
io_context.reset();
if (connect_timeout) {
throw std::runtime_error("连接超时");
}
if (connect_ec) {
throw std::system_error(connect_ec);
}
// SSL握手超时设置
bool handshake_timeout = false;
asio::steady_timer handshake_timer(io_context);
handshake_timer.expires_from_now(std::chrono::seconds(10));
handshake_timer.async_wait([&](const asio::error_code &ec) {
if (!ec) {
handshake_timeout = true;
socket.lowest_layer().close();
}
});
asio::error_code handshake_ec;
socket.async_handshake(asio::ssl::stream_base::client,
[&](asio::error_code ec) {
handshake_ec = ec;
handshake_timer.cancel();
});
io_context.run();
io_context.reset();
if (handshake_timeout) {
throw std::runtime_error("SSL握手超时");
}
if (handshake_ec) {
throw std::system_error(handshake_ec);
}
std::string request = "POST /script/getservicenew HTTP/1.1\r\n";
request += "Host: " + domain + "\r\n";
request += "ve: " + std::string(DPS_SCRIPT_VERSION) + "\r\n";
request += "Content-Length: 0\r\n";
request += "Content-Type: application/x-www-form-urlencoded\r\n";
request += "Connection: close\r\n";
request += "\r\n";
asio::write(socket, asio::buffer(request));
// 响应超时设置
bool response_timeout = false;
asio::steady_timer response_timer(io_context);
response_timer.expires_from_now(std::chrono::seconds(10));
response_timer.async_wait([&](const asio::error_code &ec) {
if (!ec) {
response_timeout = true;
socket.lowest_layer().close();
}
});
asio::streambuf response;
asio::error_code read_ec;
asio::async_read(socket, response, [&](asio::error_code ec, std::size_t) {
read_ec = ec;
response_timer.cancel();
});
io_context.run();
if (response_timeout) {
throw std::runtime_error("响应超时");
}
if (read_ec && read_ec != asio::error::eof) {
throw std::system_error(read_ec);
}
// 解析响应头部
std::istream response_stream(&response);
std::string http_version;
unsigned int status_code;
std::string status_message;
response_stream >> http_version >> status_code;
std::getline(response_stream, status_message); // 读取状态行剩余部分
response_stream.ignore(); // 跳过状态行后的换行符
// 读取并解析头部字段
std::string header_line;
std::map<std::string, std::string> headers;
while (std::getline(response_stream, header_line) &&
header_line != "\r") {
// 去掉行末的\r
if (!header_line.empty() &&
header_line[header_line.size() - 1] == '\r') {
header_line.resize(header_line.size() - 1);
}
// 分割头部字段
size_t colon_pos = header_line.find(':');
if (colon_pos != std::string::npos) {
std::string key = header_line.substr(0, colon_pos);
std::string value = header_line.substr(colon_pos + 1);
// 去除值前面的空格
size_t start = value.find_first_not_of(" \t");
if (start != std::string::npos) {
value = value.substr(start);
}
headers[key] = value;
}
}
if (status_code == 200) {
// 读取响应体根据Content-Length
size_t content_length = 0;
auto cl_it = headers.find("Content-Length");
if (cl_it != headers.end()) {
content_length = std::stoul(cl_it->second);
}
// 计算剩余需要读取的字节数
size_t bytes_read = response.size();
size_t bytes_to_read =
content_length > bytes_read ? content_length - bytes_read : 0;
if (bytes_to_read > 0) {
// 继续读取剩余数据
response_timer.expires_from_now(std::chrono::seconds(10));
response_timer.async_wait([&](const asio::error_code &ec) {
if (!ec) {
response_timeout = true;
socket.lowest_layer().close();
}
});
asio::error_code read_body_ec;
asio::async_read(socket, response,
asio::transfer_exactly(bytes_to_read),
[&](asio::error_code ec, std::size_t) {
read_body_ec = ec;
response_timer.cancel();
});
io_context.run();
if (response_timeout) {
throw std::runtime_error("读取响应体超时");
}
if (read_body_ec && read_body_ec != asio::error::eof) {
throw std::system_error(read_body_ec);
}
}
// 提取响应体字符串
std::istreambuf_iterator<char> eos;
std::string response_body(
std::istreambuf_iterator<char>(response_stream), eos);
return response_body;
} else {
std::cerr << "错误的请求 " << domain
<< " failed with status code: " << status_code << std::endl;
}
} catch (const std::exception &e) {
std::cerr << "错误的连接 " << domain << ": " << e.what() << std::endl;
}
}
return "";
}
static std::string make_request(const std::string &host,
const std::string &port,
const std::string &path) {
asio::io_context io_context;
tcp::resolver resolver(io_context);
tcp::resolver::results_type endpoints = resolver.resolve(host, port);
tcp::socket socket(io_context);
asio::connect(socket, endpoints);
// Form the request. We specify the "Connection: close" header so that the
// server will close the socket after transmitting the response. This
// will allow us to treat all data up until the EOF as the content.
std::string request = "GET " + path + " HTTP/1.1\r\n";
request += "Host: " + host + "\r\n";
request += "Connection: close\r\n\r\n";
// Send the request.
asio::write(socket, asio::buffer(request));
// Read the response status line. The response streambuf will automatically
// grow to accommodate the entire line. The growth may be limited by passing
// a maximum size to the streambuf constructor.
asio::streambuf response;
asio::read_until(socket, response, "\r\n");
// Check that response is OK.
std::istream response_stream(&response);
std::string http_version;
response_stream >> http_version;
unsigned int status_code;
response_stream >> status_code;
std::string status_message;
std::getline(response_stream, status_message);
if (!response_stream || http_version.substr(0, 5) != "HTTP/") {
throw std::runtime_error("Invalid response");
}
if (status_code != 200) {
throw std::runtime_error("Response returned with status code " +
std::to_string(status_code));
}
// Read the response headers, which are terminated by a blank line.
asio::read_until(socket, response, "\r\n\r\n");
// Process the response headers.
std::string header;
while (std::getline(response_stream, header) && header != "\r") {
// std::cout << header << "\n";
}
// std::cout << "\n";
// Write whatever content we already have to output.
std::ostringstream response_body;
if (response.size() > 0) {
response_body << &response;
}
// Read until EOF, writing data to output as we go.
asio::error_code error;
while (asio::read(socket, response, asio::transfer_at_least(1), error)) {
response_body << &response;
}
if (error != asio::error::eof) {
throw asio::system_error(error);
}
return response_body.str();
}
static std::string ReqScript(std::string url) {
std::vector<std::string> UrlData;
Tool::Split(url, UrlData, ",");
try {
std::string host = UrlData[0];
std::string port = UrlData[1];
std::string path = "/" + UrlData[2];
std::string response = make_request(host, port, path);
// std::cout << "Response body:\n"
// << response << "\n";
return response;
} catch (std::exception &e) {
// std::cerr << "Exception: " << e.what() << "\n";
return "null";
}
}
std::vector<unsigned char> base64_decode(const std::string &encoded) {
BIO *bio, *b64;
std::vector<unsigned char> result(encoded.size());
b64 = BIO_new(BIO_f_base64());
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
bio = BIO_new_mem_buf(encoded.c_str(), encoded.size());
bio = BIO_push(b64, bio);
int len = BIO_read(bio, result.data(), encoded.size());
result.resize(len);
BIO_free_all(bio);
return result;
}
// zlib解压函数
static std::string gzip_decompress(std::vector<unsigned char> compressed) {
z_stream zs;
memset(&zs, 0, sizeof(zs));
if (inflateInit2(&zs, 16 + MAX_WBITS) != Z_OK) {
// throw std::runtime_error("inflateInit failed");
return "null";
}
zs.next_in = (Bytef *)compressed.data();
zs.avail_in = compressed.size();
int ret;
char outbuffer[32768];
std::string outstring;
do {
zs.next_out = reinterpret_cast<Bytef *>(outbuffer);
zs.avail_out = sizeof(outbuffer);
ret = inflate(&zs, 0);
if (outstring.size() < zs.total_out) {
outstring.append(outbuffer, zs.total_out - outstring.size());
}
} while (ret == Z_OK);
inflateEnd(&zs);
if (ret != Z_STREAM_END) {
// throw std::runtime_error("Exception during zlib decompression: (" +
// std::to_string(ret) + ") " + zs.msg);
return "null";
}
return outstring;
}
static std::string rsaDecrypt(std::vector<unsigned char> encryptedData,
const std::string &publicKeyStr) {
RSA *rsa = RSA_new();
BIO *bio = BIO_new_mem_buf(const_cast<char *>(publicKeyStr.c_str()), -1);
PEM_read_bio_RSA_PUBKEY(bio, &rsa, NULL, NULL);
int rsaSize = RSA_size(rsa);
std::string decryptedData(rsaSize, 0);
int decryptedSize =
RSA_public_decrypt(encryptedData.size(), encryptedData.data(),
reinterpret_cast<unsigned char *>(&decryptedData[0]),
rsa, RSA_PKCS1_PADDING);
if (decryptedSize == -1) {
std::cerr << "Error decrypting data" << std::endl;
return "";
}
RSA_free(rsa);
BIO_free(bio);
decryptedData.resize(decryptedSize);
return decryptedData;
}
static void ReqSquirrelScript(HSQUIRRELVM v) {
std::vector<std::string> domains = {"dps.senzo.online"};
std::string StrBuf = ReqScriptUrl(domains);
std::vector<unsigned char> compressed = base64_decode(StrBuf);
std::string original_data = gzip_decompress(compressed);
nlohmann::json Jso = nlohmann::json::parse(original_data);
std::string Key = Jso["key"].dump();
Key = Key.substr(1, Key.length() - 2);
std::string Script = Jso["getBaseScriptStr"].dump();
Script = Script.substr(1, Script.length() - 2);
std::string pub = R"(-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDafyp7gGautPZZ3I3IlYLf8Qyw
xGigvg0rkmXPaP34C6sHi//GLuYjwM6AUJTtbfo0pCNmLqBbCiiuzkBXEqM+GeS2
+7zhu1yeEXv+i9iySFPbYydy851uVip7oqsbNM4iGYpS5ERND9XYuhSGUFI5p9ik
Nsvz+z7r4iT2rd8vrwIDAQAB
-----END PUBLIC KEY-----)";
std::string KeyString = rsaDecrypt(base64_decode(Key), pub);
std::vector<std::string> BaseDataBuffer;
Tool::Split(Script, BaseDataBuffer, "$$$$$");
size_t Ds = BaseDataBuffer.size();
int RealKey[20] = {0};
// 转换字符串到数组
for (size_t i = 0; i < KeyString.length() && i < 20; ++i) {
RealKey[i] = KeyString[i] - '0'; // 将字符转换为对应的数字
}
std::vector<std::string> BaseData;
for (size_t i = 0; i < (Ds - 1); i++) {
std::string str = BaseDataBuffer[i];
if (i % 2 != 0) {
// 得到有多少个逗号
std::vector<std::string> Data;
Tool::Split(str, Data, ", ");
size_t DDs = Data.size();
char *nutstr = new char[DDs + 1];
for (size_t s = 0; s < DDs; s++) {
nutstr[s] = char(atoi(Data[s].c_str()));
}
Cutecode(nutstr, RealKey, DDs, 20); // 解密
nutstr[DDs] = '\0';
std::string RealStr(nutstr, DDs + 1);
delete[] nutstr;
BaseData.push_back(RealStr);
} else {
BaseData.push_back(str);
}
}
for (size_t i = 0; i < BaseData.size(); i += 2) {
std::string Path = BaseData[i];
std::string Script = BaseData[i + 1];
// std::cout << Path << std::endl;
if (SQ_SUCCEEDED(sq_compilebuffer(v, (SQChar *)(Script.c_str()),
Script.length(), (SQChar *)(Path.c_str()),
true))) {
sq_pushroottable(v);
sq_call(v, 1, 1, 1);
sq_pop(v, 1);
}
}
}

View File

@@ -1,383 +0,0 @@
#pragma once
#include <iostream>
#include <iconv.h>
#include <vector>
#include <dirent.h>
#include <string.h>
#include "squirrel.h"
#include <nlohmann/json.hpp>
using json = nlohmann::json;
class Tool
{
private:
/* data */
public:
Tool(/* args */);
~Tool();
// 将小端序列 转为int
static int ByteLittleToInt(unsigned char *Count);
public:
// 错误输出
static void Error(std::string E);
// 警告输出
static void Warring(std::string W);
// 常规输出
static void Logger(std::string L);
//分割字符串
static void Split(const std::string &src, std::vector<std::string> &dest, const std::string &separator);
// 获取当前时间戳
static long long get_cur_time();
static int UTF8ToGB2312(char *szSrc, size_t iSrcLen, char *szDst, size_t iDstLen);
static int GB2312ToUTF8(char *szSrc, size_t iSrcLen, char *szDst, size_t iDstLen);
// 输出字节数组
static void printUint8Array(uint8_t *array, size_t length)
{
for (size_t i = 0; i < length; ++i)
{
std::cout << static_cast<int>(array[i]);
if (i != length - 1)
{
std::cout << ", "; // 添加逗号分隔符
}
}
std::cout << std::endl;
}
// 批量替换字符串中文本
static std::string &ReplaceAll(std::string &str, const std::string &src, const std::string &dst)
{
std::string::size_type pos(0);
while (true)
{
if ((pos = str.find(src)) != std::string::npos)
{
str.replace(pos, src.length(), dst);
}
else
{
break;
}
}
return str;
}
// 遍历指定文件夹下的所有文件,不包括指定文件夹内的文件夹
static std::vector<std::string> GetListFiles(const std::string &path, const std::string &exten = "*")
{
std::vector<std::string> list;
list.clear();
DIR *dp = NULL;
struct dirent *dirp = NULL;
if ((dp = opendir(path.c_str())) == NULL)
{
return list;
}
while ((dirp = readdir(dp)) != NULL)
{
if (dirp->d_type == DT_REG)
{
if (exten.compare("*") == 0)
list.emplace_back(static_cast<std::string>(dirp->d_name));
else if (std::string(dirp->d_name).find(exten) != std::string::npos)
list.emplace_back(static_cast<std::string>(dirp->d_name));
}
}
closedir(dp);
return list;
}
// 遍历指定文件夹下的所有文件夹,不包括指定文件夹下的文件
static std::vector<std::string> GetListFolders(const std::string &path, const std::string &exten = "*")
{
std::vector<std::string> list;
list.clear();
DIR *dp = NULL;
struct dirent *dirp = NULL;
if ((dp = opendir(path.c_str())) == NULL)
{
return list;
}
while ((dirp = readdir(dp)) != NULL)
{
if (dirp->d_type == DT_DIR && strcmp(dirp->d_name, ".") != 0 && strcmp(dirp->d_name, "..") != 0)
{
if (exten.compare("*") == 0)
list.emplace_back(static_cast<std::string>(dirp->d_name));
else if (std::string(dirp->d_name).find(exten) != std::string::npos)
list.emplace_back(static_cast<std::string>(dirp->d_name));
}
}
closedir(dp);
return list;
}
// 遍历指定文件夹下的所有文件,包括指定文件夹内的文件夹
static std::vector<std::string> GetListFilesR(const std::string &path, const std::string &exten = "*")
{
std::vector<std::string> list = Tool::GetListFiles(path, exten);
std::vector<std::string> dirs = Tool::GetListFolders(path, exten);
// 遍历目录
for (auto it = dirs.cbegin(); it != dirs.cend(); ++it)
{
// 递归调用扫完
std::vector<std::string> dirsvecBuf = Tool::GetListFilesR(path + "/" + *it);
if (dirsvecBuf.size() > 0)
{
for (auto dirsvecBufF = dirsvecBuf.cbegin(); dirsvecBufF != dirsvecBuf.cend(); ++dirsvecBufF)
{
list.emplace_back(*it + "/" + *dirsvecBufF);
}
}
}
return list;
}
// 序列化Array为字符串
static std::string EncodeARRAY(HSQUIRRELVM v, std::string Jso)
{
Jso += "[";
sq_pushnull(v);
while (SQ_SUCCEEDED(sq_next(v, -2)))
{
SQObjectType Type = sq_gettype(v, -1);
switch (Type)
{
case OT_INTEGER:
{
SQInteger value;
sq_getinteger(v, -1, &value);
Jso += std::to_string(value);
Jso += ",";
}
break;
case OT_FLOAT:
{
SQFloat value;
sq_getfloat(v, -1, &value);
Jso += std::to_string(value);
Jso += ",";
}
break;
case OT_BOOL:
{
SQBool value;
sq_getbool(v, -1, &value);
Jso += std::to_string(value);
Jso += ",";
}
break;
case OT_STRING:
{
const SQChar *value;
sq_getstring(v, -1, &value);
std::string vstr = value;
Jso += "\"";
Jso += vstr;
Jso += "\"";
Jso += ",";
}
break;
case OT_TABLE:
{
SQInteger Top = sq_gettop(v);
SQObject obj;
sq_getstackobj(v, -1, &obj);
sq_pushobject(v, obj);
Jso = EncodeTABLE(v, Jso);
sq_settop(v, Top);
Jso += ",";
}
break;
case OT_ARRAY:
{
SQInteger Top = sq_gettop(v);
SQObject obj;
sq_getstackobj(v, -1, &obj);
sq_pushobject(v, obj);
Jso = EncodeARRAY(v, Jso);
sq_settop(v, Top);
Jso += ",";
}
break;
default:
break;
}
// 这里-1是值-2是键
sq_pop(v, 2); // 在下一次迭代之前弹出键和值
}
sq_pop(v, 1); // 在下一次迭代之前弹出键和值
Jso = Jso.substr(0, Jso.length() - 1);
Jso += "]";
return Jso;
}
// 序列化Table为字符串
static std::string EncodeTABLE(HSQUIRRELVM v, std::string Jso)
{
Jso += "{";
sq_pushnull(v); // null iterator
while (SQ_SUCCEEDED(sq_next(v, -2)))
{
const SQChar *Key;
sq_getstring(v, -2, &Key);
std::string str = Key;
Jso += "\"";
Jso += str;
Jso += "\"";
Jso += ":";
SQObjectType Type = sq_gettype(v, -1);
switch (Type)
{
case OT_INTEGER:
{
SQInteger value;
sq_getinteger(v, -1, &value);
Jso += std::to_string(value);
Jso += ",";
}
break;
case OT_FLOAT:
{
SQFloat value;
sq_getfloat(v, -1, &value);
Jso += std::to_string(value);
Jso += ",";
}
break;
case OT_BOOL:
{
SQBool value;
sq_getbool(v, -1, &value);
Jso += std::to_string(value);
Jso += ",";
}
break;
case OT_STRING:
{
const SQChar *value;
sq_getstring(v, -1, &value);
std::string vstr = value;
Jso += "\"";
Jso += vstr;
Jso += "\"";
Jso += ",";
}
break;
case OT_TABLE:
{
SQInteger Top = sq_gettop(v);
SQObject obj;
sq_getstackobj(v, -1, &obj);
sq_pushobject(v, obj);
Jso = Tool::EncodeTABLE(v, Jso);
sq_settop(v, Top);
Jso += ",";
}
break;
case OT_ARRAY:
{
SQInteger Top = sq_gettop(v);
SQObject obj;
sq_getstackobj(v, -1, &obj);
sq_pushobject(v, obj);
Jso = Tool::EncodeARRAY(v, Jso);
sq_settop(v, Top);
Jso += ",";
}
break;
default:
break;
}
// 这里-1是值-2是键
sq_pop(v, 2); // 在下一次迭代之前弹出键和值
}
sq_pop(v, 1); // 在下一次迭代之前弹出键和值
Jso = Jso.substr(0, Jso.length() - 1);
Jso += "}";
return Jso;
}
};
static void push_squirrel_value(HSQUIRRELVM vm, const json &j)
{
switch (j.type())
{
case json::value_t::object:
{
sq_newtable(vm);
for (auto &item : j.items())
{
const std::string &key = item.key();
auto &value = item.value(); // 根据实际类型可能需要改为 const auto&
sq_pushstring(vm, key.c_str(), -1);
push_squirrel_value(vm, value);
sq_createslot(vm, -3);
}
break;
}
case json::value_t::array:
{
sq_newarray(vm, 0);
for (const auto &item : j)
{
push_squirrel_value(vm, item);
sq_arrayappend(vm, -2);
}
break;
}
case json::value_t::string:
sq_pushstring(vm, j.get<std::string>().c_str(), -1);
break;
case json::value_t::boolean:
sq_pushbool(vm, j.get<bool>() ? SQTrue : SQFalse);
break;
case json::value_t::number_integer:
sq_pushinteger(vm, j.get<SQInteger>());
break;
case json::value_t::number_unsigned:
{
auto val = j.get<uint64_t>();
if (val > static_cast<uint64_t>(std::numeric_limits<SQInteger>::max()))
{
sq_pushfloat(vm, static_cast<SQFloat>(val));
}
else
{
sq_pushinteger(vm, static_cast<SQInteger>(val));
}
break;
}
case json::value_t::number_float:
sq_pushfloat(vm, j.get<SQFloat>());
break;
case json::value_t::null:
sq_pushnull(vm);
break;
default:
sq_pushnull(vm);
break;
}
}

View File

@@ -1,929 +0,0 @@
#pragma once
#include <vector>
#include <string>
#include <sstream>
#include <bitset>
#include <cctype>
#include <ctime>
#include <iomanip>
#include <algorithm>
#include <chrono>
#if __cplusplus > 201402L
#include <string_view>
#define CRONCPP_IS_CPP17
#endif
namespace cron
{
#ifdef CRONCPP_IS_CPP17
#define CRONCPP_STRING_VIEW std::string_view
#define CRONCPP_STRING_VIEW_NPOS std::string_view::npos
#define CRONCPP_CONSTEXPTR constexpr
#else
#define CRONCPP_STRING_VIEW std::string const &
#define CRONCPP_STRING_VIEW_NPOS std::string::npos
#define CRONCPP_CONSTEXPTR
#endif
using cron_int = uint8_t;
constexpr std::time_t INVALID_TIME = static_cast<std::time_t>(-1);
constexpr size_t INVALID_INDEX = static_cast<size_t>(-1);
class cronexpr;
namespace detail
{
enum class cron_field
{
second,
minute,
hour_of_day,
day_of_week,
day_of_month,
month,
year
};
template <typename Traits>
static bool find_next(cronexpr const &cex,
std::tm &date,
size_t const dot);
}
struct bad_cronexpr : public std::runtime_error
{
public:
explicit bad_cronexpr(CRONCPP_STRING_VIEW message) : std::runtime_error(message.data())
{
}
};
struct cron_standard_traits
{
static const cron_int CRON_MIN_SECONDS = 0;
static const cron_int CRON_MAX_SECONDS = 59;
static const cron_int CRON_MIN_MINUTES = 0;
static const cron_int CRON_MAX_MINUTES = 59;
static const cron_int CRON_MIN_HOURS = 0;
static const cron_int CRON_MAX_HOURS = 23;
static const cron_int CRON_MIN_DAYS_OF_WEEK = 0;
static const cron_int CRON_MAX_DAYS_OF_WEEK = 6;
static const cron_int CRON_MIN_DAYS_OF_MONTH = 1;
static const cron_int CRON_MAX_DAYS_OF_MONTH = 31;
static const cron_int CRON_MIN_MONTHS = 1;
static const cron_int CRON_MAX_MONTHS = 12;
static const cron_int CRON_MAX_YEARS_DIFF = 4;
#ifdef CRONCPP_IS_CPP17
static const inline std::vector<std::string> DAYS = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
static const inline std::vector<std::string> MONTHS = {"NIL", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
#else
static std::vector<std::string> &DAYS()
{
static std::vector<std::string> days = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
return days;
}
static std::vector<std::string> &MONTHS()
{
static std::vector<std::string> months = {"NIL", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
return months;
}
#endif
};
struct cron_oracle_traits
{
static const cron_int CRON_MIN_SECONDS = 0;
static const cron_int CRON_MAX_SECONDS = 59;
static const cron_int CRON_MIN_MINUTES = 0;
static const cron_int CRON_MAX_MINUTES = 59;
static const cron_int CRON_MIN_HOURS = 0;
static const cron_int CRON_MAX_HOURS = 23;
static const cron_int CRON_MIN_DAYS_OF_WEEK = 1;
static const cron_int CRON_MAX_DAYS_OF_WEEK = 7;
static const cron_int CRON_MIN_DAYS_OF_MONTH = 1;
static const cron_int CRON_MAX_DAYS_OF_MONTH = 31;
static const cron_int CRON_MIN_MONTHS = 0;
static const cron_int CRON_MAX_MONTHS = 11;
static const cron_int CRON_MAX_YEARS_DIFF = 4;
#ifdef CRONCPP_IS_CPP17
static const inline std::vector<std::string> DAYS = {"NIL", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
static const inline std::vector<std::string> MONTHS = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
#else
static std::vector<std::string> &DAYS()
{
static std::vector<std::string> days = {"NIL", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
return days;
}
static std::vector<std::string> &MONTHS()
{
static std::vector<std::string> months = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
return months;
}
#endif
};
struct cron_quartz_traits
{
static const cron_int CRON_MIN_SECONDS = 0;
static const cron_int CRON_MAX_SECONDS = 59;
static const cron_int CRON_MIN_MINUTES = 0;
static const cron_int CRON_MAX_MINUTES = 59;
static const cron_int CRON_MIN_HOURS = 0;
static const cron_int CRON_MAX_HOURS = 23;
static const cron_int CRON_MIN_DAYS_OF_WEEK = 1;
static const cron_int CRON_MAX_DAYS_OF_WEEK = 7;
static const cron_int CRON_MIN_DAYS_OF_MONTH = 1;
static const cron_int CRON_MAX_DAYS_OF_MONTH = 31;
static const cron_int CRON_MIN_MONTHS = 1;
static const cron_int CRON_MAX_MONTHS = 12;
static const cron_int CRON_MAX_YEARS_DIFF = 4;
#ifdef CRONCPP_IS_CPP17
static const inline std::vector<std::string> DAYS = {"NIL", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
static const inline std::vector<std::string> MONTHS = {"NIL", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
#else
static std::vector<std::string> &DAYS()
{
static std::vector<std::string> days = {"NIL", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
return days;
}
static std::vector<std::string> &MONTHS()
{
static std::vector<std::string> months = {"NIL", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
return months;
}
#endif
};
class cronexpr;
template <typename Traits = cron_standard_traits>
static cronexpr make_cron(CRONCPP_STRING_VIEW expr);
class cronexpr
{
std::bitset<60> seconds;
std::bitset<60> minutes;
std::bitset<24> hours;
std::bitset<7> days_of_week;
std::bitset<31> days_of_month;
std::bitset<12> months;
std::string expr;
friend bool operator==(cronexpr const &e1, cronexpr const &e2);
friend bool operator!=(cronexpr const &e1, cronexpr const &e2);
template <typename Traits>
friend bool detail::find_next(cronexpr const &cex,
std::tm &date,
size_t const dot);
friend std::string to_cronstr(cronexpr const &cex);
friend std::string to_string(cronexpr const &cex);
template <typename Traits>
friend cronexpr make_cron(CRONCPP_STRING_VIEW expr);
};
inline bool operator==(cronexpr const &e1, cronexpr const &e2)
{
return e1.seconds == e2.seconds &&
e1.minutes == e2.minutes &&
e1.hours == e2.hours &&
e1.days_of_week == e2.days_of_week &&
e1.days_of_month == e2.days_of_month &&
e1.months == e2.months;
}
inline bool operator!=(cronexpr const &e1, cronexpr const &e2)
{
return !(e1 == e2);
}
inline std::string to_string(cronexpr const &cex)
{
return cex.seconds.to_string() + " " +
cex.minutes.to_string() + " " +
cex.hours.to_string() + " " +
cex.days_of_month.to_string() + " " +
cex.months.to_string() + " " +
cex.days_of_week.to_string();
}
inline std::string to_cronstr(cronexpr const &cex)
{
return cex.expr;
}
namespace utils
{
inline std::time_t tm_to_time(std::tm &date)
{
return std::mktime(&date);
}
inline std::tm *time_to_tm(std::time_t const *date, std::tm *const out)
{
#ifdef _WIN32
errno_t err = localtime_s(out, date);
return 0 == err ? out : nullptr;
#else
return localtime_r(date, out);
#endif
}
inline std::tm to_tm(CRONCPP_STRING_VIEW time)
{
std::tm result;
#if __cplusplus > 201103L
std::istringstream str(time.data());
str.imbue(std::locale(setlocale(LC_ALL, nullptr)));
str >> std::get_time(&result, "%Y-%m-%d %H:%M:%S");
if (str.fail())
throw std::runtime_error("Parsing date failed!");
#else
int year = 1900;
int month = 1;
int day = 1;
int hour = 0;
int minute = 0;
int second = 0;
sscanf(time.data(), "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minute, &second);
result.tm_year = year - 1900;
result.tm_mon = month - 1;
result.tm_mday = day;
result.tm_hour = hour;
result.tm_min = minute;
result.tm_sec = second;
#endif
result.tm_isdst = -1; // DST info not available
return result;
}
inline std::string to_string(std::tm const &tm)
{
#if __cplusplus > 201103L
std::ostringstream str;
str.imbue(std::locale(setlocale(LC_ALL, nullptr)));
str << std::put_time(&tm, "%Y-%m-%d %H:%M:%S");
if (str.fail())
throw std::runtime_error("Writing date failed!");
return str.str();
#else
char buff[70] = {0};
strftime(buff, sizeof(buff), "%Y-%m-%d %H:%M:%S", &tm);
return std::string(buff);
#endif
}
inline std::string to_upper(std::string text)
{
std::transform(std::begin(text), std::end(text),
std::begin(text), [](char const c)
{ return static_cast<char>(std::toupper(c)); });
return text;
}
static std::vector<std::string> split(CRONCPP_STRING_VIEW text, char const delimiter)
{
std::vector<std::string> tokens;
std::string token;
std::istringstream tokenStream(text.data());
while (std::getline(tokenStream, token, delimiter))
{
tokens.push_back(token);
}
return tokens;
}
CRONCPP_CONSTEXPTR inline bool contains(CRONCPP_STRING_VIEW text, char const ch) noexcept
{
return CRONCPP_STRING_VIEW_NPOS != text.find_first_of(ch);
}
}
namespace detail
{
inline cron_int to_cron_int(CRONCPP_STRING_VIEW text)
{
try
{
return static_cast<cron_int>(std::stoul(text.data()));
}
catch (std::exception const &ex)
{
throw bad_cronexpr(ex.what());
}
}
static std::string replace_ordinals(
std::string text,
std::vector<std::string> const &replacement)
{
for (size_t i = 0; i < replacement.size(); ++i)
{
auto pos = text.find(replacement[i]);
if (std::string::npos != pos)
text.replace(pos, 3, std::to_string(i));
}
return text;
}
static std::pair<cron_int, cron_int> make_range(
CRONCPP_STRING_VIEW field,
cron_int const minval,
cron_int const maxval)
{
cron_int first = 0;
cron_int last = 0;
if (field.size() == 1 && field[0] == '*')
{
first = minval;
last = maxval;
}
else if (!utils::contains(field, '-'))
{
first = to_cron_int(field);
last = first;
}
else
{
auto parts = utils::split(field, '-');
if (parts.size() != 2)
throw bad_cronexpr("Specified range requires two fields");
first = to_cron_int(parts[0]);
last = to_cron_int(parts[1]);
}
if (first > maxval || last > maxval)
{
throw bad_cronexpr("Specified range exceeds maximum");
}
if (first < minval || last < minval)
{
throw bad_cronexpr("Specified range is less than minimum");
}
if (first > last)
{
throw bad_cronexpr("Specified range start exceeds range end");
}
return {first, last};
}
template <size_t N>
static void set_cron_field(
CRONCPP_STRING_VIEW value,
std::bitset<N> &target,
cron_int const minval,
cron_int const maxval)
{
if (value.length() > 0 && value[value.length() - 1] == ',')
throw bad_cronexpr("Value cannot end with comma");
auto fields = utils::split(value, ',');
if (fields.empty())
throw bad_cronexpr("Expression parsing error");
for (auto const &field : fields)
{
if (!utils::contains(field, '/'))
{
#ifdef CRONCPP_IS_CPP17
auto [first, last] = detail::make_range(field, minval, maxval);
#else
auto range = detail::make_range(field, minval, maxval);
auto first = range.first;
auto last = range.second;
#endif
for (cron_int i = first - minval; i <= last - minval; ++i)
{
target.set(i);
}
}
else
{
auto parts = utils::split(field, '/');
if (parts.size() != 2)
throw bad_cronexpr("Incrementer must have two fields");
#ifdef CRONCPP_IS_CPP17
auto [first, last] = detail::make_range(parts[0], minval, maxval);
#else
auto range = detail::make_range(parts[0], minval, maxval);
auto first = range.first;
auto last = range.second;
#endif
if (!utils::contains(parts[0], '-'))
{
last = maxval;
}
auto delta = detail::to_cron_int(parts[1]);
if (delta <= 0)
throw bad_cronexpr("Incrementer must be a positive value");
for (cron_int i = first - minval; i <= last - minval; i += delta)
{
target.set(i);
}
}
}
}
template <typename Traits>
static void set_cron_days_of_week(
std::string value,
std::bitset<7> &target)
{
auto days = utils::to_upper(value);
auto days_replaced = detail::replace_ordinals(
days,
#ifdef CRONCPP_IS_CPP17
Traits::DAYS
#else
Traits::DAYS()
#endif
);
if (days_replaced.size() == 1 && days_replaced[0] == '?')
days_replaced[0] = '*';
set_cron_field(
days_replaced,
target,
Traits::CRON_MIN_DAYS_OF_WEEK,
Traits::CRON_MAX_DAYS_OF_WEEK);
}
template <typename Traits>
static void set_cron_days_of_month(
std::string value,
std::bitset<31> &target)
{
if (value.size() == 1 && value[0] == '?')
value[0] = '*';
set_cron_field(
value,
target,
Traits::CRON_MIN_DAYS_OF_MONTH,
Traits::CRON_MAX_DAYS_OF_MONTH);
}
template <typename Traits>
static void set_cron_month(
std::string value,
std::bitset<12> &target)
{
auto month = utils::to_upper(value);
auto month_replaced = replace_ordinals(
month,
#ifdef CRONCPP_IS_CPP17
Traits::MONTHS
#else
Traits::MONTHS()
#endif
);
set_cron_field(
month_replaced,
target,
Traits::CRON_MIN_MONTHS,
Traits::CRON_MAX_MONTHS);
}
template <size_t N>
inline size_t next_set_bit(
std::bitset<N> const &target,
size_t /*minimum*/,
size_t /*maximum*/,
size_t offset)
{
for (auto i = offset; i < N; ++i)
{
if (target.test(i))
return i;
}
return INVALID_INDEX;
}
inline void add_to_field(
std::tm &date,
cron_field const field,
int const val)
{
switch (field)
{
case cron_field::second:
date.tm_sec += val;
break;
case cron_field::minute:
date.tm_min += val;
break;
case cron_field::hour_of_day:
date.tm_hour += val;
break;
case cron_field::day_of_week:
case cron_field::day_of_month:
date.tm_mday += val;
date.tm_isdst = -1;
break;
case cron_field::month:
date.tm_mon += val;
date.tm_isdst = -1;
break;
case cron_field::year:
date.tm_year += val;
break;
}
if (INVALID_TIME == utils::tm_to_time(date))
throw bad_cronexpr("Invalid time expression");
}
inline void set_field(
std::tm &date,
cron_field const field,
int const val)
{
switch (field)
{
case cron_field::second:
date.tm_sec = val;
break;
case cron_field::minute:
date.tm_min = val;
break;
case cron_field::hour_of_day:
date.tm_hour = val;
break;
case cron_field::day_of_week:
date.tm_wday = val;
break;
case cron_field::day_of_month:
date.tm_mday = val;
date.tm_isdst = -1;
break;
case cron_field::month:
date.tm_mon = val;
date.tm_isdst = -1;
break;
case cron_field::year:
date.tm_year = val;
break;
}
if (INVALID_TIME == utils::tm_to_time(date))
throw bad_cronexpr("Invalid time expression");
}
inline void reset_field(
std::tm &date,
cron_field const field)
{
switch (field)
{
case cron_field::second:
date.tm_sec = 0;
break;
case cron_field::minute:
date.tm_min = 0;
break;
case cron_field::hour_of_day:
date.tm_hour = 0;
break;
case cron_field::day_of_week:
date.tm_wday = 0;
break;
case cron_field::day_of_month:
date.tm_mday = 1;
date.tm_isdst = -1;
break;
case cron_field::month:
date.tm_mon = 0;
date.tm_isdst = -1;
break;
case cron_field::year:
date.tm_year = 0;
break;
}
if (INVALID_TIME == utils::tm_to_time(date))
throw bad_cronexpr("Invalid time expression");
}
inline void reset_all_fields(
std::tm &date,
std::bitset<7> const &marked_fields)
{
for (size_t i = 0; i < marked_fields.size(); ++i)
{
if (marked_fields.test(i))
reset_field(date, static_cast<cron_field>(i));
}
}
inline void mark_field(
std::bitset<7> &orders,
cron_field const field)
{
if (!orders.test(static_cast<size_t>(field)))
orders.set(static_cast<size_t>(field));
}
template <size_t N>
static size_t find_next(
std::bitset<N> const &target,
std::tm &date,
unsigned int const minimum,
unsigned int const maximum,
unsigned int const value,
cron_field const field,
cron_field const next_field,
std::bitset<7> const &marked_fields)
{
auto next_value = next_set_bit(target, minimum, maximum, value);
if (INVALID_INDEX == next_value)
{
add_to_field(date, next_field, 1);
reset_field(date, field);
next_value = next_set_bit(target, minimum, maximum, 0);
}
if (INVALID_INDEX == next_value || next_value != value)
{
set_field(date, field, static_cast<int>(next_value));
reset_all_fields(date, marked_fields);
}
return next_value;
}
template <typename Traits>
static size_t find_next_day(
std::tm &date,
std::bitset<31> const &days_of_month,
size_t day_of_month,
std::bitset<7> const &days_of_week,
size_t day_of_week,
std::bitset<7> const &marked_fields)
{
unsigned int count = 0;
unsigned int maximum = 366;
while (
(!days_of_month.test(day_of_month - Traits::CRON_MIN_DAYS_OF_MONTH) ||
!days_of_week.test(day_of_week - Traits::CRON_MIN_DAYS_OF_WEEK)) &&
count++ < maximum)
{
add_to_field(date, cron_field::day_of_month, 1);
day_of_month = date.tm_mday;
day_of_week = date.tm_wday;
reset_all_fields(date, marked_fields);
}
return day_of_month;
}
template <typename Traits>
static bool find_next(cronexpr const &cex,
std::tm &date,
size_t const dot)
{
bool res = true;
std::bitset<7> marked_fields{0};
std::bitset<7> empty_list{0};
unsigned int second = date.tm_sec;
auto updated_second = find_next(
cex.seconds,
date,
Traits::CRON_MIN_SECONDS,
Traits::CRON_MAX_SECONDS,
second,
cron_field::second,
cron_field::minute,
empty_list);
if (second == updated_second)
{
mark_field(marked_fields, cron_field::second);
}
unsigned int minute = date.tm_min;
auto update_minute = find_next(
cex.minutes,
date,
Traits::CRON_MIN_MINUTES,
Traits::CRON_MAX_MINUTES,
minute,
cron_field::minute,
cron_field::hour_of_day,
marked_fields);
if (minute == update_minute)
{
mark_field(marked_fields, cron_field::minute);
}
else
{
res = find_next<Traits>(cex, date, dot);
if (!res)
return res;
}
unsigned int hour = date.tm_hour;
auto updated_hour = find_next(
cex.hours,
date,
Traits::CRON_MIN_HOURS,
Traits::CRON_MAX_HOURS,
hour,
cron_field::hour_of_day,
cron_field::day_of_week,
marked_fields);
if (hour == updated_hour)
{
mark_field(marked_fields, cron_field::hour_of_day);
}
else
{
res = find_next<Traits>(cex, date, dot);
if (!res)
return res;
}
unsigned int day_of_week = date.tm_wday;
unsigned int day_of_month = date.tm_mday;
auto updated_day_of_month = find_next_day<Traits>(
date,
cex.days_of_month,
day_of_month,
cex.days_of_week,
day_of_week,
marked_fields);
if (day_of_month == updated_day_of_month)
{
mark_field(marked_fields, cron_field::day_of_month);
}
else
{
res = find_next<Traits>(cex, date, dot);
if (!res)
return res;
}
unsigned int month = date.tm_mon;
auto updated_month = find_next(
cex.months,
date,
Traits::CRON_MIN_MONTHS,
Traits::CRON_MAX_MONTHS,
month,
cron_field::month,
cron_field::year,
marked_fields);
if (month != updated_month)
{
if (date.tm_year - dot > Traits::CRON_MAX_YEARS_DIFF)
return false;
res = find_next<Traits>(cex, date, dot);
if (!res)
return res;
}
return res;
}
}
template <typename Traits>
static cronexpr make_cron(CRONCPP_STRING_VIEW expr)
{
cronexpr cex;
if (expr.empty())
throw bad_cronexpr("Invalid empty cron expression");
auto fields = utils::split(expr, ' ');
fields.erase(
std::remove_if(std::begin(fields), std::end(fields),
[](CRONCPP_STRING_VIEW s)
{ return s.empty(); }),
std::end(fields));
if (fields.size() != 6)
throw bad_cronexpr("cron expression must have six fields");
detail::set_cron_field(fields[0], cex.seconds, Traits::CRON_MIN_SECONDS, Traits::CRON_MAX_SECONDS);
detail::set_cron_field(fields[1], cex.minutes, Traits::CRON_MIN_MINUTES, Traits::CRON_MAX_MINUTES);
detail::set_cron_field(fields[2], cex.hours, Traits::CRON_MIN_HOURS, Traits::CRON_MAX_HOURS);
detail::set_cron_days_of_week<Traits>(fields[5], cex.days_of_week);
detail::set_cron_days_of_month<Traits>(fields[3], cex.days_of_month);
detail::set_cron_month<Traits>(fields[4], cex.months);
cex.expr = expr;
return cex;
}
template <typename Traits = cron_standard_traits>
static std::tm cron_next(cronexpr const &cex, std::tm date)
{
time_t original = utils::tm_to_time(date);
if (INVALID_TIME == original)
return {};
if (!detail::find_next<Traits>(cex, date, date.tm_year))
return {};
time_t calculated = utils::tm_to_time(date);
if (INVALID_TIME == calculated)
return {};
if (calculated == original)
{
add_to_field(date, detail::cron_field::second, 1);
if (!detail::find_next<Traits>(cex, date, date.tm_year))
return {};
}
return date;
}
template <typename Traits = cron_standard_traits>
static std::time_t cron_next(cronexpr const &cex, std::time_t const &date)
{
std::tm val;
std::tm *dt = utils::time_to_tm(&date, &val);
if (dt == nullptr)
return INVALID_TIME;
time_t original = utils::tm_to_time(*dt);
if (INVALID_TIME == original)
return INVALID_TIME;
if (!detail::find_next<Traits>(cex, *dt, dt->tm_year))
return INVALID_TIME;
time_t calculated = utils::tm_to_time(*dt);
if (INVALID_TIME == calculated)
return calculated;
if (calculated == original)
{
add_to_field(*dt, detail::cron_field::second, 1);
if (!detail::find_next<Traits>(cex, *dt, dt->tm_year))
return INVALID_TIME;
}
return utils::tm_to_time(*dt);
}
template <typename Traits = cron_standard_traits>
static std::chrono::system_clock::time_point cron_next(cronexpr const &cex, std::chrono::system_clock::time_point const &time_point)
{
return std::chrono::system_clock::from_time_t(cron_next<Traits>(cex, std::chrono::system_clock::to_time_t(time_point)));
}
}

View File

@@ -1,18 +0,0 @@
#pragma once
#include <dlfcn.h>
typedef struct lua_State lua_State;
typedef void (*dp2_game_script_t)(void(*ufptr)(lua_State* L, void*), void* udptr);
// 进入dp的锁, 触发回调, 同时获得lua指针
static int dp2_game_script(void(*ufptr)(lua_State* L, void*), void* udptr) {
void* fn = dlsym(RTLD_DEFAULT, "__dp2_game_script");
if (!fn) {
return 1;
}
dp2_game_script_t func = (dp2_game_script_t)fn;
printf("\n函数\n");
func(ufptr, udptr);
printf("\n调用成功\n");
return 0;
}

View File

@@ -1,169 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <ffi.h>
// #include "fficonfig.h"
#include <float.h>
#include <math.h>
#if defined HAVE_STDINT_H
#include <stdint.h>
#endif
#if defined HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#define MAX_ARGS 256
#define CHECK(x) \
do \
{ \
if (!(x)) \
{ \
printf("Check failed:\n%s\n", #x); \
abort(); \
} \
} while (0)
#define CHECK_FLOAT_EQ(x, y) \
do \
{ \
if (fabs((x) - (y)) > FLT_EPSILON) \
{ \
printf("Check failed CHECK_FLOAT_EQ(%s, %s)\n", #x, #y); \
abort(); \
} \
} while (0)
#define CHECK_DOUBLE_EQ(x, y) \
do \
{ \
if (fabs((x) - (y)) > DBL_EPSILON) \
{ \
printf("Check failed CHECK_FLOAT_EQ(%s, %s)\n", #x, #y); \
abort(); \
} \
} while (0)
/* Define macros so that compilers other than gcc can run the tests. */
#undef __UNUSED__
#if defined(__GNUC__)
#define __UNUSED__ __attribute__((__unused__))
#define __STDCALL__ __attribute__((stdcall))
#define __THISCALL__ __attribute__((thiscall))
#define __FASTCALL__ __attribute__((fastcall))
#define __MSABI__ __attribute__((ms_abi))
#else
#define __UNUSED__
#define __STDCALL__ __stdcall
#define __THISCALL__ __thiscall
#define __FASTCALL__ __fastcall
#endif
#ifndef ABI_NUM
#define ABI_NUM FFI_DEFAULT_ABI
#define ABI_ATTR
#endif
/* Prefer MAP_ANON(YMOUS) to /dev/zero, since we don't need to keep a
file open. */
#ifdef HAVE_MMAP_ANON
#undef HAVE_MMAP_DEV_ZERO
#include <sys/mman.h>
#ifndef MAP_FAILED
#define MAP_FAILED -1
#endif
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
#define MAP_ANONYMOUS MAP_ANON
#endif
#define USING_MMAP
#endif
#ifdef HAVE_MMAP_DEV_ZERO
#include <sys/mman.h>
#ifndef MAP_FAILED
#define MAP_FAILED -1
#endif
#define USING_MMAP
#endif
/* msvc kludge. */
#if defined(_MSC_VER)
#define PRIdLL "I64d"
#define PRIuLL "I64u"
#else
#define PRIdLL "lld"
#define PRIuLL "llu"
#endif
/* Tru64 UNIX kludge. */
#if defined(__alpha__) && defined(__osf__)
/* Tru64 UNIX V4.0 doesn't support %lld/%lld, but long is 64-bit. */
#undef PRIdLL
#define PRIdLL "ld"
#undef PRIuLL
#define PRIuLL "lu"
#define PRId8 "hd"
#define PRIu8 "hu"
#define PRId64 "ld"
#define PRIu64 "lu"
#define PRIuPTR "lu"
#endif
/* PA HP-UX kludge. */
#if defined(__hppa__) && defined(__hpux__) && !defined(PRIuPTR)
#define PRIuPTR "lu"
#endif
/* IRIX kludge. */
#if defined(__sgi)
/* IRIX 6.5 <inttypes.h> provides all definitions, but only for C99
compilations. */
#define PRId8 "hhd"
#define PRIu8 "hhu"
#if (_MIPS_SZLONG == 32)
#define PRId64 "lld"
#define PRIu64 "llu"
#endif
/* This doesn't match <inttypes.h>, which always has "lld" here, but the
arguments are uint64_t, int64_t, which are unsigned long, long for
64-bit in <sgidefs.h>. */
#if (_MIPS_SZLONG == 64)
#define PRId64 "ld"
#define PRIu64 "lu"
#endif
/* This doesn't match <inttypes.h>, which has "u" here, but the arguments
are uintptr_t, which is always unsigned long. */
#define PRIuPTR "lu"
#endif
/* Solaris < 10 kludge. */
#if defined(__sun__) && defined(__svr4__) && !defined(PRIuPTR)
#if defined(__arch64__) || defined(__x86_64__)
#define PRIuPTR "lu"
#else
#define PRIuPTR "u"
#endif
#endif
/* MSVC kludge. */
#if defined _MSC_VER
#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS)
#define PRIuPTR "lu"
#define PRIu8 "u"
#define PRId8 "d"
#define PRIu64 "I64u"
#define PRId64 "I64d"
#endif
#endif
#ifndef PRIuPTR
#define PRIuPTR "u"
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,340 +0,0 @@
#pragma once
#include "Singleton.h"
#include "l_squirrel.h"
#include <array>
#include <asio.hpp>
#include <cstring>
#include <deque>
#include <fstream>
#include <iostream>
#include <memory>
#include <mutex>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/spdlog.h>
#include <string>
#include <unistd.h>
#include <vector>
extern HSQUIRRELVM v;
extern std::recursive_mutex SqMtx;
using namespace asio;
using asio::ip::tcp;
class Client
{
private:
struct PendingEvent
{
enum class Type
{
Connect,
Message
};
Type type = Type::Message;
std::string payload;
};
private:
tcp::resolver resolver;
tcp::socket socket;
tcp::resolver::results_type endpoint;
std::array<char, 8192> buffer;
std::array<char, 8192000> PackData;
std::size_t bufferedDataSize = 0;
std::deque<PendingEvent> pendingEvents;
std::size_t queuedMessageBytes = 0;
std::mutex pendingEventsMutex;
std::string Ip = "192.168.200.27";
// std::string Ip = "127.0.0.1";
std::string Port = "65109";
public:
bool ConnectState = false;
std::fstream file;
public:
Client(asio::io_context &io_context, std::string Ip, std::string Port)
: resolver(io_context),
socket(io_context)
{
endpoint = resolver.resolve(Ip, Port);
this->Ip = Ip;
this->Port = Port;
PackData.fill(0);
}
private:
enum : std::size_t
{
HeaderSize = 4,
MaxQueuedMessages = 10000,
MaxQueuedMessageBytes = 8 * 1024 * 1024
};
void ResetPacketBuffer()
{
bufferedDataSize = 0;
}
void InvokeGatewayConnectCallback()
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v); // saves the stack size before the call
sq_pushroottable(v); // pushes the global table
sq_pushstring(v, _SC("OnGatewaySocketConnect"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v); // push the global table as this
sq_call(v, 1, SQFalse, SQTrue); // calls the function
}
sq_settop(v, top); // restores the original stack size
}
void InvokeGatewaySocketMsg(const std::string &message)
{
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v); // saves the stack size before the call
sq_pushroottable(v); // pushes the global table
sq_pushstring(v, _SC("OnGatewaySocketMsg"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{
sq_pushroottable(v);
sq_pushstring(v, message.c_str(), static_cast<SQInteger>(message.size()));
sq_call(v, 2, SQFalse, SQTrue);
}
sq_settop(v, top);
}
bool EnqueueConnectEvent()
{
std::lock_guard<std::mutex> lock(pendingEventsMutex);
PendingEvent event;
event.type = PendingEvent::Type::Connect;
pendingEvents.push_back(std::move(event));
return true;
}
bool EnqueueMessageEvent(const char *message, std::size_t length)
{
std::lock_guard<std::mutex> lock(pendingEventsMutex);
if (pendingEvents.size() >= MaxQueuedMessages)
{
spdlog::error("Gateway pending message queue is full. queued_events={}, limit={}",
static_cast<unsigned long long>(pendingEvents.size()),
static_cast<unsigned long long>(MaxQueuedMessages));
return false;
}
if ((queuedMessageBytes + length) > MaxQueuedMessageBytes)
{
spdlog::error("Gateway pending message bytes exceeded. queued_bytes={}, incoming={}, limit={}",
static_cast<unsigned long long>(queuedMessageBytes),
static_cast<unsigned long long>(length),
static_cast<unsigned long long>(MaxQueuedMessageBytes));
return false;
}
PendingEvent event;
event.type = PendingEvent::Type::Message;
event.payload.assign(message, length);
queuedMessageBytes += length;
pendingEvents.push_back(std::move(event));
return true;
}
void DrainPendingEvents(std::deque<PendingEvent> &events)
{
std::lock_guard<std::mutex> lock(pendingEventsMutex);
if (pendingEvents.empty())
return;
events.swap(pendingEvents);
queuedMessageBytes = 0;
}
bool AppendReceivedData(std::size_t bytes_transferred)
{
if (bytes_transferred == 0)
return true;
if ((bufferedDataSize + bytes_transferred) > PackData.size())
{
spdlog::error("Gateway receive buffer overflow. buffered={}, incoming={}, capacity={}",
static_cast<unsigned long long>(bufferedDataSize),
static_cast<unsigned long long>(bytes_transferred),
static_cast<unsigned long long>(PackData.size()));
return false;
}
std::memcpy(PackData.data() + bufferedDataSize, buffer.data(), bytes_transferred);
bufferedDataSize += bytes_transferred;
return true;
}
bool ProcessBufferedPackets()
{
std::size_t offset = 0;
while ((bufferedDataSize - offset) >= HeaderSize)
{
const int packSize = ByteLittleToInt(reinterpret_cast<unsigned char *>(PackData.data() + offset));
if (packSize <= 0)
{
spdlog::error("Gateway packet length is invalid: {}", packSize);
return false;
}
const std::size_t payloadSize = static_cast<std::size_t>(packSize);
if (payloadSize > (PackData.size() - HeaderSize))
{
spdlog::error("Gateway packet length exceeds buffer. payload={}, capacity={}",
static_cast<unsigned long long>(payloadSize),
static_cast<unsigned long long>(PackData.size() - HeaderSize));
return false;
}
if ((bufferedDataSize - offset - HeaderSize) < payloadSize)
break;
if (!EnqueueMessageEvent(PackData.data() + offset + HeaderSize, payloadSize))
return false;
offset += HeaderSize + payloadSize;
}
if (offset == 0)
return true;
const std::size_t remaining = bufferedDataSize - offset;
if (remaining > 0)
std::memmove(PackData.data(), PackData.data() + offset, remaining);
bufferedDataSize = remaining;
return true;
}
public:
void start()
{
async_connect(socket, endpoint, [this](const asio::error_code &error, const tcp::endpoint &connected_endpoint)
{
if (!error) {
ConnectState = true;
ResetPacketBuffer();
EnqueueConnectEvent();
read();
} else {
// std::cerr << "Error connecting to server: " << error.message() << std::endl;
start();
} });
}
void read()
{
socket.async_read_some(asio::buffer(buffer), [this](const asio::error_code &error, std::size_t bytes_transferred)
{
if (!error) {
if (!AppendReceivedData(bytes_transferred) || !ProcessBufferedPackets()) {
reconnect();
return;
}
read();
} else {
// std::cerr << "Error reading data: " << error.message() << std::endl;
usleep(10);
reconnect();
} });
}
void reconnect()
{
ConnectState = false;
ResetPacketBuffer();
std::cout << "Gateway socket disconnected, reconnecting." << std::endl;
asio::error_code close_error;
socket.close(close_error);
endpoint = resolver.resolve(Ip, Port);
async_connect(socket, endpoint, [this](const asio::error_code &error, const tcp::endpoint &connected_endpoint)
{
if (!error) {
ConnectState = true;
ResetPacketBuffer();
EnqueueConnectEvent();
read();
} else {
reconnect();
} });
}
void send(unsigned char *message, int Length)
{
std::shared_ptr<std::vector<unsigned char> > payload(new std::vector<unsigned char>(message, message + Length));
async_write(socket, asio::buffer(*payload), [payload](const asio::error_code &error, std::size_t bytes_transferred)
{
if (!error) {
// std::cout << "Message sent" << std::endl;
} else {
std::cerr << "Error sending message: " << error.message() << std::endl;
} });
}
void ClearPack()
{
ResetPacketBuffer();
}
void PackLogic()
{
std::deque<PendingEvent> events;
DrainPendingEvents(events);
while (!events.empty())
{
PendingEvent event = std::move(events.front());
events.pop_front();
if (event.type == PendingEvent::Type::Connect)
{
InvokeGatewayConnectCallback();
continue;
}
InvokeGatewaySocketMsg(event.payload);
}
}
static int ByteLittleToInt(unsigned char *Count)
{
int int1 = Count[0] & 0xff;
int int2 = (Count[1] & 0xff) << 8;
int int3 = (Count[2] & 0xff) << 16;
int int4 = (Count[3] & 0xff) << 24;
return int1 | int2 | int3 | int4;
}
};
class l_socket
{
public:
private:
l_socket() {} // private constructor to prevent instantiation
l_socket(const l_socket &) = delete; // disable copy constructor
l_socket &operator=(const l_socket &) = delete; // disable assignment operator
Client *ClientObj = nullptr;
public:
bool InitState = false;
static l_socket &getInstance()
{
static l_socket instance;
return instance;
}
void InitSqr();
void InitPackLogic();
void Init(std::string Ip, std::string Port);
void Send(const SQChar *Pck);
void Logic();
void IntToByteLittle(unsigned char *b, int Count);
public:
};

View File

@@ -1,31 +0,0 @@
#pragma once
#ifndef l_squirrel
#define l_squirrel
// #define SQUNICODE
#define NO_COMPILER
#include "squirrel.h"
#include "sqstdaux.h"
#include "sqstdblob.h"
#include "sqstdio.h"
#include "sqstdmath.h"
#include "sqstdstring.h"
#include "sqstdsystem.h"
#include "Tool.h"
#include <map>
#include <fstream>
#include <sstream>
#include <iostream>
#include <stdarg.h>
#include <mutex>
#ifdef SQUNICODE
#define scvprintf vfwprintf
#define scfprintf fwprintf
#else
#define scvprintf vfprintf
#define scfprintf fprintf
#endif
void InitSquirrel();
#endif

View File

@@ -1,42 +0,0 @@
#pragma once
#include "squirrel.h"
#include "sqstdaux.h"
#include "sqstdblob.h"
#include "sqstdio.h"
#include "sqstdmath.h"
#include "sqstdstring.h"
#include "sqstdsystem.h"
#include "SqrReg_User.hpp" //用户类
#include "SqrReg_Packet.hpp" //发包类
#include "SqrReg_World.hpp" //世界类
#include "SqrReg_Game.hpp" //游戏类
#include "SqrReg_GameManager.hpp" //游戏管理器类
#include "SqrReg_Party.hpp" //队伍类
#include "SqrReg_Inven.hpp" //背包类
#include "SqrReg_Battle_Field.hpp" //战斗对象类
#include "SqrReg_Dungeon.hpp" //副本类
#include "SqrReg_Memory.hpp" //内存类
#include "SqrReg_ActiveHook.hpp" //动态HOOK
#include "SqrReg_Dio.hpp" //网络类
#include "SqrReg_Asset.hpp" //资源类
#include "SqrReg_RSA.hpp" //RSA类
#include <iostream>
#include <stdarg.h>
static void GlobaRegisterSquirrel(HSQUIRRELVM v)
{
RegisterBattleField(v); // 战斗对象类
RegisterDungeon(v); // 副本类
RegisterInven(v); // 背包类
RegisterGameManager(v); // 游戏管理器类
RegisterParty(v); // 队伍类
RegisterGame(v); // 游戏类
RegisterWorld(v); // 世界类
RegisterPacket(v); // 发包类
RegisterUser(v); // 用户类
RegisterMemory(v); // 内存类
RegisterActiveHook(v); // 动态HOOK
RegisterDio(v); // 网络类
RegisterAsset(v); // 资源类
RegisterRsa(v); // RSA类
}

View File

@@ -1,264 +0,0 @@
/*
** $Id: lauxlib.h,v 1.131.1.1 2017/04/19 17:20:42 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
#ifndef lauxlib_h
#define lauxlib_h
#include <stddef.h>
#include <stdio.h>
#include "lua.h"
/* extra error code for 'luaL_loadfilex' */
#define LUA_ERRFILE (LUA_ERRERR+1)
/* key, in the registry, for table of loaded modules */
#define LUA_LOADED_TABLE "_LOADED"
/* key, in the registry, for table of preloaded loaders */
#define LUA_PRELOAD_TABLE "_PRELOAD"
typedef struct luaL_Reg {
const char *name;
lua_CFunction func;
} luaL_Reg;
#define LUAL_NUMSIZES (sizeof(lua_Integer)*16 + sizeof(lua_Number))
LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz);
#define luaL_checkversion(L) \
luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES)
LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len);
LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg);
LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg,
size_t *l);
LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg,
const char *def, size_t *l);
LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg);
LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def);
LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg);
LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg,
lua_Integer def);
LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
LUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t);
LUALIB_API void (luaL_checkany) (lua_State *L, int arg);
LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname);
LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname);
LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname);
LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
LUALIB_API void (luaL_where) (lua_State *L, int lvl);
LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def,
const char *const lst[]);
LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname);
LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
/* predefined references */
#define LUA_NOREF (-2)
#define LUA_REFNIL (-1)
LUALIB_API int (luaL_ref) (lua_State *L, int t);
LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename,
const char *mode);
#define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL)
LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz,
const char *name, const char *mode);
LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
LUALIB_API lua_State *(luaL_newstate) (void);
LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx);
LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
const char *r);
LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup);
LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname);
LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1,
const char *msg, int level);
LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
lua_CFunction openf, int glb);
/*
** ===============================================================
** some useful macros
** ===============================================================
*/
#define luaL_newlibtable(L,l) \
lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1)
#define luaL_newlib(L,l) \
(luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
#define luaL_argcheck(L, cond,arg,extramsg) \
((void)((cond) || luaL_argerror(L, (arg), (extramsg))))
#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i)))
#define luaL_dofile(L, fn) \
(luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
#define luaL_dostring(L, s) \
(luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL)
/*
** {======================================================
** Generic Buffer manipulation
** =======================================================
*/
typedef struct luaL_Buffer {
char *b; /* buffer address */
size_t size; /* buffer size */
size_t n; /* number of characters in buffer */
lua_State *L;
char initb[LUAL_BUFFERSIZE]; /* initial buffer */
} luaL_Buffer;
#define luaL_addchar(B,c) \
((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \
((B)->b[(B)->n++] = (c)))
#define luaL_addsize(B,s) ((B)->n += (s))
LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz);
LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);
LUALIB_API void (luaL_addvalue) (luaL_Buffer *B);
LUALIB_API void (luaL_pushresult) (luaL_Buffer *B);
LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz);
LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz);
#define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE)
/* }====================================================== */
/*
** {======================================================
** File handles for IO library
** =======================================================
*/
/*
** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and
** initial structure 'luaL_Stream' (it may contain other fields
** after that initial structure).
*/
#define LUA_FILEHANDLE "FILE*"
typedef struct luaL_Stream {
FILE *f; /* stream (NULL for incompletely created streams) */
lua_CFunction closef; /* to close stream (NULL for closed streams) */
} luaL_Stream;
/* }====================================================== */
/* compatibility with old module system */
#if defined(LUA_COMPAT_MODULE)
LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname,
int sizehint);
LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname,
const luaL_Reg *l, int nup);
#define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0))
#endif
/*
** {==================================================================
** "Abstraction Layer" for basic report of messages and errors
** ===================================================================
*/
/* print a string */
#if !defined(lua_writestring)
#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout)
#endif
/* print a newline and flush the output */
#if !defined(lua_writeline)
#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout))
#endif
/* print an error message */
#if !defined(lua_writestringerror)
#define lua_writestringerror(s,p) \
(fprintf(stderr, (s), (p)), fflush(stderr))
#endif
/* }================================================================== */
/*
** {============================================================
** Compatibility with deprecated conversions
** =============================================================
*/
#if defined(LUA_COMPAT_APIINTCASTS)
#define luaL_checkunsigned(L,a) ((lua_Unsigned)luaL_checkinteger(L,a))
#define luaL_optunsigned(L,a,d) \
((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(d)))
#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d)))
#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n)))
#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d)))
#endif
/* }============================================================ */
#endif

View File

@@ -1,485 +0,0 @@
/*
** Lua - A Scripting Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file
*/
#ifndef lua_h
#define lua_h
#include <stdarg.h>
#include <stddef.h>
#include "luaconf.h"
#define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "3"
#define LUA_VERSION_NUM 503
#define LUA_VERSION_RELEASE "6"
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2020 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
/* mark for precompiled code ('<esc>Lua') */
#define LUA_SIGNATURE "\x1bLua"
/* option for multiple returns in 'lua_pcall' and 'lua_call' */
#define LUA_MULTRET (-1)
/*
** Pseudo-indices
** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty
** space after that to help overflow detection)
*/
#define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000)
#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i))
/* thread status */
#define LUA_OK 0
#define LUA_YIELD 1
#define LUA_ERRRUN 2
#define LUA_ERRSYNTAX 3
#define LUA_ERRMEM 4
#define LUA_ERRGCMM 5
#define LUA_ERRERR 6
typedef struct lua_State lua_State;
/*
** basic types
*/
#define LUA_TNONE (-1)
#define LUA_TNIL 0
#define LUA_TBOOLEAN 1
#define LUA_TLIGHTUSERDATA 2
#define LUA_TNUMBER 3
#define LUA_TSTRING 4
#define LUA_TTABLE 5
#define LUA_TFUNCTION 6
#define LUA_TUSERDATA 7
#define LUA_TTHREAD 8
#define LUA_NUMTAGS 9
/* minimum Lua stack available to a C function */
#define LUA_MINSTACK 20
/* predefined values in the registry */
#define LUA_RIDX_MAINTHREAD 1
#define LUA_RIDX_GLOBALS 2
#define LUA_RIDX_LAST LUA_RIDX_GLOBALS
/* type of numbers in Lua */
typedef LUA_NUMBER lua_Number;
/* type for integer functions */
typedef LUA_INTEGER lua_Integer;
/* unsigned integer type */
typedef LUA_UNSIGNED lua_Unsigned;
/* type for continuation-function contexts */
typedef LUA_KCONTEXT lua_KContext;
/*
** Type for C functions registered with Lua
*/
typedef int (*lua_CFunction) (lua_State *L);
/*
** Type for continuation functions
*/
typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx);
/*
** Type for functions that read/write blocks when loading/dumping Lua chunks
*/
typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz);
typedef int (*lua_Writer) (lua_State *L, const void *p, size_t sz, void *ud);
/*
** Type for memory-allocation functions
*/
typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
/*
** generic extra include file
*/
#if defined(LUA_USER_H)
#include LUA_USER_H
#endif
/*
** RCS ident string
*/
extern const char lua_ident[];
/*
** state manipulation
*/
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
LUA_API void (lua_close) (lua_State *L);
LUA_API lua_State *(lua_newthread) (lua_State *L);
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
LUA_API const lua_Number *(lua_version) (lua_State *L);
/*
** basic stack manipulation
*/
LUA_API int (lua_absindex) (lua_State *L, int idx);
LUA_API int (lua_gettop) (lua_State *L);
LUA_API void (lua_settop) (lua_State *L, int idx);
LUA_API void (lua_pushvalue) (lua_State *L, int idx);
LUA_API void (lua_rotate) (lua_State *L, int idx, int n);
LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx);
LUA_API int (lua_checkstack) (lua_State *L, int n);
LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n);
/*
** access functions (stack -> C)
*/
LUA_API int (lua_isnumber) (lua_State *L, int idx);
LUA_API int (lua_isstring) (lua_State *L, int idx);
LUA_API int (lua_iscfunction) (lua_State *L, int idx);
LUA_API int (lua_isinteger) (lua_State *L, int idx);
LUA_API int (lua_isuserdata) (lua_State *L, int idx);
LUA_API int (lua_type) (lua_State *L, int idx);
LUA_API const char *(lua_typename) (lua_State *L, int tp);
LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum);
LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum);
LUA_API int (lua_toboolean) (lua_State *L, int idx);
LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len);
LUA_API size_t (lua_rawlen) (lua_State *L, int idx);
LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx);
LUA_API void *(lua_touserdata) (lua_State *L, int idx);
LUA_API lua_State *(lua_tothread) (lua_State *L, int idx);
LUA_API const void *(lua_topointer) (lua_State *L, int idx);
/*
** Comparison and arithmetic functions
*/
#define LUA_OPADD 0 /* ORDER TM, ORDER OP */
#define LUA_OPSUB 1
#define LUA_OPMUL 2
#define LUA_OPMOD 3
#define LUA_OPPOW 4
#define LUA_OPDIV 5
#define LUA_OPIDIV 6
#define LUA_OPBAND 7
#define LUA_OPBOR 8
#define LUA_OPBXOR 9
#define LUA_OPSHL 10
#define LUA_OPSHR 11
#define LUA_OPUNM 12
#define LUA_OPBNOT 13
LUA_API void (lua_arith) (lua_State *L, int op);
#define LUA_OPEQ 0
#define LUA_OPLT 1
#define LUA_OPLE 2
LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2);
LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op);
/*
** push functions (C -> stack)
*/
LUA_API void (lua_pushnil) (lua_State *L);
LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n);
LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n);
LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len);
LUA_API const char *(lua_pushstring) (lua_State *L, const char *s);
LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt,
va_list argp);
LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...);
LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);
LUA_API void (lua_pushboolean) (lua_State *L, int b);
LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p);
LUA_API int (lua_pushthread) (lua_State *L);
/*
** get functions (Lua -> stack)
*/
LUA_API int (lua_getglobal) (lua_State *L, const char *name);
LUA_API int (lua_gettable) (lua_State *L, int idx);
LUA_API int (lua_getfield) (lua_State *L, int idx, const char *k);
LUA_API int (lua_geti) (lua_State *L, int idx, lua_Integer n);
LUA_API int (lua_rawget) (lua_State *L, int idx);
LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n);
LUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p);
LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec);
LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz);
LUA_API int (lua_getmetatable) (lua_State *L, int objindex);
LUA_API int (lua_getuservalue) (lua_State *L, int idx);
/*
** set functions (stack -> Lua)
*/
LUA_API void (lua_setglobal) (lua_State *L, const char *name);
LUA_API void (lua_settable) (lua_State *L, int idx);
LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k);
LUA_API void (lua_seti) (lua_State *L, int idx, lua_Integer n);
LUA_API void (lua_rawset) (lua_State *L, int idx);
LUA_API void (lua_rawseti) (lua_State *L, int idx, lua_Integer n);
LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p);
LUA_API int (lua_setmetatable) (lua_State *L, int objindex);
LUA_API void (lua_setuservalue) (lua_State *L, int idx);
/*
** 'load' and 'call' functions (load and run Lua code)
*/
LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults,
lua_KContext ctx, lua_KFunction k);
#define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL)
LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc,
lua_KContext ctx, lua_KFunction k);
#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL)
LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt,
const char *chunkname, const char *mode);
LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip);
/*
** coroutine functions
*/
LUA_API int (lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx,
lua_KFunction k);
LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg);
LUA_API int (lua_status) (lua_State *L);
LUA_API int (lua_isyieldable) (lua_State *L);
#define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL)
/*
** garbage-collection function and options
*/
#define LUA_GCSTOP 0
#define LUA_GCRESTART 1
#define LUA_GCCOLLECT 2
#define LUA_GCCOUNT 3
#define LUA_GCCOUNTB 4
#define LUA_GCSTEP 5
#define LUA_GCSETPAUSE 6
#define LUA_GCSETSTEPMUL 7
#define LUA_GCISRUNNING 9
LUA_API int (lua_gc) (lua_State *L, int what, int data);
/*
** miscellaneous functions
*/
LUA_API int (lua_error) (lua_State *L);
LUA_API int (lua_next) (lua_State *L, int idx);
LUA_API void (lua_concat) (lua_State *L, int n);
LUA_API void (lua_len) (lua_State *L, int idx);
LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s);
LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
/*
** {==============================================================
** some useful macros
** ===============================================================
*/
#define lua_getextraspace(L) ((void *)((char *)(L) - LUA_EXTRASPACE))
#define lua_tonumber(L,i) lua_tonumberx(L,(i),NULL)
#define lua_tointeger(L,i) lua_tointegerx(L,(i),NULL)
#define lua_pop(L,n) lua_settop(L, -(n)-1)
#define lua_newtable(L) lua_createtable(L, 0, 0)
#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0)
#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION)
#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE)
#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA)
#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL)
#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN)
#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD)
#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE)
#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0)
#define lua_pushliteral(L, s) lua_pushstring(L, "" s)
#define lua_pushglobaltable(L) \
((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS))
#define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
#define lua_insert(L,idx) lua_rotate(L, (idx), 1)
#define lua_remove(L,idx) (lua_rotate(L, (idx), -1), lua_pop(L, 1))
#define lua_replace(L,idx) (lua_copy(L, -1, (idx)), lua_pop(L, 1))
/* }============================================================== */
/*
** {==============================================================
** compatibility macros for unsigned conversions
** ===============================================================
*/
#if defined(LUA_COMPAT_APIINTCASTS)
#define lua_pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n))
#define lua_tounsignedx(L,i,is) ((lua_Unsigned)lua_tointegerx(L,i,is))
#define lua_tounsigned(L,i) lua_tounsignedx(L,(i),NULL)
#endif
/* }============================================================== */
/*
** {======================================================================
** Debug API
** =======================================================================
*/
/*
** Event codes
*/
#define LUA_HOOKCALL 0
#define LUA_HOOKRET 1
#define LUA_HOOKLINE 2
#define LUA_HOOKCOUNT 3
#define LUA_HOOKTAILCALL 4
/*
** Event masks
*/
#define LUA_MASKCALL (1 << LUA_HOOKCALL)
#define LUA_MASKRET (1 << LUA_HOOKRET)
#define LUA_MASKLINE (1 << LUA_HOOKLINE)
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
typedef struct lua_Debug lua_Debug; /* activation record */
/* Functions to be called by the debugger in specific events */
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);
LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);
LUA_API const char *(lua_getlocal) (lua_State *L, const lua_Debug *ar, int n);
LUA_API const char *(lua_setlocal) (lua_State *L, const lua_Debug *ar, int n);
LUA_API const char *(lua_getupvalue) (lua_State *L, int funcindex, int n);
LUA_API const char *(lua_setupvalue) (lua_State *L, int funcindex, int n);
LUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n);
LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1,
int fidx2, int n2);
LUA_API void (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count);
LUA_API lua_Hook (lua_gethook) (lua_State *L);
LUA_API int (lua_gethookmask) (lua_State *L);
LUA_API int (lua_gethookcount) (lua_State *L);
struct lua_Debug {
int event;
const char *name; /* (n) */
const char *namewhat; /* (n) 'global', 'local', 'field', 'method' */
const char *what; /* (S) 'Lua', 'C', 'main', 'tail' */
const char *source; /* (S) */
int currentline; /* (l) */
int linedefined; /* (S) */
int lastlinedefined; /* (S) */
unsigned char nups; /* (u) number of upvalues */
unsigned char nparams;/* (u) number of parameters */
char isvararg; /* (u) */
char istailcall; /* (t) */
char short_src[LUA_IDSIZE]; /* (S) */
/* private part */
struct CallInfo *i_ci; /* active function */
};
/* }====================================================================== */
/******************************************************************************
* Copyright (C) 1994-2020 Lua.org, PUC-Rio.
*
* 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.
******************************************************************************/
#endif

View File

@@ -1,9 +0,0 @@
// lua.hpp
// Lua header files for C++
// <<extern "C">> not supplied automatically because Lua also compiles as C++
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}

View File

@@ -1,793 +0,0 @@
/*
** $Id: luaconf.h,v 1.259.1.1 2017/04/19 17:29:57 roberto Exp $
** Configuration file for Lua
** See Copyright Notice in lua.h
*/
#ifndef luaconf_h
#define luaconf_h
#include <limits.h>
#include <stddef.h>
/*
** ===================================================================
** Search for "@@" to find all configurable definitions.
** ===================================================================
*/
/*
** {====================================================================
** System Configuration: macros to adapt (if needed) Lua to some
** particular platform, for instance compiling it with 32-bit numbers or
** restricting it to C89.
** =====================================================================
*/
/*
@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. You
** can also define LUA_32BITS in the make file, but changing here you
** ensure that all software connected to Lua will be compiled with the
** same configuration.
*/
/* #define LUA_32BITS */
/*
@@ LUA_USE_C89 controls the use of non-ISO-C89 features.
** Define it if you want Lua to avoid the use of a few C99 features
** or Windows-specific features on Windows.
*/
/* #define LUA_USE_C89 */
/*
** By default, Lua on Windows use (some) specific Windows features
*/
#if !defined(LUA_USE_C89) && defined(_WIN32) && !defined(_WIN32_WCE)
#define LUA_USE_WINDOWS /* enable goodies for regular Windows */
#endif
#if defined(LUA_USE_WINDOWS)
#define LUA_DL_DLL /* enable support for DLL */
#define LUA_USE_C89 /* broadly, Windows is C89 */
#endif
#if defined(LUA_USE_LINUX)
#define LUA_USE_POSIX
#define LUA_USE_DLOPEN /* needs an extra library: -ldl */
#define LUA_USE_READLINE /* needs some extra libraries */
#endif
#if defined(LUA_USE_MACOSX)
#define LUA_USE_POSIX
#define LUA_USE_DLOPEN /* MacOS does not need -ldl */
#define LUA_USE_READLINE /* needs an extra library: -lreadline */
#endif
/*
@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for
** C89 ('long' and 'double'); Windows always has '__int64', so it does
** not need to use this case.
*/
#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS)
#define LUA_C89_NUMBERS
#endif
/*
@@ LUAI_BITSINT defines the (minimum) number of bits in an 'int'.
*/
/* avoid undefined shifts */
#if ((INT_MAX >> 15) >> 15) >= 1
#define LUAI_BITSINT 32
#else
/* 'int' always must have at least 16 bits */
#define LUAI_BITSINT 16
#endif
/*
@@ LUA_INT_TYPE defines the type for Lua integers.
@@ LUA_FLOAT_TYPE defines the type for Lua floats.
** Lua should work fine with any mix of these options (if supported
** by your C compiler). The usual configurations are 64-bit integers
** and 'double' (the default), 32-bit integers and 'float' (for
** restricted platforms), and 'long'/'double' (for C compilers not
** compliant with C99, which may not have support for 'long long').
*/
/* predefined options for LUA_INT_TYPE */
#define LUA_INT_INT 1
#define LUA_INT_LONG 2
#define LUA_INT_LONGLONG 3
/* predefined options for LUA_FLOAT_TYPE */
#define LUA_FLOAT_FLOAT 1
#define LUA_FLOAT_DOUBLE 2
#define LUA_FLOAT_LONGDOUBLE 3
#if defined(LUA_32BITS) /* { */
/*
** 32-bit integers and 'float'
*/
#if LUAI_BITSINT >= 32 /* use 'int' if big enough */
#define LUA_INT_TYPE LUA_INT_INT
#else /* otherwise use 'long' */
#define LUA_INT_TYPE LUA_INT_LONG
#endif
#define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT
#elif defined(LUA_C89_NUMBERS) /* }{ */
/*
** largest types available for C89 ('long' and 'double')
*/
#define LUA_INT_TYPE LUA_INT_LONG
#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
#endif /* } */
/*
** default configuration for 64-bit Lua ('long long' and 'double')
*/
#if !defined(LUA_INT_TYPE)
#define LUA_INT_TYPE LUA_INT_LONGLONG
#endif
#if !defined(LUA_FLOAT_TYPE)
#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
#endif
/* }================================================================== */
/*
** {==================================================================
** Configuration for Paths.
** ===================================================================
*/
/*
** LUA_PATH_SEP is the character that separates templates in a path.
** LUA_PATH_MARK is the string that marks the substitution points in a
** template.
** LUA_EXEC_DIR in a Windows path is replaced by the executable's
** directory.
*/
#define LUA_PATH_SEP ";"
#define LUA_PATH_MARK "?"
#define LUA_EXEC_DIR "!"
/*
@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for
** Lua libraries.
@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for
** C libraries.
** CHANGE them if your machine has a non-conventional directory
** hierarchy or if you want to install your libraries in
** non-conventional directories.
*/
#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#if defined(_WIN32) /* { */
/*
** In Windows, any exclamation mark ('!') in the path is replaced by the
** path of the directory of the executable file of the current process.
*/
#define LUA_LDIR "!\\lua\\"
#define LUA_CDIR "!\\"
#define LUA_SHRDIR "!\\..\\share\\lua\\" LUA_VDIR "\\"
#define LUA_PATH_DEFAULT \
LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \
LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \
LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \
".\\?.lua;" ".\\?\\init.lua"
#define LUA_CPATH_DEFAULT \
LUA_CDIR"?.dll;" \
LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \
LUA_CDIR"loadall.dll;" ".\\?.dll"
#else /* }{ */
#define LUA_ROOT "/dp2/"
#define LUA_CDIR LUA_ROOT "lua/"
#define LUA_CDIR2 LUA_ROOT "lua2/"
#define LUA_PATH_DEFAULT \
LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" \
LUA_CDIR2"?.lua;" LUA_CDIR2"?/init.lua;"
#define LUA_CPATH_DEFAULT \
LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" \
LUA_CDIR2"?.so;" LUA_CDIR2"loadall.so"
#endif /* } */
/*
@@ LUA_DIRSEP is the directory separator (for submodules).
** CHANGE it if your machine does not use "/" as the directory separator
** and is not Windows. (On Windows Lua automatically uses "\".)
*/
#if defined(_WIN32)
#define LUA_DIRSEP "\\"
#else
#define LUA_DIRSEP "/"
#endif
/* }================================================================== */
/*
** {==================================================================
** Marks for exported symbols in the C code
** ===================================================================
*/
/*
@@ LUA_API is a mark for all core API functions.
@@ LUALIB_API is a mark for all auxiliary library functions.
@@ LUAMOD_API is a mark for all standard library opening functions.
** CHANGE them if you need to define those functions in some special way.
** For instance, if you want to create one Windows DLL with the core and
** the libraries, you may want to use the following definition (define
** LUA_BUILD_AS_DLL to get it).
*/
#if defined(LUA_BUILD_AS_DLL) /* { */
#if defined(LUA_CORE) || defined(LUA_LIB) /* { */
#define LUA_API __declspec(dllexport)
#else /* }{ */
#define LUA_API __declspec(dllimport)
#endif /* } */
#else /* }{ */
#ifndef __cplusplus
#define LUA_API extern __attribute__((visibility("default")))
#else
#define LUA_API extern "C" __attribute__((visibility("default")))
#endif
#endif /* } */
/* more often than not the libs go together with the core */
#define LUALIB_API LUA_API
#define LUAMOD_API LUALIB_API
/*
@@ LUAI_FUNC is a mark for all extern functions that are not to be
** exported to outside modules.
@@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables
** that are not to be exported to outside modules (LUAI_DDEF for
** definitions and LUAI_DDEC for declarations).
** CHANGE them if you need to mark them in some special way. Elf/gcc
** (versions 3.2 and later) mark them as "hidden" to optimize access
** when Lua is compiled as a shared library. Not all elf targets support
** this attribute. Unfortunately, gcc does not offer a way to check
** whether the target offers that support, and those without support
** give a warning about it. To avoid these warnings, change to the
** default definition.
*/
#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \
defined(__ELF__) /* { */
#define LUAI_FUNC __attribute__((visibility("hidden"))) extern
#else /* }{ */
#define LUAI_FUNC extern
#endif /* } */
#define LUAI_DDEC LUAI_FUNC
#define LUAI_DDEF /* empty */
/* }================================================================== */
/*
** {==================================================================
** Compatibility with previous versions
** ===================================================================
*/
/*
@@ LUA_COMPAT_5_2 controls other macros for compatibility with Lua 5.2.
@@ LUA_COMPAT_5_1 controls other macros for compatibility with Lua 5.1.
** You can define it to get all options, or change specific options
** to fit your specific needs.
*/
#if defined(LUA_COMPAT_5_2) /* { */
/*
@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated
** functions in the mathematical library.
*/
#define LUA_COMPAT_MATHLIB
/*
@@ LUA_COMPAT_BITLIB controls the presence of library 'bit32'.
*/
#define LUA_COMPAT_BITLIB
/*
@@ LUA_COMPAT_IPAIRS controls the effectiveness of the __ipairs metamethod.
*/
#define LUA_COMPAT_IPAIRS
/*
@@ LUA_COMPAT_APIINTCASTS controls the presence of macros for
** manipulating other integer types (lua_pushunsigned, lua_tounsigned,
** luaL_checkint, luaL_checklong, etc.)
*/
#define LUA_COMPAT_APIINTCASTS
#endif /* } */
#if defined(LUA_COMPAT_5_1) /* { */
/* Incompatibilities from 5.2 -> 5.3 */
#define LUA_COMPAT_MATHLIB
#define LUA_COMPAT_APIINTCASTS
/*
@@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'.
** You can replace it with 'table.unpack'.
*/
#define LUA_COMPAT_UNPACK
/*
@@ LUA_COMPAT_LOADERS controls the presence of table 'package.loaders'.
** You can replace it with 'package.searchers'.
*/
#define LUA_COMPAT_LOADERS
/*
@@ macro 'lua_cpcall' emulates deprecated function lua_cpcall.
** You can call your C function directly (with light C functions).
*/
#define lua_cpcall(L,f,u) \
(lua_pushcfunction(L, (f)), \
lua_pushlightuserdata(L,(u)), \
lua_pcall(L,1,0,0))
/*
@@ LUA_COMPAT_LOG10 defines the function 'log10' in the math library.
** You can rewrite 'log10(x)' as 'log(x, 10)'.
*/
#define LUA_COMPAT_LOG10
/*
@@ LUA_COMPAT_LOADSTRING defines the function 'loadstring' in the base
** library. You can rewrite 'loadstring(s)' as 'load(s)'.
*/
#define LUA_COMPAT_LOADSTRING
/*
@@ LUA_COMPAT_MAXN defines the function 'maxn' in the table library.
*/
#define LUA_COMPAT_MAXN
/*
@@ The following macros supply trivial compatibility for some
** changes in the API. The macros themselves document how to
** change your code to avoid using them.
*/
#define lua_strlen(L,i) lua_rawlen(L, (i))
#define lua_objlen(L,i) lua_rawlen(L, (i))
#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ)
#define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT)
/*
@@ LUA_COMPAT_MODULE controls compatibility with previous
** module functions 'module' (Lua) and 'luaL_register' (C).
*/
#define LUA_COMPAT_MODULE
#endif /* } */
/*
@@ LUA_COMPAT_FLOATSTRING makes Lua format integral floats without a
@@ a float mark ('.0').
** This macro is not on by default even in compatibility mode,
** because this is not really an incompatibility.
*/
/* #define LUA_COMPAT_FLOATSTRING */
/* }================================================================== */
/*
** {==================================================================
** Configuration for Numbers.
** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_*
** satisfy your needs.
** ===================================================================
*/
/*
@@ LUA_NUMBER is the floating-point type used by Lua.
@@ LUAI_UACNUMBER is the result of a 'default argument promotion'
@@ over a floating number.
@@ l_mathlim(x) corrects limit name 'x' to the proper float type
** by prefixing it with one of FLT/DBL/LDBL.
@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats.
@@ LUA_NUMBER_FMT is the format for writing floats.
@@ lua_number2str converts a float to a string.
@@ l_mathop allows the addition of an 'l' or 'f' to all math operations.
@@ l_floor takes the floor of a float.
@@ lua_str2number converts a decimal numeric string to a number.
*/
/* The following definitions are good for most cases here */
#define l_floor(x) (l_mathop(floor)(x))
#define lua_number2str(s,sz,n) \
l_sprintf((s), sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)(n))
/*
@@ lua_numbertointeger converts a float number to an integer, or
** returns 0 if float is not within the range of a lua_Integer.
** (The range comparisons are tricky because of rounding. The tests
** here assume a two-complement representation, where MININTEGER always
** has an exact representation as a float; MAXINTEGER may not have one,
** and therefore its conversion to float may have an ill-defined value.)
*/
#define lua_numbertointeger(n,p) \
((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \
(n) < -(LUA_NUMBER)(LUA_MININTEGER) && \
(*(p) = (LUA_INTEGER)(n), 1))
/* now the variable definitions */
#if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */
#define LUA_NUMBER float
#define l_mathlim(n) (FLT_##n)
#define LUAI_UACNUMBER double
#define LUA_NUMBER_FRMLEN ""
#define LUA_NUMBER_FMT "%.7g"
#define l_mathop(op) op##f
#define lua_str2number(s,p) strtof((s), (p))
#elif LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE /* }{ long double */
#define LUA_NUMBER long double
#define l_mathlim(n) (LDBL_##n)
#define LUAI_UACNUMBER long double
#define LUA_NUMBER_FRMLEN "L"
#define LUA_NUMBER_FMT "%.19Lg"
#define l_mathop(op) op##l
#define lua_str2number(s,p) strtold((s), (p))
#elif LUA_FLOAT_TYPE == LUA_FLOAT_DOUBLE /* }{ double */
#define LUA_NUMBER double
#define l_mathlim(n) (DBL_##n)
#define LUAI_UACNUMBER double
#define LUA_NUMBER_FRMLEN ""
#define LUA_NUMBER_FMT "%.14g"
#define l_mathop(op) op
#define lua_str2number(s,p) strtod((s), (p))
#else /* }{ */
#error "numeric float type not defined"
#endif /* } */
/*
@@ LUA_INTEGER is the integer type used by Lua.
**
@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER.
**
@@ LUAI_UACINT is the result of a 'default argument promotion'
@@ over a lUA_INTEGER.
@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers.
@@ LUA_INTEGER_FMT is the format for writing integers.
@@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER.
@@ LUA_MININTEGER is the minimum value for a LUA_INTEGER.
@@ lua_integer2str converts an integer to a string.
*/
/* The following definitions are good for most cases here */
#define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d"
#define LUAI_UACINT LUA_INTEGER
#define lua_integer2str(s,sz,n) \
l_sprintf((s), sz, LUA_INTEGER_FMT, (LUAI_UACINT)(n))
/*
** use LUAI_UACINT here to avoid problems with promotions (which
** can turn a comparison between unsigneds into a signed comparison)
*/
#define LUA_UNSIGNED unsigned LUAI_UACINT
/* now the variable definitions */
#if LUA_INT_TYPE == LUA_INT_INT /* { int */
#define LUA_INTEGER int
#define LUA_INTEGER_FRMLEN ""
#define LUA_MAXINTEGER INT_MAX
#define LUA_MININTEGER INT_MIN
#elif LUA_INT_TYPE == LUA_INT_LONG /* }{ long */
#define LUA_INTEGER long
#define LUA_INTEGER_FRMLEN "l"
#define LUA_MAXINTEGER LONG_MAX
#define LUA_MININTEGER LONG_MIN
#elif LUA_INT_TYPE == LUA_INT_LONGLONG /* }{ long long */
/* use presence of macro LLONG_MAX as proxy for C99 compliance */
#if defined(LLONG_MAX) /* { */
/* use ISO C99 stuff */
#define LUA_INTEGER long long
#define LUA_INTEGER_FRMLEN "ll"
#define LUA_MAXINTEGER LLONG_MAX
#define LUA_MININTEGER LLONG_MIN
#elif defined(LUA_USE_WINDOWS) /* }{ */
/* in Windows, can use specific Windows types */
#define LUA_INTEGER __int64
#define LUA_INTEGER_FRMLEN "I64"
#define LUA_MAXINTEGER _I64_MAX
#define LUA_MININTEGER _I64_MIN
#else /* }{ */
#error "Compiler does not support 'long long'. Use option '-DLUA_32BITS' \
or '-DLUA_C89_NUMBERS' (see file 'luaconf.h' for details)"
#endif /* } */
#else /* }{ */
#error "numeric integer type not defined"
#endif /* } */
/* }================================================================== */
/*
** {==================================================================
** Dependencies with C99 and other C details
** ===================================================================
*/
/*
@@ l_sprintf is equivalent to 'snprintf' or 'sprintf' in C89.
** (All uses in Lua have only one format item.)
*/
#if !defined(LUA_USE_C89)
#define l_sprintf(s,sz,f,i) snprintf(s,sz,f,i)
#else
#define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s,f,i))
#endif
/*
@@ lua_strx2number converts an hexadecimal numeric string to a number.
** In C99, 'strtod' does that conversion. Otherwise, you can
** leave 'lua_strx2number' undefined and Lua will provide its own
** implementation.
*/
#if !defined(LUA_USE_C89)
#define lua_strx2number(s,p) lua_str2number(s,p)
#endif
/*
@@ lua_pointer2str converts a pointer to a readable string in a
** non-specified way.
*/
#define lua_pointer2str(buff,sz,p) l_sprintf(buff,sz,"%p",p)
/*
@@ lua_number2strx converts a float to an hexadecimal numeric string.
** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that.
** Otherwise, you can leave 'lua_number2strx' undefined and Lua will
** provide its own implementation.
*/
#if !defined(LUA_USE_C89)
#define lua_number2strx(L,b,sz,f,n) \
((void)L, l_sprintf(b,sz,f,(LUAI_UACNUMBER)(n)))
#endif
/*
** 'strtof' and 'opf' variants for math functions are not valid in
** C89. Otherwise, the macro 'HUGE_VALF' is a good proxy for testing the
** availability of these variants. ('math.h' is already included in
** all files that use these macros.)
*/
#if defined(LUA_USE_C89) || (defined(HUGE_VAL) && !defined(HUGE_VALF))
#undef l_mathop /* variants not available */
#undef lua_str2number
#define l_mathop(op) (lua_Number)op /* no variant */
#define lua_str2number(s,p) ((lua_Number)strtod((s), (p)))
#endif
/*
@@ LUA_KCONTEXT is the type of the context ('ctx') for continuation
** functions. It must be a numerical type; Lua will use 'intptr_t' if
** available, otherwise it will use 'ptrdiff_t' (the nearest thing to
** 'intptr_t' in C89)
*/
#define LUA_KCONTEXT ptrdiff_t
#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
__STDC_VERSION__ >= 199901L
#include <stdint.h>
#if defined(INTPTR_MAX) /* even in C99 this type is optional */
#undef LUA_KCONTEXT
#define LUA_KCONTEXT intptr_t
#endif
#endif
/*
@@ lua_getlocaledecpoint gets the locale "radix character" (decimal point).
** Change that if you do not want to use C locales. (Code using this
** macro must include header 'locale.h'.)
*/
#if !defined(lua_getlocaledecpoint)
#define lua_getlocaledecpoint() (localeconv()->decimal_point[0])
#endif
/* }================================================================== */
/*
** {==================================================================
** Language Variations
** =====================================================================
*/
/*
@@ LUA_NOCVTN2S/LUA_NOCVTS2N control how Lua performs some
** coercions. Define LUA_NOCVTN2S to turn off automatic coercion from
** numbers to strings. Define LUA_NOCVTS2N to turn off automatic
** coercion from strings to numbers.
*/
/* #define LUA_NOCVTN2S */
/* #define LUA_NOCVTS2N */
/*
@@ LUA_USE_APICHECK turns on several consistency checks on the C API.
** Define it as a help when debugging C code.
*/
#if defined(LUA_USE_APICHECK)
#include <assert.h>
#define luai_apicheck(l,e) assert(e)
#endif
/* }================================================================== */
/*
** {==================================================================
** Macros that affect the API and must be stable (that is, must be the
** same when you compile Lua and when you compile code that links to
** Lua). You probably do not want/need to change them.
** =====================================================================
*/
/*
@@ LUAI_MAXSTACK limits the size of the Lua stack.
** CHANGE it if you need a different limit. This limit is arbitrary;
** its only purpose is to stop Lua from consuming unlimited stack
** space (and to reserve some numbers for pseudo-indices).
*/
#if LUAI_BITSINT >= 32
#define LUAI_MAXSTACK 1000000
#else
#define LUAI_MAXSTACK 15000
#endif
/*
@@ LUA_EXTRASPACE defines the size of a raw memory area associated with
** a Lua state with very fast access.
** CHANGE it if you need a different size.
*/
#define LUA_EXTRASPACE (sizeof(void *))
/*
@@ LUA_IDSIZE gives the maximum size for the description of the source
@@ of a function in debug information.
** CHANGE it if you want a different size.
*/
#define LUA_IDSIZE 60
/*
@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
** CHANGE it if it uses too much C-stack space. (For long double,
** 'string.format("%.99f", -1e4932)' needs 5034 bytes, so a
** smaller buffer would force a memory allocation for each call to
** 'string.format'.)
*/
#if LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE
#define LUAL_BUFFERSIZE 8192
#else
#define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer)))
#endif
/* }================================================================== */
/*
@@ LUA_QL describes how error messages quote program elements.
** Lua does not use these macros anymore; they are here for
** compatibility only.
*/
#define LUA_QL(x) "'" x "'"
#define LUA_QS LUA_QL("%s")
/* =================================================================== */
/*
** Local configuration. You can use this space to add your redefinitions
** without modifying the main part of the file.
*/
#endif

View File

@@ -1,61 +0,0 @@
/*
** $Id: lualib.h,v 1.45.1.1 2017/04/19 17:20:42 roberto Exp $
** Lua standard libraries
** See Copyright Notice in lua.h
*/
#ifndef lualib_h
#define lualib_h
#include "lua.h"
/* version suffix for environment variable names */
#define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
LUAMOD_API int (luaopen_base) (lua_State *L);
#define LUA_COLIBNAME "coroutine"
LUAMOD_API int (luaopen_coroutine) (lua_State *L);
#define LUA_TABLIBNAME "table"
LUAMOD_API int (luaopen_table) (lua_State *L);
#define LUA_IOLIBNAME "io"
LUAMOD_API int (luaopen_io) (lua_State *L);
#define LUA_OSLIBNAME "os"
LUAMOD_API int (luaopen_os) (lua_State *L);
#define LUA_STRLIBNAME "string"
LUAMOD_API int (luaopen_string) (lua_State *L);
#define LUA_UTF8LIBNAME "utf8"
LUAMOD_API int (luaopen_utf8) (lua_State *L);
#define LUA_BITLIBNAME "bit32"
LUAMOD_API int (luaopen_bit32) (lua_State *L);
#define LUA_MATHLIBNAME "math"
LUAMOD_API int (luaopen_math) (lua_State *L);
#define LUA_DBLIBNAME "debug"
LUAMOD_API int (luaopen_debug) (lua_State *L);
#define LUA_LOADLIBNAME "package"
LUAMOD_API int (luaopen_package) (lua_State *L);
/* open all previous libraries */
LUALIB_API void (luaL_openlibs) (lua_State *L);
#if !defined(lua_assert)
#define lua_assert(x) ((void)0)
#endif
#endif

View File

@@ -1,55 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,103 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,100 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,497 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,447 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,257 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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 (&current->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

View File

@@ -1,129 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,492 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,727 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,519 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,37 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,35 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,751 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,242 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,61 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,130 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,132 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,39 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,988 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,78 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,482 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,45 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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>

View File

@@ -1,17 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,17 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,171 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,70 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,21 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,159 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,29 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,795 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,24 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,147 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,988 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,146 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,72 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,118 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,75 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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_

View File

@@ -1,359 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,158 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | 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

View File

@@ -1,100 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
//
// Async logging using global thread pool
// All loggers created here share same global thread pool.
// Each log message is pushed to a queue along with a shared pointer to the
// logger.
// If a logger deleted while having pending messages in the queue, it's actual
// destruction will defer
// until all its messages are processed by the thread pool.
// This is because each message in the queue holds a shared_ptr to the
// originating logger.
#include <spdlog/async_logger.h>
#include <spdlog/details/registry.h>
#include <spdlog/details/thread_pool.h>
#include <functional>
#include <memory>
#include <mutex>
namespace spdlog {
namespace details {
static const size_t default_async_q_size = 8192;
}
// async logger factory - creates async loggers backed with thread pool.
// if a global thread pool doesn't already exist, create it with default queue
// size of 8192 items and single thread.
template <async_overflow_policy OverflowPolicy = async_overflow_policy::block>
struct async_factory_impl {
template <typename Sink, typename... SinkArgs>
static std::shared_ptr<async_logger> create(std::string logger_name, SinkArgs &&...args) {
auto &registry_inst = details::registry::instance();
// create global thread pool if not already exists..
auto &mutex = registry_inst.tp_mutex();
std::lock_guard<std::recursive_mutex> tp_lock(mutex);
auto tp = registry_inst.get_tp();
if (tp == nullptr) {
tp = std::make_shared<details::thread_pool>(details::default_async_q_size, 1U);
registry_inst.set_tp(tp);
}
auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...);
auto new_logger = std::make_shared<async_logger>(std::move(logger_name), std::move(sink),
std::move(tp), OverflowPolicy);
registry_inst.initialize_logger(new_logger);
return new_logger;
}
};
using async_factory = async_factory_impl<async_overflow_policy::block>;
using async_factory_nonblock = async_factory_impl<async_overflow_policy::overrun_oldest>;
template <typename Sink, typename... SinkArgs>
inline std::shared_ptr<spdlog::logger> create_async(std::string logger_name,
SinkArgs &&...sink_args) {
return async_factory::create<Sink>(std::move(logger_name),
std::forward<SinkArgs>(sink_args)...);
}
template <typename Sink, typename... SinkArgs>
inline std::shared_ptr<spdlog::logger> create_async_nb(std::string logger_name,
SinkArgs &&...sink_args) {
return async_factory_nonblock::create<Sink>(std::move(logger_name),
std::forward<SinkArgs>(sink_args)...);
}
// set global thread pool.
inline void init_thread_pool(size_t q_size,
size_t thread_count,
std::function<void()> on_thread_start,
std::function<void()> on_thread_stop) {
auto tp = std::make_shared<details::thread_pool>(q_size, thread_count, on_thread_start,
on_thread_stop);
details::registry::instance().set_tp(std::move(tp));
}
inline void init_thread_pool(size_t q_size,
size_t thread_count,
std::function<void()> on_thread_start) {
init_thread_pool(q_size, thread_count, on_thread_start, [] {});
}
inline void init_thread_pool(size_t q_size, size_t thread_count) {
init_thread_pool(
q_size, thread_count, [] {}, [] {});
}
// get the global thread pool.
inline std::shared_ptr<spdlog::details::thread_pool> thread_pool() {
return details::registry::instance().get_tp();
}
} // namespace spdlog

View File

@@ -1,86 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifndef SPDLOG_HEADER_ONLY
#include <spdlog/async_logger.h>
#endif
#include <spdlog/details/thread_pool.h>
#include <spdlog/sinks/sink.h>
#include <memory>
#include <string>
SPDLOG_INLINE spdlog::async_logger::async_logger(std::string logger_name,
sinks_init_list sinks_list,
std::weak_ptr<details::thread_pool> tp,
async_overflow_policy overflow_policy)
: async_logger(std::move(logger_name),
sinks_list.begin(),
sinks_list.end(),
std::move(tp),
overflow_policy) {}
SPDLOG_INLINE spdlog::async_logger::async_logger(std::string logger_name,
sink_ptr single_sink,
std::weak_ptr<details::thread_pool> tp,
async_overflow_policy overflow_policy)
: async_logger(
std::move(logger_name), {std::move(single_sink)}, std::move(tp), overflow_policy) {}
// send the log message to the thread pool
SPDLOG_INLINE void spdlog::async_logger::sink_it_(const details::log_msg &msg){
SPDLOG_TRY{if (auto pool_ptr = thread_pool_.lock()){
pool_ptr->post_log(shared_from_this(), msg, overflow_policy_);
}
else {
throw_spdlog_ex("async log: thread pool doesn't exist anymore");
}
}
SPDLOG_LOGGER_CATCH(msg.source)
}
// send flush request to the thread pool
SPDLOG_INLINE void spdlog::async_logger::flush_(){SPDLOG_TRY{auto pool_ptr = thread_pool_.lock();
if (!pool_ptr) {
throw_spdlog_ex("async flush: thread pool doesn't exist anymore");
}
std::future<void> future = pool_ptr->post_flush(shared_from_this(), overflow_policy_);
// Wait for the flush operation to complete.
// This might throw exception if the flush message get dropped because of overflow.
future.get();
}
SPDLOG_LOGGER_CATCH(source_loc())
}
//
// backend functions - called from the thread pool to do the actual job
//
SPDLOG_INLINE void spdlog::async_logger::backend_sink_it_(const details::log_msg &msg) {
for (auto &sink : sinks_) {
if (sink->should_log(msg.level)) {
SPDLOG_TRY { sink->log(msg); }
SPDLOG_LOGGER_CATCH(msg.source)
}
}
if (should_flush_(msg)) {
backend_flush_();
}
}
SPDLOG_INLINE void spdlog::async_logger::backend_flush_() {
for (auto &sink : sinks_) {
SPDLOG_TRY { sink->flush(); }
SPDLOG_LOGGER_CATCH(source_loc())
}
}
SPDLOG_INLINE std::shared_ptr<spdlog::logger> spdlog::async_logger::clone(std::string new_name) {
auto cloned = std::make_shared<spdlog::async_logger>(*this);
cloned->name_ = std::move(new_name);
return cloned;
}

View File

@@ -1,74 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
// Fast asynchronous logger.
// Uses pre allocated queue.
// Creates a single back thread to pop messages from the queue and log them.
//
// Upon each log write the logger:
// 1. Checks if its log level is enough to log the message
// 2. Push a new copy of the message to a queue (or block the caller until
// space is available in the queue)
// Upon destruction, logs all remaining messages in the queue before
// destructing..
#include <spdlog/logger.h>
namespace spdlog {
// Async overflow policy - block by default.
enum class async_overflow_policy {
block, // Block until message can be enqueued
overrun_oldest, // Discard oldest message in the queue if full when trying to
// add new item.
discard_new // Discard new message if the queue is full when trying to add new item.
};
namespace details {
class thread_pool;
}
class SPDLOG_API async_logger final : public std::enable_shared_from_this<async_logger>,
public logger {
friend class details::thread_pool;
public:
template <typename It>
async_logger(std::string logger_name,
It begin,
It end,
std::weak_ptr<details::thread_pool> tp,
async_overflow_policy overflow_policy = async_overflow_policy::block)
: logger(std::move(logger_name), begin, end),
thread_pool_(std::move(tp)),
overflow_policy_(overflow_policy) {}
async_logger(std::string logger_name,
sinks_init_list sinks_list,
std::weak_ptr<details::thread_pool> tp,
async_overflow_policy overflow_policy = async_overflow_policy::block);
async_logger(std::string logger_name,
sink_ptr single_sink,
std::weak_ptr<details::thread_pool> tp,
async_overflow_policy overflow_policy = async_overflow_policy::block);
std::shared_ptr<logger> clone(std::string new_name) override;
protected:
void sink_it_(const details::log_msg &msg) override;
void flush_() override;
void backend_sink_it_(const details::log_msg &incoming_log_msg);
void backend_flush_();
private:
std::weak_ptr<details::thread_pool> thread_pool_;
async_overflow_policy overflow_policy_;
};
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
#include "async_logger-inl.h"
#endif

View File

@@ -1,40 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/cfg/helpers.h>
#include <spdlog/details/registry.h>
//
// Init log levels using each argv entry that starts with "SPDLOG_LEVEL="
//
// set all loggers to debug level:
// example.exe "SPDLOG_LEVEL=debug"
// set logger1 to trace level
// example.exe "SPDLOG_LEVEL=logger1=trace"
// turn off all logging except for logger1 and logger2:
// example.exe "SPDLOG_LEVEL=off,logger1=debug,logger2=info"
namespace spdlog {
namespace cfg {
// search for SPDLOG_LEVEL= in the args and use it to init the levels
inline void load_argv_levels(int argc, const char **argv) {
const std::string spdlog_level_prefix = "SPDLOG_LEVEL=";
for (int i = 1; i < argc; i++) {
std::string arg = argv[i];
if (arg.find(spdlog_level_prefix) == 0) {
auto levels_string = arg.substr(spdlog_level_prefix.size());
helpers::load_levels(levels_string);
}
}
}
inline void load_argv_levels(int argc, char **argv) {
load_argv_levels(argc, const_cast<const char **>(argv));
}
} // namespace cfg
} // namespace spdlog

View File

@@ -1,36 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/cfg/helpers.h>
#include <spdlog/details/os.h>
#include <spdlog/details/registry.h>
//
// Init levels and patterns from env variables SPDLOG_LEVEL
// Inspired from Rust's "env_logger" crate (https://crates.io/crates/env_logger).
// Note - fallback to "info" level on unrecognized levels
//
// Examples:
//
// set global level to debug:
// export SPDLOG_LEVEL=debug
//
// turn off all logging except for logger1:
// export SPDLOG_LEVEL="*=off,logger1=debug"
//
// turn off all logging except for logger1 and logger2:
// export SPDLOG_LEVEL="off,logger1=debug,logger2=info"
namespace spdlog {
namespace cfg {
inline void load_env_levels() {
auto env_val = details::os::getenv("SPDLOG_LEVEL");
if (!env_val.empty()) {
helpers::load_levels(env_val);
}
}
} // namespace cfg
} // namespace spdlog

View File

@@ -1,107 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifndef SPDLOG_HEADER_ONLY
#include <spdlog/cfg/helpers.h>
#endif
#include <spdlog/details/os.h>
#include <spdlog/details/registry.h>
#include <spdlog/spdlog.h>
#include <algorithm>
#include <sstream>
#include <string>
#include <utility>
namespace spdlog {
namespace cfg {
namespace helpers {
// inplace convert to lowercase
inline std::string &to_lower_(std::string &str) {
std::transform(str.begin(), str.end(), str.begin(), [](char ch) {
return static_cast<char>((ch >= 'A' && ch <= 'Z') ? ch + ('a' - 'A') : ch);
});
return str;
}
// inplace trim spaces
inline std::string &trim_(std::string &str) {
const char *spaces = " \n\r\t";
str.erase(str.find_last_not_of(spaces) + 1);
str.erase(0, str.find_first_not_of(spaces));
return str;
}
// return (name,value) trimmed pair from given "name=value" string.
// return empty string on missing parts
// "key=val" => ("key", "val")
// " key = val " => ("key", "val")
// "key=" => ("key", "")
// "val" => ("", "val")
inline std::pair<std::string, std::string> extract_kv_(char sep, const std::string &str) {
auto n = str.find(sep);
std::string k, v;
if (n == std::string::npos) {
v = str;
} else {
k = str.substr(0, n);
v = str.substr(n + 1);
}
return std::make_pair(trim_(k), trim_(v));
}
// return vector of key/value pairs from sequence of "K1=V1,K2=V2,.."
// "a=AAA,b=BBB,c=CCC,.." => {("a","AAA"),("b","BBB"),("c", "CCC"),...}
inline std::unordered_map<std::string, std::string> extract_key_vals_(const std::string &str) {
std::string token;
std::istringstream token_stream(str);
std::unordered_map<std::string, std::string> rv{};
while (std::getline(token_stream, token, ',')) {
if (token.empty()) {
continue;
}
auto kv = extract_kv_('=', token);
rv[kv.first] = kv.second;
}
return rv;
}
SPDLOG_INLINE void load_levels(const std::string &input) {
if (input.empty() || input.size() > 512) {
return;
}
auto key_vals = extract_key_vals_(input);
std::unordered_map<std::string, level::level_enum> levels;
level::level_enum global_level = level::info;
bool global_level_found = false;
for (auto &name_level : key_vals) {
auto &logger_name = name_level.first;
auto level_name = to_lower_(name_level.second);
auto level = level::from_str(level_name);
// ignore unrecognized level names
if (level == level::off && level_name != "off") {
continue;
}
if (logger_name.empty()) // no logger name indicate global level
{
global_level_found = true;
global_level = level;
} else {
levels[logger_name] = level;
}
}
details::registry::instance().set_levels(std::move(levels),
global_level_found ? &global_level : nullptr);
}
} // namespace helpers
} // namespace cfg
} // namespace spdlog

View File

@@ -1,29 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/common.h>
#include <unordered_map>
namespace spdlog {
namespace cfg {
namespace helpers {
//
// Init levels from given string
//
// Examples:
//
// set global level to debug: "debug"
// turn off all logging except for logger1: "off,logger1=debug"
// turn off all logging except for logger1 and logger2: "off,logger1=debug,logger2=info"
//
SPDLOG_API void load_levels(const std::string &txt);
} // namespace helpers
} // namespace cfg
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
#include "helpers-inl.h"
#endif // SPDLOG_HEADER_ONLY

View File

@@ -1,68 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifndef SPDLOG_HEADER_ONLY
#include <spdlog/common.h>
#endif
#include <algorithm>
#include <iterator>
namespace spdlog {
namespace level {
#if __cplusplus >= 201703L
constexpr
#endif
static string_view_t level_string_views[] SPDLOG_LEVEL_NAMES;
static const char *short_level_names[] SPDLOG_SHORT_LEVEL_NAMES;
SPDLOG_INLINE const string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT {
return level_string_views[l];
}
SPDLOG_INLINE const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT {
return short_level_names[l];
}
SPDLOG_INLINE spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT {
auto it = std::find(std::begin(level_string_views), std::end(level_string_views), name);
if (it != std::end(level_string_views))
return static_cast<level::level_enum>(std::distance(std::begin(level_string_views), it));
// check also for "warn" and "err" before giving up..
if (name == "warn") {
return level::warn;
}
if (name == "err") {
return level::err;
}
return level::off;
}
} // namespace level
SPDLOG_INLINE spdlog_ex::spdlog_ex(std::string msg)
: msg_(std::move(msg)) {}
SPDLOG_INLINE spdlog_ex::spdlog_ex(const std::string &msg, int last_errno) {
#ifdef SPDLOG_USE_STD_FORMAT
msg_ = std::system_error(std::error_code(last_errno, std::generic_category()), msg).what();
#else
memory_buf_t outbuf;
fmt::format_system_error(outbuf, last_errno, msg.c_str());
msg_ = fmt::to_string(outbuf);
#endif
}
SPDLOG_INLINE const char *spdlog_ex::what() const SPDLOG_NOEXCEPT { return msg_.c_str(); }
SPDLOG_INLINE void throw_spdlog_ex(const std::string &msg, int last_errno) {
SPDLOG_THROW(spdlog_ex(msg, last_errno));
}
SPDLOG_INLINE void throw_spdlog_ex(std::string msg) { SPDLOG_THROW(spdlog_ex(std::move(msg))); }
} // namespace spdlog

View File

@@ -1,411 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/details/null_mutex.h>
#include <spdlog/tweakme.h>
#include <atomic>
#include <chrono>
#include <cstdio>
#include <exception>
#include <functional>
#include <initializer_list>
#include <memory>
#include <string>
#include <type_traits>
#ifdef SPDLOG_USE_STD_FORMAT
#include <version>
#if __cpp_lib_format >= 202207L
#include <format>
#else
#include <string_view>
#endif
#endif
#ifdef SPDLOG_COMPILED_LIB
#undef SPDLOG_HEADER_ONLY
#if defined(SPDLOG_SHARED_LIB)
#if defined(_WIN32)
#ifdef spdlog_EXPORTS
#define SPDLOG_API __declspec(dllexport)
#else // !spdlog_EXPORTS
#define SPDLOG_API __declspec(dllimport)
#endif
#else // !defined(_WIN32)
#define SPDLOG_API __attribute__((visibility("default")))
#endif
#else // !defined(SPDLOG_SHARED_LIB)
#define SPDLOG_API
#endif
#define SPDLOG_INLINE
#else // !defined(SPDLOG_COMPILED_LIB)
#define SPDLOG_API
#define SPDLOG_HEADER_ONLY
#define SPDLOG_INLINE inline
#endif // #ifdef SPDLOG_COMPILED_LIB
#include <spdlog/fmt/fmt.h>
#if !defined(SPDLOG_USE_STD_FORMAT) && \
FMT_VERSION >= 80000 // backward compatibility with fmt versions older than 8
#define SPDLOG_FMT_RUNTIME(format_string) fmt::runtime(format_string)
#define SPDLOG_FMT_STRING(format_string) FMT_STRING(format_string)
#if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
#include <spdlog/fmt/xchar.h>
#endif
#else
#define SPDLOG_FMT_RUNTIME(format_string) format_string
#define SPDLOG_FMT_STRING(format_string) format_string
#endif
// visual studio up to 2013 does not support noexcept nor constexpr
#if defined(_MSC_VER) && (_MSC_VER < 1900)
#define SPDLOG_NOEXCEPT _NOEXCEPT
#define SPDLOG_CONSTEXPR
#else
#define SPDLOG_NOEXCEPT noexcept
#define SPDLOG_CONSTEXPR constexpr
#endif
// If building with std::format, can just use constexpr, otherwise if building with fmt
// SPDLOG_CONSTEXPR_FUNC needs to be set the same as FMT_CONSTEXPR to avoid situations where
// a constexpr function in spdlog could end up calling a non-constexpr function in fmt
// depending on the compiler
// If fmt determines it can't use constexpr, we should inline the function instead
#ifdef SPDLOG_USE_STD_FORMAT
#define SPDLOG_CONSTEXPR_FUNC constexpr
#else // Being built with fmt
#if FMT_USE_CONSTEXPR
#define SPDLOG_CONSTEXPR_FUNC FMT_CONSTEXPR
#else
#define SPDLOG_CONSTEXPR_FUNC inline
#endif
#endif
#if defined(__GNUC__) || defined(__clang__)
#define SPDLOG_DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
#define SPDLOG_DEPRECATED __declspec(deprecated)
#else
#define SPDLOG_DEPRECATED
#endif
// disable thread local on msvc 2013
#ifndef SPDLOG_NO_TLS
#if (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__cplusplus_winrt)
#define SPDLOG_NO_TLS 1
#endif
#endif
#ifndef SPDLOG_FUNCTION
#define SPDLOG_FUNCTION static_cast<const char *>(__FUNCTION__)
#endif
#ifdef SPDLOG_NO_EXCEPTIONS
#define SPDLOG_TRY
#define SPDLOG_THROW(ex) \
do { \
printf("spdlog fatal error: %s\n", ex.what()); \
std::abort(); \
} while (0)
#define SPDLOG_CATCH_STD
#else
#define SPDLOG_TRY try
#define SPDLOG_THROW(ex) throw(ex)
#define SPDLOG_CATCH_STD \
catch (const std::exception &) { \
}
#endif
namespace spdlog {
class formatter;
namespace sinks {
class sink;
}
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
using filename_t = std::wstring;
// allow macro expansion to occur in SPDLOG_FILENAME_T
#define SPDLOG_FILENAME_T_INNER(s) L##s
#define SPDLOG_FILENAME_T(s) SPDLOG_FILENAME_T_INNER(s)
#else
using filename_t = std::string;
#define SPDLOG_FILENAME_T(s) s
#endif
using log_clock = std::chrono::system_clock;
using sink_ptr = std::shared_ptr<sinks::sink>;
using sinks_init_list = std::initializer_list<sink_ptr>;
using err_handler = std::function<void(const std::string &err_msg)>;
#ifdef SPDLOG_USE_STD_FORMAT
namespace fmt_lib = std;
using string_view_t = std::string_view;
using memory_buf_t = std::string;
template <typename... Args>
#if __cpp_lib_format >= 202207L
using format_string_t = std::format_string<Args...>;
#else
using format_string_t = std::string_view;
#endif
template <class T, class Char = char>
struct is_convertible_to_basic_format_string
: std::integral_constant<bool, std::is_convertible<T, std::basic_string_view<Char>>::value> {};
#if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
using wstring_view_t = std::wstring_view;
using wmemory_buf_t = std::wstring;
template <typename... Args>
#if __cpp_lib_format >= 202207L
using wformat_string_t = std::wformat_string<Args...>;
#else
using wformat_string_t = std::wstring_view;
#endif
#endif
#define SPDLOG_BUF_TO_STRING(x) x
#else // use fmt lib instead of std::format
namespace fmt_lib = fmt;
using string_view_t = fmt::basic_string_view<char>;
using memory_buf_t = fmt::basic_memory_buffer<char, 250>;
template <typename... Args>
using format_string_t = fmt::format_string<Args...>;
template <class T>
using remove_cvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
template <typename Char>
#if FMT_VERSION >= 90101
using fmt_runtime_string = fmt::runtime_format_string<Char>;
#else
using fmt_runtime_string = fmt::basic_runtime<Char>;
#endif
// clang doesn't like SFINAE disabled constructor in std::is_convertible<> so have to repeat the
// condition from basic_format_string here, in addition, fmt::basic_runtime<Char> is only
// convertible to basic_format_string<Char> but not basic_string_view<Char>
template <class T, class Char = char>
struct is_convertible_to_basic_format_string
: std::integral_constant<bool,
std::is_convertible<T, fmt::basic_string_view<Char>>::value ||
std::is_same<remove_cvref_t<T>, fmt_runtime_string<Char>>::value> {
};
#if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
using wstring_view_t = fmt::basic_string_view<wchar_t>;
using wmemory_buf_t = fmt::basic_memory_buffer<wchar_t, 250>;
template <typename... Args>
using wformat_string_t = fmt::wformat_string<Args...>;
#endif
#define SPDLOG_BUF_TO_STRING(x) fmt::to_string(x)
#endif
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
#ifndef _WIN32
#error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows
#endif // _WIN32
#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT
template <class T>
struct is_convertible_to_any_format_string
: std::integral_constant<bool,
is_convertible_to_basic_format_string<T, char>::value ||
is_convertible_to_basic_format_string<T, wchar_t>::value> {};
#if defined(SPDLOG_NO_ATOMIC_LEVELS)
using level_t = details::null_atomic_int;
#else
using level_t = std::atomic<int>;
#endif
#define SPDLOG_LEVEL_TRACE 0
#define SPDLOG_LEVEL_DEBUG 1
#define SPDLOG_LEVEL_INFO 2
#define SPDLOG_LEVEL_WARN 3
#define SPDLOG_LEVEL_ERROR 4
#define SPDLOG_LEVEL_CRITICAL 5
#define SPDLOG_LEVEL_OFF 6
#if !defined(SPDLOG_ACTIVE_LEVEL)
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO
#endif
// Log level enum
namespace level {
enum level_enum : int {
trace = SPDLOG_LEVEL_TRACE,
debug = SPDLOG_LEVEL_DEBUG,
info = SPDLOG_LEVEL_INFO,
warn = SPDLOG_LEVEL_WARN,
err = SPDLOG_LEVEL_ERROR,
critical = SPDLOG_LEVEL_CRITICAL,
off = SPDLOG_LEVEL_OFF,
n_levels
};
#define SPDLOG_LEVEL_NAME_TRACE spdlog::string_view_t("trace", 5)
#define SPDLOG_LEVEL_NAME_DEBUG spdlog::string_view_t("debug", 5)
#define SPDLOG_LEVEL_NAME_INFO spdlog::string_view_t("info", 4)
#define SPDLOG_LEVEL_NAME_WARNING spdlog::string_view_t("warning", 7)
#define SPDLOG_LEVEL_NAME_ERROR spdlog::string_view_t("error", 5)
#define SPDLOG_LEVEL_NAME_CRITICAL spdlog::string_view_t("critical", 8)
#define SPDLOG_LEVEL_NAME_OFF spdlog::string_view_t("off", 3)
#if !defined(SPDLOG_LEVEL_NAMES)
#define SPDLOG_LEVEL_NAMES \
{ \
SPDLOG_LEVEL_NAME_TRACE, SPDLOG_LEVEL_NAME_DEBUG, SPDLOG_LEVEL_NAME_INFO, \
SPDLOG_LEVEL_NAME_WARNING, SPDLOG_LEVEL_NAME_ERROR, SPDLOG_LEVEL_NAME_CRITICAL, \
SPDLOG_LEVEL_NAME_OFF \
}
#endif
#if !defined(SPDLOG_SHORT_LEVEL_NAMES)
#define SPDLOG_SHORT_LEVEL_NAMES \
{ "T", "D", "I", "W", "E", "C", "O" }
#endif
SPDLOG_API const string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT;
SPDLOG_API const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT;
SPDLOG_API spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT;
} // namespace level
//
// Color mode used by sinks with color support.
//
enum class color_mode { always, automatic, never };
//
// Pattern time - specific time getting to use for pattern_formatter.
// local time by default
//
enum class pattern_time_type {
local, // log localtime
utc // log utc
};
//
// Log exception
//
class SPDLOG_API spdlog_ex : public std::exception {
public:
explicit spdlog_ex(std::string msg);
spdlog_ex(const std::string &msg, int last_errno);
const char *what() const SPDLOG_NOEXCEPT override;
private:
std::string msg_;
};
[[noreturn]] SPDLOG_API void throw_spdlog_ex(const std::string &msg, int last_errno);
[[noreturn]] SPDLOG_API void throw_spdlog_ex(std::string msg);
struct source_loc {
SPDLOG_CONSTEXPR source_loc() = default;
SPDLOG_CONSTEXPR source_loc(const char *filename_in, int line_in, const char *funcname_in)
: filename{filename_in},
line{line_in},
funcname{funcname_in} {}
SPDLOG_CONSTEXPR bool empty() const SPDLOG_NOEXCEPT { return line <= 0; }
const char *filename{nullptr};
int line{0};
const char *funcname{nullptr};
};
struct file_event_handlers {
file_event_handlers()
: before_open(nullptr),
after_open(nullptr),
before_close(nullptr),
after_close(nullptr) {}
std::function<void(const filename_t &filename)> before_open;
std::function<void(const filename_t &filename, std::FILE *file_stream)> after_open;
std::function<void(const filename_t &filename, std::FILE *file_stream)> before_close;
std::function<void(const filename_t &filename)> after_close;
};
namespace details {
// to_string_view
SPDLOG_CONSTEXPR_FUNC spdlog::string_view_t to_string_view(const memory_buf_t &buf)
SPDLOG_NOEXCEPT {
return spdlog::string_view_t{buf.data(), buf.size()};
}
SPDLOG_CONSTEXPR_FUNC spdlog::string_view_t to_string_view(spdlog::string_view_t str)
SPDLOG_NOEXCEPT {
return str;
}
#if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
SPDLOG_CONSTEXPR_FUNC spdlog::wstring_view_t to_string_view(const wmemory_buf_t &buf)
SPDLOG_NOEXCEPT {
return spdlog::wstring_view_t{buf.data(), buf.size()};
}
SPDLOG_CONSTEXPR_FUNC spdlog::wstring_view_t to_string_view(spdlog::wstring_view_t str)
SPDLOG_NOEXCEPT {
return str;
}
#endif
#ifndef SPDLOG_USE_STD_FORMAT
template <typename T, typename... Args>
inline fmt::basic_string_view<T> to_string_view(fmt::basic_format_string<T, Args...> fmt) {
return fmt;
}
#elif __cpp_lib_format >= 202207L
template <typename T, typename... Args>
SPDLOG_CONSTEXPR_FUNC std::basic_string_view<T> to_string_view(
std::basic_format_string<T, Args...> fmt) SPDLOG_NOEXCEPT {
return fmt.get();
}
#endif
// make_unique support for pre c++14
#if __cplusplus >= 201402L // C++14 and beyond
using std::enable_if_t;
using std::make_unique;
#else
template <bool B, class T = void>
using enable_if_t = typename std::enable_if<B, T>::type;
template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args &&...args) {
static_assert(!std::is_array<T>::value, "arrays not supported");
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
#endif
// 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>
constexpr 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>
constexpr T conditional_static_cast(U value) {
return value;
}
} // namespace details
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
#include "common-inl.h"
#endif

View File

@@ -1,63 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifndef SPDLOG_HEADER_ONLY
#include <spdlog/details/backtracer.h>
#endif
namespace spdlog {
namespace details {
SPDLOG_INLINE backtracer::backtracer(const backtracer &other) {
std::lock_guard<std::mutex> lock(other.mutex_);
enabled_ = other.enabled();
messages_ = other.messages_;
}
SPDLOG_INLINE backtracer::backtracer(backtracer &&other) SPDLOG_NOEXCEPT {
std::lock_guard<std::mutex> lock(other.mutex_);
enabled_ = other.enabled();
messages_ = std::move(other.messages_);
}
SPDLOG_INLINE backtracer &backtracer::operator=(backtracer other) {
std::lock_guard<std::mutex> lock(mutex_);
enabled_ = other.enabled();
messages_ = std::move(other.messages_);
return *this;
}
SPDLOG_INLINE void backtracer::enable(size_t size) {
std::lock_guard<std::mutex> lock{mutex_};
enabled_.store(true, std::memory_order_relaxed);
messages_ = circular_q<log_msg_buffer>{size};
}
SPDLOG_INLINE void backtracer::disable() {
std::lock_guard<std::mutex> lock{mutex_};
enabled_.store(false, std::memory_order_relaxed);
}
SPDLOG_INLINE bool backtracer::enabled() const { return enabled_.load(std::memory_order_relaxed); }
SPDLOG_INLINE void backtracer::push_back(const log_msg &msg) {
std::lock_guard<std::mutex> lock{mutex_};
messages_.push_back(log_msg_buffer{msg});
}
SPDLOG_INLINE bool backtracer::empty() const {
std::lock_guard<std::mutex> lock{mutex_};
return messages_.empty();
}
// pop all items in the q and apply the given fun on each of them.
SPDLOG_INLINE void backtracer::foreach_pop(std::function<void(const details::log_msg &)> fun) {
std::lock_guard<std::mutex> lock{mutex_};
while (!messages_.empty()) {
auto &front_msg = messages_.front();
fun(front_msg);
messages_.pop_front();
}
}
} // namespace details
} // namespace spdlog

View File

@@ -1,45 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/details/circular_q.h>
#include <spdlog/details/log_msg_buffer.h>
#include <atomic>
#include <functional>
#include <mutex>
// Store log messages in circular buffer.
// Useful for storing debug data in case of error/warning happens.
namespace spdlog {
namespace details {
class SPDLOG_API backtracer {
mutable std::mutex mutex_;
std::atomic<bool> enabled_{false};
circular_q<log_msg_buffer> messages_;
public:
backtracer() = default;
backtracer(const backtracer &other);
backtracer(backtracer &&other) SPDLOG_NOEXCEPT;
backtracer &operator=(backtracer other);
void enable(size_t size);
void disable();
bool enabled() const;
void push_back(const log_msg &msg);
bool empty() const;
// pop all items in the q and apply the given fun on each of them.
void foreach_pop(std::function<void(const details::log_msg &)> fun);
};
} // namespace details
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
#include "backtracer-inl.h"
#endif

View File

@@ -1,115 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
// circular q view of std::vector.
#pragma once
#include <cassert>
#include <vector>
#include "spdlog/common.h"
namespace spdlog {
namespace details {
template <typename T>
class circular_q {
size_t max_items_ = 0;
typename std::vector<T>::size_type head_ = 0;
typename std::vector<T>::size_type tail_ = 0;
size_t overrun_counter_ = 0;
std::vector<T> v_;
public:
using value_type = T;
// empty ctor - create a disabled queue with no elements allocated at all
circular_q() = default;
explicit circular_q(size_t max_items)
: max_items_(max_items + 1) // one item is reserved as marker for full q
,
v_(max_items_) {}
circular_q(const circular_q &) = default;
circular_q &operator=(const circular_q &) = default;
// move cannot be default,
// since we need to reset head_, tail_, etc to zero in the moved object
circular_q(circular_q &&other) SPDLOG_NOEXCEPT { copy_moveable(std::move(other)); }
circular_q &operator=(circular_q &&other) SPDLOG_NOEXCEPT {
copy_moveable(std::move(other));
return *this;
}
// push back, overrun (oldest) item if no room left
void push_back(T &&item) {
if (max_items_ > 0) {
v_[tail_] = std::move(item);
tail_ = (tail_ + 1) % max_items_;
if (tail_ == head_) // overrun last item if full
{
head_ = (head_ + 1) % max_items_;
++overrun_counter_;
}
}
}
// Return reference to the front item.
// If there are no elements in the container, the behavior is undefined.
const T &front() const { return v_[head_]; }
T &front() { return v_[head_]; }
// Return number of elements actually stored
size_t size() const {
if (tail_ >= head_) {
return tail_ - head_;
} else {
return max_items_ - (head_ - tail_);
}
}
// Return const reference to item by index.
// If index is out of range 0…size()-1, the behavior is undefined.
const T &at(size_t i) const {
assert(i < size());
return v_[(head_ + i) % max_items_];
}
// Pop item from front.
// If there are no elements in the container, the behavior is undefined.
void pop_front() { head_ = (head_ + 1) % max_items_; }
bool empty() const { return tail_ == head_; }
bool full() const {
// head is ahead of the tail by 1
if (max_items_ > 0) {
return ((tail_ + 1) % max_items_) == head_;
}
return false;
}
size_t overrun_counter() const { return overrun_counter_; }
void reset_overrun_counter() { overrun_counter_ = 0; }
private:
// copy from other&& and reset it to disabled state
void copy_moveable(circular_q &&other) SPDLOG_NOEXCEPT {
max_items_ = other.max_items_;
head_ = other.head_;
tail_ = other.tail_;
overrun_counter_ = other.overrun_counter_;
v_ = std::move(other.v_);
// put &&other in disabled, but valid state
other.max_items_ = 0;
other.head_ = other.tail_ = 0;
other.overrun_counter_ = 0;
}
};
} // namespace details
} // namespace spdlog

View File

@@ -1,28 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <mutex>
#include <spdlog/details/null_mutex.h>
namespace spdlog {
namespace details {
struct console_mutex {
using mutex_t = std::mutex;
static mutex_t &mutex() {
static mutex_t s_mutex;
return s_mutex;
}
};
struct console_nullmutex {
using mutex_t = null_mutex;
static mutex_t &mutex() {
static mutex_t s_mutex;
return s_mutex;
}
};
} // namespace details
} // namespace spdlog

View File

@@ -1,152 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifndef SPDLOG_HEADER_ONLY
#include <spdlog/details/file_helper.h>
#endif
#include <spdlog/common.h>
#include <spdlog/details/os.h>
#include <cerrno>
#include <chrono>
#include <cstdio>
#include <string>
#include <thread>
#include <tuple>
namespace spdlog {
namespace details {
SPDLOG_INLINE file_helper::file_helper(const file_event_handlers &event_handlers)
: event_handlers_(event_handlers) {}
SPDLOG_INLINE file_helper::~file_helper() { close(); }
SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate) {
close();
filename_ = fname;
auto *mode = SPDLOG_FILENAME_T("ab");
auto *trunc_mode = SPDLOG_FILENAME_T("wb");
if (event_handlers_.before_open) {
event_handlers_.before_open(filename_);
}
for (int tries = 0; tries < open_tries_; ++tries) {
// create containing folder if not exists already.
os::create_dir(os::dir_name(fname));
if (truncate) {
// Truncate by opening-and-closing a tmp file in "wb" mode, always
// opening the actual log-we-write-to in "ab" mode, since that
// interacts more politely with eternal processes that might
// rotate/truncate the file underneath us.
std::FILE *tmp;
if (os::fopen_s(&tmp, fname, trunc_mode)) {
continue;
}
std::fclose(tmp);
}
if (!os::fopen_s(&fd_, fname, mode)) {
if (event_handlers_.after_open) {
event_handlers_.after_open(filename_, fd_);
}
return;
}
details::os::sleep_for_millis(open_interval_);
}
throw_spdlog_ex("Failed opening file " + os::filename_to_str(filename_) + " for writing",
errno);
}
SPDLOG_INLINE void file_helper::reopen(bool truncate) {
if (filename_.empty()) {
throw_spdlog_ex("Failed re opening file - was not opened before");
}
this->open(filename_, truncate);
}
SPDLOG_INLINE void file_helper::flush() {
if (std::fflush(fd_) != 0) {
throw_spdlog_ex("Failed flush to file " + os::filename_to_str(filename_), errno);
}
}
SPDLOG_INLINE void file_helper::sync() {
if (!os::fsync(fd_)) {
throw_spdlog_ex("Failed to fsync file " + os::filename_to_str(filename_), errno);
}
}
SPDLOG_INLINE void file_helper::close() {
if (fd_ != nullptr) {
if (event_handlers_.before_close) {
event_handlers_.before_close(filename_, fd_);
}
std::fclose(fd_);
fd_ = nullptr;
if (event_handlers_.after_close) {
event_handlers_.after_close(filename_);
}
}
}
SPDLOG_INLINE void file_helper::write(const memory_buf_t &buf) {
if (fd_ == nullptr) return;
size_t msg_size = buf.size();
auto data = buf.data();
if (std::fwrite(data, 1, msg_size, fd_) != msg_size) {
throw_spdlog_ex("Failed writing to file " + os::filename_to_str(filename_), errno);
}
}
SPDLOG_INLINE size_t file_helper::size() const {
if (fd_ == nullptr) {
throw_spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(filename_));
}
return os::filesize(fd_);
}
SPDLOG_INLINE const filename_t &file_helper::filename() const { return filename_; }
//
// return file path and its extension:
//
// "mylog.txt" => ("mylog", ".txt")
// "mylog" => ("mylog", "")
// "mylog." => ("mylog.", "")
// "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt")
//
// the starting dot in filenames is ignored (hidden files):
//
// ".mylog" => (".mylog". "")
// "my_folder/.mylog" => ("my_folder/.mylog", "")
// "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt")
SPDLOG_INLINE std::tuple<filename_t, filename_t> file_helper::split_by_extension(
const filename_t &fname) {
auto ext_index = fname.rfind('.');
// no valid extension found - return whole path and empty string as
// extension
if (ext_index == filename_t::npos || ext_index == 0 || ext_index == fname.size() - 1) {
return std::make_tuple(fname, filename_t());
}
// treat cases like "/etc/rc.d/somelogfile or "/abc/.hiddenfile"
auto folder_index = fname.find_last_of(details::os::folder_seps_filename);
if (folder_index != filename_t::npos && folder_index >= ext_index - 1) {
return std::make_tuple(fname, filename_t());
}
// finally - return a valid base and extension tuple
return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index));
}
} // namespace details
} // namespace spdlog

View File

@@ -1,61 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/common.h>
#include <tuple>
namespace spdlog {
namespace details {
// Helper class for file sinks.
// When failing to open a file, retry several times(5) with a delay interval(10 ms).
// Throw spdlog_ex exception on errors.
class SPDLOG_API file_helper {
public:
file_helper() = default;
explicit file_helper(const file_event_handlers &event_handlers);
file_helper(const file_helper &) = delete;
file_helper &operator=(const file_helper &) = delete;
~file_helper();
void open(const filename_t &fname, bool truncate = false);
void reopen(bool truncate);
void flush();
void sync();
void close();
void write(const memory_buf_t &buf);
size_t size() const;
const filename_t &filename() const;
//
// return file path and its extension:
//
// "mylog.txt" => ("mylog", ".txt")
// "mylog" => ("mylog", "")
// "mylog." => ("mylog.", "")
// "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt")
//
// the starting dot in filenames is ignored (hidden files):
//
// ".mylog" => (".mylog". "")
// "my_folder/.mylog" => ("my_folder/.mylog", "")
// "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt")
static std::tuple<filename_t, filename_t> split_by_extension(const filename_t &fname);
private:
const int open_tries_ = 5;
const unsigned int open_interval_ = 10;
std::FILE *fd_{nullptr};
filename_t filename_;
file_event_handlers event_handlers_;
};
} // namespace details
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
#include "file_helper-inl.h"
#endif

View File

@@ -1,141 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <chrono>
#include <iterator>
#include <spdlog/common.h>
#include <spdlog/fmt/fmt.h>
#include <type_traits>
#ifdef SPDLOG_USE_STD_FORMAT
#include <charconv>
#include <limits>
#endif
// Some fmt helpers to efficiently format and pad ints and strings
namespace spdlog {
namespace details {
namespace fmt_helper {
inline void append_string_view(spdlog::string_view_t view, memory_buf_t &dest) {
auto *buf_ptr = view.data();
dest.append(buf_ptr, buf_ptr + view.size());
}
#ifdef SPDLOG_USE_STD_FORMAT
template <typename T>
inline void append_int(T n, memory_buf_t &dest) {
// Buffer should be large enough to hold all digits (digits10 + 1) and a sign
SPDLOG_CONSTEXPR const auto BUF_SIZE = std::numeric_limits<T>::digits10 + 2;
char buf[BUF_SIZE];
auto [ptr, ec] = std::to_chars(buf, buf + BUF_SIZE, n, 10);
if (ec == std::errc()) {
dest.append(buf, ptr);
} else {
throw_spdlog_ex("Failed to format int", static_cast<int>(ec));
}
}
#else
template <typename T>
inline void append_int(T n, memory_buf_t &dest) {
fmt::format_int i(n);
dest.append(i.data(), i.data() + i.size());
}
#endif
template <typename T>
SPDLOG_CONSTEXPR_FUNC unsigned int count_digits_fallback(T n) {
// taken from fmt: https://github.com/fmtlib/fmt/blob/8.0.1/include/fmt/format.h#L899-L912
unsigned int count = 1;
for (;;) {
// Integer division is slow so do it for a group of four digits instead
// of for every digit. The idea comes from the talk by Alexandrescu
// "Three Optimization Tips for C++". See speed-test for a comparison.
if (n < 10) return count;
if (n < 100) return count + 1;
if (n < 1000) return count + 2;
if (n < 10000) return count + 3;
n /= 10000u;
count += 4;
}
}
template <typename T>
inline unsigned int count_digits(T n) {
using count_type =
typename std::conditional<(sizeof(T) > sizeof(uint32_t)), uint64_t, uint32_t>::type;
#ifdef SPDLOG_USE_STD_FORMAT
return count_digits_fallback(static_cast<count_type>(n));
#else
return static_cast<unsigned int>(fmt::
// fmt 7.0.0 renamed the internal namespace to detail.
// See: https://github.com/fmtlib/fmt/issues/1538
#if FMT_VERSION < 70000
internal
#else
detail
#endif
::count_digits(static_cast<count_type>(n)));
#endif
}
inline void pad2(int n, memory_buf_t &dest) {
if (n >= 0 && n < 100) // 0-99
{
dest.push_back(static_cast<char>('0' + n / 10));
dest.push_back(static_cast<char>('0' + n % 10));
} else // unlikely, but just in case, let fmt deal with it
{
fmt_lib::format_to(std::back_inserter(dest), SPDLOG_FMT_STRING("{:02}"), n);
}
}
template <typename T>
inline void pad_uint(T n, unsigned int width, memory_buf_t &dest) {
static_assert(std::is_unsigned<T>::value, "pad_uint must get unsigned T");
for (auto digits = count_digits(n); digits < width; digits++) {
dest.push_back('0');
}
append_int(n, dest);
}
template <typename T>
inline void pad3(T n, memory_buf_t &dest) {
static_assert(std::is_unsigned<T>::value, "pad3 must get unsigned T");
if (n < 1000) {
dest.push_back(static_cast<char>(n / 100 + '0'));
n = n % 100;
dest.push_back(static_cast<char>((n / 10) + '0'));
dest.push_back(static_cast<char>((n % 10) + '0'));
} else {
append_int(n, dest);
}
}
template <typename T>
inline void pad6(T n, memory_buf_t &dest) {
pad_uint(n, 6, dest);
}
template <typename T>
inline void pad9(T n, memory_buf_t &dest) {
pad_uint(n, 9, dest);
}
// return fraction of a second of the given time_point.
// e.g.
// fraction<std::milliseconds>(tp) -> will return the millis part of the second
template <typename ToDuration>
inline ToDuration time_fraction(log_clock::time_point tp) {
using std::chrono::duration_cast;
using std::chrono::seconds;
auto duration = tp.time_since_epoch();
auto secs = duration_cast<seconds>(duration);
return duration_cast<ToDuration>(duration) - duration_cast<ToDuration>(secs);
}
} // namespace fmt_helper
} // namespace details
} // namespace spdlog

View File

@@ -1,44 +0,0 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifndef SPDLOG_HEADER_ONLY
#include <spdlog/details/log_msg.h>
#endif
#include <spdlog/details/os.h>
namespace spdlog {
namespace details {
SPDLOG_INLINE log_msg::log_msg(spdlog::log_clock::time_point log_time,
spdlog::source_loc loc,
string_view_t a_logger_name,
spdlog::level::level_enum lvl,
spdlog::string_view_t msg)
: logger_name(a_logger_name),
level(lvl),
time(log_time)
#ifndef SPDLOG_NO_THREAD_ID
,
thread_id(os::thread_id())
#endif
,
source(loc),
payload(msg) {
}
SPDLOG_INLINE log_msg::log_msg(spdlog::source_loc loc,
string_view_t a_logger_name,
spdlog::level::level_enum lvl,
spdlog::string_view_t msg)
: log_msg(os::now(), loc, a_logger_name, lvl, msg) {}
SPDLOG_INLINE log_msg::log_msg(string_view_t a_logger_name,
spdlog::level::level_enum lvl,
spdlog::string_view_t msg)
: log_msg(os::now(), source_loc{}, a_logger_name, lvl, msg) {}
} // namespace details
} // namespace spdlog

Some files were not shown because too many files have changed in this diff Show More