• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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