Introduction JSON extension

This commit is contained in:
ProjectSky 2025-10-18 20:58:40 +08:00
parent e4fda1bd78
commit 574423abee
15 changed files with 29728 additions and 0 deletions

View File

@ -678,6 +678,7 @@ else:
'extensions/tf2/AMBuilder',
'extensions/topmenus/AMBuilder',
'extensions/updater/AMBuilder',
'extensions/yyjson/AMBuilder',
]
if builder.backend == 'amb2':

28
extensions/yyjson/AMBuilder Executable file
View File

@ -0,0 +1,28 @@
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
import os
for cxx in builder.targets:
binary = SM.ExtLibrary(builder, cxx, 'yyjson.ext')
if binary.compiler.family == 'gcc' or binary.compiler.family == 'clang':
binary.compiler.cxxflags += ['-fno-rtti']
binary.compiler.cflags += ['-fPIC']
elif binary.compiler.family == 'msvc':
binary.compiler.cxxflags += ['/GR-']
binary.compiler.defines += [
'YYJSON_DISABLE_INCR_READER',
]
binary.compiler.cxxincludes += [
os.path.join(builder.sourcePath, 'extensions', 'yyjson', 'yyjson'),
]
binary.sources += [
'extension.cpp',
'YYJSONManager.cpp',
'json_natives.cpp',
'yyjson/yyjson.c',
'../../public/smsdk_ext.cpp',
]
SM.extensions += [builder.Add(binary)]

1339
extensions/yyjson/IYYJSONManager.h Executable file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

264
extensions/yyjson/YYJSONManager.h Executable file
View File

