Objectively
Ultra-lightweight object oriented framework for GNU C.
Loading...
Searching...
No Matches
JSONContext.c File Reference
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Boole.h"
#include "JSONContext.h"
#include "Array.h"
#include "Data.h"
#include "Dictionary.h"
#include "Null.h"
#include "Number.h"

Go to the source code of this file.

Data Structures

struct  JSONReader
 Internal state for JSON text parsing. More...
 
struct  JSONWriter
 Internal state for JSON text generation. More...
 

Macros

#define _Class   _JSONContext
 

Functions

Class_JSONContext (void)
 
static void addError (JSONContext *self, int code, const char *key, const char *description)
 Records an error on the context.
 
static bool consumeBytes (JSONReader *reader, const char *bytes)
 Consumes and validates a fixed byte sequence from reader.
 
static DatadataFromObject (JSONContext *self, const ident obj, int options)
 
static DatadataFromStruct (JSONContext *self, const JSONProperties *properties, const ident instance)
 
static DatadataFromStructs (JSONContext *self, const JSONProperties *properties, const ident instances, size_t count)
 
static void dealloc (Object *self)
 
static void destroy (Class *clazz)
 
static DictionarydictionaryFromStruct (JSONContext *self, const JSONProperties *properties, const ident instance)
 Serializes a C struct instance to a Dictionary.
 
static JSONContextinit (JSONContext *self)
 
static void initialize (Class *clazz)
 
static ident objectFromData (JSONContext *self, const Data *data, int options)
 
static ArrayreadArray (JSONReader *reader)
 Reads a JSON array from reader.
 
static BoolereadBoole (JSONReader *reader)
 Reads a JSON boolean from reader.
 
static int readByte (JSONReader *reader)
 Advances the reader by one byte.
 
static int readByteUntil (JSONReader *reader, const char *stop)
 Advances the reader until one of the bytes in stop is found.
 
static ident readElement (JSONReader *reader)
 Reads any JSON element from reader.
 
static StringreadLabel (JSONReader *reader)
 Reads a JSON object key label from reader.
 
static NullreadNull (JSONReader *reader)
 Reads a JSON null from reader.
 
static NumberreadNumber (JSONReader *reader)
 Reads a JSON number from reader.
 
static DictionaryreadObject (JSONReader *reader)
 Reads a JSON object (Dictionary) from reader.
 
static StringreadString (JSONReader *reader)
 Reads a JSON-escaped string from reader.
 
static bool structFromData (JSONContext *self, const JSONProperties *properties, const Data *data, ident instance)
 
static bool structFromDictionary (JSONContext *self, const JSONProperties *properties, const Dictionary *dictionary, ident instance)
 Deserializes a Dictionary into a C struct.
 
static size_t structsFromArray (JSONContext *self, const JSONProperties *properties, const Array *array, ident instances, size_t count)
 Deserializes a JSON Array into an array of C structs.
 
static size_t structsFromData (JSONContext *self, const JSONProperties *properties, const Data *data, ident instances, size_t count)
 
static void writeArray (JSONWriter *writer, const Array *array)
 Writes a JSON array to writer.
 
static void writeBoole (JSONWriter *writer, const Boole *boolean)
 Writes a JSON boolean to writer.
 
static void writeElement (JSONWriter *writer, const ident obj)
 Writes any JSON element to writer.
 
static void writeLabel (JSONWriter *writer, const String *label)
 Writes a JSON object key label to writer.
 
static void writeNull (JSONWriter *writer, const Null *null)
 Writes null to writer.
 
static void writeNumber (JSONWriter *writer, const Number *number)
 Writes a JSON number to writer.
 
static void writeObject (JSONWriter *writer, const Dictionary *object)
 Writes a JSON object (Dictionary) to writer.
 
static void writePretty (JSONWriter *writer)
 Writes pretty-print indentation to writer, if enabled.
 
static void writeString (JSONWriter *writer, const String *string)
 Writes a JSON-escaped string to writer.
 

Macro Definition Documentation

◆ _Class

#define _Class   _JSONContext

Definition at line 40 of file JSONContext.c.

Function Documentation

◆ _JSONContext()

Class * _JSONContext ( void  )

Definition at line 821 of file JSONContext.c.

