Boot Linux faster!

Check our new training course

Boot Linux faster!

Check our new training course
and Creative Commons CC-BY-SA
lecture and lab materials

Bootlin logo

Elixir Cross Referencer

  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
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
/*
 * Copyright (c) 2017 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#ifndef ZEPHYR_INCLUDE_DATA_JSON_H_
#define ZEPHYR_INCLUDE_DATA_JSON_H_

#include <sys/util.h>
#include <stddef.h>
#include <zephyr/types.h>
#include <sys/types.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief Structured Data
 * @defgroup structured_data Structured Data
 */


/**
 * @defgroup json JSON
 * @ingroup structured_data
 * @{
 */

enum json_tokens {
	/* Before changing this enum, ensure that its maximum
	 * value is still within 7 bits. See comment next to the
	 * declaration of `type` in struct json_obj_descr.
	 */

	JSON_TOK_NONE = '_',
	JSON_TOK_OBJECT_START = '{',
	JSON_TOK_OBJECT_END = '}',
	JSON_TOK_LIST_START = '[',
	JSON_TOK_LIST_END = ']',
	JSON_TOK_STRING = '"',
	JSON_TOK_COLON = ':',
	JSON_TOK_COMMA = ',',
	JSON_TOK_NUMBER = '0',
	JSON_TOK_TRUE = 't',
	JSON_TOK_FALSE = 'f',
	JSON_TOK_NULL = 'n',
	JSON_TOK_ERROR = '!',
	JSON_TOK_EOF = '\0',
};

struct json_obj_descr {
	const char *field_name;

	/* Alignment can be 1, 2, 4, or 8.  The macros to create
	 * a struct json_obj_descr will store the alignment's
	 * power of 2 in order to keep this value in the 0-3 range
	 * and thus use only 2 bits.
	 */
	u32_t align_shift : 2;

	/* 127 characters is more than enough for a field name. */
	u32_t field_name_len : 7;

	/* Valid values here (enum json_tokens): JSON_TOK_STRING,
	 * JSON_TOK_NUMBER, JSON_TOK_TRUE, JSON_TOK_FALSE,
	 * JSON_TOK_OBJECT_START, JSON_TOK_LIST_START.  (All others
	 * ignored.) Maximum value is '}' (125), so this has to be 7 bits
	 * long.
	 */
	u32_t type : 7;

	/* 65535 bytes is more than enough for many JSON payloads. */
	u32_t offset : 16;

	union {
		struct {
			const struct json_obj_descr *sub_descr;
			size_t sub_descr_len;
		} object;
		struct {
			const struct json_obj_descr *element_descr;
			size_t n_elements;
		} array;
	};
};

/**
 * @brief Function pointer type to append bytes to a buffer while
 * encoding JSON data.
 *
 * @param bytes Contents to write to the output
 * @param len Number of bytes in @param bytes to append to output
 * @param data User-provided pointer
 *
 * @return This callback function should return a negative number on
 * error (which will be propagated to the return value of
 * json_obj_encode()), or 0 on success.
 */
typedef int (*json_append_bytes_t)(const char *bytes, size_t len,
				   void *data);

#define Z_ALIGN_SHIFT(type)	(__alignof__(type) == 1 ? 0 : \
				 __alignof__(type) == 2 ? 1 : \
				 __alignof__(type) == 4 ? 2 : 3)

/**
 * @brief Helper macro to declare a descriptor for supported primitive
 * values.
 *
 * @param struct_ Struct packing the values
 *
 * @param field_name_ Field name in the struct
 *
 * @param type_ Token type for JSON value corresponding to a primitive
 * type. Must be one of: JSON_TOK_STRING for strings, JSON_TOK_NUMBER
 * for numbers, JSON_TOK_TRUE (or JSON_TOK_FALSE) for booleans.
 *
 * Here's an example of use:
 *
 *     struct foo {
 *         int some_int;
 *     };
 *
 *     struct json_obj_descr foo[] = {
 *         JSON_OBJ_DESCR_PRIM(struct foo, some_int, JSON_TOK_NUMBER),
 *     };
 */
