JST: JSON tools  1.0.0
JSON tools dynamic library for reading, manipulating and writing JSON tree
JST_serialize.c
Go to the documentation of this file.
1 #include "JST_string.h"
2 
3 #include <stdlib.h>
4 
5 static bool serialize_quoted_string( JST_String * string, const char * s ) {
6  return JST_String_append_char ( string, '"' )
7  && JST_String_append_string( string, s )
8  && JST_String_append_char ( string, '"' );
9 }
10 
11 static JST_Error serialize_element( const JST_Element * elt, JST_String * string, unsigned left_margin, unsigned indent );
12 
13 static JST_Error serialize_object( const JST_Object * object, JST_String * string, unsigned left_margin, unsigned indent ) {
14  for( JST_Pair * iter = object->first; iter; iter = iter->next ) {
15  if( ( ! JST_String_spaces ( string, left_margin ))
16  ||( ! serialize_quoted_string ( string, iter->name ))
17  ||( ! JST_String_append_string( string, ": " )))
18  {
19  return JST_ERR_ERRNO;
20  }
21  JST_Error err = serialize_element( &(iter->element), string, left_margin, indent );
22  if( err != JST_ERR_NONE ) {
23  return err;
24  }
25  if( ! JST_String_append_string( string, iter->next ? ",\n" : "\n" )) {
26  return JST_ERR_ERRNO;
27  }
28  }
29  return JST_ERR_NONE;
30 }
31 
32 static JST_Error serialize_array( const JST_Array * array, JST_String * string, unsigned left_margin, unsigned indent ) {
33  for( unsigned i = 0; i < array->count; ++i ) {
34  if( ! JST_String_spaces( string, left_margin )) {
35  return JST_ERR_ERRNO;
36  }
37  JST_Error err = serialize_element( &(array->items[i]->element), string, left_margin, indent );
38  if( err != JST_ERR_NONE ) {
39  return err;
40  }
41  if( ! JST_String_append_string( string, ( i < array->count - 1 ) ? ",\n" : "\n" )) {
42  return JST_ERR_ERRNO;
43  }
44  }
45  return JST_ERR_NONE;
46 }
47 
48 static JST_Error serialize_element( const JST_Element * elt, JST_String * string, unsigned left_margin, unsigned indent ) {
49  static char buffer[100];
50  JST_Error err = JST_ERR_NONE;
51  switch( elt->type ) {
52  case JST_OBJECT:
53  if( ! JST_String_append_string( string, "{\n" )) {
54  return JST_ERR_ERRNO;
55  }
56  err = serialize_object( &(elt->value.object), string, left_margin+indent, indent );
57  if( err != JST_ERR_NONE ) {
58  return err;
59  }
60  if( ( ! JST_String_spaces( string, left_margin ))
61  ||( ! JST_String_append_char( string, '}' )))
62  {
63  return JST_ERR_ERRNO;
64  }
65  break;
66  case JST_ARRAY:
67  if( ! JST_String_append_string( string, "[\n" )) {
68  return JST_ERR_ERRNO;
69  }
70  err = serialize_array( &(elt->value.array), string, left_margin+indent, indent );
71  if( err != JST_ERR_NONE ) {
72  return err;
73  }
74  if( ( ! JST_String_spaces( string, left_margin ))
75  ||( ! JST_String_append_char( string, ']' )))
76  {
77  return JST_ERR_ERRNO;
78  }
79  break;
80  case JST_BOOLEAN:
81  if( ! JST_String_append_string( string, elt->value.boolean ? "true" : "false" )) {
82  return JST_ERR_ERRNO;
83  }
84  break;
85  case JST_INTEGER:
86  sprintf( buffer, "%ld", elt->value.integer );
87  if( ! JST_String_append_string( string, buffer )) {
88  return JST_ERR_ERRNO;
89  }
90  break;
91  case JST_DOUBLE:
92  sprintf( buffer, "%G", elt->value.dbl );
93  if( ! JST_String_append_string( string, buffer )) {
94  return JST_ERR_ERRNO;
95  }
96  break;
97  case JST_STRING:
98  if( ! serialize_quoted_string( string, elt->value.string )) {
99  return JST_ERR_ERRNO;
100  }
101  break;
102  case JST_NULL:
103  if( ! JST_String_append_string( string, "null" )) {
104  return JST_ERR_ERRNO;
105  }
106  break;
107  default: return JST_ERR_NULL_TYPE;
108  }
109  return JST_ERR_NONE;
110 }
111 
112 JST_Error JST_serialize( JST_Element * root, char ** dest, unsigned indent ) {
113  if(( root == NULL )||( dest == NULL )) {
114  return JST_ERR_NULL_ARGUMENT;
115  }
116  JST_String string = JST_String_Zero;
117  if(( serialize_element( root, &string, 0, indent ) == JST_ERR_NONE )&& JST_String_append_char( &string, '\n' )) {
118  string.buffer[string.length] = '\0';
119  *dest = realloc( string.buffer, string.length + 1 ); // truncate, if necessary
120  if( *dest == NULL ) {
121  JST_String_delete( &string );
122  return JST_ERR_ERRNO;
123  }
124  string.buffer = NULL;
125  }
126  JST_String_delete( &string );
127  return JST_ERR_NONE;
128 }
129 
130 static JST_Error serialize_element_compact( const JST_Element * elt, JST_String * string );
131 
132 static JST_Error serialize_object_compact( const JST_Object * object, JST_String * string ) {
133  for( JST_Pair * iter = object->first; iter; iter = iter->next ) {
134  if( ( ! serialize_quoted_string( string, iter->name ))
135  ||( ! JST_String_append_char ( string, ':' )))
136  {
137  return JST_ERR_ERRNO;
138  }
139  JST_Error err = serialize_element_compact( &(iter->element), string );
140  if( err != JST_ERR_NONE ) {
141  return err;
142  }
143  if( iter->next ) {
144  if( ! JST_String_append_char( string, ',' )) {
145  return JST_ERR_ERRNO;
146  }
147  }
148  }
149  return JST_ERR_NONE;
150 }
151 
152 static JST_Error serialize_array_compact( const JST_Array * array, JST_String * string ) {
153  for( unsigned i = 0; i < array->count; ++i ) {
154  JST_Error err = serialize_element_compact( &(array->items[i]->element), string );
155  if( err != JST_ERR_NONE ) {
156  return err;
157  }
158  if( i < array->count - 1 ) {
159  if( ! JST_String_append_char( string, ',' )) {
160  return JST_ERR_ERRNO;
161  }
162  }
163  }
164  return JST_ERR_NONE;
165 }
166 
167 static JST_Error serialize_element_compact( const JST_Element * elt, JST_String * string ) {
168  static char buffer[100];
169  JST_Error err = JST_ERR_NONE;
170  switch( elt->type ) {
171  case JST_OBJECT:
172  if( ! JST_String_append_char( string, '{' )) {
173  return JST_ERR_ERRNO;
174  }
175  err = serialize_object_compact( &(elt->value.object), string );
176  if( err != JST_ERR_NONE ) {
177  return err;
178  }
179  if( ! JST_String_append_char( string, '}' )) {
180  return JST_ERR_ERRNO;
181  }
182  break;
183  case JST_ARRAY:
184  if( ! JST_String_append_char( string, '[' )) {
185  return JST_ERR_ERRNO;
186  }
187  err = serialize_array_compact( &(elt->value.array), string );
188  if( err != JST_ERR_NONE ) {
189  return err;
190  }
191  if( ! JST_String_append_char( string, ']' )) {
192  return JST_ERR_ERRNO;
193  }
194  break;
195  case JST_BOOLEAN:
196  if( ! JST_String_append_string( string, elt->value.boolean ? "true" : "false" )) {
197  return JST_ERR_ERRNO;
198  }
199  break;
200  case JST_INTEGER:
201  sprintf( buffer, "%ld", elt->value.integer );
202  if( ! JST_String_append_string( string, buffer )) {
203  return JST_ERR_ERRNO;
204  }
205  break;
206  case JST_DOUBLE:
207  sprintf( buffer, "%G", elt->value.dbl );
208  if( ! JST_String_append_string( string, buffer )) {
209  return JST_ERR_ERRNO;
210  }
211  break;
212  case JST_STRING:
213  if( ! serialize_quoted_string( string, elt->value.string )) {
214  return JST_ERR_ERRNO;
215  }
216  break;
217  case JST_NULL:
218  if( ! JST_String_append_string( string, "null" )) {
219  return JST_ERR_ERRNO;
220  }
221  break;
222  default: return JST_ERR_NULL_TYPE;
223  }
224  return JST_ERR_NONE;
225 }
226 
227 JST_Error JST_serialize_compact( JST_Element * root, char ** dest ) {
228  if(( root == NULL )||( dest == NULL )) {
229  return JST_ERR_NULL_ARGUMENT;
230  }
231  JST_String string = JST_String_Zero;
232  if(( serialize_element_compact( root, &string ) == JST_ERR_NONE )) {
233  string.buffer[string.length] = '\0';
234  *dest = realloc( string.buffer, string.length + 1 ); // truncate, if necessary
235  if( *dest == NULL ) {
236  JST_String_delete( &string );
237  return JST_ERR_ERRNO;
238  }
239  string.buffer = NULL;
240  }
241  JST_String_delete( &string );
242  return JST_ERR_NONE;
243 }
bool JST_String_append_string(JST_String *string, const char *s)
Definition: JST_string.c:26
char * buffer
Definition: JST_string.h:8
A object attribute item has a parent and is a named-typed-value pair.
Definition: jstools.h:93
A JSON array.
Definition: jstools.h:10
JST_Element element
Definition: jstools.h:85
JST_Error JST_serialize_compact(JST_Element *root, char **dest)
Serialize the JSON tree to a string as a single line of text, without whitespaces.
A type field has been set to JST_NONE.
Definition: jstools.h:111
char * string
Definition: jstools.h:46
A JSON object, a sorted set of named-value pairs.
Definition: jstools.h:24
JST_Object object
Definition: jstools.h:41
bool boolean
Definition: jstools.h:43
JST_Value value
Definition: jstools.h:72
JST_Error
When things goes wrong, an error information is given.
Definition: jstools.h:108
struct JST_Pair_ * first
A linked list is mandatory to preserve the properties&#39;s order.
Definition: jstools.h:28
strerror() or perror() can be used to show the operating system layer error
Definition: jstools.h:112
An element is a typed value.
Definition: jstools.h:70
bool JST_String_append_char(JST_String *string, char c)
Definition: JST_string.c:8
JST_Array array
Definition: jstools.h:42
double dbl
Definition: jstools.h:45
JST_Error JST_String_delete(JST_String *string)
Definition: JST_string.c:45
struct JST_Pair_ * next
A linked list is mandatory to preserve the properties&#39;s order.
Definition: jstools.h:97
bool JST_String_spaces(JST_String *string, unsigned count)
Definition: JST_string.c:36
int64_t integer
Definition: jstools.h:44
Function misused.
Definition: jstools.h:110
JST_Error JST_serialize(JST_Element *root, char **dest, unsigned indent)
Serialize the JSON tree to a string, pretty-printed.
struct JST_ArrayItem_ ** items
Array of JST_ArrayItem.
Definition: jstools.h:11
unsigned count
Cardinality of the previous array.
Definition: jstools.h:12
JST_ValueType type
Definition: jstools.h:71
const JST_String JST_String_Zero
Definition: JST_string.c:6