821 {
822 static Class *clazz;
823 static Once once;
824
825 do_once(&once, {
826 clazz = _initialize(&(const ClassDef) {
827 .name = "JSONContext",
828 .superclass = _Object(),
829 .instanceSize = sizeof(JSONContext),
830 .interfaceOffset = offsetof(JSONContext, interface),
831 .interfaceSize = sizeof(JSONContextInterface),
833 .destroy = destroy,
834 });
835 });
836
837 return clazz;
838}
Class * _initialize(const ClassDef *def)
Initializes the given Class.
Definition Class.c:86
static void destroy(Class *clazz)
static void initialize(Class *clazz)
Class * _Object(void)
Definition Object.c:136
long Once
The Once type.
Definition Once.h:37
#define do_once(once, block)
Executes the given block at most one time.
Definition Once.h:43
ClassDefs are passed to _initialize via an archetype to initialize a Class.
Definition Class.h:41
The runtime representation of a Class.
Definition Class.h:95
A context for JSON serialization and deserialization.
Definition JSONContext.h:72

◆ addError()

static void addError ( JSONContext self,
int  code,
const char *  key,
const char *  description 
)
static

Records an error on the context.

Parameters
selfThe JSONContext; may be NULL (no-op).
codeA JSON_ERROR_* code.
keyThe JSON key associated with the error, or NULL.
descriptionA human-readable description.

Definition at line 65 of file JSONContext.c.

65 {
66
67 if (!self) {
68 return;
69 }
70
71 if (!self->errors) {
72 self->errors = $(alloc(Array), init);
73 }
74
75 String *domain = $$(String, stringWithCharacters, "JSONContext");
76 String *message;
77 if (key) {
78 message = $(alloc(String), initWithFormat, "%s: %s", key, description);
79 } else {
81 }
82
83 Error *error = $(alloc(Error), initWithDomain, domain, code, message);
84 $(self->errors, addObject, error);
85
86 release(domain);
87 release(message);
89}
static String * description(const Object *self)
Definition Array.c:115
static void addObject(Array *self, const ident obj)
Definition Array.c:181
ident release(ident obj)
Atomically decrement the given Object's reference count. If the resulting reference count is 0,...
Definition Class.c:195
#define alloc(type)
Allocate and initialize and instance of type.
Definition Class.h:176
static DateFormatter * initWithFormat(DateFormatter *self, const char *fmt)
static Error * initWithDomain(Error *self, String *domain, int code, String *message)
Definition Error.c:128
static JSONContext * init(JSONContext *self)
static void error(const Log *self, const char *fmt,...)
Definition Log.c:80
static String * stringWithCharacters(const char *chars)
Definition String.c:349
Arrays.
Definition Array.h:56
Encapsulation for error conditions.
Definition Error.h:41
Array * errors
Errors accumulated during the operation.
Definition JSONContext.h:89
UTF-8 strings.
Definition String.h:69

◆ consumeBytes()

static bool consumeBytes ( JSONReader reader,
const char *  bytes 
)
static

Consumes and validates a fixed byte sequence from reader.

Returns
true on success, false if the input did not match.

Definition at line 330 of file JSONContext.c.

330 {
331
332 for (size_t i = 1; i < strlen(bytes); i++) {
333 const int b = readByte(reader);
334 if (b != bytes[i]) {
335 reader->error = true;
336 return false;
337 }
338 }
339
340 return true;
341}
static int readByte(JSONReader *reader)
Advances the reader by one byte.

◆ dataFromObject()

static Data * dataFromObject ( JSONContext self,
const ident  obj,
int  options 
)
static

Definition at line 584 of file JSONContext.c.

584 {
585
586 (void) self;
587
588 if (obj) {
589 JSONWriter writer = {
590 .data = $(alloc(Data), init),
591 .options = options
592 };
593
594 writeElement(&writer, obj);
595
596 return (Data *) writer.data;
597 }
598
599 return NULL;
600}
#define obj
static void writeElement(JSONWriter *writer, const ident obj)
Writes any JSON element to writer.
static int options(RESTClient *self, const char *url, Data **data)
Definition RESTClient.c:217
Data buffers.
Definition Data.h:50
Internal state for JSON text generation.
Definition JSONContext.c:94
Data * data
Definition JSONContext.c:95

◆ dataFromStruct()

static Data * dataFromStruct ( JSONContext self,
const JSONProperties properties,
const ident  instance 
)
static

Definition at line 606 of file JSONContext.c.

606 {
607
608 Dictionary *dict = $(self, dictionaryFromStruct, properties, instance);
609 Data *data = dataFromObject(self, dict, 0);
610 release(dict);
611 return data;
612}
static Data * data(void)
Definition Data.c:286
static Dictionary * dictionaryFromStruct(JSONContext *self, const JSONProperties *properties, const ident instance)
Serializes a C struct instance to a Dictionary.
static Data * dataFromObject(JSONContext *self, const ident obj, int options)
Key-value stores.
Definition Dictionary.h:60

