RyanCW hai 4 semanas
pai
achega
664ddfdad6
Modificáronse 39 ficheiros con 4501 adicións e 2294 borrados
  1. 82 35
      .clang-format
  2. 1 1
      .clang-format-ignore
  3. 1 1
      .clang-tidy
  4. 3 0
      .gitignore
  5. 423 330
      RyanJson/RyanJson.c
  6. 160 124
      RyanJson/RyanJson.h
  7. 105 0
      RyanJson/RyanJsonConfig.h
  8. 162 0
      RyanJson/RyanJsonUtils.c
  9. 35 0
      RyanJson/RyanJsonUtils.h
  10. 6 3
      example/RyanJsonExample.c
  11. 1 1
      externalModule/cJSON/cJSON.c
  12. 1 1
      externalModule/cJSON/cJSON.h
  13. 251 92
      externalModule/yyjson/yyjson.c
  14. 105 3
      externalModule/yyjson/yyjson.h
  15. 39 0
      run_coverage.sh
  16. 1 0
      test/RFC8259JsonData/y_1.json
  17. 1 0
      test/RFC8259JsonData/y_2.json
  18. 1 0
      test/RFC8259JsonData/y_3.json
  19. 1 0
      test/RFC8259JsonData/y_array_nesting.json
  20. 0 312
      test/RFC8259JsonTest.c
  21. 0 1202
      test/RyanJsonBaseTest.c
  22. 164 85
      test/RyanJsonMemoryFootprintTest.c
  23. 613 0
      test/RyanJsonRFC8259JsonTest.c
  24. 113 11
      test/RyanJsonTest.c
  25. 10 8
      test/RyanJsonTest.h
  26. 90 0
      test/baseTest/RyanJsonBaseTest.c
  27. 46 0
      test/baseTest/RyanJsonBaseTest.h
  28. 198 0
      test/baseTest/RyanJsonBaseTestChangeJson.c
  29. 158 0
      test/baseTest/RyanJsonBaseTestCompareJson.c
  30. 86 0
      test/baseTest/RyanJsonBaseTestCreateJson.c
  31. 139 0
      test/baseTest/RyanJsonBaseTestDuplicateJson.c
  32. 45 0
      test/baseTest/RyanJsonBaseTestForEachJson.c
  33. 278 0
      test/baseTest/RyanJsonBaseTestLoadJson.c
  34. 169 0
      test/baseTest/RyanJsonBaseTestUtile.c
  35. 722 0
      test/fuzzer/RyanJsonFuzzer.c
  36. 172 0
      test/fuzzer/RyanJsonFuzzer.dict
  37. 26 35
      test/valloc/valloc.c
  38. 3 0
      test/valloc/valloc.h
  39. 90 50
      xmake.lua

+ 82 - 35
.clang-format

@@ -10,26 +10,46 @@
 #   - https://clang.llvm.org/docs/ClangFormatStyleOptions.html
 
 ---
-# 基于 LLVM 的代码风格
+# 基于 LLVM 的代码风格作为起点,随后覆盖指定字段
 BasedOnStyle: LLVM
-# 连续宏定义的对齐方式:跨注释对齐
+
+# 连续宏定义的对齐方式
+# Enabled: true         -> 启用对齐连续宏定义
+# AcrossComments: true  -> 跨注释也会对齐,适合一组宏中间穿插注释的情况
 AlignConsecutiveMacros:
   Enabled: true
   AcrossComments: true
-# 短代码块不允许单行显示
-AllowShortBlocksOnASingleLine: Never
-# 短 case 标签不允许单行显示
+
+# 是否允许短代码块(如 { ... })出现在单行
+# true  -> 允许短块单行(例如 `{}` 或 `{ a(); }`)
+# 你的原值 true:保持允许(便于简短动作写在一行)
+AllowShortBlocksOnASingleLine: true
+
+# 是否允许短 case 标签单行
+# true  -> 允许 `case X: doSomething();`
 AllowShortCaseLabelsOnASingleLine: true
-# 短枚举不允许单行显示
+
+# 是否允许短枚举在一行
+# true  -> 允许短枚举如 `enum { A, B };`
 AllowShortEnumsOnASingleLine: false
-# 短函数不允许单行显示(None 表示对所有函数都应用此规则)
-AllowShortFunctionsOnASingleLine: None
-# 短 if 语句不允许单行显示
+
+# 是否允许短函数在单行
+# None 表示对所有函数都应用此规则(即不限制单行函数)
+# 通常我们不希望把所有函数压成一行,所以保留 None(更严格)
+AllowShortFunctionsOnASingleLine: true
+
+AllowShortCaseExpressionOnASingleLine: true
+
+# 短 if 语句单行显示策略
+# Always  -> 允许并尽可能保留短 if 语句为单行(包括带 else 的情况)
+# 你希望单行 + 大括号时使用这个选项
 AllowShortIfStatementsOnASingleLine: true
-# 短循环不允许单行显示
+
+# 是否允许短循环(for/while)单行显示
 AllowShortLoopsOnASingleLine: true
 
-# 属性宏列表
+# 属性宏列表,列出在格式化时应视为属性的宏(影响对齐、换行等)
+# 如果代码库使用自定义属性宏,把它们列在这里可以提升格式化准确性
 AttributeMacros:
   - __aligned
   - __deprecated
@@ -39,17 +59,19 @@ AttributeMacros:
   - __syscall_always_inline
   - __subsystem
 
-# 位字段冒号后的空格位置:冒号后
+# 位字段冒号后的空格:After 表示 `int x : 3;` 中冒号后带一个空格(风格选择)
 BitFieldColonSpacing: After
 
+# 大括号换行策略:使用 Custom 配合 BraceWrapping 指定细节
+# 你用了 Custom,这意味着下面的 BraceWrapping 字段决定具体行为
 BreakBeforeBraces: Custom
 BraceWrapping:
-  AfterCaseLabel: false
-  AfterClass: true
-  AfterControlStatement: Always
-  AfterEnum: true
+  AfterCaseLabel: false           # case 标签后不另起行放 {,通常 case: 仍和语句对齐
+  AfterClass: true                # class 后大括号另起行
+  AfterControlStatement: Always   # 控制语句(if/for/while)后通常将 { 放在新行(可被覆盖)
+  AfterEnum: true                 # enum 后另起行
   AfterExternBlock: false
-  AfterFunction: true
+  AfterFunction: true             # 函数体大括号另起行
   AfterNamespace: true
   AfterObjCDeclaration: true
   AfterStruct: true
@@ -58,28 +80,32 @@ BraceWrapping:
   BeforeElse: true
   BeforeLambdaBody: false
   BeforeWhile: false
-  IndentBraces: false
+  IndentBraces: false             # 不单独缩进大括号行
   SplitEmptyFunction: true
   SplitEmptyRecord: true
   SplitEmptyNamespace: true
 
-# 单行代码的最大列数
-ColumnLimit: 200
-# 构造函数初始化列表的缩进宽度
+# 单行代码的最大列数(换行阈值)
+ColumnLimit: 140
+
+# 构造函数初始化列表的缩进宽度(可针对长列表调整可读性)
 ConstructorInitializerIndentWidth: 8
-# 折行缩进宽度
+
+# 折行缩进宽度(续行缩进)
 ContinuationIndentWidth: 8
-# ForEach 宏列表
+
+# ForEach 宏列表:告诉 clang-format 哪些宏应当当作循环处理(便于格式化块体)
 ForEachMacros:
   - "ARRAY_FOR_EACH"
   - "ARRAY_FOR_EACH_PTR"
   - "FOR_EACH"
 
-# If 宏列表
+# If 宏列表:把 CHECKIF 等宏视为 if 语句(影响括号和后续块处理)
 IfMacros:
   - "CHECKIF"
 
-# 包含文件的分类和优先级
+# include 文件的分类和排序优先级
+# Regex: 正则匹配,Priority: 数字越小优先级越高(越先放)
 IncludeCategories:
   - Regex: '^".*\.h"$'
     Priority: 0
@@ -90,25 +116,38 @@ IncludeCategories:
   - Regex: ".*"
     Priority: 3
 
-# case 标签不缩进
+# case 标签是否缩进(true 会将 case 缩进到 switch 中)
+# false -> case 与 switch 对齐(你原先设置 false)
 IndentCaseLabels: false
-# goto 标签不缩进
+
+# goto 标签是否缩进(false 表示标签在行首)
 IndentGotoLabels: false
-# 缩进宽度
+
+# 缩进宽度(通常与制表符策略配合使用)
 IndentWidth: 8
-# 自动插入大括号
+
+# 自动插入大括号(即使单语句也插入 { })
+# 这可以避免单行语句因为后续添加语句而引入 bug
 InsertBraces: true
-# 文件末尾自动插入新行
+
+# 文件末尾自动插入换行
 InsertNewlineAtEOF: true
-# 继承冒号前不加空格
+
+# 继承冒号前是否加空格(False 表示不加空格:"class A: public B")
 SpaceBeforeInheritanceColon: False
-# 控制语句(除了控制宏)前加空格
+
+# 控制语句后是否加空格(这个值控制 if/for/while 等的格式)
+# ControlStatementsExceptControlMacros -> 控制语句(非宏)前加空格:`if (cond)` 而非 `if(cond)`
 SpaceBeforeParens: ControlStatementsExceptControlMacros
-# 从不排序包含文件
+
+# 包含文件是否自动排序(Never 表示不排序)
 SortIncludes: Never
-# 使用制表符进行续行和缩进
+
+# 缩进与续行使用制表符策略
+# ForContinuationAndIndentation -> 续行与缩进使用制表符,其他空格仍按规则
 UseTab: ForContinuationAndIndentation
-# 对空白字符敏感的宏列表
+
+# 对空白敏感的宏列表(多用于预处理器宏展开格式保持)
 WhitespaceSensitiveMacros:
   - COND_CODE_0
   - COND_CODE_1
@@ -118,3 +157,11 @@ WhitespaceSensitiveMacros:
   - STRINGIFY
   - Z_STRINGIFY
   - DT_FOREACH_PROP_ELEM_SEP
+
+# --------------------------
+# 可选:降低 clang-format 拆行惩罚,使其更倾向于保留短 if/else 单行
+# 下面两个值可以帮助把格式化后的多行 if/else 更可能压缩成单行(仅在 AllowShortIfStatementsOnASingleLine: Always 有效时可用)
+# PenaltyBreakIfElse: 0
+# PenaltyBreakStatement: 0
+
+# 注:上面的 Penalty 设置是可选的,如果你发现 clang-format 依旧不把某些 if/else 压成单行,可以取消注释并试验效果。

+ 1 - 1
.clang-format-ignore

@@ -1,2 +1,2 @@
-# 忽略coreMqtt
+# 忽略外部包
 externalModule/*

+ 1 - 1
.clang-tidy

@@ -31,7 +31,7 @@ Checks:
   # 静默的窄化转换交给编译器来判断?
   - 'bugprone-*,-bugprone-easily-swappable-parameters'
   - 'readability-identifier-naming'
-  - 'misc-*,-misc-const-correctness,-misc-unused-parameters,-misc-non-private-member-variables-in-classes,-misc-no-recursion,-misc-use-anonymous-namespace,-misc-include-cleaner'
+  - 'misc-*,-misc-const-correctness,-misc-no-recursion,-misc-include-cleaner'
 
 CheckOptions:
   # 类名使用帕斯卡命名法(如 MyClass)

+ 3 - 0
.gitignore

@@ -15,3 +15,6 @@ build
 .xmake
 .vscode-ctags
 
+default.profdata
+default.profraw
+test/fuzzer/corpus

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 423 - 330
RyanJson/RyanJson.c


+ 160 - 124
RyanJson/RyanJson.h

@@ -6,176 +6,212 @@
 extern "C" {
 #endif
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <stdarg.h>
-#include <limits.h>
-#include <float.h>
-#include <math.h>
-#include <inttypes.h>
-
-#define RyanMqttMemset  memset
-#define RyanMqttMemcpy  memcpy
-#define RyanMqttStrlen  strlen
-#define RyanMqttStrncmp strncmp
-#define RyanMqttStrcmp  strcmp
-#define RyanMqttSprintf sprintf
+#include "RyanJsonConfig.h"
 
-typedef enum
-{
-	// 类型标志 占用8字节,剩余一个备用
-	RyanJsonTypeUnknow = 1 << 0,
-	RyanJsonTypeNull = 1 << 1,
-	RyanJsonTypeBool = 1 << 2,
-	RyanJsonTypeNumber = 1 << 3,
-	RyanJsonTypeString = 1 << 4,
-	RyanJsonTypeArray = 1 << 5,
-	RyanJsonTypeObject = 1 << 6,
-} RyanjsonType_e;
+/**
+ * @brief Json 错误处理块
+ *
+ */
+#define RyanJsonCheckCodeNoReturn(EX, code)                                                                                                \
+	if (!(EX))                                                                                                                         \
+	{                                                                                                                                  \
+		jsonLog("\r\n%s:%d Check failed: %s\n", __FILE__, __LINE__, #EX);                                                          \
+		{code};                                                                                                                    \
+	}
+
+#define RyanJsonCheckCode(EX, code) RyanJsonCheckCodeNoReturn(EX, { {code}; });
+
+#define RyanJsonCheckReturnFlase(EX) RyanJsonCheckCode(EX, { return RyanJsonFalse; })
+#define RyanJsonCheckReturnNull(EX)  RyanJsonCheckCode(EX, { return NULL; })
+#define RyanJsonCheckAssert(EX)      RyanJsonCheckCode(EX, { RyanJsonAssert(NULL && "RyanJsonCheckAssert"); })
+
+// Json的最基础节点,所有Json元素都由该节点表示。
+// 结构体中仅包含固定的 next 指针,用于单向链表串联。
+// 其余数据(flag、key、stringValue、numberValue、doubleValue 等)均通过动态内存分配管理。
+//
+// 在 next 后紧跟一个字节的 flag,用于描述节点的核心信息:
+//   - 节点类型(null / bool / number / string / object)
+//   - 是否包含 key
+//   - Bool 类型的取值(true/false)
+//   - Number 类型的类别(整数 / 浮点数)
+//   - Key 的长度(占用 1~4 字节)
+//
+// flag 后若节点包含 key 或字符串值,则跟随一个指针,指向存储区:
+//   [ keyLen | key | stringValue ]
+//   其中 keyLen 的大小由 flag 中的长度信息决定(最多 4 字节)。
+//
+// 在指针之后,根据节点类型存储具体数据:
+//   - null / bool:由 flag 表示
+//   - string:由上述指针指向
+//   - number:根据 flag 决定存储 int 或 double,来申请空间
+//   - object:动态分配空间存储子节点,申请一个指针空间
+//
+// 整个设计通过一个字节的 flag 高度复用信息,保证结构紧凑且灵活。
+// 设计特点:
+//   - 一个 Json 节点最多 malloc 两次(一次节点本身,一次可选的 key/stringValue),
+//     对嵌入式系统非常友好,减少 malloc 头部开销。
+//   - key 和 stringValue 必须通过指针管理:
+//       * 如果直接将key 和 stringValue放在节点里,虽然只需一次 malloc,但部分修改场景会遇到问题
+//       * 如何找到前置节点的问题,需要找到前置节点,替换修改过节点,然后释放当前节点。(这个最开始已经实现了,关键是下面这条)
+//       * 用户可能传递的 Json 对象不是指针,无法直接替换节点。要求应用层传递指针会增加侵入性,改动太大,不符合“应用层无需修改”的更新目标。
+//   - 因此采用指针方式,保证灵活性和低侵入性。
 
-typedef enum
+struct RyanJsonNode
 {
-	// flag标志
-	RyanJsonValueBoolTrueFlag = 1 << 8,
-	RyanJsonValueNumberIntFlag = 1 << 9,
-	RyanJsonWithKeyFlag = 1 << 10
-} RyanJsonInfoFlag_e;
+	struct RyanJsonNode *next; // 单链表node节点
+};
+
+typedef struct RyanJsonNode *RyanJson_t;
 
 typedef enum
 {
-	RyanJsonFalse = 0,
-	RyanJsonTrue = 1
-} RyanJsonBool_e;
+	// 类型标志 占用8字节,剩余一个备用
+	RyanJsonTypeNull = 1,
+	RyanJsonTypeBool = 2,
+	RyanJsonTypeNumber = 3,
+	RyanJsonTypeString = 4,
+	RyanJsonTypeArray = 5,
+	RyanJsonTypeObject = 6,
+} RyanjsonType_e;
+
+#define RyanJsonFalse (false)
+#define RyanJsonTrue  (true)
 
 // !兼容之前的类型定义
+typedef bool RyanJsonBool_e;
 typedef RyanJsonBool_e RyanJsonBool;
 
-struct RyanJsonNode
-{
-	uint32_t info;             // 包含类型,key等标志
-	struct RyanJsonNode *next; // 单链表node节点
-
-	// [char *key] 有key的json节点, 会动态创建指针
-
-	// 有value值的节点, 会动态创建指针
-	// [int32_t value / double value / char* value / RyanJson_t item]
-};
-
-typedef struct RyanJsonNode *RyanJson_t;
-
 // 内存钩子函数
-typedef void *(*malloc_t)(size_t size);
-typedef void (*free_t)(void *block);
-typedef void *(*realloc_t)(void *block, size_t size);
-
-// 限制解析数组/对象中嵌套的深度
-// RyanJson使用递归 序列化/反序列化 json
-// 请根据单片机资源合理设置以防止堆栈溢出。
-#ifndef RyanJsonNestingLimit
-#define RyanJsonNestingLimit 30000
-#endif
-
-// 当 RyanJsonPrint 剩余缓冲空间不足时申请的空间大小
-#define RyanJsonPrintfPreAlloSize (64)
+typedef void *(*RyanJsonMalloc_t)(size_t size);
+typedef void (*RyanJsonFree_t)(void *block);
+typedef void *(*RyanJsonRealloc_t)(void *block, size_t size);
 
 /**
- * @brief 较底层接口, 不推荐用户使用,除非用户知道这些接口意义
+ * !!!较底层接口, 不推荐用户使用,除非用户知道这些接口意义
+ * !!!一定要看这里,这里的接口不推荐使用
  */
-#define RyanJsonGetInfo(pJson) ((pJson) ? ((pJson)->info) : 0)
-// NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
-#define RyanJsonGetType(pJson) ((RyanjsonType_e)((uint8_t)RyanJsonGetInfo(pJson)))
+#define RyanJsonGetMask(bits)                           (((1U << (bits)) - 1))
+#define RyanJsonGetPayloadPtr(pJson)                    ((uint8_t *)(pJson) + sizeof(struct RyanJsonNode))
+#define RyanJsonGetPayloadFlagField(pJson, shift, mask) (((*RyanJsonGetPayloadPtr(pJson)) >> (shift)) & (mask))
+#define RyanJsonSetPayloadFlagField(pJson, shift, mask, value)                                                                             \
+	((*RyanJsonGetPayloadPtr(pJson)) =                                                                                                 \
+		 ((*RyanJsonGetPayloadPtr(pJson)) & ~((mask) << (shift))) | ((uint8_t)(((value) & (mask)) << (shift))))
+
+#define RyanJsonGetType(pJson)       ((RyanjsonType_e)RyanJsonGetPayloadFlagField((pJson), 0, RyanJsonGetMask(3)))
+#define RyanJsonSetType(pJson, type) (RyanJsonSetPayloadFlagField((pJson), 0, RyanJsonGetMask(3), (RyanjsonType_e)(type)))
+
+// bool跟number用一个字段,因为bool和number类型不会同时存在
+#define RyanJsonGetPayloadBoolValueByFlag(pJson)             RyanJsonGetPayloadFlagField((pJson), 3, RyanJsonGetMask(1))
+#define RyanJsonSetPayloadBoolValueByFlag(pJson, value)      RyanJsonSetPayloadFlagField((pJson), 3, RyanJsonGetMask(1), (value))
+#define RyanJsonGetPayloadNumberIsDoubleByFlag(pJson)        RyanJsonGetPayloadFlagField((pJson), 3, RyanJsonGetMask(1))
+#define RyanJsonSetPayloadNumberIsDoubleByFlag(pJson, value) RyanJsonSetPayloadFlagField((pJson), 3, RyanJsonGetMask(1), (value))
+
+#define RyanJsonGetPayloadWhiteKeyByFlag(pJson)        RyanJsonGetPayloadFlagField((pJson), 4, RyanJsonGetMask(1))
+#define RyanJsonSetPayloadWhiteKeyByFlag(pJson, value) RyanJsonSetPayloadFlagField((pJson), 4, RyanJsonGetMask(1), (value))
+
+// ! 使用超过8字节后一定要注意 RyanJsonSetPayloadFlagField 目前限制uint8_t类型
+// flag空间不够的时候可以把这个字段弃用,用redis的listpack方法将key和keyLen一起表示,内存占用也挺好,但是复杂度高,有空间就保持现在这样
+#define RyanJsonGetPayloadEncodeKeyLenByFlag(pJson)        ((uint8_t)RyanJsonGetPayloadFlagField((pJson), 5, RyanJsonGetMask(2)) + 1)
+#define RyanJsonSetPayloadEncodeKeyLenByFlag(pJson, value) RyanJsonSetPayloadFlagField((pJson), 5, RyanJsonGetMask(2), (value))
 extern RyanJsonBool_e RyanJsonInsert(RyanJson_t pJson, int32_t index, RyanJson_t item);
 extern void *RyanJsonGetValue(RyanJson_t pJson);
-extern RyanJson_t RyanJsonGetObjectByIndexs(RyanJson_t pJson, int32_t index, ...);
-extern RyanJson_t RyanJsonGetObjectByKeys(RyanJson_t pJson, char *key, ...);
-extern RyanJsonBool_e RyanJsonReapplyString(char **dst, const char *src);
 extern RyanJson_t RyanJsonCreateItem(const char *key, RyanJson_t item);
+/**
+ * !!!上面的接口不推荐使用
+ *
+ */
 
 /**
  * @brief json对象函数
  */
-extern RyanJsonBool_e RyanJsonInitHooks(malloc_t _malloc, free_t _free, realloc_t _realloc);
-extern RyanJson_t RyanJsonParseOptions(const char *text, uint32_t size, RyanJsonBool_e mustBeNullTerminated, const char **parseEndPtr); // 需用户释放内存
-#define RyanJsonParse(text) RyanJsonParseOptions(text, strlen(text), RyanJsonFalse, NULL)                                               // 需用户释放内存
+extern RyanJsonBool_e RyanJsonInitHooks(RyanJsonMalloc_t _malloc, RyanJsonFree_t _free, RyanJsonRealloc_t _realloc);
+extern RyanJson_t RyanJsonParseOptions(const char *text, int32_t size, RyanJsonBool_e requireNullTerminator,
+				       const char **parseEndPtr);                                            // 需用户释放内存
+#define RyanJsonParse(text) RyanJsonParseOptions((text), (int32_t)RyanJsonStrlen(text), RyanJsonFalse, NULL) // 需用户释放内存
 
-extern char *RyanJsonPrint(RyanJson_t pJson, uint32_t preset, RyanJsonBool_e format, uint32_t *len); // 需用户释放内存
-extern char *RyanJsonPrintPreallocated(RyanJson_t pJson, char *buffer, uint32_t length, RyanJsonBool_e format, uint32_t *len);
+/**
+ * @brief 打印json对象函数
+ */
+extern char *RyanJsonPrint(RyanJson_t pJson, int32_t preset, RyanJsonBool_e format, int32_t *len); // 需用户释放内存
+extern char *RyanJsonPrintPreallocated(RyanJson_t pJson, char *buffer, int32_t length, RyanJsonBool_e format, int32_t *len);
 
+/**
+ * @brief json杂项函数
+ */
 extern RyanJson_t RyanJsonDuplicate(RyanJson_t pJson); // 需用户释放内存
-extern uint32_t RyanJsonGetSize(RyanJson_t pJson);     // 获取Json中子项个数
-extern void RyanJsonMinify(char *text);
+extern int32_t RyanJsonGetSize(RyanJson_t pJson);      // 获取Json中子项个数
+extern int32_t RyanJsonMinify(char *text, int32_t textLen);
 
 extern void RyanJsonDelete(RyanJson_t pJson);
 extern void RyanJsonFree(void *block);
 
 extern RyanJsonBool_e RyanJsonCompare(RyanJson_t a, RyanJson_t b);
-extern RyanJsonBool_e RyanJsonCompareOnlyKey(RyanJson_t a, RyanJson_t b);
 
 /**
  * @brief 添加 / 删除相关函数
  */
-extern RyanJson_t RyanJsonCreateObject(void);                            // 如果没有添加到父json, 则需释放内存
-extern RyanJson_t RyanJsonCreateNull(char *key);                         // 如果没有添加到父json, 则需释放内存
-extern RyanJson_t RyanJsonCreateBool(char *key, RyanJsonBool_e boolean); // 如果没有添加到父json, 则需释放内存
-extern RyanJson_t RyanJsonCreateInt(char *key, int32_t number);          // 如果没有添加到父json, 则需释放内存
-extern RyanJson_t RyanJsonCreateDouble(char *key, double number);        // 如果没有添加到父json, 则需释放内存
-extern RyanJson_t RyanJsonCreateString(char *key, const char *string);   // 如果没有添加到父json, 则需释放内存
-
-extern RyanJson_t RyanJsonCreateArray(void);                                       // 如果没有添加到父json, 则需释放内存
-extern RyanJson_t RyanJsonCreateIntArray(const int32_t *numbers, int32_t count);   // 语法糖,根据传入的numbers数组创建一个int类型的数组。如果没有添加到父json, 则需释放内存
-extern RyanJson_t RyanJsonCreateDoubleArray(const double *numbers, int32_t count); // 语法糖,根据传入的numbers数组创建一个double类型的数组。如果没有添加到父json, 则需释放内存
-extern RyanJson_t RyanJsonCreateStringArray(const char **strings, int32_t count);  // 语法糖,根据传入的strings数组创建一个string类型的数组。如果没有添加到父json, 则需释放内存
+extern RyanJson_t RyanJsonCreateObject(void);                                  // 如果没有添加到父json, 则需释放内存
+extern RyanJson_t RyanJsonCreateNull(const char *key);                         // 如果没有添加到父json, 则需释放内存
+extern RyanJson_t RyanJsonCreateBool(const char *key, RyanJsonBool_e boolean); // 如果没有添加到父json, 则需释放内存
+extern RyanJson_t RyanJsonCreateInt(const char *key, int32_t number);          // 如果没有添加到父json, 则需释放内存
+extern RyanJson_t RyanJsonCreateDouble(const char *key, double number);        // 如果没有添加到父json, 则需释放内存
+extern RyanJson_t RyanJsonCreateString(const char *key, const char *string);   // 如果没有添加到父json, 则需释放内存
+extern RyanJson_t RyanJsonCreateArray(void);                                   // 如果没有添加到父json, 则需释放内存
+
+// 语法糖,根据传入的numbers数组创建一个int类型的数组。如果没有添加到父json, 则需释放内存
+extern RyanJson_t RyanJsonCreateIntArray(const int32_t *numbers, int32_t count);
+// 语法糖,根据传入的numbers数组创建一个double类型的数组。如果没有添加到父json, 则需释放内存
+extern RyanJson_t RyanJsonCreateDoubleArray(const double *numbers, int32_t count);
+// 语法糖,根据传入的strings数组创建一个string类型的数组。如果没有添加到父json, 则需释放内存
+extern RyanJson_t RyanJsonCreateStringArray(const char **strings, int32_t count);
 
 extern RyanJson_t RyanJsonDetachByIndex(RyanJson_t pJson, int32_t index); // 需用户释放内存
 extern RyanJson_t RyanJsonDetachByKey(RyanJson_t pJson, const char *key); // 需用户释放内存
 extern RyanJsonBool_e RyanJsonDeleteByIndex(RyanJson_t pJson, int32_t index);
 extern RyanJsonBool_e RyanJsonDeleteByKey(RyanJson_t pJson, const char *key);
 
+// 工具宏
+#define RyanJsonMakeBool(ex) ((ex) ? RyanJsonTrue : RyanJsonFalse)
+
 /**
  * @brief 查询函数
  */
 extern RyanJson_t RyanJsonGetObjectByKey(RyanJson_t pJson, const char *key);
 extern RyanJson_t RyanJsonGetObjectByIndex(RyanJson_t pJson, int32_t index);
-#define RyanJsonGetObjectToKey(pJson, key, ...)     RyanJsonGetObjectByKeys(pJson, key, ##__VA_ARGS__, NULL)
-#define RyanJsonGetObjectToIndex(pJson, index, ...) RyanJsonGetObjectByIndexs(pJson, index, ##__VA_ARGS__, INT_MIN)
-
-#define RyanJsonHasObjectByKey(pJson, key)        (RyanJsonGetObjectByKey(pJson, key) ? RyanJsonTrue : RyanJsonFalse)
-#define RyanJsonHasObjectByIndex(pJson, key)      (RyanJsonGetObjectByIndex(pJson, index) ? RyanJsonTrue : RyanJsonFalse)
-#define RyanJsonHasObjectToKey(pJson, key, ...)   (RyanJsonGetObjectByKeys(pJson, key, ##__VA_ARGS__, NULL) ? RyanJsonTrue : RyanJsonFalse)
-#define RyanJsonHasObjectToIndex(pJson, key, ...) (RyanJsonGetObjectByIndexs(pJson, index, ##__VA_ARGS__, INT_MIN) ? RyanJsonTrue : RyanJsonFalse)
-
-#define returnJsonBool(ex)      ((ex) ? RyanJsonTrue : RyanJsonFalse)
-#define RyanJsonIsKey(pJson)    returnJsonBool(RyanJsonGetInfo(pJson) & RyanJsonWithKeyFlag)
-#define RyanJsonIsNull(pJson)   returnJsonBool(RyanJsonGetType(pJson) & RyanJsonTypeNull)
-#define RyanJsonIsBool(pJson)   returnJsonBool(RyanJsonGetType(pJson) & RyanJsonTypeBool)
-#define RyanJsonIsNumber(pJson) returnJsonBool(RyanJsonGetType(pJson) & RyanJsonTypeNumber)
-#define RyanJsonIsInt(pJson)    returnJsonBool(RyanJsonIsNumber(pJson) && (RyanJsonGetInfo(pJson) & RyanJsonValueNumberIntFlag))
-#define RyanJsonIsDouble(pJson) returnJsonBool(RyanJsonIsNumber(pJson) && !(RyanJsonGetInfo(pJson) & RyanJsonValueNumberIntFlag))
-#define RyanJsonIsString(pJson) returnJsonBool(RyanJsonGetType(pJson) & RyanJsonTypeString)
-#define RyanJsonIsArray(pJson)  returnJsonBool(RyanJsonGetType(pJson) & RyanJsonTypeArray)
-#define RyanJsonIsObject(pJson) returnJsonBool(RyanJsonGetType(pJson) & RyanJsonTypeObject)
-
-//! get value函数使用前建议RyanJsonIsXXXX宏做好判断
-#define RyanJsonGetKey(pJson)         (*(char **)((RyanJson_t)(pJson) + 1))
-#define RyanJsonGetNullValue(pJson)   (NULL)
-#define RyanJsonGetBoolValue(pJson)   (RyanJsonGetInfo(pJson) & RyanJsonValueBoolTrueFlag ? RyanJsonTrue : RyanJsonFalse)
+
+#define RyanJsonHasObjectByKey(pJson, key)     RyanJsonMakeBool(RyanJsonGetObjectByKey(pJson, key))
+#define RyanJsonHasObjectByIndex(pJson, index) RyanJsonMakeBool(RyanJsonGetObjectByIndex(pJson, index))
+
+#define RyanJsonIsKey(pJson)    RyanJsonMakeBool(RyanJsonGetPayloadWhiteKeyByFlag(pJson))
+#define RyanJsonIsNull(pJson)   RyanJsonMakeBool(RyanJsonGetType(pJson) == RyanJsonTypeNull)
+#define RyanJsonIsBool(pJson)   RyanJsonMakeBool(RyanJsonGetType(pJson) == RyanJsonTypeBool)
+#define RyanJsonIsNumber(pJson) RyanJsonMakeBool(RyanJsonGetType(pJson) == RyanJsonTypeNumber)
+#define RyanJsonIsInt(pJson)    RyanJsonMakeBool(RyanJsonIsNumber(pJson) && (RyanJsonFalse == RyanJsonGetPayloadNumberIsDoubleByFlag(pJson)))
+#define RyanJsonIsDouble(pJson) RyanJsonMakeBool(RyanJsonIsNumber(pJson) && (RyanJsonTrue == RyanJsonGetPayloadNumberIsDoubleByFlag(pJson)))
+#define RyanJsonIsString(pJson) RyanJsonMakeBool(RyanJsonGetType(pJson) == RyanJsonTypeString)
+#define RyanJsonIsArray(pJson)  RyanJsonMakeBool(RyanJsonGetType(pJson) == RyanJsonTypeArray)
+#define RyanJsonIsObject(pJson) RyanJsonMakeBool(RyanJsonGetType(pJson) == RyanJsonTypeObject)
+
+//! get value函数使用前一定要RyanJsonIsXXXX宏做好判断,否则会内存访问越界
+extern char *RyanJsonGetKey(RyanJson_t pJson);
+extern char *RyanJsonGetStringValue(RyanJson_t pJson);
+#define RyanJsonGetBoolValue(pJson)   RyanJsonGetPayloadBoolValueByFlag(pJson)
 #define RyanJsonGetIntValue(pJson)    (*(int32_t *)RyanJsonGetValue(pJson))
 #define RyanJsonGetDoubleValue(pJson) (*(double *)RyanJsonGetValue(pJson))
-#define RyanJsonGetStringValue(pJson) (*(char **)RyanJsonGetValue(pJson))
 #define RyanJsonGetArrayValue(pJson)  (*(RyanJson_t *)RyanJsonGetValue(pJson))
 #define RyanJsonGetObjectValue(pJson) (*(RyanJson_t *)RyanJsonGetValue(pJson))
 
 #define RyanJsonGetArraySize(pJson) RyanJsonGetSize(pJson)
 
-//! add函数使用前建议RyanJsonIsXXXX宏判断是否是对象 / 数组
-#define RyanJsonAddNullToObject(pJson, key)           RyanJsonInsert(pJson, INT_MAX, RyanJsonCreateNull(key))
-#define RyanJsonAddBoolToObject(pJson, key, boolean)  RyanJsonInsert(pJson, INT_MAX, RyanJsonCreateBool(key, boolean))
-#define RyanJsonAddIntToObject(pJson, key, number)    RyanJsonInsert(pJson, INT_MAX, RyanJsonCreateInt(key, number))
-#define RyanJsonAddDoubleToObject(pJson, key, number) RyanJsonInsert(pJson, INT_MAX, RyanJsonCreateDouble(key, number))
-#define RyanJsonAddStringToObject(pJson, key, string) RyanJsonInsert(pJson, INT_MAX, RyanJsonCreateString(key, string))
-#define RyanJsonAddItemToObject(pJson, key, item)     RyanJsonInsert(pJson, INT_MAX, RyanJsonCreateItem(key, item))
+//! add函数使用前建议RyanJsonIsXXXX宏判断是否是对象 / 数组,否则会内存访问越界
+//! add函数内部会处理失败情况,如果返回false,不需要用户手动释放内存
+#define RyanJsonAddNullToObject(pJson, key)           RyanJsonInsert(pJson, INT32_MAX, RyanJsonCreateNull(key))
+#define RyanJsonAddBoolToObject(pJson, key, boolean)  RyanJsonInsert(pJson, INT32_MAX, RyanJsonCreateBool(key, boolean))
+#define RyanJsonAddIntToObject(pJson, key, number)    RyanJsonInsert(pJson, INT32_MAX, RyanJsonCreateInt(key, number))
+#define RyanJsonAddDoubleToObject(pJson, key, number) RyanJsonInsert(pJson, INT32_MAX, RyanJsonCreateDouble(key, number))
+#define RyanJsonAddStringToObject(pJson, key, string) RyanJsonInsert(pJson, INT32_MAX, RyanJsonCreateString(key, string))
+// #define RyanJsonAddItemToObject(pJson, key, item)     RyanJsonInsert(pJson, INT32_MAX, RyanJsonCreateItem(key, item))
+extern RyanJsonBool_e RyanJsonAddItemToObject(RyanJson_t pJson, char *key, RyanJson_t item);
 
 #define RyanJsonAddNullToArray(pJson)           RyanJsonAddNullToObject(pJson, NULL)
 #define RyanJsonAddBoolToArray(pJson, boolean)  RyanJsonAddBoolToObject(pJson, NULL, boolean)
@@ -184,17 +220,17 @@ extern RyanJson_t RyanJsonGetObjectByIndex(RyanJson_t pJson, int32_t index);
 #define RyanJsonAddStringToArray(pJson, string) RyanJsonAddStringToObject(pJson, NULL, string)
 #define RyanJsonAddItemToArray(pJson, item)     RyanJsonAddItemToObject(pJson, NULL, item)
 
-// 便利函数
+// 遍历函数
 #define RyanJsonArrayForEach(pJson, item)  for ((item) = RyanJsonGetArrayValue(pJson); NULL != (item); (item) = (item)->next)
 #define RyanJsonObjectForEach(pJson, item) for ((item) = RyanJsonGetObjectValue(pJson); NULL != (item); (item) = (item)->next)
 
 /**
  * @brief change函数
- * !change函数没有对入参做校验,使用前请做使用RyanJsonIsXXXX宏做好判断
+ * !change函数没有对入参做校验,使用前请做使用RyanJsonIsXXXX宏做好判断,否则会内存访问越界
  */
