File: cbor.h

package info (click to toggle)
aws-crt-python 0.24.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 75,932 kB
  • sloc: ansic: 418,984; python: 23,626; makefile: 6,035; sh: 4,075; ruby: 208; java: 82; perl: 73; cpp: 25; xml: 11
file content (449 lines) | stat: -rw-r--r-- 16,840 bytes parent folder | download
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
#ifndef AWS_COMMON_CBOR_H
#define AWS_COMMON_CBOR_H

/**
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0.
 */

#include <aws/common/byte_buf.h>
#include <aws/common/common.h>

AWS_PUSH_SANE_WARNING_LEVEL
AWS_EXTERN_C_BEGIN

/**
 * The types use by APIs, not 1:1 with major type.
 * It's an extension for cbor major type in RFC8949 section 3.1
 * Major type 0 - AWS_CBOR_TYPE_UINT
 * Major type 1 - AWS_CBOR_TYPE_NEGINT
 * Major type 2 - AWS_CBOR_TYPE_BYTES/AWS_CBOR_TYPE_INDEF_BYTES_START
 * Major type 3 - AWS_CBOR_TYPE_TEXT/AWS_CBOR_TYPE_INDEF_TEXT_START
 * Major type 4 - AWS_CBOR_TYPE_ARRAY_START/AWS_CBOR_TYPE_INDEF_ARRAY_START
 * Major type 5 - AWS_CBOR_TYPE_MAP_START/AWS_CBOR_TYPE_INDEF_MAP_START
 * Major type 6 - AWS_CBOR_TYPE_TAG
 * Major type 7
 *  - 20/21 - AWS_CBOR_TYPE_BOOL
 *  - 22 - AWS_CBOR_TYPE_NULL
 *  - 23 - AWS_CBOR_TYPE_UNDEFINED
 *  - 25/26/27 - AWS_CBOR_TYPE_FLOAT
 *  - 31 - AWS_CBOR_TYPE_BREAK
 *  - rest of value are not supported.
 */
enum aws_cbor_type {
    AWS_CBOR_TYPE_UNKNOWN = 0,

    AWS_CBOR_TYPE_UINT,
    AWS_CBOR_TYPE_NEGINT,
    AWS_CBOR_TYPE_FLOAT,
    AWS_CBOR_TYPE_BYTES,
    AWS_CBOR_TYPE_TEXT,

    AWS_CBOR_TYPE_ARRAY_START,
    AWS_CBOR_TYPE_MAP_START,

    AWS_CBOR_TYPE_TAG,

    AWS_CBOR_TYPE_BOOL,
    AWS_CBOR_TYPE_NULL,
    AWS_CBOR_TYPE_UNDEFINED,
    AWS_CBOR_TYPE_BREAK,

    AWS_CBOR_TYPE_INDEF_BYTES_START,
    AWS_CBOR_TYPE_INDEF_TEXT_START,
    AWS_CBOR_TYPE_INDEF_ARRAY_START,
    AWS_CBOR_TYPE_INDEF_MAP_START,
};

/**
 * The common tags, refer to RFC8949 section 3.4
 * Expected value type followed by the tag:
 * AWS_CBOR_TAG_STANDARD_TIME - AWS_CBOR_TYPE_TEXT
 * AWS_CBOR_TAG_EPOCH_TIME - AWS_CBOR_TYPE_UINT/AWS_CBOR_TYPE_NEGINT/AWS_CBOR_TYPE_FLOAT
 * AWS_CBOR_TAG_UNSIGNED_BIGNUM - AWS_CBOR_TYPE_BYTES
 * AWS_CBOR_TAG_NEGATIVE_BIGNUM - AWS_CBOR_TYPE_BYTES
 * AWS_CBOR_TAG_DECIMAL_FRACTION - AWS_CBOR_TYPE_ARRAY_START/AWS_CBOR_TYPE_INDEF_ARRAY_START
 **/
#define AWS_CBOR_TAG_STANDARD_TIME 0
#define AWS_CBOR_TAG_EPOCH_TIME 1
#define AWS_CBOR_TAG_UNSIGNED_BIGNUM 2
#define AWS_CBOR_TAG_NEGATIVE_BIGNUM 3
#define AWS_CBOR_TAG_DECIMAL_FRACTION 4