@ -0,0 +1,264 @@
#ifndef _INCLUDE_SM_YYJSON_YYJSONMANAGER_H_
#define _INCLUDE_SM_YYJSON_YYJSONMANAGER_H_
#include <IYYJSONManager.h>
#include <yyjson.h>
#include <IHandleSys.h>
#include <random>
#include <memory>
/**
* @brief JSON value wrapper
*
* Wraps yyjson mutable/immutable documents and values.
* Used as the primary data type for JSON operations.
*/
class YYJSONValue {
public:
YYJSONValue() = default;
~YYJSONValue() {
if (m_pDocument_mut.unique()) {
yyjson_mut_doc_free(m_pDocument_mut.get());
}
if (m_pDocument.unique()) {
yyjson_doc_free(m_pDocument.get());
}
}
YYJSONValue(const YYJSONValue&) = delete;
YYJSONValue& operator=(const YYJSONValue&) = delete;
void ResetObjectIterator() {
m_iterInitialized = false;
}
void ResetArrayIterator() {
m_iterInitialized = false;
m_arrayIndex = 0;
}
bool IsMutable() const {
return m_pDocument_mut != nullptr;
}
bool IsImmutable() const {
return m_pDocument != nullptr;
}
// Mutable document
std::shared_ptr<yyjson_mut_doc> m_pDocument_mut;
yyjson_mut_val* m_pVal_mut{ nullptr };
// Immutable document
std::shared_ptr<yyjson_doc> m_pDocument;
yyjson_val* m_pVal{ nullptr };
// Mutable document iterators
yyjson_mut_obj_iter m_iterObj;
yyjson_mut_arr_iter m_iterArr;
// Immutable document iterators
yyjson_obj_iter m_iterObjImm;
yyjson_arr_iter m_iterArrImm;
SourceMod::Handle_t m_handle{ BAD_HANDLE };
size_t m_arrayIndex{ 0 };
size_t m_readSize{ 0 };
bool m_iterInitialized{ false };
};
class YYJSONManager : public IYYJSONManager
{
public:
YYJSONManager();
~YYJSONManager();
public:
// ========== Document Operations ==========
virtual YYJSONValue* ParseJSON(const char* json_str, bool is_file, bool is_mutable,
yyjson_read_flag read_flg, char* error, size_t error_size) override;
virtual bool WriteToString(YYJSONValue* handle, char* buffer, size_t buffer_size,
yyjson_write_flag write_flg, size_t* out_size) override;
virtual bool WriteToFile(YYJSONValue* handle, const char* path, yyjson_write_flag write_flg,
char* error, size_t error_size) override;
virtual bool Equals(YYJSONValue* handle1, YYJSONValue* handle2) override;
virtual YYJSONValue* DeepCopy(YYJSONValue* targetDoc, YYJSONValue* sourceValue) override;
virtual const char* GetTypeDesc(YYJSONValue* handle) override;
virtual size_t GetSerializedSize(YYJSONValue* handle, yyjson_write_flag write_flg) override;
virtual YYJSONValue* ToMutable(YYJSONValue* handle) override;
virtual YYJSONValue* ToImmutable(YYJSONValue* handle) override;
virtual yyjson_type GetType(YYJSONValue* handle) override;
virtual yyjson_subtype GetSubtype(YYJSONValue* handle) override;
virtual bool IsArray(YYJSONValue* handle) override;
virtual bool IsObject(YYJSONValue* handle) override;
virtual bool IsInt(YYJSONValue* handle) override;
virtual bool IsUint(YYJSONValue* handle) override;
virtual bool IsSint(YYJSONValue* handle) override;
virtual bool IsNum(YYJSONValue* handle) override;
virtual bool IsBool(YYJSONValue* handle) override;
virtual bool IsTrue(YYJSONValue* handle) override;
virtual bool IsFalse(YYJSONValue* handle) override;
virtual bool IsFloat(YYJSONValue* handle) override;
virtual bool IsStr(YYJSONValue* handle) override;
virtual bool IsNull(YYJSONValue* handle) override;
virtual bool IsCtn(YYJSONValue* handle) override;
virtual bool IsMutable(YYJSONValue* handle) override;
virtual bool IsImmutable(YYJSONValue* handle) override;
virtual size_t GetReadSize(YYJSONValue* handle) override;
// ========== Object Operations ==========
virtual YYJSONValue* ObjectInit() override;
virtual YYJSONValue* ObjectInitWithStrings(const char** pairs, size_t count) override;
virtual YYJSONValue* ObjectParseString(const char* str, yyjson_read_flag read_flg,
char* error, size_t error_size) override;
virtual YYJSONValue* ObjectParseFile(const char* path, yyjson_read_flag read_flg,
char* error, size_t error_size) override;
virtual size_t ObjectGetSize(YYJSONValue* handle) override;
virtual bool ObjectGetKey(YYJSONValue* handle, size_t index, const char** out_key) override;
virtual YYJSONValue* ObjectGetValueAt(YYJSONValue* handle, size_t index) override;
virtual YYJSONValue* ObjectGet(YYJSONValue* handle, const char* key) override;
virtual bool ObjectGetBool(YYJSONValue* handle, const char* key, bool* out_value) override;
virtual bool ObjectGetFloat(YYJSONValue* handle, const char* key, double* out_value) override;
virtual bool ObjectGetInt(YYJSONValue* handle, const char* key, int* out_value) override;
virtual bool ObjectGetInt64(YYJSONValue* handle, const char* key, int64_t* out_value) override;
virtual bool ObjectGetString(YYJSONValue* handle, const char* key, const char** out_str, size_t* out_len) override;
virtual bool ObjectIsNull(YYJSONValue* handle, const char* key, bool* out_is_null) override;
virtual bool ObjectHasKey(YYJSONValue* handle, const char* key, bool use_pointer) override;
virtual bool ObjectRenameKey(YYJSONValue* handle, const char* old_key, const char* new_key, bool allow_duplicate) override;
virtual bool ObjectSet(YYJSONValue* handle, const char* key, YYJSONValue* value) override;
virtual bool ObjectSetBool(YYJSONValue* handle, const char* key, bool value) override;
virtual bool ObjectSetFloat(YYJSONValue* handle, const char* key, double value) override;
virtual bool ObjectSetInt(YYJSONValue* handle, const char* key, int value) override;
virtual bool ObjectSetInt64(YYJSONValue* handle, const char* key, int64_t value) override;
virtual bool ObjectSetNull(YYJSONValue* handle, const char* key) override;
virtual bool ObjectSetString(YYJSONValue* handle, const char* key, const char* value) override;
virtual bool ObjectRemove(YYJSONValue* handle, const char* key) override;
virtual bool ObjectClear(YYJSONValue* handle) override;
virtual bool ObjectSort(YYJSONValue* handle, YYJSON_SORT_ORDER sort_mode) override;
// ========== Array Operations ==========
virtual YYJSONValue* ArrayInit() override;
virtual YYJSONValue* ArrayInitWithStrings(const char** strings, size_t count) override;
virtual YYJSONValue* ArrayParseString(const char* str, yyjson_read_flag read_flg,
char* error, size_t error_size) override;
virtual YYJSONValue* ArrayParseFile(const char* path, yyjson_read_flag read_flg,
char* error, size_t error_size) override;
virtual size_t ArrayGetSize(YYJSONValue* handle) override;
virtual YYJSONValue* ArrayGet(YYJSONValue* handle, size_t index) override;
virtual YYJSONValue* ArrayGetFirst(YYJSONValue* handle) override;
virtual YYJSONValue* ArrayGetLast(YYJSONValue* handle) override;
virtual bool ArrayGetBool(YYJSONValue* handle, size_t index, bool* out_value) override;
virtual bool ArrayGetFloat(YYJSONValue* handle, size_t index, double* out_value) override;
virtual bool ArrayGetInt(YYJSONValue* handle, size_t index, int* out_value) override;
virtual bool ArrayGetInt64(YYJSONValue* handle, size_t index, int64_t* out_value) override;
virtual bool ArrayGetString(YYJSONValue* handle, size_t index, const char** out_str, size_t* out_len) override;
virtual bool ArrayIsNull(YYJSONValue* handle, size_t index) override;
virtual bool ArrayReplace(YYJSONValue* handle, size_t index, YYJSONValue* value) override;
virtual bool ArrayReplaceBool(YYJSONValue* handle, size_t index, bool value) override;
virtual bool ArrayReplaceFloat(YYJSONValue* handle, size_t index, double value) override;
virtual bool ArrayReplaceInt(YYJSONValue* handle, size_t index, int value) override;
virtual bool ArrayReplaceInt64(YYJSONValue* handle, size_t index, int64_t value) override;
virtual bool ArrayReplaceNull(YYJSONValue* handle, size_t index) override;
virtual bool ArrayReplaceString(YYJSONValue* handle, size_t index, const char* value) override;
virtual bool ArrayAppend(YYJSONValue* handle, YYJSONValue* value) override;
virtual bool ArrayAppendBool(YYJSONValue* handle, bool value) override;
virtual bool ArrayAppendFloat(YYJSONValue* handle, double value) override;
virtual bool ArrayAppendInt(YYJSONValue* handle, int value) override;
virtual bool ArrayAppendInt64(YYJSONValue* handle, int64_t value) override;
virtual bool ArrayAppendNull(YYJSONValue* handle) override;
virtual bool ArrayAppendString(YYJSONValue* handle, const char* value) override;
virtual bool ArrayRemove(YYJSONValue* handle, size_t index) override;
virtual bool ArrayRemoveFirst(YYJSONValue* handle) override;
virtual bool ArrayRemoveLast(YYJSONValue* handle) override;
virtual bool ArrayRemoveRange(YYJSONValue* handle, size_t start_index, size_t end_index) override;
virtual bool ArrayClear(YYJSONValue* handle) override;
virtual int ArrayIndexOfBool(YYJSONValue* handle, bool search_value) override;
virtual int ArrayIndexOfString(YYJSONValue* handle, const char* search_value) override;
virtual int ArrayIndexOfInt(YYJSONValue* handle, int search_value) override;
virtual int ArrayIndexOfInt64(YYJSONValue* handle, int64_t search_value) override;
virtual int ArrayIndexOfFloat(YYJSONValue* handle, double search_value) override;
virtual bool ArraySort(YYJSONValue* handle, YYJSON_SORT_ORDER sort_mode) override;
// ========== Value Operations ==========
virtual YYJSONValue* Pack(const char* format, IPackParamProvider* param_provider, char* error, size_t error_size) override;
virtual YYJSONValue* CreateBool(bool value) override;
virtual YYJSONValue* CreateFloat(double value) override;
virtual YYJSONValue* CreateInt(int value) override;
virtual YYJSONValue* CreateInt64(int64_t value) override;
virtual YYJSONValue* CreateNull() override;
virtual YYJSONValue* CreateString(const char* value) override;
virtual bool GetBool(YYJSONValue* handle, bool* out_value) override;
virtual bool GetFloat(YYJSONValue* handle, double* out_value) override;
virtual bool GetInt(YYJSONValue* handle, int* out_value) override;
virtual bool GetInt64(YYJSONValue* handle, int64_t* out_value) override;
virtual bool GetString(YYJSONValue* handle, const char** out_str, size_t* out_len) override;
// ========== Pointer Operations ==========
virtual YYJSONValue* PtrGet(YYJSONValue* handle, const char* path, char* error, size_t error_size) override;
virtual bool PtrGetBool(YYJSONValue* handle, const char* path, bool* out_value, char* error, size_t error_size) override;
virtual bool PtrGetFloat(YYJSONValue* handle, const char* path, double* out_value, char* error, size_t error_size) override;
virtual bool PtrGetInt(YYJSONValue* handle, const char* path, int* out_value, char* error, size_t error_size) override;
virtual bool PtrGetInt64(YYJSONValue* handle, const char* path, int64_t* out_value, char* error, size_t error_size) override;
virtual bool PtrGetString(YYJSONValue* handle, const char* path, const char** out_str, size_t* out_len, char* error, size_t error_size) override;
virtual bool PtrGetIsNull(YYJSONValue* handle, const char* path, bool* out_is_null, char* error, size_t error_size) override;
virtual bool PtrGetLength(YYJSONValue* handle, const char* path, size_t* out_len, char* error, size_t error_size) override;
virtual bool PtrSet(YYJSONValue* handle, const char* path, YYJSONValue* value, char* error, size_t error_size) override;
virtual bool PtrSetBool(YYJSONValue* handle, const char* path, bool value, char* error, size_t error_size) override;
virtual bool PtrSetFloat(YYJSONValue* handle, const char* path, double value, char* error, size_t error_size) override;
virtual bool PtrSetInt(YYJSONValue* handle, const char* path, int value, char* error, size_t error_size) override;
virtual bool PtrSetInt64(YYJSONValue* handle, const char* path, int64_t value, char* error, size_t error_size) override;
virtual bool PtrSetString(YYJSONValue* handle, const char* path, const char* value, char* error, size_t error_size) override;
virtual bool PtrSetNull(YYJSONValue* handle, const char* path, char* error, size_t error_size) override;
virtual bool PtrAdd(YYJSONValue* handle, const char* path, YYJSONValue* value, char* error, size_t error_size) override;
virtual bool PtrAddBool(YYJSONValue* handle, const char* path, bool value, char* error, size_t error_size) override;
virtual bool PtrAddFloat(YYJSONValue* handle, const char* path, double value, char* error, size_t error_size) override;
virtual bool PtrAddInt(YYJSONValue* handle, const char* path, int value, char* error, size_t error_size) override;
virtual bool PtrAddInt64(YYJSONValue* handle, const char* path, int64_t value, char* error, size_t error_size) override;
virtual bool PtrAddString(YYJSONValue* handle, const char* path, const char* value, char* error, size_t error_size) override;
virtual bool PtrAddNull(YYJSONValue* handle, const char* path, char* error, size_t error_size) override;
virtual bool PtrRemove(YYJSONValue* handle, const char* path, char* error, size_t error_size) override;
virtual YYJSONValue* PtrTryGet(YYJSONValue* handle, const char* path) override;
virtual bool PtrTryGetBool(YYJSONValue* handle, const char* path, bool* out_value) override;
virtual bool PtrTryGetFloat(YYJSONValue* handle, const char* path, double* out_value) override;
virtual bool PtrTryGetInt(YYJSONValue* handle, const char* path, int* out_value) override;
virtual bool PtrTryGetInt64(YYJSONValue* handle, const char* path, int64_t* out_value) override;
virtual bool PtrTryGetString(YYJSONValue* handle, const char* path, const char** out_str, size_t* out_len) override;
// ========== Iterator Operations ==========
virtual bool ObjectForeachNext(YYJSONValue* handle, const char** out_key,
size_t* out_key_len, YYJSONValue** out_value) override;
virtual bool ArrayForeachNext(YYJSONValue* handle, size_t* out_index,
YYJSONValue** out_value) override;
virtual bool ObjectForeachKeyNext(YYJSONValue* handle, const char** out_key,
size_t* out_key_len) override;
virtual bool ArrayForeachIndexNext(YYJSONValue* handle, size_t* out_index) override;
// ========== Release Operations ==========
virtual void Release(YYJSONValue* value) override;
// ========== Handle Type Operations ==========
virtual HandleType_t GetHandleType() override;
// ========== Handle Operations ==========
virtual YYJSONValue* GetFromHandle(IPluginContext* pContext, Handle_t handle) override;
private:
std::random_device m_randomDevice;
std::mt19937 m_randomGenerator;
// Helper methods
static std::unique_ptr<YYJSONValue> CreateWrapper();
static std::shared_ptr<yyjson_mut_doc> WrapDocument(yyjson_mut_doc* doc);
static std::shared_ptr<yyjson_mut_doc> CopyDocument(yyjson_doc* doc);
static std::shared_ptr<yyjson_mut_doc> CreateDocument();
static std::shared_ptr<yyjson_doc> WrapImmutableDocument(yyjson_doc* doc);
// Pack helper methods
static const char* SkipSeparators(const char* ptr);
static void SetPackError(char* error, size_t error_size, const char* fmt, ...);
static yyjson_mut_val* PackImpl(yyjson_mut_doc* doc, const char* format,
IPackParamProvider* provider, char* error,
size_t error_size, const char** out_end_ptr);
};
#endif // _INCLUDE_SM_YYJSON_YYJSONMANAGER_H_