-#define RyanJsonChangeKey(pJson, key)            (RyanJsonReapplyString(&RyanJsonGetKey(pJson), key))
-#define RyanJsonChangeStringValue(pJson, string) (RyanJsonReapplyString(&RyanJsonGetStringValue(pJson), string))
-#define RyanJsonChangeBoolValue(pJson, boolean)  ((boolean) == RyanJsonTrue) ? ((pJson)->info |= (RyanJsonValueBoolTrueFlag)) : ((pJson)->info &= (~RyanJsonValueBoolTrueFlag))
+extern RyanJsonBool_e RyanJsonChangeKey(RyanJson_t pJson, const char *key);
+extern RyanJsonBool_e RyanJsonChangeStringValue(RyanJson_t pJson, const char *strValue);
+#define RyanJsonChangeBoolValue(pJson, boolean)  RyanJsonSetPayloadBoolValueByFlag(pJson, boolean)
 #define RyanJsonChangeIntValue(pJson, number)    (RyanJsonGetIntValue(pJson) = (number))
 #define RyanJsonChangeDoubleValue(pJson, number) (RyanJsonGetDoubleValue(pJson) = (number))
 

+ 105 - 0
RyanJson/RyanJsonConfig.h

@@ -0,0 +1,105 @@
+#ifndef __RyanJsonConfig__
+#define __RyanJsonConfig__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef RT_VER_NUM
+#define RyanJsonMemset             rt_memset
+#define RyanJsonMemcpy             rt_memcpy
+#define RyanJsonStrlen             rt_strlen
+#define RyanJsonStrcmp             rt_strcmp
+#define RyanJsonSnprintf           rt_snprintf
+#define RyanJsonPlatformAssert(EX) RT_ASSERT(EX)
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <limits.h>
+#include <float.h>
+#include <math.h>
+#include <inttypes.h>
+#include <assert.h>
+#include "valloc.h"
+#define RyanJsonMemset             memset
+#define RyanJsonMemcpy             memcpy
+#define RyanJsonStrlen             strlen
+#define RyanJsonStrcmp             strcmp
+#define RyanJsonSnprintf           snprintf
+#define RyanJsonPlatformAssert(EX) assert(EX)
+#endif
+
+// 是否启用assert
+// #define RyanJsonEnableAssert
+
+// 是否支持未对齐访问,未定义时会根据平台选择,
+// 一般不用管,如果你明白你的需求就自己定义
+// #define RyanJsonAlignUnalignedAccessSupported 0
+
+// 限制解析数组/对象中嵌套的深度
+// RyanJson使用递归 序列化/反序列化 json
+// 请根据单片机资源合理设置以防止堆栈溢出。
+#ifndef RyanJsonNestingLimit
+#define RyanJsonNestingLimit 900000000
+#endif
+
+// 当 RyanJsonPrint 剩余缓冲空间不足时申请的空间大小
+#ifndef RyanJsonPrintfPreAlloSize
+#define RyanJsonPrintfPreAlloSize (64U)
+#endif
+
+/**
+ * @brief 调试相关配置
+ *
+ */
+// #define jsonLog(fmt, ...) printf("%s:%d " fmt, __FILE__, __LINE__, ##__VA_ARGS__)
+#define jsonLog(...)
+
+#ifdef RyanJsonEnableAssert
+#define RyanJsonAssert(EX) RyanJsonPlatformAssert(EX)
+#else
+#define RyanJsonAssert(EX) (void)(EX)
+#endif
+
+/**
+ * @brief 判断是否支持未对齐访问
+ *
+ */
+#ifndef RyanJsonAlignUnalignedAccessSupported
+
+#if defined(__ARM_ARCH_6M__) // Cortex-M0/M0+/M1 属于 ARMv6-M
+#define RyanJsonAlignUnalignedAccessSupported 0
+#elif defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) // Cortex-M3/M4/M7 属于 ARMv7-M/EM
+#define RyanJsonAlignUnalignedAccessSupported 1
+#elif defined(__ARM_ARCH_8M_BASE__) || defined(__ARM_ARCH_8M_MAIN__) // Cortex-M23/M33 属于 ARMv8-M
+#define RyanJsonAlignUnalignedAccessSupported 1
+#elif defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) // Cortex-A/R 属于 ARMv7-A/R
+#define RyanJsonAlignUnalignedAccessSupported 1
+#elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5E__) // ARM9/ARM11 等老核
+#define RyanJsonAlignUnalignedAccessSupported 0
+#elif defined(__riscv) // RISC-V MCU 默认不支持未对齐访问
+#define RyanJsonAlignUnalignedAccessSupported 0
+#elif defined(__i386__) || defined(__x86_64__) // x86 / x86-64
+#define RyanJsonAlignUnalignedAccessSupported 1
+#else
+// 默认认为不支持未对齐访问
+#define RyanJsonAlignUnalignedAccessSupported 0
+#endif
+
+#endif // RyanJsonAlignUnalignedAccessSupported
+
+#if 0 == RyanJsonAlignUnalignedAccessSupported
+#define RyanJsonAlign sizeof(void *)
+#else
+#define RyanJsonAlign sizeof(uint8_t)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 162 - 0
RyanJson/RyanJsonUtils.c

@@ -0,0 +1,162 @@
+#include "RyanJsonUtils.h"
+
+/**
+ * @brief 连续通过 key 获取json对象的子项
+ *
+ * @param pJson
+ * @param key
+ * @param ... 可变参,连续输入key,直到NULL结束
+ * @return RyanJson_t
+ */
+RyanJson_t RyanJsonGetObjectByKeys(RyanJson_t pJson, const char *key, ...)
+{
+	RyanJsonCheckReturnNull(NULL != pJson && NULL != key);
+
+	const char *s = key;
+	RyanJson_t nextItem = RyanJsonGetObjectByKey(pJson, s);
+	RyanJsonCheckReturnNull(NULL != nextItem && RyanJsonIsKey(nextItem));
+
+	va_list args;
+	va_start(args, key);
+	s = va_arg(args, const char *);
+	while (nextItem && NULL != s)
+	{
+		nextItem = RyanJsonGetObjectByKey(nextItem, s);
+		s = va_arg(args, char *);
+	}
+	va_end(args);
+
+	return nextItem;
+}
+
+/**
+ * @brief 连续通过 索引 获取json对象的子项
+ *
+ * @param pJson
+ * @param index
+ * @param ... 可变参,连续输入索引,直到INT_MIN结束
+ * @return RyanJson_t
+ */
+RyanJson_t RyanJsonGetObjectByIndexs(RyanJson_t pJson, int32_t index, ...)
+{
+	RyanJsonCheckReturnNull(NULL != pJson && index >= 0);
+
+	int32_t i = index;
+	RyanJson_t nextItem = RyanJsonGetObjectByIndex(pJson, i);
+	RyanJsonCheckReturnNull(NULL != nextItem);
+
+	va_list args;
+	va_start(args, index);
+	i = va_arg(args, int32_t);
+	while (nextItem && INT32_MIN != i)
+	{
+		nextItem = RyanJsonGetObjectByIndex(nextItem, i);
+		i = va_arg(args, int32_t);
+	}
+	va_end(args);
+
+	return nextItem;
+}
+
+/**
+ * @brief 创建一个int类型的数组json对象
+ *
+ * @param numbers 数组的地址必须为int类型
+ * @param count 数组的长度
+ * @return RyanJson_t
+ */
+RyanJson_t RyanJsonCreateIntArray(const int32_t *numbers, int32_t count)
+{
+	RyanJsonCheckReturnNull(NULL != numbers && count > 0);
+
+	RyanJson_t pJson = RyanJsonCreateArray();
+	for (int32_t i = 0; pJson && i < count; i++) { RyanJsonAddIntToArray(pJson, numbers[i]); }
+	return pJson;
+}
+
+/**
+ * @brief 创建一个double类型的数组json对象
+ *
+ * @param numbers
+ * @param count
+ * @return RyanJson_t
+ */
+RyanJson_t RyanJsonCreateDoubleArray(const double *numbers, int32_t count)
+{
+	RyanJsonCheckReturnNull(NULL != numbers && count > 0);
+
+	RyanJson_t pJson = RyanJsonCreateArray();
+	for (int32_t i = 0; pJson && i < count; i++) { RyanJsonAddDoubleToArray(pJson, numbers[i]); }
+	return pJson;
+}
+
+/**
+ * @brief 创建一个string类型的数组json对象
+ *
+ * @param strings
+ * @param count
+ * @return RyanJson_t
+ */
+RyanJson_t RyanJsonCreateStringArray(const char **strings, int32_t count)
+{
+	RyanJsonCheckReturnNull(NULL != strings && count > 0);
+
+	RyanJson_t pJson = RyanJsonCreateArray();
+	for (int32_t i = 0; pJson && i < count; i++) { RyanJsonAddStringToArray(pJson, strings[i]); }
+	return pJson;
+}
+
+/**
+ * @brief 递归比较两个 pJson 对象key是否相等。
+ * 此接口效率较低, 谨慎使用
+ * @param a
+ * @param b
+ * @return RyanJsonBool_e
+ */
+RyanJsonBool_e RyanJsonCompareOnlyKey(RyanJson_t a, RyanJson_t b)
+{
+	if (NULL == a || NULL == b) { return RyanJsonFalse; }
+
+	// 相同的对象相等
+	if (a == b) { return RyanJsonTrue; }
+
+	if (RyanJsonGetType(a) != RyanJsonGetType(b)) { return RyanJsonFalse; }
+
+	switch (RyanJsonGetType(a))
+	{
+	case RyanJsonTypeBool:
+	case RyanJsonTypeNull:
+	case RyanJsonTypeNumber:
+	case RyanJsonTypeString: return RyanJsonTrue;
+
+	case RyanJsonTypeArray: {
+		if (RyanJsonGetSize(a) != RyanJsonGetSize(b)) { return RyanJsonFalse; }
+
+		for (int32_t count = 0; count < RyanJsonGetSize(a); count++)
+		{
+			if (RyanJsonTrue != RyanJsonCompareOnlyKey(RyanJsonGetObjectByIndex(a, count), RyanJsonGetObjectByIndex(b, count)))
+			{
+				return RyanJsonFalse;
+			}
+		}
+		return RyanJsonTrue;
+	}
+
+	case RyanJsonTypeObject: {
+		RyanJson_t a_element, b_element;
+		if (RyanJsonGetSize(a) != RyanJsonGetSize(b)) { return RyanJsonFalse; }
+
+		RyanJsonObjectForEach(a, a_element)
+		{
+			b_element = RyanJsonGetObjectByKey(b, RyanJsonGetKey(a_element));
+			if (NULL == b_element) { return RyanJsonFalse; }
+
+			if (RyanJsonTrue != RyanJsonCompareOnlyKey(a_element, b_element)) { return RyanJsonFalse; }
+		}
+
+		return RyanJsonTrue;
+	}
+	}
+
+	return RyanJsonFalse;
+}

+ 35 - 0
RyanJson/RyanJsonUtils.h

@@ -0,0 +1,35 @@
+
+#ifndef __RyanJsonUtils__
+#define __RyanJsonUtils__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "RyanJson.h"
+
+// 语法糖,根据传入的numbers数组创建一个int类型的数组。如果没有添加到父json, 则需释放内存
+extern RyanJson_t RyanJsonCreateIntArray(const int32_t *numbers, int32_t count);
+// 语法糖,根据传入的numbers数组创建一个double类型的数组。如果没有添加到父json, 则需释放内存
+extern RyanJson_t RyanJsonCreateDoubleArray(const double *numbers, int32_t count);
+// 语法糖,根据传入的strings数组创建一个string类型的数组。如果没有添加到父json, 则需释放内存
+extern RyanJson_t RyanJsonCreateStringArray(const char **strings, int32_t count);
+
+extern RyanJsonBool_e RyanJsonCompareOnlyKey(RyanJson_t a, RyanJson_t b);
+
+/**
+ * @brief 查询函数
+ */
+extern RyanJson_t RyanJsonGetObjectByIndexs(RyanJson_t pJson, int32_t index, ...);
+extern RyanJson_t RyanJsonGetObjectByKeys(RyanJson_t pJson, const char *key, ...);
+#define RyanJsonGetObjectToKey(pJson, key, ...)     RyanJsonGetObjectByKeys(pJson, (key), ##__VA_ARGS__, NULL)
+#define RyanJsonGetObjectToIndex(pJson, index, ...) RyanJsonGetObjectByIndexs(pJson, (index), ##__VA_ARGS__, INT32_MIN)
+
+#define RyanJsonHasObjectToKey(pJson, key, ...)     RyanJsonMakeBool(RyanJsonGetObjectByKeys(pJson, key, ##__VA_ARGS__, NULL))
+#define RyanJsonHasObjectToIndex(pJson, index, ...) RyanJsonMakeBool(RyanJsonGetObjectByIndexs(pJson, index, ##__VA_ARGS__, INT32_MIN))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 6 - 3
example/RyanJsonExample.c

@@ -37,16 +37,19 @@ static int createJsonExample(void)
 	RyanJsonAddNullToObject(item, "null");
 	RyanJsonAddItemToObject(jsonRoot, "item", item); // 将上面创建的item子对象添加到root父对象
 
-	// 添加子数组
+	// 添加数字子数组
 	int arrayInt[] = {16, 16, 16, 16, 16};
 	RyanJsonAddItemToObject(jsonRoot, "arrayInt", RyanJsonCreateIntArray(arrayInt, sizeof(arrayInt) / sizeof(arrayInt[0])));
 
+	// 添加浮点数子数组
 	double arrayDouble[] = {16.89, 16.89, 16.89, 16.89, 16.89};
 	RyanJsonAddItemToObject(jsonRoot, "arrayDouble", RyanJsonCreateDoubleArray(arrayDouble, sizeof(arrayDouble) / sizeof(arrayDouble[0])));
 
+	// 添加字符串子数组
 	const char *arrayString[] = {"hello", "hello", "hello", "hello", "hello"};
 	RyanJsonAddItemToObject(jsonRoot, "arrayString", RyanJsonCreateStringArray(arrayString, sizeof(arrayString) / sizeof(arrayString[0])));
 
+	// 添加杂项数组
 	RyanJson_t array = RyanJsonCreateArray();
 	RyanJsonAddIntToArray(array, 16);
 	RyanJsonAddDoubleToArray(array, 16.89);
@@ -174,7 +177,7 @@ static int changeJsonExample(void)
 	return 0;
 }
 
-int RyanJsonExample(void)
+RyanJsonBool_e RyanJsonExample(void)
 {
 	RyanJsonInitHooks(v_malloc, v_free, v_realloc);
 
@@ -187,5 +190,5 @@ int RyanJsonExample(void)
 	printf("\r\n--------------------------- RyanJson 修改json示例 --------------------------\r\n");
 	changeJsonExample();
 
-	return -1;
+	return RyanJsonTrue;
 }

+ 1 - 1
externalModule/cJSON/cJSON.c

@@ -117,7 +117,7 @@ CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item)
 }
 
 /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
-#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 18)
+#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 19)
     #error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
 #endif
 

+ 1 - 1
externalModule/cJSON/cJSON.h

@@ -81,7 +81,7 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ
 /* project version */
 #define CJSON_VERSION_MAJOR 1
 #define CJSON_VERSION_MINOR 7
-#define CJSON_VERSION_PATCH 18
+#define CJSON_VERSION_PATCH 19
 
 #include <stddef.h>
 

+ 251 - 92
externalModule/yyjson/yyjson.c

@@ -35,7 +35,7 @@
 #   pragma clang diagnostic ignored "-Wunused-label"
 #   pragma clang diagnostic ignored "-Wunused-macros"
 #   pragma clang diagnostic ignored "-Wunused-variable"
-#elif defined(__GNUC__)
+#elif YYJSON_IS_REAL_GCC
 #   pragma GCC diagnostic ignored "-Wunused-function"
 #   pragma GCC diagnostic ignored "-Wunused-parameter"
 #   pragma GCC diagnostic ignored "-Wunused-label"
@@ -46,6 +46,7 @@
 #   pragma warning(disable:4101) /* unreferenced variable */
 #   pragma warning(disable:4102) /* unreferenced label */
 #   pragma warning(disable:4127) /* conditional expression is constant */
+#   pragma warning(disable:4702) /* unreachable code */
 #   pragma warning(disable:4706) /* assignment within conditional expression */
 #endif
 
@@ -338,8 +339,9 @@ uint32_t yyjson_version(void) {
 #ifndef YYJSON_DISABLE_UTF8_VALIDATION
 #define YYJSON_DISABLE_UTF8_VALIDATION 0
 #endif
-
-
+#ifndef YYJSON_READER_DEPTH_LIMIT
+#define YYJSON_READER_DEPTH_LIMIT 0
+#endif
 
 /*==============================================================================
  * MARK: - Macros (Private)
@@ -438,6 +440,7 @@ uint32_t yyjson_version(void) {
 #define MSG_ERR_UTF8    "invalid utf-8 encoding in string"
 #define MSG_ERR_UTF16   "UTF-16 encoding is not supported"
 #define MSG_ERR_UTF32   "UTF-32 encoding is not supported"
+#define MSG_DEPTH       "depth limit exceeded"
 
 /* U64 constant values */
 #undef  U64_MAX
@@ -1187,11 +1190,13 @@ utf8_seq_def(b4_req2, 03, 30, 00, 00)
 /** Maximum pow10 exponent that can be represented exactly as a float64. */
 #define F64_POW10_MAX_EXACT_EXP 22
 
+#if YYJSON_DOUBLE_MATH_CORRECT
 /** Cached pow10 table. */
 static const f64 f64_pow10_table[F64_POW10_MAX_EXACT_EXP + 1] = {
     1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12,
     1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22
 };
+#endif
 
 /** Maximum pow10 exponent that can be represented exactly as a uint64. */
 #define U64_POW10_MAX_EXACT_EXP 19
@@ -5306,6 +5311,7 @@ fail_literal_null:  return_err(cur, LITERAL, MSG_CHAR_N);
 fail_character:     return_err(cur, UNEXPECTED_CHARACTER, MSG_CHAR);
 fail_comment:       return_err(cur, INVALID_COMMENT, MSG_COMMENT);
 fail_garbage:       return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
+fail_depth:         return_err(cur, DEPTH, MSG_DEPTH);
 
 #undef return_err
 }
@@ -5366,6 +5372,10 @@ static_inline yyjson_doc *read_root_minify(u8 *hdr, u8 *cur, u8 *eof,
     u8 *raw_ptr = raw_end;
     u8 **pre = &raw_ptr; /* previous raw end pointer */
 
+#if YYJSON_READER_DEPTH_LIMIT
+    u32 container_depth = 0; /* current array/object depth */
+#endif
+
     dat_len = has_flg(STOP_WHEN_DONE) ? 256 : (usize)(eof - cur);
     hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
     hdr_len += (sizeof(yyjson_doc) % sizeof(yyjson_val)) > 0;
@@ -5391,6 +5401,12 @@ static_inline yyjson_doc *read_root_minify(u8 *hdr, u8 *cur, u8 *eof,
     }
 
 arr_begin:
+#if YYJSON_READER_DEPTH_LIMIT
+    container_depth++;
+    if (unlikely(container_depth >= YYJSON_READER_DEPTH_LIMIT)) {
+        goto fail_depth;
+    }
+#endif
     /* save current container */
     ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
                (ctn->tag & YYJSON_TAG_MASK);
@@ -5496,6 +5512,9 @@ arr_val_end:
     goto fail_character_arr_end;
 
 arr_end:
+#if YYJSON_READER_DEPTH_LIMIT
+    container_depth--;
+#endif
     /* get parent container */
     ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
 
@@ -5514,6 +5533,12 @@ arr_end:
     }
 
 obj_begin:
+#if YYJSON_READER_DEPTH_LIMIT
+    container_depth++;
+    if (unlikely(container_depth >= YYJSON_READER_DEPTH_LIMIT)) {
+        goto fail_depth;
+    }
+#endif
     /* push container */
     ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
                (ctn->tag & YYJSON_TAG_MASK);
@@ -5660,6 +5685,9 @@ obj_val_end:
     goto fail_character_obj_end;
 
 obj_end:
+#if YYJSON_READER_DEPTH_LIMIT
+    container_depth--;
+#endif
     /* pop container */
     ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
     /* point to the next value */
@@ -5709,6 +5737,7 @@ fail_character_obj_sep: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_SEP);
 fail_character_obj_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_END);
 fail_comment:           return_err(cur, INVALID_COMMENT, MSG_COMMENT);
 fail_garbage:           return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
+fail_depth:             return_err(cur, DEPTH, MSG_DEPTH);
 
 #undef val_incr
 #undef return_err
@@ -5769,6 +5798,9 @@ static_inline yyjson_doc *read_root_pretty(u8 *hdr, u8 *cur, u8 *eof,
     u8 raw_end[1]; /* raw end for null-terminator */
     u8 *raw_ptr = raw_end;
     u8 **pre = &raw_ptr; /* previous raw end pointer */
+#if YYJSON_READER_DEPTH_LIMIT
+    u32 container_depth = 0; /* current array/object depth */
+#endif
 
     dat_len = has_flg(STOP_WHEN_DONE) ? 256 : (usize)(eof - cur);
     hdr_len = sizeof(yyjson_doc) / sizeof(yyjson_val);
@@ -5797,6 +5829,13 @@ static_inline yyjson_doc *read_root_pretty(u8 *hdr, u8 *cur, u8 *eof,
     }
 
 arr_begin:
+#if YYJSON_READER_DEPTH_LIMIT
+    container_depth++;
+    if (unlikely(container_depth >= YYJSON_READER_DEPTH_LIMIT)) {
+        goto fail_depth;
+    }
+#endif
+
     /* save current container */
     ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
                (ctn->tag & YYJSON_TAG_MASK);
@@ -5919,6 +5958,9 @@ arr_val_end:
     goto fail_character_arr_end;
 
 arr_end:
+#if YYJSON_READER_DEPTH_LIMIT
+    container_depth--;
+#endif
     /* get parent container */
     ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
 
@@ -5938,6 +5980,13 @@ arr_end:
     }
 
 obj_begin:
+#if YYJSON_READER_DEPTH_LIMIT
+    container_depth++;
+    if (unlikely(container_depth >= YYJSON_READER_DEPTH_LIMIT)) {
+        goto fail_depth;
+    }
+#endif
+
     /* push container */
     ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
                (ctn->tag & YYJSON_TAG_MASK);
@@ -6104,6 +6153,10 @@ obj_val_end:
     goto fail_character_obj_end;
 
 obj_end:
+#if YYJSON_READER_DEPTH_LIMIT
+    container_depth--;
+#endif
+
     /* pop container */
     ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
     /* point to the next value */
@@ -6154,6 +6207,7 @@ fail_character_obj_sep: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_SEP);
 fail_character_obj_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_END);
 fail_comment:           return_err(cur, INVALID_COMMENT, MSG_COMMENT);
 fail_garbage:           return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
+fail_depth:             return_err(cur, DEPTH, MSG_DEPTH);
 
 #undef val_incr
 #undef return_err
@@ -6612,6 +6666,10 @@ yyjson_doc *yyjson_incr_read(yyjson_incr_state *state, size_t len,
     u8 **con = NULL; /* for incremental string parsing */
     u8 saved_end = '\0'; /* saved end char */
 
+#if YYJSON_READER_DEPTH_LIMIT
+    u32 container_depth = 0; /* current array/object depth */
+#endif
+
     /* validate input parameters */
     if (!err) err = &tmp_err;
     if (unlikely(!state)) {
@@ -6733,6 +6791,13 @@ doc_begin:
     return_err(cur, UNEXPECTED_CHARACTER, msg);
 
 arr_begin:
+#if YYJSON_READER_DEPTH_LIMIT
+    container_depth++;
+    if (unlikely(container_depth >= YYJSON_READER_DEPTH_LIMIT)) {
+        goto fail_depth;
+    }
+#endif
+
     /* save current container */
     ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
                (ctn->tag & YYJSON_TAG_MASK);
@@ -6822,6 +6887,9 @@ arr_val_end:
     goto fail_character_arr_end;
 
 arr_end:
+#if YYJSON_READER_DEPTH_LIMIT
+    container_depth--;
+#endif
     /* get parent container */
     ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
 
@@ -6840,6 +6908,13 @@ arr_end:
     }
 
 obj_begin:
+#if YYJSON_READER_DEPTH_LIMIT
+    container_depth++;
+    if (unlikely(container_depth >= YYJSON_READER_DEPTH_LIMIT)) {
+        goto fail_depth;
+    }
+#endif
+
     /* push container */
     ctn->tag = (((u64)ctn_len + 1) << YYJSON_TAG_BIT) |
                (ctn->tag & YYJSON_TAG_MASK);
@@ -6954,6 +7029,10 @@ obj_val_end:
     goto fail_character_obj_end;
 
 obj_end:
+#if YYJSON_READER_DEPTH_LIMIT
+    container_depth--;
+#endif
+
     /* pop container */
     ctn_parent = (yyjson_val *)(void *)((u8 *)ctn - ctn->uni.ofs);
     /* point to the next value */
@@ -7020,6 +7099,7 @@ fail_character_obj_key: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_KEY);
 fail_character_obj_sep: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_SEP);
 fail_character_obj_end: return_err(cur, UNEXPECTED_CHARACTER, MSG_OBJ_END);
 fail_garbage:           return_err(cur, UNEXPECTED_CONTENT, MSG_GARBAGE);
+fail_depth:             return_err(cur, DEPTH, MSG_DEPTH);
 
 #undef val_incr
 #undef return_err
@@ -8944,11 +9024,11 @@ static_inline void yyjson_write_ctx_get(yyjson_write_ctx *ctx,
 }
 
 /** Write single JSON value. */