struct aws_cbor_encoder;
struct aws_cbor_decoder;

/*******************************************************************************
 * ENCODE
 ******************************************************************************/

/* Return c-string for aws_cbor_type */
AWS_COMMON_API
const char *aws_cbor_type_cstr(enum aws_cbor_type type);

/**
 * @brief Create a new cbor encoder. Creating a encoder with a temporay buffer.
 * Every aws_cbor_encoder_write_* will encode directly into the buffer to follow the encoded data.
 *
 * @param allocator
 * @return aws_cbor_encoder
 */
AWS_COMMON_API
struct aws_cbor_encoder *aws_cbor_encoder_new(struct aws_allocator *allocator);

AWS_COMMON_API
struct aws_cbor_encoder *aws_cbor_encoder_destroy(struct aws_cbor_encoder *encoder);

/**
 * @brief Get the current encoded data from encoder. The encoded data has the same lifetime as the encoder, and once
 * any other function call invoked for the encoder, the encoded data is no longer valid.
 *
 * @param encoder
 * @return struct aws_byte_cursor from the encoder buffer.
 */
AWS_COMMON_API
struct aws_byte_cursor aws_cbor_encoder_get_encoded_data(const struct aws_cbor_encoder *encoder);

/**
 * @brief Clear the current encoded buffer from encoder.
 *
 * @param encoder
 */
AWS_COMMON_API
void aws_cbor_encoder_reset(struct aws_cbor_encoder *encoder);

/**
 * @brief Encode a AWS_CBOR_TYPE_UINT value to "smallest possible" in encoder's buffer.
 *  Referring to RFC8949 section 4.2.1
 *
 * TODO: maybe add a width of the encoded value.
 *
 * @param encoder
 * @param value value to encode.
 */
AWS_COMMON_API
void aws_cbor_encoder_write_uint(struct aws_cbor_encoder *encoder, uint64_t value);

/**
 * @brief Encode a AWS_CBOR_TYPE_NEGINT value to "smallest possible" in encoder's buffer.
 * It represents (-1 - value).
 *  Referring to RFC8949 section 4.2.1
 *
 *
 * @param encoder
 * @param value The argument to encode to negative integer, which is (-1 - expected_val)
 */
AWS_COMMON_API
void aws_cbor_encoder_write_negint(struct aws_cbor_encoder *encoder, uint64_t value);

/**
 * @brief Encode a AWS_CBOR_TYPE_FLOAT value to "smallest possible", but will not be encoded into half-precision float,
 * as it's not well supported cross languages.
 *
 * To be more specific, it will be encoded into integer/negative/float
 * (Order with priority) when the conversation will not cause precision loss.
 *
 * @param encoder
 * @param value value to encode.
 */
AWS_COMMON_API
void aws_cbor_encoder_write_float(struct aws_cbor_encoder *encoder, double value);

/**
 * @brief Encode a AWS_CBOR_TYPE_BYTES value to "smallest possible" in encoder's buffer.
 *  Referring to RFC8949 section 4.2.1, the length of "from" will be encoded first and then the value of "from" will
 * be followed.
 *
 * @param encoder
 * @param from value to encode.
 */
AWS_COMMON_API
void aws_cbor_encoder_write_bytes(struct aws_cbor_encoder *encoder, struct aws_byte_cursor from);

/**
 * @brief Encode a AWS_CBOR_TYPE_TEXT value to "smallest possible" in encoder's buffer.
 *  Referring to RFC8949 section 4.2.1, the length of "from" will be encoded first and then the value of "from" will
 * be followed.
 *
 * @param encoder
 * @param from value to encode.
 */
AWS_COMMON_API
void aws_cbor_encoder_write_text(struct aws_cbor_encoder *encoder, struct aws_byte_cursor from);

/**
 * @brief Encode a AWS_CBOR_TYPE_ARRAY_START value to "smallest possible" in encoder's buffer.
 *  Referring to RFC8949 section 4.2.1
 *  The "number_entries" is the cbor data items should be followed as the content of the array.
 * Notes: it's user's responsibility to keep the integrity of the array to be encoded.
 *
 * @param encoder
 * @param number_entries The number of data item in array.
 */