62
extensions/yyjson/extension.cpp Executable file
View File

@ -0,0 +1,62 @@
#include "extension.h"
#include "YYJSONManager.h"
JsonExtension g_JsonExtension;
SMEXT_LINK(&g_JsonExtension);
HandleType_t g_htJSON;
JSONHandler g_JSONHandler;
IYYJSONManager* g_pYYJSONManager;
bool JsonExtension::SDK_OnLoad(char* error, size_t maxlen, bool late)
{
sharesys->AddNatives(myself, json_natives);
sharesys->RegisterLibrary(myself, "yyjson");
HandleAccess haJSON;
handlesys->InitAccessDefaults(nullptr, &haJSON);
haJSON.access[HandleAccess_Read] = 0;
haJSON.access[HandleAccess_Delete] = 0;
HandleError err;
g_htJSON = handlesys->CreateType("YYJSON", &g_JSONHandler, 0, nullptr, &haJSON, myself->GetIdentity(), &err);
if (!g_htJSON) {
snprintf(error, maxlen, "Failed to create YYJSON handle type (err: %d)", err);
return false;
}
// Delete the existing instance if it exists
if (g_pYYJSONManager) {
delete g_pYYJSONManager;
g_pYYJSONManager = nullptr;
}
g_pYYJSONManager = new YYJSONManager();
if (!g_pYYJSONManager) {
snprintf(error, maxlen, "Failed to create YYJSONManager instance");
return false;
}
return sharesys->AddInterface(myself, g_pYYJSONManager);
}
void JsonExtension::SDK_OnUnload()
{
handlesys->RemoveType(g_htJSON, myself->GetIdentity());
if (g_pYYJSONManager) {
delete g_pYYJSONManager;
g_pYYJSONManager = nullptr;
}
}
void JSONHandler::OnHandleDestroy(HandleType_t type, void* object)
{
delete (YYJSONValue*)object;
}
IYYJSONManager* JsonExtension::GetYYJSONManager()
{
return g_pYYJSONManager;
}