-static_inline u8 *yyjson_write_single(yyjson_val *val,
-                                      yyjson_write_flag flg,
-                                      yyjson_alc alc,
-                                      usize *dat_len,
-                                      yyjson_write_err *err) {
+static_inline u8 *write_root_single(yyjson_val *val,
+                                    yyjson_write_flag flg,
+                                    yyjson_alc alc,
+                                    char *buf, usize *dat_len,
+                                    yyjson_write_err *err) {
 #define return_err(_code, _msg) do { \
     if (hdr) alc.free(alc.ctx, (void *)hdr); \
     *dat_len = 0; \
@@ -8958,7 +9038,8 @@ static_inline u8 *yyjson_write_single(yyjson_val *val,
 } while (false)
 
 #define incr_len(_len) do { \
-    hdr = (u8 *)alc.malloc(alc.ctx, _len); \
+    if (buf) hdr = *dat_len >= _len ? (u8 *)buf : (u8 *)NULL; \
+    else hdr = (u8 *)alc.malloc(alc.ctx, _len); \
     if (!hdr) goto fail_alloc; \
     cur = hdr; \
 } while (false)
@@ -9050,11 +9131,11 @@ fail_str:   return_err(INVALID_STRING, MSG_ERR_UTF8);
 
 /** Write JSON document minify.
     The root of this document should be a non-empty container. */
-static_inline u8 *yyjson_write_minify(const yyjson_val *root,
-                                      const yyjson_write_flag flg,
-                                      const yyjson_alc alc,
-                                      usize *dat_len,
-                                      yyjson_write_err *err) {
+static_inline u8 *write_root_minify(const yyjson_val *root,
+                                    const yyjson_write_flag flg,
+                                    const yyjson_alc alc,
+                                    char *buf, usize *dat_len,
+                                    yyjson_write_err *err) {
 #define return_err(_code, _msg) do { \
     *dat_len = 0; \
     err->code = YYJSON_WRITE_ERROR_##_code; \
@@ -9104,11 +9185,18 @@ static_inline u8 *yyjson_write_minify(const yyjson_val *root,
     bool inv = has_allow(INVALID_UNICODE) != 0;
     bool newline = has_flg(NEWLINE_AT_END) != 0;
 
-    alc_len = root->uni.ofs / sizeof(yyjson_val);
-    alc_len = alc_len * YYJSON_WRITER_ESTIMATED_MINIFY_RATIO + 64;
-    alc_len = size_align_up(alc_len, sizeof(yyjson_write_ctx));
-    hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
-    if (!hdr) goto fail_alloc;
+    if (buf) {
+        hdr = (u8 *)buf;
+        alc_len = *dat_len;
+        alc_len = size_align_down(alc_len, sizeof(yyjson_write_ctx));
+        if (alc_len <= sizeof(yyjson_write_ctx)) goto fail_alloc;
+    } else {
+        alc_len = root->uni.ofs / sizeof(yyjson_val);
+        alc_len = alc_len * YYJSON_WRITER_ESTIMATED_MINIFY_RATIO + 64;
+        alc_len = size_align_up(alc_len, sizeof(yyjson_write_ctx));
+        hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
+        if (!hdr) goto fail_alloc;
+    }
     cur = hdr;
     end = hdr + alc_len;
     ctx = (yyjson_write_ctx *)(void *)end;
@@ -9149,7 +9237,7 @@ val_begin:
                     (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
         ctn_len_tmp = unsafe_yyjson_get_len(val);
         ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
-        incr_len(16);
+        incr_len(2 * sizeof(*ctx));
         if (unlikely(ctn_len_tmp == 0)) {
             /* write empty container */
             *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
@@ -9231,11 +9319,11 @@ fail_str:   return_err(INVALID_STRING, MSG_ERR_UTF8);
 
 /** Write JSON document pretty.
     The root of this document should be a non-empty container. */
-static_inline u8 *yyjson_write_pretty(const yyjson_val *root,
-                                      const yyjson_write_flag flg,
-                                      const yyjson_alc alc,
-                                      usize *dat_len,
-                                      yyjson_write_err *err) {
+static_inline u8 *write_root_pretty(const yyjson_val *root,
+                                    const yyjson_write_flag flg,
+                                    const yyjson_alc alc,
+                                    char *buf, usize *dat_len,
+                                    yyjson_write_err *err) {
 #define return_err(_code, _msg) do { \
     *dat_len = 0; \
     err->code = YYJSON_WRITE_ERROR_##_code; \
@@ -9286,11 +9374,18 @@ static_inline u8 *yyjson_write_pretty(const yyjson_val *root,
     usize spaces = has_flg(PRETTY_TWO_SPACES) ? 2 : 4;
     bool newline = has_flg(NEWLINE_AT_END) != 0;
 
-    alc_len = root->uni.ofs / sizeof(yyjson_val);
-    alc_len = alc_len * YYJSON_WRITER_ESTIMATED_PRETTY_RATIO + 64;
-    alc_len = size_align_up(alc_len, sizeof(yyjson_write_ctx));
-    hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
-    if (!hdr) goto fail_alloc;
+    if (buf) {
+        hdr = (u8 *)buf;
+        alc_len = *dat_len;
+        alc_len = size_align_down(alc_len, sizeof(yyjson_write_ctx));
+        if (alc_len <= sizeof(yyjson_write_ctx)) goto fail_alloc;
+    } else {
+        alc_len = root->uni.ofs / sizeof(yyjson_val);
+        alc_len = alc_len * YYJSON_WRITER_ESTIMATED_PRETTY_RATIO + 64;
+        alc_len = size_align_up(alc_len, sizeof(yyjson_write_ctx));
+        hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
+        if (!hdr) goto fail_alloc;
+    }
     cur = hdr;
     end = hdr + alc_len;
     ctx = (yyjson_write_ctx *)(void *)end;
@@ -9340,9 +9435,9 @@ val_begin:
         no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
         ctn_len_tmp = unsafe_yyjson_get_len(val);
         ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
+        incr_len(2 * sizeof(*ctx) + (no_indent ? 0 : level * 4));
         if (unlikely(ctn_len_tmp == 0)) {
             /* write empty container */
-            incr_len(16 + (no_indent ? 0 : level * 4));
             cur = write_indent(cur, no_indent ? 0 : level, spaces);
             *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
             *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
@@ -9351,7 +9446,6 @@ val_begin:
             goto val_end;
         } else {
             /* push context, setup new container */
-            incr_len(32 + (no_indent ? 0 : level * 4));
             yyjson_write_ctx_set(--ctx, ctn_len, ctn_obj);
             ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
             ctn_obj = ctn_obj_tmp;
@@ -9436,17 +9530,11 @@ fail_str:   return_err(INVALID_STRING, MSG_ERR_UTF8);
 #undef check_str_len
 }
 
-
-
-/*==============================================================================
- * MARK: - JSON Writer (Public)
- *============================================================================*/
-
-char *yyjson_val_write_opts(const yyjson_val *val,
-                            yyjson_write_flag flg,
-                            const yyjson_alc *alc_ptr,
-                            usize *dat_len,
-                            yyjson_write_err *err) {
+static char *write_root(const yyjson_val *val,
+                        yyjson_write_flag flg,
+                        const yyjson_alc *alc_ptr,
+                        char *buf, usize *dat_len,
+                        yyjson_write_err *err) {
     yyjson_write_err tmp_err;
     usize tmp_dat_len;
     yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
@@ -9463,21 +9551,35 @@ char *yyjson_val_write_opts(const yyjson_val *val,
     }
 
     if (!unsafe_yyjson_is_ctn(root) || unsafe_yyjson_get_len(root) == 0) {
-        return (char *)yyjson_write_single(root, flg, alc, dat_len, err);
+        return (char *)write_root_single(root, flg, alc, buf, dat_len, err);
     } else if (flg & (YYJSON_WRITE_PRETTY | YYJSON_WRITE_PRETTY_TWO_SPACES)) {
-        return (char *)yyjson_write_pretty(root, flg, alc, dat_len, err);
+        return (char *)write_root_pretty(root, flg, alc, buf, dat_len, err);
     } else {
-        return (char *)yyjson_write_minify(root, flg, alc, dat_len, err);
+        return (char *)write_root_minify(root, flg, alc, buf, dat_len, err);
     }
 }
 
+
+
+/*==============================================================================
+ * MARK: - JSON Writer (Public)
+ *============================================================================*/
+
+char *yyjson_val_write_opts(const yyjson_val *val,
+                            yyjson_write_flag flg,
+                            const yyjson_alc *alc_ptr,
+                            usize *dat_len,
+                            yyjson_write_err *err) {
+    return write_root(val, flg, alc_ptr, NULL, dat_len, err);
+}
+
 char *yyjson_write_opts(const yyjson_doc *doc,
                         yyjson_write_flag flg,
                         const yyjson_alc *alc_ptr,
                         usize *dat_len,
                         yyjson_write_err *err) {
     yyjson_val *root = doc ? doc->root : NULL;
-    return yyjson_val_write_opts(root, flg, alc_ptr, dat_len, err);
+    return write_root(root, flg, alc_ptr, NULL, dat_len, err);
 }
 
 bool yyjson_val_write_file(const char *path,
@@ -9499,7 +9601,7 @@ bool yyjson_val_write_file(const char *path,
         return false;
     }
 
-    dat = (u8 *)yyjson_val_write_opts(root, flg, &alc, &dat_len, err);
+    dat = (u8 *)write_root(root, flg, &alc, NULL, &dat_len, err);
     if (unlikely(!dat)) return false;
     suc = write_dat_to_file(path, dat, dat_len, err);
     alc.free(alc.ctx, dat);
@@ -9525,13 +9627,27 @@ bool yyjson_val_write_fp(FILE *fp,
         return false;
     }
 
-    dat = (u8 *)yyjson_val_write_opts(root, flg, &alc, &dat_len, err);
+    dat = (u8 *)write_root(root, flg, &alc, NULL, &dat_len, err);
     if (unlikely(!dat)) return false;
     suc = write_dat_to_fp(fp, dat, dat_len, err);
     alc.free(alc.ctx, dat);
     return suc;
 }
 
+size_t yyjson_val_write_buf(char *buf, size_t buf_len,
+                            const yyjson_val *val,
+                            yyjson_write_flag flg,
+                            yyjson_write_err *err) {
+    if (unlikely(!buf || !buf_len)) {
+        if (err) err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
+        if (err) err->msg = "input buf or buf_len is invalid";
+        return 0;
+    } else {
+        write_root(val, flg, &YYJSON_NULL_ALC, buf, &buf_len, err);
+        return buf_len;
+    }
+}
+
 bool yyjson_write_file(const char *path,
                        const yyjson_doc *doc,
                        yyjson_write_flag flg,
@@ -9550,6 +9666,14 @@ bool yyjson_write_fp(FILE *fp,
     return yyjson_val_write_fp(fp, root, flg, alc_ptr, err);
 }
 
+size_t yyjson_write_buf(char *buf, size_t buf_len,
+                        const yyjson_doc *doc,
+                        yyjson_write_flag flg,
+                        yyjson_write_err *err) {
+    yyjson_val *root = doc ? doc->root : NULL;
+    return yyjson_val_write_buf(buf, buf_len, root, flg, err);
+}
+
 
 
 /*==============================================================================
@@ -9593,22 +9717,22 @@ static_inline usize yyjson_mut_doc_estimated_val_num(
 }
 
 /** Write single JSON value. */
-static_inline u8 *yyjson_mut_write_single(yyjson_mut_val *val,
-                                          yyjson_write_flag flg,
-                                          yyjson_alc alc,
-                                          usize *dat_len,
-                                          yyjson_write_err *err) {
-    return yyjson_write_single((yyjson_val *)val, flg, alc, dat_len, err);
+static_inline u8 *mut_write_root_single(yyjson_mut_val *val,
+                                        yyjson_write_flag flg,
+                                        yyjson_alc alc,
+                                        char *buf, usize *dat_len,
+                                        yyjson_write_err *err) {
+    return write_root_single((yyjson_val *)val, flg, alc, buf, dat_len, err);
 }
 
 /** Write JSON document minify.
     The root of this document should be a non-empty container. */
-static_inline u8 *yyjson_mut_write_minify(const yyjson_mut_val *root,
-                                          usize estimated_val_num,
-                                          yyjson_write_flag flg,
-                                          yyjson_alc alc,
-                                          usize *dat_len,
-                                          yyjson_write_err *err) {
+static_inline u8 *mut_write_root_minify(const yyjson_mut_val *root,
+                                        usize estimated_val_num,
+                                        yyjson_write_flag flg,
+                                        yyjson_alc alc,
+                                        char *buf, usize *dat_len,
+                                        yyjson_write_err *err) {
 #define return_err(_code, _msg) do { \
     *dat_len = 0; \
     err->code = YYJSON_WRITE_ERROR_##_code; \
@@ -9658,10 +9782,17 @@ static_inline u8 *yyjson_mut_write_minify(const yyjson_mut_val *root,
     bool inv = has_allow(INVALID_UNICODE) != 0;
     bool newline = has_flg(NEWLINE_AT_END) != 0;
 
-    alc_len = estimated_val_num * YYJSON_WRITER_ESTIMATED_MINIFY_RATIO + 64;
-    alc_len = size_align_up(alc_len, sizeof(yyjson_mut_write_ctx));
-    hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
-    if (!hdr) goto fail_alloc;
+    if (buf) {
+        hdr = (u8 *)buf;
+        alc_len = *dat_len;
+        alc_len = size_align_down(alc_len, sizeof(yyjson_mut_write_ctx));
+        if (alc_len <= sizeof(yyjson_mut_write_ctx)) goto fail_alloc;
+    } else {
+        alc_len = estimated_val_num * YYJSON_WRITER_ESTIMATED_MINIFY_RATIO + 64;
+        alc_len = size_align_up(alc_len, sizeof(yyjson_mut_write_ctx));
+        hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
+        if (!hdr) goto fail_alloc;
+    }
     cur = hdr;
     end = hdr + alc_len;
     ctx = (yyjson_mut_write_ctx *)(void *)end;
@@ -9704,7 +9835,7 @@ val_begin:
                     (YYJSON_TYPE_ARR & YYJSON_TYPE_OBJ)) {
         ctn_len_tmp = unsafe_yyjson_get_len(val);
         ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
-        incr_len(16);
+        incr_len(2 * sizeof(*ctx));
         if (unlikely(ctn_len_tmp == 0)) {
             /* write empty container */
             *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
@@ -9790,12 +9921,12 @@ fail_str:   return_err(INVALID_STRING, MSG_ERR_UTF8);
 
 /** Write JSON document pretty.
     The root of this document should be a non-empty container. */
-static_inline u8 *yyjson_mut_write_pretty(const yyjson_mut_val *root,
-                                          usize estimated_val_num,
-                                          yyjson_write_flag flg,
-                                          yyjson_alc alc,
-                                          usize *dat_len,
-                                          yyjson_write_err *err) {
+static_inline u8 *mut_write_root_pretty(const yyjson_mut_val *root,
+                                        usize estimated_val_num,
+                                        yyjson_write_flag flg,
+                                        yyjson_alc alc,
+                                        char *buf, usize *dat_len,
+                                        yyjson_write_err *err) {
 #define return_err(_code, _msg) do { \
     *dat_len = 0; \
     err->code = YYJSON_WRITE_ERROR_##_code; \
@@ -9846,10 +9977,17 @@ static_inline u8 *yyjson_mut_write_pretty(const yyjson_mut_val *root,
     usize spaces = has_flg(PRETTY_TWO_SPACES) ? 2 : 4;
     bool newline = has_flg(NEWLINE_AT_END) != 0;
 
-    alc_len = estimated_val_num * YYJSON_WRITER_ESTIMATED_PRETTY_RATIO + 64;
-    alc_len = size_align_up(alc_len, sizeof(yyjson_mut_write_ctx));
-    hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
-    if (!hdr) goto fail_alloc;
+    if (buf) {
+        hdr = (u8 *)buf;
+        alc_len = *dat_len;
+        alc_len = size_align_down(alc_len, sizeof(yyjson_mut_write_ctx));
+        if (alc_len <= sizeof(yyjson_mut_write_ctx)) goto fail_alloc;
+    } else {
+        alc_len = estimated_val_num * YYJSON_WRITER_ESTIMATED_PRETTY_RATIO + 64;
+        alc_len = size_align_up(alc_len, sizeof(yyjson_mut_write_ctx));
+        hdr = (u8 *)alc.malloc(alc.ctx, alc_len);
+        if (!hdr) goto fail_alloc;
+    }
     cur = hdr;
     end = hdr + alc_len;
     ctx = (yyjson_mut_write_ctx *)(void *)end;
@@ -9901,9 +10039,9 @@ val_begin:
         no_indent = (bool)((u8)ctn_obj & (u8)ctn_len);
         ctn_len_tmp = unsafe_yyjson_get_len(val);
         ctn_obj_tmp = (val_type == YYJSON_TYPE_OBJ);
+        incr_len(2 * sizeof(*ctx) + (no_indent ? 0 : level * 4));
         if (unlikely(ctn_len_tmp == 0)) {
             /* write empty container */
-            incr_len(16 + (no_indent ? 0 : level * 4));
             cur = write_indent(cur, no_indent ? 0 : level, spaces);
             *cur++ = (u8)('[' | ((u8)ctn_obj_tmp << 5));
             *cur++ = (u8)(']' | ((u8)ctn_obj_tmp << 5));
@@ -9912,7 +10050,6 @@ val_begin:
             goto val_end;
         } else {
             /* push context, setup new container */
-            incr_len(32 + (no_indent ? 0 : level * 4));
             yyjson_mut_write_ctx_set(--ctx, ctn, ctn_len, ctn_obj);
             ctn_len = ctn_len_tmp << (u8)ctn_obj_tmp;
             ctn_obj = ctn_obj_tmp;
@@ -10001,12 +10138,12 @@ fail_str:   return_err(INVALID_STRING, MSG_ERR_UTF8);
 #undef check_str_len
 }
 
-static char *yyjson_mut_write_opts_impl(const yyjson_mut_val *val,
-                                        usize estimated_val_num,
-                                        yyjson_write_flag flg,
-                                        const yyjson_alc *alc_ptr,
-                                        usize *dat_len,
-                                        yyjson_write_err *err) {
+static char *mut_write_root(const yyjson_mut_val *val,
+                            usize estimated_val_num,
+                            yyjson_write_flag flg,
+                            const yyjson_alc *alc_ptr,
+                            char *buf, usize *dat_len,
+                            yyjson_write_err *err) {
     yyjson_write_err tmp_err;
     usize tmp_dat_len;
     yyjson_alc alc = alc_ptr ? *alc_ptr : YYJSON_DEFAULT_ALC;
@@ -10023,13 +10160,13 @@ static char *yyjson_mut_write_opts_impl(const yyjson_mut_val *val,
     }
 
     if (!unsafe_yyjson_is_ctn(root) || unsafe_yyjson_get_len(root) == 0) {
-        return (char *)yyjson_mut_write_single(root, flg, alc, dat_len, err);
+        return (char *)mut_write_root_single(root, flg, alc, buf, dat_len, err);
     } else if (flg & (YYJSON_WRITE_PRETTY | YYJSON_WRITE_PRETTY_TWO_SPACES)) {
-        return (char *)yyjson_mut_write_pretty(root, estimated_val_num,
-                                               flg, alc, dat_len, err);
+        return (char *)mut_write_root_pretty(root, estimated_val_num,
+                                             flg, alc, buf, dat_len, err);
     } else {
-        return (char *)yyjson_mut_write_minify(root, estimated_val_num,
-                                               flg, alc, dat_len, err);
+        return (char *)mut_write_root_minify(root, estimated_val_num,
+                                             flg, alc, buf, dat_len, err);
     }
 }
 
@@ -10044,7 +10181,7 @@ char *yyjson_mut_val_write_opts(const yyjson_mut_val *val,
                                 const yyjson_alc *alc_ptr,
                                 usize *dat_len,
                                 yyjson_write_err *err) {
-    return yyjson_mut_write_opts_impl(val, 0, flg, alc_ptr, dat_len, err);
+    return mut_write_root(val, 0, flg, alc_ptr, NULL, dat_len, err);
 }
 
 char *yyjson_mut_write_opts(const yyjson_mut_doc *doc,
@@ -10061,8 +10198,8 @@ char *yyjson_mut_write_opts(const yyjson_mut_doc *doc,
         root = NULL;
         estimated_val_num = 0;
     }
-    return yyjson_mut_write_opts_impl(root, estimated_val_num,
-                                      flg, alc_ptr, dat_len, err);
+    return mut_write_root(root, estimated_val_num,
+                          flg, alc_ptr, NULL, dat_len, err);
 }
 
 bool yyjson_mut_val_write_file(const char *path,
@@ -10117,6 +10254,20 @@ bool yyjson_mut_val_write_fp(FILE *fp,
     return suc;
 }
 
+size_t yyjson_mut_val_write_buf(char *buf, size_t buf_len,
+                                const yyjson_mut_val *val,
+                                yyjson_write_flag flg,
+                                yyjson_write_err *err) {
+    if (unlikely(!buf || !buf_len)) {
+        if (err) err->code = YYJSON_WRITE_ERROR_INVALID_PARAMETER;
+        if (err) err->msg = "input buf or buf_len is invalid";
+        return 0;
+    } else {
+        mut_write_root(val, 0, flg, &YYJSON_NULL_ALC, buf, &buf_len, err);
+        return buf_len;
+    }
+}
+
 bool yyjson_mut_write_file(const char *path,
                            const yyjson_mut_doc *doc,
                            yyjson_write_flag flg,
@@ -10135,6 +10286,14 @@ bool yyjson_mut_write_fp(FILE *fp,
     return yyjson_mut_val_write_fp(fp, root, flg, alc_ptr, err);
 }
 
+size_t yyjson_mut_write_buf(char *buf, size_t buf_len,
+                            const yyjson_mut_doc *doc,
+                            yyjson_write_flag flg,
+                            yyjson_write_err *err) {
+    yyjson_mut_val *root = doc ? doc->root : NULL;
+    return yyjson_mut_val_write_buf(buf, buf_len, root, flg, err);
+}
+
 #undef has_flg
 #undef has_allow
 #endif /* YYJSON_DISABLE_WRITER */

+ 105 - 3
externalModule/yyjson/yyjson.h

@@ -142,6 +142,9 @@
 #ifndef YYJSON_HAS_STDBOOL_H
 #endif
 
+/* Define to an integer to set a depth limit for containers (arrays, objects). */
+#ifndef YYJSON_READER_DEPTH_LIMIT
+#endif
 
 
 /*==============================================================================
@@ -418,8 +421,8 @@
 
 /** stdbool (C89 compatible) */
 #if (defined(YYJSON_HAS_STDBOOL_H) && YYJSON_HAS_STDBOOL_H) || \
-    (yyjson_has_include(<stdbool.h>) && !defined(__STRICT_ANSI__)) || \
-    YYJSON_MSC_VER >= 1800 || YYJSON_STDC_VER >= 199901L
+    YYJSON_MSC_VER >= 1800 || YYJSON_STDC_VER >= 199901L || \
+    (yyjson_has_include(<stdbool.h>) && !defined(__STRICT_ANSI__))
 #   include <stdbool.h>
 #elif !defined(__bool_true_false_are_defined)
 #   define __bool_true_false_are_defined 1
@@ -474,7 +477,7 @@ extern "C" {
 #   pragma clang diagnostic push
 #   pragma clang diagnostic ignored "-Wunused-function"
 #   pragma clang diagnostic ignored "-Wunused-parameter"
-#elif defined(__GNUC__)
+#elif YYJSON_IS_REAL_GCC
 #   if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
 #       pragma GCC diagnostic push
 #   endif
@@ -875,6 +878,9 @@ static const yyjson_read_code YYJSON_READ_ERROR_FILE_READ               = 13;
 /** Incomplete input during incremental parsing; parsing state is preserved. */
 static const yyjson_read_code YYJSON_READ_ERROR_MORE                    = 14;
 
+/** Read depth limit exceeded. */
+static const yyjson_read_code YYJSON_READ_ERROR_DEPTH                   = 15;
+
 /** Error information for JSON reader. */
 typedef struct yyjson_read_err {
     /** Error code, see `yyjson_read_code` for all possible values. */
@@ -1338,6 +1344,30 @@ yyjson_api bool yyjson_write_fp(FILE *fp,
                                 const yyjson_alc *alc,
                                 yyjson_write_err *err);
 
+/**
+ Write a document into a buffer.
+
+ This function does not allocate memory, but the buffer must be larger than the
+ final JSON size to allow temporary space. See `API.md` for details.
+
+ @param buf The output buffer.
+    If the buffer is NULL, the function will fail and return 0.
+ @param buf_len The buffer length.
+    If the buf_len is too small, the function will fail and return 0.
+ @param doc doc The JSON document.
+    If this doc is NULL or has no root, the function will fail and return 0.
+ @param flg flg The JSON write options.
+    Multiple options can be combined with `|` operator. 0 means no options.
+ @param err err A pointer to receive error information.
+    Pass NULL if you don't need error information.
+ @return The number of bytes written (excluding the null terminator),
+    or 0 on failure.
+ */
+yyjson_api size_t yyjson_write_buf(char *buf, size_t buf_len,
+                                   const yyjson_doc *doc,
+                                   yyjson_write_flag flg,
+                                   yyjson_write_err *err);
+
 /**
  Write a document to JSON string.
 
@@ -1442,6 +1472,30 @@ yyjson_api bool yyjson_mut_write_fp(FILE *fp,
                                     const yyjson_alc *alc,
                                     yyjson_write_err *err);
 
+/**
+ Write a document into a buffer.
+ 
+ This function does not allocate memory, but the buffer must be larger than the
+ final JSON size to allow temporary space. See `API.md` for details.
+ 
+ @param buf The output buffer.
+    If the buffer is NULL, the function will fail and return 0.
+ @param buf_len The buffer length.
+    If the buf_len is too small, the function will fail and return 0.
+ @param doc doc The JSON document.
+    If this doc is NULL or has no root, the function will fail and return 0.
+ @param flg flg The JSON write options.
+    Multiple options can be combined with `|` operator. 0 means no options.
+ @param err err A pointer to receive error information.
+    Pass NULL if you don't need error information.
+ @return The number of bytes written (excluding the null terminator),
+    or 0 on failure.
+ */
+yyjson_api size_t yyjson_mut_write_buf(char *buf, size_t buf_len,
+                                       const yyjson_mut_doc *doc,
+                                       yyjson_write_flag flg,
+                                       yyjson_write_err *err);
+
 /**
  Write a document to JSON string.
 
@@ -1549,6 +1603,30 @@ yyjson_api bool yyjson_val_write_fp(FILE *fp,
                                     const yyjson_alc *alc,
                                     yyjson_write_err *err);
 
+/**
+ Write a value into a buffer.
+
+ This function does not allocate memory, but the buffer must be larger than the
+ final JSON size to allow temporary space. See `API.md` for details.
+
+ @param buf The output buffer.
+    If the buffer is NULL, the function will fail and return 0.
+ @param buf_len The buffer length.
+    If the buf_len is too small, the function will fail and return 0.
+ @param val The JSON root value.
+    If this parameter is NULL, the function will fail and return NULL.
+ @param flg flg The JSON write options.
+    Multiple options can be combined with `|` operator. 0 means no options.
+ @param err err A pointer to receive error information.
+    Pass NULL if you don't need error information.
+ @return The number of bytes written (excluding the null terminator),
+    or 0 on failure.
+ */
+yyjson_api size_t yyjson_val_write_buf(char *buf, size_t buf_len,
+                                       const yyjson_val *val,
+                                       yyjson_write_flag flg,
+                                       yyjson_write_err *err);
+
 /**
  Write a value to JSON string.
 
@@ -1651,6 +1729,30 @@ yyjson_api bool yyjson_mut_val_write_fp(FILE *fp,
                                         const yyjson_alc *alc,
                                         yyjson_write_err *err);
 
+/**
+ Write a value into a buffer.
+
+ This function does not allocate memory, but the buffer must be larger than the
+ final JSON size to allow temporary space. See `API.md` for details.
+
+ @param buf The output buffer.
+    If the buffer is NULL, the function will fail and return 0.
+ @param buf_len The buffer length.
+    If the buf_len is too small, the function will fail and return 0.
+ @param val The JSON root value.
+    If this parameter is NULL, the function will fail and return NULL.
+ @param flg flg The JSON write options.
+    Multiple options can be combined with `|` operator. 0 means no options.
+ @param err err A pointer to receive error information.
+    Pass NULL if you don't need error information.
+ @return The number of bytes written (excluding the null terminator),
+    or 0 on failure.
+ */
+yyjson_api size_t yyjson_mut_val_write_buf(char *buf, size_t buf_len,
+                                           const yyjson_mut_val *val,
+                                           yyjson_write_flag flg,
+                                           yyjson_write_err *err);
+
 /**
  Write a value to JSON string.
 

+ 39 - 0
run_coverage.sh

@@ -0,0 +1,39 @@
+#!/bin/bash
+set -e  # 遇到错误立即退出
+
+# ================================
+# 1. 运行 fuzzer
+# ================================
+./build/linux/x86/release/RyanJson \
+  ./test/fuzzer/corpus \
+  -dict=./test/fuzzer/RyanJsonFuzzer.dict \
+  -timeout=2 \
+  -runs=99999 \
+  -verbosity=0 \
+  -max_len=16384
+
+# ================================
+# 2. 合并 profile 数据
+# ================================
+llvm-profdata merge -sparse default.profraw -o default.profdata
+
+# ================================
+# 3. 生成覆盖率报告(文本汇总)
+# ================================
+# 注意:llvm-cov report 只支持汇总统计,不支持行级参数
+# --show-functions       显示函数级覆盖率
+# --show-region-summary  显示区域覆盖率
+llvm-cov report ./build/linux/x86/release/RyanJson \
+  -instr-profile=default.profdata \
+  -show-mcdc-summary \
+  -show-functions \
+  -sources ./test/fuzzer ./RyanJson
+
+# ================================
+# 4. 生成覆盖率报告(HTML详细)
+# ================================
+llvm-cov show ./build/linux/x86/release/RyanJson \
+  -instr-profile=default.profdata \
+  -format=html \
+  -output-dir=coverage_report \
+  -show-mcdc-summary

+ 1 - 0
test/RFC8259JsonData/y_1.json

@@ -0,0 +1 @@
+{"emoji":"😀"}

+ 1 - 0
test/RFC8259JsonData/y_2.json

@@ -0,0 +1 @@
+{"rare":"𠀀"}

+ 1 - 0
test/RFC8259JsonData/y_3.json

@@ -0,0 +1 @@
+{"mahjong":"🀄"}

+ 1 - 0
test/RFC8259JsonData/y_array_nesting.json

@@ -0,0 +1 @@
+[[], [], [], [], [], [], [], [], [], []]

+ 0 - 312
test/RFC8259JsonTest.c

@@ -1,312 +0,0 @@
-#include "RyanJsonTest.h"
-
-#define PrintfStrCmpEnable
-
-typedef int (*jsonParseData)(char *fileName, char *data, uint32_t len);
-
-static void *yy_malloc(void *ctx, size_t size)
-{
-	return v_malloc(size);
-}
-static void *yy_realloc(void *ctx, void *ptr, size_t old_size, size_t size)
-{
-	return v_realloc(ptr, size);
-}
-static void yy_free(void *ctx, void *ptr)
-{
-	v_free(ptr);
-}
-
-static yyjson_alc yyalc = {yy_malloc, yy_realloc, yy_free, NULL};
-
-/* Read a file, parse, render back, etc. */
-static int testFile(const char *path, jsonParseData jsonParseDataHandle)
-{
-
-	DIR *dir = NULL;
-	struct dirent *entry;
-
-	int path_len = strlen(path);
-	int count = 0;
-	int used_count = 0;
-	if (!path || !path_len || !(dir = opendir(path)))
-	{
-		goto fail;
-	}
-
-	while ((entry = readdir(dir)))
-	{
-
-		char *name = (char *)entry->d_name;
-
-		if (!name || !strlen(name))
-		{
-			continue;
-		}
-
-		if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
-		{
-			continue;
-		}
-
-		char aaa[300] = {0};
-		snprintf(aaa, sizeof(aaa), "%s/%s", path, name);
-
-		FILE *f = fopen(aaa, "rb");
-		if (f == NULL)
-		{
-			goto fail;
-		}
-
-		fseek(f, 0, SEEK_END);
-		long len = ftell(f);
-		fseek(f, 0, SEEK_SET);
-		char *data = (char *)malloc(len + 10);
-		fread(data, 1, len, f);
-		data[len] = '\0';
-		fclose(f);
-		int status = 0;
-
-		status = jsonParseDataHandle(name, data, len);
-
-		used_count++;
-		if (0 == strncmp("y_", name, 2))
-		{
-			if (0 == status)
-			{
-				count++;
-			}
-			else
-			{
-				printf("应该成功,但是失败: %s, len: %ld\n", data, len);
-			}
-		}
-		else if (0 == strncmp("n_", name, 2))
-		{
-			if (0 != status)
-			{
-				count++;
-			}
-			else
-			{
-				printf("应该失败,但是成功: %s, len: %ld\n", data, len);
-			}
-		}
-		else if (0 == strncmp("i_", name, 2))
-		{
-			count++;
-		}
-
-		int area = 0, use = 0;
-		v_mcheck(&area, &use);
-		if (use != (len + 10))
-		{
-			free(data);
-			printf("内存泄漏 %s len: %ld\r\n", data, len);
-			// printf("内存泄漏 %x len: %ld\r\n", (unsigned int)data, len);
-			// printf("内存泄漏 %c len: %ld\r\n", (int)data, len);
-			printf("|||----------->>> area = %d, size = %d\r\n", area, use);
-			break;
-		}
-		free(data);
-	}
-
-	closedir(dir);
-
-	printf("RFC 8259 JSON: (%d/%d)\r\n", count, used_count);
-	return 0;
-
-fail:
-	if (dir)
-	{
-		closedir(dir);
-	}
-
-	return -1;
-}
-
-/**
- * @brief RyanJson 测试程序
- *
- * @param fileName
- * @param data
- * @param len
- * @return int
- */
-static int RyanJsonParseData(char *fileName, char *data, uint32_t len)
-{
-
-	if (strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0 || strcmp(fileName, "n_structure_open_array_object.json") == 0 ||
-	    strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0)
-	{
-		return -1;
-	}
-
-	RyanJson_t json = RyanJsonParseOptions(data, len, RyanJsonTrue, NULL);
-	if (NULL == json)
-	{
-		return -1;
-	}
-
-#ifdef PrintfStrCmpEnable
-	char *str = RyanJsonPrint(json, 60, RyanJsonFalse, NULL);
-	if (NULL == str)
-	{
-		printf("反序列化失败: [%s]\n", data);
-		goto err;
-	}
-
-	RyanJsonMinify(data);
-	if (0 != strcmp(data, str))
-	{
-		printf("数据不一致 -- 原始: %s -- 序列化: %s\n", data, str);
-	}
-
-	RyanJsonFree(str);
-#endif
-
-	RyanJsonDelete(json);
-	return 0;
-
-err:
-	RyanJsonDelete(json);
-	return -1;
-}
-
-/**
- * @brief cJson测试程序
- *
- * @param fileName
- * @param data
- * @param len
- * @return int
- */
-static int cJSONParseData(char *fileName, char *data, uint32_t len)
-{
-
-	if (strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0 || strcmp(fileName, "n_structure_open_array_object.json") == 0 ||
-	    strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0)
-	{
-		return -1;
-	}
-
-	cJSON *json = cJSON_ParseWithLengthOpts(data, len + sizeof(""), NULL, RyanJsonTrue);
-	if (NULL == json)
-	{
-		return -1;
-	}
-
-#ifdef PrintfStrCmpEnable
-	char *str = cJSON_PrintBuffered(json, 60, RyanJsonFalse);
-	if (NULL == str)
-	{
-		printf("反序列化失败: [%s]\n", data);
-		goto err;
-	}
-
-	cJSON_Minify(data);
-	if (0 != strcmp(data, str))
-	{
-		printf("-- 原始: %s -- 序列化: %s\n", data, str);
-	}
-
-	cJSON_free(str);
-#endif
-
-	cJSON_Delete(json);
-	return 0;
-err:
-	cJSON_Delete(json);
-	return -1;
-}
-
-/**
- * @brief cJson测试程序
- *
- * @param fileName
- * @param data
- * @param len
- * @return int
- */
-static int yyjsonParseData(char *fileName, char *data, uint32_t len)
-{
-
-	if (strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0 || strcmp(fileName, "n_structure_open_array_object.json") == 0 ||
-	    strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0)
-	{
-		return -1;
-	}
-
-	yyjson_doc *doc = yyjson_read_opts(data, len, YYJSON_READ_NOFLAG, &yyalc, NULL);
-	if (NULL == doc)
-	{
-		return -1;
-	}
-
-#ifdef PrintfStrCmpEnable
-	char *str = yyjson_write_opts(doc, YYJSON_WRITE_NOFLAG, &yyalc, NULL, NULL);
-	if (NULL == str)
-	{
-		printf("反序列化失败: [%s]\n", data);
-		goto err;
-	}
-
-	cJSON_Minify(data);
-	if (0 != strcmp(data, str))
-	{
-		printf("-- 原始: %s -- 序列化: %s\n", data, str);
-	}
-
-	free(str);
-#endif
-
-	yyjson_doc_free(doc);
-	return 0;
-err:
-	yyjson_doc_free(doc);
-	return -1;
-}
-
-// RFC 8259 JSON Test Suite
-// https://github.com/nst/JSONTestSuite
-RyanJsonBool RFC8259JsonTest(void)
-{
-	int result = 0;
-	RyanJsonInitHooks(v_malloc, v_free, v_realloc);
-
-	cJSON_Hooks hooks = {.malloc_fn = v_malloc, .free_fn = v_free};
-	cJSON_InitHooks(&hooks);
-
-	printf("开始 RFC 8259 JSON 测试");
-
-	printf("\r\n--------------------------- RFC8259  RyanJson --------------------------\r\n");
-	result = testFile("./RyanJsonExample/RFC8259JsonData", RyanJsonParseData);
-	if (0 != result)
-	{
-		printf("%s:%d RyanJson RFC8259JsonTest fail\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	printf("\r\n--------------------------- RFC8259  cJSON --------------------------\r\n");
-	result = testFile("./RyanJsonExample/RFC8259JsonData", cJSONParseData);
-	if (0 != result)
-	{
-		printf("%s:%d cJSON RFC8259JsonTest fail\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	printf("\r\n--------------------------- RFC8259  yyjson --------------------------\r\n");
-	result = testFile("./RyanJsonExample/RFC8259JsonData", yyjsonParseData);
-	if (0 != result)
-	{
-		printf("%s:%d yyjson RFC8259JsonTest fail\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	displayMem();
-	return RyanJsonTrue;
-
-err:
-	displayMem();
-	return RyanJsonFalse;
-}

+ 0 - 1202
test/RyanJsonBaseTest.c

@@ -1,1202 +0,0 @@
-
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <math.h>
-#include <time.h>
-
-#include "RyanJson.h"
-#include "cJSON.h"
-#include "valloc.h"
-
-/* --------------------------------------- jsonTest ------------------------------------------- */
-// !(fabs(RyanJsonGetDoubleValue(RyanJsonGetObjectToKey(json, "double")) - 16.89) < 1e-6)
-static RyanJsonBool compare_double(double a, double b)
-{
-	double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
-	return (fabs(a - b) <= maxVal * DBL_EPSILON);
-}
-
-static int rootNodeCheckTest(RyanJson_t json)
-{
-	if (!RyanJsonIsInt(RyanJsonGetObjectToKey(json, "inter")) || 16 != RyanJsonGetIntValue(RyanJsonGetObjectToKey(json, "inter")))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	if (!RyanJsonIsDouble(RyanJsonGetObjectToKey(json, "double")) || !compare_double(RyanJsonGetDoubleValue(RyanJsonGetObjectToKey(json, "double")), 16.89))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	if (!RyanJsonIsString(RyanJsonGetObjectToKey(json, "string")) || strcmp(RyanJsonGetStringValue(RyanJsonGetObjectToKey(json, "string")), "hello"))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	if (!RyanJsonIsBool(RyanJsonGetObjectToKey(json, "boolTrue")) || RyanJsonGetBoolValue(RyanJsonGetObjectToKey(json, "boolTrue")) != RyanJsonTrue)
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	if (!RyanJsonIsBool(RyanJsonGetObjectToKey(json, "boolFalse")) || RyanJsonGetBoolValue(RyanJsonGetObjectToKey(json, "boolFalse")) != RyanJsonFalse)
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	if (!RyanJsonIsNull(RyanJsonGetObjectToKey(json, "null")))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	return 0;
-}
-
-static int itemNodeCheckTest(RyanJson_t json)
-{
-	RyanJson_t item = RyanJsonGetObjectToKey(json, "item");
-	if (0 != rootNodeCheckTest(item))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	return 0;
-}
-
-static int arrayNodeCheckTest(RyanJson_t json)
-{
-	RyanJson_t item = NULL;
-
-	// 判断是不是数组类型
-	if (!RyanJsonIsArray(RyanJsonGetObjectToKey(json, "arrayInt")))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	if (!RyanJsonIsArray(RyanJsonGetObjectToKey(json, "arrayDouble")))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	if (!RyanJsonIsArray(RyanJsonGetObjectToKey(json, "arrayString")))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	if (!RyanJsonIsArray(RyanJsonGetObjectToKey(json, "array")))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	/**
-	 * @brief 检查弱类型数组
-	 *
-	 */
-	//   array: [16, 16.89, "hello", true, false, null],
-	if (!RyanJsonIsInt(RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "array"), 0)) || 16 != RyanJsonGetIntValue(RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "array"), 0)))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	if (!RyanJsonIsDouble(RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "array"), 1)) ||
-	    !compare_double(RyanJsonGetDoubleValue(RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "array"), 1)), 16.89))
-	{
-		printf("%s:%d 解析失败 %f\r\n", __FILE__, __LINE__, RyanJsonGetDoubleValue(RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "array"), 1)));
-		return -1;
-	}
-
-	if (!RyanJsonIsString(RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "array"), 2)) ||
-	    0 != strcmp(RyanJsonGetStringValue(RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "array"), 2)), "hello"))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	if (!RyanJsonIsBool(RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "array"), 3)) ||
-	    RyanJsonGetBoolValue(RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "array"), 3)) != RyanJsonTrue)
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	if (!RyanJsonIsBool(RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "array"), 4)) ||
-	    RyanJsonGetBoolValue(RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "array"), 4)) != RyanJsonFalse)
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	if (!RyanJsonIsNull(RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "array"), 5)))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	/**
-	 * @brief 检查强类型数组
-	 *
-	 */
-	for (uint32_t count = 0; count < RyanJsonGetSize(RyanJsonGetObjectToKey(json, "arrayInt")); count++)
-	{
-		item = RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "arrayInt"), count);
-		if (!RyanJsonIsInt(item) || 16 != RyanJsonGetIntValue(item))
-		{
-			printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-			return -1;
-		}
-	}
-
-	for (uint32_t count = 0; count < RyanJsonGetSize(RyanJsonGetObjectToKey(json, "arrayDouble")); count++)
-	{
-		item = RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "arrayDouble"), count);
-		if (!RyanJsonIsDouble(item) || fabs(RyanJsonGetDoubleValue(item) - 16.8) < 0.001)
-		{
-			printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-			return -1;
-		}
-	}
-
-	for (uint32_t count = 0; count < RyanJsonGetSize(RyanJsonGetObjectToKey(json, "arrayString")); count++)
-	{
-		item = RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "arrayString"), count);
-		if (!RyanJsonIsString(item) || strcmp(RyanJsonGetStringValue(item), "hello"))
-		{
-			printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-			return -1;
-		}
-	}
-
-	if (6 != RyanJsonGetSize(RyanJsonGetObjectToKey(json, "array")))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	return 0;
-}
-
-static int arrayItemNodeCheckTest(RyanJson_t json)
-{
-	if (!RyanJsonIsArray(RyanJsonGetObjectToKey(json, "arrayItem")))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	if (0 != rootNodeCheckTest(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json, "arrayItem"), 0)))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	if (0 != rootNodeCheckTest(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json, "arrayItem"), 1)))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-	return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int loadJsonTest()
-{
-	char *str = NULL;
-	RyanJson_t json;
-	char jsonstr[] = "{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\","
-			 "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\","
-			 "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
-			 "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]}";
-
-	json = RyanJsonParse(jsonstr);
-	if (json == NULL)
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	str = RyanJsonPrint(json, 250, RyanJsonFalse, NULL);
-	if (strcmp(str, jsonstr) != 0)
-	{
-		printf("%s:%d 序列化与反序列化后的数据不对应\r\n", __FILE__, __LINE__);
-		RyanJsonFree(str);
-		RyanJsonDelete(json);
-		return -1;
-	}
-
-	RyanJsonFree(str);
-
-	if (0 != rootNodeCheckTest(json))
-	{
-		RyanJsonDelete(json);
-		printf("%s:%d rootNodeCheckTest fail\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	if (0 != itemNodeCheckTest(json))
-	{
-		RyanJsonDelete(json);
-		printf("%s:%d itemNodeCheckTest fail\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	if (0 != arrayNodeCheckTest(json))
-	{
-		RyanJsonDelete(json);
-		printf("%s:%d arrayNodeCheckTest fail\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	if (0 != arrayItemNodeCheckTest(json))
-	{
-		RyanJsonDelete(json);
-		printf("%s:%d arrayItemNodeCheckTest fail\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-	RyanJsonDelete(json);
-
-	/**
-	 * @brief 测试序列化错误json结构
-	 *
-	 */
-	// \"inter\":16poi,  无效数字
-	json = RyanJsonParse("{\"inter\":16poi,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\","
-			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\","
-			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
-			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]}");
-	if (json != NULL)
-	{
-		RyanJsonDelete(json);
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	// \"double\":16.8yu9,,  无效浮点数
-	json = RyanJsonParse("{\"inter\":16,\"double\":16.8yu9,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\","
-			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\","
-			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
-			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]}");
-	if (json != NULL)
-	{
-		RyanJsonDelete(json);
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	// boolTrue 设置为 tru
-	json = RyanJsonParse("{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":tru,\"boolFalse\":false,\"null\":null,\"item\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\","
-			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\","
-			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
-			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]}");
-	if (json != NULL)
-	{
-		RyanJsonDelete(json);
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	// boolFalse 设置为 fale
-	json = RyanJsonParse("{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":fale,\"null\":null,\"item\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\","
-			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\","
-			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
-			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]}");
-	if (json != NULL)
-	{
-		RyanJsonDelete(json);
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	// null 设置为 nul
-	json = RyanJsonParse("{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":nul,\"item\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\","
-			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\","
-			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
-			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]}");
-	if (json != NULL)
-	{
-		RyanJsonDelete(json);
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	// null 设置为 NULL
-	json = RyanJsonParse("{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":NULL,\"item\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\","
-			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\","
-			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
-			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]}");
-	if (json != NULL)
-	{
-		RyanJsonDelete(json);
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	// \"inter\":16后面少个,
-	json = RyanJsonParse("{\"inter\":16\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\","
-			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\","
-			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
-			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]}");
-	if (json != NULL)
-	{
-		RyanJsonDelete(json);
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	// array数组项少一个,
-	json = RyanJsonParse("{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\","
-			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\","
-			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
-			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]}");
-	if (json != NULL)
-	{
-		RyanJsonDelete(json);
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	// \"item:{\"inter\":16,\"  少一个"
-	json = RyanJsonParse("{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item:{\"inter\":16,\"double\":16.89,\"string\":\"hello\","
-			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\","
-			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
-			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]}");
-	if (json != NULL)
-	{
-		RyanJsonDelete(json);
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	// \"item\":{\"inter\":16,double\"  少一个"
-	json = RyanJsonParse("{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":{\"inter\":16,double\":16.89,\"string\":\"hello\","
-			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\","
-			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
-			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]}");
-	if (json != NULL)
-	{
-		RyanJsonDelete(json);
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	// \"item\":{\"inter\":16,\"\"double\"  多一个"
-	json = RyanJsonParse("{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":{\"inter\":16,\"\"double\":16.89,\"string\":\"hello\","
-			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\","
-			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
-			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]}");
-	if (json != NULL)
-	{
-		RyanJsonDelete(json);
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	// \"item\":{\"inter\":16\",\"double\"  多一个"
-	json = RyanJsonParse("{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":{\"inter\":16\",\"double\":16.89,\"string\":\"hello\","
-			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\","
-			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
-			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]}");
-	if (json != NULL)
-	{
-		RyanJsonDelete(json);
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	// \"arrayInt\":[16,16,16m,16,16]  无效数组数字
-	json = RyanJsonParse("{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\","
-			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16m,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\","
-			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
-			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]}");
-	if (json != NULL)
-	{
-		RyanJsonDelete(json);
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-	return 0;
-}
-
-static int createJsonTest()
-{
-	RyanJson_t jsonRoot, item;
-
-	// 对象生成测试
-	jsonRoot = RyanJsonCreateObject();
-	RyanJsonAddIntToObject(jsonRoot, "inter", 16);
-	RyanJsonAddDoubleToObject(jsonRoot, "double", 16.89);
-	RyanJsonAddStringToObject(jsonRoot, "string", "hello");
-	RyanJsonAddBoolToObject(jsonRoot, "boolTrue", RyanJsonTrue);
-	RyanJsonAddBoolToObject(jsonRoot, "boolFalse", RyanJsonFalse);
-	RyanJsonAddNullToObject(jsonRoot, "null");
-
-	/**
-	 * @brief 对象添加测试
-	 *
-	 */
-	item = RyanJsonCreateObject();
-	RyanJsonAddIntToObject(item, "inter", 16);
-	RyanJsonAddDoubleToObject(item, "double", 16.89);
-	RyanJsonAddStringToObject(item, "string", "hello");
-	RyanJsonAddBoolToObject(item, "boolTrue", RyanJsonTrue);
-	RyanJsonAddBoolToObject(item, "boolFalse", RyanJsonFalse);
-	RyanJsonAddNullToObject(item, "null");
-	RyanJsonAddItemToObject(jsonRoot, "item", item);
-
-	/**
-	 * @brief 数组添加测试
-	 *
-	 */
-	int arrayInt[] = {16, 16, 16, 16, 16};
-	RyanJsonAddItemToObject(jsonRoot, "arrayInt", RyanJsonCreateIntArray(arrayInt, sizeof(arrayInt) / sizeof(arrayInt[0])));
-
-	double arrayDouble[] = {16.89, 16.89, 16.89, 16.89, 16.89};
-	RyanJsonAddItemToObject(jsonRoot, "arrayDouble", RyanJsonCreateDoubleArray(arrayDouble, sizeof(arrayDouble) / sizeof(arrayDouble[0])));
-
-	const char *arrayString[] = {"hello", "hello", "hello", "hello", "hello"};
-	RyanJsonAddItemToObject(jsonRoot, "arrayString", RyanJsonCreateStringArray(arrayString, sizeof(arrayString) / sizeof(arrayString[0])));
-
-	RyanJson_t array = RyanJsonCreateArray();
-	RyanJsonAddIntToArray(array, 16);
-	RyanJsonAddDoubleToArray(array, 16.89);
-	RyanJsonAddStringToArray(array, "hello");
-	RyanJsonAddBoolToArray(array, RyanJsonTrue);
-	RyanJsonAddBoolToArray(array, RyanJsonFalse);
-	RyanJsonAddNullToArray(array);
-	RyanJsonAddItemToObject(jsonRoot, "array", array);
-
-	/**
-	 * @brief 对象数组测试
-	 *
-	 */
-	RyanJson_t arrayItem = RyanJsonCreateArray();
-	item = RyanJsonCreateObject();
-	RyanJsonAddIntToObject(item, "inter", 16);
-	RyanJsonAddDoubleToObject(item, "double", 16.89);
-	RyanJsonAddStringToObject(item, "string", "hello");
-	RyanJsonAddBoolToObject(item, "boolTrue", RyanJsonTrue);
-	RyanJsonAddBoolToObject(item, "boolFalse", RyanJsonFalse);
-	RyanJsonAddNullToObject(item, "null");
-	RyanJsonAddItemToObject(arrayItem, "item", item);
-
-	item = RyanJsonCreateObject();
-	RyanJsonAddIntToObject(item, "inter", 16);
-	RyanJsonAddDoubleToObject(item, "double", 16.89);
-	RyanJsonAddStringToObject(item, "string", "hello");
-	RyanJsonAddBoolToObject(item, "boolTrue", RyanJsonTrue);
-	RyanJsonAddBoolToObject(item, "boolFalse", RyanJsonFalse);
-	RyanJsonAddNullToObject(item, "null");
-	RyanJsonAddItemToObject(arrayItem, "item", item);
-
-	RyanJsonAddItemToObject(jsonRoot, "arrayItem", arrayItem);
-
-	if (0 != rootNodeCheckTest(jsonRoot))
-	{
-		RyanJsonDelete(jsonRoot);
-		printf("%s:%d rootNodeCheckTest fail\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	if (0 != itemNodeCheckTest(jsonRoot))
-	{
-		RyanJsonDelete(jsonRoot);
-		printf("%s:%d itemNodeCheckTest fail\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	if (0 != arrayNodeCheckTest(jsonRoot))
-	{
-		RyanJsonDelete(jsonRoot);
-		printf("%s:%d arrayNodeCheckTest fail\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	if (0 != arrayItemNodeCheckTest(jsonRoot))
-	{
-		RyanJsonDelete(jsonRoot);
-		printf("%s:%d arrayItemNodeCheckTest fail\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-	RyanJsonDelete(jsonRoot);
-
-	return 0;
-}
-
-static int changeJsonTest()
-{
-
-	char jsonstr[] = "{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\","
-			 "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\","
-			 "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
-			 "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]}";
-
-	RyanJson_t json = RyanJsonParse(jsonstr);
-	if (json == NULL)
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		return -1;
-	}
-
-	/**
-	 * @brief 修改对应类型
-	 *
-	 */
-	RyanJsonChangeIntValue(RyanJsonGetObjectToKey(json, "inter"), 20);
-	if (!RyanJsonIsInt(RyanJsonGetObjectToKey(json, "inter")) || 20 != RyanJsonGetIntValue(RyanJsonGetObjectToKey(json, "inter")))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonChangeDoubleValue(RyanJsonGetObjectToKey(json, "double"), 20.89);
-	if (!RyanJsonIsDouble(RyanJsonGetObjectToKey(json, "double")) || !compare_double(RyanJsonGetDoubleValue(RyanJsonGetObjectToKey(json, "double")), 20.89))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonChangeStringValue(RyanJsonGetObjectToKey(json, "string"), "world");
-	if (!RyanJsonIsString(RyanJsonGetObjectToKey(json, "string")) || strcmp(RyanJsonGetStringValue(RyanJsonGetObjectToKey(json, "string")), "world"))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonChangeBoolValue(RyanJsonGetObjectToKey(json, "boolTrue"), RyanJsonFalse);
-	if (!RyanJsonIsBool(RyanJsonGetObjectToKey(json, "boolTrue")) || RyanJsonGetBoolValue(RyanJsonGetObjectToKey(json, "boolTrue")) != RyanJsonFalse)
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonChangeBoolValue(RyanJsonGetObjectToKey(json, "boolFalse"), RyanJsonTrue);
-	if (!RyanJsonIsBool(RyanJsonGetObjectToKey(json, "boolFalse")) || RyanJsonGetBoolValue(RyanJsonGetObjectToKey(json, "boolFalse")) != RyanJsonTrue)
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	/* ---------------------------------- replace使用 -------------------------------------*/
-	// 数组没有key, replace的子项不能有key, 函数内部没有做逻辑判断,会造成内存泄漏
-	RyanJsonReplaceByIndex(RyanJsonGetObjectToKey(json, "arrayInt"), 0, RyanJsonCreateString(NULL, "arrayInt"));
-	if (!RyanJsonIsString(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json, "arrayInt"), 0)) ||
-	    strcmp(RyanJsonGetStringValue(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json, "arrayInt"), 0)), "arrayInt"))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonReplaceByIndex(RyanJsonGetObjectToKey(json, "arrayItem"), 0, RyanJsonCreateString(NULL, "arrayItem"));
-	if (!RyanJsonIsString(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json, "arrayItem"), 0)) ||
-	    strcmp(RyanJsonGetStringValue(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json, "arrayItem"), 0)), "arrayItem"))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	// 对象必须包含key, 如果创建的对象key为null会引起内存错误
-	RyanJsonReplaceByKey(json, "arrayString", RyanJsonCreateString("", "arrayString"));
-	if (!RyanJsonIsString(RyanJsonGetObjectToKey(json, "arrayString")) || strcmp(RyanJsonGetStringValue(RyanJsonGetObjectToKey(json, "arrayString")), "arrayString"))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	// 修改数组节点为对象节点
-	RyanJsonReplaceByKey(json, "arrayDouble", RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "item")));
-	if (!RyanJsonIsObject(RyanJsonGetObjectToKey(json, "arrayDouble")) || -1 == rootNodeCheckTest(RyanJsonGetObjectToKey(json, "arrayDouble")))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-
-		goto err;
-	}
-
-	/**
-	 * @brief 对象子项删除测试
-	 *
-	 */
-	RyanJsonDeleteByIndex(json, 0);
-	if (RyanJsonGetObjectToKey(json, "inter"))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonDeleteByKey(json, "double");
-	if (RyanJsonGetObjectToKey(json, "double"))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	/**
-	 * @brief 数组对象子项删除测试
-	 *
-	 */
-	RyanJsonDeleteByIndex(RyanJsonGetObjectToKey(json, "array"), 0);
-	if (RyanJsonGetSize(RyanJsonGetObjectToKey(json, "array")) != 5)
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	// str = RyanJsonPrint(json, 1024, RyanJsonTrue, NULL);
-	// printf("aa %s\r\n", str);
-	// RyanJsonFree(str);
-	RyanJsonDelete(json);
-	return 0;
-
-err:
-	RyanJsonDelete(json);
-	return -1;
-}
-
-static int compareJsonTest()
-{
-	char jsonstr[] = "{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\","
-			 "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\","
-			 "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
-			 "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]}";
-	// char jsonstr[] = "{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}";
-
-	RyanJson_t json = RyanJsonParse(jsonstr);
-	RyanJson_t json2 = RyanJsonParse(jsonstr);
-
-	// 比较函数
-	if (RyanJsonTrue != RyanJsonCompare(json, json2))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonDelete(json2);
-	json2 = RyanJsonParse(jsonstr);
-	RyanJsonAddStringToObject(json2, "test", "hello");
-	if (RyanJsonFalse != RyanJsonCompare(json, json2))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonDelete(json2);
-	json2 = RyanJsonParse(jsonstr);
-	RyanJsonAddIntToObject(json2, "test", 1);
-	if (RyanJsonFalse != RyanJsonCompare(json, json2))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonDelete(json2);
-	json2 = RyanJsonParse(jsonstr);
-	RyanJsonAddDoubleToObject(json2, "test", 2.0);
-	if (RyanJsonFalse != RyanJsonCompare(json, json2))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonDelete(json2);
-	json2 = RyanJsonParse(jsonstr);
-	RyanJsonAddBoolToObject(json2, "test", RyanJsonTrue);
-	if (RyanJsonFalse != RyanJsonCompare(json, json2))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonDelete(json2);
-	json2 = RyanJsonParse(jsonstr);
-	RyanJsonAddNullToObject(json2, "test");
-	if (RyanJsonFalse != RyanJsonCompare(json, json2))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonDelete(json2);
-	json2 = RyanJsonParse(jsonstr);
-	RyanJsonAddIntToArray(RyanJsonGetObjectToKey(json2, "arrayInt"), 2);
-	if (RyanJsonFalse != RyanJsonCompare(json, json2))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonDelete(json2);
-	json2 = RyanJsonParse(jsonstr);
-	RyanJsonAddDoubleToArray(RyanJsonGetObjectToKey(json2, "arrayDouble"), 2.0);
-	if (RyanJsonFalse != RyanJsonCompare(json, json2))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonDelete(json2);
-	json2 = RyanJsonParse(jsonstr);
-	RyanJsonAddStringToArray(RyanJsonGetObjectToKey(json2, "arrayString"), "hello");
-	if (RyanJsonFalse != RyanJsonCompare(json, json2))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonDelete(json2);
-	json2 = RyanJsonParse(jsonstr);
-	RyanJsonAddItemToArray(RyanJsonGetObjectToKey(json2, "arrayItem"), RyanJsonCreateString("test", "hello"));
-	if (RyanJsonFalse != RyanJsonCompare(json, json2))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonDelete(json2);
-	json2 = RyanJsonParse(jsonstr);
-	RyanJsonChangeKey(RyanJsonGetObjectToKey(json2, "inter"), "int2");
-	if (RyanJsonFalse != RyanJsonCompare(json, json2))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonDelete(json2);
-	json2 = RyanJsonParse(jsonstr);
-	RyanJsonChangeIntValue(RyanJsonGetObjectToKey(json2, "inter"), 17);
-	if (RyanJsonFalse != RyanJsonCompare(json, json2))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonDelete(json2);
-	json2 = RyanJsonParse(jsonstr);
-	RyanJsonChangeDoubleValue(RyanJsonGetObjectToKey(json2, "double"), 20.89);
-	if (RyanJsonFalse != RyanJsonCompare(json, json2))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonDelete(json2);
-	json2 = RyanJsonParse(jsonstr);
-	RyanJsonChangeStringValue(RyanJsonGetObjectToKey(json2, "string"), "49");
-	if (RyanJsonFalse != RyanJsonCompare(json, json2))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonDelete(json2);
-	json2 = RyanJsonParse(jsonstr);
-	RyanJsonChangeBoolValue(RyanJsonGetObjectToKey(json2, "boolTrue"), RyanJsonFalse);
-	if (RyanJsonFalse != RyanJsonCompare(json, json2))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonDelete(json2);
-	json2 = RyanJsonParse(jsonstr);
-	RyanJsonChangeBoolValue(RyanJsonGetObjectToKey(json2, "item", "boolTrue"), RyanJsonFalse);
-	if (RyanJsonFalse != RyanJsonCompare(json, json2))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonDelete(json2);
-	json2 = RyanJsonParse(jsonstr);
-	RyanJsonChangeIntValue(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json2, "arrayInt"), 0), 17);
-	if (RyanJsonFalse != RyanJsonCompare(json, json2))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonDelete(json2);
-	json2 = RyanJsonParse(jsonstr);
-	RyanJsonChangeDoubleValue(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json2, "arrayDouble"), 0), 20.89);
-	if (RyanJsonFalse != RyanJsonCompare(json, json2))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonDelete(json2);
-	json2 = RyanJsonParse(jsonstr);
-	RyanJsonChangeStringValue(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json2, "arrayString"), 0), "20.89");
-	if (RyanJsonFalse != RyanJsonCompare(json, json2))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonDelete(json2);
-	json2 = RyanJsonParse(jsonstr);
-	RyanJsonChangeIntValue(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json2, "array"), 0), 17);
-	if (RyanJsonFalse != RyanJsonCompare(json, json2))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonDelete(json2);
-	json2 = RyanJsonParse(jsonstr);
-	RyanJsonChangeIntValue(RyanJsonGetObjectToKey(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json2, "arrayItem"), 0), "inter"), 17);
-	if (RyanJsonFalse != RyanJsonCompare(json, json2))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonDelete(json2);
-	json2 = RyanJsonParse(jsonstr);
-	RyanJsonDeleteByKey(json2, "arrayItem");
-	if (RyanJsonFalse != RyanJsonCompare(json, json2))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonDelete(json2);
-	json2 = RyanJsonParse(jsonstr);
-	RyanJsonDeleteByIndex(RyanJsonGetObjectToKey(json2, "arrayInt"), 2);
-	if (RyanJsonFalse != RyanJsonCompare(json, json2))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonDelete(json2);
-	json2 = RyanJsonParse(jsonstr);
-	RyanJsonDeleteByIndex(RyanJsonGetObjectToKey(json2, "arrayItem"), 0);
-	if (RyanJsonFalse != RyanJsonCompare(json, json2))
-	{
-		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
-		goto err;
-	}
-
-	RyanJsonDelete(json);
-	RyanJsonDelete(json2);
-	return 0;
-
-err:
-	RyanJsonDelete(json);
-	RyanJsonDelete(json2);
-	return -1;
-}
-
-static int duplicateTest()
-{
-	RyanJson_t json, dupItem, jsonRoot = NULL;
-	char jsonstr[] = "{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\","
-			 "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\","
-			 "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
-			 "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]}";
-
-	/**
-	 * @brief 普通类型
-	 *
-	 */
-	json = RyanJsonParse(jsonstr);
-	dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "inter"));
-	if (RyanJsonFalse == RyanJsonCompare(dupItem, RyanJsonGetObjectToKey(json, "inter")))
-	{
-		goto err;
-	}
-	RyanJsonDelete(dupItem);
-
-	dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "inter"));
-	RyanJsonAddItemToObject(json, "test", dupItem);
-	if (RyanJsonFalse == RyanJsonCompare(RyanJsonGetObjectToKey(json, "test", "inter"), RyanJsonGetObjectToKey(json, "inter")))
-	{
-		goto err;
-	}
-	RyanJsonDelete(RyanJsonDetachByKey(json, "test"));
-
-	dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "inter"));
-	RyanJsonAddItemToObject(json, "test", dupItem);
-	if (RyanJsonFalse == RyanJsonCompare(RyanJsonGetObjectToKey(json, "test", "inter"), RyanJsonGetObjectToKey(json, "inter")))
-	{
-		goto err;
-	}
-	RyanJsonDelete(json);
-
-	json = RyanJsonParse(jsonstr);
-	dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "inter"));
-	RyanJsonAddItemToObject(json, "test", dupItem);
-	if (RyanJsonFalse == RyanJsonCompare(RyanJsonGetObjectToKey(json, "test", "inter"), RyanJsonGetObjectToKey(json, "inter")))
-	{
-		goto err;
-	}
-	RyanJsonDelete(RyanJsonDetachByKey(json, "test"));
-	RyanJsonDelete(json);
-
-	/**
-	 * @brief 对象类型
-	 *
-	 */
-	json = RyanJsonParse(jsonstr);
-	dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "item"));
-	if (RyanJsonFalse == RyanJsonCompare(dupItem, RyanJsonGetObjectToKey(json, "item")))
-	{
-		goto err;
-	}
-	RyanJsonDelete(dupItem);
-
-	dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "item"));
-	RyanJsonAddItemToObject(json, "test", dupItem);
-	if (RyanJsonFalse == RyanJsonCompare(RyanJsonGetObjectToKey(json, "test"), RyanJsonGetObjectToKey(json, "item")))
-	{
-		goto err;
-	}
-	RyanJsonDelete(RyanJsonDetachByKey(json, "test"));
-
-	dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "item"));
-	RyanJsonAddItemToObject(json, "test", dupItem);
-	if (RyanJsonFalse == RyanJsonCompare(RyanJsonGetObjectToKey(json, "test"), RyanJsonGetObjectToKey(json, "item")))
-	{
-		goto err;
-	}
-	RyanJsonDelete(json);
-
-	json = RyanJsonParse(jsonstr);
-	dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "item"));
-	RyanJsonAddItemToObject(json, "test", dupItem);
-	if (RyanJsonFalse == RyanJsonCompare(RyanJsonGetObjectToKey(json, "test"), RyanJsonGetObjectToKey(json, "item")))
-	{
-		goto err;
-	}
-	RyanJsonDelete(RyanJsonDetachByKey(json, "test"));
-	RyanJsonDelete(json);
-
-	/**
-	 * @brief 数组类型
-	 *
-	 */
-	json = RyanJsonParse(jsonstr);
-	dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "arrayItem"));
-	if (RyanJsonFalse == RyanJsonCompare(dupItem, RyanJsonGetObjectToKey(json, "arrayItem")))
-	{
-		goto err;
-	}
-	RyanJsonDelete(dupItem);
-
-	dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "arrayItem"));
-	RyanJsonAddItemToObject(json, "test", dupItem);
-	if (RyanJsonFalse == RyanJsonCompare(RyanJsonGetObjectToKey(json, "test"), RyanJsonGetObjectToKey(json, "arrayItem")))
-	{
-		goto err;
-	}
-	RyanJsonDelete(RyanJsonDetachByKey(json, "test"));
-
-	dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "arrayItem"));
-	RyanJsonAddItemToObject(json, "test", dupItem);
-	if (RyanJsonFalse == RyanJsonCompare(RyanJsonGetObjectToKey(json, "test"), RyanJsonGetObjectToKey(json, "arrayItem")))
-	{
-		goto err;
-	}
-	RyanJsonDelete(json);
-
-	json = RyanJsonParse(jsonstr);
-	dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "arrayItem"));
-	RyanJsonAddItemToObject(json, "test", dupItem);
-	if (RyanJsonFalse == RyanJsonCompare(RyanJsonGetObjectToKey(json, "test"), RyanJsonGetObjectToKey(json, "arrayItem")))
-	{
-		goto err;
-	}
-	RyanJsonDelete(RyanJsonDetachByKey(json, "test"));
-	RyanJsonDelete(json);
-
-	json = RyanJsonParse(jsonstr);
-	jsonRoot = RyanJsonCreateObject();
-	RyanJsonAddBoolToObject(jsonRoot, "arrayItem", RyanJsonTrue);
-	int use = 0;
-	for (uint8_t i = 0; i < 10; i++)
-	{
-		dupItem = RyanJsonParse(jsonstr);
-		RyanJsonReplaceByKey(jsonRoot, "arrayItem", RyanJsonDuplicate(dupItem));
-		if (RyanJsonFalse == RyanJsonCompare(RyanJsonGetObjectToKey(jsonRoot, "arrayItem"), dupItem))
-		{
-			goto err;
-		}
-		RyanJsonReplaceByKey(json, "arrayItem", RyanJsonDuplicate(RyanJsonGetObjectByKey(dupItem, "item")));
-		if (RyanJsonFalse == RyanJsonCompare(RyanJsonGetObjectToKey(json, "arrayItem"), RyanJsonGetObjectByKey(dupItem, "item")))
-		{
-			goto err;
-		}
-		RyanJsonDelete(dupItem);
-
-		int newuse = 0;
-		v_mcheck(NULL, &newuse);
-		if (i != 0 && newuse != use)
-		{
-			printf("%s:%d 内存泄漏\r\n", __FILE__, __LINE__);
-			goto err;
-		}
-		use = newuse;
-	}
-
-	RyanJsonDelete(json);
-	RyanJsonDelete(jsonRoot);
-	return 0;
-
-err:
-	RyanJsonDelete(json);
-	RyanJsonDelete(jsonRoot);
-	return -1;
-}
-
-static int likeReferenceTest()
-{
-
-	// char *str = NULL;
-	// char jsonstr[] =
-	// "{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\",\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]}";
-	// RyanJson_t json = RyanJsonParse(jsonstr);
-	// RyanJson_t item = NULL;
-
-	// // RyanJson_t adfasdf = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "item"));
-
-	// // RyanJsonAddItemToObject(json, "test", adfasdf);
-
-	// // 这里做你想做的事,这里我选择打印出来
-	// // str = RyanJsonPrint(json, 50, RyanJsonTrue, NULL);
-	// // printf("item %s \r\n", str);
-	// // RyanJsonFree(str);
-
-	// for (int i = 0; i < 1; i++)
-	// {
-	//     // 分离test对象
-	//     item = RyanJsonDetachByKey(json, "item");
-
-	//     // if (RyanJsonIsKey(item))
-	//     //     RyanJsonFree(RyanJsonGetKey(item));
-
-	//     // RyanJsonFree(item);
-	// }
-
-	// RyanJsonAddItemToObject(json, "item", item);
-
-	// str = RyanJsonPrint(json, 50, RyanJsonTrue, NULL);
-	// printf("item %s \r\n", str);
-	// RyanJsonFree(str);
-
-	// RyanJsonDelete(json);
-
-	return 0;
-}
-
-static int forEachTest()
-{
-	char *str = NULL;
-	char jsonstr[] = "{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\","
-			 "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\","
-			 "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
-			 "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]}";
-
-	RyanJson_t json = RyanJsonParse(jsonstr);
-	RyanJson_t item = NULL;
-	printf("arrayDouble: ");
-	RyanJsonArrayForEach(RyanJsonGetObjectToKey(json, "arrayDouble"), item)
-	{
-		if (!RyanJsonIsDouble(item) || !compare_double(16.89, RyanJsonGetDoubleValue(item)))
-		{
-			goto err;
-		}
-	}
-
-	RyanJsonArrayForEach(RyanJsonGetObjectToKey(json, "arrayInt"), item)
-	{
-		if (!RyanJsonIsInt(item) || 16 != RyanJsonGetIntValue(item))
-		{
-			goto err;
-		}
-	}
-
-	uint32_t strLen;
-	RyanJsonObjectForEach(RyanJsonGetObjectToKey(json, "item"), item)
-	{
-		str = RyanJsonPrint(item, 50, RyanJsonTrue, &strLen);
-		printf("item { %s : %s }  %d\r\n", RyanJsonGetKey(item), str, strLen);
-		RyanJsonFree(str);
-	}
-
-	RyanJsonDelete(json);
-	return 0;
-
-err:
-	RyanJsonDelete(json);
-	return -1;
-}
-
-RyanJsonBool RyanJsonBaseTest(void)
-{
-	int result = 0;
-	RyanJsonInitHooks(v_malloc, v_free, v_realloc);
-
-	result = loadJsonTest(); // 从文本解析json测试
-	if (0 != result)
-	{
-		printf("%s:%d loadJsonTest fail\r\n", __FILE__, __LINE__);
-		return RyanJsonFalse;
-	}
-
-	result = createJsonTest(); // 生成json节点树测试
-	if (0 != result)
-	{
-		printf("%s:%d loadJsonTest fail\r\n", __FILE__, __LINE__);
-		return RyanJsonFalse;
-	}
-
-	result = changeJsonTest(); // 修改json节点测试,包含删除、分离
-	if (0 != result)
-	{
-		printf("%s:%d loadJsonTest fail\r\n", __FILE__, __LINE__);
-		return RyanJsonFalse;
-	}
-
-	result = compareJsonTest(); // 比较json节点树测试
-	if (0 != result)
-	{
-		printf("%s:%d loadJsonTest fail\r\n", __FILE__, __LINE__);
-		return RyanJsonFalse;
-	}
-
-	result = duplicateTest(); // 复制测试
-	if (0 != result)
-	{
-		printf("%s:%d loadJsonTest fail\r\n", __FILE__, __LINE__);
-		return RyanJsonFalse;
-	}
-
-	result = forEachTest();
-	if (0 != result)
-	{
-		printf("%s:%d loadJsonTest fail\r\n", __FILE__, __LINE__);
-		return RyanJsonFalse;
-	}
-
-	result = likeReferenceTest(); // 模仿 引用类型实现 示例
-	if (0 != result)
-	{
-		printf("%s:%d loadJsonTest fail\r\n", __FILE__, __LINE__);
-		return RyanJsonFalse;
-	}
-
-	displayMem();
-
-	return RyanJsonTrue;
-}