#define JSON_OBJ_DESCR_PRIM(struct_, field_name_, type_) \
	{ \
		.field_name = (#field_name_), \
		.align_shift = Z_ALIGN_SHIFT(struct_), \
		.field_name_len = sizeof(#field_name_) - 1, \
		.type = type_, \
		.offset = offsetof(struct_, field_name_), \
	}

/**
 * @brief Helper macro to declare a descriptor for an object value
 *
 * @param struct_ Struct packing the values
 *
 * @param field_name_ Field name in the struct
 *
 * @param sub_descr_ Array of json_obj_descr describing the subobject
 *
 * Here's an example of use:
 *
 *      struct nested {
 *          int foo;
 *          struct {
 *             int baz;
 *          } bar;
 *      };
 *
 *      struct json_obj_descr nested_bar[] = {
 *          { ... declare bar.baz descriptor ... },
 *      };
 *      struct json_obj_descr nested[] = {
 *          { ... declare foo descriptor ... },
 *          JSON_OBJ_DESCR_OBJECT(struct nested, bar, nested_bar),
 *      };
 */
#define JSON_OBJ_DESCR_OBJECT(struct_, field_name_, sub_descr_) \
	{ \
		.field_name = (#field_name_), \
		.align_shift = Z_ALIGN_SHIFT(struct_), \
		.field_name_len = (sizeof(#field_name_) - 1), \
		.type = JSON_TOK_OBJECT_START, \
		.offset = offsetof(struct_, field_name_), \
		.object = { \
			.sub_descr = sub_descr_, \
			.sub_descr_len = ARRAY_SIZE(sub_descr_), \
		}, \
	}

/**
 * @brief Helper macro to declare a descriptor for an array of primitives
 *
 * @param struct_ Struct packing the values
 *
 * @param field_name_ Field name in the struct
 *
 * @param max_len_ Maximum number of elements in array
 *
 * @param len_field_ Field name in the struct for the number of elements
 * in the array
 *
 * @param elem_type_ Element type, must be a primitive type
 *
 * Here's an example of use:
 *
 *      struct example {
 *          int foo[10];
 *          size_t foo_len;
 *      };
 *
 *      struct json_obj_descr array[] = {
 *           JSON_OBJ_DESCR_ARRAY(struct example, foo, 10, foo_len,
 *                                JSON_TOK_NUMBER)
 *      };
 */
#define JSON_OBJ_DESCR_ARRAY(struct_, field_name_, max_len_, \
			     len_field_, elem_type_) \
	{ \
		.field_name = (#field_name_), \
		.align_shift = Z_ALIGN_SHIFT(struct_), \
		.field_name_len = sizeof(#field_name_) - 1, \
		.type = JSON_TOK_LIST_START, \
		.offset = offsetof(struct_, field_name_), \
		.array = { \
			.element_descr = &(struct json_obj_descr) { \
				.align_shift = Z_ALIGN_SHIFT(struct_), \
				.type = elem_type_, \
				.offset = offsetof(struct_, len_field_), \
			}, \
			.n_elements = (max_len_), \
		}, \
	}

/**
 * @brief Helper macro to declare a descriptor for an array of objects
 *
 * @param struct_ Struct packing the values
 *
 * @param field_name_ Field name in the struct containing the array
 *
 * @param max_len_ Maximum number of elements in the array
 *
 * @param len_field_ Field name in the struct for the number of elements
 * in the array
 *
 * @param elem_descr_ Element descriptor, pointer to a descriptor array
 *
 * @param elem_descr_len_ Number of elements in elem_descr_
 *
 * Here's an example of use:
 *
 *      struct person_height {
 *          const char *name;
 *          int height;
 *      };
 *
 *      struct people_heights {
 *          struct person_height heights[10];
 *          size_t heights_len;
 *      };
 *
 *      struct json_obj_descr person_height_descr[] = {
 *           JSON_OBJ_DESCR_PRIM(struct person_height, name, JSON_TOK_STRING),
 *           JSON_OBJ_DESCR_PRIM(struct person_height, height, JSON_TOK_NUMBER),
 *      };
 *
 *      struct json_obj_descr array[] = {
 *           JSON_OBJ_DESCR_OBJ_ARRAY(struct people_heights, heights, 10,
 *                                    heights_len, person_height_descr,
 *                                    ARRAY_SIZE(person_height_descr)),
 *      };
 */
#define JSON_OBJ_DESCR_OBJ_ARRAY(struct_, field_name_, max_len_, \
				 len_field_, elem_descr_, elem_descr_len_) \
	{ \
		.field_name = (#field_name_), \
		.align_shift = Z_ALIGN_SHIFT(struct_), \
		.field_name_len = sizeof(#field_name_) - 1, \
		.type = JSON_TOK_LIST_START, \
		.offset = offsetof(struct_, field_name_), \
		.array = { \
			.element_descr = &(struct json_obj_descr) { \
				.align_shift = Z_ALIGN_SHIFT(struct_), \
				.type = JSON_TOK_OBJECT_START, \
				.offset = offsetof(struct_, len_field_), \
				.object = { \
					.sub_descr = elem_descr_, \
					.sub_descr_len = elem_descr_len_, \
				}, \
			}, \
			.n_elements = (max_len_), \
		}, \
	}

/**
 * @brief Helper macro to declare a descriptor for an array of array
 *
 * @param struct_ Struct packing the values
 *
 * @param field_name_ Field name in the struct containing the array
 *
 * @param max_len_ Maximum number of elements in the array
 *
 * @param len_field_ Field name in the struct for the number of elements
 * in the array
 *
 * @param elem_descr_ Element descriptor, pointer to a descriptor array
 *
 * @param elem_descr_len_ Number of elements in elem_descr_
 *
 * Here's an example of use:
 *
 *      struct person_height {
 *          const char *name;
 *          int height;
 *      };
 *
 *      struct person_heights_array {
 *          struct person_height heights;
 *      }
 *
 *      struct people_heights {
 *          struct person_height_array heights[10];
 *          size_t heights_len;
 *      };
 *
 *      struct json_obj_descr person_height_descr[] = {
 *          JSON_OBJ_DESCR_PRIM(struct person_height, name, JSON_TOK_STRING),
 *          JSON_OBJ_DESCR_PRIM(struct person_height, height, JSON_TOK_NUMBER),
 *      };
 *
 *      struct json_obj_descr person_height_array_descr[] = {
 *          JSON_OBJ_DESCR_OBJECT(struct person_heights_array,
 *                                heights, person_heigth_descr),
 *      };
 *
 *      struct json_obj_descr array_array[] = {
 *           JSON_OBJ_DESCR_ARRAY_ARRAY(struct people_heights, heights, 10,
 *                                      heights_len, person_height_array_descr,
 *                                      ARRAY_SIZE(person_height_array_descr)),
 *      };
 */
#define JSON_OBJ_DESCR_ARRAY_ARRAY(struct_, field_name_, max_len_, len_field_, \
				   elem_descr_, elem_descr_len_) \
	{ \
		.field_name = (#field_name_), \
		.align_shift = Z_ALIGN_SHIFT(struct_), \
		.field_name_len = sizeof(#field_name_) - 1, \
		.type = JSON_TOK_LIST_START, \
		.offset = offsetof(struct_, field_name_), \
		.array = { \
			.element_descr = &(struct json_obj_descr) { \
				.align_shift = Z_ALIGN_SHIFT(struct_), \
				.type = JSON_TOK_LIST_START, \
				.offset = offsetof(struct_, len_field_), \
				.object = { \
					.sub_descr = elem_descr_, \
					.sub_descr_len = elem_descr_len_, \
				}, \
			}, \
			.n_elements = (max_len_), \
		}, \
	}

/**
 * @brief Variant of JSON_OBJ_DESCR_PRIM that can be used when the
 *        structure and JSON field names differ.
 *
 * This is useful when the JSON field is not a valid C identifier.
 *
 * @param struct_ Struct packing the values.
 *
 * @param json_field_name_ String, field name in JSON strings
 *
 * @param struct_field_name_ Field name in the struct
 *
 * @param type_ Token type for JSON value corresponding to a primitive
 * type.
 *
 * @see JSON_OBJ_DESCR_PRIM
 */
#define JSON_OBJ_DESCR_PRIM_NAMED(struct_, json_field_name_, \
				  struct_field_name_, type_) \
	{ \
		.field_name = (json_field_name_), \
		.align_shift = Z_ALIGN_SHIFT(struct_), \
		.field_name_len = sizeof(json_field_name_) - 1, \
		.type = type_, \
		.offset = offsetof(struct_, struct_field_name_), \
	}

/**
 * @brief Variant of JSON_OBJ_DESCR_OBJECT that can be used when the
 *        structure and JSON field names differ.
 *
 * This is useful when the JSON field is not a valid C identifier.
 *
 * @param struct_ Struct packing the values
 *
 * @param json_field_name_ String, field name in JSON strings
 *
 * @param struct_field_name_ Field name in the struct
 *
 * @param sub_descr_ Array of json_obj_descr describing the subobject
 *
 * @see JSON_OBJ_DESCR_OBJECT
 */
#define JSON_OBJ_DESCR_OBJECT_NAMED(struct_, json_field_name_, \
				    struct_field_name_, sub_descr_) \
	{ \
		.field_name = (json_field_name_), \
		.align_shift = Z_ALIGN_SHIFT(struct_), \
		.field_name_len = (sizeof(json_field_name_) - 1), \
		.type = JSON_TOK_OBJECT_START, \
		.offset = offsetof(struct_, struct_field_name_), \
		.object = { \
			.sub_descr = sub_descr_, \
			.sub_descr_len = ARRAY_SIZE(sub_descr_), \
		}, \
	}

/**
 * @brief Variant of JSON_OBJ_DESCR_ARRAY that can be used when the
 *        structure and JSON field names differ.
 *
 * This is useful when the JSON field is not a valid C identifier.
 *
 * @param struct_ Struct packing the values
 *
 * @param json_field_name_ String, field name in JSON strings
 *
 * @param struct_field_name_ Field name in the struct
 *
 * @param max_len_ Maximum number of elements in array
 *
 * @param len_field_ Field name in the struct for the number of elements
 * in the array
 *
 * @param elem_type_ Element type, must be a primitive type
 *
 * @see JSON_OBJ_DESCR_ARRAY
 */
#define JSON_OBJ_DESCR_ARRAY_NAMED(struct_, json_field_name_,\
				   struct_field_name_, max_len_, len_field_, \
				   elem_type_) \
	{ \
		.field_name = (json_field_name_), \
		.align_shift = Z_ALIGN_SHIFT(struct_), \
		.field_name_len = sizeof(json_field_name_) - 1, \
		.type = JSON_TOK_LIST_START, \
		.offset = offsetof(struct_, struct_field_name_), \
		.array = { \
			.element_descr = &(struct json_obj_descr) { \
				.align_shift = Z_ALIGN_SHIFT(struct_), \
				.type = elem_type_, \
				.offset = offsetof(struct_, len_field_), \
			}, \
			.n_elements = (max_len_), \
		}, \
	}

/**
 * @brief Variant of JSON_OBJ_DESCR_OBJ_ARRAY that can be used when
 *        the structure and JSON field names differ.
 *
 * This is useful when the JSON field is not a valid C identifier.
 *
 * @param struct_ Struct packing the values
 *
 * @param json_field_name_ String, field name of the array in JSON strings
 *
 * @param struct_field_name_ Field name in the struct containing the array
 *
 * @param max_len_ Maximum number of elements in the array
 *
 * @param len_field_ Field name in the struct for the number of elements
 * in the array
 *
 * @param elem_descr_ Element descriptor, pointer to a descriptor array
 *
 * @param elem_descr_len_ Number of elements in elem_descr_
 *
 * Here's an example of use:
 *
 *      struct person_height {
 *          const char *name;
 *          int height;
 *      };
 *
 *      struct people_heights {
 *          struct person_height heights[10];
 *          size_t heights_len;
 *      };
 *
 *      struct json_obj_descr person_height_descr[] = {
 *           JSON_OBJ_DESCR_PRIM(struct person_height, name, JSON_TOK_STRING),
 *           JSON_OBJ_DESCR_PRIM(struct person_height, height, JSON_TOK_NUMBER),
 *      };
 *
 *      struct json_obj_descr array[] = {
 *           JSON_OBJ_DESCR_OBJ_ARRAY_NAMED(struct people_heights,
 *                                          "people-heights", heights,
 *                                          10, heights_len,
 *                                          person_height_descr,
 *                                          ARRAY_SIZE(person_height_descr)),
 *      };
 */
#define JSON_OBJ_DESCR_OBJ_ARRAY_NAMED(struct_, json_field_name_, \
				       struct_field_name_, max_len_, \
				       len_field_, elem_descr_, \
				       elem_descr_len_) \
	{ \
		.field_name = json_field_name_, \
		.align_shift = Z_ALIGN_SHIFT(struct_), \
		.field_name_len = sizeof(json_field_name_) - 1, \
		.type = JSON_TOK_LIST_START, \
		.offset = offsetof(struct_, struct_field_name_), \
		.element_descr = &(struct json_obj_descr) { \
			.align_shift = Z_ALIGN_SHIFT(struct_), \
			.type = JSON_TOK_OBJECT_START, \
			.offset = offsetof(struct_, len_field_), \
			.object = { \
				.sub_descr = elem_descr_, \
				.sub_descr_len = elem_descr_len_, \
			}, \
		}, \
		.n_elements = (max_len_), \
	}

/**
 * @brief Parses the JSON-encoded object pointer to by @a json, with
 * size @a len, according to the descriptor pointed to by @a descr.
 * Values are stored in a struct pointed to by @a val.  Set up the
 * descriptor like this:
 *
 *    struct s { int foo; char *bar; }
 *    struct json_obj_descr descr[] = {
 *       JSON_OBJ_DESCR_PRIM(struct s, foo, JSON_TOK_NUMBER),
 *       JSON_OBJ_DESCR_PRIM(struct s, bar, JSON_TOK_STRING),
 *    };
 *
 * Since this parser is designed for machine-to-machine communications, some
 * liberties were taken to simplify the design:
 * (1) strings are not unescaped (but only valid escape sequences are
 * accepted);
 * (2) no UTF-8 validation is performed; and
 * (3) only integer numbers are supported (no strtod() in the minimal libc).
 *
 * @param json Pointer to JSON-encoded value to be parsed
 *
 * @param len Length of JSON-encoded value
 *
 * @param descr Pointer to the descriptor array
 *
 * @param descr_len Number of elements in the descriptor array. Must be less
 * than 31 due to implementation detail reasons (if more fields are
 * necessary, use two descriptors)
 *
 * @param val Pointer to the struct to hold the decoded values
 *
 * @return < 0 if error, bitmap of decoded fields on success (bit 0
 * is set if first field in the descriptor has been properly decoded, etc).
 */
int json_obj_parse(char *json, size_t len,
	const struct json_obj_descr *descr, size_t descr_len,
	void *val);

/**
 * @brief Escapes the string so it can be used to encode JSON objects
 *
 * @param str The string to escape; the escape string is stored the
 * buffer pointed to by this parameter
 *
 * @param len Points to a size_t containing the size before and after
 * the escaping process
 *
 * @param buf_size The size of buffer str points to
 *
 * @return 0 if string has been escaped properly, or -ENOMEM if there
 * was not enough space to escape the buffer
 */
ssize_t json_escape(char *str, size_t *len, size_t buf_size);

/**
 * @brief Calculates the JSON-escaped string length
 *
 * @param str The string to analyze
 *
 * @param len String size
 *
 * @return The length str would have if it were escaped
 */
size_t json_calc_escaped_len(const char *str, size_t len);

/**
 * @brief Calculates the string length to fully encode an object
 *
 * @param descr Pointer to the descriptor array
 *
 * @param descr_len Number of elements in the descriptor array
 *
 * @param val Struct holding the values
 *
 * @return Number of bytes necessary to encode the values if >0,
 * an error code is returned.
 */
ssize_t json_calc_encoded_len(const struct json_obj_descr *descr,
			      size_t descr_len, const void *val);

/**
 * @brief Encodes an object in a contiguous memory location
 *
 * @param descr Pointer to the descriptor array
 *
 * @param descr_len Number of elements in the descriptor array
 *
 * @param val Struct holding the values
 *
 * @param buffer Buffer to store the JSON data
 *
 * @param buf_size Size of buffer, in bytes, with space for the terminating
 * NUL character
 *
 * @return 0 if object has been successfully encoded. A negative value
 * indicates an error (as defined on errno.h).
 */
int json_obj_encode_buf(const struct json_obj_descr *descr, size_t descr_len,
			const void *val, char *buffer, size_t buf_size);

/**
 * @brief Encodes an object using an arbitrary writer function
 *
 * @param descr Pointer to the descriptor array
 *
 * @param descr_len Number of elements in the descriptor array
 *
 * @param val Struct holding the values
 *
 * @param append_bytes Function to append bytes to the output
 *
 * @param data Data pointer to be passed to the append_bytes callback
 * function.
 *
 * @return 0 if object has been successfully encoded. A negative value
 * indicates an error.
 */
int json_obj_encode(const struct json_obj_descr *descr, size_t descr_len,
		    const void *val, json_append_bytes_t append_bytes,
		    void *data);

#ifdef __cplusplus
}
#endif

/**
 * @}
 */
#endif /* ZEPHYR_INCLUDE_DATA_JSON_H_ */