◆ dataFromStructs()

static Data * dataFromStructs ( JSONContext self,
const JSONProperties properties,
const ident  instances,
size_t  count 
)
static

Definition at line 618 of file JSONContext.c.

618 {
619
620 if (!count) {
621 return NULL;
622 }
623
624 Array *array = $(alloc(Array), init);
625
626 for (size_t i = 0; i < count; i++) {
627 const ident instance = instances + i * properties->size;
628 Dictionary *dict = $(self, dictionaryFromStruct, properties, instance);
629 $(array, addObject, dict);
630 release(dict);
631 }
632
633 Data *data = dataFromObject(self, array, 0);
634 release(array);
635 return data;
636}
static Array * array(void)
Definition Array.c:234
void * ident
The identity type, similar to Objective-C id.
Definition Types.h:49
size_t size
The struct size, i.e. sizeof(Struct).

◆ dealloc()

static void dealloc ( Object self)
static
See also
Object::dealloc(Object *)

Definition at line 47 of file JSONContext.c.

47 {
48
49 JSONContext *this = (JSONContext *) self;
50
51 release(this->errors);
52
53 super(Object, self, dealloc);
54}
#define super(type, obj, method,...)
static void dealloc(Object *self)
Definition JSONContext.c:47
Object is the root Class of The Objectively Class hierarchy.
Definition Object.h:46

◆ destroy()

static void destroy ( Class clazz)
static
See also
Class::destroy(Class *)

Definition at line 794 of file JSONContext.c.

794 {
795 (void) clazz;
796}

◆ dictionaryFromStruct()

static Dictionary * dictionaryFromStruct ( JSONContext self,
const JSONProperties properties,
const ident  instance 
)
static

Serializes a C struct instance to a Dictionary.

Definition at line 641 of file JSONContext.c.

641 {
642
643 if (!properties || !instance) {
644 return NULL;
645 }
646
647 Dictionary *dict = $(alloc(Dictionary), init);
648
649 for (const JSONProperty *p = properties->properties; p->key; p++) {
650 if (!p->serializer) {
651 continue;
652 }
653
654 const ident field = instance + p->offset;
655 ident val = p->serializer(properties, p, field, p->data, self);
656
657 if (val) {
658 String *key = $$(String, stringWithCharacters, p->key);
659 $(dict, setObjectForKey, val, key);
660 release(key);
661 release(val);
662 }
663 }
664
665 return (Dictionary *) dict;
666}
static void setObjectForKey(Dictionary *self, const ident obj, const ident key)
Definition Dictionary.c:634
const JSONProperty * properties
The NULL-terminated JSONProperty array.
Describes the JSON binding strategy for a single field of a C struct.

◆ init()

static JSONContext * init ( JSONContext self)
static
See also
Object::init(Object *)

Definition at line 671 of file JSONContext.c.

671 {
672 return (JSONContext *) super(Object, self, init);
673}

◆ initialize()

static void initialize ( Class clazz)
static
See also
Class::initialize(Class *)

Definition at line 801 of file JSONContext.c.

801 {
802
803 ((ObjectInterface *) clazz->interface)->dealloc = dealloc;
804
805 ((JSONContextInterface *) clazz->interface)->dataFromObject = dataFromObject;
806 ((JSONContextInterface *) clazz->interface)->dataFromStruct = dataFromStruct;
807 ((JSONContextInterface *) clazz->interface)->dataFromStructs = dataFromStructs;
808 ((JSONContextInterface *) clazz->interface)->dictionaryFromStruct = dictionaryFromStruct;
809 ((JSONContextInterface *) clazz->interface)->init = init;
810 ((JSONContextInterface *) clazz->interface)->objectFromData = objectFromData;
811 ((JSONContextInterface *) clazz->interface)->structFromData = structFromData;
812 ((JSONContextInterface *) clazz->interface)->structsFromData = structsFromData;
813 ((JSONContextInterface *) clazz->interface)->structFromDictionary = structFromDictionary;
814 ((JSONContextInterface *) clazz->interface)->structsFromArray = structsFromArray;
815}
static bool structFromData(JSONContext *self, const JSONProperties *properties, const Data *data, ident instance)
static Data * dataFromStructs(JSONContext *self, const JSONProperties *properties, const ident instances, size_t count)
static Data * dataFromStruct(JSONContext *self, const JSONProperties *properties, const ident instance)
static size_t structsFromArray(JSONContext *self, const JSONProperties *properties, const Array *array, ident instances, size_t count)
Deserializes a JSON Array into an array of C structs.
static bool structFromDictionary(JSONContext *self, const JSONProperties *properties, const Dictionary *dictionary, ident instance)
Deserializes a Dictionary into a C struct.
static ident objectFromData(JSONContext *self, const Data *data, int options)
static size_t structsFromData(JSONContext *self, const JSONProperties *properties, const Data *data, ident instances, size_t count)
ident interface
The interface of the Class.
Definition Class.h:105
Dictionary * init(Dictionary *self)
Initializes this Dictionary.
Definition Dictionary.c:350
ident objectFromData(JSONContext *self, const Data *data, int options)
Parses a JSON Data buffer into an Objectively object graph.