+ 164 - 85
test/RyanJsonMemoryFootprintTest.c

@@ -1,22 +1,12 @@
 #include "RyanJsonTest.h"
 
-static void *yy_malloc(void *ctx, size_t size)
-{
-	return v_malloc(size);
-}
-static void *yy_realloc(void *ctx, void *ptr, size_t old_size, size_t size)
-{
-	return v_realloc(ptr, size);
-}
-static void yy_free(void *ctx, void *ptr)
-{
-	v_free(ptr);
-}
-
-static yyjson_alc yyalc = {yy_malloc, yy_realloc, yy_free, NULL};
+static void *yy_malloc(void *ctx, size_t size) { return v_malloc(size); }
+static void *yy_realloc(void *ctx, void *ptr, size_t old_size, size_t size) { return v_realloc(ptr, size); }
+static void yy_free(void *ctx, void *ptr) { v_free(ptr); }
 
 static int RyanJsonMemoryFootprint(char *jsonstr)
 {
+	int32_t use = vallocGetUse();
 	RyanJsonInitHooks(v_malloc, v_free, v_realloc);
 
 	RyanJson_t json = RyanJsonParse(jsonstr);
@@ -26,8 +16,7 @@ static int RyanJsonMemoryFootprint(char *jsonstr)
 		return -1;
 	}
 
-	int area = 0, use = 0;
-	v_mcheck(&area, &use);
+	use = vallocGetUse() - use;
 
 	RyanJsonDelete(json);
 	return use;
@@ -35,6 +24,7 @@ static int RyanJsonMemoryFootprint(char *jsonstr)
 
 static int cJSONMemoryFootprint(char *jsonstr)
 {
+	int32_t use = vallocGetUse();
 	cJSON_Hooks hooks = {.malloc_fn = v_malloc, .free_fn = v_free};
 	cJSON_InitHooks(&hooks);
 
@@ -45,26 +35,29 @@ static int cJSONMemoryFootprint(char *jsonstr)
 		return -1;
 	}
 
-	int area = 0, use = 0;
-	v_mcheck(&area, &use);
-
+	use = vallocGetUse() - use;
 	cJSON_Delete(json);
 	return use;
 }
 
 static int yyjsonMemoryFootprint(char *jsonstr)
 {
+	// static yyjson_alc yyalc = {yy_malloc, yy_realloc, yy_free, NULL};
+	// // 先解析成只读文档(可用自定义分配器 yyalc)
+	// yyjson_doc *doc = yyjson_read_opts(jsonstr, strlen(jsonstr), YYJSON_READ_NOFLAG, &yyalc, NULL);
+	// if (doc == NULL) { return -1; }
 
-	yyjson_doc *doc = yyjson_read_opts(jsonstr, strlen(jsonstr), YYJSON_READ_NOFLAG, &yyalc, NULL);
-	if (NULL == doc)
-	{
-		return -1;
-	}
+	// // 从只读文档拷贝为可变文档(用于后续读写修改)
+	// yyjson_mut_doc *mdoc = yyjson_doc_mut_copy(doc, &yyalc);
+	// yyjson_doc_free(doc);
+	// if (mdoc == NULL) { return -1; }
 
+	// 统计当前分配器的占用
 	int area = 0, use = 0;
 	v_mcheck(&area, &use);
 
-	yyjson_doc_free(doc);
+	// // 用完释放可变文档
+	// yyjson_mut_doc_free(mdoc);
 	return use;
 }
 
@@ -76,78 +69,163 @@ static void printfJsonCompera(char *jsonstr)
 	RyanJsonCount = RyanJsonMemoryFootprint(jsonstr);
 	cJSONCount = cJSONMemoryFootprint(jsonstr);
 	yyjsonCount = yyjsonMemoryFootprint(jsonstr);
-	printf("json原始文本长度为 %ld, 序列化后RyanJson内存占用: %d, cJSON内存占用: %d, yyjson内存占用: %d\r\n", strlen(jsonstr), RyanJsonCount, cJSONCount, yyjsonCount);
+	printf("json原始文本长度为 %ld, 序列化后RyanJson内存占用: %d, cJSON内存占用: %d, yyjson内存占用: %d\r\n", strlen(jsonstr),
+	       RyanJsonCount, cJSONCount, yyjsonCount);
+
+	double save_vs_cjson = 100.0 - ((double)RyanJsonCount * 100.0) / (double)cJSONCount;
+	double save_vs_yyjson = 100.0 - ((double)RyanJsonCount * 100.0) / (double)yyjsonCount;
 
-	printf("比cJSON节省: %d%% 内存占用, 比yyjson节省: %d%% 内存占用\r\n", 100 - RyanJsonCount * 100 / cJSONCount, 100 - RyanJsonCount * 100 / yyjsonCount);
+	printf("比cJSON节省: %.2f%% 内存占用, 比yyjson节省: %.2f%% 内存占用\r\n", save_vs_cjson, save_vs_yyjson);
 }
 
