xref: /openbsd/lib/libcbor/src/cbor/data.h (revision 4dcc46c4)
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
17 extern "C" {
18 #endif
19 
20 typedef const unsigned char* cbor_data;
21 typedef unsigned char* cbor_mutable_data;
22 
23 /** Specifies the Major type of ::cbor_item_t */
24 typedef 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 */
44 typedef 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 */
58 typedef 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 */
66 typedef 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 */
77 typedef enum {
78   _CBOR_METADATA_DEFINITE,
79   _CBOR_METADATA_INDEFINITE
80 } _cbor_dst_metadata;
81 
82 /** Semantic mapping for CTRL simple values */
83 typedef 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 */
97 struct _cbor_int_metadata {
98   cbor_int_width width;
99 };
100 
101 /** Bytestrings specific metadata */
102 struct _cbor_bytestring_metadata {
103   size_t length;
104   _cbor_dst_metadata type;
105 };
106 
107 /** Strings specific metadata */
108 struct _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 */
116 struct _cbor_array_metadata {
117   size_t allocated;
118   size_t end_ptr;
119   _cbor_dst_metadata type;
120 };
121 
122 /** Maps specific metadata */
123 struct _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  */
135 struct _cbor_tag_metadata {
136   struct cbor_item_t* tagged_item;
137   uint64_t value;
138 };
139 
140 /** Floats specific metadata - includes CTRL values */
141 struct _cbor_float_ctrl_metadata {
142   cbor_float_width width;
143   uint8_t ctrl;
144 };
145 
146 /** Raw memory casts helper */
147 union _cbor_float_helper {
148   float as_float;
149   uint32_t as_uint;
150 };
151 
152 /** Raw memory casts helper */
153 union _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  */
160 union 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 */
171 typedef 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  */
186 struct 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 */
193 struct 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 */
201 struct cbor_pair {
202   cbor_item_t *key, *value;
203 };
204 
205 /** High-level decoding result */
206 struct 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 */
214 enum 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 */
230 struct 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