libcbor  0.5.0
libcbor is a C library for parsing and generating CBOR, the general-purpose schema-less binary data format.
builder_callbacks.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014-2017 Pavel Kalvoda <me@pavelkalvoda.com>
3  *
4  * libcbor is free software; you can redistribute it and/or modify
5  * it under the terms of the MIT license. See LICENSE for details.
6  */
7 
8 #include "builder_callbacks.h"
9 #include "unicode.h"
10 #include <string.h>
11 #include "../arrays.h"
12 #include "../bytestrings.h"
13 #include "../floats_ctrls.h"
14 #include "../ints.h"
15 #include "../maps.h"
16 #include "../strings.h"
17 #include "../tags.h"
18 
20 {
21  if (ctx->stack->size == 0) {
22  /* Top level item */
23  ctx->root = item;
24  } else {
25  /* Part of a bigger structure */
26  switch (ctx->stack->top->item->type) {
27  case CBOR_TYPE_ARRAY: {
28  if (cbor_array_is_definite(ctx->stack->top->item)) {
29  assert(ctx->stack->top->subitems > 0);
30  cbor_array_push(ctx->stack->top->item, item);
31  ctx->stack->top->subitems--;
32  if (ctx->stack->top->subitems == 0) {
33  cbor_item_t *item = ctx->stack->top->item;
34  _cbor_stack_pop(ctx->stack);
35  _cbor_builder_append(item, ctx);
36  }
37  cbor_decref(&item);
38  } else {
39  /* Indefinite array, don't bother with subitems */
40  cbor_array_push(ctx->stack->top->item, item);
41  cbor_decref(&item);
42  }
43  break;
44  }
45  case CBOR_TYPE_MAP: {
46  /* We use 0 and 1 subitems to distinguish between keys and values in indefinite items */
47  if (ctx->stack->top->subitems % 2) {
48  /* Odd record, this is a value */
50  } else {
51  /* Even record, this is a key */
52  _cbor_map_add_key(ctx->stack->top->item, cbor_move(item));
53  }
54  if (cbor_map_is_definite(ctx->stack->top->item)) {
55  ctx->stack->top->subitems--;
56  if (ctx->stack->top->subitems == 0) {
57  cbor_item_t *item = ctx->stack->top->item;
58  _cbor_stack_pop(ctx->stack);
59  _cbor_builder_append(item, ctx);
60  }
61  } else {
62  ctx->stack->top->subitems ^= 1; /* Flip the indicator for indefinite items */
63  }
64  break;
65  }
66  case CBOR_TYPE_TAG: {
67  assert(ctx->stack->top->subitems == 1);
68  cbor_tag_set_item(ctx->stack->top->item, item);
69  cbor_decref(&item); /* Give up on our reference */
70  cbor_item_t *item = ctx->stack->top->item;
71  _cbor_stack_pop(ctx->stack);
72  _cbor_builder_append(item, ctx);
73  break;
74  }
75  default: {
76  cbor_decref(&item);
77  ctx->syntax_error = true;
78  }
79  }
80  }
81 }
82 
83 
84 #define CHECK_RES do { if (res == NULL) { ctx->creation_failed = true; return; } } while (0)
85 
86 void cbor_builder_uint8_callback(void *context, uint8_t value)
87 {
88  struct _cbor_decoder_context *ctx = context;
89  cbor_item_t *res = cbor_new_int8();
90  CHECK_RES;
91  cbor_mark_uint(res);
92  cbor_set_uint8(res, value);
93  _cbor_builder_append(res, ctx);
94 }
95 
96 void cbor_builder_uint16_callback(void *context, uint16_t value)
97 {
98  struct _cbor_decoder_context *ctx = context;
99  cbor_item_t *res = cbor_new_int16();
100  CHECK_RES;
101  cbor_mark_uint(res);
102  cbor_set_uint16(res, value);
103  _cbor_builder_append(res, ctx);
104 }
105 
106 void cbor_builder_uint32_callback(void *context, uint32_t value)
107 {
108  struct _cbor_decoder_context *ctx = context;
109  cbor_item_t *res = cbor_new_int32();
110  CHECK_RES;
111  cbor_mark_uint(res);
112  cbor_set_uint32(res, value);
113  _cbor_builder_append(res, ctx);
114 }
115 
116 void cbor_builder_uint64_callback(void *context, uint64_t value)
117 {
118  struct _cbor_decoder_context *ctx = context;
119  cbor_item_t *res = cbor_new_int64();
120  CHECK_RES;
121  cbor_mark_uint(res);
122  cbor_set_uint64(res, value);
123  _cbor_builder_append(res, ctx);
124 }
125 
126 void cbor_builder_negint8_callback(void *context, uint8_t value)
127 {
128  struct _cbor_decoder_context *ctx = context;
129  cbor_item_t *res = cbor_new_int8();
130  CHECK_RES;
131  cbor_mark_negint(res);
132  cbor_set_uint8(res, value);
133  _cbor_builder_append(res, ctx);
134 }
135 
136 void cbor_builder_negint16_callback(void *context, uint16_t value)
137 {
138  struct _cbor_decoder_context *ctx = context;
139  cbor_item_t *res = cbor_new_int16();
140  cbor_mark_negint(res);
141  cbor_set_uint16(res, value);
142  _cbor_builder_append(res, ctx);
143 }
144 
145 void cbor_builder_negint32_callback(void *context, uint32_t value)
146 {
147  struct _cbor_decoder_context *ctx = context;
148  cbor_item_t *res = cbor_new_int32();
149  CHECK_RES;
150  cbor_mark_negint(res);
151  cbor_set_uint32(res, value);
152  _cbor_builder_append(res, ctx);
153 }
154 
155 void cbor_builder_negint64_callback(void *context, uint64_t value)
156 {
157  struct _cbor_decoder_context *ctx = context;
158  cbor_item_t *res = cbor_new_int64();
159  CHECK_RES;
160  cbor_mark_negint(res);
161  cbor_set_uint64(res, value);
162  _cbor_builder_append(res, ctx);
163 }
164 
165 void cbor_builder_byte_string_callback(void *context, cbor_data data, size_t length)
166 {
167  struct _cbor_decoder_context *ctx = context;
168  unsigned char *new_handle = _CBOR_MALLOC(length);
169  if (new_handle == NULL) {
170  ctx->creation_failed = true;
171  return;
172  }
173 
174  memcpy(new_handle, data, length);
176 
177  if (res == NULL) {
178  _CBOR_FREE(new_handle);
179  ctx->creation_failed = true;
180  return;
181  }
182 
183  cbor_bytestring_set_handle(res, new_handle, length);
184 
185  if (ctx->stack->size > 0 && cbor_isa_bytestring(ctx->stack->top->item)) {
188  } else {
189  cbor_decref(&res);
190  ctx->syntax_error = true;
191  }
192  } else {
193  _cbor_builder_append(res, ctx);
194  }
195 }
196 
198 {
199  struct _cbor_decoder_context *ctx = context;
201  CHECK_RES;
202  _cbor_stack_push(ctx->stack, res, 0);
203 }
204 
205 
206 void cbor_builder_string_callback(void *context, cbor_data data, size_t length)
207 {
208  struct _cbor_decoder_context *ctx = context;
209  struct _cbor_unicode_status unicode_status;
210 
211  size_t codepoint_count = _cbor_unicode_codepoint_count(data, length, &unicode_status);
212 
213  if (unicode_status.status == _CBOR_UNICODE_BADCP) {
214  ctx->syntax_error = true;
215  return;
216  }
217 
218  unsigned char *new_handle = _CBOR_MALLOC(length);
219 
220  if (new_handle == NULL) {
221  ctx->creation_failed = true;
222  return;
223  }
224 
225  memcpy(new_handle, data, length);
227  cbor_string_set_handle(res, new_handle, length);
228  res->metadata.string_metadata.codepoint_count = codepoint_count;
229 
230  /* Careful here: order matters */
231  if (ctx->stack->size > 0 && cbor_isa_string(ctx->stack->top->item)) {
232  if (cbor_string_is_indefinite(ctx->stack->top->item)) {
234  } else {
235  cbor_decref(&res);
236  ctx->syntax_error = true;
237  }
238  } else {
239  _cbor_builder_append(res, ctx);
240  }
241 }
242 
244 {
245  struct _cbor_decoder_context *ctx = context;
247  CHECK_RES;
248  _cbor_stack_push(ctx->stack, res, 0);
249 }
250 
251 void cbor_builder_array_start_callback(void *context, size_t size)
252 {
253  struct _cbor_decoder_context *ctx = context;
255  CHECK_RES;
256  if (size > 0) {
257  _cbor_stack_push(ctx->stack, res, size);
258  } else {
259  _cbor_builder_append(res, ctx);
260  }
261 }
262 
264 {
265  struct _cbor_decoder_context *ctx = context;
267  CHECK_RES;
268  _cbor_stack_push(ctx->stack, res, 0);
269 }
270 
272 {
273  struct _cbor_decoder_context *ctx = context;
275  CHECK_RES;
276  _cbor_stack_push(ctx->stack, res, 0);
277 }
278 
279 void cbor_builder_map_start_callback(void *context, size_t size)
280 {
281  struct _cbor_decoder_context *ctx = context;
282  cbor_item_t *res = cbor_new_definite_map(size);
283  CHECK_RES;
284  if (size > 0) {
285  _cbor_stack_push(ctx->stack, res, size * 2);
286  } else {
287  _cbor_builder_append(res, ctx);
288  }
289 }
290 
292 {
293  struct _cbor_decoder_context *ctx = context;
294  if (ctx->stack->size == 0) {
295  // TODO complain
296  } else {
297  cbor_item_t *item = ctx->stack->top->item;
298  _cbor_stack_pop(ctx->stack);
299  _cbor_builder_append(item, ctx);
300  }
301 }
302 
303 void cbor_builder_float2_callback(void *context, float value)
304 {
305  struct _cbor_decoder_context *ctx = context;
306  cbor_item_t *res = cbor_new_float2();
307  cbor_set_float2(res, value);
308  _cbor_builder_append(res, ctx);
309 }
310 
311 void cbor_builder_float4_callback(void *context, float value)
312 {
313  struct _cbor_decoder_context *ctx = context;
314  cbor_item_t *res = cbor_new_float4();
315  CHECK_RES;
316  cbor_set_float4(res, value);
317  _cbor_builder_append(res, ctx);
318 }
319 
320 void cbor_builder_float8_callback(void *context, double value)
321 {
322  struct _cbor_decoder_context *ctx = context;
323  cbor_item_t *res = cbor_new_float8();
324  CHECK_RES;
325  cbor_set_float8(res, value);
326  _cbor_builder_append(res, ctx);
327 }
328 
329 void cbor_builder_null_callback(void *context)
330 {
331  struct _cbor_decoder_context *ctx = context;
332  cbor_item_t *res = cbor_new_null();
333  CHECK_RES;
334  _cbor_builder_append(res, ctx);
335 }
336 
338 {
339  struct _cbor_decoder_context *ctx = context;
340  cbor_item_t *res = cbor_new_undef();
341  CHECK_RES;
342  _cbor_builder_append(res, ctx);
343 }
344 
345 void cbor_builder_boolean_callback(void *context, bool value)
346 {
347  struct _cbor_decoder_context *ctx = context;
348  cbor_item_t *res = cbor_build_bool(value);
349  CHECK_RES;
350  _cbor_builder_append(res, ctx);
351 }
352 
353 void cbor_builder_tag_callback(void *context, uint64_t value)
354 {
355  struct _cbor_decoder_context *ctx = context;
356  cbor_item_t *res = cbor_new_tag(value);
357  CHECK_RES;
358  _cbor_stack_push(ctx->stack, res, 1);
359 }
void cbor_builder_float4_callback(void *context, float value)
void cbor_set_float4(cbor_item_t *item, float value)
Assigns a float value.
Definition: floats_ctrls.c:71
cbor_item_t * cbor_new_int64()
Allocates new integer with 8B width.
Definition: ints.c:133
void cbor_set_float2(cbor_item_t *item, float value)
Assigns a float value.
Definition: floats_ctrls.c:64
size_t size
Definition: stack.h:27
size_t subitems
Definition: stack.h:21
bool syntax_error
Stack expectation mismatch.
6 - tags
Definition: data.h:31
void cbor_string_set_handle(cbor_item_t *item, cbor_mutable_data CBOR_RESTRICT_POINTER data, size_t length)
Set the handle to the underlying string.
Definition: strings.c:59
union cbor_item_metadata metadata
Discriminated by type.
Definition: data.h:151
void cbor_set_uint16(cbor_item_t *item, uint16_t value)
Assigns the integer value.
Definition: ints.c:63
void cbor_builder_byte_string_callback(void *context, cbor_data data, size_t length)
void cbor_builder_uint32_callback(void *context, uint32_t value)
cbor_item_t * cbor_new_int8()
Allocates new integer with 1B width.
Definition: ints.c:97
cbor_item_t * cbor_new_indefinite_bytestring()
Creates a new indefinite byte string.
Definition: bytestrings.c:46
cbor_item_t * cbor_new_indefinite_string()
Creates a new indefinite string.
Definition: strings.c:23
void cbor_builder_uint8_callback(void *context, uint8_t value)
void cbor_decref(cbor_item_t **item_ref)
Decreases the reference count by one, deallocating the item if needed.
Definition: common.c:99
bool cbor_isa_string(const cbor_item_t *item)
Does the item have the appropriate major type?
Definition: common.c:33
void cbor_builder_uint64_callback(void *context, uint64_t value)
void cbor_builder_tag_callback(void *context, uint64_t value)
cbor_item_t * cbor_new_definite_bytestring()
Creates a new definite byte string.
Definition: bytestrings.c:35
bool cbor_isa_bytestring(const cbor_item_t *item)
Does the item have the appropriate major type?
Definition: common.c:28
void cbor_builder_float2_callback(void *context, float value)
void cbor_builder_indef_break_callback(void *context)
cbor_item_t * cbor_new_undef()
Constructs new under ctrl item.
Definition: floats_ctrls.c:153
void cbor_builder_negint8_callback(void *context, uint8_t value)
#define CHECK_RES
bool cbor_bytestring_is_indefinite(const cbor_item_t *item)
Is the byte string indefinite?
Definition: bytestrings.c:30
cbor_item_t * cbor_build_bool(bool value)
Constructs new boolean ctrl item.
Definition: floats_ctrls.c:160
4 - arrays
Definition: data.h:29
cbor_item_t * cbor_new_tag(uint64_t value)
Create a new tag.
Definition: tags.c:10
void cbor_set_uint8(cbor_item_t *item, uint8_t value)
Assigns the integer value.
Definition: ints.c:56
enum _cbor_unicode_status_error status
Definition: unicode.h:24
bool _cbor_map_add_key(cbor_item_t *item, cbor_item_t *key)
Add a key to the map.
Definition: maps.c:66
cbor_item_t * cbor_new_indefinite_array()
Create new indefinite array.
Definition: arrays.c:138
cbor_type type
Major type discriminator.
Definition: data.h:155
void cbor_builder_negint16_callback(void *context, uint16_t value)
void cbor_mark_negint(cbor_item_t *item)
Marks the integer item as a negative integer.
Definition: ints.c:91
High-level decoding context.
#define _CBOR_FREE
Definition: common.h:86
#define _CBOR_MALLOC
Definition: common.h:84
void cbor_builder_undefined_callback(void *context)
cbor_item_t * cbor_new_definite_string()
Creates a new definite string.
Definition: strings.c:12
void _cbor_stack_pop(struct _cbor_stack *stack)
Definition: stack.c:15
bool cbor_array_is_definite(const cbor_item_t *item)
Is the array definite?
Definition: arrays.c:88
void cbor_builder_null_callback(void *context)
bool cbor_array_push(cbor_item_t *array, cbor_item_t *pushee)
Append to the end.
Definition: arrays.c:52
void cbor_builder_string_start_callback(void *context)
void cbor_builder_array_start_callback(void *context, size_t size)
void cbor_set_uint32(cbor_item_t *item, uint32_t value)
Assigns the integer value.
Definition: ints.c:71
void cbor_builder_string_callback(void *context, cbor_data data, size_t length)
cbor_item_t * cbor_new_float4()
Constructs a new float item.
Definition: floats_ctrls.c:122
bool cbor_bytestring_add_chunk(cbor_item_t *item, cbor_item_t *chunk)
Appends a chunk to the bytestring.
Definition: bytestrings.c:95
Signals unicode validation error and possibly its location.
Definition: unicode.h:23
size_t codepoint_count
Definition: data.h:90
void cbor_builder_indef_array_start_callback(void *context)
cbor_item_t * cbor_new_float8()
Constructs a new float item.
Definition: floats_ctrls.c:134
const unsigned char * cbor_data
Definition: data.h:20
size_t _cbor_unicode_codepoint_count(cbor_data source, size_t source_length, struct _cbor_unicode_status *status)
Definition: unicode.c:43
void cbor_mark_uint(cbor_item_t *item)
Marks the integer item as a positive integer.
Definition: ints.c:85
struct _cbor_stack * stack
void cbor_set_float8(cbor_item_t *item, double value)
Assigns a float value.
Definition: floats_ctrls.c:78
bool cbor_map_is_definite(const cbor_item_t *item)
Is this map definite?
Definition: maps.c:126
cbor_item_t * cbor_move(cbor_item_t *item)
Provides CPP-like move construct.
Definition: common.c:184
cbor_item_t * cbor_new_null()
Constructs new null ctrl item.
Definition: floats_ctrls.c:146
void cbor_builder_negint32_callback(void *context, uint32_t value)
struct _cbor_string_metadata string_metadata
Definition: data.h:141
void cbor_builder_negint64_callback(void *context, uint64_t value)
cbor_item_t * cbor_new_float2()
Constructs a new float item.
Definition: floats_ctrls.c:110
bool _cbor_map_add_value(cbor_item_t *item, cbor_item_t *value)
Add a value to the map.
Definition: maps.c:106
void cbor_tag_set_item(cbor_item_t *item, cbor_item_t *tagged_item)
Set the tagged item.
Definition: tags.c:34
void cbor_builder_float8_callback(void *context, double value)
void cbor_bytestring_set_handle(cbor_item_t *item, cbor_mutable_data CBOR_RESTRICT_POINTER data, size_t length)
Set the handle to the binary data.
Definition: bytestrings.c:72
bool cbor_string_add_chunk(cbor_item_t *item, cbor_item_t *chunk)
Appends a chunk to the string.
Definition: strings.c:82
cbor_item_t * cbor_new_definite_array(size_t size)
Create new definite array.
Definition: arrays.c:106
cbor_item_t * cbor_new_int32()
Allocates new integer with 4B width.
Definition: ints.c:121
void _cbor_builder_append(cbor_item_t *item, struct _cbor_decoder_context *ctx)
void cbor_builder_map_start_callback(void *context, size_t size)
struct _cbor_stack_record * _cbor_stack_push(struct _cbor_stack *stack, cbor_item_t *item, size_t subitems)
Definition: stack.c:23
void cbor_builder_boolean_callback(void *context, bool value)
cbor_item_t * item
Definition: stack.h:20
cbor_item_t * cbor_new_indefinite_map()
Create a new indefinite map.
Definition: maps.c:46
void cbor_builder_uint16_callback(void *context, uint16_t value)
The item handle.
Definition: data.h:149
void cbor_builder_byte_string_start_callback(void *context)
cbor_item_t * cbor_new_definite_map(size_t size)
Create a new definite map.
Definition: maps.c:23
void cbor_builder_indef_map_start_callback(void *context)
void cbor_set_uint64(cbor_item_t *item, uint64_t value)
Assigns the integer value.
Definition: ints.c:78
cbor_item_t * cbor_new_int16()
Allocates new integer with 2B width.
Definition: ints.c:109
struct _cbor_stack_record * top
Definition: stack.h:26
5 - maps
Definition: data.h:30
bool cbor_string_is_indefinite(const cbor_item_t *item)
Is the string indefinite?
Definition: strings.c:130
bool creation_failed
Callback creating the last item has failed.