-RyanJsonBool RyanJsonMemoryFootprintTest(void)
+RyanJsonBool_e RyanJsonMemoryFootprintTest(void)
 {
 	char *jsonstr;
 
 	printf("\r\n--------------------------- 混合类型json数据测试 --------------------------\r\n");
-	jsonstr = "{\"item1\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\","
-		  "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\",\"hello\","
-		  "\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,"
-		  "\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]},\"item2\":{\"inter\":16,\"double\":16.89,\"string\":"
-		  "\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null},"
-		  "\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\",\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\","
-		  "true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":"
-		  "\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]},\"item3\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,"
-		  "\"item\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,"
-		  "16.89,16.89],\"arrayString\":[\"hello\",\"hello\",\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,"
-		  "\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]}"
-		  ",\"item4\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\","
-		  "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\",\"hello\","
-		  "\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,"
-		  "\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]}}";
+	jsonstr = "{\"item1\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,"
+		  "\"item\":{\"inter\":16,"
+		  "\"double\":16.89,\"string\":\"hello\","
+		  "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,"
+		  "16.89,16.89],"
+		  "\"arrayString\":[\"hello\",\"hello\",\"hello\","
+		  "\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,"
+		  "\"string\":\"hello\","
+		  "\"boolTrue\":true,\"boolFalse\":false,"
+		  "\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]"
+		  "},\"item2\":{"
+		  "\"inter\":16,\"double\":16.89,\"string\":"
+		  "\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":{\"inter\":16,\"double\":16.89,\"string\":"
+		  "\"hello\",\"boolTrue\":"
+		  "true,\"boolFalse\":false,\"null\":null},"
+		  "\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\","
+		  "\"hello\",\"hello\","
+		  "\"hello\"],\"array\":[16,16.89,\"hello\","
+		  "true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":"
+		  "false,\"null\":null},{"
+		  "\"inter\":16,\"double\":16.89,\"string\":"
+		  "\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]},\"item3\":{\"inter\":16,\"double\":16.89,\"string\":"
+		  "\"hello\",\"boolTrue\":"
+		  "true,\"boolFalse\":false,\"null\":null,"
+		  "\"item\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null},"
+		  "\"arrayInt\":[16,16,16,16,"
+		  "16],\"arrayDouble\":[16.89,16.89,16.89,"
+		  "16.89,16.89],\"arrayString\":[\"hello\",\"hello\",\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,"
+		  "false,null],"
+		  "\"arrayItem\":[{\"inter\":16,\"double\":16.89,"
+		  "\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":"
+		  "\"hello\",\"boolTrue\":"
+		  "true,\"boolFalse\":false,\"null\":null}]}"
+		  ",\"item4\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,"
+		  "\"item\":{\"inter\":16,"
+		  "\"double\":16.89,\"string\":\"hello\","
+		  "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,"
+		  "16.89,16.89],"
+		  "\"arrayString\":[\"hello\",\"hello\",\"hello\","
+		  "\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,"
+		  "\"string\":\"hello\","
+		  "\"boolTrue\":true,\"boolFalse\":false,"
+		  "\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]"
+		  "}}";
 	printfJsonCompera(jsonstr);
 
 	printf("\r\n--------------------------- 对象占多json数据测试 --------------------------\r\n");
-	jsonstr = "{\"message\":\"success感谢又拍云(upyun.com)提供CDN赞助\",\"status\":200,\"date\":\"20230822\",\"time\":\"2023-08-22 "
-		  "09:44:54\",\"cityInfo\":{\"city\":\"郑州市\",\"citykey\":\"101180101\",\"parent\":\"河南\",\"updateTime\":\"07:46\"},\"data\":{\"shidu\":\"85%\",\"pm25\":20,\"pm10\":56,"
-		  "\"quality\":\"良\",\"wendu\":\"29\",\"ganmao\":\"极少数敏感人群应减少户外活动\",\"forecast\":[{\"date\":\"22\",\"high\":\"高温 35℃\",\"low\":\"低温 "
-		  "23℃\",\"ymd\":\"2023-08-22\",\"week\":\"星期二\",\"sunrise\":\"05:51\",\"sunset\":\"19:05\",\"aqi\":78,\"fx\":\"东南风\",\"fl\":\"2级\",\"type\":\"晴\",\"notice\":"
-		  "\"愿你拥有比阳光明媚的心情\"},{\"date\":\"23\",\"high\":\"高温 33℃\",\"low\":\"低温 "
-		  "23℃\",\"ymd\":\"2023-08-23\",\"week\":\"星期三\",\"sunrise\":\"05:52\",\"sunset\":\"19:04\",\"aqi\":71,\"fx\":\"南风\",\"fl\":\"2级\",\"type\":\"中雨\",\"notice\":"
-		  "\"记得随身携带雨伞哦\"},{\"date\":\"24\",\"high\":\"高温 31℃\",\"low\":\"低温 "
-		  "21℃\",\"ymd\":\"2023-08-24\",\"week\":\"星期四\",\"sunrise\":\"05:52\",\"sunset\":\"19:03\",\"aqi\":74,\"fx\":\"东风\",\"fl\":\"2级\",\"type\":\"晴\",\"notice\":"
-		  "\"愿你拥有比阳光明媚的心情\"},{\"date\":\"25\",\"high\":\"高温 30℃\",\"low\":\"低温 "
-		  "23℃\",\"ymd\":\"2023-08-25\",\"week\":\"星期五\",\"sunrise\":\"05:53\",\"sunset\":\"19:02\",\"aqi\":93,\"fx\":\"东风\",\"fl\":\"1级\",\"type\":\"小雨\",\"notice\":"
-		  "\"雨虽小,注意保暖别感冒\"},{\"date\":\"26\",\"high\":\"高温 25℃\",\"low\":\"低温 "
-		  "22℃\",\"ymd\":\"2023-08-26\",\"week\":\"星期六\",\"sunrise\":\"05:54\",\"sunset\":\"19:00\",\"aqi\":80,\"fx\":\"东北风\",\"fl\":\"1级\",\"type\":\"阴\",\"notice\":"
-		  "\"不要被阴云遮挡住好心情\"},{\"date\":\"27\",\"high\":\"高温 27℃\",\"low\":\"低温 "
-		  "20℃\",\"ymd\":\"2023-08-27\",\"week\":\"星期日\",\"sunrise\":\"05:55\",\"sunset\":\"18:59\",\"aqi\":74,\"fx\":\"西北风\",\"fl\":\"1级\",\"type\":\"阴\",\"notice\":"
-		  "\"不要被阴云遮挡住好心情\"},{\"date\":\"28\",\"high\":\"高温 30℃\",\"low\":\"低温 20℃\",\"ymd\":\"2023-08-28\",\"week\":\"星期 "
-		  "一\",\"sunrise\":\"05:55\",\"sunset\":\"18:58\",\"aqi\":80,\"fx\":\"东北风\",\"fl\":\"2级\",\"type\":\"多云\",\"notice\":\"阴晴之间,谨防紫外线侵扰\"},{\"date\":\"29\",\"high\":"
-		  "\"高温 30℃\",\"low\":\"低温 "
-		  "20℃\",\"ymd\":\"2023-08-29\",\"week\":\"星期二\",\"sunrise\":\"05:56\",\"sunset\":\"18:56\",\"aqi\":80,\"fx\":\"东北风\",\"fl\":\"2级\",\"type\":\"多云\",\"notice\":"
-		  "\"阴晴之间,谨防紫外线侵扰\"},{\"date\":\"30\",\"high\":\"高温 31℃\",\"low\":\"低温 "
-		  "20℃\",\"ymd\":\"2023-08-30\",\"week\":\"星期三\",\"sunrise\":\"05:57\",\"sunset\":\"18:55\",\"aqi\":92,\"fx\":\"南风\",\"fl\":\"1级\",\"type\":\"晴\",\"notice\":"
-		  "\"愿你拥有比阳光明媚的心情\"},{\"date\":\"31\",\"high\":\"高温 33℃\",\"low\":\" 低温 "
-		  "22℃\",\"ymd\":\"2023-08-31\",\"week\":\"星期四\",\"sunrise\":\"05:57\",\"sunset\":\"18:54\",\"aqi\":91,\"fx\":\"南风\",\"fl\":\"1级\",\"type\":\"晴\",\"notice\":"
-		  "\"愿你拥有比阳光明媚的心情\"},{\"date\":\"01\",\"high\":\"高温 34℃\",\"low\":\"低温 "
-		  "23℃\",\"ymd\":\"2023-09-01\",\"week\":\"星期五\",\"sunrise\":\"05:58\",\"sunset\":\"18:52\",\"aqi\":91,\"fx\":\"西风\",\"fl\":\"1级\",\"type\":\"晴\",\"notice\":"
-		  "\"愿你拥有比阳光明媚的心情\"},{\"date\":\"02\",\"high\":\"高温 36℃\",\"low\":\"低温 "
-		  "25℃\",\"ymd\":\"2023-09-02\",\"week\":\"星期六\",\"sunrise\":\"05:59\",\"sunset\":\"18:51\",\"aqi\":78,\"fx\":\"南风\",\"fl\":\"1级\",\"type\":\"阴\",\"notice\":"
-		  "\"不要被阴云遮挡住好心情\"},{\"date\":\"03\",\"high\":\"高温 35℃\",\"low\":\"低温 "
-		  "24℃\",\"ymd\":\"2023-09-03\",\"week\":\"星期日\",\"sunrise\":\"06:00\",\"sunset\":\"18:50\",\"aqi\":82,\"fx\":\"东北风\",\"fl\":\"1级\",\"type\":\"晴\",\"notice\":"
-		  "\"愿你拥有比阳光明媚的心情\"},{\"date\":\"04\",\"high\":\"高温 35℃\",\"low\":\"低温 "
-		  "25℃\",\"ymd\":\"2023-09-04\",\"week\":\"星期一\",\"sunrise\":\"06:00\",\"sunset\":\"18:48\",\"aqi\":88,\"fx\":\"南风\",\"fl\":\"2级\",\"type\":\"晴\",\"notice\":"
-		  "\"愿你拥有比阳光明媚的心情\"},{\"date\":\"05\",\"high\":\"高温 35℃\",\"low\":\"低温 "
-		  "25℃\",\"ymd\":\"2023-09-05\",\"week\":\"星期二\",\"sunrise\":\"06:01\",\"sunset\":\"18:47\",\"aqi\":58,\"fx\":\"南风\",\"fl\":\"2级\",\"type\":\"阴\",\"notice\":"
-		  "\"不要被阴云遮挡住好心情\"}],\"yesterday\":{\"date\":\"21\",\"high\":\"高温 34℃\",\"low\":\"低温 24℃\",\"ymd\":\"2023-08-21\",\"week\":\" "
-		  "星期一\",\"sunrise\":\"05:50\",\"sunset\":\"19:07\",\"aqi\":60,\"fx\":\"西风\",\"fl\":\"2级\",\"type\":\"小雨\",\"notice\":\"雨虽小,注意保暖别感冒\"}}}";
+	jsonstr =
+		"{\"message\":\"success感谢又拍云(upyun.com)提供CDN赞助\",\"status\":200,\"date\":\"20230822\",\"time\":\"2023-08-22 "
+		"09:44:54\",\"cityInfo\":{\"city\":\"郑州市\",\"citykey\":\"101180101\",\"parent\":\"河南\",\"updateTime\":\"07:46\"},"
+		"\"data\":{\"shidu\":"
+		"\"85%\",\"pm25\":20,\"pm10\":56,"
+		"\"quality\":\"良\",\"wendu\":\"29\",\"ganmao\":\"极少数敏感人群应减少户外活动\",\"forecast\":[{\"date\":\"22\",\"high\":"
+		"\"高温 "
+		"35℃\",\"low\":\"低温 "
+		"23℃\",\"ymd\":\"2023-08-22\",\"week\":\"星期二\",\"sunrise\":\"05:51\",\"sunset\":\"19:05\",\"aqi\":78,\"fx\":\"东南风\","
+		"\"fl\":\"2级\","
+		"\"type\":\"晴\",\"notice\":"
+		"\"愿你拥有比阳光明媚的心情\"},{\"date\":\"23\",\"high\":\"高温 33℃\",\"low\":\"低温 "
+		"23℃\",\"ymd\":\"2023-08-23\",\"week\":\"星期三\",\"sunrise\":\"05:52\",\"sunset\":\"19:04\",\"aqi\":71,\"fx\":\"南风\","
+		"\"fl\":\"2级\","
+		"\"type\":\"中雨\",\"notice\":"
+		"\"记得随身携带雨伞哦\"},{\"date\":\"24\",\"high\":\"高温 31℃\",\"low\":\"低温 "
+		"21℃\",\"ymd\":\"2023-08-24\",\"week\":\"星期四\",\"sunrise\":\"05:52\",\"sunset\":\"19:03\",\"aqi\":74,\"fx\":\"东风\","
+		"\"fl\":\"2级\","
+		"\"type\":\"晴\",\"notice\":"
+		"\"愿你拥有比阳光明媚的心情\"},{\"date\":\"25\",\"high\":\"高温 30℃\",\"low\":\"低温 "
+		"23℃\",\"ymd\":\"2023-08-25\",\"week\":\"星期五\",\"sunrise\":\"05:53\",\"sunset\":\"19:02\",\"aqi\":93,\"fx\":\"东风\","
+		"\"fl\":\"1级\","
+		"\"type\":\"小雨\",\"notice\":"
+		"\"雨虽小,注意保暖别感冒\"},{\"date\":\"26\",\"high\":\"高温 25℃\",\"low\":\"低温 "
+		"22℃\",\"ymd\":\"2023-08-26\",\"week\":\"星期六\",\"sunrise\":\"05:54\",\"sunset\":\"19:00\",\"aqi\":80,\"fx\":\"东北风\","
+		"\"fl\":\"1级\","
+		"\"type\":\"阴\",\"notice\":"
+		"\"不要被阴云遮挡住好心情\"},{\"date\":\"27\",\"high\":\"高温 27℃\",\"low\":\"低温 "
+		"20℃\",\"ymd\":\"2023-08-27\",\"week\":\"星期日\",\"sunrise\":\"05:55\",\"sunset\":\"18:59\",\"aqi\":74,\"fx\":\"西北风\","
+		"\"fl\":\"1级\","
+		"\"type\":\"阴\",\"notice\":"
+		"\"不要被阴云遮挡住好心情\"},{\"date\":\"28\",\"high\":\"高温 30℃\",\"low\":\"低温 "
+		"20℃\",\"ymd\":\"2023-08-28\",\"week\":\"星期 "
+		"一\",\"sunrise\":\"05:55\",\"sunset\":\"18:58\",\"aqi\":80,\"fx\":\"东北风\",\"fl\":\"2级\",\"type\":\"多云\",\"notice\":"
+		"\"阴晴之间,谨防紫外线侵扰\"},{\"date\":\"29\",\"high\":"
+		"\"高温 30℃\",\"low\":\"低温 "
+		"20℃\",\"ymd\":\"2023-08-29\",\"week\":\"星期二\",\"sunrise\":\"05:56\",\"sunset\":\"18:56\",\"aqi\":80,\"fx\":\"东北风\","
+		"\"fl\":\"2级\","
+		"\"type\":\"多云\",\"notice\":"
+		"\"阴晴之间,谨防紫外线侵扰\"},{\"date\":\"30\",\"high\":\"高温 31℃\",\"low\":\"低温 "
+		"20℃\",\"ymd\":\"2023-08-30\",\"week\":\"星期三\",\"sunrise\":\"05:57\",\"sunset\":\"18:55\",\"aqi\":92,\"fx\":\"南风\","
+		"\"fl\":\"1级\","
+		"\"type\":\"晴\",\"notice\":"
+		"\"愿你拥有比阳光明媚的心情\"},{\"date\":\"31\",\"high\":\"高温 33℃\",\"low\":\" 低温 "
+		"22℃\",\"ymd\":\"2023-08-31\",\"week\":\"星期四\",\"sunrise\":\"05:57\",\"sunset\":\"18:54\",\"aqi\":91,\"fx\":\"南风\","
+		"\"fl\":\"1级\","
+		"\"type\":\"晴\",\"notice\":"
+		"\"愿你拥有比阳光明媚的心情\"},{\"date\":\"01\",\"high\":\"高温 34℃\",\"low\":\"低温 "
+		"23℃\",\"ymd\":\"2023-09-01\",\"week\":\"星期五\",\"sunrise\":\"05:58\",\"sunset\":\"18:52\",\"aqi\":91,\"fx\":\"西风\","
+		"\"fl\":\"1级\","
+		"\"type\":\"晴\",\"notice\":"
+		"\"愿你拥有比阳光明媚的心情\"},{\"date\":\"02\",\"high\":\"高温 36℃\",\"low\":\"低温 "
+		"25℃\",\"ymd\":\"2023-09-02\",\"week\":\"星期六\",\"sunrise\":\"05:59\",\"sunset\":\"18:51\",\"aqi\":78,\"fx\":\"南风\","
+		"\"fl\":\"1级\","
+		"\"type\":\"阴\",\"notice\":"
+		"\"不要被阴云遮挡住好心情\"},{\"date\":\"03\",\"high\":\"高温 35℃\",\"low\":\"低温 "
+		"24℃\",\"ymd\":\"2023-09-03\",\"week\":\"星期日\",\"sunrise\":\"06:00\",\"sunset\":\"18:50\",\"aqi\":82,\"fx\":\"东北风\","
+		"\"fl\":\"1级\","
+		"\"type\":\"晴\",\"notice\":"
+		"\"愿你拥有比阳光明媚的心情\"},{\"date\":\"04\",\"high\":\"高温 35℃\",\"low\":\"低温 "
+		"25℃\",\"ymd\":\"2023-09-04\",\"week\":\"星期一\",\"sunrise\":\"06:00\",\"sunset\":\"18:48\",\"aqi\":88,\"fx\":\"南风\","
+		"\"fl\":\"2级\","
+		"\"type\":\"晴\",\"notice\":"
+		"\"愿你拥有比阳光明媚的心情\"},{\"date\":\"05\",\"high\":\"高温 35℃\",\"low\":\"低温 "
+		"25℃\",\"ymd\":\"2023-09-05\",\"week\":\"星期二\",\"sunrise\":\"06:01\",\"sunset\":\"18:47\",\"aqi\":58,\"fx\":\"南风\","
+		"\"fl\":\"2级\","
+		"\"type\":\"阴\",\"notice\":"
+		"\"不要被阴云遮挡住好心情\"}],\"yesterday\":{\"date\":\"21\",\"high\":\"高温 34℃\",\"low\":\"低温 "
+		"24℃\",\"ymd\":\"2023-08-21\",\"week\":\" "
+		"星期一\",\"sunrise\":\"05:50\",\"sunset\":\"19:07\",\"aqi\":60,\"fx\":\"西风\",\"fl\":\"2级\",\"type\":\"小雨\","
+		"\"notice\":"
+		"\"雨虽小,注意保暖别感冒\"}}}";
 	printfJsonCompera(jsonstr);
 
 	printf("\r\n--------------------------- 数组占多json数据测试 --------------------------\r\n");
-	jsonstr = "{\"item1\":{\"arrayInt\":[16,16,16,16,16,16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89,16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\","
-		  "\"hello\",\"hello\",\"hello\",\"hello\",\"hello\",\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null,16,16.89,\"hello\",true,false,null]},\"item2\":{"
-		  "\"arrayInt\":[16,16,16,16,16,16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89,16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\",\"hello\",\"hello\","
-		  "\"hello\",\"hello\",\"hello\",\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null,16,16.89,\"hello\",true,false,null]},\"item3\":{\"arrayInt\":[16,16,16,"
-		  "16,16,16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89,16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\",\"hello\",\"hello\",\"hello\",\"hello\","
-		  "\"hello\",\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null,16,16.89,\"hello\",true,false,null]},\"item4\":{\"arrayInt\":[16,16,16,16,16,16,16,16,16,16],"
-		  "\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89,16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\",\"hello\",\"hello\",\"hello\",\"hello\",\"hello\",\"hello\","
+	jsonstr = "{\"item1\":{\"arrayInt\":[16,16,16,16,16,16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89,16.89,16.89,16."
+		  "89,16.89,16.89],"
+		  "\"arrayString\":[\"hello\",\"hello\","
+		  "\"hello\",\"hello\",\"hello\",\"hello\",\"hello\",\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,"
+		  "false,null,16,16.89,"
+		  "\"hello\",true,false,null]},\"item2\":{"
+		  "\"arrayInt\":[16,16,16,16,16,16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89,16.89,16.89,16.89,16.89,16."
+		  "89],\"arrayString\":["
+		  "\"hello\",\"hello\",\"hello\",\"hello\","
+		  "\"hello\",\"hello\",\"hello\",\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null,16,16.89,"
+		  "\"hello\",true,false,"
+		  "null]},\"item3\":{\"arrayInt\":[16,16,16,"
+		  "16,16,16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89,16.89,16.89,16.89,16.89,16.89],\"arrayString\":["
+		  "\"hello\",\"hello\","
+		  "\"hello\",\"hello\",\"hello\",\"hello\","
+		  "\"hello\",\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null,16,16.89,\"hello\",true,false,"
+		  "null]},\"item4\":{"
+		  "\"arrayInt\":[16,16,16,16,16,16,16,16,16,16],"
+		  "\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89,16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\","
+		  "\"hello\",\"hello\","
+		  "\"hello\",\"hello\",\"hello\",\"hello\","
 		  "\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null,16,16.89,\"hello\",true,false,null]}}";
 	printfJsonCompera(jsonstr);
 
@@ -156,7 +234,8 @@ RyanJsonBool RyanJsonMemoryFootprintTest(void)
 	printfJsonCompera(jsonstr);
 
 	printf("\r\n--------------------------- 小对象json 纯字符串内存占用测试 --------------------------\r\n");
-	jsonstr = "{\"inter\":\"16\",\"double\":\"16.89\",\"string\":\"hello\",\"boolTrue\":\"true\",\"boolFalse\":\"false\",\"null\":\"null\"}";
+	jsonstr = "{\"inter\":\"16\",\"double\":\"16.89\",\"string\":\"hello\",\"boolTrue\":\"true\",\"boolFalse\":\"false\",\"null\":"
+		  "\"null\"}";
 	printfJsonCompera(jsonstr);
 
 	/**

+ 613 - 0
test/RyanJsonRFC8259JsonTest.c

@@ -0,0 +1,613 @@
+#include "RyanJsonTest.h"
+
+#define PrintfStrCmpEnable
+
+typedef int (*jsonParseData)(char *fileName, char *data, uint32_t len);
+
+// static void *yy_malloc(void *ctx, size_t size) { return v_malloc(size); }
+// static void *yy_realloc(void *ctx, void *ptr, size_t old_size, size_t size) { return v_realloc(ptr, size); }
+// static void yy_free(void *ctx, void *ptr) { v_free(ptr); }
+
+// static yyjson_alc yyalc = {yy_malloc, yy_realloc, yy_free, NULL};
+
+/* Read a file, parse, render back, etc. */
+static int testFile(const char *path, jsonParseData jsonParseDataHandle)
+{
+
+	DIR *dir = NULL;
+	struct dirent *entry;
+
+	int path_len = strlen(path);
+	int count = 0;
+	int used_count = 0;
+	if (!path || !path_len || !(dir = opendir(path))) { goto fail; }
+
+	while ((entry = readdir(dir)))
+	{
+
+		char *name = (char *)entry->d_name;
+
+		if (!name || !strlen(name)) { continue; }
+
+		if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { continue; }
+
+		char aaa[300] = {0};
+		snprintf(aaa, sizeof(aaa), "%s/%s", path, name);
+
+		FILE *f = fopen(aaa, "rb");
+		if (f == NULL) { goto fail; }
+
+		fseek(f, 0, SEEK_END);
+		long len = ftell(f);
+		fseek(f, 0, SEEK_SET);
+		char *data = (char *)malloc(len + 10);
+		fread(data, 1, len, f);
+		data[len] = '\0';
+		fclose(f);
+		int status = 0;
+
+		int startUse = vallocGetUse();
+		status = jsonParseDataHandle(name, data, len);
+
+		used_count++;
+		if (0 == strncmp("y_", name, 2))
+		{
+			if (0 == status) { count++; }
+			else
+			{
+				printf("应该成功,但是失败: %s, len: %ld\n", data, len);
+			}
+		}
+		else if (0 == strncmp("n_", name, 2))
+		{
+			if (0 != status) { count++; }
+			else
+			{
+				printf("应该失败,但是成功: %s, len: %ld\n", data, len);
+			}
+		}
+		else if (0 == strncmp("i_", name, 2)) { count++; }
+
+		if (startUse != vallocGetUse())
+		{
+			int area = 0, use = 0;
+			v_mcheck(&area, &use);
+			free(data);
+			printf("内存泄漏 %s len: %ld\r\n", data, len);
+			// printf("内存泄漏 %x len: %ld\r\n", (unsigned int)data, len);
+			// printf("内存泄漏 %c len: %ld\r\n", (int)data, len);
+			printf("|||----------->>> area = %d, size = %d\r\n", area, use);
+			break;
+		}
+
+		// if (use != (len + 10))
+		// {
+		// 	int area = 0, use = 0;
+		// 	v_mcheck(&area, &use);
+		// 	free(data);
+		// 	printf("内存泄漏 %s len: %ld\r\n", data, len);
+		// 	// printf("内存泄漏 %x len: %ld\r\n", (unsigned int)data, len);
+		// 	// printf("内存泄漏 %c len: %ld\r\n", (int)data, len);
+		// 	printf("|||----------->>> area = %d, size = %d\r\n", area, use);
+		// 	break;
+		// }
+		free(data);
+	}
+
+	closedir(dir);
+
+	printf("RFC 8259 JSON: (%d/%d)\r\n", count, used_count);
+	return 0;
+
+fail:
+	if (dir) { closedir(dir); }
+
+	return -1;
+}
+
+typedef struct
+{
+	const char *p;
+	size_t len;
+} Slice;
+
+static int hexval(int c)
+{
+	if (c >= '0' && c <= '9') { return c - '0'; }
+	c = (c >= 'a' && c <= 'f') ? (c - 'a' + 'A') : c;
+	if (c >= 'A' && c <= 'F') { return c - 'A' + 10; }
+	return -1;
+}
+
+static int decode_u4(const char *s, uint16_t *out)
+{
+	int h0 = hexval(s[0]), h1 = hexval(s[1]), h2 = hexval(s[2]), h3 = hexval(s[3]);
+	if (h0 < 0 || h1 < 0 || h2 < 0 || h3 < 0) { return 0; }
+	*out = (uint16_t)((h0 << 12) | (h1 << 8) | (h2 << 4) | h3);
+	return 1;
+}
+
+// 将 JSON 字符串(不含两端引号)规范化为 UTF-8 字节序列
+static int normalize_json_string(const char *in, size_t in_len, unsigned char **out, size_t *out_len)
+{
+	// 预留足够缓冲
+	size_t cap = in_len * 4 + 8;
+	unsigned char *buf = (unsigned char *)malloc(cap);
+	if (!buf) { return 0; }
+	size_t pos = 0;
+
+	for (size_t i = 0; i < in_len; i++)
+	{
+		unsigned char ch = (unsigned char)in[i];
+
+		if (ch == '\\')
+		{
+			if (i + 1 >= in_len)
+			{
+				free(buf);
+				return 0;
+			}
+			unsigned char esc = (unsigned char)in[++i];
+			switch (esc)
+			{
+			case '\"': buf[pos++] = '\"'; break;
+			case '\\': buf[pos++] = '\\'; break;
+			case '/': buf[pos++] = '/'; break;
+			case 'b': buf[pos++] = '\b'; break;
+			case 'f': buf[pos++] = '\f'; break;
+			case 'n': buf[pos++] = '\n'; break;
+			case 'r': buf[pos++] = '\r'; break;
+			case 't': buf[pos++] = '\t'; break;
+			case 'u': {
+				if (i + 4 >= in_len)
+				{
+					free(buf);
+					return 0;
+				}
+				uint16_t u1;
+				if (!decode_u4(&in[i + 1], &u1))
+				{
+					free(buf);
+					return 0;
+				}
+				i += 4;
+
+				if (u1 >= 0xD800 && u1 <= 0xDBFF)
+				{
+					// 高代理,必须跟 \uXXXX 低代理
+					if (i + 2 >= in_len || in[i + 1] != '\\' || in[i + 2] != 'u' || i + 6 >= in_len)
+					{
+						free(buf);
+						return 0;
+					}
+					i += 2;
+					uint16_t u2;
+					if (!decode_u4(&in[i + 1], &u2))
+					{
+						free(buf);
+						return 0;
+					}
+					i += 4;
+					if (!(u2 >= 0xDC00 && u2 <= 0xDFFF))
+					{
+						free(buf);
+						return 0;
+					}
+					// 组合码点
+					uint32_t cp = 0x10000 + (((uint32_t)(u1 - 0xD800) << 10) | (uint32_t)(u2 - 0xDC00));
+					// 编码为 UTF-8
+					buf[pos++] = (unsigned char)(0xF0 | ((cp >> 18) & 0x07));
+					buf[pos++] = (unsigned char)(0x80 | ((cp >> 12) & 0x3F));
+					buf[pos++] = (unsigned char)(0x80 | ((cp >> 6) & 0x3F));
+					buf[pos++] = (unsigned char)(0x80 | (cp & 0x3F));
+				}
+				else if (u1 >= 0xDC00 && u1 <= 0xDFFF)
+				{
+					// 单独低代理非法
+					free(buf);
+					return 0;
+				}
+				else
+				{
+					// BMP 码点 → UTF-8
+					if (u1 <= 0x007F) { buf[pos++] = (unsigned char)u1; }
+					else if (u1 <= 0x07FF)
+					{
+						buf[pos++] = (unsigned char)(0xC0 | ((u1 >> 6) & 0x1F));
+						buf[pos++] = (unsigned char)(0x80 | (u1 & 0x3F));
+					}
+					else
+					{
+						buf[pos++] = (unsigned char)(0xE0 | ((u1 >> 12) & 0x0F));
+						buf[pos++] = (unsigned char)(0x80 | ((u1 >> 6) & 0x3F));
+						buf[pos++] = (unsigned char)(0x80 | (u1 & 0x3F));
+					}
+				}
+				break;
+			}
+			default:
+				// 非法转义
+				free(buf);
+				return 0;
+			}
+		}
+		else
+		{
+			// 原始字节:直接拷贝(假设输入整体是合法 UTF-8)
+			buf[pos++] = ch;
+		}
+
+		if (pos + 8 > cap)
+		{
+			cap *= 2;
+			unsigned char *nb = (unsigned char *)realloc(buf, cap);
+			if (!nb)
+			{
+				free(buf);
+				return 0;
+			}
+			buf = nb;
+		}
+	}
+
+	*out = buf;
+	*out_len = pos;
+	return 1;
+}
+
+// 比较:规范化两侧为 UTF-8 字节序列,再 memcmp
+static int json_string_equal_semantic(const char *a, size_t a_len, const char *b, size_t b_len)
+{
+	unsigned char *na = NULL, *nb = NULL;
+	size_t nla = 0, nlb = 0;
+
+	if (!normalize_json_string(a, a_len, &na, &nla)) { return 0; }
+	if (!normalize_json_string(b, b_len, &nb, &nlb))
+	{
+		free(na);
+		return 0;
+	}
+
+	int eq = (nla == nlb) && (memcmp(na, nb, nla) == 0);
+	free(na);
+	free(nb);
+	return eq;
+}
+#include <ctype.h>
+/* 去空白 */
+static void trim(const char **s, size_t *len)
+{
+	const char *p = *s;
+	size_t n = *len;
+	while (n && isspace((unsigned char)*p))
+	{
+		p++;
+		n--;
+	}
+	while (n && isspace((unsigned char)p[n - 1])) { n--; }
+	*s = p;
+	*len = n;
+}
+
+/* 是否是带双引号的字符串值 */
+static int is_quoted_string(const char *s, size_t len) { return len >= 2 && s[0] == '\"' && s[len - 1] == '\"'; }
+
+/* 值级语义比较:字符串(去引号并 normalize)、数字(含科学计数法)、布尔、null */
+static int json_scalar_equal(const char *a, size_t a_len, const char *b, size_t b_len)
+{
+	trim(&a, &a_len);
+	trim(&b, &b_len);
+
+	/* 字符串:去掉引号后做转义规范化再比较字节 */
+	if (is_quoted_string(a, a_len) && is_quoted_string(b, b_len))
+	{
+		const char *as = a + 1;
+		size_t al = a_len - 2;
+		const char *bs = b + 1;
+		size_t bl = b_len - 2;
+
+		unsigned char *na = NULL, *nb = NULL;
+		size_t nla = 0, nlb = 0;
+		if (!normalize_json_string(as, al, &na, &nla)) { return 0; }
+		if (!normalize_json_string(bs, bl, &nb, &nlb))
+		{
+			free(na);
+			return 0;
+		}
+
+		int eq = (nla == nlb) && (memcmp(na, nb, nla) == 0);
+		free(na);
+		free(nb);
+		return eq;
+	}
+
+	/* 布尔 / null */
+	if (a_len == 4 && strncmp(a, "true", 4) == 0 && b_len == 4 && strncmp(b, "true", 4) == 0) { return 1; }
+	if (a_len == 5 && strncmp(a, "false", 5) == 0 && b_len == 5 && strncmp(b, "false", 5) == 0) { return 1; }
+	if (a_len == 4 && strncmp(a, "null", 4) == 0 && b_len == 4 && strncmp(b, "null", 4) == 0) { return 1; }
+
+	/* 数字:用 strtod 支持科学计数法,最后一字节必须到达字符串末尾(避免部分解析) */
+	{
+		char *endA = NULL, *endB = NULL;
+
+		/* 拷贝到以 NUL 结尾的缓冲,避免 strtod 依赖外部长度 */
+		char *bufA = (char *)malloc(a_len + 1);
+		char *bufB = (char *)malloc(b_len + 1);
+		if (!bufA || !bufB)
+		{
+			free(bufA);
+			free(bufB);
+			return 0;
+		}
+
+		memcpy(bufA, a, a_len);
+		bufA[a_len] = '\0';
+		memcpy(bufB, b, b_len);
+		bufB[b_len] = '\0';
+
+		double va = strtod(bufA, &endA);
+		double vb = strtod(bufB, &endB);
+
+		int okA = (endA && *endA == '\0');
+		int okB = (endB && *endB == '\0');
+
+		free(bufA);
+		free(bufB);
+
+		if (okA && okB)
+		{
+			/* 直接相等(包含 -0 与 0)或允许极小误差 */
+			if (va == vb) { return 1; }
+			if (fabs(va - vb) < 1e-15) { return 1; }
+			return 0;
+		}
+	}
+
+	/* 其余作为纯文本兜底比较 */
+	return (a_len == b_len) && (memcmp(a, b, a_len) == 0);
+}
+
+/* 提取一元素数组的唯一元素;若不是一元素数组返回 0 */
+static int extract_single_array_element(const char *s, size_t len, const char **elem, size_t *elem_len)
+{
+	trim(&s, &len);
+	if (len < 2 || s[0] != '[' || s[len - 1] != ']') { return 0; }
+
+	const char *p = s + 1;
+	size_t n = len - 2;
+
+	/* 去前后空白 */
+	trim(&p, &n);
+	if (n == 0) { return 0; /* 空数组 */ }
+
+	/* 扫描逗号,确保只有一个元素(字符串中的逗号不算) */
+	int in_str = 0;
+	int escape = 0;
+	for (size_t i = 0; i < n; i++)
+	{
+		char c = p[i];
+		if (in_str)
+		{
+			if (escape) { escape = 0; }
+			else if (c == '\\') { escape = 1; }
+			else if (c == '\"') { in_str = 0; }
+		}
+		else
+		{
+			if (c == '\"') { in_str = 1; }
+			else if (c == ',') { return 0; /* 多元素数组 */ }
+		}
+	}
+
+	/* 去尾部空白 */
+	const char *q = p + n;
+	while (n && isspace((unsigned char)q[-1]))
+	{
+		q--;
+		n--;
+	}
+
+	*elem = p;
+	*elem_len = n;
+	return 1;
+}
+
+/* 顶层比较:若两侧都是一元素数组则剥离后比较;否则直接按值级比较 */
+static int json_value_equal(const char *a, size_t a_len, const char *b, size_t b_len)
+{
+	const char *ae = NULL, *be = NULL;
+	size_t ale = 0, ble = 0;
+
+	if (extract_single_array_element(a, a_len, &ae, &ale) && extract_single_array_element(b, b_len, &be, &ble))
+	{
+		return json_scalar_equal(ae, ale, be, ble);
+	}
+
+	return json_scalar_equal(a, a_len, b, b_len);
+}
+
+/**
+ * @brief RyanJson 测试程序
+ *
+ * @param fileName
+ * @param data
+ * @param len
+ * @return int
+ */
+static int RyanJsonParseData(char *fileName, char *data, uint32_t len)
+{
+
+	if (strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0 ||
+	    strcmp(fileName, "n_structure_open_array_object.json") == 0 || strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0)
+	{
+		return -1;
+	}
+	// printf("开始解析: %s\r\n", fileName);
+	RyanJson_t json = RyanJsonParseOptions(data, len, RyanJsonTrue, NULL);
+	if (NULL == json) { return -1; }
+
+#ifdef PrintfStrCmpEnable
+	int32_t strLena = 0;
+	char *str = RyanJsonPrint(json, 60, RyanJsonFalse, &strLena);
+	if (NULL == str)
+	{
+		printf("反序列化失败: [%s]\n", data);
+		goto err;
+	}
+
+	RyanJsonMinify(data, len);
+	// {"foo\u0000bar":42}
+	static uint32_t alksdjfCOunt = 0;
+
+	if (0 != strcmp(data, str))
+	{
+		// if (data[0] = '[' && data[len - 1] = ']' && str[0] = '[' && str[strLena - 1] = ']') {
+
+		// }
+		// data/str 是去掉两端引号后的 JSON 字符串内容,并且有长度
+		if (!json_value_equal(data, len, str, strLena))
+		{
+			alksdjfCOunt++;
+			// 打印时避免 %s,被 NUL 截断;可以打印十六进制
+			printf("%d %s 数据不一致 -- 原始: %s -- 序列化: %s\n", alksdjfCOunt, fileName, data, str);
+			// printf("数据不一致 -- 原始len:%zu -- 序列化len:%zu\n", data_len, str_len);
+		}
+	}
+
+	RyanJsonFree(str);
+#endif
+
+	RyanJsonDelete(json);
+	return 0;
+
+err:
+	RyanJsonDelete(json);
+	return -1;
+}
+
+/**
+ * @brief cJson测试程序
+ *
+ * @param fileName
+ * @param data
+ * @param len
+ * @return int
+ */
+static int cJSONParseData(char *fileName, char *data, uint32_t len)
+{
+
+	if (strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0 ||
+	    strcmp(fileName, "n_structure_open_array_object.json") == 0 || strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0)
+	{
+		return -1;
+	}
+
+	cJSON *json = cJSON_ParseWithLengthOpts(data, len + sizeof(""), NULL, RyanJsonTrue);
+	if (NULL == json) { return -1; }
+
+#ifdef PrintfStrCmpEnable
+	char *str = cJSON_PrintBuffered(json, 60, RyanJsonFalse);
+	if (NULL == str)
+	{
+		printf("反序列化失败: [%s]\n", data);
+		goto err;
+	}
+
+	cJSON_Minify(data);
+	if (0 != strcmp(data, str)) { printf("-- 原始: %s -- 序列化: %s\n", data, str); }
+
+	cJSON_free(str);
+#endif
+
+	cJSON_Delete(json);
+	return 0;
+err:
+	cJSON_Delete(json);
+	return -1;
+}
+
+/**
+ * @brief cJson测试程序
+ *
+ * @param fileName
+ * @param data
+ * @param len
+ * @return int
+ */
+static int yyjsonParseData(char *fileName, char *data, uint32_t len)
+{
+
+	// 	if (strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0 ||
+	// 	    strcmp(fileName, "n_structure_open_array_object.json") == 0 || strcmp(fileName,
+	// "n_structure_100000_opening_arrays.json") == 0)
+	// 	{
+	// 		return -1;
+	// 	}
+
+	// 	yyjson_doc *doc = yyjson_read_opts(data, len, YYJSON_READ_NOFLAG, &yyalc, NULL);
+	// 	if (NULL == doc) { return -1; }
+
+	// #ifdef PrintfStrCmpEnable
+	// 	char *str = yyjson_write_opts(doc, YYJSON_WRITE_NOFLAG, &yyalc, NULL, NULL);
+	// 	if (NULL == str)
+	// 	{
+	// 		printf("反序列化失败: [%s]\n", data);
+	// 		goto err;
+	// 	}
+
+	// 	cJSON_Minify(data);
+	// 	if (0 != strcmp(data, str)) { printf("-- 原始: %s -- 序列化: %s\n", data, str); }
+
+	// 	free(str);
+	// #endif
+
+	// 	yyjson_doc_free(doc);
+	// 	return 0;
+	// err:
+	// 	yyjson_doc_free(doc);
+	// 	return -1;
+}
+
+// RFC 8259 JSON Test Suite
+// https://github.com/nst/JSONTestSuite
+RyanJsonBool_e RFC8259JsonTest(void)
+{
+	int result = 0;
+	RyanJsonInitHooks(v_malloc, v_free, v_realloc);
+
+	cJSON_Hooks hooks = {.malloc_fn = v_malloc, .free_fn = v_free};
+	cJSON_InitHooks(&hooks);
+
+	printf("开始 RFC 8259 JSON 测试");
+
+	printf("\r\n--------------------------- RFC8259  RyanJson --------------------------\r\n");
+	result = testFile("../../../../test//RFC8259JsonData", RyanJsonParseData);
+	if (0 != result)
+	{
+		printf("%s:%d RyanJson RFC8259JsonTest fail\r\n", __FILE__, __LINE__);
+		goto err;
+	}
+
+	// printf("\r\n--------------------------- RFC8259  cJSON --------------------------\r\n");
+	// result = testFile("../../../../test//RFC8259JsonData", cJSONParseData);
+	// if (0 != result)
+	// {
+	// 	printf("%s:%d cJSON RFC8259JsonTest fail\r\n", __FILE__, __LINE__);
+	// 	goto err;
+	// }
+
+	// printf("\r\n--------------------------- RFC8259  yyjson --------------------------\r\n");
+	// result = testFile("../../../../test//RFC8259JsonData", yyjsonParseData);
+	// if (0 != result)
+	// {
+	// 	printf("%s:%d yyjson RFC8259JsonTest fail\r\n", __FILE__, __LINE__);
+	// 	goto err;
+	// }
+
+	displayMem();
+	return RyanJsonTrue;
+
+err:
+	displayMem();
+	return RyanJsonFalse;
+}

+ 113 - 11
test/RyanJsonTest.c

@@ -9,13 +9,117 @@ static void printfTitle(char *title)
 	printf("*****************************************************************************\r\n");
 }
 
+#ifndef isEnableFuzzer
 int main(void)
 {
-	RyanJsonBool result = 0;
+	RyanJsonBool_e result = 0;
 	printfTitle("RyanJson 示例程序");
-	// RyanJsonExample();
+	RyanJsonInitHooks(v_malloc, v_free, v_realloc);
+
+	char *str = NULL;
+	RyanJson_t jsonRoot, item;
+
+	for (uint32_t i = 0; i < 1; i++)
+	{
+		// const char *jsonstr =
+		// 	"{\"emoji\":\"\\uD83D\\uDE00\"} ";
+		// const char *jsonstr = "{\"name\":\"Mash\",\"star\":4,\"hits\":[2,2,1,3]}";
+		// const char *jsonstr = "\012{\"nnnnnnnnnnnnnnnnnnn\012nnlnnnnnn\":0}";
+		// const char *jsonstr =
+		//
+		//
+		// "\012{\"\377\377\377\377\377\377\377\377\375\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\":"
+		// "0}";
+		// char jsonstr[] = "[\"\\u200B\"]";
+		// char jsonstr[] = "[\"new\\u000Aline\"]";
+		// char jsonstr[] =
+		// "\012{\"wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww\":0}"; char
+		// jsonstr[] = "\"\334\334\334\""; char jsonstr[] =
+		// 	"{\"\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367"
+		// 	"\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367"
+		// 	"\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\367\":0}"
+		// 	"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\351\000\000\000\000\000\000\000\000\000\000\000"
+		// 	"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000";
+		// const char *jsonstr = "{\"string\":\"\\u6211\\u662F\\u5730\\u7403\\uD83C\\uDF0D\"}";
+		// const char *jsonstr = "\012444444444444444";
+		// const char *jsonstr = "\"\"";
+		// const char *jsonstr = "{\"nnnnnnnnnnnnnnnnnnn\012nnlnnnnnn\":0}";
+		const char *jsonstr =
+			"[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["
+			"[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["
+			"[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["
+			"[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["
+			"[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["
+			"[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["
+			"[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["
+			"[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["
+			"[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[";
+		// const char jsonstr[] =
+		// 	"{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":{"
+		// 	"\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,"
+		// 	"16.89,"
+		// 	"\"hello\",\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":"
+		// 	"16,"
+		// 	"\"boolTrue\":true,\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\","
+		// 	"\"boolTrue\":"
+		// 	"true,\"boolFalse\":false,\"null\":null}]}";
+
+		// extern int LLVMFuzzerTestOneInput(const char *data, int32_t size);
+		// LLVMFuzzerTestOneInput(jsonstr, strlen(jsonstr));
+
+		// 解析json数据
+		jsonRoot = RyanJsonParse(jsonstr);
+		if (jsonRoot == NULL) { printf("%s:%d 序列化失败\r\n", __FILE__, __LINE__); }
+		else
+		{
+			printf("jsonRoot: %p\r\n", jsonRoot);
+			// RyanJsonChangeStringValue(jsonRoot, "hello");
+			// RyanJsonChangeStrValue(jsonRoot, "hello");
+
+			RyanJsonDeleteByKey(jsonRoot, "non_exist_key");
+
+			// RyanJsonReplaceByKey(jsonRoot, "star2", RyanJsonDuplicate(jsonRoot));
+			// RyanJson_t jsonRoot2 = RyanJsonCreateObject();
+			// RyanJsonAddStringToObject(jsonRoot2, "star2", "NULL");
+			// if (RyanJsonFalse == RyanJsonReplaceByKey(jsonRoot, "star2", jsonRoot2)) { RyanJsonDelete(jsonRoot2); }
+
+			// RyanJson_t pJson2 = RyanJsonCreateObject();
+			// if (RyanJsonFalse == RyanJsonReplaceByIndex(jsonRoot, RyanJsonGetSize(jsonRoot) - 1, pJson2))
+			// {
+			// 	RyanJsonDelete(pJson2);
+			// }
+
+			// printf(" %s\r\n", RyanJsonPrint(RyanJsonCreateString("NULL", "arrayString2222"), 10, RyanJsonFalse, NULL));
+
+			printf("jsonRoot22: %p\r\n", jsonRoot);
+			uint32_t len = 0;
+			str = RyanJsonPrint(jsonRoot, 10, RyanJsonFalse, &len); // 以带格式方式将数据打印出来
+			printf("strLen: %d, data: %s\r\n", len, str);
+
+			// RyanJson_t pJsonDup = RyanJsonDuplicate(jsonRoot);
+			// assert(NULL != pJsonDup);
+
+			// // 判断复制json的size是否一致
+			// assert(RyanJsonGetSize(jsonRoot) == RyanJsonGetSize(pJsonDup));
+			// int32_t dupLen = 0;
+			// char *jsonStrDup = RyanJsonPrint(pJsonDup, 100, RyanJsonFalse, &dupLen); // 以带格式方式将数据打印出来
+			// if (len != dupLen || 0 != memcmp(str, jsonStrDup, len))
+			// {
+			// 	printf("len:%d, dupLen:%d\r\n", len, dupLen);
+			// 	printf("jsonStr:%s \r\njsonDup:%s\r\n", str, jsonStrDup);
+			// }
+
+			// printf("jsonStr:%s \r\njsonDup:%s\r\n", str, jsonStrDup);
+			// RyanJsonFree(jsonStrDup);
+			// RyanJsonDelete(pJsonDup);
+
+			RyanJsonFree(str);
+			RyanJsonDelete(jsonRoot);
+		}
+	}
+
+	RyanJsonExample();
 
-	printfTitle("RyanJson 接口测试程序");
 	result = RyanJsonBaseTest();
 	if (RyanJsonTrue != result)
 	{
@@ -23,17 +127,15 @@ int main(void)
 		return -1;
 	}
 
-	// printfTitle("RyanJson / cJSON / yyjson RFC8259标准测试");
-	// result = RFC8259JsonTest();
-	// if (0 != result)
-	// {
-	//     printf("%s:%d RFC8259JsonTest fail\r\n", __FILE__, __LINE__);
-	//     return -1;
-	// }
+	printfTitle("RyanJson / cJSON / yyjson RFC8259标准测试");
+	RFC8259JsonTest();
 
 	printfTitle("RyanJson / cJSON / yyjson 内存对比程序");
-	result = RyanJsonMemoryFootprintTest();
+	RyanJsonMemoryFootprintTest();
+	printf("\r\nok\r\n");
 
 	displayMem();
 	return 0;
 }
+
+#endif // isEnableFuzzer

+ 10 - 8
test/RyanJsonTest.h

@@ -13,14 +13,15 @@ extern "C" {
 #include <sys/stat.h>
 #include <dirent.h>
 #include "valloc.h"
-#define malloc  v_malloc
-#define calloc  v_calloc
-#define free    v_free
-#define realloc v_realloc
+// #define malloc  v_malloc
+// #define calloc  v_calloc
+// #define free    v_free
+// #define realloc v_realloc
 
 #include "RyanJson.h"
+#include "RyanJsonUtils.h"
 #include "cJSON.h"
-#include "yyjson.h"
+// #include "yyjson.h"
 
 #define getArraySize(arr) ((int32_t)(sizeof(arr) / sizeof((arr)[0])))
 #define checkMemory                                                                                                                                                                                    \
@@ -45,9 +46,10 @@ extern "C" {
 // 定义结构体类型
 
 /* extern variables-----------------------------------------------------------*/
-extern RyanJsonBool RyanJsonBaseTest(void);
-extern RyanJsonBool RFC8259JsonTest(void);
-extern RyanJsonBool RyanJsonMemoryFootprintTest(void);
+extern RyanJsonBool_e RyanJsonExample(void);
+extern RyanJsonBool_e RyanJsonBaseTest(void);
+extern RyanJsonBool_e RFC8259JsonTest(void);
+extern RyanJsonBool_e RyanJsonMemoryFootprintTest(void);
 #ifdef __cplusplus
 }
 #endif

+ 90 - 0
test/baseTest/RyanJsonBaseTest.c

@@ -0,0 +1,90 @@
+#include "RyanJsonBaseTest.h"
+
+static RyanJsonBool_e likeReferenceTest()
+{
+
+	// char *str = NULL;
+	// char jsonstr[] =
+	// "{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89],\"arrayString\":[\"hello\",\"hello\",\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}]}";
+	// RyanJson_t json = RyanJsonParse(jsonstr);
+	// RyanJson_t item = NULL;
+
+	// // RyanJson_t adfasdf = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "item"));
+
+	// // RyanJsonAddItemToObject(json, "test", adfasdf);
+
+	// // 这里做你想做的事,这里我选择打印出来
+	// // str = RyanJsonPrint(json, 50, RyanJsonTrue, NULL);
+	// // printf("item %s \r\n", str);
+	// // RyanJsonFree(str);
+
+	// for (int i = 0; i < 1; i++)
+	// {
+	//     // 分离test对象
+	//     item = RyanJsonDetachByKey(json, "item");
+
+	//     // if (RyanJsonIsKey(item))
+	//     //     RyanJsonFree(RyanJsonGetKey(item));
+
+	//     // RyanJsonFree(item);
+	// }
+
+	// RyanJsonAddItemToObject(json, "item", item);
+
+	// str = RyanJsonPrint(json, 50, RyanJsonTrue, NULL);
+	// printf("item %s \r\n", str);
+	// RyanJsonFree(str);
+
+	// RyanJsonDelete(json);
+
+	return 0;
+}
+
+uint64_t platformUptimeMs(void)
+{
+	struct timespec ts;
+	// CLOCK_MONOTONIC: 单调递增,不受系统时间修改影响,适合做耗时统计
+	clock_gettime(CLOCK_MONOTONIC, &ts);
+	return (uint64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
+}
+
+RyanJsonBool_e RyanJsonBaseTest(void)
+{
+	int result = 0;
+	RyanJsonInitHooks(v_malloc, v_free, v_realloc);
+
+	uint32_t testRunCount = 0;
+	uint64_t funcStartMs;
+#define runTestWithLogAndTimer(fun)                                                                                                        \
+	do                                                                                                                                 \
+	{                                                                                                                                  \
+		testRunCount++;                                                                                                            \
+		printf("┌── [TEST %d] 开始执行: " #fun "()\r\n", testRunCount);                                                            \
+		funcStartMs = platformUptimeMs();                                                                                          \
+		result = fun();                                                                                                            \
+		printf("└── [TEST %d] 结束执行: 返回值 = %d %s | 耗时: %llu ms\x1b[0m\r\n\r\n", testRunCount, result,                      \
+		       (result == RyanJsonTrue) ? "✅" : "❌", (platformUptimeMs() - funcStartMs));                                        \
+		RyanJsonCheckCodeNoReturn(RyanJsonTrue == result, { goto __exit; });                                                       \
+	} while (0)
+
+	runTestWithLogAndTimer(RyanJsonBaseTestLoadJson);      // 从文本解析json测试
+	runTestWithLogAndTimer(RyanJsonBaseTestCreateJson);    // 创建json节点树测试
+	runTestWithLogAndTimer(RyanJsonBaseTestChangeJson);    // 修改json节点测试,包含删除、分离
+	runTestWithLogAndTimer(RyanJsonBaseTestCompareJson);   // 修改json节点测试,包含删除、分离
+	runTestWithLogAndTimer(RyanJsonBaseTestDuplicateJson); // 复制测试
+	runTestWithLogAndTimer(RyanJsonBaseTestForEachJson);   // 循环测试
+
+	// result = likeReferenceTest(); // 模仿 引用类型实现 示例
+	// if (0 != result)
+	// {
+	// 	printf("%s:%d loadJsonTest fail\r\n", __FILE__, __LINE__);
+	// 	return RyanJsonFalse;
+	// }
+
+	displayMem();
+	return RyanJsonTrue;
+
+__exit:
+	displayMem();
+	return RyanJsonFalse;
+}

+ 46 - 0
test/baseTest/RyanJsonBaseTest.h

@@ -0,0 +1,46 @@
+#ifndef __RyanJsonBaseTest__
+#define __RyanJsonBaseTest__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+
+#include "RyanJson.h"
+#include "RyanJsonUtils.h"
+#include "cJSON.h"
+#include "valloc.h"
+#include "RyanJsonTest.h"
+#define jsonLog(fmt, ...) printf("%s:%d " fmt, __FILE__, __LINE__, ##__VA_ARGS__)
+
+// 定义枚举类型
+
+// 定义结构体类型
+
+/* extern variables-----------------------------------------------------------*/
+
+extern RyanJsonBool_e compare_double(double a, double b);
+extern void printfJsonaaaa(RyanJson_t json);
+extern RyanJsonBool_e rootNodeCheckTest(RyanJson_t json);
+extern RyanJsonBool_e itemNodeCheckTest(RyanJson_t json);
+extern RyanJsonBool_e arrayNodeCheckTest(RyanJson_t json);
+extern RyanJsonBool_e arrayItemNodeCheckTest(RyanJson_t json);
+extern RyanJsonBool_e RyanJsonBaseTestCheckRoot(RyanJson_t pJson);
+
+extern RyanJsonBool_e RyanJsonBaseTestCreateJson();
+extern RyanJsonBool_e RyanJsonBaseTestLoadJson();
+extern RyanJsonBool_e RyanJsonBaseTestChangeJson();
+extern RyanJsonBool_e RyanJsonBaseTestCompareJson();
+extern RyanJsonBool_e RyanJsonBaseTestDuplicateJson();
+extern RyanJsonBool_e RyanJsonBaseTestForEachJson();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 198 - 0
test/baseTest/RyanJsonBaseTestChangeJson.c

@@ -0,0 +1,198 @@
+
+#include "RyanJsonBaseTest.h"
+
+/* --------------------------------------------------------------------- */
+
+RyanJsonBool_e RyanJsonBaseTestChangeJson()
+{
+
+	char jsonstr[] = "{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":"
+			 "{\"inter\":16,\"double\":16."
+			 "89,\"string\":\"hello\","
+			 "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,"
+			 "16.89,16.89,16.89],"
+			 "\"arrayString\":[\"hello\",\"hello\","
+			 "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,"
+			 "\"double\":16.89,\"string\":"
+			 "\"hello\",\"boolTrue\":true,"
+			 "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
+			 "\"boolFalse\":false,\"null\":null}],"
+			 "\"string2222\":\"hello\"}";
+
+	RyanJson_t json = RyanJsonParse(jsonstr);
+	RyanJsonCheckReturnFlase(NULL != json);
+
+	/**
+	 * @brief 修改对应类型
+	 *
+	 */
+	RyanJsonChangeIntValue(RyanJsonGetObjectToKey(json, "inter"), 20);
+	RyanJsonCheckCode(RyanJsonIsInt(RyanJsonGetObjectToKey(json, "inter")) &&
+				  20 == RyanJsonGetIntValue(RyanJsonGetObjectToKey(json, "inter")),
+			  { goto err; });
+
+	RyanJsonChangeDoubleValue(RyanJsonGetObjectToKey(json, "double"), 20.89);
+	if (!RyanJsonIsDouble(RyanJsonGetObjectToKey(json, "double")) ||
+	    !compare_double(RyanJsonGetDoubleValue(RyanJsonGetObjectToKey(json, "double")), 20.89))
+	{
+		RyanJsonCheckCode(NULL, { goto err; });
+	}
+
+	RyanJsonChangeStringValue(RyanJsonGetObjectToKey(json, "string"), "world");
+	if (!RyanJsonIsString(RyanJsonGetObjectToKey(json, "string")) ||
+	    strcmp(RyanJsonGetStringValue(RyanJsonGetObjectToKey(json, "string")), "world"))
+	{
+		RyanJsonCheckCode(NULL, { goto err; });
+	}
+
+	RyanJsonChangeBoolValue(RyanJsonGetObjectToKey(json, "boolTrue"), RyanJsonFalse);
+	if (!RyanJsonIsBool(RyanJsonGetObjectToKey(json, "boolTrue")) ||
+	    RyanJsonGetBoolValue(RyanJsonGetObjectToKey(json, "boolTrue")) != RyanJsonFalse)
+	{
+		RyanJsonCheckCode(NULL, { goto err; });
+	}
+
+	RyanJsonChangeBoolValue(RyanJsonGetObjectToKey(json, "boolFalse"), RyanJsonTrue);
+	if (!RyanJsonIsBool(RyanJsonGetObjectToKey(json, "boolFalse")) ||
+	    RyanJsonGetBoolValue(RyanJsonGetObjectToKey(json, "boolFalse")) != RyanJsonTrue)
+	{
+		RyanJsonCheckCode(NULL, { goto err; });
+	}
+
+	RyanJsonChangeKey(RyanJsonGetObjectToKey(json, "inter"), "inter");
+	RyanJsonChangeKey(RyanJsonGetObjectToKey(json, "double"), "double22222222");
+	RyanJsonChangeKey(RyanJsonGetObjectToKey(json, "string2222"), "string333");
+	RyanJsonChangeStringValue(RyanJsonGetObjectToKey(json, "string333"), "stringValye333");
+	if (!RyanJsonIsBool(RyanJsonGetObjectToKey(json, "boolFalse")) ||
+	    RyanJsonGetBoolValue(RyanJsonGetObjectToKey(json, "boolFalse")) != RyanJsonTrue)
+	{
+		RyanJsonCheckCode(NULL, { goto err; });
+	}
+
+	/* ---------------------------------- replace使用 -------------------------------------*/
+	{
+		// 数组没有key, replace的子项不能有key, 函数内部没有做逻辑判断,会造成内存泄漏
+		RyanJsonReplaceByIndex(RyanJsonGetObjectToKey(json, "arrayInt"), 0, RyanJsonCreateString(NULL, "arrayInt"));
+		if (!RyanJsonIsString(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json, "arrayInt"), 0)) ||
+		    strcmp(RyanJsonGetStringValue(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json, "arrayInt"), 0)), "arrayInt"))
+		{
+			RyanJsonCheckCode(NULL, { goto err; });
+		}
+
+		RyanJsonReplaceByIndex(RyanJsonGetObjectToKey(json, "arrayInt"),
+				       RyanJsonGetSize(RyanJsonGetObjectToKey(json, "arrayInt")) - 1,
+				       RyanJsonCreateString(NULL, "arrayInt"));
+		if (!RyanJsonIsString(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json, "arrayInt"),
+							       RyanJsonGetSize(RyanJsonGetObjectToKey(json, "arrayInt")) - 1)) ||
+		    strcmp(RyanJsonGetStringValue(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json, "arrayInt"),
+									   RyanJsonGetSize(RyanJsonGetObjectToKey(json, "arrayInt")) - 1)),
+			   "arrayInt"))
+		{
+			RyanJsonCheckCode(NULL, { goto err; });
+		}
+
+		RyanJsonReplaceByIndex(RyanJsonGetObjectToKey(json, "arrayItem"), 0, RyanJsonCreateString(NULL, "arrayItem"));
+		if (!RyanJsonIsString(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json, "arrayItem"), 0)) ||
+		    strcmp(RyanJsonGetStringValue(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json, "arrayItem"), 0)), "arrayItem"))
+		{
+			RyanJsonCheckCode(NULL, { goto err; });
+		}
+
+		RyanJsonReplaceByIndex(RyanJsonGetObjectToKey(json, "arrayItem"), 1, RyanJsonCreateString(NULL, "arrayItem"));
+		if (!RyanJsonIsString(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json, "arrayItem"), 1)) ||
+		    strcmp(RyanJsonGetStringValue(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json, "arrayItem"), 1)), "arrayItem"))
+		{
+			RyanJsonCheckCode(NULL, { goto err; });
+		}
+
+		// 对象必须包含key, 如果创建的对象key为null会引起内存错误
+		RyanJsonReplaceByKey(json, "arrayString", RyanJsonCreateString("", "arrayString2222"));
+		if (!RyanJsonIsString(RyanJsonGetObjectToKey(json, "arrayString")) ||
+		    strcmp(RyanJsonGetStringValue(RyanJsonGetObjectToKey(json, "arrayString")), "arrayString2222"))
+		{
+			RyanJsonCheckCode(NULL, { goto err; });
+		}
+
+		// 修改数组节点为对象节点
+		RyanJson_t duplicateJson = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "item"));
+		printfJsonaaaa(duplicateJson);
+
+		// RyanJson_t item = RyanJsonCreateObject2("key");
+		// // RyanJson_t item = RyanJsonCreateObject();
+		// RyanJsonAddIntToObject(item, "inter", 16);
+		// RyanJsonAddDoubleToObject(item, "double", 16.89);
+		// RyanJsonAddStringToObject(item, "string", "hello");
+		// RyanJsonAddBoolToObject(item, "boolTrue", RyanJsonTrue);
+		// RyanJsonAddBoolToObject(item, "boolFalse", RyanJsonFalse);
+		// RyanJsonAddNullToObject(item, "null");
+
+		// RyanJsonReplaceByKey(json, "arrayDouble", item);
+		RyanJsonReplaceByKey(json, "arrayDouble", duplicateJson);
+		if (!RyanJsonIsObject(RyanJsonGetObjectToKey(json, "arrayDouble")) ||
+		    -1 == rootNodeCheckTest(RyanJsonGetObjectToKey(json, "arrayDouble")))
+		{
+			RyanJsonCheckCode(NULL, { goto err; });
+		}
+	}
+
+	/**
+	 * @brief 对象子项删除测试
+	 *
+	 */
+	{
+		RyanJsonDeleteByIndex(json, 0);
+		if (RyanJsonGetObjectToKey(json, "inter"))
+		{
+			RyanJsonCheckCode(NULL, { goto err; });
+		}
+
+		RyanJsonDeleteByKey(json, "double");
+		if (RyanJsonGetObjectToKey(json, "double"))
+		{
+			RyanJsonCheckCode(NULL, { goto err; });
+		}
+	}
+
+	/**
+	 * @brief 数组对象子项删除测试
+	 *
+	 */
+	{
+		RyanJsonDeleteByIndex(RyanJsonGetObjectToKey(json, "array"), 0);
+		if (RyanJsonGetSize(RyanJsonGetObjectToKey(json, "array")) != 5)
+		{
+			RyanJsonCheckCode(NULL, { goto err; });
+		}
+	}
+
+	/**
+	 * @brief 对象子项分离测试
+	 *
+	 */
+	{
+		RyanJson_t json2 = RyanJsonParse(jsonstr);
+		RyanJsonDelete(RyanJsonDetachByIndex(json, 0));
+		if (RyanJsonGetObjectToKey(json, "inter"))
+		{
+			RyanJsonCheckCode(NULL, { goto err; });
+		}
+		RyanJsonDelete(json2);
+
+		json2 = RyanJsonParse(jsonstr);
+		RyanJsonDelete(RyanJsonDetachByKey(json, "inter"));
+		if (RyanJsonGetObjectToKey(json, "inter"))
+		{
+			RyanJsonCheckCode(NULL, { goto err; });
+		}
+		RyanJsonDelete(json2);
+	}
+
+	char *str = RyanJsonPrint(json, 1024, RyanJsonTrue, NULL);
+	RyanJsonFree(str);
+	RyanJsonDelete(json);
+	return RyanJsonTrue;
+
+err:
+	RyanJsonDelete(json);
+	return RyanJsonFalse;
+}