29
extensions/yyjson/extension.h Executable file
View File

@ -0,0 +1,29 @@
#ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
#define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
#include "smsdk_ext.h"
#include <yyjson.h>
#include <random>
#include "IYYJSONManager.h"
class JsonExtension : public SDKExtension
{
public:
virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late);
virtual void SDK_OnUnload();
IYYJSONManager* GetYYJSONManager();
};
class JSONHandler : public IHandleTypeDispatch
{
public:
void OnHandleDestroy(HandleType_t type, void *object);
};
extern JsonExtension g_JsonExtension;
extern HandleType_t g_htJSON;
extern JSONHandler g_JSONHandler;
extern const sp_nativeinfo_t json_natives[];
extern IYYJSONManager* g_pYYJSONManager;
#endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_

2479
extensions/yyjson/json_natives.cpp Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,17 @@
#ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_
#define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_
#define SMEXT_CONF_NAME "SourceMod YYJSON Extension"
#define SMEXT_CONF_DESCRIPTION "Provide JSON Native"
#define SMEXT_CONF_VERSION "1.1.4a"
#define SMEXT_CONF_AUTHOR "ProjectSky"
#define SMEXT_CONF_URL "https://github.com/ProjectSky/sm-ext-yyjson"
#define SMEXT_CONF_LOGTAG "yyjson"
#define SMEXT_CONF_LICENSE "GPL"
#define SMEXT_CONF_DATESTRING __DATE__
#define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name;
#define SMEXT_ENABLE_HANDLESYS
#endif // _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_