◆ objectFromData()

static ident objectFromData ( JSONContext self,
const Data data,
int  options 
)
static

Definition at line 679 of file JSONContext.c.

679 {
680
681 if (data && data->length) {
682 JSONReader reader = {
683 .data = data,
684 .options = options
685 };
686
687 ident obj = readElement(&reader);
688
689 if (reader.error) {
690 addError(self, 1, NULL, "JSON parse error");
691 release(obj);
692 return NULL;
693 }
694
695 return obj;
696 }
697
698 return NULL;
699}
static ident readElement(JSONReader *reader)
Reads any JSON element from reader.
static void addError(JSONContext *self, int code, const char *key, const char *description)
Records an error on the context.
Definition JSONContext.c:65
size_t length
The length of bytes.
Definition Data.h:76
Internal state for JSON text parsing.
const Data * data

◆ readArray()

static Array * readArray ( JSONReader reader)
static

Reads a JSON array from reader.

Definition at line 531 of file JSONContext.c.

531 {
532
533 Array *array = $(alloc(Array), init);
534
535 while (true) {
536
537 Object *obj = readElement(reader);
538 if (obj == NULL) {
539 const int b = readByteUntil(reader, "]");
540 if (b != ']') {
541 reader->error = true;
542 }
543 break;
544 }
545
546 $(array, addObject, obj);
547 release(obj);
548 }
549
550 return (Array *) array;
551}
static int readByteUntil(JSONReader *reader, const char *stop)
Advances the reader until one of the bytes in stop is found.

◆ readBoole()

static Boole * readBoole ( JSONReader reader)
static

Reads a JSON boolean from reader.

Definition at line 434 of file JSONContext.c.

434 {
435
436 Boole *boolean = NULL;
437
438 switch (*reader->b) {
439 case 't':
440 if (!consumeBytes(reader, "true")) {
441 return NULL;
442 }
443 boolean = $$(Boole, True);
444 break;
445 case 'f':
446 if (!consumeBytes(reader, "false")) {
447 return NULL;
448 }
449 boolean = $$(Boole, False);
450 break;
451 default:
452 reader->error = true;
453 return NULL;
454 }
455
456 return retain(boolean);
457}
static Boole * True(void)
Definition Boole.c:77
static Boole * False(void)
Definition Boole.c:59
ident retain(ident obj)
Atomically increment the given Object's reference count.
Definition Class.c:210
static bool consumeBytes(JSONReader *reader, const char *bytes)
Consumes and validates a fixed byte sequence from reader.
A wrapper for placing boolean primitives into collections, etc.
Definition Boole.h:41
uint8_t * b

◆ readByte()

static int readByte ( JSONReader reader)
static

Advances the reader by one byte.

Returns
The next byte, or -1 when the input is exhausted.

Definition at line 293 of file JSONContext.c.

293 {
294
295 if (reader->b) {
296 if (reader->b - reader->data->bytes < reader->data->length) {
297 return (int) *(++(reader->b));
298 }
299 } else {
300 if (reader->data->bytes) {
301 return (int) *(reader->b = reader->data->bytes);
302 }
303 }
304
305 return -1;
306}
uint8_t * bytes
The bytes.
Definition Data.h:66

◆ readByteUntil()

static int readByteUntil ( JSONReader reader,
const char *  stop 
)
static

Advances the reader until one of the bytes in stop is found.

Returns
The matched stop byte, or -1 when the input is exhausted.

Definition at line 312 of file JSONContext.c.