+ 158 - 0
test/baseTest/RyanJsonBaseTestCompareJson.c

@@ -0,0 +1,158 @@
+#include "RyanJsonBaseTest.h"
+/* --------------------------------------------------------------------- */
+
+RyanJsonBool_e RyanJsonBaseTestCompareJson()
+{
+	char jsonstr[] = "{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":"
+			 "{\"inter\":16,\"double\":16."
+			 "89,\"string\":\"hello\","
+			 "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,"
+			 "16.89,16.89,16.89],"
+			 "\"arrayString\":[\"hello\",\"hello\","
+			 "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,"
+			 "\"double\":16.89,\"string\":"
+			 "\"hello\",\"boolTrue\":true,"
+			 "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
+			 "\"boolFalse\":false,\"null\":null}]}";
+
+	RyanJson_t json = RyanJsonParse(jsonstr);
+	RyanJson_t json2 = RyanJsonParse(jsonstr);
+
+	// 比较函数
+	RyanJsonCheckCode(RyanJsonTrue == RyanJsonCompare(json, json2), { goto err; });
+
+	RyanJsonDelete(json2);
+	json2 = RyanJsonParse(jsonstr);
+	RyanJsonAddStringToObject(json2, "test", "hello");
+	RyanJsonCheckCode(RyanJsonFalse == RyanJsonCompare(json, json2), { goto err; });
+
+	RyanJsonDelete(json2);
+	json2 = RyanJsonParse(jsonstr);
+	RyanJsonAddIntToObject(json2, "test", 1);
+	RyanJsonCheckCode(RyanJsonFalse == RyanJsonCompare(json, json2), { goto err; });
+
+	RyanJsonDelete(json2);
+	json2 = RyanJsonParse(jsonstr);
+	RyanJsonAddDoubleToObject(json2, "test", 2.0);
+	RyanJsonCheckCode(RyanJsonFalse == RyanJsonCompare(json, json2), { goto err; });
+
+	RyanJsonDelete(json2);
+	json2 = RyanJsonParse(jsonstr);
+	RyanJsonAddBoolToObject(json2, "test", RyanJsonTrue);
+	RyanJsonCheckCode(RyanJsonFalse == RyanJsonCompare(json, json2), { goto err; });
+
+	RyanJsonDelete(json2);
+	json2 = RyanJsonParse(jsonstr);
+	RyanJsonAddNullToObject(json2, "test");
+	RyanJsonCheckCode(RyanJsonFalse == RyanJsonCompare(json, json2), { goto err; });
+
+	RyanJsonDelete(json2);
+	json2 = RyanJsonParse(jsonstr);
+	RyanJsonAddIntToArray(RyanJsonGetObjectToKey(json2, "arrayInt"), 2);
+	RyanJsonCheckCode(RyanJsonFalse == RyanJsonCompare(json, json2), { goto err; });
+
+	RyanJsonDelete(json2);
+	json2 = RyanJsonParse(jsonstr);
+	RyanJsonAddDoubleToArray(RyanJsonGetObjectToKey(json2, "arrayDouble"), 2.0);
+	RyanJsonCheckCode(RyanJsonFalse == RyanJsonCompare(json, json2), { goto err; });
+
+	RyanJsonDelete(json2);
+	json2 = RyanJsonParse(jsonstr);
+	RyanJsonAddStringToArray(RyanJsonGetObjectToKey(json2, "arrayString"), "hello");
+	RyanJsonCheckCode(RyanJsonFalse == RyanJsonCompare(json, json2), { goto err; });
+
+	RyanJsonDelete(json2);
+	json2 = RyanJsonParse(jsonstr);
+	RyanJsonAddItemToArray(RyanJsonGetObjectToKey(json2, "arrayItem"), RyanJsonCreateString("test", "hello"));
+	RyanJsonCheckCode(RyanJsonFalse == RyanJsonCompare(json, json2), { goto err; });
+
+	RyanJsonDelete(json2);
+	json2 = RyanJsonParse(jsonstr);
+	RyanJsonChangeKey(RyanJsonGetObjectToKey(json2, "inter"), "int2");
+	RyanJsonCheckCode(RyanJsonFalse == RyanJsonCompare(json, json2), { goto err; });
+
+	RyanJsonDelete(json2);
+	json2 = RyanJsonParse(jsonstr);
+	RyanJsonChangeIntValue(RyanJsonGetObjectToKey(json2, "inter"), 17);
+	RyanJsonCheckCode(RyanJsonFalse == RyanJsonCompare(json, json2), { goto err; });
+
+	RyanJsonDelete(json2);
+	json2 = RyanJsonParse(jsonstr);
+	RyanJsonChangeDoubleValue(RyanJsonGetObjectToKey(json2, "double"), 20.89);
+	if (RyanJsonFalse != RyanJsonCompare(json, json2))
+	{
+		printf("%s:%d 解析失败\r\n", __FILE__, __LINE__);
+		goto err;
+	}
+
+	RyanJsonDelete(json2);
+	json2 = RyanJsonParse(jsonstr);
+	RyanJsonDelete(RyanJsonDetachByKey(json2, "double"));
+	RyanJsonAddIntToObject(json2, "double", 20); // 改为int
+	RyanJsonCheckCode(RyanJsonFalse == RyanJsonCompare(json, json2), { goto err; });
+
+	RyanJsonDelete(json2);
+	json2 = RyanJsonParse(jsonstr);
+	RyanJsonChangeStringValue(RyanJsonGetObjectToKey(json2, "string"), "49");
+	RyanJsonCheckCode(RyanJsonFalse == RyanJsonCompare(json, json2), { goto err; });
+
+	RyanJsonDelete(json2);
+	json2 = RyanJsonParse(jsonstr);
+	RyanJsonChangeBoolValue(RyanJsonGetObjectToKey(json2, "boolTrue"), RyanJsonFalse);
+	RyanJsonCheckCode(RyanJsonFalse == RyanJsonCompare(json, json2), { goto err; });
+
+	RyanJsonDelete(json2);
+	json2 = RyanJsonParse(jsonstr);
+	RyanJsonChangeBoolValue(RyanJsonGetObjectToKey(json2, "item", "boolTrue"), RyanJsonFalse);
+	RyanJsonCheckCode(RyanJsonFalse == RyanJsonCompare(json, json2), { goto err; });
+
+	RyanJsonDelete(json2);
+	json2 = RyanJsonParse(jsonstr);
+	RyanJsonChangeIntValue(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json2, "arrayInt"), 0), 17);
+	RyanJsonCheckCode(RyanJsonFalse == RyanJsonCompare(json, json2), { goto err; });
+
+	RyanJsonDelete(json2);
+	json2 = RyanJsonParse(jsonstr);
+	RyanJsonChangeDoubleValue(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json2, "arrayDouble"), 0), 20.89);
+	RyanJsonCheckCode(RyanJsonFalse == RyanJsonCompare(json, json2), { goto err; });
+
+	RyanJsonDelete(json2);
+	json2 = RyanJsonParse(jsonstr);
+	RyanJsonChangeStringValue(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json2, "arrayString"), 0), "20.89");
+	RyanJsonCheckCode(RyanJsonFalse == RyanJsonCompare(json, json2), { goto err; });
+
+	RyanJsonDelete(json2);
+	json2 = RyanJsonParse(jsonstr);
+	RyanJsonChangeIntValue(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json2, "array"), 0), 17);
+	RyanJsonCheckCode(RyanJsonFalse == RyanJsonCompare(json, json2), { goto err; });
+
+	RyanJsonDelete(json2);
+	json2 = RyanJsonParse(jsonstr);
+	RyanJsonChangeIntValue(RyanJsonGetObjectToKey(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json2, "arrayItem"), 0), "inter"),
+			       17);
+	RyanJsonCheckCode(RyanJsonFalse == RyanJsonCompare(json, json2), { goto err; });
+
+	RyanJsonDelete(json2);
+	json2 = RyanJsonParse(jsonstr);
+	RyanJsonDeleteByKey(json2, "arrayItem");
+	RyanJsonCheckCode(RyanJsonFalse == RyanJsonCompare(json, json2), { goto err; });
+
+	RyanJsonDelete(json2);
+	json2 = RyanJsonParse(jsonstr);
+	RyanJsonDeleteByIndex(RyanJsonGetObjectToKey(json2, "arrayInt"), 2);
+	RyanJsonCheckCode(RyanJsonFalse == RyanJsonCompare(json, json2), { goto err; });
+
+	RyanJsonDelete(json2);
+	json2 = RyanJsonParse(jsonstr);
+	RyanJsonDeleteByIndex(RyanJsonGetObjectToKey(json2, "arrayItem"), 0);
+	RyanJsonCheckCode(RyanJsonFalse == RyanJsonCompare(json, json2), { goto err; });
+
+	RyanJsonDelete(json);
+	RyanJsonDelete(json2);
+	return RyanJsonTrue;
+
+err:
+	RyanJsonDelete(json);
+	RyanJsonDelete(json2);
+	return RyanJsonFalse;
+}

+ 86 - 0
test/baseTest/RyanJsonBaseTestCreateJson.c

@@ -0,0 +1,86 @@
+
+#include "RyanJsonBaseTest.h"
+
+RyanJsonBool_e RyanJsonBaseTestCreateJson()
+{
+	RyanJson_t jsonRoot, item;
+
+	// 对象生成测试
+	jsonRoot = RyanJsonCreateObject();
+	RyanJsonAddIntToObject(jsonRoot, "inter", 16);
+	RyanJsonAddDoubleToObject(jsonRoot, "double", 16.89);
+	RyanJsonAddStringToObject(jsonRoot, "string", "hello");
+	RyanJsonAddBoolToObject(jsonRoot, "boolTrue", RyanJsonTrue);
+	RyanJsonAddBoolToObject(jsonRoot, "boolFalse", RyanJsonFalse);
+	RyanJsonAddNullToObject(jsonRoot, "null");
+
+	/**
+	 * @brief 对象添加测试
+	 *
+	 */
+	item = RyanJsonCreateObject();
+	RyanJsonAddIntToObject(item, "inter", 16);
+	RyanJsonAddDoubleToObject(item, "double", 16.89);
+	RyanJsonAddStringToObject(item, "string", "hello");
+	RyanJsonAddBoolToObject(item, "boolTrue", RyanJsonTrue);
+	RyanJsonAddBoolToObject(item, "boolFalse", RyanJsonFalse);
+	RyanJsonAddNullToObject(item, "null");
+	RyanJsonAddItemToObject(jsonRoot, "item", item);
+
+	/**
+	 * @brief 数组添加测试
+	 *
+	 */
+	int arrayInt[] = {16, 16, 16, 16, 16};
+	RyanJsonAddItemToObject(jsonRoot, "arrayInt", RyanJsonCreateIntArray(arrayInt, sizeof(arrayInt) / sizeof(arrayInt[0])));
+
+	double arrayDouble[] = {16.89, 16.89, 16.89, 16.89, 16.89};
+	RyanJsonAddItemToObject(jsonRoot, "arrayDouble",
+				RyanJsonCreateDoubleArray(arrayDouble, sizeof(arrayDouble) / sizeof(arrayDouble[0])));
+
+	const char *arrayString[] = {"hello", "hello", "hello", "hello", "hello"};
+	RyanJsonAddItemToObject(jsonRoot, "arrayString",
+				RyanJsonCreateStringArray(arrayString, sizeof(arrayString) / sizeof(arrayString[0])));
+
+	RyanJson_t array = RyanJsonCreateArray();
+	RyanJsonAddIntToArray(array, 16);
+	RyanJsonAddDoubleToArray(array, 16.89);
+	RyanJsonAddStringToArray(array, "hello");
+	RyanJsonAddBoolToArray(array, RyanJsonTrue);
+	RyanJsonAddBoolToArray(array, RyanJsonFalse);
+	RyanJsonAddNullToArray(array);
+	RyanJsonAddItemToObject(jsonRoot, "array", array);
+
+	/**
+	 * @brief 对象数组测试
+	 *
+	 */
+	RyanJson_t arrayItem = RyanJsonCreateArray();
+	item = RyanJsonCreateObject();
+	RyanJsonAddIntToObject(item, "inter", 16);
+	RyanJsonAddDoubleToObject(item, "double", 16.89);
+	RyanJsonAddStringToObject(item, "string", "hello");
+	RyanJsonAddBoolToObject(item, "boolTrue", RyanJsonTrue);
+	RyanJsonAddBoolToObject(item, "boolFalse", RyanJsonFalse);
+	RyanJsonAddNullToObject(item, "null");
+	RyanJsonAddItemToObject(arrayItem, "item", item);
+
+	item = RyanJsonCreateObject();
+	RyanJsonAddIntToObject(item, "inter", 16);
+	RyanJsonAddDoubleToObject(item, "double", 16.89);
+	RyanJsonAddStringToObject(item, "string", "hello");
+	RyanJsonAddBoolToObject(item, "boolTrue", RyanJsonTrue);
+	RyanJsonAddBoolToObject(item, "boolFalse", RyanJsonFalse);
+	RyanJsonAddNullToObject(item, "null");
+	RyanJsonAddItemToObject(arrayItem, "item", item);
+
+	RyanJsonAddItemToObject(jsonRoot, "arrayItem", arrayItem);
+
+	RyanJsonCheckCode(RyanJsonTrue != RyanJsonBaseTestCheckRoot(jsonRoot), {
+		RyanJsonDelete(jsonRoot);
+		return RyanJsonFalse;
+	});
+	RyanJsonDelete(jsonRoot);
+
+	return RyanJsonTrue;
+}

+ 139 - 0
test/baseTest/RyanJsonBaseTestDuplicateJson.c