AWS_COMMON_API
void aws_cbor_encoder_write_array_start(struct aws_cbor_encoder *encoder, size_t number_entries);

/**
 * @brief Encode a AWS_CBOR_TYPE_MAP_START value to "smallest possible" in encoder's buffer.
 *  Referring to RFC8949 section 4.2.1
 *  The "number_entries" is the number of pair of cbor data items as key and value should be followed as the content of
 * the map.
 *
 * Notes: it's user's responsibility to keep the integrity of the map to be encoded.
 *
 * @param encoder
 * @param number_entries The number of data item in map.
 */
AWS_COMMON_API
void aws_cbor_encoder_write_map_start(struct aws_cbor_encoder *encoder, size_t number_entries);

/**
 * @brief Encode a AWS_CBOR_TYPE_TAG value to "smallest possible" in encoder's buffer.
 *  Referring to RFC8949 section 4.2.1
 * The following cbor data item will be the content of the tagged value.
 * Notes: it's user's responsibility to keep the integrity of the tagged value to follow the RFC8949 section 3.4
 *
 * @param encoder
 * @param tag_number The tag value to encode.
 */
AWS_COMMON_API
void aws_cbor_encoder_write_tag(struct aws_cbor_encoder *encoder, uint64_t tag_number);

/**
 * @brief Encode a simple value AWS_CBOR_TYPE_NULL
 *
 * @param encoder
 */
AWS_COMMON_API
void aws_cbor_encoder_write_null(struct aws_cbor_encoder *encoder);

/**
 * @brief Encode a simple value AWS_CBOR_TYPE_UNDEFINED
 *
 * @param encoder
 */
AWS_COMMON_API
void aws_cbor_encoder_write_undefined(struct aws_cbor_encoder *encoder);

/**
 * @brief Encode a simple value AWS_CBOR_TYPE_BOOL
 *
 * @param encoder
 */
AWS_COMMON_API
void aws_cbor_encoder_write_bool(struct aws_cbor_encoder *encoder, bool value);

/**
 * @brief Encode a simple value AWS_CBOR_TYPE_BREAK
 *
 * Notes: no error checking, it's user's responsibility to track the break
 * to close the corresponding indef_start
 */
AWS_COMMON_API
void aws_cbor_encoder_write_break(struct aws_cbor_encoder *encoder);

/**
 * @brief Encode a AWS_CBOR_TYPE_INDEF_BYTES_START
 *
 * Notes: no error checking, it's user's responsibility to add corresponding data and the break
 * to close the indef_start
 */
AWS_COMMON_API
void aws_cbor_encoder_write_indef_bytes_start(struct aws_cbor_encoder *encoder);
/**
 * @brief Encode a AWS_CBOR_TYPE_INDEF_TEXT_START
 *
 * Notes: no error checking, it's user's responsibility to add corresponding data
 * and the break to close the indef_start
 */
AWS_COMMON_API
void aws_cbor_encoder_write_indef_text_start(struct aws_cbor_encoder *encoder);
/**
 * @brief Encode a AWS_CBOR_TYPE_INDEF_ARRAY_START
 *
 * Notes: no error checking, it's user's responsibility to add corresponding data
 * and the break to close the indef_start
 */
AWS_COMMON_API
void aws_cbor_encoder_write_indef_array_start(struct aws_cbor_encoder *encoder);
/**
 * @brief Encode a AWS_CBOR_TYPE_INDEF_MAP_START
 *
 * Notes: no error checking, it's user's responsibility to add corresponding data
 * and the break to close the indef_start
 */
AWS_COMMON_API
void aws_cbor_encoder_write_indef_map_start(struct aws_cbor_encoder *encoder);

/*******************************************************************************
 * DECODE
 ******************************************************************************/

