RyanJsonRFC8259JsonTest.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. #include "RyanJsonTest.h"
  2. #define PrintfStrCmpEnable
  3. typedef int (*jsonParseData)(char *fileName, char *data, uint32_t len);
  4. /* Read a file, parse, render back, etc. */
  5. static int testFile(const char *path, jsonParseData jsonParseDataHandle)
  6. {
  7. DIR *dir = NULL;
  8. struct dirent *entry;
  9. int path_len = strlen(path);
  10. int count = 0;
  11. int used_count = 0;
  12. if (!path || !path_len || !(dir = opendir(path))) { goto fail; }
  13. while ((entry = readdir(dir)))
  14. {
  15. char *name = (char *)entry->d_name;
  16. if (!name || !strlen(name)) { continue; }
  17. if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { continue; }
  18. char aaa[300] = {0};
  19. snprintf(aaa, sizeof(aaa), "%s/%s", path, name);
  20. FILE *f = fopen(aaa, "rb");
  21. if (f == NULL) { goto fail; }
  22. fseek(f, 0, SEEK_END);
  23. long len = ftell(f);
  24. fseek(f, 0, SEEK_SET);
  25. char *data = (char *)malloc(len + 10);
  26. fread(data, 1, len, f);
  27. data[len] = '\0';
  28. fclose(f);
  29. int status = 0;
  30. int startUse = vallocGetUse();
  31. status = jsonParseDataHandle(name, data, len);
  32. used_count++;
  33. if (0 == strncmp("y_", name, 2))
  34. {
  35. if (0 == status) { count++; }
  36. else
  37. {
  38. printf("应该成功,但是失败: %s, len: %ld\n", data, len);
  39. }
  40. }
  41. else if (0 == strncmp("n_", name, 2))
  42. {
  43. if (0 != status) { count++; }
  44. else
  45. {
  46. printf("应该失败,但是成功: %s, len: %ld\n", data, len);
  47. }
  48. }
  49. else if (0 == strncmp("i_", name, 2)) { count++; }
  50. if (startUse != vallocGetUse())
  51. {
  52. int area = 0, use = 0;
  53. v_mcheck(&area, &use);
  54. printf("内存泄漏 %s len: %ld\r\n", data, len);
  55. free(data);
  56. // printf("内存泄漏 %x len: %ld\r\n", (unsigned int)data, len);
  57. // printf("内存泄漏 %c len: %ld\r\n", (int)data, len);
  58. printf("|||----------->>> area = %d, size = %d\r\n", area, use);
  59. break;
  60. }
  61. // if (use != (len + 10))
  62. // {
  63. // int area = 0, use = 0;
  64. // v_mcheck(&area, &use);
  65. // free(data);
  66. // printf("内存泄漏 %s len: %ld\r\n", data, len);
  67. // // printf("内存泄漏 %x len: %ld\r\n", (unsigned int)data, len);
  68. // // printf("内存泄漏 %c len: %ld\r\n", (int)data, len);
  69. // printf("|||----------->>> area = %d, size = %d\r\n", area, use);
  70. // break;
  71. // }
  72. free(data);
  73. }
  74. closedir(dir);
  75. printf("RFC 8259 JSON: (%d/%d)\r\n", count, used_count);
  76. return 0;
  77. fail:
  78. if (dir) { closedir(dir); }
  79. return -1;
  80. }
  81. typedef struct
  82. {
  83. const char *p;
  84. int32_t len;
  85. } Slice;
  86. static int hexval(int c)
  87. {
  88. if (c >= '0' && c <= '9') { return c - '0'; }
  89. c = (c >= 'a' && c <= 'f') ? (c - 'a' + 'A') : c;
  90. if (c >= 'A' && c <= 'F') { return c - 'A' + 10; }
  91. return -1;
  92. }
  93. static int decode_u4(const char *s, uint16_t *out)
  94. {
  95. int h0 = hexval(s[0]), h1 = hexval(s[1]), h2 = hexval(s[2]), h3 = hexval(s[3]);
  96. if (h0 < 0 || h1 < 0 || h2 < 0 || h3 < 0) { return 0; }
  97. *out = (uint16_t)((h0 << 12) | (h1 << 8) | (h2 << 4) | h3);
  98. return 1;
  99. }
  100. // 将 JSON 字符串(不含两端引号)规范化为 UTF-8 字节序列
  101. static int normalize_json_string(const char *in, int32_t in_len, unsigned char **out, int32_t *out_len)
  102. {
  103. // 预留足够缓冲
  104. int32_t cap = in_len * 4 + 8;
  105. unsigned char *buf = (unsigned char *)malloc(cap);
  106. if (!buf) { return 0; }
  107. int32_t pos = 0;
  108. for (int32_t i = 0; i < in_len; i++)
  109. {
  110. unsigned char ch = (unsigned char)in[i];
  111. if (ch == '\\')
  112. {
  113. if (i + 1 >= in_len)
  114. {
  115. free(buf);
  116. return 0;
  117. }
  118. unsigned char esc = (unsigned char)in[++i];
  119. switch (esc)
  120. {
  121. case '\"': buf[pos++] = '\"'; break;
  122. case '\\': buf[pos++] = '\\'; break;
  123. case '/': buf[pos++] = '/'; break;
  124. case 'b': buf[pos++] = '\b'; break;
  125. case 'f': buf[pos++] = '\f'; break;
  126. case 'n': buf[pos++] = '\n'; break;
  127. case 'r': buf[pos++] = '\r'; break;
  128. case 't': buf[pos++] = '\t'; break;
  129. case 'u': {
  130. if (i + 4 >= in_len)
  131. {
  132. free(buf);
  133. return 0;
  134. }
  135. uint16_t u1;
  136. if (!decode_u4(&in[i + 1], &u1))
  137. {
  138. free(buf);
  139. return 0;
  140. }
  141. i += 4;
  142. if (u1 >= 0xD800 && u1 <= 0xDBFF)
  143. {
  144. // 高代理,必须跟 \uXXXX 低代理
  145. if (i + 2 >= in_len || in[i + 1] != '\\' || in[i + 2] != 'u' || i + 6 >= in_len)
  146. {
  147. free(buf);
  148. return 0;
  149. }
  150. i += 2;
  151. uint16_t u2;
  152. if (!decode_u4(&in[i + 1], &u2))
  153. {
  154. free(buf);
  155. return 0;
  156. }
  157. i += 4;
  158. if (!(u2 >= 0xDC00 && u2 <= 0xDFFF))
  159. {
  160. free(buf);
  161. return 0;
  162. }
  163. // 组合码点
  164. uint32_t cp = 0x10000 + (((uint32_t)(u1 - 0xD800) << 10) | (uint32_t)(u2 - 0xDC00));
  165. // 编码为 UTF-8
  166. buf[pos++] = (unsigned char)(0xF0 | ((cp >> 18) & 0x07));
  167. buf[pos++] = (unsigned char)(0x80 | ((cp >> 12) & 0x3F));
  168. buf[pos++] = (unsigned char)(0x80 | ((cp >> 6) & 0x3F));
  169. buf[pos++] = (unsigned char)(0x80 | (cp & 0x3F));
  170. }
  171. else if (u1 >= 0xDC00 && u1 <= 0xDFFF)
  172. {
  173. // 单独低代理非法
  174. free(buf);
  175. return 0;
  176. }
  177. else
  178. {
  179. // BMP 码点 → UTF-8
  180. if (u1 <= 0x007F) { buf[pos++] = (unsigned char)u1; }
  181. else if (u1 <= 0x07FF)
  182. {
  183. buf[pos++] = (unsigned char)(0xC0 | ((u1 >> 6) & 0x1F));
  184. buf[pos++] = (unsigned char)(0x80 | (u1 & 0x3F));
  185. }
  186. else
  187. {
  188. buf[pos++] = (unsigned char)(0xE0 | ((u1 >> 12) & 0x0F));
  189. buf[pos++] = (unsigned char)(0x80 | ((u1 >> 6) & 0x3F));
  190. buf[pos++] = (unsigned char)(0x80 | (u1 & 0x3F));
  191. }
  192. }
  193. break;
  194. }
  195. default:
  196. // 非法转义
  197. free(buf);
  198. return 0;
  199. }
  200. }
  201. else
  202. {
  203. // 原始字节:直接拷贝(假设输入整体是合法 UTF-8)
  204. buf[pos++] = ch;
  205. }
  206. if (pos + 8 > cap)
  207. {
  208. cap *= 2;
  209. unsigned char *nb = (unsigned char *)realloc(buf, cap);
  210. if (!nb)
  211. {
  212. free(buf);
  213. return 0;
  214. }
  215. buf = nb;
  216. }
  217. }
  218. *out = buf;
  219. *out_len = pos;
  220. return 1;
  221. }
  222. // 比较:规范化两侧为 UTF-8 字节序列,再 memcmp
  223. static int json_string_equal_semantic(const char *a, int32_t a_len, const char *b, int32_t b_len)
  224. {
  225. unsigned char *na = NULL, *nb = NULL;
  226. int32_t nla = 0, nlb = 0;
  227. if (!normalize_json_string(a, a_len, &na, &nla)) { return 0; }
  228. if (!normalize_json_string(b, b_len, &nb, &nlb))
  229. {
  230. free(na);
  231. return 0;
  232. }
  233. int eq = (nla == nlb) && (memcmp(na, nb, nla) == 0);
  234. free(na);
  235. free(nb);
  236. return eq;
  237. }
  238. /* 去空白 */
  239. static void trim(const char **s, int32_t *len)
  240. {
  241. const char *p = *s;
  242. int32_t n = *len;
  243. while (n && isspace((unsigned char)*p))
  244. {
  245. p++;
  246. n--;
  247. }
  248. while (n && isspace((unsigned char)p[n - 1])) { n--; }
  249. *s = p;
  250. *len = n;
  251. }
  252. /* 是否是带双引号的字符串值 */
  253. static int is_quoted_string(const char *s, int32_t len) { return len >= 2 && s[0] == '\"' && s[len - 1] == '\"'; }
  254. /* 值级语义比较:字符串(去引号并 normalize)、数字(含科学计数法)、布尔、null */
  255. static int json_scalar_equal(const char *a, int32_t a_len, const char *b, int32_t b_len)
  256. {
  257. trim(&a, &a_len);
  258. trim(&b, &b_len);
  259. /* 字符串:去掉引号后做转义规范化再比较字节 */
  260. if (is_quoted_string(a, a_len) && is_quoted_string(b, b_len))
  261. {
  262. const char *as = a + 1;
  263. int32_t al = a_len - 2;
  264. const char *bs = b + 1;
  265. int32_t bl = b_len - 2;
  266. unsigned char *na = NULL, *nb = NULL;
  267. int32_t nla = 0, nlb = 0;
  268. if (!normalize_json_string(as, al, &na, &nla)) { return 0; }
  269. if (!normalize_json_string(bs, bl, &nb, &nlb))
  270. {
  271. free(na);
  272. return 0;
  273. }
  274. int eq = (nla == nlb) && (memcmp(na, nb, nla) == 0);
  275. free(na);
  276. free(nb);
  277. return eq;
  278. }
  279. /* 布尔 / null */
  280. if (a_len == 4 && strncmp(a, "true", 4) == 0 && b_len == 4 && strncmp(b, "true", 4) == 0) { return 1; }
  281. if (a_len == 5 && strncmp(a, "false", 5) == 0 && b_len == 5 && strncmp(b, "false", 5) == 0) { return 1; }
  282. if (a_len == 4 && strncmp(a, "null", 4) == 0 && b_len == 4 && strncmp(b, "null", 4) == 0) { return 1; }
  283. /* 数字:用 strtod 支持科学计数法,最后一字节必须到达字符串末尾(避免部分解析) */
  284. {
  285. char *endA = NULL, *endB = NULL;
  286. /* 拷贝到以 NUL 结尾的缓冲,避免 strtod 依赖外部长度 */
  287. char *bufA = (char *)malloc(a_len + 1);
  288. char *bufB = (char *)malloc(b_len + 1);
  289. if (!bufA || !bufB)
  290. {
  291. free(bufA);
  292. free(bufB);
  293. return 0;
  294. }
  295. memcpy(bufA, a, a_len);
  296. bufA[a_len] = '\0';
  297. memcpy(bufB, b, b_len);
  298. bufB[b_len] = '\0';
  299. double va = strtod(bufA, &endA);
  300. double vb = strtod(bufB, &endB);
  301. int okA = (endA && *endA == '\0');
  302. int okB = (endB && *endB == '\0');
  303. free(bufA);
  304. free(bufB);
  305. if (okA && okB)
  306. {
  307. /* 直接相等(包含 -0 与 0)或允许极小误差 */
  308. if (va == vb) { return 1; }
  309. if (fabs(va - vb) < 1e-15) { return 1; }
  310. return 0;
  311. }
  312. }
  313. /* 其余作为纯文本兜底比较 */
  314. return (a_len == b_len) && (memcmp(a, b, a_len) == 0);
  315. }
  316. /* 提取一元素数组的唯一元素;若不是一元素数组返回 0 */
  317. static int extract_single_array_element(const char *s, int32_t len, const char **elem, int32_t *elem_len)
  318. {
  319. trim(&s, &len);
  320. if (len < 2 || s[0] != '[' || s[len - 1] != ']') { return 0; }
  321. const char *p = s + 1;
  322. int32_t n = len - 2;
  323. /* 去前后空白 */
  324. trim(&p, &n);
  325. if (n == 0) { return 0; /* 空数组 */ }
  326. /* 扫描逗号,确保只有一个元素(字符串中的逗号不算) */
  327. int in_str = 0;
  328. int escape = 0;
  329. for (int32_t i = 0; i < n; i++)
  330. {
  331. char c = p[i];
  332. if (in_str)
  333. {
  334. if (escape) { escape = 0; }
  335. else if (c == '\\') { escape = 1; }
  336. else if (c == '\"') { in_str = 0; }
  337. }
  338. else
  339. {
  340. if (c == '\"') { in_str = 1; }
  341. else if (c == ',') { return 0; /* 多元素数组 */ }
  342. }
  343. }
  344. /* 去尾部空白 */
  345. const char *q = p + n;
  346. while (n && isspace((unsigned char)q[-1]))
  347. {
  348. q--;
  349. n--;
  350. }
  351. *elem = p;
  352. *elem_len = n;
  353. return 1;
  354. }
  355. /* 顶层比较:若两侧都是一元素数组则剥离后比较;否则直接按值级比较 */
  356. static int json_value_equal(const char *a, int32_t a_len, const char *b, int32_t b_len)
  357. {
  358. const char *ae = NULL, *be = NULL;
  359. int32_t ale = 0, ble = 0;
  360. if (extract_single_array_element(a, a_len, &ae, &ale) && extract_single_array_element(b, b_len, &be, &ble))
  361. {
  362. return json_scalar_equal(ae, ale, be, ble);
  363. }
  364. return json_scalar_equal(a, a_len, b, b_len);
  365. }
  366. static void checkadjfladjfl(char *data, uint32_t len, char *str, uint32_t strLen, uint32_t *alksdjfCOunt)
  367. {
  368. if (0 != strcmp(data, str))
  369. {
  370. // data/str 是去掉两端引号后的 JSON 字符串内容,并且有长度
  371. if (!json_value_equal(data, len, str, strLen))
  372. {
  373. (*alksdjfCOunt)++;
  374. // 打印时避免 %s,被 NUL 截断;可以打印十六进制
  375. printf("%d 数据不完全一致 -- 原始: %s -- 序列化: %s\n", *alksdjfCOunt, data, str);
  376. }
  377. }
  378. }
  379. /**
  380. * @brief RyanJson 测试程序
  381. *
  382. * @param fileName
  383. * @param data
  384. * @param len
  385. * @return int
  386. */
  387. static int RyanJsonParseData(char *fileName, char *data, uint32_t len)
  388. {
  389. if (strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0 ||
  390. strcmp(fileName, "n_structure_open_array_object.json") == 0 || strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0)
  391. {
  392. return -1;
  393. }
  394. // printf("开始解析: %s\r\n", fileName);
  395. RyanJson_t json = RyanJsonParseOptions(data, len, RyanJsonTrue, NULL);
  396. if (NULL == json) { return -1; }
  397. #ifdef PrintfStrCmpEnable
  398. int32_t strLen = 0;
  399. char *str = RyanJsonPrint(json, 60, RyanJsonFalse, &strLen);
  400. if (NULL == str)
  401. {
  402. printf("反序列化失败: [%s]\n", data);
  403. goto err;
  404. }
  405. RyanJsonMinify(data, len);
  406. static uint32_t alksdjfCOunt = 0;
  407. checkadjfladjfl(data, len, str, strLen, &alksdjfCOunt);
  408. RyanJsonFree(str);
  409. #endif
  410. RyanJsonDelete(json);
  411. return 0;
  412. err:
  413. RyanJsonDelete(json);
  414. return -1;
  415. }
  416. /**
  417. * @brief cJson测试程序
  418. *
  419. * @param fileName
  420. * @param data
  421. * @param len
  422. * @return int
  423. */
  424. static int cJSONParseData(char *fileName, char *data, uint32_t len)
  425. {
  426. if (strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0 ||
  427. strcmp(fileName, "n_structure_open_array_object.json") == 0 || strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0)
  428. {
  429. return -1;
  430. }
  431. cJSON *json = cJSON_ParseWithLengthOpts(data, len + sizeof(""), NULL, RyanJsonTrue);
  432. if (NULL == json) { return -1; }
  433. #ifdef PrintfStrCmpEnable
  434. char *str = cJSON_PrintBuffered(json, 60, RyanJsonFalse);
  435. if (NULL == str)
  436. {
  437. printf("反序列化失败: [%s]\n", data);
  438. goto err;
  439. }
  440. cJSON_Minify(data);
  441. static uint32_t alksdjfCOunt = 0;
  442. checkadjfladjfl(data, len, str, strlen(str), &alksdjfCOunt);
  443. cJSON_free(str);
  444. #endif
  445. cJSON_Delete(json);
  446. return 0;
  447. err:
  448. cJSON_Delete(json);
  449. return -1;
  450. }
  451. /**
  452. * @brief cJson测试程序
  453. *
  454. * @param fileName
  455. * @param data
  456. * @param len
  457. * @return int
  458. */
  459. static int yyjsonParseData(char *fileName, char *data, uint32_t len)
  460. {
  461. if (strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0 ||
  462. strcmp(fileName, "n_structure_open_array_object.json") == 0 || strcmp(fileName, "n_structure_100000_opening_arrays.json") == 0)
  463. {
  464. return -1;
  465. }
  466. yyjson_doc *doc = yyjson_read(data, len, 0);
  467. if (NULL == doc) { return -1; }
  468. #ifdef PrintfStrCmpEnable
  469. char *str = yyjson_write(doc, 0, NULL);
  470. if (NULL == str)
  471. {
  472. printf("反序列化失败: [%s]\n", data);
  473. goto err;
  474. }
  475. cJSON_Minify(data);
  476. static uint32_t alksdjfCOunt = 0;
  477. checkadjfladjfl(data, len, str, strlen(str), &alksdjfCOunt);
  478. free(str);
  479. #endif
  480. yyjson_doc_free(doc);
  481. return 0;
  482. err:
  483. yyjson_doc_free(doc);
  484. return -1;
  485. }
  486. // RFC 8259 JSON Test Suite
  487. // https://github.com/nst/JSONTestSuite
  488. RyanJsonBool_e RFC8259JsonTest(void)
  489. {
  490. int result = 0;
  491. RyanJsonInitHooks(v_malloc, v_free, v_realloc);
  492. cJSON_Hooks hooks = {.malloc_fn = v_malloc, .free_fn = v_free};
  493. cJSON_InitHooks(&hooks);
  494. printf("开始 RFC 8259 JSON 测试");
  495. printf("\r\n--------------------------- RFC8259 RyanJson --------------------------\r\n");
  496. result = testFile("../../../../test//RFC8259JsonData", RyanJsonParseData);
  497. if (0 != result)
  498. {
  499. printf("%s:%d RyanJson RFC8259JsonTest fail\r\n", __FILE__, __LINE__);
  500. goto err;
  501. }
  502. printf("\r\n--------------------------- RFC8259 cJSON --------------------------\r\n");
  503. result = testFile("../../../../test//RFC8259JsonData", cJSONParseData);
  504. if (0 != result)
  505. {
  506. printf("%s:%d cJSON RFC8259JsonTest fail\r\n", __FILE__, __LINE__);
  507. goto err;
  508. }
  509. printf("\r\n--------------------------- RFC8259 yyjson --------------------------\r\n");
  510. result = testFile("../../../../test//RFC8259JsonData", yyjsonParseData);
  511. if (0 != result)
  512. {
  513. printf("%s:%d yyjson RFC8259JsonTest fail\r\n", __FILE__, __LINE__);
  514. goto err;
  515. }
  516. displayMem();
  517. return RyanJsonTrue;
  518. err:
  519. displayMem();
  520. return RyanJsonFalse;
  521. }