@@ -0,0 +1,139 @@
+
+#include "RyanJsonBaseTest.h"
+
+RyanJsonBool_e RyanJsonBaseTestDuplicateJson()
+{
+	RyanJson_t json, dupItem, jsonRoot = NULL;
+	char jsonstr[] = "{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":"
+			 "{\"inter\":16,\"double\":16."
+			 "89,\"string\":\"hello\","
+			 "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,"
+			 "16.89,16.89,16.89],"
+			 "\"arrayString\":[\"hello\",\"hello\","
+			 "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,"
+			 "\"double\":16.89,\"string\":"
+			 "\"hello\",\"boolTrue\":true,"
+			 "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
+			 "\"boolFalse\":false,\"null\":null}]}";
+
+	/**
+	 * @brief 普通类型
+	 *
+	 */
+	json = RyanJsonParse(jsonstr);
+	dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "inter"));
+	if (RyanJsonFalse == RyanJsonCompare(dupItem, RyanJsonGetObjectToKey(json, "inter"))) { goto err; }
+	RyanJsonDelete(dupItem);
+
+	dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "inter"));
+	RyanJsonAddItemToObject(json, "test", dupItem);
+	if (RyanJsonFalse == RyanJsonCompare(RyanJsonGetObjectToKey(json, "test", "inter"), RyanJsonGetObjectToKey(json, "inter")))
+	{
+		goto err;
+	}
+	RyanJsonDelete(RyanJsonDetachByKey(json, "test"));
+
+	dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "inter"));
+	RyanJsonAddItemToObject(json, "test", dupItem);
+	if (RyanJsonFalse == RyanJsonCompare(RyanJsonGetObjectToKey(json, "test", "inter"), RyanJsonGetObjectToKey(json, "inter")))
+	{
+		goto err;
+	}
+	RyanJsonDelete(json);
+
+	json = RyanJsonParse(jsonstr);
+	dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "inter"));
+	RyanJsonAddItemToObject(json, "test", dupItem);
+	if (RyanJsonFalse == RyanJsonCompare(RyanJsonGetObjectToKey(json, "test", "inter"), RyanJsonGetObjectToKey(json, "inter")))
+	{
+		goto err;
+	}
+	RyanJsonDelete(RyanJsonDetachByKey(json, "test"));
+	RyanJsonDelete(json);
+
+	/**
+	 * @brief 对象类型
+	 *
+	 */
+	json = RyanJsonParse(jsonstr);
+	dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "item"));
+	if (RyanJsonFalse == RyanJsonCompare(dupItem, RyanJsonGetObjectToKey(json, "item"))) { goto err; }
+	RyanJsonDelete(dupItem);
+
+	dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "item"));
+	RyanJsonAddItemToObject(json, "test", dupItem);
+	if (RyanJsonFalse == RyanJsonCompare(RyanJsonGetObjectToKey(json, "test"), RyanJsonGetObjectToKey(json, "item"))) { goto err; }
+	RyanJsonDelete(RyanJsonDetachByKey(json, "test"));
+
+	dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "item"));
+	RyanJsonAddItemToObject(json, "test", dupItem);
+	if (RyanJsonFalse == RyanJsonCompare(RyanJsonGetObjectToKey(json, "test"), RyanJsonGetObjectToKey(json, "item"))) { goto err; }
+	RyanJsonDelete(json);
+
+	json = RyanJsonParse(jsonstr);
+	dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "item"));
+	RyanJsonAddItemToObject(json, "test", dupItem);
+	if (RyanJsonFalse == RyanJsonCompare(RyanJsonGetObjectToKey(json, "test"), RyanJsonGetObjectToKey(json, "item"))) { goto err; }
+	RyanJsonDelete(RyanJsonDetachByKey(json, "test"));
+	RyanJsonDelete(json);
+
+	/**
+	 * @brief 数组类型
+	 *
+	 */
+	json = RyanJsonParse(jsonstr);
+	dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "arrayItem"));
+	if (RyanJsonFalse == RyanJsonCompare(dupItem, RyanJsonGetObjectToKey(json, "arrayItem"))) { goto err; }
+	RyanJsonDelete(dupItem);
+
+	dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "arrayItem"));
+	RyanJsonAddItemToObject(json, "test", dupItem);
+	if (RyanJsonFalse == RyanJsonCompare(RyanJsonGetObjectToKey(json, "test"), RyanJsonGetObjectToKey(json, "arrayItem"))) { goto err; }
+	RyanJsonDelete(RyanJsonDetachByKey(json, "test"));
+
+	dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "arrayItem"));
+	RyanJsonAddItemToObject(json, "test", dupItem);
+	if (RyanJsonFalse == RyanJsonCompare(RyanJsonGetObjectToKey(json, "test"), RyanJsonGetObjectToKey(json, "arrayItem"))) { goto err; }
+	RyanJsonDelete(json);
+
+	json = RyanJsonParse(jsonstr);
+	dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "arrayItem"));
+	RyanJsonAddItemToObject(json, "test", dupItem);
+	if (RyanJsonFalse == RyanJsonCompare(RyanJsonGetObjectToKey(json, "test"), RyanJsonGetObjectToKey(json, "arrayItem"))) { goto err; }
+	RyanJsonDelete(RyanJsonDetachByKey(json, "test"));
+	RyanJsonDelete(json);
+
+	json = RyanJsonParse(jsonstr);
+	jsonRoot = RyanJsonCreateObject();
+	RyanJsonAddBoolToObject(jsonRoot, "arrayItem", RyanJsonTrue);
+	int use = 0;
+	for (uint8_t i = 0; i < 10; i++)
+	{
+		dupItem = RyanJsonParse(jsonstr);
+		RyanJsonReplaceByKey(jsonRoot, "arrayItem", RyanJsonDuplicate(dupItem));
+		if (RyanJsonFalse == RyanJsonCompare(RyanJsonGetObjectToKey(jsonRoot, "arrayItem"), dupItem)) { goto err; }
+		RyanJsonReplaceByKey(json, "arrayItem", RyanJsonDuplicate(RyanJsonGetObjectByKey(dupItem, "item")));
+		if (RyanJsonFalse == RyanJsonCompare(RyanJsonGetObjectToKey(json, "arrayItem"), RyanJsonGetObjectByKey(dupItem, "item")))
+		{
+			goto err;
+		}
+		RyanJsonDelete(dupItem);
+
+		int newuse = vallocGetUse();
+		if (i != 0 && newuse != use)
+		{
+			printf("%s:%d 内存泄漏\r\n", __FILE__, __LINE__);
+			goto err;
+		}
+		use = newuse;
+	}
+
+	RyanJsonDelete(json);
+	RyanJsonDelete(jsonRoot);
+	return RyanJsonTrue;
+
+err:
+	RyanJsonDelete(json);
+	RyanJsonDelete(jsonRoot);
+	return RyanJsonFalse;
+}

+ 45 - 0
test/baseTest/RyanJsonBaseTestForEachJson.c

@@ -0,0 +1,45 @@
+
+#include "RyanJsonBaseTest.h"
+
+RyanJsonBool_e RyanJsonBaseTestForEachJson()
+{
+	char *str = NULL;
+	char jsonstr[] = "{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":"
+			 "{\"inter\":16,\"double\":16."
+			 "89,\"string\":\"hello\","
+			 "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,"
+			 "16.89,16.89,16.89],"
+			 "\"arrayString\":[\"hello\",\"hello\","
+			 "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,"
+			 "\"double\":16.89,\"string\":"
+			 "\"hello\",\"boolTrue\":true,"
+			 "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
+			 "\"boolFalse\":false,\"null\":null}]}";
+
+	RyanJson_t json = RyanJsonParse(jsonstr);
+	RyanJson_t item = NULL;
+	RyanJsonArrayForEach(RyanJsonGetObjectToKey(json, "arrayDouble"), item)
+	{
+		if (!RyanJsonIsDouble(item) || !compare_double(16.89, RyanJsonGetDoubleValue(item))) { goto err; }
+	}
+
+	RyanJsonArrayForEach(RyanJsonGetObjectToKey(json, "arrayInt"), item)
+	{
+		if (!RyanJsonIsInt(item) || 16 != RyanJsonGetIntValue(item)) { goto err; }
+	}
+
+	int32_t strLen;
+	RyanJsonObjectForEach(RyanJsonGetObjectToKey(json, "item"), item)
+	{
+		str = RyanJsonPrint(item, 50, RyanJsonTrue, &strLen);
+		printf("item { %s : %s }  %d\r\n", RyanJsonGetKey(item), str, strLen);
+		RyanJsonFree(str);
+	}
+
+	RyanJsonDelete(json);
+	return RyanJsonTrue;
+
+err:
+	RyanJsonDelete(json);
+	return RyanJsonFalse;
+}

+ 278 - 0
test/baseTest/RyanJsonBaseTestLoadJson.c

@@ -0,0 +1,278 @@
+
+#include "RyanJsonBaseTest.h"
+
+/* --------------------------------------------------------------------- */
+
+RyanJsonBool_e RyanJsonBaseTestLoadJson()
+{
+	char *str = NULL;
+	RyanJson_t json;
+	char jsonstr[] = "{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":"
+			 "{\"inter\":16,\"double\":16."
+			 "89,\"string\":\"hello\","
+			 "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,"
+			 "16.89,16.89,16.89],"
+			 "\"arrayString\":[\"hello\",\"hello\","
+			 "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,"
+			 "\"double\":16.89,\"string\":"
+			 "\"hello\",\"boolTrue\":true,"
+			 "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
+			 "\"boolFalse\":false,\"null\":null}]}";
+
+	json = RyanJsonParse(jsonstr);
+	RyanJsonCheckReturnFlase(NULL != json);
+
+	str = RyanJsonPrint(json, 250, RyanJsonFalse, NULL);
+	RyanJsonCheckCode(0 == strcmp(str, jsonstr), {
+		RyanJsonFree(str);
+		RyanJsonDelete(json);
+		return RyanJsonFalse;
+	});
+
+	RyanJsonFree(str);
+
+	RyanJsonCheckCode(RyanJsonTrue != RyanJsonBaseTestCheckRoot(json), {
+		RyanJsonDelete(json);
+		return RyanJsonFalse;
+	});
+
+	RyanJsonDelete(json);
+
+	/**
+	 * @brief 测试序列化错误json结构
+	 *
+	 */
+	// \"inter\":16poi,  无效数字
+	json = RyanJsonParse("{\"inter\":16poi,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,"
+			     "\"item\":{\"inter\":"
+			     "16,\"double\":16.89,\"string\":\"hello\","
+			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16."
+			     "89,16.89,16.89,16."
+			     "89],\"arrayString\":[\"hello\",\"hello\","
+			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,"
+			     "\"double\":16.89,"
+			     "\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,"
+			     "\"null\":null}]}");
+	RyanJsonCheckCode(NULL == json, {
+		RyanJsonDelete(json);
+		return RyanJsonFalse;
+	});
+
+	// \"double\":16.8yu9,,  无效浮点数
+	json = RyanJsonParse("{\"inter\":16,\"double\":16.8yu9,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,"
+			     "\"item\":{\"inter\":16,"
+			     "\"double\":16.89,\"string\":\"hello\","
+			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16."
+			     "89,16.89,16.89,16."
+			     "89],\"arrayString\":[\"hello\",\"hello\","
+			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,"
+			     "\"double\":16.89,"
+			     "\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,"
+			     "\"null\":null}]}");
+	RyanJsonCheckCode(NULL == json, {
+		RyanJsonDelete(json);
+		return RyanJsonFalse;
+	});
+
+	// boolTrue 设置为 tru
+	json = RyanJsonParse("{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":tru,\"boolFalse\":false,\"null\":null,"
+			     "\"item\":{\"inter\":16,"
+			     "\"double\":16.89,\"string\":\"hello\","
+			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16."
+			     "89,16.89,16.89,16."
+			     "89],\"arrayString\":[\"hello\",\"hello\","
+			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,"
+			     "\"double\":16.89,"
+			     "\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,"
+			     "\"null\":null}]}");
+	RyanJsonCheckCode(NULL == json, {
+		RyanJsonDelete(json);
+		return RyanJsonFalse;
+	});
+
+	// boolFalse 设置为 fale
+	json = RyanJsonParse("{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":fale,\"null\":null,"
+			     "\"item\":{\"inter\":16,"
+			     "\"double\":16.89,\"string\":\"hello\","
+			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16."
+			     "89,16.89,16.89,16."
+			     "89],\"arrayString\":[\"hello\",\"hello\","
+			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,"
+			     "\"double\":16.89,"
+			     "\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,"
+			     "\"null\":null}]}");
+	RyanJsonCheckCode(NULL == json, {
+		RyanJsonDelete(json);
+		return RyanJsonFalse;
+	});
+
+	// null 设置为 nul
+	json = RyanJsonParse("{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":nul,"
+			     "\"item\":{\"inter\":16,"
+			     "\"double\":16.89,\"string\":\"hello\","
+			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16."
+			     "89,16.89,16.89,16."
+			     "89],\"arrayString\":[\"hello\",\"hello\","
+			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,"
+			     "\"double\":16.89,"
+			     "\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,"
+			     "\"null\":null}]}");
+	RyanJsonCheckCode(NULL == json, {
+		RyanJsonDelete(json);
+		return RyanJsonFalse;
+	});
+
+	// null 设置为 NULL
+	json = RyanJsonParse("{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":NULL,"
+			     "\"item\":{\"inter\":16,"
+			     "\"double\":16.89,\"string\":\"hello\","
+			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16."
+			     "89,16.89,16.89,16."
+			     "89],\"arrayString\":[\"hello\",\"hello\","
+			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,"
+			     "\"double\":16.89,"
+			     "\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,"
+			     "\"null\":null}]}");
+	RyanJsonCheckCode(NULL == json, {
+		RyanJsonDelete(json);
+		return RyanJsonFalse;
+	});
+
+	// \"inter\":16后面少个,
+	json = RyanJsonParse("{\"inter\":16\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,"
+			     "\"item\":{\"inter\":16,"
+			     "\"double\":16.89,\"string\":\"hello\","
+			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16."
+			     "89,16.89,16.89,16."
+			     "89],\"arrayString\":[\"hello\",\"hello\","
+			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,"
+			     "\"double\":16.89,"
+			     "\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,"
+			     "\"null\":null}]}");
+	RyanJsonCheckCode(NULL == json, {
+		RyanJsonDelete(json);
+		return RyanJsonFalse;
+	});
+	// array数组项少一个,
+	json = RyanJsonParse("{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,"
+			     "\"item\":{\"inter\":16,"
+			     "\"double\":16.89,\"string\":\"hello\","
+			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16."
+			     "89,16.89,16.89,16."
+			     "89],\"arrayString\":[\"hello\",\"hello\","
+			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,"
+			     "\"double\":16.89,"
+			     "\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,"
+			     "\"null\":null}]}");
+	RyanJsonCheckCode(NULL == json, {
+		RyanJsonDelete(json);
+		return RyanJsonFalse;
+	});
+
+	// \"item:{\"inter\":16,\"  少一个"
+	json = RyanJsonParse("{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,"
+			     "\"item:{\"inter\":16,"
+			     "\"double\":16.89,\"string\":\"hello\","
+			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16."
+			     "89,16.89,16.89,16."
+			     "89],\"arrayString\":[\"hello\",\"hello\","
+			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,"
+			     "\"double\":16.89,"
+			     "\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,"
+			     "\"null\":null}]}");
+	RyanJsonCheckCode(NULL == json, {
+		RyanJsonDelete(json);
+		return RyanJsonFalse;
+	});
+
+	// \"item\":{\"inter\":16,double\"  少一个"
+	json = RyanJsonParse("{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,"
+			     "\"item\":{\"inter\":16,"
+			     "double\":16.89,\"string\":\"hello\","
+			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16."
+			     "89,16.89,16.89,16."
+			     "89],\"arrayString\":[\"hello\",\"hello\","
+			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,"
+			     "\"double\":16.89,"
+			     "\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,"
+			     "\"null\":null}]}");
+	RyanJsonCheckCode(NULL == json, {
+		RyanJsonDelete(json);
+		return RyanJsonFalse;
+	});
+
+	// \"item\":{\"inter\":16,\"\"double\"  多一个"
+	json = RyanJsonParse("{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,"
+			     "\"item\":{\"inter\":16,"
+			     "\"\"double\":16.89,\"string\":\"hello\","
+			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16."
+			     "89,16.89,16.89,16."
+			     "89],\"arrayString\":[\"hello\",\"hello\","
+			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,"
+			     "\"double\":16.89,"
+			     "\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,"
+			     "\"null\":null}]}");
+	RyanJsonCheckCode(NULL == json, {
+		RyanJsonDelete(json);
+		return RyanJsonFalse;
+	});
+
+	// \"item\":{\"inter\":16\",\"double\"  多一个"
+	json = RyanJsonParse("{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,"
+			     "\"item\":{\"inter\":16\","
+			     "\"double\":16.89,\"string\":\"hello\","
+			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16."
+			     "89,16.89,16.89,16."
+			     "89],\"arrayString\":[\"hello\",\"hello\","
+			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,"
+			     "\"double\":16.89,"
+			     "\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,"
+			     "\"null\":null}]}");
+	RyanJsonCheckCode(NULL == json, {
+		RyanJsonDelete(json);
+		return RyanJsonFalse;
+	});
+
+	// \"arrayInt\":[16,16,16m,16,16]  无效数组数字
+	json = RyanJsonParse("{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,"
+			     "\"item\":{\"inter\":16,"
+			     "\"double\":16.89,\"string\":\"hello\","
+			     "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16m,16,16],\"arrayDouble\":[16.89,"
+			     "16.89,16.89,16.89,16."
+			     "89],\"arrayString\":[\"hello\",\"hello\","
+			     "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,"
+			     "\"double\":16.89,"
+			     "\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
+			     "\"boolFalse\":false,"
+			     "\"null\":null}]}");
+	RyanJsonCheckCode(NULL == json, {
+		RyanJsonDelete(json);
+		return RyanJsonFalse;
+	});
+	return RyanJsonTrue;
+}

+ 169 - 0
test/baseTest/RyanJsonBaseTestUtile.c

@@ -0,0 +1,169 @@
+
+#include "RyanJsonBaseTest.h"
+
+/* --------------------------------------- jsonTest ------------------------------------------- */
+// !(fabs(RyanJsonGetDoubleValue(RyanJsonGetObjectToKey(json, "double")) - 16.89) < 1e-6)
+RyanJsonBool_e compare_double(double a, double b)
+{
+	double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
+	return (fabs(a - b) <= maxVal * DBL_EPSILON);
+}
+
+void printfJsonaaaa(RyanJson_t json)
+{
+	char *str = RyanJsonPrint(json, 1024, RyanJsonTrue, NULL);
+	printf("aa %s\r\n", str);
+	RyanJsonFree(str);
+}
+
+RyanJsonBool_e rootNodeCheckTest(RyanJson_t json)
+{
+	if (!RyanJsonIsInt(RyanJsonGetObjectToKey(json, "inter")) || 16 != RyanJsonGetIntValue(RyanJsonGetObjectToKey(json, "inter")))
+	{
+		RyanJsonCheckReturnFlase(NULL);
+	}
+
+	if (!RyanJsonIsDouble(RyanJsonGetObjectToKey(json, "double")) ||
+	    !compare_double(RyanJsonGetDoubleValue(RyanJsonGetObjectToKey(json, "double")), 16.89))
+	{
+		RyanJsonCheckReturnFlase(NULL);
+	}
+
+	if (!RyanJsonIsString(RyanJsonGetObjectToKey(json, "string")) ||
+	    strcmp(RyanJsonGetStringValue(RyanJsonGetObjectToKey(json, "string")), "hello"))
+	{
+		RyanJsonCheckReturnFlase(NULL);
+	}
+
+	if (!RyanJsonIsBool(RyanJsonGetObjectToKey(json, "boolTrue")) ||
+	    RyanJsonGetBoolValue(RyanJsonGetObjectToKey(json, "boolTrue")) != RyanJsonTrue)
+	{
+		RyanJsonCheckReturnFlase(NULL);
+	}
+
+	if (!RyanJsonIsBool(RyanJsonGetObjectToKey(json, "boolFalse")) ||
+	    RyanJsonGetBoolValue(RyanJsonGetObjectToKey(json, "boolFalse")) != RyanJsonFalse)
+	{
+		RyanJsonCheckReturnFlase(NULL);
+	}
+
+	if (!RyanJsonIsNull(RyanJsonGetObjectToKey(json, "null"))) { RyanJsonCheckReturnFlase(NULL); }
+
+	return RyanJsonTrue;
+}
+
+RyanJsonBool_e itemNodeCheckTest(RyanJson_t json)
+{
+	RyanJson_t item = RyanJsonGetObjectToKey(json, "item");
+	if (RyanJsonTrue != rootNodeCheckTest(item)) { RyanJsonCheckReturnFlase(NULL); }
+
+	return RyanJsonTrue;
+}
+
+RyanJsonBool_e arrayNodeCheckTest(RyanJson_t json)
+{
+	RyanJson_t item = NULL;
+
+	// 判断是不是数组类型
+	if (!RyanJsonIsArray(RyanJsonGetObjectToKey(json, "arrayInt"))) { RyanJsonCheckReturnFlase(NULL); }
+
+	if (!RyanJsonIsArray(RyanJsonGetObjectToKey(json, "arrayDouble"))) { RyanJsonCheckReturnFlase(NULL); }
+
+	if (!RyanJsonIsArray(RyanJsonGetObjectToKey(json, "arrayString"))) { RyanJsonCheckReturnFlase(NULL); }
+
+	if (!RyanJsonIsArray(RyanJsonGetObjectToKey(json, "array"))) { RyanJsonCheckReturnFlase(NULL); }
+
+	/**
+	 * @brief 检查弱类型数组
+	 *
+	 */
+	//   array: [16, 16.89, "hello", true, false, null],
+	if (!RyanJsonIsInt(RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "array"), 0)) ||
+	    16 != RyanJsonGetIntValue(RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "array"), 0)))
+	{
+		RyanJsonCheckReturnFlase(NULL);
+	}
+
+	if (!RyanJsonIsDouble(RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "array"), 1)) ||
+	    !compare_double(RyanJsonGetDoubleValue(RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "array"), 1)), 16.89))
+	{
+		printf("%s:%d 解析失败 %f\r\n", __FILE__, __LINE__,
+		       RyanJsonGetDoubleValue(RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "array"), 1)));
+		RyanJsonCheckReturnFlase(NULL);
+	}
+
+	if (!RyanJsonIsString(RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "array"), 2)) ||
+	    0 != strcmp(RyanJsonGetStringValue(RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "array"), 2)), "hello"))
+	{
+		RyanJsonCheckReturnFlase(NULL);
+	}
+
+	if (!RyanJsonIsBool(RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "array"), 3)) ||
+	    RyanJsonGetBoolValue(RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "array"), 3)) != RyanJsonTrue)
+	{
+		RyanJsonCheckReturnFlase(NULL);
+	}
+
+	if (!RyanJsonIsBool(RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "array"), 4)) ||
+	    RyanJsonGetBoolValue(RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "array"), 4)) != RyanJsonFalse)
+	{
+		RyanJsonCheckReturnFlase(NULL);
+	}
+
+	if (!RyanJsonIsNull(RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "array"), 5))) { RyanJsonCheckReturnFlase(NULL); }
+
+	/**
+	 * @brief 检查强类型数组
+	 *
+	 */
+	for (int32_t count = 0; count < RyanJsonGetSize(RyanJsonGetObjectToKey(json, "arrayInt")); count++)
+	{
+		item = RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "arrayInt"), count);
+		if (!RyanJsonIsInt(item) || 16 != RyanJsonGetIntValue(item)) { RyanJsonCheckReturnFlase(NULL); }
+	}
+
+	for (int32_t count = 0; count < RyanJsonGetSize(RyanJsonGetObjectToKey(json, "arrayDouble")); count++)
+	{
+		item = RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "arrayDouble"), count);
+		if (!RyanJsonIsDouble(item) || fabs(RyanJsonGetDoubleValue(item) - 16.8) < 0.001) { RyanJsonCheckReturnFlase(NULL); }
+	}
+
+	for (int32_t count = 0; count < RyanJsonGetSize(RyanJsonGetObjectToKey(json, "arrayString")); count++)
+	{
+		item = RyanJsonGetObjectByIndex(RyanJsonGetObjectToKey(json, "arrayString"), count);
+		if (!RyanJsonIsString(item) || strcmp(RyanJsonGetStringValue(item), "hello")) { RyanJsonCheckReturnFlase(NULL); }
+	}
+
+	if (6 != RyanJsonGetSize(RyanJsonGetObjectToKey(json, "array"))) { RyanJsonCheckReturnFlase(NULL); }
+
+	return RyanJsonTrue;
+}
+
+RyanJsonBool_e arrayItemNodeCheckTest(RyanJson_t json)
+{
+	if (!RyanJsonIsArray(RyanJsonGetObjectToKey(json, "arrayItem"))) { RyanJsonCheckReturnFlase(NULL); }
+
+	if (RyanJsonTrue != rootNodeCheckTest(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json, "arrayItem"), 0)))
+	{
+		RyanJsonCheckReturnFlase(NULL);
+	}
+
+	if (RyanJsonTrue != rootNodeCheckTest(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(json, "arrayItem"), 1)))
+	{
+		RyanJsonCheckReturnFlase(NULL);
+	}
+	return RyanJsonTrue;
+}
+
+RyanJsonBool_e RyanJsonBaseTestCheckRoot(RyanJson_t pJson)
+{
+	RyanJsonCheckReturnFlase(RyanJsonTrue != rootNodeCheckTest(pJson));
+
+	RyanJsonCheckReturnFlase(RyanJsonTrue != itemNodeCheckTest(pJson));
+
+	RyanJsonCheckReturnFlase(RyanJsonTrue != arrayNodeCheckTest(pJson));
+
+	RyanJsonCheckReturnFlase(RyanJsonTrue != arrayItemNodeCheckTest(pJson));
+
+	return RyanJsonTrue;
+}

+ 722 - 0
test/fuzzer/RyanJsonFuzzer.c