/**
 * @brief Create a cbor decoder to take src to decode.
 * The typical usage of decoder will be:
 * - If the next element type only accept what expected, `aws_cbor_decoder_pop_next_*`
 * - If the next element type accept different type, invoke `aws_cbor_decoder_peek_type` first, then based on the type
 * to invoke corresponding `aws_cbor_decoder_pop_next_*`
 * - If the next element type doesn't have corrsponding value, specifically: AWS_CBOR_TYPE_NULL,
 * AWS_CBOR_TYPE_UNDEFINED, AWS_CBOR_TYPE_INF_*_START, AWS_CBOR_TYPE_BREAK, call
 * `aws_cbor_decoder_consume_next_single_element` to consume it and continues for further decoding.
 * - To ignore the next data item (the element and the content of it), `aws_cbor_decoder_consume_next_whole_data_item`
 *
 * Note: it's caller's responsibilty to keep the src outlive the decoder.
 *
 * @param allocator
 * @param src   The src data to decode from.
 * @return decoder
 */
AWS_COMMON_API
struct aws_cbor_decoder *aws_cbor_decoder_new(struct aws_allocator *allocator, struct aws_byte_cursor src);

AWS_COMMON_API
struct aws_cbor_decoder *aws_cbor_decoder_destroy(struct aws_cbor_decoder *decoder);

/**
 * @brief  Get the length of the remaining bytes of the source. Once the source was decoded, it will be consumed,
 * and result in decrease of the remaining length of bytes.
 *
 * @param decoder
 * @return The length of bytes remaining of the decoder source.
 */
AWS_COMMON_API
size_t aws_cbor_decoder_get_remaining_length(const struct aws_cbor_decoder *decoder);

/**
 * @brief Decode the next element and store it in the decoder cache if there was no element cached.
 * If there was element cached, just return the type of the cached element.
 *
 * @param decoder
 * @param out_type
 * @return AWS_OP_SUCCESS if succeed, AWS_OP_ERR for any decoding error and corresponding error code will be raised.
 */
AWS_COMMON_API
int aws_cbor_decoder_peek_type(struct aws_cbor_decoder *decoder, enum aws_cbor_type *out_type);

/**
 * @brief Consume the next data item, includes all the content within the data item.
 *
 * As an example for the following cbor, this function will consume all the data
 * as it's only one cbor data item, an indefinite map with 2 <key, value> pair:
 * 0xbf6346756ef563416d7421ff
 * BF           -- Start indefinite-length map
 *   63        -- First key, UTF-8 string length 3
 *      46756e --   "Fun"
 *   F5        -- First value, true
 *   63        -- Second key, UTF-8 string length 3
 *      416d74 --   "Amt"
 *   21        -- Second value, -2
 *   FF        -- "break"
 *
 * Notes: this function will not ensure the data item is well-formed.
 *
 * @param src The src to parse data from
 * @return AWS_OP_SUCCESS successfully consumed the next data item, otherwise AWS_OP_ERR.
 */
AWS_COMMON_API
int aws_cbor_decoder_consume_next_whole_data_item(struct aws_cbor_decoder *decoder);

/**
 * @brief Consume the next single element, without the content followed by the element.
 *
 * As an example for the following cbor, this function will only consume the
 * 0xBF, "Start indefinite-length map", not any content of the map represented.
 * The next element to decode will start from 0x63
 * 0xbf6346756ef563416d7421ff
 * BF           -- Start indefinite-length map
 *   63        -- First key, UTF-8 string length 3
 *      46756e --   "Fun"
 *   F5        -- First value, true
 *   63        -- Second key, UTF-8 string length 3
 *      416d74 --   "Amt"
 *   21        -- Second value, -2
 *   FF        -- "break"
 *
 * @param decoder The decoder to parse data from
 * @return AWS_OP_SUCCESS successfully consumed the next element, otherwise AWS_OP_ERR.
 */
AWS_COMMON_API
int aws_cbor_decoder_consume_next_single_element(struct aws_cbor_decoder *decoder);

/**
 * @brief Get the next element based on the type. If the next element doesn't match the expected type. Error will be
 * raised. If the next element already been cached, it will consume the cached item when no error was returned.
 * Specifically:
 *  AWS_CBOR_TYPE_UINT - aws_cbor_decoder_pop_next_unsigned_int_val
 *  AWS_CBOR_TYPE_NEGINT - aws_cbor_decoder_pop_next_negative_int_val, it represents (-1 - *out)
 *  AWS_CBOR_TYPE_FLOAT - aws_cbor_decoder_pop_next_float_val
 *  AWS_CBOR_TYPE_BYTES - aws_cbor_decoder_pop_next_bytes_val
 *  AWS_CBOR_TYPE_TEXT - aws_cbor_decoder_pop_next_text_val
 *
 * @param decoder
 * @param out
 * @return AWS_OP_SUCCESS successfully consumed the next element and get the result, otherwise AWS_OP_ERR.
 */
