@gravito/core 1.6.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/README.md +100 -6
  2. package/README.zh-TW.md +101 -6
  3. package/dist/Application.d.ts +256 -0
  4. package/dist/CommandKernel.d.ts +33 -0
  5. package/dist/ConfigManager.d.ts +65 -0
  6. package/dist/Container/RequestScopeManager.d.ts +62 -0
  7. package/dist/Container/RequestScopeMetrics.d.ts +144 -0
  8. package/dist/Container.d.ts +153 -0
  9. package/dist/ErrorHandler.d.ts +66 -0
  10. package/dist/Event.d.ts +5 -0
  11. package/dist/EventManager.d.ts +123 -0
  12. package/dist/GlobalErrorHandlers.d.ts +47 -0
  13. package/dist/GravitoServer.d.ts +28 -0
  14. package/dist/HookManager.d.ts +435 -0
  15. package/dist/Listener.d.ts +4 -0
  16. package/dist/Logger.d.ts +20 -0
  17. package/dist/PlanetCore.d.ts +402 -0
  18. package/dist/RequestContext.d.ts +97 -0
  19. package/dist/Route.d.ts +36 -0
  20. package/dist/Router.d.ts +270 -0
  21. package/dist/ServiceProvider.d.ts +178 -0
  22. package/dist/adapters/GravitoEngineAdapter.d.ts +27 -0
  23. package/dist/adapters/bun/AdaptiveAdapter.d.ts +99 -0
  24. package/dist/adapters/bun/BunContext.d.ts +54 -0
  25. package/dist/adapters/bun/BunNativeAdapter.d.ts +66 -0
  26. package/dist/adapters/bun/BunRequest.d.ts +31 -0
  27. package/dist/adapters/bun/BunWebSocketHandler.d.ts +48 -0
  28. package/dist/adapters/bun/RadixNode.d.ts +19 -0
  29. package/dist/adapters/bun/RadixRouter.d.ts +32 -0
  30. package/dist/adapters/bun/index.d.ts +7 -0
  31. package/dist/adapters/bun/types.d.ts +20 -0
  32. package/dist/adapters/index.d.ts +12 -0
  33. package/dist/adapters/types.d.ts +235 -0
  34. package/dist/binary/BinaryUtils.d.ts +105 -0
  35. package/dist/binary/index.d.ts +5 -0
  36. package/dist/cli/queue-commands.d.ts +6 -0
  37. package/dist/compat/async-local-storage.browser.d.ts +9 -0
  38. package/dist/compat/async-local-storage.d.ts +7 -0
  39. package/dist/compat/crypto.browser.d.ts +5 -0
  40. package/dist/compat/crypto.d.ts +6 -0
  41. package/dist/compat.cjs +42 -11
  42. package/dist/compat.cjs.map +9 -0
  43. package/dist/compat.d.ts +23 -1
  44. package/dist/compat.js +3 -0
  45. package/dist/compat.js.map +9 -0
  46. package/dist/engine/AOTRouter.d.ts +139 -0
  47. package/dist/engine/FastContext.d.ts +141 -0
  48. package/dist/engine/Gravito.d.ts +131 -0
  49. package/dist/engine/MinimalContext.d.ts +102 -0
  50. package/dist/engine/analyzer.d.ts +113 -0
  51. package/dist/engine/constants.d.ts +23 -0
  52. package/dist/engine/index.cjs +758 -532
  53. package/dist/engine/index.cjs.map +22 -0
  54. package/dist/engine/index.d.ts +14 -690
  55. package/dist/engine/index.js +758 -508
  56. package/dist/engine/index.js.map +22 -0
  57. package/dist/engine/path.d.ts +26 -0
  58. package/dist/engine/pool.d.ts +83 -0
  59. package/dist/engine/types.d.ts +149 -0
  60. package/dist/error-handling/RequestScopeErrorContext.d.ts +126 -0
  61. package/dist/events/BackpressureManager.d.ts +215 -0
  62. package/dist/events/CircuitBreaker.d.ts +229 -0
  63. package/dist/events/DeadLetterQueue.d.ts +219 -0
  64. package/dist/events/EventBackend.d.ts +12 -0
  65. package/dist/events/EventOptions.d.ts +204 -0
  66. package/dist/events/EventPriorityQueue.d.ts +63 -0
  67. package/dist/events/FlowControlStrategy.d.ts +109 -0
  68. package/dist/events/IdempotencyCache.d.ts +60 -0
  69. package/dist/events/MessageQueueBridge.d.ts +184 -0
  70. package/dist/events/PriorityEscalationManager.d.ts +82 -0
  71. package/dist/events/RetryScheduler.d.ts +104 -0
  72. package/dist/events/WorkerPool.d.ts +98 -0
  73. package/dist/events/WorkerPoolConfig.d.ts +153 -0
  74. package/dist/events/WorkerPoolMetrics.d.ts +65 -0
  75. package/dist/events/aggregation/AggregationWindow.d.ts +77 -0
  76. package/dist/events/aggregation/DeduplicationManager.d.ts +135 -0
  77. package/dist/events/aggregation/EventAggregationManager.d.ts +108 -0
  78. package/dist/events/aggregation/EventBatcher.d.ts +99 -0
  79. package/dist/events/aggregation/index.d.ts +10 -0
  80. package/dist/events/aggregation/types.d.ts +117 -0
  81. package/dist/events/index.d.ts +26 -0
  82. package/dist/events/observability/EventMetrics.d.ts +132 -0
  83. package/dist/events/observability/EventTracer.d.ts +68 -0
  84. package/dist/events/observability/EventTracing.d.ts +161 -0
  85. package/dist/events/observability/OTelEventMetrics.d.ts +332 -0
  86. package/dist/events/observability/ObservableHookManager.d.ts +108 -0
  87. package/dist/events/observability/StreamWorkerMetrics.d.ts +76 -0
  88. package/dist/events/observability/index.d.ts +24 -0
  89. package/dist/events/observability/metrics-types.d.ts +16 -0
  90. package/dist/events/queue-core.d.ts +77 -0
  91. package/dist/events/task-executor.d.ts +51 -0
  92. package/dist/events/types.d.ts +134 -0
  93. package/dist/exceptions/AuthenticationException.d.ts +8 -0
  94. package/dist/exceptions/AuthorizationException.d.ts +8 -0
  95. package/dist/exceptions/CircularDependencyException.d.ts +9 -0
  96. package/dist/exceptions/GravitoException.d.ts +23 -0
  97. package/dist/exceptions/HttpException.d.ts +9 -0
  98. package/dist/exceptions/ModelNotFoundException.d.ts +10 -0
  99. package/dist/exceptions/ValidationException.d.ts +22 -0
  100. package/dist/exceptions/index.d.ts +7 -0
  101. package/dist/ffi/NativeAccelerator.d.ts +69 -0
  102. package/dist/ffi/NativeHasher.d.ts +139 -0
  103. package/dist/ffi/cbor-fallback.d.ts +96 -0
  104. package/dist/ffi/hash-fallback.d.ts +33 -0
  105. package/dist/ffi/index.cjs +621 -0
  106. package/dist/ffi/index.cjs.map +14 -0
  107. package/dist/ffi/index.d.ts +10 -0
  108. package/dist/ffi/index.js +602 -0
  109. package/dist/ffi/index.js.map +14 -0
  110. package/dist/ffi/types.d.ts +135 -0
  111. package/dist/health/HealthProvider.d.ts +67 -0
  112. package/dist/helpers/Arr.d.ts +19 -0
  113. package/dist/helpers/Str.d.ts +38 -0
  114. package/dist/helpers/data.d.ts +25 -0
  115. package/dist/helpers/errors.d.ts +34 -0
  116. package/dist/helpers/response.d.ts +41 -0
  117. package/dist/helpers.d.ts +338 -0
  118. package/dist/hooks/ActionManager.d.ts +132 -0
  119. package/dist/hooks/AsyncDetector.d.ts +84 -0
  120. package/dist/hooks/FilterManager.d.ts +71 -0
  121. package/dist/hooks/MigrationWarner.d.ts +24 -0
  122. package/dist/hooks/dlq-operations.d.ts +60 -0
  123. package/dist/hooks/index.d.ts +11 -0
  124. package/dist/hooks/types.d.ts +107 -0
  125. package/dist/http/CookieJar.d.ts +51 -0
  126. package/dist/http/cookie.d.ts +29 -0
  127. package/dist/http/index.d.ts +12 -0
  128. package/dist/{compat-C4Src6NN.d.cts → http/types.d.ts} +48 -16
  129. package/dist/index.browser.d.ts +34 -0
  130. package/dist/index.cjs +12909 -9492
  131. package/dist/index.cjs.map +168 -0
  132. package/dist/index.d.ts +58 -8707
  133. package/dist/index.js +12906 -9381
  134. package/dist/index.js.map +168 -0
  135. package/dist/observability/QueueDashboard.d.ts +136 -0
  136. package/dist/observability/contracts.d.ts +137 -0
  137. package/dist/observability/index.d.ts +13 -0
  138. package/dist/reliability/DeadLetterQueueManager.d.ts +349 -0
  139. package/dist/reliability/RetryPolicy.d.ts +217 -0
  140. package/dist/reliability/index.d.ts +6 -0
  141. package/dist/router/ControllerDispatcher.d.ts +12 -0
  142. package/dist/router/RequestValidator.d.ts +20 -0
  143. package/dist/runtime/adapter-bun.d.ts +12 -0
  144. package/dist/runtime/adapter-deno.d.ts +12 -0
  145. package/dist/runtime/adapter-node.d.ts +12 -0
  146. package/dist/runtime/adapter-unknown.d.ts +13 -0
  147. package/dist/runtime/archive.d.ts +17 -0
  148. package/dist/runtime/compression.d.ts +21 -0
  149. package/dist/runtime/deep-equals.d.ts +56 -0
  150. package/dist/runtime/detection.d.ts +22 -0
  151. package/dist/runtime/escape.d.ts +34 -0
  152. package/dist/runtime/index.browser.d.ts +20 -0
  153. package/dist/runtime/index.d.ts +44 -0
  154. package/dist/runtime/markdown.d.ts +44 -0
  155. package/dist/runtime/types.d.ts +436 -0
  156. package/dist/runtime-helpers.d.ts +67 -0
  157. package/dist/runtime.d.ts +11 -0
  158. package/dist/security/Encrypter.d.ts +33 -0
  159. package/dist/security/Hasher.d.ts +29 -0
  160. package/dist/testing/HttpTester.d.ts +39 -0
  161. package/dist/testing/TestResponse.d.ts +78 -0
  162. package/dist/testing/index.d.ts +2 -0
  163. package/dist/transpiler-utils.d.ts +170 -0
  164. package/dist/types/events.d.ts +94 -0
  165. package/dist/types.d.ts +13 -0
  166. package/package.json +23 -53
  167. package/src/ffi/native/cbor.c +1148 -0
  168. package/dist/compat-C4Src6NN.d.ts +0 -357
  169. package/dist/compat.d.cts +0 -1
  170. package/dist/engine/index.d.cts +0 -702
  171. package/dist/index.d.cts +0 -8734