@@ -0,0 +1,722 @@
+#include "RyanJsonTest.h"
+#include <signal.h>
+
+// cmake .. -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
+// ./build/linux/x86/release/RyanJson -dict=./test/fuzzer/RyanJsonFuzzer.dict
+// ./build/linux/x86/release/RyanJson -dict=./test/fuzzer/RyanJsonFuzzer.dict -timeout=10 -runs=999999 -max_len=8192 -print_final_stats=0
+// -verbosity=0 test/fuzzer/input
+// ./build/linux/x86/release/RyanJson -dict=./test/fuzzer/RyanJsonFuzzer.dict -timeout=10 -runs=99999 -verbosity=0 -max_len=8192
+
+// llvm-profdata merge -sparse default.profraw -o default.profdata
+// 文本报告
+// llvm-cov report ./build/linux/x86/release/RyanJson -instr-profile=default.profdata
+// html报告
+// llvm-cov show ./build/linux/x86/release/RyanJson -instr-profile=default.profdata -format=html -output-dir=coverage_report
+// llvm-cov show ./build/linux/x86/release/RyanJson \
+//   -instr-profile=default.profdata \
+//   -format=html \
+//   -output-dir=coverage_report \
+//   -compilation-dir=/home/ryan/linux/appDev/RyanJson \
+//   -path-equivalence=/home/ryan/linux/appDev/RyanJson,./RyanJson
+
+// llvm-cov show ./build/linux/x86/release/RyanJson -instr-profile=default.profdata -format=html -output-dir=coverage_report
+// llvm-cov show ./build/linux/x86/release/RyanJson -instr-profile=default.profdata -name=RyanJson -format=html > coverage_report.html
+// llvm-cov show ./build/linux/x86/release/RyanJson -instr-profile=default.profdata -name=FuzzMe
+
+// RyanJsonBool_e RyanJson
+#define RyanJsonCheckGotoExit(EX)                                                                                                          \
+	RyanJsonCheckCode(EX, {                                                                                                            \
+		result = RyanJsonFalse;                                                                                                    \
+		goto __exit;                                                                                                               \
+	})
+RyanJsonBool_e isadfa = RyanJsonTrue;
+
+static void RyanPrintJsonToLog22(RyanJson_t pJson)
+{
+	int32_t strLen = 0;
+	char *jsonStr = RyanJsonPrint(pJson, 512, RyanJsonFalse, &strLen);
+	if (NULL == jsonStr) { return; }
+
+	for (int32_t i = 0; i < strLen; i++)
+	{
+		int32_t aaa = strLen - (i * 100);
+		if (aaa > 100) { printf("%.*s", 100, jsonStr + (i * 100)); }
+		else
+		{
+			if (aaa) { printf("%.*s", aaa, jsonStr + (i * 100)); }
+			printf("\r\n");
+			break;
+		}
+	}
+	RyanJsonFree(jsonStr);
+}
+
+static RyanJsonBool_e RyanJsonFuzzerTestByParseAndPrint(RyanJson_t pJson, const char *data, int32_t size)
+{
+
+	int32_t len = 0;
+	char *jsonStr = RyanJsonPrint(pJson, 100, size % 2 ? RyanJsonFalse : RyanJsonTrue, &len); // 以带格式方式将数据打印出来
+	// printf("len222222222222222222: %d\r\n", len);
+	RyanJsonCheckReturnFlase(NULL != jsonStr && len > 0);
+	RyanJsonFree(jsonStr);
+
+	{
+		int32_t bufLen = len * 3;
+		if (bufLen < 8192) { bufLen = 8192; }
+		char *buf = malloc((size_t)bufLen);
+
+		int32_t len2 = 0;
+		char *jsonStr2 = RyanJsonPrintPreallocated(pJson, buf, bufLen, size % 2 ? RyanJsonFalse : RyanJsonTrue, &len2);
+		// printf("len: %d, len2: %d, str: %s\r\n", len, len2, NULL == jsonStr2 ? "NULL" : jsonStr2);
+		if (buf)
+		{
+			RyanJsonCheckCode(NULL != jsonStr2 && len == len2, {
+				free(buf);
+				return RyanJsonFalse;
+			});
+
+			free(buf);
+		}
+	}
+
+	{
+		int32_t bufLen = size * 3;
+		char *buf = malloc((size_t)bufLen);
+		if (buf)
+		{
+			memset(buf, 0, (size_t)bufLen);
+			memcpy(buf, data, (size_t)size);
+			RyanJson_t jsonRoot = RyanJsonParse(buf);
+			RyanJsonCheckCode(NULL != jsonRoot, {
+				free(buf);
+				return RyanJsonFalse;
+			});
+			free(buf);
+
+			int32_t len3 = 0;
+			char *jsonStr3 =
+				RyanJsonPrint(jsonRoot, 100, size % 2 ? RyanJsonFalse : RyanJsonTrue, &len3); // 以带格式方式将数据打印出来
+			// printf("len222222222222222222: %d\r\n", len);
+			RyanJsonCheckCode(NULL != jsonStr3 && len == len3, {
+				if (jsonStr3) { RyanJsonFree(jsonStr3); }
+				RyanJsonDelete(jsonRoot);
+				return RyanJsonFalse;
+			});
+
+			RyanJsonFree(jsonStr3);
+
+			RyanJsonDelete(jsonRoot);
+		}
+	}
+
+	return RyanJsonTrue;
+}
+
+static RyanJsonBool_e RyanJsonFuzzerTestByDup(RyanJson_t pJson)
+{
+	RyanJsonBool_e result = RyanJsonTrue;
+	char *jsonStr = NULL;
+	char *jsonStrDup = NULL;
+	RyanJson_t pJsonDup = NULL;
+
+	// 测试打印和复制功能
+	int32_t len = 0;
+
+	jsonStr = RyanJsonPrint(pJson, 100, RyanJsonFalse, &len); // 以带格式方式将数据打印出来
+	RyanJsonCheckGotoExit(NULL != jsonStr && len > 0);
+
+	pJsonDup = RyanJsonDuplicate(pJson);
+	RyanJsonCheckGotoExit(NULL != pJsonDup);
+
+	// 测试dup失败情况
+	RyanJsonCheckGotoExit(NULL == RyanJsonDuplicate(NULL));
+
+	// 判断复制json的size是否一致
+	RyanJsonCheckGotoExit(0 == RyanJsonGetSize(NULL));
+	RyanJsonCheckGotoExit(RyanJsonGetSize(pJson) == RyanJsonGetSize(pJsonDup));
+	RyanJsonCompare(pJson, pJsonDup);
+	RyanJsonCompareOnlyKey(pJson, pJsonDup);
+	// assert(RyanJsonTrue == RyanJsonCompare(pJson, pJsonDup)); // 大浮点数判断容易出错
+	// RyanJsonCheckGotoExit(RyanJsonTrue == RyanJsonCompareOnlyKey(pJson, pJsonDup)); // 重复key也会失败
+
+	// 测试compare特殊情况
+	RyanJsonCheckGotoExit(RyanJsonTrue == RyanJsonCompare(pJson, pJson));
+	RyanJsonCheckGotoExit(RyanJsonFalse == RyanJsonCompare(NULL, pJsonDup));
+	RyanJsonCheckGotoExit(RyanJsonFalse == RyanJsonCompare(pJson, NULL));
+	RyanJsonCheckGotoExit(RyanJsonFalse == RyanJsonCompare(NULL, NULL));
+
+	// 测试compareKey特殊情况
+	RyanJsonCheckGotoExit(RyanJsonTrue == RyanJsonCompareOnlyKey(pJson, pJson));
+	RyanJsonCheckGotoExit(RyanJsonFalse == RyanJsonCompareOnlyKey(NULL, pJsonDup));
+	RyanJsonCheckGotoExit(RyanJsonFalse == RyanJsonCompareOnlyKey(pJson, NULL));
+	RyanJsonCheckGotoExit(RyanJsonFalse == RyanJsonCompareOnlyKey(NULL, NULL));
+
+	int32_t dupLen = 0;
+	jsonStrDup = RyanJsonPrint(pJsonDup, 100, RyanJsonFalse, &dupLen); // 以带格式方式将数据打印出来
+	RyanJsonCheckGotoExit(NULL != jsonStrDup && dupLen > 0);
+
+	RyanJsonCheckCode(len == dupLen && 0 == memcmp(jsonStr, jsonStrDup, (size_t)len), {
+		printf("len:%d, dupLen:%d\r\n", len, dupLen);
+		printf("jsonStr:%s, jsonStrDup:%s\r\n", jsonStr, jsonStrDup);
+		RyanJsonCheckGotoExit(0);
+	});
+
+	if (RyanJsonIsArray(pJson) || RyanJsonIsObject(pJson))
+	{
+		// 测试size不相等
+		RyanJsonDelete(RyanJsonDetachByIndex(pJson, 0));
+
+		if (RyanJsonIsArray(pJson) || RyanJsonIsObject(pJson))
+		{
+			// 改变key
+			RyanJson_t item;
+			RyanJsonObjectForEach(pJson, item)
+			{
+				if (RyanJsonIsKey(item))
+				{
+					RyanJsonChangeKey(item, "key12231123");
+					break;
+				}
+			}
+
+			// 改变value
+			RyanJsonObjectForEach(pJson, item)
+			{
+				if (RyanJsonIsBool(item))
+				{
+					RyanJsonChangeBoolValue(item, !RyanJsonGetBoolValue(item));
+					break;
+				}
+			}
+
+			// 改变obj的key
+			RyanJsonObjectForEach(pJson, item)
+			{
+				if (RyanJsonIsKey(item) && RyanJsonIsObject(item))
+				{
+					RyanJsonChangeKey(item, "key12231123");
+					break;
+				}
+			}
+		}
+
+		RyanJsonCompare(pJson, pJsonDup);
+		RyanJsonCompareOnlyKey(pJson, pJsonDup);
+	}
+__exit:
+
+	if (jsonStr)
+	{
+		RyanJsonFree(jsonStr);
+		jsonStr = NULL;
+	}
+	if (pJsonDup)
+	{
+		RyanJsonDelete(pJsonDup);
+		pJsonDup = NULL;
+	}
+	if (jsonStrDup)
+	{
+		RyanJsonFree(jsonStrDup);
+		jsonStrDup = NULL;
+	}
+
+	return result;
+}
+
+static RyanJsonBool_e RyanJsonFuzzerTestByForEachChange(RyanJson_t pJson, int32_t size)
+{
+	RyanJsonIsNull(pJson);
+
+	if (RyanJsonIsKey(pJson))
+	{
+		char *key = malloc(strlen(RyanJsonGetKey(pJson)) + 1);
+		if (key)
+		{
+
+			memset(key, 0, strlen(RyanJsonGetKey(pJson)) + 1);
+			memcpy(key, RyanJsonGetKey(pJson), strlen(RyanJsonGetKey(pJson)));
+
+			RyanJsonChangeKey(pJson, "key");
+			RyanJsonChangeKey(pJson, key);
+			free(key);
+		}
+	}
+	if (RyanJsonIsBool(pJson)) { RyanJsonChangeBoolValue(pJson, !RyanJsonGetBoolValue(pJson)); }
+	if (RyanJsonIsNumber(pJson))
+	{
+		if (RyanJsonIsInt(pJson))
+		{
+			int32_t value = RyanJsonGetIntValue(pJson);
+			RyanJsonChangeIntValue(pJson, size);
+			RyanJsonChangeIntValue(pJson, value);
+		}
+		if (RyanJsonIsDouble(pJson))
+		{
+			double value = RyanJsonGetDoubleValue(pJson);
+			RyanJsonChangeDoubleValue(pJson, size * 1.123456789);
+			RyanJsonChangeDoubleValue(pJson, value);
+		}
+	}
+
+	if (RyanJsonIsString(pJson))
+	{
+		char *value = malloc(strlen(RyanJsonGetStringValue(pJson)) + 1);
+		if (value)
+		{
+			memset(value, 0, strlen(RyanJsonGetStringValue(pJson)) + 1);
+			memcpy(value, RyanJsonGetStringValue(pJson), strlen(RyanJsonGetStringValue(pJson)));
+
+			RyanJsonChangeStringValue(pJson, "hello world");
+			RyanJsonChangeStringValue(pJson, value);
+
+			free(value);
+		}
+	}
+
+	if (RyanJsonIsArray(pJson) || RyanJsonIsObject(pJson))
+	{
+		RyanJson_t item;
+		if (RyanJsonIsArray(pJson))
+		{
+			RyanJsonArrayForEach(pJson, item)
+			{ RyanJsonCheckReturnFlase(RyanJsonTrue == RyanJsonFuzzerTestByForEachChange(item, size)); }
+		}
+		else
+		{
+			RyanJsonObjectForEach(pJson, item)
+			{ RyanJsonCheckReturnFlase(RyanJsonTrue == RyanJsonFuzzerTestByForEachChange(item, size)); }
+		}
+	}
+
+	return RyanJsonTrue;
+}
+
+static RyanJsonBool_e RyanJsonFuzzerTestByForEachGet2(RyanJson_t lastJson, RyanJson_t pJson, int32_t index, int32_t size)
+{
+	RyanJsonIsNull(pJson);
+
+	if (RyanJsonIsKey(pJson)) { RyanJsonGetObjectToKey(lastJson, RyanJsonGetKey(pJson)); }
+	else
+	{
+		RyanJsonGetObjectToIndex(lastJson, index);
+	}
+
+	if (RyanJsonIsArray(pJson) || RyanJsonIsObject(pJson))
+	{
+		RyanJson_t item;
+		RyanJsonObjectForEach(pJson, item) { RyanJsonFuzzerTestByForEachGet2(pJson, item, index, size); }
+	}
+
+	return RyanJsonTrue;
+}
+
+static RyanJsonBool_e RyanJsonFuzzerTestByForEachGet(RyanJson_t pJson, int32_t size)
+{
+	if (RyanJsonIsArray(pJson) || RyanJsonIsObject(pJson))
+	{
+		RyanJson_t item;
+		int32_t index = 0;
+		RyanJsonObjectForEach(pJson, item)
+		{
+			RyanJsonFuzzerTestByForEachGet2(pJson, item, index, size);
+			index++;
+		}
+	}
+	return RyanJsonTrue;
+}
+
+static RyanJson_t RyanJsonFuzzerTestalkdfjald(RyanJson_t pJson)
+{
+	static int32_t count = 0;
+	static int32_t count2 = 0;
+	count++;
+	char *key = "true";
+	if (count % 10 > 5) { key = NULL; }
+	switch (count % 50)
+	{
+	case 0: return RyanJsonCreateArray();
+	case 1: return RyanJsonCreateObject();
+	case 2:
+		count2++;
+		if (0 == count2 % 10) { return RyanJsonDuplicate(pJson); }
+	case 11:
+	case 12:
+	case 13: return RyanJsonCreateBool(key, RyanJsonTrue);
+	case 20:
+	case 21:
+	case 22: return RyanJsonCreateInt(key, count);
+	case 31:
+	case 32:
+	case 33: return RyanJsonCreateDouble(key, count * 1.123456789);
+
+	default: return RyanJsonCreateString(key, "true");
+	}
+}
+
+static RyanJsonBool_e RyanJsonFuzzerTestByForEachCreate(RyanJson_t pJson, int32_t size)
+{
+	// RyanJsonInsert的特殊情况
+	RyanJsonCheckReturnFlase(RyanJsonFalse == RyanJsonInsert(NULL, INT32_MAX, RyanJsonCreateString("key", "string")));
+	RyanJsonCheckReturnFlase(RyanJsonFalse == RyanJsonInsert(pJson, -10, RyanJsonCreateString("key", "string")));
+	RyanJsonCheckReturnFlase(RyanJsonFalse == RyanJsonInsert(pJson, INT32_MAX, NULL));
+	RyanJsonCheckReturnFlase(RyanJsonFalse == RyanJsonInsert(NULL, -10, NULL));
+
+	char *key = "keyaaa";
+	RyanJsonAddNullToObject(pJson, key);
+	if (RyanJsonIsKey(pJson)) { key = RyanJsonGetKey(pJson); }
+	if (RyanJsonIsBool(pJson)) { RyanJsonAddBoolToObject(pJson, key, RyanJsonGetBoolValue(pJson)); }
+	if (RyanJsonIsNumber(pJson))
+	{
+		if (RyanJsonIsInt(pJson))
+		{
+			RyanJsonAddIntToObject(pJson, key, RyanJsonGetIntValue(pJson));
+			int arrayInt[] = {RyanJsonGetIntValue(pJson), RyanJsonGetIntValue(pJson), RyanJsonGetIntValue(pJson),
+					  RyanJsonGetIntValue(pJson), RyanJsonGetIntValue(pJson)};
+			RyanJsonAddItemToObject(pJson, (size % 2) ? key : "arrayString",
+						RyanJsonCreateIntArray(arrayInt, sizeof(arrayInt) / sizeof(arrayInt[0])));
+		}
+		if (RyanJsonIsDouble(pJson))
+		{
+			RyanJsonAddDoubleToObject(pJson, key, RyanJsonGetDoubleValue(pJson));
+			double arrayDouble[] = {RyanJsonGetDoubleValue(pJson), RyanJsonGetDoubleValue(pJson), RyanJsonGetDoubleValue(pJson),
+						RyanJsonGetDoubleValue(pJson), RyanJsonGetDoubleValue(pJson)};
+			RyanJsonAddItemToObject(pJson, (size % 2) ? key : "arrayString",
+						RyanJsonCreateDoubleArray(arrayDouble, sizeof(arrayDouble) / sizeof(arrayDouble[0])));
+		}
+	}
+
+	if (RyanJsonIsString(pJson))
+	{
+		RyanJsonAddStringToObject(pJson, key, RyanJsonGetStringValue(pJson));
+		const char *arrayString[] = {RyanJsonGetStringValue(pJson), RyanJsonGetStringValue(pJson), RyanJsonGetStringValue(pJson),
+					     RyanJsonGetStringValue(pJson), RyanJsonGetStringValue(pJson)};
+		RyanJsonAddItemToObject(pJson, (size % 2) ? key : "arrayString",
+					RyanJsonCreateStringArray(arrayString, sizeof(arrayString) / sizeof(arrayString[0])));
+	}
+
+	if (RyanJsonIsArray(pJson) || RyanJsonIsObject(pJson))
+	{
+		RyanJson_t item;
+
+		RyanJsonObjectForEach(pJson, item) { RyanJsonFuzzerTestByForEachCreate(item, size); }
+
+		RyanJson_t pJson2 = RyanJsonFuzzerTestalkdfjald(pJson);
+		RyanJsonAddItemToObject(pJson, key, pJson2);
+
+		if (RyanJsonIsArray(pJson))
+		{
+			RyanJsonAddNullToArray(pJson);
+			RyanJsonAddBoolToArray(pJson, size % 2 ? RyanJsonTrue : RyanJsonFalse);
+			RyanJsonAddItemToArray(pJson, RyanJsonFuzzerTestalkdfjald(RyanJsonGetArrayValue(pJson)));
+		}
+	}
+
+	return RyanJsonTrue;
+}
+
+/**
+ * @brief 测试 Json 的 Replace 功能(保护根节点)
+ *
+ * @param pJson 待测试的 Json 节点
+ * @param size  用于计算 index 的模数
+ * @param isFirst 是否为第一次调用(根节点)
+ * @return RyanJsonBool_e
+ */
+static RyanJsonBool_e RyanJsonFuzzerTestByForEachReplace(RyanJson_t pJson, int32_t size)
+{
+	// 只处理数组或对象
+	if (!(RyanJsonIsArray(pJson) || RyanJsonIsObject(pJson))) { return RyanJsonTrue; }
+
+	// 递归替换子节点
+	RyanJson_t item = NULL;
+	RyanJson_t LastItem = NULL;
+	RyanJsonObjectForEach(pJson, item)
+	{
+		if (RyanJsonTrue != RyanJsonFuzzerTestByForEachReplace(item, size)) { return RyanJsonFalse; }
+		LastItem = item;
+	}
+
+	// 只有非根节点才做替换
+
+	// 按 key 替换(仅对象)
+	// 不要动第一个节点
+	if (RyanJsonIsObject(pJson))
+	{
+		if (LastItem && RyanJsonIsKey(LastItem))
+		{
+			RyanJson_t newNode = RyanJsonFuzzerTestalkdfjald(pJson);
+			if (RyanJsonFalse == RyanJsonReplaceByKey(pJson, RyanJsonGetKey(LastItem), newNode))
+			{
+				if (newNode) { RyanJsonDelete(newNode); }
+				return RyanJsonFalse;
+			}
+		}
+	}
+
+	// 按 index 替换
+	{
+		int32_t idx = RyanJsonGetSize(pJson) % size;
+		RyanJson_t newNode = RyanJsonFuzzerTestalkdfjald(pJson);
+		if (RyanJsonFalse == RyanJsonReplaceByIndex(pJson, (size % 25) ? idx : 0, newNode))
+		{
+			if (newNode) { RyanJsonDelete(newNode); }
+			return RyanJsonFalse;
+		}
+	}
+
+	return RyanJsonTrue;
+}
+
+/**
+ * @brief 测试 Json 的 Detach 分离功能(保护根节点)
+ *
+ * @param pJson 待测试的 Json 节点
+ * @param size  用于计算 index 的模数
+ * @param isFirst 是否为第一次调用(根节点)
+ * @return RyanJsonBool_e
+ */
+static RyanJsonBool_e RyanJsonFuzzerTestByForEachDetach(RyanJson_t pJson, int32_t size)
+{
+	if (!(RyanJsonIsArray(pJson) || RyanJsonIsObject(pJson))) { return RyanJsonTrue; }
+
+	// 递归遍历子节点
+	RyanJson_t item = NULL;
+	RyanJson_t LastItem = NULL;
+	RyanJsonObjectForEach(pJson, item)
+	{
+		RyanJsonFuzzerTestByForEachDetach(item, size);
+		LastItem = item;
+	}
+
+	// 只有非根节点才做 detach
+
+	// 按 key 分离(仅对象)
+	if (RyanJsonIsObject(pJson))
+	{
+		if (LastItem && RyanJsonIsKey(LastItem))
+		{
+			RyanJson_t detached = RyanJsonDetachByKey(pJson, RyanJsonGetKey(LastItem));
+			if (detached) { RyanJsonDelete(detached); }
+		}
+	}
+
+	// 按 index 分离
+	{
+		int32_t idx = RyanJsonGetSize(pJson) % size;
+		RyanJson_t detached = RyanJsonDetachByIndex(pJson, (size % 25) ? idx : 0);
+		if (detached) { RyanJsonDelete(detached); }
+	}
+
+	return RyanJsonTrue;
+}
+
+/**
+ * @brief 测试 Json 的 Delete 功能(保护根节点)
+ *
+ * @param pJson 待测试的 Json 节点
+ * @param size  用于计算 index 的模数
+ * @param isFirst 是否为第一次调用(根节点)
+ * @return RyanJsonBool_e
+ */
+static RyanJsonBool_e RyanJsonFuzzerTestByForEachDelete(RyanJson_t pJson, int32_t size)
+{
+	if (!(RyanJsonIsArray(pJson) || RyanJsonIsObject(pJson))) { return RyanJsonTrue; }
+
+	// -------- 测试错误的 delete 调用 --------
+	// Key 删除错误用例
+	RyanJsonDeleteByKey(pJson, "non_exist_key");
+	RyanJsonDeleteByKey(NULL, "some_key");
+	RyanJsonDeleteByKey(pJson, NULL);
+	RyanJsonDeleteByKey(NULL, NULL);
+
+	// Index 删除错误用例
+	RyanJsonDeleteByIndex(pJson, RyanJsonGetSize(pJson)); // 越界
+	RyanJsonDeleteByIndex(NULL, (RyanJsonGetSize(pJson) % size));
+	RyanJsonDeleteByIndex(pJson, -size); // 负数
+	RyanJsonDeleteByIndex(NULL, -size);
+
+	// 递归遍历子节点
+	RyanJson_t item = NULL;
+	RyanJson_t LastItem = NULL;
+	RyanJsonObjectForEach(pJson, item)
+	{
+		RyanJsonFuzzerTestByForEachDelete(item, size);
+		LastItem = item;
+	}
+
+	// -------- 正常删除逻辑(保护根节点) --------
+
+	// 按 key 删除(仅对象)
+	if (RyanJsonIsObject(pJson))
+	{
+		if (LastItem && RyanJsonIsKey(LastItem))
+		{
+			// RyanPrintJsonToLog22(pJson);
+
+			// printf("key is %d %s\r\n", RyanJsonGetType(LastItem),
+			//        RyanJsonGetKey(LastItem) == NULL ? "NULL" : RyanJsonGetKey(LastItem));
+			RyanJsonDeleteByKey(pJson, RyanJsonGetKey(LastItem));
+		}
+	}
+
+	// 按 index 删除
+	int32_t idx = RyanJsonGetSize(pJson) % size;
+	RyanJsonDeleteByIndex(pJson, (size % 25) ? idx : 0);
+
+	return RyanJsonTrue;
+}
+
+static RyanJsonBool_e RyanJsonFuzzerTestByMinify(const char *data, int32_t size)
+{
+	char *buf = malloc(size + 100);
+	memset(buf, 0, size + 100);
+	memcpy(buf, data, size);
+
+	int32_t size2 = RyanJsonMinify(buf, size);
+	// 非法情况
+	{
+		RyanJsonCheckReturnFlase(0 == RyanJsonMinify(NULL, 0));
+		RyanJsonCheckReturnFlase(0 == RyanJsonMinify(NULL, 10));
+		RyanJsonCheckReturnFlase(0 == RyanJsonMinify(NULL, -10));
+		RyanJsonCheckReturnFlase(0 == RyanJsonMinify(buf, -10));
+	}
+	RyanJson_t pJson2 = RyanJsonParseOptions(buf, size2, size % 2 ? RyanJsonTrue : RyanJsonFalse, NULL);
+	free(buf);
+	if (NULL != pJson2)
+	{
+		int32_t len = 0;
+		char *jsonStr = RyanJsonPrint(pJson2, 100, RyanJsonFalse, &len); // 以带格式方式将数据打印出来
+		RyanJsonCheckCode(NULL != jsonStr && len > 0, {
+			RyanJsonDelete(pJson2);
+			return RyanJsonFalse;
+		});
+		RyanJsonFree(jsonStr);
+		RyanJsonDelete(pJson2);
+	}
+	else
+	{
+		return RyanJsonFalse;
+	}
+
+	return RyanJsonTrue;
+}
+
+static void *RyanJsonFuzzerMalloc(size_t size)
+{
+	static int32_t count = 0;
+	count++;
+	if (RyanJsonTrue == isadfa)
+	{
+		if (0 == count % 709) { return NULL; }
+	}
+	return (char *)v_malloc(size);
+}
+
+static void RyanJsonFuzzerFree(void *block) { v_free(block); }
+
+static void *RyanJsonFuzzerRealloc(void *block, size_t size)
+{
+	static int32_t count = 0;
+	count++;
+	if (RyanJsonTrue == isadfa)
+	{
+		if (0 == count % 708) { return NULL; }
+	}
+	return (char *)v_realloc(block, size);
+}
+
+// 需要模拟内存故障
+// tokey需要增加s测试
+int LLVMFuzzerTestOneInput(const char *data, int32_t size)
+{
+
+	// !检查分支覆盖率的时候要把这个取消掉,否则不知道是这个测试用例还是Fuzzer触发的,期望的是Fuzzer触发
+	// {
+	// 	// 执行基础测试
+	// 	static bool isFirst = true;
+	// 	if (true == isFirst)
+	// 	{
+	// 		RyanJsonBool_e result = RyanJsonBaseTest();
+	// 		if (RyanJsonTrue != result)
+	// 		{
+	// 			printf("%s:%d RyanJsonTest fail\r\n", __FILE__, __LINE__);
+	// 			return -1;
+	// 		}
+
+	// 		result = RFC8259JsonTest();
+	// 		// if (RyanJsonTrue != result)
+	// 		// {
+	// 		// 	printf("%s:%d RFC8259JsonTest fail\r\n", __FILE__, __LINE__);
+	// 		// 	return -1;
+	// 		// }
+	// 		isFirst = false;
+	// 	}
+	// }
+
+	// for (int i = 0; i < size; i++) { printf("%c", size, data[i]); }
+	// printf("\r\n");
+
+	RyanJsonInitHooks(RyanJsonFuzzerMalloc, RyanJsonFuzzerFree, size % 2 ? NULL : RyanJsonFuzzerRealloc);
+
+	const char *parseEndPtr = NULL;
+	RyanJson_t pJson = RyanJsonParseOptions(data, size, size % 2 ? RyanJsonTrue : RyanJsonFalse, &parseEndPtr);
+	if (NULL != pJson)
+	{
+		assert(NULL != parseEndPtr && parseEndPtr - data <= size);
+
+		{
+			isadfa = RyanJsonFalse;
+			RyanJson_t pJson2 = RyanJsonDuplicate(pJson);
+			isadfa = RyanJsonTrue;
+			RyanJsonCheckCode(RyanJsonFuzzerTestByForEachDelete(pJson2, size), {
+				RyanJsonDelete(pJson2);
+				goto __exit;
+			});
+			RyanJsonDelete(pJson2);
+		}
+
+		{
+			isadfa = RyanJsonFalse;
+			RyanJson_t pJson2 = RyanJsonDuplicate(pJson);
+			isadfa = RyanJsonTrue;
+			RyanJsonCheckCode(RyanJsonFuzzerTestByForEachDetach(pJson2, size), {
+				RyanJsonDelete(pJson2);
+				goto __exit;
+			});
+			RyanJsonDelete(pJson2);
+		}
+
+		RyanJsonFuzzerTestByMinify(data, size);
+		RyanJsonFuzzerTestByParseAndPrint(pJson, data, size);
+		RyanJsonFuzzerTestByForEachGet(pJson, size);
+
+		RyanJsonFuzzerTestByDup(pJson);
+		RyanJsonCheckCode(RyanJsonFuzzerTestByForEachChange(pJson, size), { goto __exit; });
+		RyanJsonCheckCode(RyanJsonFuzzerTestByForEachCreate(pJson, size), { goto __exit; });
+
+		RyanJsonCheckCode(RyanJsonFuzzerTestByForEachReplace(pJson, size), { goto __exit; });
+
+		// 测试打印和复制功能
+		RyanJsonDelete(pJson);
+	}
+
+	// cJSON_Hooks hooks = {.malloc_fn = v_malloc, .free_fn = v_free};
+	// cJSON_InitHooks(&hooks);
+
+	// cJSON *json = cJSON_ParseWithLength(data, size);
+	// if (json)
+	// {
+
+	// 	char *str2 = cJSON_Print(json);
+	// 	cJSON_free(str2);
+	// 	cJSON_Delete(json);
+	// }
+
+	// RyanJsonMinify(data);
+	return 0;
+
+__exit:
+	RyanJsonDelete(pJson);
+	return 0;
+}

+ 172 - 0
test/fuzzer/RyanJsonFuzzer.dict

@@ -0,0 +1,172 @@
+# 基本关键字
+"true"
+"false"
+"null"
+
+# 对象结构
+"{"
+"}"
+":"
+","
+
+# 数组结构
+"["
+"]"
+
+# 常见字符串模式
+"\"key\""
+"\"value\""
+"\"name\""
+"\"id\""
+"\"string\""
+"\"number\""
+"\"message\""
+"\"data\""
+"\"status\""
+"\"error\""
+
+# 数字边界
+"0"
+"1"
+"-1"
+"1234567890"
+"3.14159"
+"1e10"
+"-1e-10"
+"999999999999999999999999999"
+"-999999999999999999999999999"
+
+# 嵌套结构
+"{\"a\":1}"
+"[1,2,3]"
+"{\"obj\":{\"nested\":true}}"
+"{\"arr\":[{\"x\":1},{\"y\":2}]}"
+"{\"deep\":{\"nest\":{\"more\":{\"inner\":{\"flag\":true}}}}}"
+"[{\"id\":1,\"val\":true},{\"id\":2,\"val\":false}]"
+
+# 复杂对象
+"{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}"
+"{\"items\":[{\"id\":1},{\"id\":2},{\"id\":3}]}"
+"{\"user\":{\"id\":123,\"name\":\"Alice\",\"roles\":[\"admin\",\"editor\"]}}"
+"{\"response\":{\"status\":200,\"data\":[{\"id\":1},{\"id\":2}]}}"
+
+# 空结构
+"{}"
+"[]"
+
+# 特殊转义
+"\\n"
+"\\r"
+"\\t"
+"\\b"
+"\\f"
+"\\u0000"
+"\\uD800\\uDC00"
+"\\uDBFF\\uDFFF"
+"\\\""
+"\\\\"
+"/"
+
+# 一维对象,覆盖所有 JSON 类型
+"{\"string\":\"hello\",\"number\":123,\"boolean_true\":true,\"boolean_false\":false,\"null_value\":null,\"array\":[1,\"two\",false,null],\"object\":{\"nested_key\":\"nested_value\"}}"
+
+# 错误重复结构
+"[{\"error\":4,\"error\":\"45\"}]"
+"[{\"id\":1,\"id\":2}]"
+"[{\"name\":\"Alice\",\"name\":\"Bob\"}]"
+"[{\"value\":true,\"value\":false}]"
+"[{\"unicode\":\"\\u4F60\\u597D\",\"unicode\":\"\\u4E16\\u754C\"}]"
+"[{\"data\":[1,2,3],\"data\":{\"x\":1}}]"
+"[{\"nested\":{\"a\":1},\"nested\":{\"a\":2}}]"
+"[{\"error\":null,\"error\":999}]"
+"[{\"flag\":false,\"flag\":true}]"
+"[{\"number\":123,\"number\":\"123\"}]"
+"[{\"list\":[1,2],\"list\":[3,4]}]"
+
+# Unicode 示例(转义形式)
+"{\"unicode\":\"\\u4F60\\u597D\"}"
+"{\"unicode\":\"\\u4E16\\u754C\"}"
+"{\"unicode\":\"\\uD83C\\uDF0D\"}"
+"{\"unicode\":\"\\uD83D\\uDE00\"}"
+# 孤立高代理
+"{\"unicode\":\"\\uD800\"}" 
+# 孤立低代理         
+"{\"unicode\":\"\\uDFFF\"}"  
+# 超出最大码点        
+"{\"unicode\":\"\\u110000\"}" 
+ # 非十六进制       
+"{\"unicode\":\"\\uZZZZ\"}"    
+# 位数不足     
+"{\"unicode\":\"\\u12\"}"     
+# 错误代理配对       
+"{\"unicode\":\"\\uD800\\u0041\"}"   
+
+# RESTful 风格常见响应
+"{\"status\":200,\"message\":\"OK\"}"
+"{\"status\":404,\"error\":\"Not Found\"}"
+"{\"status\":500,\"error\":\"Internal Server Error\"}"
+"{\"status\":401,\"error\":\"Unauthorized\"}"
+"{\"status\":403,\"error\":\"Forbidden\"}"
+
+# RESTful 数据响应
+"{\"status\":200,\"data\":{\"id\":1,\"name\":\"Alice\"}}"
+"{\"status\":200,\"data\":[{\"id\":1,\"name\":\"Alice\"},{\"id\":2,\"name\":\"Bob\"}]}"
+"{\"status\":200,\"data\":{\"items\":[{\"id\":1,\"value\":true},{\"id\":2,\"value\":false}]}}"
+
+# RESTful 分页响应
+"{\"status\":200,\"page\":1,\"pageSize\":10,\"total\":100,\"data\":[{\"id\":1},{\"id\":2}]}"
+"{\"status\":200,\"meta\":{\"page\":2,\"limit\":20},\"data\":[{\"id\":21},{\"id\":22}]}"
+
+# RESTful 错误响应
+"{\"error\":{\"code\":1234,\"message\":\"Invalid request\"}}"
+"{\"error\":{\"code\":5678,\"message\":\"Timeout\"}}"
+
+# RESTful 复杂响应
+"{\"status\":200,\"user\":{\"id\":123,\"name\":\"Alice\",\"roles\":[\"admin\",\"editor\"]},\"token\":\"abcdef123456\"}"
+"{\"status\":200,\"config\":{\"theme\":\"dark\",\"language\":\"en\"},\"features\":[\"chat\",\"upload\",\"search\"]}"
+
+# 循环/深度嵌套场景
+"{\"a\":{\"b\":{\"c\":{\"d\":{\"e\":{\"f\":{\"g\":true}}}}}}}"
+"[[[[[[[[[[1]]]]]]]]]]"
+"[{\"a\":[{\"b\":[{\"c\":[{\"d\":true}]}]}]}]"
+"{\"a\":[{\"b\":[{\"c\":[{\"d\":[{\"e\":false}]}]}]}]}"
+"{\"node\":{\"id\":1,\"child\":{\"id\":2,\"child\":{\"id\":3,\"child\":{\"id\":4}}}}}"
+"{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":{\"x\":null}}}}}}"
+"{\"status\":200,\"data\":{\"items\":[{\"id\":1,\"children\":[{\"id\":2,\"children\":[{\"id\":3}]}]}]}}"
+"{\"mixed\":[{\"obj\":{\"arr\":[{\"obj\":{\"arr\":[{\"obj\":{\"arr\":[true]}]}]}]}}]}"
+
+# 极端情况
+"{\"long\":\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}"
+"{\"big\":999999999999999999999999999}"
+"[[],[],[],[],[],[],[],[],[],[]]"
+"{\"nestedArray\":[[1,2],[3,4],[5,[6,[7,[8]]]]]}"
+"{\"escape\":\"line1\\nline2\\tTabbed\"}"
+"{\"mixed\":[16,16.89,\"hello\",true,false,null,{\"deep\":{}}]}"
+
+# 非法/边界片段(测试错误处理)
+",{}"
+":[]"
+"[[]]"
+"{{}}"
+",[]"
+":{}"
+"''"
+"\\x00"
+"\\0"
+
+"//"
+"/**/"
+
+"\x01\x00"
+"\x00\x00\x00\x00"
+"\x00\x00\x00\x00\x00\x00\x00\x00"
+"\x00\x00\x00\x00\x00\x00\x00\x01"
+"\x01\x00\x00\x00\x00\x00\x00\x00"
+"\x10\x00\x00\x00\x00\x00\x00\x00"
+
+"\xff\xff"
+"\xfe\xff\xff\xee"
+"\xff\xff\xff\xff"
+"\xfe\xff\xff\xff\xff\xff\xff\xfa"
+"\xfb\xff\xff\xff\xff\xff\xff\xff"
+"\xff\xff\xff\xff\xff\xff\xff\xff"

+ 26 - 35
test/valloc/valloc.c

@@ -5,28 +5,23 @@
 #include <unistd.h>
 #include "valloc.h"
 
-#define HEADER_SIZE sizeof(int)
+#define HEADER_SIZE        sizeof(int)
+#define MALLOC_HEADER_SIZE 12
 
 static int count = 0;
 static int use = 0;
 
 void *v_malloc(size_t size)
 {
-	if (size == 0)
-	{
-		return NULL;
-	}
+	if (size == 0) { return NULL; }
 
 	void *p = malloc(size + HEADER_SIZE);
-	if (!p)
-	{
-		return NULL;
-	}
+	if (!p) { return NULL; }
 
 	*(int *)p = (int)size;
 
 	count++;
-	use += (int)size;
+	use += (int)size + MALLOC_HEADER_SIZE;
 
 	return (char *)p + HEADER_SIZE;
 }
@@ -35,25 +30,19 @@ void *v_calloc(size_t num, size_t size)
 {
 	size_t total = num * size;
 	void *p = v_malloc(total);
-	if (p)
-	{
-		memset(p, 0, total);
-	}
+	if (p) { memset(p, 0, total); }
 	return p;
 }
 
 void v_free(void *block)
 {
-	if (!block)
-	{
-		return;
-	}
+	if (!block) { return; }
 
 	void *p = (char *)block - HEADER_SIZE;
 	int size = *(int *)p;
 
 	count--;
-	use -= size;
+	use -= size + MALLOC_HEADER_SIZE;
 
 	free(p);
 }
@@ -76,17 +65,11 @@ void *v_realloc(void *block, size_t size)
 	}
 
 	void *p = realloc(raw, size + HEADER_SIZE);
-	if (!p)
-	{
-		return NULL;
-	}
+	if (!p) { return NULL; }
 
 	*(int *)p = (int)size;
 
-	if (!block)
-	{
-		count++;
-	}
+	if (!block) { count++; }
 	use += (int)(size - old_size);
 
 	return (char *)p + HEADER_SIZE;
@@ -94,17 +77,25 @@ void *v_realloc(void *block, size_t size)
 
 int v_mcheck(int *dstCount, int *dstUse)
 {
-	if (dstCount)
-	{
-		*dstCount = count;
-	}
-	if (dstUse)
-	{
-		*dstUse = use;
-	}
+	if (dstCount) { *dstCount = count; }
+	if (dstUse) { *dstUse = use; }
 	return 0;
 }
 
+int32_t vallocGetArea(void)
+{
+	int32_t area2 = 0, use2 = 0;
+	v_mcheck(&area2, &use2);
+	return area2;
+}
+
+int32_t vallocGetUse(void)
+{
+	int32_t area2 = 0, use2 = 0;
+	v_mcheck(&area2, &use2);
+	return use2;
+}
+
 void displayMem(void)
 {
 	int32_t area2 = 0, use2 = 0;

+ 3 - 0
test/valloc/valloc.h

@@ -16,6 +16,7 @@ extern "C" {
 #endif
 
 #include <stdlib.h>
+#include <stdint.h>
 
 extern void *v_malloc(size_t size);
 extern void *v_calloc(size_t num, size_t size);
@@ -24,6 +25,8 @@ extern void *v_realloc(void *block, size_t size);
 extern int v_mcheck(int *dstCount, int *dstUse);
 extern void displayMem(void);
 extern void vallocInit(void);
+extern int32_t vallocGetArea(void);
+extern int32_t vallocGetUse(void);
 
 #ifdef __cplusplus
 }

+ 90 - 50
xmake.lua

@@ -2,19 +2,43 @@ add_rules("plugin.compile_commands.autoupdate", {outputdir = ".vscode"})
 target("RyanJson",function()
     set_kind("binary")
 
-    set_toolchains("gcc")  -- 确保使用 GCC
+    -- set_toolchains("gcc")  -- 确保使用 GCC
+    set_toolchains("clang")
+    set_plat("linux")
+    set_arch("x86")
     set_languages("gnu99") -- 关键!启用 GNU 扩展
+    add_defines("isEnableFuzzer")
+    add_cxflags("-fsanitize=fuzzer", "-fprofile-instr-generate", "-fcoverage-mapping", {force = true} )
+    add_ldflags("-fsanitize=fuzzer", "-fprofile-instr-generate", "-fcoverage-mapping", {force = true} )
 
+    set_policy("build.ccache", false)
     -- set_optimize("smallest") -- -Os
-    set_optimize("faster") -- -O2
-    -- set_optimize("fastest") -- -O3
+    -- set_optimize("faster") -- -O2
+    set_optimize("fastest") -- -O3
     -- set_optimize("aggressive") -- -Ofast
 
     -- 启用全部警告
-    set_warnings("everything") -- -Wall -Wextra -Weffc++ / -Weverything
+    -- set_warnings("everything") -- -Wall -Wextra -Weffc++ / -Weverything
 
     -- 链接器选项:生成 map 文件
-    add_ldflags("-Wl,-Map=$(buildir)/RyanJson.map")
+    -- add_ldflags("-Wl,-Map=$(buildir)/RyanJson.map")
+
+    -- 开启库加固(需与 -O2 以上配合)
+    -- add_defines("_FORTIFY_SOURCE=2")   -- glibc 格式/内存函数加固
+
+    -- 链接器安全硬化与优化
+    add_ldflags(
+        -- "-flto",                    -- 链接时优化(启用 LTO,便于 CFI 等)
+        -- "-fPIE",                    -- 位置无关可执行
+        -- "-pie",                     -- 与 -fPIE 搭配,启用 ASLR
+        -- "-fno-omit-frame-pointer",  -- 保留帧指针,便于崩溃分析
+        -- "-fstack-clash-protection", -- 栈碰撞保护(平台支持时有效)
+        -- "-Wl,-z,relro",             -- 只读重定位(硬化)
+        -- "-Wl,-z,now",               -- 立即绑定(与 relro 搭配)
+        -- "-Wl,-z,noexecstack",       -- 栈不可执行
+        -- "-Wl,-z,separate-code",     -- 代码与数据段分离
+        {force = true}
+    )
 
     -- Sanitizer 检测项(运行时错误)
     add_ldflags(
@@ -26,55 +50,69 @@ target("RyanJson",function()
         "-fsanitize=bounds", -- 数组越界
         "-fsanitize=float-divide-by-zero", -- 浮点除零
         "-fsanitize=float-cast-overflow", -- 浮点转整数溢出
+        -- "-fsanitize=thread",      -- 多线程数据竞争
+        -- "-fsanitize=memory",      -- 未初始化内存使用
+        -- "-fsanitize=safe-stack",  -- 栈分离机制
+        -- "-fsanitize=cfi",         -- 控制流完整性(需 LTO 与 Clang)
         -- "-fsanitize=alignment", -- 检测未对齐的内存访问
-        "-fno-sanitize=alignment", -- 某些平台不兼容
+        -- "-fno-sanitize=alignment", -- 某些平台不兼容
         {force = true}
     )
 
-    -- 编译器警告与静态分析(开发期错误检测)
+    -- 编译器警告与静态分析(开发期错误检测,Clang 兼容
     add_cxflags(
-        -- "-flto", -- 链接时优化(可选)
-        "-pedantic", -- 强制遵循 ISO C/C++ 标准
-        "-Wall", -- 启用大多数常见警告
-        "-Wextra", -- 启用额外警告
-        "-fanalyzer", -- 启用 gcc 静态分析器
-        "-Wno-unused-parameter",
-        "-Wfloat-equal", -- 浮点直接比较
-        "-Wshadow", -- 局部变量遮蔽
-        "-Wcast-align", -- 类型转换对齐问题
-        "-Wpointer-arith", -- 指针运算
-        "-Warray-bounds=2", -- 数组越界访问(编译期可分析到的)
-        "-Wstringop-overflow=2", -- memcpy / strcpy 等可能的溢出
-        "-Wstringop-truncation", -- 字符串截断风险
-        "-Walloc-zero", -- malloc(0) 等分配 0 字节的情况
-        "-Wfree-nonheap-object", -- 释放非堆对象
-        -- "-Wconversion", -- 隐式类型转换可能导致精度丢失/溢出
-        "-Wnull-dereference", -- 空指针解引用
-        "-Wlogical-op", -- 逻辑运算符误用
-        "-Wstrict-overflow=5", -- 有符号溢出优化假设
-        "-Wmissing-prototypes", -- 未在头文件声明的全局函数
-        "-Wmissing-declarations", -- 未声明的全局变量/函数
-        "-Wredundant-decls", -- 重复声明
-        "-Wunreachable-code", -- 不可达代码
-        "-Wunsafe-loop-optimizations", -- 循环优化可能引入的问题
-        "-Wtype-limits", -- 比较恒真/恒假的表达式(如 unsigned < 0)
-        "-Wshift-overflow=2", -- 移位导致的溢出
-        "-Wshift-negative-value", -- 对负数进行移位
-        "-Wdiv-by-zero", -- 除以零(编译期可分析到的)
-        "-Wformat-security", -- 格式化字符串安全问题
+        "-g3",                  -- 生成调试信息"
+        "-pedantic",               -- 强制遵循 ISO C 标准
+        "-Wall",                   -- 常见警告
+        "-Wextra",                 -- 额外警告
+        "-Wconversion",            -- 隐式类型转换风险
+        "-Wsign-conversion",       -- 有符号/无符号转换风险
+        "-Wdouble-promotion",      -- float 自动提升为 double
+        "-Wstrict-prototypes",     -- 函数声明必须带参数类型
+        "-Wold-style-definition",  -- 检测旧式函数定义
+        "-Wimplicit-fallthrough",  -- switch/case 未显式 fallthrough
+        "-Wshadow",                -- 局部变量遮蔽
+        "-Wcast-align",            -- 类型转换对齐问题
+        "-Wpointer-arith",         -- 指针运算风险
+        "-Warray-bounds",          -- 数组越界访问
+        "-Wshift-overflow",        -- 位移造成的溢出
+        "-Wformat-truncation",     -- 格式化字符串被截断风险(替代 stringop-truncation)
+        "-Walloc-size",            -- 分配大小问题(替代 alloc-zero)
+        "-Wnull-dereference",      -- 空指针解引用
+        "-Wtautological-compare",  -- 恒真/恒假的比较
+        "-Wstrict-overflow",       -- 有符号溢出优化假设
+        "-Wmissing-prototypes",    -- 全局函数未在头文件声明
+        "-Wmissing-declarations",  -- 全局变量/函数未声明
+        "-Wredundant-decls",       -- 重复声明
+        "-Wunreachable-code",      -- 不可达代码
+        "-Wtype-limits",           -- 比较恒真/恒假的表达式(如 unsigned < 0)
+        "-Wshift-negative-value",  -- 对负数进行移位
+        "-Wdiv-by-zero",           -- 除以零(编译期可分析)
+        "-Wformat-security",       -- 格式化字符串安全问题
         "-Wdisabled-optimization", -- 被禁用的优化
-        -- "-Wwrite-strings", -- 将字符串字面量视为 const char[],防止被修改
-        "-Wreturn-local-addr", -- 返回局部变量地址
-        "-Wuse-after-free", -- 释放后使用(编译期可分析到的)
-        "-Wdangling-pointer=2", -- 悬空指针(GCC 12+)
-        "-fstack-protector-strong", -- 栈保护
-
-        -- clang 的兼容项(可选)
-        -- "-Wno-gnu-zero-variadic-macro-arguments",
-        -- "-Wno-c23-extensions",
+        "-Wreturn-local-addr",     -- 返回局部变量地址
+        "-Wdeprecated",            -- 使用已弃用的特性
+        -- "-Wunsafe-buffer-usage",   -- 不安全的数组/指针用法(Clang 新增)
+        "-Wuninitialized",         -- 使用未初始化变量
+        "-fstack-protector-strong",-- 栈保护
+        -- 进一步增强(可选,按需开启)
+        "-Wmissing-include-dirs",      -- 头文件目录缺失
+        "-Wcast-qual",                 -- 丢弃 const/volatile 限定符的转换
+        "-Wconditional-uninitialized", -- 条件路径未初始化
+        "-Wcovered-switch-default",    -- default 覆盖所有枚举值
+        "-Wformat-nonliteral",         -- 非字面量格式串
+        "-Wformat-signedness",         -- 格式化与符号性不匹配
+        "-Wvla",                       -- 可变长度数组(不安全/不建议使用)
+        "-fno-common",                 -- 禁止旧式多重定义(链接期更严格)
+        "-fno-strict-aliasing",        -- 禁止严格别名优化,减少别名相关 UB 风险
+        "-Wno-documentation", -- 临时变比
+        "-Wno-parentheses-equality",
         {force = true}
     )
 
+    add_includedirs('./test/fuzzer', {public = true})
+    add_files('./test/fuzzer/*.c', {public = true})
+
     --加入代码和头文件
     add_includedirs('./RyanJson', {public = true})
     add_files('./RyanJson/*.c', {public = true})
@@ -82,13 +120,15 @@ target("RyanJson",function()
     add_includedirs('./example', {public = true})
     add_includedirs('./test', {public = true})
     add_includedirs('./test/valloc', {public = true})
+    add_includedirs('./test/baseTest', {public = true})
     add_includedirs('./externalModule/cJSON', {public = true})
-    add_includedirs('./externalModule/yyjson', {public = true})
+    -- add_includedirs('./externalModule/yyjson', {public = true})
 
     add_files('./example/*.c', {public = true})
-    add_files('./test/*.c', {public = true})
-    add_files('./test/valloc/*.c', {public = true})
-    add_files('./externalModule/cJSON/*.c', {public = true})
-    add_files('./externalModule/yyjson/*.c', {public = true})
+    add_files('./test/*.c', {public = true}, {cxflags = "-w"})
+    add_files('./test/valloc/*.c', {public = true}, {cxflags = "-w"})
+    add_files('./test/baseTest/*.c', {public = true}, {cxflags = "-w"})
+    add_files('./externalModule/cJSON/*.c', {public = true}, {cxflags = "-w"})
+    -- add_files('./externalModule/yyjson/*.c', {public = true})
 
 end)

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio