1 #ifndef CN_CBOR_C
2 #define CN_CBOR_C
3
4 #ifdef __cplusplus
5 extern "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>
16 #include <arpa/inet.h> // needed for ntohl (e.g.) on Linux
17
18 #include "cn-cbor/cn-cbor.h"
19 #include "cbor.h"
20
21 #define CN_CBOR_FAIL(code) do { pb->err = code; goto fail; } while(0)
22
cn_cbor_free(cn_cbor * cb CBOR_CONTEXT)23 void cn_cbor_free(cn_cbor* cb CBOR_CONTEXT) {
24 cn_cbor* p = cb;
25 assert(!p || !p->parent);
26 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 }
35 CN_CBOR_FREE_CONTEXT(p);
36 p = p1;
37 }
38 }
39
40 #ifndef CBOR_NO_FLOAT
decode_half(int half)41 static 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 }
50 #endif /* CBOR_NO_FLOAT */
51
52 /* Fix these if you can't do non-aligned reads */
53 #define ntoh8p(p) (*(unsigned char*)(p))
54 #define ntoh16p(p) (ntohs(*(unsigned short*)(p)))
55 #define ntoh32p(p) (ntohl(*(uint32_t*)(p)))
ntoh64p(unsigned char * p)56 static uint64_t ntoh64p(unsigned char *p) {
57 uint64_t ret = ntoh32p(p);
58 ret <<= 32;
59 ret += ntoh32p(p+4);
60 return ret;
61 }
62
63 static cn_cbor_type mt_trans[] = {
64 CN_CBOR_UINT, CN_CBOR_INT,
65 CN_CBOR_BYTES, CN_CBOR_TEXT,
66 CN_CBOR_ARRAY, CN_CBOR_MAP,
67 CN_CBOR_TAG, CN_CBOR_SIMPLE,
68 };
69
70 struct parse_buf {
71 unsigned char *buf;
72 unsigned char *ebuf;
73 cn_cbor_error err;
74 };
75
76 #define TAKE(pos, ebuf, n, stmt) \
77 if (n > (size_t)(ebuf - pos)) \
78 CN_CBOR_FAIL(CN_CBOR_ERR_OUT_OF_DATA); \
79 stmt; \
80 pos += n;
81
decode_item(struct parse_buf * pb CBOR_CONTEXT,cn_cbor * top_parent)82 static cn_cbor *decode_item (struct parse_buf *pb CBOR_CONTEXT, cn_cbor* top_parent) {
83 unsigned char *pos = pb->buf;
84 unsigned char *ebuf = pb->ebuf;
85 cn_cbor* parent = top_parent;
86 int ib;
87 unsigned int mt;
88 int ai;
89 uint64_t val;
90 cn_cbor* cb = NULL;
91 #ifndef CBOR_NO_FLOAT
92 union {
93 float f;
94 uint32_t u;
95 } u32;
96 union {
97 double d;
98 uint64_t u;
99 } u64;
100 #endif /* CBOR_NO_FLOAT */
101
102 again:
103 TAKE(pos, ebuf, 1, ib = ntoh8p(pos) );
104 if (ib == IB_BREAK) {
105 if (!(parent->flags & CN_CBOR_FL_INDEF))
106 CN_CBOR_FAIL(CN_CBOR_ERR_BREAK_OUTSIDE_INDEF);
107 switch (parent->type) {
108 case CN_CBOR_BYTES: case CN_CBOR_TEXT:
109 parent->type += 2; /* CN_CBOR_* -> CN_CBOR_*_CHUNKED */
110 break;
111 case CN_CBOR_MAP:
112 if (parent->length & 1)
113 CN_CBOR_FAIL(CN_CBOR_ERR_ODD_SIZE_INDEF_MAP);
114 default:;
115 }
116 goto complete;
117 }
118 mt = ib >> 5;
119 ai = ib & 0x1f;
120 val = ai;
121
122 cb = CN_CALLOC_CONTEXT();
123 if (!cb)
124 CN_CBOR_FAIL(CN_CBOR_ERR_OUT_OF_MEMORY);
125
126 cb->type = mt_trans[mt];
127
128 cb->parent = parent;
129 if (parent->last_child) {
130 parent->last_child->next = cb;
131 } else {
132 parent->first_child = cb;
133 }
134 parent->last_child = cb;
135 parent->length++;
136
137 switch (ai) {
138 case AI_1: TAKE(pos, ebuf, 1, val = ntoh8p(pos)) ; break;
139 case AI_2: TAKE(pos, ebuf, 2, val = ntoh16p(pos)) ; break;
140 case AI_4: TAKE(pos, ebuf, 4, val = ntoh32p(pos)) ; break;
141 case AI_8: TAKE(pos, ebuf, 8, val = ntoh64p(pos)) ; break;
142 case 28: case 29: case 30: CN_CBOR_FAIL(CN_CBOR_ERR_RESERVED_AI);
143 case AI_INDEF:
144 if ((mt - MT_BYTES) <= MT_MAP) {
145 cb->flags |= CN_CBOR_FL_INDEF;
146 goto push;
147 } else {
148 CN_CBOR_FAIL(CN_CBOR_ERR_MT_UNDEF_FOR_INDEF);
149 }
150 }
151 // process content
152 switch (mt) {
153 case MT_UNSIGNED:
154 cb->v.uint = val; /* to do: Overflow check */
155 break;
156 case MT_NEGATIVE:
157 cb->v.sint = ~val; /* to do: Overflow check */
158 break;
159 case MT_BYTES: case MT_TEXT:
160 cb->v.str = (char *) pos;
161 cb->length = val;
162 TAKE(pos, ebuf, val, ;);
163 break;
164 case MT_MAP:
165 val <<= 1;
166 /* fall through */
167 case MT_ARRAY:
168 if ((cb->v.count = val)) {
169 cb->flags |= CN_CBOR_FL_COUNT;
170 goto push;
171 }
172 break;
173 case MT_TAG:
174 cb->v.uint = val;
175 goto push;
176 case MT_PRIM:
177 switch (ai) {
178 case VAL_FALSE: cb->type = CN_CBOR_FALSE; break;
179 case VAL_TRUE: cb->type = CN_CBOR_TRUE; break;
180 case VAL_NIL: cb->type = CN_CBOR_NULL; break;
181 case VAL_UNDEF: cb->type = CN_CBOR_UNDEF; break;
182 case AI_2:
183 #ifndef CBOR_NO_FLOAT
184 cb->type = CN_CBOR_DOUBLE;
185 cb->v.dbl = decode_half(val);
186 #else /* CBOR_NO_FLOAT */
187 CN_CBOR_FAIL(CN_CBOR_ERR_FLOAT_NOT_SUPPORTED);
188 #endif /* CBOR_NO_FLOAT */
189 break;
190 case AI_4:
191 #ifndef CBOR_NO_FLOAT
192 cb->type = CN_CBOR_DOUBLE;
193 u32.u = val;
194 cb->v.dbl = u32.f;
195 #else /* CBOR_NO_FLOAT */
196 CN_CBOR_FAIL(CN_CBOR_ERR_FLOAT_NOT_SUPPORTED);
197 #endif /* CBOR_NO_FLOAT */
198 break;
199 case AI_8:
200 #ifndef CBOR_NO_FLOAT
201 cb->type = CN_CBOR_DOUBLE;
202 u64.u = val;
203 cb->v.dbl = u64.d;
204 #else /* CBOR_NO_FLOAT */
205 CN_CBOR_FAIL(CN_CBOR_ERR_FLOAT_NOT_SUPPORTED);
206 #endif /* CBOR_NO_FLOAT */
207 break;
208 default: cb->v.uint = val;
209 }
210 }
211 fill: /* emulate loops */
212 if (parent->flags & CN_CBOR_FL_INDEF) {
213 if (parent->type == CN_CBOR_BYTES || parent->type == CN_CBOR_TEXT)
214 if (cb->type != parent->type)
215 CN_CBOR_FAIL(CN_CBOR_ERR_WRONG_NESTING_IN_INDEF_STRING);
216 goto again;
217 }
218 if (parent->flags & CN_CBOR_FL_COUNT) {
219 if (--parent->v.count)
220 goto again;
221 }
222 /* so we are done filling parent. */
223 complete: /* emulate return from call */
224 if (parent == top_parent) {
225 if (pos != ebuf) /* XXX do this outside */
226 CN_CBOR_FAIL(CN_CBOR_ERR_NOT_ALL_DATA_CONSUMED);
227 pb->buf = pos;
228 return cb;
229 }
230 cb = parent;
231 parent = parent->parent;
232 goto fill;
233 push: /* emulate recursive call */
234 parent = cb;
235 goto again;
236 fail:
237 pb->buf = pos;
238 return 0;
239 }
240
cn_cbor_decode(const unsigned char * buf,size_t len CBOR_CONTEXT,cn_cbor_errback * errp)241 cn_cbor* cn_cbor_decode(const unsigned char* buf, size_t len CBOR_CONTEXT, cn_cbor_errback *errp) {
242 cn_cbor catcher = {CN_CBOR_INVALID, 0, {0}, 0, NULL, NULL, NULL, NULL};
243 struct parse_buf pb;
244 cn_cbor* ret;
245
246 pb.buf = (unsigned char *)buf;
247 pb.ebuf = (unsigned char *)buf+len;
248 pb.err = CN_CBOR_NO_ERROR;
249 ret = decode_item(&pb CBOR_CONTEXT_PARAM, &catcher);
250 if (ret != NULL) {
251 /* mark as top node */
252 ret->parent = NULL;
253 } else {
254 if (catcher.first_child) {
255 catcher.first_child->parent = 0;
256 cn_cbor_free(catcher.first_child CBOR_CONTEXT_PARAM);
257 }
258 //fail:
259 if (errp) {
260 errp->err = pb.err;
261 errp->pos = pb.buf - (unsigned char *)buf;
262 }
263 return NULL;
264 }
265 return ret;
266 }
267
268 #ifdef __cplusplus
269 }
270 #endif
271
272 #endif /* CN_CBOR_C */
273