AWS_COMMON_API
int aws_cbor_decoder_pop_next_unsigned_int_val(struct aws_cbor_decoder *decoder, uint64_t *out);
AWS_COMMON_API
int aws_cbor_decoder_pop_next_negative_int_val(struct aws_cbor_decoder *decoder, uint64_t *out);
AWS_COMMON_API
int aws_cbor_decoder_pop_next_float_val(struct aws_cbor_decoder *decoder, double *out);
AWS_COMMON_API
int aws_cbor_decoder_pop_next_boolean_val(struct aws_cbor_decoder *decoder, bool *out);
AWS_COMMON_API
int aws_cbor_decoder_pop_next_bytes_val(struct aws_cbor_decoder *decoder, struct aws_byte_cursor *out);
AWS_COMMON_API
int aws_cbor_decoder_pop_next_text_val(struct aws_cbor_decoder *decoder, struct aws_byte_cursor *out);

/**
 * @brief Get the next AWS_CBOR_TYPE_ARRAY_START element. Only consume the AWS_CBOR_TYPE_ARRAY_START element and set the
 * size of array to *out_size, not the content of the array. The next *out_size cbor data items will be the content of
 * the array for a valid cbor data,
 *
 * Notes: For indefinite-length, this function will fail with "AWS_ERROR_CBOR_UNEXPECTED_TYPE". The designed way to
 * handle indefinite-length is:
 * - Get AWS_CBOR_TYPE_INDEF_ARRAY_START from _peek_type
 * - call `aws_cbor_decoder_consume_next_single_element` to pop the indefinite-length start.
 * - Decode the next data item until AWS_CBOR_TYPE_BREAK read.
 *
 * @param decoder
 * @param out_size store the size of array if succeed.
 * @return AWS_OP_SUCCESS successfully consumed the next element and get the result, otherwise AWS_OP_ERR.
 */
AWS_COMMON_API
int aws_cbor_decoder_pop_next_array_start(struct aws_cbor_decoder *decoder, uint64_t *out_size);

/**
 * @brief Get the next AWS_CBOR_TYPE_MAP_START element. Only consume the AWS_CBOR_TYPE_MAP_START element and set the
 * size of array to *out_size, not the content of the map. The next *out_size pair of cbor data items as key and value
 * will be the content of the array for a valid cbor data,
 *
 * Notes: For indefinite-length, this function will fail with "AWS_ERROR_CBOR_UNEXPECTED_TYPE". The designed way to
 * handle indefinite-length is:
 * - Get AWS_CBOR_TYPE_INDEF_MAP_START from _peek_type
 * - call `aws_cbor_decoder_consume_next_single_element` to pop the indefinite-length start.
 * - Decode the next data item until AWS_CBOR_TYPE_BREAK read.
 *
 * @param decoder
 * @param out_size store the size of map if succeed.
 * @return AWS_OP_SUCCESS successfully consumed the next element and get the result, otherwise AWS_OP_ERR.
 */
AWS_COMMON_API
int aws_cbor_decoder_pop_next_map_start(struct aws_cbor_decoder *decoder, uint64_t *out_size);

/**
 * @brief Get the next AWS_CBOR_TYPE_TAG element. Only consume the AWS_CBOR_TYPE_TAG element and set the
 * tag value to *out_tag_val, not the content of the tagged. The next cbor data item will be the content of the tagged
 * value for a valid cbor data.
 *
 * @param decoder
 * @param out_size store the size of map if succeed.
 * @return AWS_OP_SUCCESS successfully consumed the next element and get the result, otherwise AWS_OP_ERR.
 */
AWS_COMMON_API
int aws_cbor_decoder_pop_next_tag_val(struct aws_cbor_decoder *decoder, uint64_t *out_tag_val);

AWS_EXTERN_C_END
AWS_POP_SANE_WARNING_LEVEL

#endif // AWS_COMMON_CBOR_H