312 {
313
314 int b;
315
316 while (true) {
317 b = readByte(reader);
318 if (b == -1 || strchr(stop, b)) {
319 break;
320 }
321 }
322
323 return b;
324}

◆ readElement()

static ident readElement ( JSONReader reader)
static

Reads any JSON element from reader.

Definition at line 556 of file JSONContext.c.

556 {
557
558 const int b = readByteUntil(reader, "{[\"tfn0123456789.-]}");
559 if (b == '{') {
560 return readObject(reader);
561 } else if (b == '[') {
562 return readArray(reader);
563 } else if (b == '"') {
564 return readString(reader);
565 } else if (b == 't' || b == 'f') {
566 return readBoole(reader);
567 } else if (b == 'n') {
568 return readNull(reader);
569 } else if (b == '.' || b == '-' || isdigit(b)) {
570 return readNumber(reader);
571 } else if (b == ']' || b == '}') {
572 reader->b--;
573 }
574
575 return NULL;
576}
static Dictionary * readObject(JSONReader *reader)
Reads a JSON object (Dictionary) from reader.
static String * readString(JSONReader *reader)
Reads a JSON-escaped string from reader.
static Boole * readBoole(JSONReader *reader)
Reads a JSON boolean from reader.
static Array * readArray(JSONReader *reader)
Reads a JSON array from reader.
static Number * readNumber(JSONReader *reader)
Reads a JSON number from reader.
static Null * readNull(JSONReader *reader)
Reads a JSON null from reader.

◆ readLabel()

static String * readLabel ( JSONReader reader)
static

Reads a JSON object key label from reader.

Definition at line 474 of file JSONContext.c.

474 {
475
476 const int b = readByteUntil(reader, "\"}");
477 if (b == '"') {
478 return readString(reader);
479 }
480 if (b == '}') {
481 reader->b--;
482 }
483
484 return NULL;
485}

◆ readNull()

static Null * readNull ( JSONReader reader)
static

Reads a JSON null from reader.

Definition at line 462 of file JSONContext.c.

462 {
463
464 if (!consumeBytes(reader, "null")) {
465 return NULL;
466 }
467
468 return retain($$(Null, null));
469}
static Null * null(void)
Definition Null.c:48
The Null sentinel.
Definition Null.h:42

◆ readNumber()

static Number * readNumber ( JSONReader reader)
static

Reads a JSON number from reader.

Definition at line 415 of file JSONContext.c.

415 {
416
417 uint8_t *bytes = reader->b;
418
419 uint8_t *end;
420 const double d = strtod((char *) bytes, (char **) &end);
421
422 if (end <= bytes) {
423 reader->error = true;
424 return NULL;
425 }
426
427 reader->b = end - 1;
428 return $$(Number, numberWithValue, d);
429}
static Number * numberWithValue(double value)
Definition Number.c:159
A wrapper for placing numeric primitives into collections, etc.
Definition Number.h:41

◆ readObject()

static Dictionary * readObject ( JSONReader reader)
static

Reads a JSON object (Dictionary) from reader.

Definition at line 490 of file JSONContext.c.

490 {
491
492 Dictionary *object = $(alloc(Dictionary), init);
493
494 while (true) {
495
496 String *key = readLabel(reader);
497 if (key == NULL) {
498 const int b = readByteUntil(reader, "}");
499 if (b != '}') {
500 reader->error = true;
501 }
502 break;
503 }
504
505 const int b = readByteUntil(reader, ":");
506 if (b != ':') {
507 release(key);
508 reader->error = true;
509 break;
510 }
511
512 ident obj = readElement(reader);
513 if (!obj) {
514 release(key);
515 reader->error = true;
516 break;
517 }
518
519 $(object, setObjectForKey, obj, key);
520
521 release(key);
522 release(obj);
523 }
524
525 return (Dictionary *) object;
526}
static String * readLabel(JSONReader *reader)
Reads a JSON object key label from reader.

◆ readString()

static String * readString ( JSONReader reader)
static

Reads a JSON-escaped string from reader.

Definition at line 346 of file JSONContext.c.

