summaryrefslogtreecommitdiff
path: root/lib/libjson/json.h
blob: a406df04d829b919d4cc65f964682d76ab3c775e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
#ifndef JSON_H
#define JSON_H

#ifndef JSON_ARRAY_INITIAL_CAPACITY
/**
 * @brief Defines the initial capacity for JSON arrays.
 *
 * This value determines the number of elements a JSON array
 * can hold before requiring a reallocation. Adjust this value
 * to optimize memory usage and performance for your specific use case.
 */
#define JSON_ARRAY_INITIAL_CAPACITY 1
#endif

#ifndef JSON_ARRAY_CAPACITY_MULTIPLIER
/**
 * @brief Defines the capacity multiplier for JSON arrays.
 *
 * When a JSON array exceeds its current capacity, its capacity is
 * multiplied by this value to allocate additional space. A higher
 * multiplier reduces the frequency of reallocations but increases
 * memory usage.
 */
#define JSON_ARRAY_CAPACITY_MULTIPLIER 2
#endif

#ifndef JSON_ARRAY_CAPACITY_THRESHOLD
/**
 * @brief Threshold for triggering reallocation in JSON arrays.
 *
 * Defines how full the array must be (relative to capacity)
 * before reallocating. Typically set to 1 (100% full).
 */
#define JSON_ARRAY_CAPACITY_THRESHOLD 1
#endif

#ifndef JSON_OBJECT_INITIAL_CAPACITY
/**
 * @brief Defines the initial capacity for JSON objects.
 *
 * Determines how many key-value pairs a JSON object can store
 * before requiring reallocation. Increase this value to reduce
 * early reallocations for large objects.
 */
#define JSON_OBJECT_INITIAL_CAPACITY 1
#endif

#ifndef JSON_OBJECT_CAPACITY_MULTIPLIER
/**
 * @brief Growth multiplier for JSON object capacity.
 *
 * When the object exceeds its current capacity, the capacity
 * is multiplied by this factor. A larger multiplier reduces
 * the frequency of reallocations but may waste memory.
 */
#define JSON_OBJECT_CAPACITY_MULTIPLIER 2
#endif

#ifndef JSON_OBJECT_CAPACITY_THRESHOLD
/**
 * @brief Threshold for triggering reallocation in JSON objects.
 *
 * Defines how full the object must be (relative to capacity)
 * before reallocating. Typically set to 1 (100% full).
 */
#define JSON_OBJECT_CAPACITY_THRESHOLD 1
#endif

/**
 * @brief Represents a JSON value.
 *
 * This structure encapsulates a JSON value, which can be one of several types
 * including null, boolean, number, string, array, or object. The type of the
 * value is determined by the `type` field, and the actual data is stored in
 * the corresponding member of the union.
 */
struct json_value {
	/**
	 * @brief Enum representing the type of the JSON value.
	 *
	 * The type determines which member of the union is valid.
	 *
	 * - `JSON_TYPE_NULL`: Represents a null value.
	 * - `JSON_TYPE_BOOLEAN`: Represents a boolean value (true/false).
	 * - `JSON_TYPE_NUMBER`: Represents a numeric value.
	 * - `JSON_TYPE_STRING`: Represents a string value.
	 * - `JSON_TYPE_ARRAY`: Represents an array of JSON values.
	 * - `JSON_TYPE_OBJECT`: Represents an object with key-value pairs.
	 */
	enum {
		JSON_TYPE_NULL,	   /**< Null value. */
		JSON_TYPE_BOOLEAN, /**< Boolean value (true/false). */
		JSON_TYPE_NUMBER,  /**< Numeric value. */
		JSON_TYPE_STRING,  /**< String value. */
		JSON_TYPE_ARRAY,   /**< Array of JSON values. */
		JSON_TYPE_OBJECT   /**< Object with key-value pairs. */
	} type;

	/**
	 * @brief Union holding the actual data of the JSON value.
	 *
	 * The type of data stored depends on the `type` field.
	 */
	union {
		/**
		 * @brief Holds a numeric value when `type` is
		 * `JSON_TYPE_NUMBER`.
		 */
		double number;

		/**
		 * @brief Holds an array of JSON values when `type` is
		 * `JSON_TYPE_ARRAY`.
		 *
		 * - `capacity`: The total allocated capacity of the array.
		 * - `length`: The current number of elements in the array.
		 * - `items`: A pointer to an array of pointers to `json_value`
		 * elements.
		 */
		struct {
			int capacity; /**< Total allocated capacity of the
					 array. */
			int length;   /**< Current number of elements in the
					 array. */
			struct json_value **items; /**< Pointer to an array of
						     pointers to `json_value`
						     elements. */
		} array;

		/**
		 * @brief Holds a string value when `type` is
		 * `JSON_TYPE_STRING`.
		 *
		 * - `capacity`: The total allocated capacity of the string.
		 * - `length`: The current length of the string (excluding null
		 * terminator).
		 * - `value`: A pointer to the null-terminated string.
		 */
		struct {
			int capacity; /**< Total allocated capacity of the
					 string. */
			int length; /**< Current length of the string (excluding
			     null terminator). */
			char *value; /**< Pointer to the null-terminated string.
				      */
		} string;

		/**
		 * @brief Holds an object with key-value pairs when `type` is
		 * `JSON_TYPE_OBJECT`.
		 *
		 * - `capacity`: The total allocated capacity for key-value
		 * pairs.
		 * - `n_items`: The current number of key-value pairs in the
		 * object.
		 * - `items`: A pointer to an array of pointers to key-value
		 * pair structures. Each key-value pair consists of:
		 *     - `key`: A pointer to a null-terminated string
		 * representing the key.
		 *     - `value`: A pointer to a `json_value` representing the
		 * associated value.
		 */
		struct {
			int capacity; /**< Total allocated capacity for
					 key-value pairs. */
			int n_items;  /**< Current number of key-value pairs in
				       * the object.
				       */
			struct {
				char *key; /**< Pointer to a null-terminated
					     string representing the key. */
				struct json_value *value; /**< Pointer to a
							`json_value`
							representing the
							associated value. */
			} **items; /**< Pointer to an array of pointers to
				      key-value pair structures. */
		} object;
	};
};

/**
 * @brief Checks if a JSON value is an array.
 *
 * This macro determines whether a given JSON value is of type array.
 *
 * @param VALUE The JSON value to check.
 * @return Non-zero if the value is an array, 0 otherwise.
 */
#define json_is_array(VALUE) ((VALUE) && (VALUE)->type == JSON_TYPE_ARRAY)

/**
 * @brief Checks if a JSON value is a boolean.
 *
 * This macro determines whether a given JSON value is of type boolean.
 *
 * @param VALUE The JSON value to check.
 * @return Non-zero if the value is a boolean, 0 otherwise.
 */
#define json_is_boolean(VALUE) ((VALUE) && (VALUE)->type == JSON_TYPE_BOOLEAN)

/**
 * @brief Checks if a JSON value is null.
 *
 * This macro determines whether a given JSON value is of type null.
 *
 * @param VALUE The JSON value to check.
 * @return Non-zero if the value is null, 0 otherwise.
 */
#define json_is_null(VALUE) ((VALUE) && (VALUE)->type == JSON_TYPE_NULL)

/**
 * @brief Checks if a JSON value is a number.
 *
 * This macro determines whether a given JSON value is of type number.
 *
 * @param VALUE The JSON value to check.
 * @return Non-zero if the value is a number, 0 otherwise.
 */
#define json_is_number(VALUE) ((VALUE) && (VALUE)->type == JSON_TYPE_NUMBER)

/**
 * @brief Checks if a JSON value is an object.
 *
 * This macro determines whether a given JSON value is of type object.
 *
 * @param VALUE The JSON value to check.
 * @return Non-zero if the value is an object, 0 otherwise.
 */
#define json_is_object(VALUE) ((VALUE) && (VALUE)->type == JSON_TYPE_OBJECT)

/**
 * @brief Checks if a JSON value is a string.
 *
 * This macro determines whether a given JSON value is of type string.
 *
 * @param VALUE The JSON value to check.
 * @return Non-zero if the value is a string, 0 otherwise.
 */
#define json_is_string(VALUE) ((VALUE) && (VALUE)->type == JSON_TYPE_STRING)

/**
 * @brief Retrieves the boolean value from a JSON boolean.
 *
 * This macro extracts the boolean value from a JSON boolean type.
 *
 * @param VALUE The JSON boolean value to retrieve.
 * @return Non-zero if the boolean is true, 0 if false.
 */
#define json_boolean_get(VALUE) ((VALUE)->number != 0.0)

/**
 * @brief Sets the boolean value of a JSON boolean.
 *
 * This macro modifies the boolean value of a JSON boolean type.
 *
 * @param VALUE The JSON boolean value to modify.
 * @param STATE The new boolean value to set (non-zero for true, 0 for false).
 */
#define json_boolean_set(VALUE, STATE) ((VALUE)->number = STATE)

/**
 * @brief Retrieves the numeric value from a JSON number.
 *
 * This macro extracts the numeric value from a JSON number type.
 *
 * @param VALUE The JSON number value to retrieve.
 * @return The numeric value.
 */
#define json_number_get(VALUE) ((VALUE)->number)

/**
 * @brief Sets the numeric value of a JSON number.
 *
 * This macro modifies the numeric value of a JSON number type.
 *
 * @param JSON The JSON number value to modify.
 * @param VALUE The new numeric value to set.
 */
#define json_number_set(JSON, VALUE) ((JSON)->number = VALUE)

/**
 * @brief Retrieves the string value from a JSON string.
 *
 * This macro extracts the string value from a JSON string type.
 *
 * @param JSON The JSON string value to retrieve.
 * @return A pointer to the string value.
 */
#define json_string_get(JSON) ((JSON) ? (JSON)->string.value : NULL)

/**
 * @brief Sets the string value of a JSON string.
 *
 * This macro modifies the string value of a JSON string type.
 *
 * @param JSON The JSON string value to modify.
 * @param VALUE The new string value to set.
 */
#define json_string_set(JSON, VALUE) ((JSON)->string.value = VALUE)

/**
 * @brief Retrieves an element from a JSON array.
 *
 * This function retrieves an element from a JSON array at the specified index.
 *
 * @param array The JSON array to retrieve from.
 * @param index The index of the element to retrieve.
 * @return A pointer to the element at the specified index, or NULL if out of
 * bounds.
 */
struct json_value *json_array_get(struct json_value *array, int index);

/**
 * @brief Sets an element in a JSON array.
 *
 * This macro sets an element in a JSON array at the specified index.
 *
 * @param array The JSON array to modify.
 * @param index The index of the element to set.
 * @param value The new value to set.
 */
#define json_array_set(ARRAY, INDEX, VALUE) \
	((ARRAY)->array.items[(INDEX)] = (VALUE))

/**
 * @brief Retrieves the number of key-value pairs in a JSON object.
 *
 * This macro returns the total count of key-value pairs in a JSON object.
 *
 * @param OBJECT A pointer to the JSON object to query.
 * @return The total count of key-value pairs in the object.
 */
#define json_object_count(OBJECT) ((OBJECT)->object.n_items)

/**
 * @brief Retrieves the number of elements in a JSON array.
 *
 * This macro returns the total count of elements in a JSON array.
 *
 * @param ARRAY A pointer to the JSON array to query.
 * @return The total count of elements in the array.
 */
#define json_array_count(ARRAY) ((ARRAY)->array.length)

/**
 * @brief Encodes a JSON value into a JSON string.
 *
 * This function takes a structured `json_value` and converts it into
 * a JSON-encoded string representation. The caller is responsible for
 * freeing the returned string using `free()`.
 *
 * @param value The JSON value to encode. Must not be NULL.
 * @return A pointer to the JSON-encoded string, or NULL if encoding fails.
 */
char *json_encode(struct json_value *value);

/**
 * @brief Decodes a JSON string into a JSON value.
 *
 * This function parses a JSON-encoded string and converts it into a
 * structured representation using the `json_value` type. The caller
 * is responsible for freeing the returned `json_value` using `json_free()`.
 *
 * @param json The JSON-encoded string to decode. Must be null-terminated.
 * @return A pointer to the decoded `json_value`, or NULL if decoding fails.
 */
struct json_value *json_decode(const char *json);

/**
 * @brief Decodes a JSON string into a JSON value.
 *
 * Decodes up to `length` bytes, see `json_decode` for more.
 *
 * @param json The JSON-encoded string to decode.
 * @param length The length of the string to decode.
 * @return A pointer to the decoded `json_value`, or NULL if decoding fails.
 */
struct json_value *json_decode_with_length(const char *json, int length);

/**
 * @brief Creates a new JSON object.
 *
 * This function allocates and initializes a new JSON object.
 *
 * @return A pointer to the newly created JSON object, or NULL on failure.
 */
struct json_value *json_object_new(void);

/**
 * @brief Frees the memory associated with a JSON object.
 *
 * This function releases all memory used by the JSON object, including
 * its key-value pairs and their associated values.
 *
 * @param object The JSON object to free.
 */
void json_object_free(struct json_value *object);

/**
 * @brief Retrieves the value associated with a key in a JSON object.
 *
 * This function searches for a key in the JSON object and returns the
 * associated value if the key exists.
 *
 * @param object The JSON object to query.
 * @param key The key to look up.
 * @return A pointer to the associated value, or NULL if the key does not exist.
 */
struct json_value *json_object_get(struct json_value *object, const char *key);

/**
 * @brief Sets a key-value pair in a JSON object.
 *
 * This function adds or updates a key-value pair in the JSON object.
 * If the key already exists, its value is updated.
 *
 * @param object The JSON object to modify.
 * @param key The key to set in the object.
 * @param value The value to associate with the key.
 * @return 0 on success, or -1 on failure.
 */
int json_object_set(struct json_value *object, const char *key,
		    struct json_value *value);

/**
 * @brief Checks if a key exists in a JSON object.
 *
 * This function determines whether a specific key exists in the JSON object.
 *
 * @param object The JSON object to query.
 * @param key The key to check for.
 * @return 1 if the key exists, 0 otherwise.
 */
int json_object_has(struct json_value *object, const char *key);

/**
 * @brief Removes a key-value pair from a JSON object.
 *
 * This function deletes a key-value pair from the JSON object. If the key
 * does not exist, the function does nothing.
 *
 * @param object The JSON object to modify.
 * @param key The key to remove.
 */
void json_object_remove(struct json_value *object, const char *key);

/**
 * @brief Iterates over the key-value pairs in a JSON object.
 *
 * This function provides a way to iterate through all key-value pairs
 * in a JSON object. The iteration index should be initialized to 0
 * before the first call.
 *
 * @param object The JSON object to iterate over.
 * @param iter A pointer to the iteration index (should be initialized to 0).
 * @param key A pointer to store the current key.
 * @param value A pointer to store the current value.
 * @return 1 if there are more items to iterate, 0 otherwise.
 */
int json_object_iter(const struct json_value *object, int *iter, char **key,
		     struct json_value **value);

/**
 * @brief Appends a value to the end of a JSON array.
 *
 * This function adds a new value to the end of the JSON array.
 *
 * @param array The JSON array to modify.
 * @param value The value to append.
 * @return 0 on success, or -1 on failure.
 */
int json_array_push(struct json_value *array, struct json_value *value);

/**
 * @brief Creates a new JSON array.
 *
 * This function allocates and initializes a new JSON array.
 *
 * @return A pointer to the newly created JSON array, or NULL on failure.
 */
struct json_value *json_array_new(void);

/**
 * @brief Frees the memory associated with a JSON array.
 *
 * This function releases all memory used by the JSON array, including
 * its elements.
 *
 * @param array The JSON array to free.
 */
void json_array_free(struct json_value *array);

/**
 * @brief Initializes a JSON array.
 *
 * This function sets up the internal structure of a JSON array,
 * preparing it for use.
 *
 * @param array The JSON array to initialize.
 */
void json_array_init(struct json_value *array);

/**
 * @brief Frees the memory associated with a JSON string.
 *
 * This function releases all memory used by the JSON string.
 *
 * @param string The JSON string to free.
 */
void json_string_free(struct json_value *string);

/**
 * @brief Removes a value at a specific index in a JSON array.
 *
 * This function deletes the value at the specified index in the JSON array.
 * If the index is out of bounds, the function fails.
 *
 * @param array The JSON array to modify.
 * @param index The index to remove the value from.
 */
void json_array_remove(struct json_value *array, int index);

/**
 * @brief Retrieves the length of a JSON array.
 *
 * This function returns the number of elements in the JSON array.
 *
 * @param array The JSON array to query.
 * @return The number of elements in the array.
 */
int json_array_length(struct json_value *array);

/**
 * @brief Iterates over the elements in a JSON array.
 *
 * This function provides a way to iterate through all elements in a JSON array.
 * The iteration index should be initialized to 0 before the first call.
 *
 * @param array The JSON array to iterate over.
 * @param index A pointer to the iteration index (should be initialized to 0).
 * @param value A pointer to store the current value.
 * @return 1 on success, or 0 if the iteration is complete.
 */
int json_array_iter(struct json_value *array, int *index,
		    struct json_value **value);

/**
 * @brief Creates a new JSON string with the specified value.
 *
 * This function allocates and initializes a new JSON string with the
 * provided string value.
 *
 * @param value The string value to initialize the JSON string with.
 * @return A pointer to the newly created JSON string, or NULL on failure.
 */
struct json_value *json_string_new(const char *value);

/**
 * @brief Creates a new JSON number with the specified value.
 *
 * This function allocates and initializes a new JSON number with the
 * provided numeric value.
 *
 * @param value The numeric value to initialize the JSON number with.
 * @return A pointer to the newly created JSON number, or NULL on failure.
 */
struct json_value *json_number_new(double value);

/**
 * @brief Creates a new JSON boolean with the specified value.
 *
 * This function allocates and initializes a new JSON boolean with the
 * provided boolean value.
 *
 * @param value The boolean value to initialize the JSON boolean with.
 * @return A pointer to the newly created JSON boolean, or NULL on failure.
 */
struct json_value *json_boolean_new(int value);

/**
 * @brief Deallocates memory associated with a JSON value and its descendants.
 *
 * This function performs a comprehensive cleanup of the specified JSON value,
 * including recursively freeing all child elements, whether they are objects,
 * arrays, or strings. It ensures that all allocated memory is properly
 * released.
 *
 * @param value A pointer to the JSON value to be deallocated.
 */
void json_free(struct json_value *value);

/**
 * @brief Copy the whole value and all its children into a new json_value.
 *
 * In theory, no memory should be shared with the previous value.
 *
 * @param value The JSON value to deep-copy.
 */
struct json_value *json_deep_copy(struct json_value *value);

#endif