104
extensions/yyjson/version.rc Executable file
View File

@ -0,0 +1,104 @@
// Microsoft Visual C++ generated resource script.
//
//#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
#include <sourcemod_version.h>
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION SM_VERSION_FILE
PRODUCTVERSION SM_VERSION_FILE
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "000004b0"
BEGIN
VALUE "Comments", "YYJSON Extension"
VALUE "FileDescription", "SourceMod YYJSON Extension"
VALUE "FileVersion", SM_VERSION_FILE
VALUE "InternalName", "SourceMod YYJSON Extension"
VALUE "LegalCopyright", "Copyright (c) 2004-2009, AlliedModders LLC"
VALUE "OriginalFilename", BINARY_NAME
VALUE "ProductName", "SourceMod YYJSON Extension"
VALUE "ProductVersion", SM_VERSION_STRING
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x0, 1200
END
END
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 YaoYuan <ibireme@gmail.com>
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.

11195
extensions/yyjson/yyjson/yyjson.c Executable file

File diff suppressed because it is too large Load Diff

8346
extensions/yyjson/yyjson/yyjson.h Executable file

File diff suppressed because it is too large Load Diff

1626
plugins/include/yyjson.inc Executable file

File diff suppressed because it is too large Load Diff

566
plugins/testsuite/yyjson_test.sp Executable file
View File