346 {
347
348 Data *buf = $(alloc(Data), init);
349
350 while (true) {
351 int b = readByte(reader);
352 if (b == -1 || b == '"') {
353 break;
354 }
355 if (b == '\\') {
356 b = readByte(reader);
357 switch (b) {
358 case '"': b = '"'; break;
359 case '\\': b = '\\'; break;
360 case '/': b = '/'; break;
361 case 'b': b = '\b'; break;
362 case 'f': b = '\f'; break;
363 case 'n': b = '\n'; break;
364 case 'r': b = '\r'; break;
365 case 't': b = '\t'; break;
366 case 'u': {
367 char hex[5] = {0};
368 for (int i = 0; i < 4; i++) {
369 int h = readByte(reader);
370 if (h == -1) {
371 reader->error = true;
372 release(buf);
373 return NULL;
374 }
375 hex[i] = (char) h;
376 }
377 unsigned long cp = strtoul(hex, NULL, 16);
378 if (cp < 0x80) {
379 uint8_t byte = (uint8_t) cp;
380 $(buf, appendBytes, &byte, 1);
381 } else if (cp < 0x800) {
382 uint8_t bytes[2] = {
383 (uint8_t) (0xC0 | (cp >> 6)),
384 (uint8_t) (0x80 | (cp & 0x3F))
385 };
386 $(buf, appendBytes, bytes, 2);
387 } else {
388 uint8_t bytes[3] = {
389 (uint8_t) (0xE0 | (cp >> 12)),
390 (uint8_t) (0x80 | ((cp >> 6) & 0x3F)),
391 (uint8_t) (0x80 | (cp & 0x3F))
392 };
393 $(buf, appendBytes, bytes, 3);
394 }
395 continue;
396 }
397 default:
398 reader->error = true;
399 release(buf);
400 return NULL;
401 }
402 }
403 uint8_t byte = (uint8_t) b;
404 $(buf, appendBytes, &byte, 1);
405 }
406
407 String *string = $$(String, stringWithBytes, buf->bytes, buf->length, STRING_ENCODING_UTF8);
408 release(buf);
409 return string;
410}
static void appendBytes(Data *self, const uint8_t *bytes, size_t length)
Definition Data.c:262
static String * string(void)
Definition String.c:905
static String * stringWithBytes(const uint8_t *bytes, size_t length, StringEncoding encoding)
Definition String.c:340
@ STRING_ENCODING_UTF8
Definition String.h:53

◆ structFromData()

static bool structFromData ( JSONContext self,
const JSONProperties properties,
const Data data,
ident  instance 
)
static

Definition at line 757 of file JSONContext.c.

757 {
758
759 ident obj = $(self, objectFromData, data, 0);
760 if (!obj || !$((Object *) obj, isKindOfClass, _Dictionary())) {
761 release(obj);
762 return false;
763 }
764
765 const bool ok = structFromDictionary(self, properties, (Dictionary *) obj, instance);
766
767 release(obj);
768 return ok;
769}
Class * _Dictionary(void)
Definition Dictionary.c:762
static bool isKindOfClass(const Object *self, const Class *clazz)
Definition Object.c:101

◆ structFromDictionary()

static bool structFromDictionary ( JSONContext self,
const JSONProperties properties,
const Dictionary dictionary,
ident  instance 
)
static

Deserializes a Dictionary into a C struct.

Definition at line 704 of file JSONContext.c.

704 {
705
706 if (!properties || !dictionary || !instance) {
707 return false;
708 }
709
710 bool ok = true;
711
712 for (const JSONProperty *p = properties->properties; p->key; p++) {
713 if (!p->deserializer) {
714 continue;
715 }
716
717 String *key = $$(String, stringWithCharacters, p->key);
718 const Object *val = $(dictionary, objectForKey, key);
719 release(key);
720
721 if (!val) {
722 continue;
723 }
724
725 if (!p->deserializer(properties, p, val, instance + p->offset, self)) {
726 addError(self, 2, p->key, "type mismatch");
727 ok = false;
728 }
729 }
730
731 return ok;
732}
static Dictionary * dictionary(void)
Definition Dictionary.c:242
static ident objectForKey(const Dictionary *self, const ident key)
Definition Dictionary.c:439

◆ structsFromArray()

static size_t structsFromArray ( JSONContext self,
const JSONProperties properties,
const Array array,
ident  instances,
size_t  count 
)
static

Deserializes a JSON Array into an array of C structs.

Definition at line 737 of file JSONContext.c.

737 {
738
739 if (!properties || !array || !instances || !count) {
740 return 0;
741 }
742
743 const size_t n = min(array->count, count);
744
745 for (size_t i = 0; i < n; i++) {
747 $(self, structFromDictionary, properties, dictionary, instances + i * properties->size);
748 }
749
750 return n;
751}
static ident objectAtIndex(const Array *self, size_t index)
Definition Array.c:578
#define cast(type, obj)
Safely cast obj to type.
Definition Class.h:182
#define min(a, b)
Definition Types.h:159
size_t count
The count of elements.
Definition Array.h:72

