KSJSONCodec.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. //
  2. // KSJSONCodec.h
  3. //
  4. // Created by Karl Stenerud on 2012-01-07.
  5. //
  6. // Copyright (c) 2012 Karl Stenerud. All rights reserved.
  7. //
  8. // Permission is hereby granted, free of charge, to any person obtaining a copy
  9. // of this software and associated documentation files (the "Software"), to deal
  10. // in the Software without restriction, including without limitation the rights
  11. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. // copies of the Software, and to permit persons to whom the Software is
  13. // furnished to do so, subject to the following conditions:
  14. //
  15. // The above copyright notice and this permission notice shall remain in place
  16. // in this source code.
  17. //
  18. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. // THE SOFTWARE.
  25. //
  26. /* Reads and writes JSON encoded data.
  27. */
  28. #ifndef HDR_KSJSONCodec_h
  29. #define HDR_KSJSONCodec_h
  30. #ifdef __cplusplus
  31. extern "C" {
  32. #endif
  33. #include <stdbool.h>
  34. #include <stdint.h>
  35. /* Tells the encoder to automatically determine the length of a field value.
  36. * Currently, this is done using strlen().
  37. */
  38. #define KSJSON_SIZE_AUTOMATIC -1
  39. enum
  40. {
  41. /** Encoding or decoding: Everything completed without error */
  42. KSJSON_OK = 0,
  43. /** Encoding or decoding: Encountered an unexpected or invalid character */
  44. KSJSON_ERROR_INVALID_CHARACTER = 1,
  45. /** Decoding: Source data was too long. */
  46. KSJSON_ERROR_DATA_TOO_LONG = 2,
  47. /** Encoding: addJSONData could not handle the data.
  48. * This code is not used by the decoder, but is meant to be returned by
  49. * the addJSONData callback method if it couldn't handle the data.
  50. */
  51. KSJSON_ERROR_CANNOT_ADD_DATA = 3,
  52. /** Decoding: Source data appears to be truncated. */
  53. KSJSON_ERROR_INCOMPLETE = 4,
  54. /** Decoding: Parsing failed due to bad data structure/type/contents.
  55. * This code is not used by the decoder, but is meant to be returned
  56. * by the user callback methods if the decoded data is incorrect for
  57. * semantic or structural reasons.
  58. */
  59. KSJSON_ERROR_INVALID_DATA = 5,
  60. };
  61. /** Get a description for an error code.
  62. *
  63. * @param error The error code.
  64. *
  65. * @return A string describing the error.
  66. */
  67. const char* ksjson_stringForError(const int error);
  68. // ============================================================================
  69. // Encode
  70. // ============================================================================
  71. /** Function pointer for adding more UTF-8 encoded JSON data.
  72. *
  73. * @param data The UTF-8 data to add.
  74. *
  75. * @param length The length of the data.
  76. *
  77. * @param userData user-specified contextual data.
  78. *
  79. * @return KSJSON_OK if the data was handled.
  80. * otherwise KSJSON_ERROR_CANNOT_ADD_DATA.
  81. */
  82. typedef int (*KSJSONAddDataFunc)(const char* data, int length, void* userData);
  83. typedef struct
  84. {
  85. /** Function to call to add more encoded JSON data. */
  86. KSJSONAddDataFunc addJSONData;
  87. /** User-specified data */
  88. void* userData;
  89. /** How many containers deep we are. */
  90. int containerLevel;
  91. /** Whether or not the current container is an object. */
  92. bool isObject[200];
  93. /** true if this is the first entry at the current container level. */
  94. bool containerFirstEntry;
  95. bool prettyPrint;
  96. } KSJSONEncodeContext;
  97. /** Begin a new encoding process.
  98. *
  99. * @param context The encoding context.
  100. *
  101. * @param prettyPrint If true, insert whitespace to make the output pretty.
  102. *
  103. * @param addJSONData Function to handle adding data.
  104. *
  105. * @param userData User-specified data which gets passed to addJSONData.
  106. */
  107. void ksjson_beginEncode(KSJSONEncodeContext* context,
  108. bool prettyPrint,
  109. KSJSONAddDataFunc addJSONData,
  110. void* userData);
  111. /** End the encoding process, ending any remaining open containers.
  112. *
  113. * @return KSJSON_OK if the process was successful.
  114. */
  115. int ksjson_endEncode(KSJSONEncodeContext* context);
  116. /** Add a boolean element.
  117. *
  118. * @param context The encoding context.
  119. *
  120. * @param name The element's name.
  121. *
  122. * @param value The element's value.
  123. *
  124. * @return KSJSON_OK if the process was successful.
  125. */
  126. int ksjson_addBooleanElement(KSJSONEncodeContext* context,
  127. const char* name,
  128. bool value);
  129. /** Add an integer element.
  130. *
  131. * @param context The encoding context.
  132. *
  133. * @param name The element's name.
  134. *
  135. * @param value The element's value.
  136. *
  137. * @return KSJSON_OK if the process was successful.
  138. */
  139. int ksjson_addIntegerElement(KSJSONEncodeContext* context,
  140. const char* name,
  141. int64_t value);
  142. /** Add an unsigned integer element.
  143. *
  144. * @param context The encoding context.
  145. *
  146. * @param name The element's name.
  147. *
  148. * @param value The element's value.
  149. *
  150. * @return KSJSON_OK if the process was successful.
  151. */
  152. int ksjson_addUIntegerElement(KSJSONEncodeContext* const context,
  153. const char* const name,
  154. uint64_t value);
  155. /** Add a floating point element.
  156. *
  157. * @param context The encoding context.
  158. *
  159. * @param name The element's name.
  160. *
  161. * @param value The element's value.
  162. *
  163. * @return KSJSON_OK if the process was successful.
  164. */
  165. int ksjson_addFloatingPointElement(KSJSONEncodeContext* context,
  166. const char* name,
  167. double value);
  168. /** Add a null element.
  169. *
  170. * @param context The encoding context.
  171. *
  172. * @param name The element's name.
  173. *
  174. * @return KSJSON_OK if the process was successful.
  175. */
  176. int ksjson_addNullElement(KSJSONEncodeContext* context,
  177. const char* name);
  178. /** Add a string element.
  179. *
  180. * @param context The encoding context.
  181. *
  182. * @param name The element's name.
  183. *
  184. * @param value The element's value.
  185. *
  186. * @param length the length of the string, or KSJSON_SIZE_AUTOMATIC.
  187. *
  188. * @return KSJSON_OK if the process was successful.
  189. */
  190. int ksjson_addStringElement(KSJSONEncodeContext* context,
  191. const char* name,
  192. const char* value,
  193. int length);
  194. /** Start an incrementally-built string element.
  195. *
  196. * Use this for constructing very large strings.
  197. *
  198. * @param context The encoding context.
  199. *
  200. * @param name The element's name.
  201. *
  202. * @return KSJSON_OK if the process was successful.
  203. */
  204. int ksjson_beginStringElement(KSJSONEncodeContext* context,
  205. const char* name);
  206. /** Add a string fragment to an incrementally-built string element.
  207. *
  208. * @param context The encoding context.
  209. *
  210. * @param value The string fragment.
  211. *
  212. * @param length the length of the string fragment.
  213. *
  214. * @return KSJSON_OK if the process was successful.
  215. */
  216. int ksjson_appendStringElement(KSJSONEncodeContext* context,
  217. const char* value,
  218. int length);
  219. /** End an incrementally-built string element.
  220. *
  221. * @param context The encoding context.
  222. *
  223. * @return KSJSON_OK if the process was successful.
  224. */
  225. int ksjson_endStringElement(KSJSONEncodeContext* context);
  226. /** Add a string element. The element will be converted to string-coded hex.
  227. *
  228. * @param context The encoding context.
  229. *
  230. * @param name The element's name.
  231. *
  232. * @param value The element's value.
  233. *
  234. * @param length The length of the data.
  235. *
  236. * @return KSJSON_OK if the process was successful.
  237. */
  238. int ksjson_addDataElement(KSJSONEncodeContext* const context,
  239. const char* name,
  240. const char* value,
  241. int length);
  242. /** Start an incrementally-built data element. The element will be converted
  243. * to string-coded hex.
  244. *
  245. * Use this for constructing very large data elements.
  246. *
  247. * @param context The encoding context.
  248. *
  249. * @param name The element's name.
  250. *
  251. * @return KSJSON_OK if the process was successful.
  252. */
  253. int ksjson_beginDataElement(KSJSONEncodeContext* const context,
  254. const char* const name);
  255. /** Add a data fragment to an incrementally-built data element.
  256. *
  257. * @param context The encoding context.
  258. *
  259. * @param value The data fragment.
  260. *
  261. * @param length the length of the data fragment.
  262. *
  263. * @return KSJSON_OK if the process was successful.
  264. */
  265. int ksjson_appendDataElement(KSJSONEncodeContext* const context,
  266. const char* const value,
  267. int length);
  268. /** End an incrementally-built data element.
  269. *
  270. * @param context The encoding context.
  271. *
  272. * @return KSJSON_OK if the process was successful.
  273. */
  274. int ksjson_endDataElement(KSJSONEncodeContext* const context);
  275. /** Add a pre-formatted JSON element.
  276. *
  277. * @param encodeContext The encoding context.
  278. *
  279. * @param name The element's name.
  280. *
  281. * @param jsonData The element's value. MUST BE VALID JSON!
  282. *
  283. * @param jsonDataLength The length of the element.
  284. *
  285. * @param closeLastContainer If false, do not close the last container.
  286. *
  287. * @return KSJSON_OK if the process was successful.
  288. */
  289. int ksjson_addJSONElement(KSJSONEncodeContext* const encodeContext,
  290. const char* restrict const name,
  291. const char* restrict const jsonData,
  292. const int jsonDataLength,
  293. const bool closeLastContainer);
  294. /** Begin a new object container.
  295. *
  296. * @param context The encoding context.
  297. *
  298. * @param name The object's name.
  299. *
  300. * @return KSJSON_OK if the process was successful.
  301. */
  302. int ksjson_beginObject(KSJSONEncodeContext* context,
  303. const char* name);
  304. /** Begin a new array container.
  305. *
  306. * @param context The encoding context.
  307. *
  308. * @param name The array's name.
  309. *
  310. * @return KSJSON_OK if the process was successful.
  311. */
  312. int ksjson_beginArray(KSJSONEncodeContext* context,
  313. const char* name);
  314. /** Begin a generic JSON element, adding any necessary JSON preamble text,
  315. * including commas and names.
  316. * Note: This does not add any object or array specifiers ('{', '[').
  317. *
  318. * @param context The JSON context.
  319. *
  320. * @param name The name of the next element (only needed if parent is a dictionary).
  321. */
  322. int ksjson_beginElement(KSJSONEncodeContext* const context,
  323. const char* const name);
  324. /** Add JSON data manually.
  325. * This function just passes your data directly through, even if it's malforned.
  326. *
  327. * @param context The encoding context.
  328. *
  329. * @param data The data to write.
  330. *
  331. * @param length The length of the data.
  332. *
  333. * @return KSJSON_OK if the process was successful.
  334. */
  335. int ksjson_addRawJSONData(KSJSONEncodeContext* const context,
  336. const char* const data,
  337. const int length);
  338. /** End the current container and return to the next higher level.
  339. *
  340. * @param context The encoding context.
  341. *
  342. * @return KSJSON_OK if the process was successful.
  343. */
  344. int ksjson_endContainer(KSJSONEncodeContext* context);
  345. /** Decode and add JSON data from a file.
  346. *
  347. * @param context The encoding context.
  348. *
  349. * @param name The name to give the top element from the file.
  350. *
  351. * @param filename The file to read from.
  352. *
  353. * @param closeLastContainer If false, do not close the last container.
  354. */
  355. int ksjson_addJSONFromFile(KSJSONEncodeContext* const context,
  356. const char* restrict const name,
  357. const char* restrict const filename,
  358. const bool closeLastContainer);
  359. // ============================================================================
  360. // Decode
  361. // ============================================================================
  362. /**
  363. * Callbacks called during a JSON decode process.
  364. * All function pointers must point to valid functions.
  365. */
  366. typedef struct KSJSONDecodeCallbacks
  367. {
  368. /** Called when a boolean element is decoded.
  369. *
  370. * @param name The element's name.
  371. *
  372. * @param value The element's value.
  373. *
  374. * @param userData Data that was specified when calling ksjson_decode().
  375. *
  376. * @return KSJSON_OK if decoding should continue.
  377. */
  378. int (*onBooleanElement)(const char* name,
  379. bool value,
  380. void* userData);
  381. /** Called when a floating point element is decoded.
  382. *
  383. * @param name The element's name.
  384. *
  385. * @param value The element's value.
  386. *
  387. * @param userData Data that was specified when calling ksjson_decode().
  388. *
  389. * @return KSJSON_OK if decoding should continue.
  390. */
  391. int (*onFloatingPointElement)(const char* name,
  392. double value,
  393. void* userData);
  394. /** Called when an integer element is decoded.
  395. *
  396. * @param name The element's name.
  397. *
  398. * @param value The element's value.
  399. *
  400. * @param userData Data that was specified when calling ksjson_decode().
  401. *
  402. * @return KSJSON_OK if decoding should continue.
  403. */
  404. int (*onIntegerElement)(const char* name,
  405. int64_t value,
  406. void* userData);
  407. /** Called when a null element is decoded.
  408. *
  409. * @param name The element's name.
  410. *
  411. * @param userData Data that was specified when calling ksjson_decode().
  412. *
  413. * @return KSJSON_OK if decoding should continue.
  414. */
  415. int (*onNullElement)(const char* name,
  416. void* userData);
  417. /** Called when a string element is decoded.
  418. *
  419. * @param name The element's name.
  420. *
  421. * @param value The element's value.
  422. *
  423. * @param userData Data that was specified when calling ksjson_decode().
  424. *
  425. * @return KSJSON_OK if decoding should continue.
  426. */
  427. int (*onStringElement)(const char* name,
  428. const char* value,
  429. void* userData);
  430. /** Called when a new object is encountered.
  431. *
  432. * @param name The object's name.
  433. *
  434. * @param userData Data that was specified when calling ksjson_decode().
  435. *
  436. * @return KSJSON_OK if decoding should continue.
  437. */
  438. int (*onBeginObject)(const char* name,
  439. void* userData);
  440. /** Called when a new array is encountered.
  441. *
  442. * @param name The array's name.
  443. *
  444. * @param userData Data that was specified when calling ksjson_decode().
  445. *
  446. * @return KSJSON_OK if decoding should continue.
  447. */
  448. int (*onBeginArray)(const char* name,
  449. void* userData);
  450. /** Called when leaving the current container and returning to the next
  451. * higher level container.
  452. *
  453. * @param userData Data that was specified when calling ksjson_decode().
  454. *
  455. * @return KSJSON_OK if decoding should continue.
  456. */
  457. int (*onEndContainer)(void* userData);
  458. /** Called when the end of the input data is reached.
  459. *
  460. * @param userData Data that was specified when calling ksjson_decode().
  461. *
  462. * @return KSJSON_OK if decoding should continue.
  463. */
  464. int (*onEndData)(void* userData);
  465. } KSJSONDecodeCallbacks;
  466. /** Read a JSON encoded file from the specified FD.
  467. *
  468. * @param data UTF-8 encoded JSON data.
  469. *
  470. * @param length Length of the data.
  471. *
  472. * @param stringBuffer A buffer to use for decoding strings.
  473. * Note: 1/4 of this buffer will be used for dictionary name decoding.
  474. *
  475. * @param stringBufferLength The length of the string buffer.
  476. *
  477. * @param callbacks The callbacks to call while decoding.
  478. *
  479. * @param userData Any data you would like passed to the callbacks.
  480. *
  481. * @oaram errorOffset If not null, will contain the offset into the data
  482. * where the error (if any) occurred.
  483. *
  484. * @return KSJSON_OK if succesful. An error code otherwise.
  485. */
  486. int ksjson_decode(const char* data,
  487. int length,
  488. char* stringBuffer,
  489. int stringBufferLength,
  490. KSJSONDecodeCallbacks* callbacks,
  491. void* userData,
  492. int* errorOffset);
  493. #ifdef __cplusplus
  494. }
  495. #endif
  496. #endif // HDR_KSJSONCodec_h