blob: 2526b92041500bbf813d37ef2964ea8525b588a5 [file] [log] [blame]
Carsten Bormann64e2b522015-02-17 18:52:34 +01001#ifndef CN_CBOR_C
2#define CN_CBOR_C
3
4#ifdef __cplusplus
5extern "C" {
6#endif
7#ifdef EMACS_INDENTATION_HELPER
8} /* Duh. */
9#endif
10
11#include <stdlib.h>
12#include <stdint.h>
13#include <string.h>
14#include <assert.h>
15#include <math.h>
Joe Hildebrand60a86fe2015-04-02 11:08:09 -060016#include <arpa/inet.h> // needed for ntohl (e.g.) on Linux
Carsten Bormann64e2b522015-02-17 18:52:34 +010017
Joe Hildebrand7c6c3562015-03-31 00:21:21 -060018#include "cn-cbor/cn-cbor.h"
Joe Hildebrandef8d2772015-03-03 07:00:20 +010019#include "cbor.h"
Carsten Bormann64e2b522015-02-17 18:52:34 +010020
Carsten Bormann64e2b522015-02-17 18:52:34 +010021#define CN_CBOR_FAIL(code) do { pb->err = code; goto fail; } while(0)
22
Joe Hildebrand45e9ad92015-08-26 10:37:02 -060023void cn_cbor_free(cn_cbor* cb CBOR_CONTEXT) {
24 cn_cbor* p = cb;
25 assert(!p || !p->parent);
Carsten Bormann64e2b522015-02-17 18:52:34 +010026 while (p) {
27 cn_cbor* p1;
28 while ((p1 = p->first_child)) { /* go down */
29 p = p1;
30 }
31 if (!(p1 = p->next)) { /* go up next */
32 if ((p1 = p->parent))
33 p1->first_child = 0;
34 }
Joe Hildebrandbeee57d2015-03-30 23:06:46 -060035 CN_CBOR_FREE_CONTEXT(p);
Carsten Bormann64e2b522015-02-17 18:52:34 +010036 p = p1;
37 }
38}
39
Olaf Bergmann33034132015-04-24 17:12:40 +020040#ifndef CBOR_NO_FLOAT
Carsten Bormann64e2b522015-02-17 18:52:34 +010041static double decode_half(int half) {
42 int exp = (half >> 10) & 0x1f;
43 int mant = half & 0x3ff;
44 double val;
45 if (exp == 0) val = ldexp(mant, -24);
46 else if (exp != 31) val = ldexp(mant + 1024, exp - 25);
47 else val = mant == 0 ? INFINITY : NAN;
48 return half & 0x8000 ? -val : val;
49}
Olaf Bergmann33034132015-04-24 17:12:40 +020050#endif /* CBOR_NO_FLOAT */
Carsten Bormann64e2b522015-02-17 18:52:34 +010051
Carsten Bormann64e2b522015-02-17 18:52:34 +010052#define ntoh8p(p) (*(unsigned char*)(p))
Kaspar Schleiser6afc2222018-03-23 22:10:41 +010053
Kaspar Schleiserd458c342018-03-23 22:14:36 +010054#ifndef CBOR_ALIGN_READS
Carsten Bormann64e2b522015-02-17 18:52:34 +010055#define ntoh16p(p) (ntohs(*(unsigned short*)(p)))
Max Bires68f26ba2019-03-27 02:15:24 -070056#define ntoh32p(p) (ntohl(*(uint32_t*)(p)))
Kaspar Schleiser6afc2222018-03-23 22:10:41 +010057#else
Kaspar Schleiser894e0b42018-03-16 15:33:00 +010058static uint16_t ntoh16p(unsigned char *p) {
59 uint16_t tmp;
60 memcpy(&tmp, p, sizeof(tmp));
61 return ntohs(tmp);
62}
63
64static uint32_t ntoh32p(unsigned char *p) {
65 uint32_t tmp;
66 memcpy(&tmp, p, sizeof(tmp));
67 return ntohl(tmp);
68}
Kaspar Schleiserd458c342018-03-23 22:14:36 +010069#endif /* CBOR_ALIGN_READS */
Kaspar Schleiser894e0b42018-03-16 15:33:00 +010070
Carsten Bormann64e2b522015-02-17 18:52:34 +010071static uint64_t ntoh64p(unsigned char *p) {
72 uint64_t ret = ntoh32p(p);
73 ret <<= 32;
74 ret += ntoh32p(p+4);
75 return ret;
76}
77
78static cn_cbor_type mt_trans[] = {
79 CN_CBOR_UINT, CN_CBOR_INT,
80 CN_CBOR_BYTES, CN_CBOR_TEXT,
81 CN_CBOR_ARRAY, CN_CBOR_MAP,
82 CN_CBOR_TAG, CN_CBOR_SIMPLE,
83};
84
85struct parse_buf {
86 unsigned char *buf;
87 unsigned char *ebuf;
88 cn_cbor_error err;
89};
90
91#define TAKE(pos, ebuf, n, stmt) \
Carsten Bormann85d764d2015-03-02 10:47:13 +010092 if (n > (size_t)(ebuf - pos)) \
Joe Hildebrandd9efcab2015-03-02 09:25:05 +010093 CN_CBOR_FAIL(CN_CBOR_ERR_OUT_OF_DATA); \
Carsten Bormann64e2b522015-02-17 18:52:34 +010094 stmt; \
95 pos += n;
96
Joe Hildebrandbeee57d2015-03-30 23:06:46 -060097static cn_cbor *decode_item (struct parse_buf *pb CBOR_CONTEXT, cn_cbor* top_parent) {
Carsten Bormann64e2b522015-02-17 18:52:34 +010098 unsigned char *pos = pb->buf;
99 unsigned char *ebuf = pb->ebuf;
100 cn_cbor* parent = top_parent;
Joe Hildebrand03067892015-03-03 06:56:45 +0100101 int ib;
102 unsigned int mt;
103 int ai;
104 uint64_t val;
Joe Hildebrandbeee57d2015-03-30 23:06:46 -0600105 cn_cbor* cb = NULL;
Olaf Bergmann33034132015-04-24 17:12:40 +0200106#ifndef CBOR_NO_FLOAT
Joe Hildebrand03067892015-03-03 06:56:45 +0100107 union {
108 float f;
109 uint32_t u;
110 } u32;
111 union {
112 double d;
113 uint64_t u;
114 } u64;
Olaf Bergmann33034132015-04-24 17:12:40 +0200115#endif /* CBOR_NO_FLOAT */
Joe Hildebrand03067892015-03-03 06:56:45 +0100116
Carsten Bormann64e2b522015-02-17 18:52:34 +0100117again:
Joe Hildebrand03067892015-03-03 06:56:45 +0100118 TAKE(pos, ebuf, 1, ib = ntoh8p(pos) );
Carsten Bormann64e2b522015-02-17 18:52:34 +0100119 if (ib == IB_BREAK) {
120 if (!(parent->flags & CN_CBOR_FL_INDEF))
121 CN_CBOR_FAIL(CN_CBOR_ERR_BREAK_OUTSIDE_INDEF);
122 switch (parent->type) {
123 case CN_CBOR_BYTES: case CN_CBOR_TEXT:
124 parent->type += 2; /* CN_CBOR_* -> CN_CBOR_*_CHUNKED */
125 break;
126 case CN_CBOR_MAP:
127 if (parent->length & 1)
128 CN_CBOR_FAIL(CN_CBOR_ERR_ODD_SIZE_INDEF_MAP);
129 default:;
130 }
131 goto complete;
132 }
Joe Hildebrand03067892015-03-03 06:56:45 +0100133 mt = ib >> 5;
134 ai = ib & 0x1f;
135 val = ai;
Carsten Bormann64e2b522015-02-17 18:52:34 +0100136
Joe Hildebrandbeee57d2015-03-30 23:06:46 -0600137 cb = CN_CALLOC_CONTEXT();
Carsten Bormann64e2b522015-02-17 18:52:34 +0100138 if (!cb)
139 CN_CBOR_FAIL(CN_CBOR_ERR_OUT_OF_MEMORY);
140
141 cb->type = mt_trans[mt];
142
143 cb->parent = parent;
144 if (parent->last_child) {
145 parent->last_child->next = cb;
146 } else {
147 parent->first_child = cb;
148 }
149 parent->last_child = cb;
150 parent->length++;
151
Carsten Bormann64e2b522015-02-17 18:52:34 +0100152 switch (ai) {
153 case AI_1: TAKE(pos, ebuf, 1, val = ntoh8p(pos)) ; break;
154 case AI_2: TAKE(pos, ebuf, 2, val = ntoh16p(pos)) ; break;
155 case AI_4: TAKE(pos, ebuf, 4, val = ntoh32p(pos)) ; break;
156 case AI_8: TAKE(pos, ebuf, 8, val = ntoh64p(pos)) ; break;
157 case 28: case 29: case 30: CN_CBOR_FAIL(CN_CBOR_ERR_RESERVED_AI);
158 case AI_INDEF:
159 if ((mt - MT_BYTES) <= MT_MAP) {
160 cb->flags |= CN_CBOR_FL_INDEF;
161 goto push;
162 } else {
163 CN_CBOR_FAIL(CN_CBOR_ERR_MT_UNDEF_FOR_INDEF);
164 }
165 }
166 // process content
167 switch (mt) {
168 case MT_UNSIGNED:
169 cb->v.uint = val; /* to do: Overflow check */
170 break;
171 case MT_NEGATIVE:
172 cb->v.sint = ~val; /* to do: Overflow check */
173 break;
174 case MT_BYTES: case MT_TEXT:
175 cb->v.str = (char *) pos;
176 cb->length = val;
Joe Hildebrandbeee57d2015-03-30 23:06:46 -0600177 TAKE(pos, ebuf, val, ;);
Carsten Bormann64e2b522015-02-17 18:52:34 +0100178 break;
179 case MT_MAP:
180 val <<= 1;
181 /* fall through */
182 case MT_ARRAY:
183 if ((cb->v.count = val)) {
184 cb->flags |= CN_CBOR_FL_COUNT;
185 goto push;
186 }
187 break;
188 case MT_TAG:
189 cb->v.uint = val;
190 goto push;
191 case MT_PRIM:
192 switch (ai) {
Carsten Bormann64e2b522015-02-17 18:52:34 +0100193 case VAL_FALSE: cb->type = CN_CBOR_FALSE; break;
Joe Hildebranda9954012015-03-31 23:00:43 -0600194 case VAL_TRUE: cb->type = CN_CBOR_TRUE; break;
195 case VAL_NIL: cb->type = CN_CBOR_NULL; break;
196 case VAL_UNDEF: cb->type = CN_CBOR_UNDEF; break;
Olaf Bergmann33034132015-04-24 17:12:40 +0200197 case AI_2:
198#ifndef CBOR_NO_FLOAT
199 cb->type = CN_CBOR_DOUBLE;
200 cb->v.dbl = decode_half(val);
201#else /* CBOR_NO_FLOAT */
202 CN_CBOR_FAIL(CN_CBOR_ERR_FLOAT_NOT_SUPPORTED);
203#endif /* CBOR_NO_FLOAT */
204 break;
Carsten Bormann64e2b522015-02-17 18:52:34 +0100205 case AI_4:
Olaf Bergmann33034132015-04-24 17:12:40 +0200206#ifndef CBOR_NO_FLOAT
Carsten Bormann64e2b522015-02-17 18:52:34 +0100207 cb->type = CN_CBOR_DOUBLE;
Carsten Bormann64e2b522015-02-17 18:52:34 +0100208 u32.u = val;
209 cb->v.dbl = u32.f;
Olaf Bergmann33034132015-04-24 17:12:40 +0200210#else /* CBOR_NO_FLOAT */
211 CN_CBOR_FAIL(CN_CBOR_ERR_FLOAT_NOT_SUPPORTED);
212#endif /* CBOR_NO_FLOAT */
Carsten Bormann64e2b522015-02-17 18:52:34 +0100213 break;
214 case AI_8:
Olaf Bergmann33034132015-04-24 17:12:40 +0200215#ifndef CBOR_NO_FLOAT
Carsten Bormann64e2b522015-02-17 18:52:34 +0100216 cb->type = CN_CBOR_DOUBLE;
Carsten Bormann64e2b522015-02-17 18:52:34 +0100217 u64.u = val;
218 cb->v.dbl = u64.d;
Olaf Bergmann33034132015-04-24 17:12:40 +0200219#else /* CBOR_NO_FLOAT */
220 CN_CBOR_FAIL(CN_CBOR_ERR_FLOAT_NOT_SUPPORTED);
221#endif /* CBOR_NO_FLOAT */
Carsten Bormann64e2b522015-02-17 18:52:34 +0100222 break;
223 default: cb->v.uint = val;
224 }
225 }
226fill: /* emulate loops */
227 if (parent->flags & CN_CBOR_FL_INDEF) {
228 if (parent->type == CN_CBOR_BYTES || parent->type == CN_CBOR_TEXT)
229 if (cb->type != parent->type)
230 CN_CBOR_FAIL(CN_CBOR_ERR_WRONG_NESTING_IN_INDEF_STRING);
231 goto again;
232 }
233 if (parent->flags & CN_CBOR_FL_COUNT) {
234 if (--parent->v.count)
235 goto again;
236 }
237 /* so we are done filling parent. */
238complete: /* emulate return from call */
239 if (parent == top_parent) {
240 if (pos != ebuf) /* XXX do this outside */
241 CN_CBOR_FAIL(CN_CBOR_ERR_NOT_ALL_DATA_CONSUMED);
242 pb->buf = pos;
243 return cb;
244 }
245 cb = parent;
246 parent = parent->parent;
247 goto fill;
248push: /* emulate recursive call */
249 parent = cb;
250 goto again;
251fail:
252 pb->buf = pos;
253 return 0;
254}
255
Joe Hildebrand45e9ad92015-08-26 10:37:02 -0600256cn_cbor* cn_cbor_decode(const unsigned char* buf, size_t len CBOR_CONTEXT, cn_cbor_errback *errp) {
Joe Hildebrand03067892015-03-03 06:56:45 +0100257 cn_cbor catcher = {CN_CBOR_INVALID, 0, {0}, 0, NULL, NULL, NULL, NULL};
Joe Hildebrandbeee57d2015-03-30 23:06:46 -0600258 struct parse_buf pb;
259 cn_cbor* ret;
260
261 pb.buf = (unsigned char *)buf;
262 pb.ebuf = (unsigned char *)buf+len;
263 pb.err = CN_CBOR_NO_ERROR;
264 ret = decode_item(&pb CBOR_CONTEXT_PARAM, &catcher);
Joe Hildebrand03067892015-03-03 06:56:45 +0100265 if (ret != NULL) {
266 /* mark as top node */
267 ret->parent = NULL;
Carsten Bormann64e2b522015-02-17 18:52:34 +0100268 } else {
269 if (catcher.first_child) {
270 catcher.first_child->parent = 0;
Joe Hildebrandbeee57d2015-03-30 23:06:46 -0600271 cn_cbor_free(catcher.first_child CBOR_CONTEXT_PARAM);
Carsten Bormann64e2b522015-02-17 18:52:34 +0100272 }
Joe Hildebrandbeee57d2015-03-30 23:06:46 -0600273//fail:
Carsten Bormann64e2b522015-02-17 18:52:34 +0100274 if (errp) {
275 errp->err = pb.err;
276 errp->pos = pb.buf - (unsigned char *)buf;
277 }
Joe Hildebrand03067892015-03-03 06:56:45 +0100278 return NULL;
Carsten Bormann64e2b522015-02-17 18:52:34 +0100279 }
280 return ret;
281}
282
Carsten Bormann64e2b522015-02-17 18:52:34 +0100283#ifdef __cplusplus
284}
285#endif
286
287#endif /* CN_CBOR_C */