◆ structsFromData()

static size_t structsFromData ( JSONContext self,
const JSONProperties properties,
const Data data,
ident  instances,
size_t  count 
)
static

Definition at line 775 of file JSONContext.c.

775 {
776
777 ident obj = objectFromData(self, data, 0);
778 if (!obj || !$((Object *) obj, isKindOfClass, _Array())) {
779 release(obj);
780 return 0;
781 }
782
783 const size_t n = structsFromArray(self, properties, (Array *) obj, instances, count);
784
785 release(obj);
786 return n;
787}
Class * _Array(void)
Definition Array.c:760

◆ writeArray()

static void writeArray ( JSONWriter writer,
const Array array 
)
static

Writes a JSON array to writer.

Definition at line 231 of file JSONContext.c.

231 {
232
233 $(writer->data, appendBytes, (uint8_t *) "[", 1);
234 writer->depth++;
235
236 for (size_t i = 0; i < array->count; i++) {
237
238 writePretty(writer);
239 writeElement(writer, $(array, objectAtIndex, i));
240
241 if (i < array->count - 1) {
242 $(writer->data, appendBytes, (uint8_t *) ",", 1);
243 }
244 }
245
246 writer->depth--;
247 writePretty(writer);
248
249 $(writer->data, appendBytes, (uint8_t *) "]", 1);
250}
static void writePretty(JSONWriter *writer)
Writes pretty-print indentation to writer, if enabled.
size_t depth
Definition JSONContext.c:97

◆ writeBoole()

static void writeBoole ( JSONWriter writer,
const Boole boolean 
)
static

Writes a JSON boolean to writer.

Definition at line 113 of file JSONContext.c.

113 {
114
115 if (boolean->value) {
116 $(writer->data, appendBytes, (uint8_t *) "true", 4);
117 } else {
118 $(writer->data, appendBytes, (uint8_t *) "false", 5);
119 }
120}
bool value
The backing bool.
Definition Boole.h:57

◆ writeElement()

static void writeElement ( JSONWriter writer,
const ident  obj 
)
static

Writes any JSON element to writer.

Definition at line 255 of file JSONContext.c.

255 {
256
257 const Object *object = cast(Object, obj);
258 if (object) {
259 if ($(object, isKindOfClass, _Dictionary())) {
260 writeObject(writer, (const Dictionary *) object);
261 } else if ($(object, isKindOfClass, _Array())) {
262 writeArray(writer, (const Array *) object);
263 } else if ($(object, isKindOfClass, _String())) {
264 writeString(writer, (const String *) object);
265 } else if ($(object, isKindOfClass, _Number())) {
266 writeNumber(writer, (const Number *) object);
267 } else if ($(object, isKindOfClass, _Boole())) {
268 writeBoole(writer, (const Boole *) object);
269 } else if ($(object, isKindOfClass, _Null())) {
270 writeNull(writer, (const Null *) object);
271 }
272 }
273}
Class * _Boole(void)
Definition Boole.c:125
static void writeNull(JSONWriter *writer, const Null *null)
Writes null to writer.
static void writeString(JSONWriter *writer, const String *string)
Writes a JSON-escaped string to writer.
static void writeNumber(JSONWriter *writer, const Number *number)
Writes a JSON number to writer.
static void writeBoole(JSONWriter *writer, const Boole *boolean)
Writes a JSON boolean to writer.
static void writeArray(JSONWriter *writer, const Array *array)
Writes a JSON array to writer.
static void writeObject(JSONWriter *writer, const Dictionary *object)
Writes a JSON object (Dictionary) to writer.
Class * _Null(void)
Definition Null.c:83
Class * _Number(void)
Definition Number.c:198
Class * _String(void)
Definition String.c:999

◆ writeLabel()

static void writeLabel ( JSONWriter writer,
const String label 
)
static

Writes a JSON object key label to writer.

Definition at line 171 of file JSONContext.c.

171 {
172
173 writeString(writer, label);
174 $(writer->data, appendBytes, (uint8_t *) ": ", 2);
175}

◆ writeNull()

static void writeNull ( JSONWriter writer,
const Null null 
)
static

Writes null to writer.

Definition at line 105 of file JSONContext.c.

105 {
106
107 $(writer->data, appendBytes, (uint8_t *) "null", 4);
108}

◆ writeNumber()

