1/*
2 * Copyright (c) 2014-2020 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#ifndef LIBCBOR_DATA_H
9#define LIBCBOR_DATA_H
10
11#include <stdbool.h>
12#include <stddef.h>
13#include <stdint.h>
14#include <stdlib.h>
15
16#ifdef __cplusplus
17extern "C" {
18#endif
19
20typedef const unsigned char* cbor_data;
21typedef unsigned char* cbor_mutable_data;
22
23/** Specifies the Major type of ::cbor_item_t */
24typedef enum cbor_type {
25  CBOR_TYPE_UINT /** 0 - positive integers */
26  ,
27  CBOR_TYPE_NEGINT /** 1 - negative integers*/
28  ,
29  CBOR_TYPE_BYTESTRING /** 2 - byte strings */
30  ,
31  CBOR_TYPE_STRING /** 3 - strings */
32  ,
33  CBOR_TYPE_ARRAY /** 4 - arrays */
34  ,
35  CBOR_TYPE_MAP /** 5 - maps */
36  ,
37  CBOR_TYPE_TAG /** 6 - tags  */
38  ,
39  CBOR_TYPE_FLOAT_CTRL /** 7 - decimals and special values (true, false, nil,
40                          ...) */
41} cbor_type;
42
43/** Possible decoding errors */
44typedef enum {
45  CBOR_ERR_NONE,
46  CBOR_ERR_NOTENOUGHDATA,
47  CBOR_ERR_NODATA,
48  // TODO: Should be "malformed" or at least "malformatted". Retained for
49  // backwards compatibility.
50  CBOR_ERR_MALFORMATED,
51  CBOR_ERR_MEMERROR /** Memory error - item allocation failed. Is it too big for
52                       your allocator? */
53  ,
54  CBOR_ERR_SYNTAXERROR /** Stack parsing algorithm failed */
55} cbor_error_code;
56
57/** Possible widths of #CBOR_TYPE_UINT items */
58typedef enum {
59  CBOR_INT_8,
60  CBOR_INT_16,
61  CBOR_INT_32,
62  CBOR_INT_64
63} cbor_int_width;
64
65/** Possible widths of #CBOR_TYPE_FLOAT_CTRL items */
66typedef enum {
67  CBOR_FLOAT_0 /** Internal use - ctrl and special values */
68  ,
69  CBOR_FLOAT_16 /** Half float */
70  ,
71  CBOR_FLOAT_32 /** Single float */
72  ,
73  CBOR_FLOAT_64 /** Double */
74} cbor_float_width;
75
76/** Metadata for dynamically sized types */
77typedef enum {
78  _CBOR_METADATA_DEFINITE,
79  _CBOR_METADATA_INDEFINITE
80} _cbor_dst_metadata;
81
82/** Semantic mapping for CTRL simple values */
83typedef enum {
84  CBOR_CTRL_NONE = 0,
85  CBOR_CTRL_FALSE = 20,
86  CBOR_CTRL_TRUE = 21,
87  CBOR_CTRL_NULL = 22,
88  CBOR_CTRL_UNDEF = 23
89} _cbor_ctrl;
90
91// Metadata items use size_t (instead of uint64_t) because items in memory take
92// up at least 1B per entry or string byte, so if size_t is narrower than
93// uint64_t, we wouldn't be able to create them in the first place and can save
94// some space.
95
96/** Integers specific metadata */
97struct _cbor_int_metadata {
98  cbor_int_width width;
99};
100
101/** Bytestrings specific metadata */
102struct _cbor_bytestring_metadata {
103  size_t length;
104  _cbor_dst_metadata type;
105};
106
107/** Strings specific metadata */
108struct _cbor_string_metadata {
109  size_t length;
110  size_t codepoint_count; /* Sum of chunks' codepoint_counts for indefinite
111                             strings */
112  _cbor_dst_metadata type;
113};
114
115/** Arrays specific metadata */
116struct _cbor_array_metadata {
117  size_t allocated;
118  size_t end_ptr;
119  _cbor_dst_metadata type;
120};
121
122/** Maps specific metadata */
123struct _cbor_map_metadata {
124  size_t allocated;
125  size_t end_ptr;
126  _cbor_dst_metadata type;
127};
128
129/** Arrays specific metadata
130 *
131 * The pointer is included - cbor_item_metadata is
132 * 2 * sizeof(size_t) + sizeof(_cbor_string_type_metadata),
133 * lets use the space
134 */
135struct _cbor_tag_metadata {
136  struct cbor_item_t* tagged_item;
137  uint64_t value;
138};
139
140/** Floats specific metadata - includes CTRL values */
141struct _cbor_float_ctrl_metadata {
142  cbor_float_width width;
143  uint8_t ctrl;
144};
145
146/** Raw memory casts helper */
147union _cbor_float_helper {
148  float as_float;
149  uint32_t as_uint;
150};
151
152/** Raw memory casts helper */
153union _cbor_double_helper {
154  double as_double;
155  uint64_t as_uint;
156};
157
158/** Union of metadata across all possible types - discriminated in #cbor_item_t
159 */
160union cbor_item_metadata {
161  struct _cbor_int_metadata int_metadata;
162  struct _cbor_bytestring_metadata bytestring_metadata;
163  struct _cbor_string_metadata string_metadata;
164  struct _cbor_array_metadata array_metadata;
165  struct _cbor_map_metadata map_metadata;
166  struct _cbor_tag_metadata tag_metadata;
167  struct _cbor_float_ctrl_metadata float_ctrl_metadata;
168};
169
170/** The item handle */
171typedef struct cbor_item_t {
172  /** Discriminated by type */
173  union cbor_item_metadata metadata;
174  /** Reference count - initialize to 0 */
175  size_t refcount;
176  /** Major type discriminator */
177  cbor_type type;
178  /** Raw data block - interpretation depends on metadata */
179  unsigned char* data;
180} cbor_item_t;
181
182/** Defines cbor_item_t#data structure for indefinite strings and bytestrings
183 *
184 * Used to cast the raw representation for a sane manipulation
185 */
186struct cbor_indefinite_string_data {
187  size_t chunk_count;
188  size_t chunk_capacity;
189  cbor_item_t** chunks;
190};
191
192/** High-level decoding error */
193struct cbor_error {
194  /** Approximate position */
195  size_t position;
196  /** Description */
197  cbor_error_code code;
198};
199
200/** Simple pair of items for use in maps */
201struct cbor_pair {
202  cbor_item_t *key, *value;
203};
204
205/** High-level decoding result */
206struct cbor_load_result {
207  /** Error indicator */
208  struct cbor_error error;
209  /** Number of bytes read */
210  size_t read;
211};
212
213/** Streaming decoder result - status */
214enum cbor_decoder_status {
215  /** Decoding finished successfully (a callback has been invoked)
216   *
217   * Note that this does *not* mean that the buffer has been fully decoded;
218   * there may still be unread bytes for which no callback has been involved.
219   */
220  CBOR_DECODER_FINISHED,
221  /** Not enough data to invoke a callback */
222  // TODO: The name is inconsistent with CBOR_ERR_NOTENOUGHDATA. Retained for
223  // backwards compatibility.
224  CBOR_DECODER_NEDATA,
225  /** Bad data (reserved MTB, malformed value, etc.)  */
226  CBOR_DECODER_ERROR
227};
228
229/** Streaming decoder result */
230struct cbor_decoder_result {
231  /** Input bytes read/consumed
232   *
233   * If this is less than the size of input buffer, the client will likely
234   * resume parsing starting at the next byte (e.g. `buffer + result.read`).
235   *
236   * Set to 0 if the #status is not #CBOR_DECODER_FINISHED.
237   */
238  size_t read;
239
240  /** The decoding status */
241  enum cbor_decoder_status status;
242
243  /** Number of bytes in the input buffer needed to resume parsing
244   *
245   * Set to 0 unless the result status is #CBOR_DECODER_NEDATA. If it is, then:
246   *  - If at least one byte was passed, #required will be set to the minimum
247   *    number of bytes needed to invoke a decoded callback on the current
248   *    prefix.
249   *
250   *    For example: Attempting to decode a 1B buffer containing `0x19` will
251   *    set #required to 3 as `0x19` signals a 2B integer item, so we need at
252   *    least 3B to continue (the `0x19` MTB byte and two bytes of data needed
253   *    to invoke #cbor_callbacks.uint16).
254   *
255   *  - If there was no data at all, #read will always be set to 1
256   */
257  size_t required;
258};
259
260#ifdef __cplusplus
261}
262#endif
263
264#endif  // LIBCBOR_DATA_H
265