@ -0,0 +1,566 @@
#include <sourcemod>
#include <yyjson>
public Plugin myinfo =
{
name = "YYJSON Test Suite",
author = "ProjectSky",
description = "Test suite for YYJSON extension",
version = "1.0.2",
url = "https://github.com/ProjectSky/sm-ext-yyjson"
};
public void OnPluginStart()
{
RegServerCmd("sm_yyjson_test", Command_RunTests, "Run YYJSON test suite");
}
Action Command_RunTests(int args)
{
// Run all test cases
TestBasicOperations();
TestArrayOperations();
TestObjectOperations();
TestSortOperations();
TestSearchOperations();
TestPointerOperations();
TestIterationOperations();
TestTypeOperations();
TestFileOperations();
TestImmutabilityOperations();
TestPackOperations();
TestFromStringsOperations();
PrintToServer("[YYJSON] All tests completed!");
return Plugin_Handled;
}
void TestBasicOperations()
{
PrintToServer("[YYJSON] Testing basic operations...");
// Test creation and parsing
YYJSONObject obj = new YYJSONObject();
obj.SetInt("int", 42);
obj.SetFloat("float", 3.14);
obj.SetBool("bool", true);
obj.SetString("string", "hello");
obj.SetNull("null");
// Test serialization
char buffer[1024];
obj.ToString(buffer, sizeof(buffer));
PrintToServer("Serialized: %s", buffer);
// Test type checking
PrintToServer("Type of 'int': %d", obj.Type);
PrintToServer("SubType of 'int': %d", obj.SubType);
PrintToServer("Is object: %d", obj.IsObject);
// Test value existence
PrintToServer("Has 'int': %d", obj.HasKey("int"));
PrintToServer("Has 'nonexistent': %d", obj.HasKey("nonexistent"));
// Test value retrieval
PrintToServer("Int value: %d", obj.GetInt("int"));
PrintToServer("Float value: %f", obj.GetFloat("float"));
PrintToServer("Bool value: %d", obj.GetBool("bool"));
char strBuffer[64];
obj.GetString("string", strBuffer, sizeof(strBuffer));
PrintToServer("String value: %s", strBuffer);
PrintToServer("Is 'null' null: %d", obj.IsNull("null"));
// Test parsing
YYJSONObject parsed = YYJSON.Parse(buffer);
// Test equality
PrintToServer("Objects are equal: %d", YYJSON.Equals(obj, parsed));
// Test deep copy
YYJSONObject copy = new YYJSONObject();
YYJSONObject copyResult = YYJSON.DeepCopy(copy, obj);
PrintToServer("Copy equals original: %d", YYJSON.Equals(copyResult, obj));
// Test size and read size
PrintToServer("Object size: %d", obj.Size);
PrintToServer("Read size: %d", obj.ReadSize);
// Test type description
char typeDesc[64];
YYJSON.GetTypeDesc(obj, typeDesc, sizeof(typeDesc));
PrintToServer("Type description: %s", typeDesc);
delete obj;
delete parsed;
delete copy;
delete copyResult;
}
void TestArrayOperations()
{
PrintToServer("[YYJSON] Testing array operations...");
YYJSONArray arr = new YYJSONArray();
// Test push operations
arr.PushInt(1);
arr.PushFloat(2.5);
arr.PushBool(true);
arr.PushString("test");
arr.PushNull();
PrintToServer("Array after push operations:");
PrintJson(arr);
// Test get operations
PrintToServer("First element: %d", arr.GetInt(0));
PrintToServer("Second element: %f", arr.GetFloat(1));
PrintToServer("Third element: %d", arr.GetBool(2));
char strBuffer[64];
arr.GetString(3, strBuffer, sizeof(strBuffer));
PrintToServer("Fourth element: %s", strBuffer);
PrintToServer("Fifth element is null: %d", arr.IsNull(4));
YYJSON first = arr.First;
YYJSON last = arr.Last;
// Test array properties
PrintToServer("Array length: %d", arr.Length);
PrintToServer("First value: %x", first);
PrintToServer("Last value: %x", last);
// Test set operations
arr.SetInt(0, 100);
arr.SetFloat(1, 3.14);
arr.SetBool(2, false);
arr.SetString(3, "modified");
arr.SetNull(4);
PrintToServer("Array after set operations:");
PrintJson(arr);
// Test remove operations
arr.RemoveFirst();
PrintToServer("After RemoveFirst:");
PrintJson(arr);
arr.RemoveLast();
PrintToServer("After RemoveLast:");
PrintJson(arr);
arr.Remove(1);
PrintToServer("After Remove(1):");
PrintJson(arr);
arr.RemoveRange(0, 1);
PrintToServer("After RemoveRange(0, 1):");
PrintJson(arr);
arr.Clear();
PrintToServer("Array length after Clear: %d", arr.Length);
delete arr;
delete first;
delete last;
}
void TestObjectOperations()
{
PrintToServer("[YYJSON] Testing object operations...");
YYJSONObject obj = new YYJSONObject();
// Test set operations
obj.SetInt("int", 123);
obj.SetFloat("float", 3.14);
obj.SetBool("bool", true);
obj.SetString("string", "test");
obj.SetNull("null");
PrintToServer("Object after set operations:");
PrintJson(obj);
// Test get operations
PrintToServer("Int value: %d", obj.GetInt("int"));
PrintToServer("Float value: %f", obj.GetFloat("float"));
PrintToServer("Bool value: %d", obj.GetBool("bool"));
char strBuffer[64];
obj.GetString("string", strBuffer, sizeof(strBuffer));
PrintToServer("String value: %s", strBuffer);
PrintToServer("Is null value null: %d", obj.IsNull("null"));
// Test key operations
char key[64];
for (int i = 0; i < obj.Size; i++)
{
obj.GetKey(i, key, sizeof(key));
PrintToServer("Key at %d: %s", i, key);
YYJSON value = obj.GetValueAt(i);
PrintToServer("Value type at %d: %d", i, value.Type);
delete value;
}
// Test rename key
obj.RenameKey("int", "number");
PrintToServer("After renaming 'int' to 'number':");
PrintJson(obj);
// Test remove operations
obj.Remove("number");
PrintToServer("After removing 'number':");
PrintJson(obj);
obj.Clear();
PrintToServer("Object size after Clear: %d", obj.Size);
delete obj;
}
void TestSortOperations()
{
PrintToServer("[YYJSON] Testing sort operations...");
// Test array sorting
YYJSONArray arr = YYJSON.Parse("[3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]", .is_mutable_doc = true);
PrintToServer("Original array:");
PrintJson(arr);
arr.Sort();
PrintToServer("After ascending sort:");
PrintJson(arr);
arr.Sort(YYJSON_SORT_DESC);
PrintToServer("After descending sort:");
PrintJson(arr);
arr.Sort(YYJSON_SORT_RANDOM);
PrintToServer("After random sort:");
PrintJson(arr);
// Test mixed type array sorting
YYJSONArray mixed = YYJSON.Parse("[true, 42, \"hello\", 1.23, false, \"world\"]", .is_mutable_doc = true);
PrintToServer("Original mixed array:");
PrintJson(mixed);
mixed.Sort();
PrintToServer("After sorting mixed array:");
PrintJson(mixed);
// Test object sorting
YYJSONObject obj = YYJSON.Parse("{\"zebra\": 1, \"alpha\": 2, \"beta\": 3}", .is_mutable_doc = true);
PrintToServer("Original object:");
PrintJson(obj);
obj.Sort();
PrintToServer("After ascending sort:");
PrintJson(obj);
obj.Sort(YYJSON_SORT_DESC);
PrintToServer("After descending sort:");
PrintJson(obj);
obj.Sort(YYJSON_SORT_RANDOM);
PrintToServer("After random sort:");
PrintJson(obj);
delete arr;
delete mixed;
delete obj;
}
void TestSearchOperations()
{
PrintToServer("[YYJSON] Testing search operations...");
YYJSONArray arr = YYJSON.Parse("[42, true, \"hello\", 3.14, \"world\", false, 42]");
PrintToServer("Test array:");
PrintJson(arr);
// Test all search methods
PrintToServer("Search results:");
PrintToServer("IndexOfInt(42): %d", arr.IndexOfInt(42));
PrintToServer("IndexOfInt(999): %d", arr.IndexOfInt(999));
PrintToServer("IndexOfBool(true): %d", arr.IndexOfBool(true));
PrintToServer("IndexOfBool(false): %d", arr.IndexOfBool(false));
PrintToServer("IndexOfString(\"hello\"): %d", arr.IndexOfString("hello"));
PrintToServer("IndexOfString(\"missing\"): %d", arr.IndexOfString("missing"));
PrintToServer("IndexOfFloat(3.14): %d", arr.IndexOfFloat(3.14));
PrintToServer("IndexOfFloat(2.718): %d", arr.IndexOfFloat(2.718));
delete arr;
}
void TestPointerOperations()
{
PrintToServer("[YYJSON] Testing JSON pointer operations...");
YYJSONObject obj = new YYJSONObject();
// Test setting nested values
obj.PtrSetInt("/a/b/c", 1);
obj.PtrSetString("/a/b/name", "test");
obj.PtrSetBool("/a/flag", true);
obj.PtrSetFloat("/a/b/pi", 3.14);
obj.PtrSetNull("/a/b/empty");
PrintToServer("After setting values:");
PrintJson(obj);
// Test getting values
PrintToServer("Pointer get operations:");
PrintToServer("/a/b/c: %d", obj.PtrGetInt("/a/b/c"));
char strBuffer[64];
obj.PtrGetString("/a/b/name", strBuffer, sizeof(strBuffer));
PrintToServer("/a/b/name: %s", strBuffer);
PrintToServer("/a/flag: %d", obj.PtrGetBool("/a/flag"));
PrintToServer("/a/b/pi: %f", obj.PtrGetFloat("/a/b/pi"));
PrintToServer("/a/b/empty is null: %d", obj.PtrGetIsNull("/a/b/empty"));
// Test adding values
obj.PtrAddInt("/a/b/numbers/0", 1);
obj.PtrAddInt("/a/b/numbers/1", 2);
obj.PtrAddString("/a/b/strings", "append");
PrintToServer("After adding values:");
PrintJson(obj);
// Test length
PrintToServer("Length of /a/b/numbers: %d", obj.PtrGetLength("/a/b/numbers"));
// Test removing values
obj.PtrRemove("/a/b/c");
PrintToServer("After removing /a/b/c:");
PrintJson(obj);
delete obj;
}
void TestIterationOperations()
{
PrintToServer("[YYJSON] Testing iteration operations...");
// Test object iteration
YYJSONObject obj = YYJSON.Parse("{\"a\": 1, \"b\": 2, \"c\": 3}");
char key[64];
YYJSON value;
while (obj.ForeachObject(key, sizeof(key), value))
{
PrintToServer("Key: %s", key);
delete value;
}
// Test array iteration
YYJSONArray arr = YYJSON.Parse("[1, 2, 3, 4, 5]");
int index;
while (arr.ForeachArray(index, value))
{
PrintToServer("Index: %d", index);
delete value;
}
delete obj;
delete arr;
}
void TestTypeOperations()
{
PrintToServer("[YYJSON] Testing type operations...");
// Test value creation
YYJSON boolVal = YYJSON.CreateBool(true);
YYJSON intVal = YYJSON.CreateInt(42);
YYJSON floatVal = YYJSON.CreateFloat(3.14);
YYJSON strVal = YYJSON.CreateString("test");
YYJSON nullVal = YYJSON.CreateNull();
// Test value types
PrintToServer("Value types:");
PrintToServer("Bool type: %d", boolVal.Type);
PrintToServer("Int type: %d", intVal.Type);
PrintToServer("Float type: %d", floatVal.Type);
PrintToServer("String type: %d", strVal.Type);
PrintToServer("Null type: %d", nullVal.Type);
// Test value retrieval
PrintToServer("Value contents:");
PrintToServer("Bool value: %d", YYJSON.GetBool(boolVal));
PrintToServer("Int value: %d", YYJSON.GetInt(intVal));
PrintToServer("Float value: %f", YYJSON.GetFloat(floatVal));
char strBuffer[64];
YYJSON.GetString(strVal, strBuffer, sizeof(strBuffer));
PrintToServer("String value: %s", strBuffer);
delete boolVal;
delete intVal;
delete floatVal;
delete strVal;
delete nullVal;
}
void TestFileOperations()
{
PrintToServer("[YYJSON] Testing file operations...");
// Create test data
YYJSONObject obj = new YYJSONObject();
obj.SetInt("id", 1);
obj.SetString("name", "test");
obj.SetBool("active", true);
// Test file writing
PrintToServer("Writing to file...");
obj.ToFile("test.json", YYJSON_WRITE_PRETTY_TWO_SPACES);
// Test file reading
PrintToServer("Reading from file...");
YYJSONObject loaded = YYJSON.Parse("test.json", true);
PrintToServer("File content:");
PrintJson(loaded);
delete loaded;
delete obj;
}
void TestImmutabilityOperations()
{
PrintToServer("[YYJSON] Testing immutability operations...");
// Test immutable document creation
YYJSONObject immutable = YYJSON.Parse("{\"key\": 123, \"str\": \"test\"}");
PrintToServer("Created immutable document:");
PrintJson(immutable);
// Test property checks
PrintToServer("Is mutable: %d", immutable.IsMutable);
PrintToServer("Is immutable: %d", immutable.IsImmutable);
// Test read operations (should succeed)
PrintToServer("Read operations on immutable document:");
PrintToServer("Int value: %d", immutable.GetInt("key"));
char buffer[64];
immutable.GetString("str", buffer, sizeof(buffer));
PrintToServer("String value: %s", buffer);
// Test conversion to mutable
YYJSONObject mutable = immutable.ToMutable();
PrintToServer("\nConverted to mutable document:");
PrintToServer("Is mutable: %d", mutable.IsMutable);
PrintToServer("Is immutable: %d", mutable.IsImmutable);
// Now modifications should work
mutable.SetInt("key", 456)
PrintToServer("Successfully modified mutable document:");
PrintJson(mutable);
// Test conversion back to immutable
YYJSONObject backToImmutable = mutable.ToImmutable();
PrintToServer("\nConverted back to immutable:");
PrintToServer("Is mutable: %d", backToImmutable.IsMutable);
PrintToServer("Is immutable: %d", backToImmutable.IsImmutable);
delete backToImmutable;
delete mutable;
delete immutable;
// Test file operations with immutability
PrintToServer("\nTesting file operations with immutability...");
// Create and write a mutable document
YYJSONObject writeObj = new YYJSONObject();
writeObj.SetInt("test", 123);
writeObj.ToFile("test_immutable.json");
delete writeObj;
// Read as immutable
YYJSONObject readImmutable = YYJSON.Parse("test_immutable.json", true);
PrintToServer("Read as immutable document:");
PrintJson(readImmutable);
PrintToServer("Is mutable: %d", readImmutable.IsMutable);
PrintToServer("Is immutable: %d", readImmutable.IsImmutable);
delete readImmutable;
}
void TestPackOperations()
{
PrintToServer("[YYJSON] Testing pack operations...");
// Test basic pack operation with different types
YYJSON packed = YYJSON.Pack("{s:s,s:i,s:f,s:b,s:n}",
"name", "test",
"age", 25,
"height", 1.75,
"active", true,
"extra"
);
PrintToServer("Packed JSON:");
PrintJson(packed);
// Test nested object packing
YYJSON nested = YYJSON.Pack("{s:{s:s,s:[i,i,i]}}",
"user",
"name", "test",
"scores", 85, 90, 95
);
PrintToServer("Nested packed JSON:");
PrintJson(nested);
// Test array packing with mixed types
YYJSON array = YYJSON.Pack("[s,i,f,b,n]",
"test", 42, 3.14, true
);
PrintToServer("Array packed JSON:");
PrintJson(array);
delete packed;
delete nested;
delete array;
}
void TestFromStringsOperations()
{
PrintToServer("[YYJSON] Testing FromStrings operations...");
// Test object creation from key-value string arrays
char pairs[][] = {"name", "test", "type", "demo", "version", "1.0.0"};
YYJSONObject obj = YYJSONObject.FromStrings(pairs, sizeof(pairs));
PrintToServer("Object from strings:");
PrintJson(obj);
// Test array creation from string array
char items[][] = {"apple", "banana", "orange", "grape"};
YYJSONArray arr = YYJSONArray.FromStrings(items, sizeof(items));
PrintToServer("Array from strings:");
PrintJson(arr);
delete obj;
delete arr;
}
// Helper function to print json contents
void PrintJson(YYJSON data)
{
int len = data.GetSerializedSize(YYJSON_WRITE_PRETTY_TWO_SPACES);
char[] buffer = new char[len];
data.ToString(buffer, len, YYJSON_WRITE_PRETTY_TWO_SPACES);
PrintToServer("%s", buffer);
}