static void writeNumber ( JSONWriter writer,
const Number number 
)
static

Writes a JSON number to writer.

Definition at line 159 of file JSONContext.c.

159 {
160
161 // Use enough significant digits to preserve 32-bit epoch seconds and other
162 // large integers exactly when round-tripping through JSON.
163 String *string = $(alloc(String), initWithFormat, "%.17g", number->value);
164 $(writer->data, appendBytes, (uint8_t *) string->chars, string->length);
165 release(string);
166}
double value
The backing value.
Definition Number.h:57
char * chars
The backing null-terminated UTF-8 encoded character array.
Definition String.h:85
size_t length
The length of the String in bytes.
Definition String.h:90

◆ writeObject()

static void writeObject ( JSONWriter writer,
const Dictionary object 
)
static

Writes a JSON object (Dictionary) to writer.

Definition at line 193 of file JSONContext.c.

193 {
194
195 $(writer->data, appendBytes, (uint8_t *) "{", 1);
196 writer->depth++;
197
198 Array *keys = $(object, allKeys);
199 if (writer->options & JSON_WRITE_SORTED) {
200 Array *sorted = $(keys, sortedArray, StringCompare);
201 release(keys);
202 keys = sorted;
203 }
204
205 for (size_t i = 0; i < keys->count; i++) {
206
207 writePretty(writer);
208
209 const ident key = $(keys, objectAtIndex, i);
210 writeLabel(writer, (String *) key);
211
212 const ident obj = $(object, objectForKey, key);
213 writeElement(writer, obj);
214
215 if (i < keys->count - 1) {
216 $(writer->data, appendBytes, (uint8_t *) ",", 1);
217 }
218 }
219
220 release(keys);
221
222 writer->depth--;
223 writePretty(writer);
224
225 $(writer->data, appendBytes, (uint8_t *) "}", 1);
226}
static Array * sortedArray(const Array *self, Comparator comparator)
Definition Array.c:694
static Array * allKeys(const Dictionary *self)
Definition Dictionary.c:193
static void writeLabel(JSONWriter *writer, const String *label)
Writes a JSON object key label to writer.
@ JSON_WRITE_SORTED
Enables lexicographic sorting of JSON object keys.
Definition JSONContext.h:57
Order StringCompare(const ident a, const ident b)
Definition String.c:1066

◆ writePretty()

static void writePretty ( JSONWriter writer)
static

Writes pretty-print indentation to writer, if enabled.

Definition at line 180 of file JSONContext.c.

180 {
181
182 if (writer->options & JSON_WRITE_PRETTY) {
183 $(writer->data, appendBytes, (uint8_t *) "\n", 1);
184 for (size_t i = 0; i < writer->depth; i++) {
185 $(writer->data, appendBytes, (uint8_t *) " ", 2);
186 }
187 }
188}
@ JSON_WRITE_PRETTY
Enables pretty (indented) formatting of JSON output.
Definition JSONContext.h:52

◆ writeString()

static void writeString ( JSONWriter writer,
const String string 
)
static

Writes a JSON-escaped string to writer.

Definition at line 125 of file JSONContext.c.

125 {
126
127 $(writer->data, appendBytes, (uint8_t *) "\"", 1);
128
129 const char *s = string->chars;
130 const char *end = s + string->length;
131 while (s < end) {
132 const unsigned char c = (unsigned char) *s++;
133 switch (c) {
134 case '"': $(writer->data, appendBytes, (uint8_t *) "\\\"", 2); break;
135 case '\\': $(writer->data, appendBytes, (uint8_t *) "\\\\", 2); break;
136 case '\b': $(writer->data, appendBytes, (uint8_t *) "\\b", 2); break;
137 case '\f': $(writer->data, appendBytes, (uint8_t *) "\\f", 2); break;
138 case '\n': $(writer->data, appendBytes, (uint8_t *) "\\n", 2); break;
139 case '\r': $(writer->data, appendBytes, (uint8_t *) "\\r", 2); break;
140 case '\t': $(writer->data, appendBytes, (uint8_t *) "\\t", 2); break;
141 default:
142 if (c < 0x20) {
143 char seq[7];
144 snprintf(seq, sizeof(seq), "\\u%04x", c);
145 $(writer->data, appendBytes, (uint8_t *) seq, 6);
146 } else {
147 $(writer->data, appendBytes, (uint8_t *) &c, 1);
148 }
149 break;
150 }
151 }
152
153 $(writer->data, appendBytes, (uint8_t *) "\"", 1);
154}