@@ -0,0 +1,1148 @@
1
+ /**
2
+ * Gravito CBOR 原生編碼器/解碼器(C 實現)
3
+ * 符合 RFC 7049 規範,針對 Gravito Job 結構優化
4
+ * 使用 bun:ffi 的 TinyCC 編譯器編譯
5
+ *
6
+ * 設計約束:
7
+ * - 不進行動態記憶體分配(所有 buffer 由呼叫端提供)
8
+ * - 支援類型:map、string、uint、negint、float64、bytes、null、boolean、array
9
+ * - 最大深度:16(防止堆疊溢出)
10
+ * - 所有函數在入口做 buffer 邊界檢查
11
+ * - C99 標準(TinyCC 相容)
12
+ *
13
+ * 編碼流程:JSON string -> CBOR binary
14
+ * 解碼流程:CBOR binary -> JSON string
15
+ */
16
+
17
+ #include <stdint.h>
18
+ #include <string.h>
19
+ #include <stdlib.h>
20
+ #include <stdio.h>
21
+
22
+ /* ==================== 常數定義 ==================== */
23
+
24
+ /* CBOR Major Type 定義 (RFC 7049 Section 2.1) */
25
+ #define CBOR_UINT 0
26
+ #define CBOR_NEGINT 1
27
+ #define CBOR_BYTES 2
28
+ #define CBOR_TEXT 3
29
+ #define CBOR_ARRAY 4
30
+ #define CBOR_MAP 5
31
+ #define CBOR_TAG 6
32
+ #define CBOR_SIMPLE 7
33
+
34
+ /* CBOR Simple Values */
35
+ #define CBOR_FALSE 20
36
+ #define CBOR_TRUE 21
37
+ #define CBOR_NULL 22
38
+
39
+ /* CBOR Length / Additional Info */
40
+ #define CBOR_AI_UINT8 24
41
+ #define CBOR_AI_UINT16 25
42
+ #define CBOR_AI_UINT32 26
43
+ #define CBOR_AI_UINT64 27
44
+ #define CBOR_AI_FLOAT64 27
45
+
46
+ #define GRAVITO_CBOR_MAX_DEPTH 16
47
+ #define GRAVITO_CBOR_ERROR_BUFFER_FULL (-1)
48
+ #define GRAVITO_CBOR_ERROR_PARSE (-2)
49
+
50
+ /* ==================== 編碼器結構體 ==================== */
51
+
52
+ typedef struct {
53
+ uint8_t *buffer;
54
+ size_t capacity;
55
+ size_t offset;
56
+ int error;
57
+ } CborEncoder;
58
+
59
+ /* ==================== 解碼器結構體 ==================== */
60
+
61
+ typedef struct {
62
+ const uint8_t *data;
63
+ size_t length;
64
+ size_t offset;
65
+ int error;
66
+ } CborDecoder;
67
+
68
+ /* ==================== JSON 解析器結構體 ==================== */
69
+
70
+ typedef struct {
71
+ const char *json;
72
+ size_t length;
73
+ size_t pos;
74
+ int error;
75
+ } JsonParser;
76
+
77
+ /* ==================== 編碼輔助函數 ==================== */
78
+
79
+ static int enc_ensure(CborEncoder *enc, size_t needed) {
80
+ if (enc->error) return enc->error;
81
+ if (enc->offset + needed > enc->capacity) {
82
+ enc->error = GRAVITO_CBOR_ERROR_BUFFER_FULL;
83
+ return GRAVITO_CBOR_ERROR_BUFFER_FULL;
84
+ }
85
+ return 0;
86
+ }
87
+
88
+ static void enc_u8(CborEncoder *enc, uint8_t val) {
89
+ if (enc_ensure(enc, 1) == 0) {
90
+ enc->buffer[enc->offset++] = val;
91
+ }
92
+ }
93
+
94
+ static void enc_bytes(CborEncoder *enc, const uint8_t *src, size_t len) {
95
+ if (enc_ensure(enc, len) == 0) {
96
+ memcpy(&enc->buffer[enc->offset], src, len);
97
+ enc->offset += len;
98
+ }
99
+ }
100
+
101
+ /**
102
+ * 寫入 CBOR 型別頭 (Major Type + Additional Info)
103
+ * 支援 0 到 2^32-1 的長度
104
+ */
105
+ static void enc_type_len(CborEncoder *enc, uint8_t major, uint32_t val) {
106
+ uint8_t mt = (major << 5);
107
+ if (val < 24) {
108
+ enc_u8(enc, mt | (uint8_t)val);
109
+ } else if (val <= 0xFFU) {
110
+ enc_u8(enc, mt | CBOR_AI_UINT8);
111
+ enc_u8(enc, (uint8_t)val);
112
+ } else if (val <= 0xFFFFU) {
113
+ enc_u8(enc, mt | CBOR_AI_UINT16);
114
+ enc_u8(enc, (val >> 8) & 0xFF);
115
+ enc_u8(enc, val & 0xFF);
116
+ } else {
117
+ enc_u8(enc, mt | CBOR_AI_UINT32);
118
+ enc_u8(enc, (val >> 24) & 0xFF);
119
+ enc_u8(enc, (val >> 16) & 0xFF);
120
+ enc_u8(enc, (val >> 8) & 0xFF);
121
+ enc_u8(enc, val & 0xFF);
122
+ }
123
+ }
124
+
125
+ /**
126
+ * 寫入 CBOR float64
127
+ * 使用 union 進行 IEEE 754 大端序轉換
128
+ */
129
+ static void enc_float64(CborEncoder *enc, double val) {
130
+ union { double d; uint64_t u; } conv;
131
+ conv.d = val;
132
+ enc_u8(enc, (CBOR_SIMPLE << 5) | CBOR_AI_FLOAT64);
133
+ /* 大端序:高位元組先寫 */
134
+ enc_u8(enc, (conv.u >> 56) & 0xFF);
135
+ enc_u8(enc, (conv.u >> 48) & 0xFF);
136
+ enc_u8(enc, (conv.u >> 40) & 0xFF);
137
+ enc_u8(enc, (conv.u >> 32) & 0xFF);
138
+ enc_u8(enc, (conv.u >> 24) & 0xFF);
139
+ enc_u8(enc, (conv.u >> 16) & 0xFF);
140
+ enc_u8(enc, (conv.u >> 8) & 0xFF);
141
+ enc_u8(enc, conv.u & 0xFF);
142
+ }
143
+
144
+ /* ==================== JSON 解析輔助函數 ==================== */
145
+
146
+ static void jp_skip_ws(JsonParser *jp) {
147
+ while (jp->pos < jp->length) {
148
+ char c = jp->json[jp->pos];
149
+ if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
150
+ jp->pos++;
151
+ } else {
152
+ break;
153
+ }
154
+ }
155
+ }
156
+
157
+ static char jp_peek(JsonParser *jp) {
158
+ jp_skip_ws(jp);
159
+ if (jp->pos >= jp->length) return '\0';
160
+ return jp->json[jp->pos];
161
+ }
162
+
163
+ static char jp_next(JsonParser *jp) {
164
+ jp_skip_ws(jp);
165
+ if (jp->pos >= jp->length) return '\0';
166
+ return jp->json[jp->pos++];
167
+ }
168
+
169
+ static int jp_expect(JsonParser *jp, char ch) {
170
+ if (jp_next(jp) != ch) {
171
+ jp->error = GRAVITO_CBOR_ERROR_PARSE;
172
+ return -1;
173
+ }
174
+ return 0;
175
+ }
176
+
177
+ /**
178
+ * 解析 JSON 字串,直接寫入 CBOR text string
179
+ * 處理轉義序列:\" \\ \/ \b \f \n \r \t \uXXXX
180
+ *
181
+ * 策略:先計算解碼後長度,再寫入 CBOR
182
+ * 注意:先掃描一遍得到實際 UTF-8 長度,再寫入 header + bytes
183
+ */
184
+ static void encode_json_string(CborEncoder *enc, JsonParser *jp) {
185
+ if (jp->error || enc->error) return;
186
+
187
+ /* 期望開引號 */
188
+ if (jp_next(jp) != '"') {
189
+ jp->error = GRAVITO_CBOR_ERROR_PARSE;
190
+ return;
191
+ }
192
+
193
+ /* 第一遍:掃描計算解碼後的 UTF-8 長度 */
194
+ size_t scan_start = jp->pos;
195
+ size_t utf8_len = 0;
196
+ while (jp->pos < jp->length && jp->json[jp->pos] != '"') {
197
+ if (jp->json[jp->pos] == '\\') {
198
+ jp->pos++;
199
+ if (jp->pos >= jp->length) {
200
+ jp->error = GRAVITO_CBOR_ERROR_PARSE;
201
+ return;
202
+ }
203
+ char esc = jp->json[jp->pos];
204
+ if (esc == 'u') {
205
+ /* \uXXXX - 解析 4 位十六進制 */
206
+ jp->pos++;
207
+ uint32_t cp = 0;
208
+ int k;
209
+ for (k = 0; k < 4 && jp->pos < jp->length; k++, jp->pos++) {
210
+ char h = jp->json[jp->pos];
211
+ if (h >= '0' && h <= '9') cp = (cp << 4) | (h - '0');
212
+ else if (h >= 'a' && h <= 'f') cp = (cp << 4) | (h - 'a' + 10);
213
+ else if (h >= 'A' && h <= 'F') cp = (cp << 4) | (h - 'A' + 10);
214
+ else { jp->error = GRAVITO_CBOR_ERROR_PARSE; return; }
215
+ }
216
+ /* 處理 surrogate pair */
217
+ if (cp >= 0xD800 && cp <= 0xDBFF) {
218
+ /* 高代理,讀取低代理 \uXXXX */
219
+ if (jp->pos + 1 < jp->length && jp->json[jp->pos] == '\\' && jp->json[jp->pos+1] == 'u') {
220
+ jp->pos += 2;
221
+ uint32_t low = 0;
222
+ for (k = 0; k < 4 && jp->pos < jp->length; k++, jp->pos++) {
223
+ char h = jp->json[jp->pos];
224
+ if (h >= '0' && h <= '9') low = (low << 4) | (h - '0');
225
+ else if (h >= 'a' && h <= 'f') low = (low << 4) | (h - 'a' + 10);
226
+ else if (h >= 'A' && h <= 'F') low = (low << 4) | (h - 'A' + 10);
227
+ else { jp->error = GRAVITO_CBOR_ERROR_PARSE; return; }
228
+ }
229
+ cp = 0x10000 + ((cp - 0xD800) << 10) + (low - 0xDC00);
230
+ }
231
+ }
232
+ /* 計算 UTF-8 長度 */
233
+ if (cp < 0x80) utf8_len += 1;
234
+ else if (cp < 0x800) utf8_len += 2;
235
+ else if (cp < 0x10000) utf8_len += 3;
236
+ else utf8_len += 4;
237
+ continue; /* 已經在 for 裡面推進 pos */
238
+ }
239
+ /* 其他轉義:\", \\, \/, \b, \f, \n, \r, \t -- 各1字元 */
240
+ utf8_len += 1;
241
+ jp->pos++;
242
+ } else {
243
+ /* 普通字元 -- 直接使用原始 UTF-8 字元 */
244
+ /* UTF-8 多位元組:根據首位元組判斷 */
245
+ unsigned char uc = (unsigned char)jp->json[jp->pos];
246
+ if (uc < 0x80) { utf8_len += 1; jp->pos += 1; }
247
+ else if ((uc & 0xE0) == 0xC0) { utf8_len += 2; jp->pos += 2; }
248
+ else if ((uc & 0xF0) == 0xE0) { utf8_len += 3; jp->pos += 3; }
249
+ else if ((uc & 0xF8) == 0xF0) { utf8_len += 4; jp->pos += 4; }
250
+ else { utf8_len += 1; jp->pos += 1; }
251
+ }
252
+ }
253
+
254
+ /* 跳過閉引號 */
255
+ if (jp->pos >= jp->length || jp->json[jp->pos] != '"') {
256
+ jp->error = GRAVITO_CBOR_ERROR_PARSE;
257
+ return;
258
+ }
259
+ jp->pos++;
260
+
261
+ /* 寫入 CBOR text string header */
262
+ enc_type_len(enc, CBOR_TEXT, (uint32_t)utf8_len);
263
+
264
+ /* 第二遍:實際寫入 UTF-8 資料 */
265
+ size_t w_pos = scan_start;
266
+ while (w_pos < jp->pos - 1) { /* -1 跳過閉引號 */
267
+ if (jp->json[w_pos] == '\\') {
268
+ w_pos++;
269
+ char esc = jp->json[w_pos];
270
+ switch (esc) {
271
+ case '"': enc_u8(enc, '"'); w_pos++; break;
272
+ case '\\': enc_u8(enc, '\\'); w_pos++; break;
273
+ case '/': enc_u8(enc, '/'); w_pos++; break;
274
+ case 'b': enc_u8(enc, '\b'); w_pos++; break;
275
+ case 'f': enc_u8(enc, '\f'); w_pos++; break;
276
+ case 'n': enc_u8(enc, '\n'); w_pos++; break;
277
+ case 'r': enc_u8(enc, '\r'); w_pos++; break;
278
+ case 't': enc_u8(enc, '\t'); w_pos++; break;
279
+ case 'u': {
280
+ w_pos++;
281
+ uint32_t cp = 0;
282
+ int k;
283
+ for (k = 0; k < 4; k++, w_pos++) {
284
+ char h = jp->json[w_pos];
285
+ if (h >= '0' && h <= '9') cp = (cp << 4) | (h - '0');
286
+ else if (h >= 'a' && h <= 'f') cp = (cp << 4) | (h - 'a' + 10);
287
+ else if (h >= 'A' && h <= 'F') cp = (cp << 4) | (h - 'A' + 10);
288
+ }
289
+ /* 處理 surrogate pair */
290
+ if (cp >= 0xD800 && cp <= 0xDBFF) {
291
+ if (jp->json[w_pos] == '\\' && jp->json[w_pos+1] == 'u') {
292
+ w_pos += 2;
293
+ uint32_t low = 0;
294
+ for (k = 0; k < 4; k++, w_pos++) {
295
+ char h = jp->json[w_pos];
296
+ if (h >= '0' && h <= '9') low = (low << 4) | (h - '0');
297
+ else if (h >= 'a' && h <= 'f') low = (low << 4) | (h - 'a' + 10);
298
+ else if (h >= 'A' && h <= 'F') low = (low << 4) | (h - 'A' + 10);
299
+ }
300
+ cp = 0x10000 + ((cp - 0xD800) << 10) + (low - 0xDC00);
301
+ }
302
+ }
303
+ /* 寫入 UTF-8 */
304
+ if (cp < 0x80) {
305
+ enc_u8(enc, (uint8_t)cp);
306
+ } else if (cp < 0x800) {
307
+ enc_u8(enc, 0xC0 | (cp >> 6));
308
+ enc_u8(enc, 0x80 | (cp & 0x3F));
309
+ } else if (cp < 0x10000) {
310
+ enc_u8(enc, 0xE0 | (cp >> 12));
311
+ enc_u8(enc, 0x80 | ((cp >> 6) & 0x3F));
312
+ enc_u8(enc, 0x80 | (cp & 0x3F));
313
+ } else {
314
+ enc_u8(enc, 0xF0 | (cp >> 18));
315
+ enc_u8(enc, 0x80 | ((cp >> 12) & 0x3F));
316
+ enc_u8(enc, 0x80 | ((cp >> 6) & 0x3F));
317
+ enc_u8(enc, 0x80 | (cp & 0x3F));
318
+ }
319
+ break;
320
+ }
321
+ default:
322
+ enc_u8(enc, (uint8_t)esc);
323
+ w_pos++;
324
+ break;
325
+ }
326
+ } else {
327
+ /* 普通字元 -- 直接拷貝 UTF-8 字節 */
328
+ unsigned char uc = (unsigned char)jp->json[w_pos];
329
+ if (uc < 0x80) {
330
+ enc_u8(enc, uc);
331
+ w_pos++;
332
+ } else if ((uc & 0xE0) == 0xC0) {
333
+ enc_bytes(enc, (const uint8_t*)&jp->json[w_pos], 2);
334
+ w_pos += 2;
335
+ } else if ((uc & 0xF0) == 0xE0) {
336
+ enc_bytes(enc, (const uint8_t*)&jp->json[w_pos], 3);
337
+ w_pos += 3;
338
+ } else if ((uc & 0xF8) == 0xF0) {
339
+ enc_bytes(enc, (const uint8_t*)&jp->json[w_pos], 4);
340
+ w_pos += 4;
341
+ } else {
342
+ enc_u8(enc, uc);
343
+ w_pos++;
344
+ }
345
+ }
346
+ }
347
+ }
348
+
349
+ /* 前向宣告 */
350
+ static void encode_json_value(CborEncoder *enc, JsonParser *jp, int depth);
351
+
352
+ /**
353
+ * 解析 JSON 數字,編碼為 CBOR uint/negint/float64
354
+ *
355
+ * JSON 數字規則:
356
+ * - 整數:直接用 CBOR uint (>=0) 或 negint (<0)
357
+ * - 浮點數:使用 CBOR float64
358
+ * - 大於 2^32 的整數:使用 float64(與 JS Fallback 保持一致)
359
+ */
360
+ static void encode_json_number(CborEncoder *enc, JsonParser *jp) {
361
+ if (jp->error || enc->error) return;
362
+
363
+ size_t start = jp->pos;
364
+ int is_negative = 0;
365
+ int has_dot = 0;
366
+ int has_exp = 0;
367
+
368
+ /* 讀取負號 */
369
+ if (jp->pos < jp->length && jp->json[jp->pos] == '-') {
370
+ is_negative = 1;
371
+ jp->pos++;
372
+ }
373
+
374
+ /* 讀取整數部分 */
375
+ while (jp->pos < jp->length && jp->json[jp->pos] >= '0' && jp->json[jp->pos] <= '9') {
376
+ jp->pos++;
377
+ }
378
+
379
+ /* 檢查小數點 */
380
+ if (jp->pos < jp->length && jp->json[jp->pos] == '.') {
381
+ has_dot = 1;
382
+ jp->pos++;
383
+ while (jp->pos < jp->length && jp->json[jp->pos] >= '0' && jp->json[jp->pos] <= '9') {
384
+ jp->pos++;
385
+ }
386
+ }
387
+
388
+ /* 檢查指數 */
389
+ if (jp->pos < jp->length && (jp->json[jp->pos] == 'e' || jp->json[jp->pos] == 'E')) {
390
+ has_exp = 1;
391
+ jp->pos++;
392
+ if (jp->pos < jp->length && (jp->json[jp->pos] == '+' || jp->json[jp->pos] == '-')) {
393
+ jp->pos++;
394
+ }
395
+ while (jp->pos < jp->length && jp->json[jp->pos] >= '0' && jp->json[jp->pos] <= '9') {
396
+ jp->pos++;
397
+ }
398
+ }
399
+
400
+ size_t num_len = jp->pos - start;
401
+ if (num_len == 0 || (num_len == 1 && is_negative)) {
402
+ jp->error = GRAVITO_CBOR_ERROR_PARSE;
403
+ return;
404
+ }
405
+
406
+ /* 浮點數或帶指數 -> 使用 float64 */
407
+ if (has_dot || has_exp) {
408
+ /* 使用 strtod 精確解析浮點數 */
409
+ /* 需要臨時空結束字串(JSON 數字不含空結束符) */
410
+ char num_buf[64];
411
+ if (num_len >= sizeof(num_buf)) {
412
+ jp->error = GRAVITO_CBOR_ERROR_PARSE;
413
+ return;
414
+ }
415
+ memcpy(num_buf, &jp->json[start], num_len);
416
+ num_buf[num_len] = '\0';
417
+
418
+ double result = strtod(num_buf, 0);
419
+ enc_float64(enc, result);
420
+ return;
421
+ }
422
+
423
+ /* 整數解析 */
424
+ if (is_negative) {
425
+ /* 負整數 */
426
+ uint64_t abs_val = 0;
427
+ size_t p = start + 1; /* 跳過 '-' */
428
+ int overflow = 0;
429
+ while (p < jp->pos) {
430
+ uint64_t prev = abs_val;
431
+ abs_val = abs_val * 10 + (jp->json[p] - '0');
432
+ if (abs_val / 10 != prev) overflow = 1; /* 溢出檢測 */
433
+ p++;
434
+ }
435
+ /* 檢查是否在 uint32 範圍:CBOR negint 編碼為 -1-n,所以 n = abs_val - 1 */
436
+ uint64_t cbor_val = abs_val - 1; /* -1 對應 n=0, -256 對應 n=255, etc */
437
+ if (!overflow && cbor_val <= 0xFFFFFFFFUL) {
438
+ enc_type_len(enc, CBOR_NEGINT, (uint32_t)cbor_val);
439
+ } else {
440
+ /* 超過 32-bit 範圍,使用 float64(與 JS Fallback 一致) */
441
+ enc_float64(enc, -(double)abs_val);
442
+ }
443
+ } else {
444
+ /* 正整數 */
445
+ uint64_t val = 0;
446
+ size_t p = start;
447
+ int overflow = 0;
448
+ while (p < jp->pos) {
449
+ uint64_t prev = val;
450
+ val = val * 10 + (jp->json[p] - '0');
451
+ if (val / 10 != prev) overflow = 1;
452
+ p++;
453
+ }
454
+ if (!overflow && val <= 0xFFFFFFFFUL) {
455
+ enc_type_len(enc, CBOR_UINT, (uint32_t)val);
456
+ } else {
457
+ /* 超過 32-bit 範圍,使用 float64(與 JS Fallback 一致) */
458
+ enc_float64(enc, (double)val);
459
+ }
460
+ }
461
+ }
462
+
463
+ /**
464
+ * 解析 JSON object,編碼為 CBOR map
465
+ */
466
+ static void encode_json_object(CborEncoder *enc, JsonParser *jp, int depth) {
467
+ if (jp->error || enc->error) return;
468
+ if (depth >= GRAVITO_CBOR_MAX_DEPTH) {
469
+ jp->error = GRAVITO_CBOR_ERROR_PARSE;
470
+ return;
471
+ }
472
+
473
+ /* 期望 '{' */
474
+ if (jp_next(jp) != '{') {
475
+ jp->error = GRAVITO_CBOR_ERROR_PARSE;
476
+ return;
477
+ }
478
+
479
+ /* 先掃描計算 key 數量(不寫入任何東西) */
480
+ size_t saved_pos = jp->pos;
481
+ size_t saved_enc_offset = enc->offset;
482
+ uint32_t count = 0;
483
+
484
+ /* 跳過空物件 */
485
+ if (jp_peek(jp) == '}') {
486
+ jp->pos++; /* 消耗 '}' */
487
+ enc_type_len(enc, CBOR_MAP, 0);
488
+ return;
489
+ }
490
+
491
+ /* 計算 key 數量(簡易方法:掃描頂層逗號數 + 1)*/
492
+ {
493
+ int scan_depth = 0;
494
+ size_t scan_pos = jp->pos;
495
+ count = 1;
496
+ while (scan_pos < jp->length) {
497
+ char c = jp->json[scan_pos];
498
+ if (c == '"') {
499
+ scan_pos++;
500
+ while (scan_pos < jp->length && jp->json[scan_pos] != '"') {
501
+ if (jp->json[scan_pos] == '\\') scan_pos++; /* 跳過轉義 */
502
+ scan_pos++;
503
+ }
504
+ scan_pos++; /* 跳過閉引號 */
505
+ continue;
506
+ }
507
+ if (c == '{' || c == '[') { scan_depth++; scan_pos++; continue; }
508
+ if (c == '}' || c == ']') {
509
+ if (scan_depth == 0) break;
510
+ scan_depth--;
511
+ scan_pos++;
512
+ continue;
513
+ }
514
+ if (c == ',' && scan_depth == 0) count++;
515
+ scan_pos++;
516
+ }
517
+ }
518
+
519
+ /* 寫入 CBOR map header */
520
+ enc_type_len(enc, CBOR_MAP, count);
521
+
522
+ /* 解析 key-value 對 */
523
+ uint32_t i;
524
+ for (i = 0; i < count; i++) {
525
+ if (jp->error || enc->error) return;
526
+
527
+ if (i > 0) {
528
+ if (jp_next(jp) != ',') {
529
+ jp->error = GRAVITO_CBOR_ERROR_PARSE;
530
+ return;
531
+ }
532
+ }
533
+
534
+ /* 解析 key(必須是字串) */
535
+ jp_skip_ws(jp);
536
+ encode_json_string(enc, jp);
537
+ if (jp->error || enc->error) return;
538
+
539
+ /* 期望 ':' */
540
+ if (jp_next(jp) != ':') {
541
+ jp->error = GRAVITO_CBOR_ERROR_PARSE;
542
+ return;
543
+ }
544
+
545
+ /* 解析 value */
546
+ encode_json_value(enc, jp, depth + 1);
547
+ }
548
+
549
+ /* 期望 '}' */
550
+ if (jp_next(jp) != '}') {
551
+ jp->error = GRAVITO_CBOR_ERROR_PARSE;
552
+ return;
553
+ }
554
+ }
555
+
556
+ /**
557
+ * 解析 JSON array,編碼為 CBOR array
558
+ */
559
+ static void encode_json_array(CborEncoder *enc, JsonParser *jp, int depth) {
560
+ if (jp->error || enc->error) return;
561
+ if (depth >= GRAVITO_CBOR_MAX_DEPTH) {
562
+ jp->error = GRAVITO_CBOR_ERROR_PARSE;
563
+ return;
564
+ }
565
+
566
+ /* 期望 '[' */
567
+ if (jp_next(jp) != '[') {
568
+ jp->error = GRAVITO_CBOR_ERROR_PARSE;
569
+ return;
570
+ }
571
+
572
+ /* 空陣列 */
573
+ if (jp_peek(jp) == ']') {
574
+ jp->pos++; /* 消耗 ']' */
575
+ enc_type_len(enc, CBOR_ARRAY, 0);
576
+ return;
577
+ }
578
+
579
+ /* 計算元素數量 */
580
+ uint32_t count = 1;
581
+ {
582
+ int scan_depth = 0;
583
+ size_t scan_pos = jp->pos;
584
+ while (scan_pos < jp->length) {
585
+ char c = jp->json[scan_pos];
586
+ if (c == '"') {
587
+ scan_pos++;
588
+ while (scan_pos < jp->length && jp->json[scan_pos] != '"') {
589
+ if (jp->json[scan_pos] == '\\') scan_pos++;
590
+ scan_pos++;
591
+ }
592
+ scan_pos++;
593
+ continue;
594
+ }
595
+ if (c == '{' || c == '[') { scan_depth++; scan_pos++; continue; }
596
+ if (c == '}' || c == ']') {
597
+ if (scan_depth == 0) break;
598
+ scan_depth--;
599
+ scan_pos++;
600
+ continue;
601
+ }
602
+ if (c == ',' && scan_depth == 0) count++;
603
+ scan_pos++;
604
+ }
605
+ }
606
+
607
+ /* 寫入 CBOR array header */
608
+ enc_type_len(enc, CBOR_ARRAY, count);
609
+
610
+ /* 解析元素 */
611
+ uint32_t i;
612
+ for (i = 0; i < count; i++) {
613
+ if (jp->error || enc->error) return;
614
+ if (i > 0) {
615
+ if (jp_next(jp) != ',') {
616
+ jp->error = GRAVITO_CBOR_ERROR_PARSE;
617
+ return;
618
+ }
619
+ }
620
+ encode_json_value(enc, jp, depth + 1);
621
+ }
622
+
623
+ /* 期望 ']' */
624
+ if (jp_next(jp) != ']') {
625
+ jp->error = GRAVITO_CBOR_ERROR_PARSE;
626
+ return;
627
+ }
628
+ }
629
+
630
+ /**
631
+ * 解析單個 JSON 值,編碼為對應的 CBOR 類型
632
+ */
633
+ static void encode_json_value(CborEncoder *enc, JsonParser *jp, int depth) {
634
+ if (jp->error || enc->error) return;
635
+ if (depth >= GRAVITO_CBOR_MAX_DEPTH) {
636
+ jp->error = GRAVITO_CBOR_ERROR_PARSE;
637
+ return;
638
+ }
639
+
640
+ char c = jp_peek(jp);
641
+
642
+ switch (c) {
643
+ case '{':
644
+ encode_json_object(enc, jp, depth);
645
+ break;
646
+
647
+ case '[':
648
+ encode_json_array(enc, jp, depth);
649
+ break;
650
+
651
+ case '"':
652
+ encode_json_string(enc, jp);
653
+ break;
654
+
655
+ case 't':
656
+ /* true */
657
+ if (jp->pos + 4 <= jp->length &&
658
+ jp->json[jp->pos] == 't' && jp->json[jp->pos+1] == 'r' &&
659
+ jp->json[jp->pos+2] == 'u' && jp->json[jp->pos+3] == 'e') {
660
+ jp->pos += 4;
661
+ enc_u8(enc, (CBOR_SIMPLE << 5) | CBOR_TRUE);
662
+ } else {
663
+ jp->error = GRAVITO_CBOR_ERROR_PARSE;
664
+ }
665
+ break;
666
+
667
+ case 'f':
668
+ /* false */
669
+ if (jp->pos + 5 <= jp->length &&
670
+ jp->json[jp->pos] == 'f' && jp->json[jp->pos+1] == 'a' &&
671
+ jp->json[jp->pos+2] == 'l' && jp->json[jp->pos+3] == 's' &&
672
+ jp->json[jp->pos+4] == 'e') {
673
+ jp->pos += 5;
674
+ enc_u8(enc, (CBOR_SIMPLE << 5) | CBOR_FALSE);
675
+ } else {
676
+ jp->error = GRAVITO_CBOR_ERROR_PARSE;
677
+ }
678
+ break;
679
+
680
+ case 'n':
681
+ /* null */
682
+ if (jp->pos + 4 <= jp->length &&
683
+ jp->json[jp->pos] == 'n' && jp->json[jp->pos+1] == 'u' &&
684
+ jp->json[jp->pos+2] == 'l' && jp->json[jp->pos+3] == 'l') {
685
+ jp->pos += 4;
686
+ enc_u8(enc, (CBOR_SIMPLE << 5) | CBOR_NULL);
687
+ } else {
688
+ jp->error = GRAVITO_CBOR_ERROR_PARSE;
689
+ }
690
+ break;
691
+
692
+ case '-':
693
+ case '0': case '1': case '2': case '3': case '4':
694
+ case '5': case '6': case '7': case '8': case '9':
695
+ encode_json_number(enc, jp);
696
+ break;
697
+
698
+ default:
699
+ jp->error = GRAVITO_CBOR_ERROR_PARSE;
700
+ break;
701
+ }
702
+ }
703
+
704
+ /* ==================== 解碼輔助函數 ==================== */
705
+
706
+ static int dec_has(CborDecoder *dec, size_t needed) {
707
+ if (dec->error) return 0;
708
+ if (dec->offset + needed > dec->length) {
709
+ dec->error = GRAVITO_CBOR_ERROR_PARSE;
710
+ return 0;
711
+ }
712
+ return 1;
713
+ }
714
+
715
+ static uint8_t dec_u8(CborDecoder *dec) {
716
+ if (!dec_has(dec, 1)) return 0;
717
+ return dec->data[dec->offset++];
718
+ }
719
+
720
+ /**
721
+ * 讀取 CBOR additional info 的值
722
+ */
723
+ static uint32_t dec_read_uint(CborDecoder *dec, uint8_t ai) {
724
+ if (ai < 24) return ai;
725
+ if (ai == CBOR_AI_UINT8) return dec_u8(dec);
726
+ if (ai == CBOR_AI_UINT16) {
727
+ uint8_t b1 = dec_u8(dec);
728
+ uint8_t b2 = dec_u8(dec);
729
+ return ((uint32_t)b1 << 8) | b2;
730
+ }
731
+ if (ai == CBOR_AI_UINT32) {
732
+ uint8_t b1 = dec_u8(dec);
733
+ uint8_t b2 = dec_u8(dec);
734
+ uint8_t b3 = dec_u8(dec);
735
+ uint8_t b4 = dec_u8(dec);
736
+ return ((uint32_t)b1 << 24) | ((uint32_t)b2 << 16) | ((uint32_t)b3 << 8) | b4;
737
+ }
738
+ /* UINT64 不支援 */
739
+ dec->error = GRAVITO_CBOR_ERROR_PARSE;
740
+ return 0;
741
+ }
742
+
743
+ /**
744
+ * JSON 輸出輔助函數
745
+ */
746
+ typedef struct {
747
+ char *buffer;
748
+ size_t capacity;
749
+ size_t offset;
750
+ int error;
751
+ } JsonWriter;
752
+
753
+ static void jw_ensure(JsonWriter *jw, size_t needed) {
754
+ if (jw->error) return;
755
+ if (jw->offset + needed > jw->capacity) {
756
+ jw->error = GRAVITO_CBOR_ERROR_BUFFER_FULL;
757
+ }
758
+ }
759
+
760
+ static void jw_char(JsonWriter *jw, char c) {
761
+ jw_ensure(jw, 1);
762
+ if (!jw->error) jw->buffer[jw->offset++] = c;
763
+ }
764
+
765
+ static void jw_str(JsonWriter *jw, const char *s, size_t len) {
766
+ jw_ensure(jw, len);
767
+ if (!jw->error) {
768
+ memcpy(&jw->buffer[jw->offset], s, len);
769
+ jw->offset += len;
770
+ }
771
+ }
772
+
773
+ /**
774
+ * 寫入 JSON 字串(帶轉義)
775
+ */
776
+ static void jw_json_string(JsonWriter *jw, const uint8_t *utf8, size_t len) {
777
+ jw_char(jw, '"');
778
+ size_t i;
779
+ for (i = 0; i < len; i++) {
780
+ uint8_t c = utf8[i];
781
+ switch (c) {
782
+ case '"': jw_str(jw, "\\\"", 2); break;
783
+ case '\\': jw_str(jw, "\\\\", 2); break;
784
+ case '\b': jw_str(jw, "\\b", 2); break;
785
+ case '\f': jw_str(jw, "\\f", 2); break;
786
+ case '\n': jw_str(jw, "\\n", 2); break;
787
+ case '\r': jw_str(jw, "\\r", 2); break;
788
+ case '\t': jw_str(jw, "\\t", 2); break;
789
+ default:
790
+ if (c < 0x20) {
791
+ /* 控制字元:\u00XX */
792
+ char hex[7];
793
+ hex[0] = '\\'; hex[1] = 'u'; hex[2] = '0'; hex[3] = '0';
794
+ hex[4] = "0123456789abcdef"[(c >> 4) & 0xF];
795
+ hex[5] = "0123456789abcdef"[c & 0xF];
796
+ jw_str(jw, hex, 6);
797
+ } else {
798
+ jw_char(jw, (char)c);
799
+ }
800
+ break;
801
+ }
802
+ }
803
+ jw_char(jw, '"');
804
+ }
805
+
806
+ /**
807
+ * 寫入無符號整數的十進制表示
808
+ */
809
+ static void jw_uint(JsonWriter *jw, uint32_t val) {
810
+ char buf[12]; /* 最多 10 位 + 安全 */
811
+ int len = 0;
812
+ if (val == 0) {
813
+ jw_char(jw, '0');
814
+ return;
815
+ }
816
+ while (val > 0) {
817
+ buf[len++] = '0' + (val % 10);
818
+ val /= 10;
819
+ }
820
+ /* 反轉 */
821
+ int i;
822
+ for (i = len - 1; i >= 0; i--) {
823
+ jw_char(jw, buf[i]);
824
+ }
825
+ }
826
+
827
+ /**
828
+ * 寫入 float64 的 JSON 表示
829
+ * 使用 snprintf + 精度搜尋找到最短的精確表示
830
+ */
831
+ static void jw_float64(JsonWriter *jw, double val) {
832
+ /* 特殊值處理(JSON 不支援 NaN/Infinity) */
833
+ if (val != val) { jw_str(jw, "null", 4); return; }
834
+ if (val == 1.0/0.0) { jw_str(jw, "null", 4); return; }
835
+ if (val == -1.0/0.0) { jw_str(jw, "null", 4); return; }
836
+
837
+ char buf[32];
838
+ int len;
839
+ int prec;
840
+
841
+ /* 找到最短的精確表示(往返一致性) */
842
+ for (prec = 1; prec <= 17; prec++) {
843
+ len = snprintf(buf, sizeof(buf), "%.*g", prec, val);
844
+ double check = strtod(buf, 0);
845
+ if (check == val) {
846
+ jw_str(jw, buf, len);
847
+ return;
848
+ }
849
+ }
850
+
851
+ /* 回退到最大精度 */
852
+ len = snprintf(buf, sizeof(buf), "%.17g", val);
853
+ jw_str(jw, buf, len);
854
+ }
855
+
856
+ /* 前向宣告 */
857
+ static void decode_cbor_value(CborDecoder *dec, JsonWriter *jw, int depth);
858
+
859
+ /**
860
+ * 解碼 CBOR 值為 JSON
861
+ */
862
+ static void decode_cbor_value(CborDecoder *dec, JsonWriter *jw, int depth) {
863
+ if (dec->error || jw->error) return;
864
+ if (depth >= GRAVITO_CBOR_MAX_DEPTH) {
865
+ dec->error = GRAVITO_CBOR_ERROR_PARSE;
866
+ return;
867
+ }
868
+
869
+ uint8_t byte = dec_u8(dec);
870
+ if (dec->error) return;
871
+
872
+ uint8_t mt = (byte >> 5) & 0x07;
873
+ uint8_t ai = byte & 0x1F;
874
+
875
+ switch (mt) {
876
+ case CBOR_UINT: {
877
+ uint32_t val = dec_read_uint(dec, ai);
878
+ if (!dec->error) jw_uint(jw, val);
879
+ break;
880
+ }
881
+
882
+ case CBOR_NEGINT: {
883
+ uint32_t val = dec_read_uint(dec, ai);
884
+ if (!dec->error) {
885
+ /* CBOR negint: -1 - n */
886
+ jw_char(jw, '-');
887
+ /* 需要輸出 val + 1 */
888
+ jw_uint(jw, val + 1);
889
+ }
890
+ break;
891
+ }
892
+
893
+ case CBOR_BYTES: {
894
+ /* 位元組串 - 不常見於 JSON,跳過 */
895
+ uint32_t len = dec_read_uint(dec, ai);
896
+ if (!dec->error) {
897
+ if (!dec_has(dec, len)) return;
898
+ /* 輸出為 null(JSON 不支援原始位元組) */
899
+ jw_str(jw, "null", 4);
900
+ dec->offset += len;
901
+ }
902
+ break;
903
+ }
904
+
905
+ case CBOR_TEXT: {
906
+ uint32_t len = dec_read_uint(dec, ai);
907
+ if (dec->error) return;
908
+ if (!dec_has(dec, len)) return;
909
+ const uint8_t *text = &dec->data[dec->offset];
910
+ jw_json_string(jw, text, len);
911
+ dec->offset += len;
912
+ break;
913
+ }
914
+
915
+ case CBOR_ARRAY: {
916
+ uint32_t count = dec_read_uint(dec, ai);
917
+ if (dec->error) return;
918
+ jw_char(jw, '[');
919
+ uint32_t i;
920
+ for (i = 0; i < count; i++) {
921
+ if (dec->error || jw->error) return;
922
+ if (i > 0) jw_char(jw, ',');
923
+ decode_cbor_value(dec, jw, depth + 1);
924
+ }
925
+ jw_char(jw, ']');
926
+ break;
927
+ }
928
+
929
+ case CBOR_MAP: {
930
+ uint32_t count = dec_read_uint(dec, ai);
931
+ if (dec->error) return;
932
+ jw_char(jw, '{');
933
+ uint32_t i;
934
+ for (i = 0; i < count; i++) {
935
+ if (dec->error || jw->error) return;
936
+ if (i > 0) jw_char(jw, ',');
937
+ /* key */
938
+ decode_cbor_value(dec, jw, depth + 1);
939
+ jw_char(jw, ':');
940
+ /* value */
941
+ decode_cbor_value(dec, jw, depth + 1);
942
+ }
943
+ jw_char(jw, '}');
944
+ break;
945
+ }
946
+
947
+ case CBOR_TAG: {
948
+ /* 跳過 tag,直接解碼內容 */
949
+ dec_read_uint(dec, ai); /* 讀取 tag number 但忽略 */
950
+ decode_cbor_value(dec, jw, depth);
951
+ break;
952
+ }
953
+
954
+ case CBOR_SIMPLE: {
955
+ if (ai == CBOR_FALSE) {
956
+ jw_str(jw, "false", 5);
957
+ } else if (ai == CBOR_TRUE) {
958
+ jw_str(jw, "true", 4);
959
+ } else if (ai == CBOR_NULL) {
960
+ jw_str(jw, "null", 4);
961
+ } else if (ai == CBOR_AI_FLOAT64) {
962
+ /* 讀取 8 bytes IEEE 754 double */
963
+ if (!dec_has(dec, 8)) return;
964
+ union { double d; uint64_t u; } conv;
965
+ conv.u = 0;
966
+ int i;
967
+ for (i = 0; i < 8; i++) {
968
+ conv.u = (conv.u << 8) | dec->data[dec->offset++];
969
+ }
970
+ jw_float64(jw, conv.d);
971
+ } else if (ai == CBOR_AI_UINT16) {
972
+ /* float16 - 簡化處理,直接跳過 */
973
+ if (!dec_has(dec, 2)) return;
974
+ dec->offset += 2;
975
+ jw_str(jw, "0", 1);
976
+ } else if (ai == CBOR_AI_UINT32) {
977
+ /* float32 */
978
+ if (!dec_has(dec, 4)) return;
979
+ union { float f; uint32_t u; } conv32;
980
+ conv32.u = 0;
981
+ int i;
982
+ for (i = 0; i < 4; i++) {
983
+ conv32.u = (conv32.u << 8) | dec->data[dec->offset++];
984
+ }
985
+ jw_float64(jw, (double)conv32.f);
986
+ } else {
987
+ dec->error = GRAVITO_CBOR_ERROR_PARSE;
988
+ }
989
+ break;
990
+ }
991
+
992
+ default:
993
+ dec->error = GRAVITO_CBOR_ERROR_PARSE;
994
+ break;
995
+ }
996
+ }
997
+
998
+ /* ==================== 公開 API ==================== */
999
+
1000
+ /**
1001
+ * 編碼 JSON 字串為 CBOR 二進制
1002
+ *
1003
+ * 輸入:JSON 字串(通常來自 JSON.stringify(obj))
1004
+ * 輸出:CBOR 二進制資料
1005
+ *
1006
+ * @param json_input JSON 字串指標
1007
+ * @param json_len JSON 字串長度(位元組)
1008
+ * @param output_buf 輸出 buffer 指標
1009
+ * @param output_cap 輸出 buffer 容量
1010
+ * @return > 0: 寫入的位元組數
1011
+ * -1: buffer 不足
1012
+ * -2: JSON 解析錯誤
1013
+ */
1014
+ int gravito_cbor_encode(const char *json_input, size_t json_len,
1015
+ uint8_t *output_buf, size_t output_cap) {
1016
+ if (!json_input || !output_buf || json_len == 0) {
1017
+ return GRAVITO_CBOR_ERROR_PARSE;
1018
+ }
1019
+
1020
+ CborEncoder enc;
1021
+ enc.buffer = output_buf;
1022
+ enc.capacity = output_cap;
1023
+ enc.offset = 0;
1024
+ enc.error = 0;
1025
+
1026
+ JsonParser jp;
1027
+ jp.json = json_input;
1028
+ jp.length = json_len;
1029
+ jp.pos = 0;
1030
+ jp.error = 0;
1031
+
1032
+ /* 跳過前導空白 */
1033
+ jp_skip_ws(&jp);
1034
+
1035
+ /* 根值必須是物件或陣列 */
1036
+ char first = jp_peek(&jp);
1037
+ if (first == '{') {
1038
+ encode_json_object(&enc, &jp, 0);
1039
+ } else if (first == '[') {
1040
+ encode_json_array(&enc, &jp, 0);
1041
+ } else {
1042
+ return GRAVITO_CBOR_ERROR_PARSE;
1043
+ }
1044
+
1045
+ if (jp.error) return jp.error;
1046
+ if (enc.error) return enc.error;
1047
+
1048
+ return (int)enc.offset;
1049
+ }
1050
+
1051
+ /**
1052
+ * 解碼 CBOR 二進制為 JSON 字串
1053
+ *
1054
+ * @param cbor_input CBOR 二進制資料
1055
+ * @param cbor_len CBOR 資料長度
1056
+ * @param json_output JSON 輸出 buffer
1057
+ * @param json_cap JSON 輸出 buffer 容量
1058
+ * @return > 0: 寫入的位元組數
1059
+ * -1: buffer 不足
1060
+ * -2: CBOR 解碼錯誤
1061
+ */
1062
+ int gravito_cbor_decode(const uint8_t *cbor_input, size_t cbor_len,
1063
+ char *json_output, size_t json_cap) {
1064
+ if (!cbor_input || !json_output || cbor_len == 0) {
1065
+ return GRAVITO_CBOR_ERROR_PARSE;
1066
+ }
1067
+
1068
+ CborDecoder dec;
1069
+ dec.data = cbor_input;
1070
+ dec.length = cbor_len;
1071
+ dec.offset = 0;
1072
+ dec.error = 0;
1073
+
1074
+ JsonWriter jw;
1075
+ jw.buffer = json_output;
1076
+ jw.capacity = json_cap;
1077
+ jw.offset = 0;
1078
+ jw.error = 0;
1079
+
1080
+ decode_cbor_value(&dec, &jw, 0);
1081
+
1082
+ if (dec.error) return dec.error;
1083
+ if (jw.error) return jw.error;
1084
+
1085
+ return (int)jw.offset;
1086
+ }
1087
+
1088
+ /* ==================== 輔助測試函數 ==================== */
1089
+
1090
+ /**
1091
+ * 向 buffer 寫入 CBOR 字串(用於測試)
1092
+ */
1093
+ size_t gravito_cbor_write_string(uint8_t *output_buf, size_t output_cap,
1094
+ const char *str) {
1095
+ CborEncoder enc;
1096
+ enc.buffer = output_buf;
1097
+ enc.capacity = output_cap;
1098
+ enc.offset = 0;
1099
+ enc.error = 0;
1100
+
1101
+ size_t str_len = strlen(str);
1102
+ enc_type_len(&enc, CBOR_TEXT, (uint32_t)str_len);
1103
+ enc_bytes(&enc, (const uint8_t *)str, str_len);
1104
+
1105
+ if (enc.error != 0) return 0;
1106
+ return enc.offset;
1107
+ }
1108
+
1109
+ /**
1110
+ * 向 buffer 寫入 CBOR 整數(用於測試)
1111
+ */
1112
+ size_t gravito_cbor_write_int(uint8_t *output_buf, size_t output_cap,
1113
+ int64_t value) {
1114
+ CborEncoder enc;
1115
+ enc.buffer = output_buf;
1116
+ enc.capacity = output_cap;
1117
+ enc.offset = 0;
1118
+ enc.error = 0;
1119
+
1120
+ if (value >= 0) {
1121
+ enc_type_len(&enc, CBOR_UINT, (uint32_t)value);
1122
+ } else {
1123
+ enc_type_len(&enc, CBOR_NEGINT, (uint32_t)(-1 - value));
1124
+ }
1125
+
1126
+ if (enc.error != 0) return 0;
1127
+ return enc.offset;
1128
+ }
1129
+
1130
+ /**
1131
+ * 向 buffer 寫入 CBOR null(用於測試)
1132
+ */
1133
+ size_t gravito_cbor_write_null(uint8_t *output_buf, size_t output_cap) {
1134
+ if (output_cap < 1) return 0;
1135
+ output_buf[0] = (CBOR_SIMPLE << 5) | CBOR_NULL;
1136
+ return 1;
1137
+ }
1138
+
1139
+ /**
1140
+ * 向 buffer 寫入 CBOR 布林值(用於測試)
1141
+ */
1142
+ size_t gravito_cbor_write_bool(uint8_t *output_buf, size_t output_cap,
1143
+ int value) {
1144
+ if (output_cap < 1) return 0;
1145
+ uint8_t sv = value ? CBOR_TRUE : CBOR_FALSE;
1146
+ output_buf[0] = (CBOR_SIMPLE << 5) | sv;
1147
+ return 1;
1148
+ }