Simple interface for Mbed Cloud Client
Embed:
(wiki syntax)
Show/hide line numbers
cn-cbor.c
00001 #ifndef CN_CBOR_C 00002 #define CN_CBOR_C 00003 00004 #ifdef __cplusplus 00005 extern "C" { 00006 #endif 00007 #ifdef EMACS_INDENTATION_HELPER 00008 } /* Duh. */ 00009 #endif 00010 00011 #include <stdlib.h> 00012 #include <stdint.h> 00013 #include <string.h> 00014 #include <assert.h> 00015 #include <math.h> 00016 #ifdef CBOR_CAN_DO_UNALIGNED_READS 00017 #include <arpa/inet.h> // needed for ntohl (e.g.) on Linux 00018 #endif 00019 00020 #include "cn-cbor.h" 00021 #include "cbor.h" 00022 00023 00024 #define CN_CBOR_FAIL(code) do { pb->err = code; goto fail; } while(0) 00025 00026 void cn_cbor_free(cn_cbor* cb CBOR_CONTEXT) { 00027 cn_cbor* p = cb; 00028 assert(!p || !p->parent); 00029 while (p) { 00030 cn_cbor* p1; 00031 while ((p1 = p->first_child)) { /* go down */ 00032 p = p1; 00033 } 00034 if (!(p1 = p->next)) { /* go up next */ 00035 if ((p1 = p->parent)) 00036 p1->first_child = 0; 00037 } 00038 CN_CBOR_FREE_CONTEXT(p); 00039 p = p1; 00040 } 00041 } 00042 00043 #ifndef CBOR_NO_FLOAT 00044 static double decode_half(int half) { 00045 int exp = (half >> 10) & 0x1f; 00046 int mant = half & 0x3ff; 00047 double val = 0; 00048 if (exp == 0) { 00049 val = ldexp(mant, -24); 00050 } else if (exp != 31) { 00051 val = ldexp(mant + 1024, exp - 25); 00052 } else { 00053 if (mant == 0) { 00054 val = INFINITY; 00055 } else { 00056 val = NAN; 00057 } 00058 } 00059 return half & 0x8000 ? -val : val; 00060 } 00061 #endif /* CBOR_NO_FLOAT */ 00062 00063 /* Fix these if you can't do non-aligned reads */ 00064 #define ntoh8p(p) (*(unsigned char*)(p)) 00065 #ifdef CBOR_CAN_DO_UNALIGNED_READS 00066 #define ntoh16p(p) (ntohs(*(unsigned short*)(p))) 00067 #define ntoh32p(p) (ntohl(*(unsigned long*)(p))) 00068 #else 00069 static uint16_t ntoh16p(unsigned char *p) { 00070 uint16_t ret = ntoh8p(p); 00071 ret <<= 8; 00072 ret += ntoh8p(p+1); 00073 return ret; 00074 } 00075 static uint32_t ntoh32p(unsigned char *p) { 00076 uint64_t ret = ntoh16p(p); 00077 ret <<= 16; 00078 ret += ntoh16p(p+2); 00079 return ret; 00080 } 00081 #endif 00082 static uint64_t ntoh64p(unsigned char *p) { 00083 uint64_t ret = ntoh32p(p); 00084 ret <<= 32; 00085 ret += ntoh32p(p+4); 00086 return ret; 00087 } 00088 00089 static cn_cbor_type mt_trans[] = { 00090 CN_CBOR_UINT, CN_CBOR_INT, 00091 CN_CBOR_BYTES, CN_CBOR_TEXT, 00092 CN_CBOR_ARRAY, CN_CBOR_MAP, 00093 CN_CBOR_TAG, CN_CBOR_SIMPLE, 00094 }; 00095 00096 struct parse_buf { 00097 unsigned char *buf; 00098 unsigned char *ebuf; 00099 cn_cbor_error err; 00100 }; 00101 00102 #define TAKE(pos, ebuf, n, stmt) \ 00103 if (n > (size_t)(ebuf - pos)) \ 00104 CN_CBOR_FAIL(CN_CBOR_ERR_OUT_OF_DATA); \ 00105 stmt; \ 00106 pos += n; 00107 00108 static cn_cbor *decode_item (struct parse_buf *pb CBOR_CONTEXT, cn_cbor* top_parent) { 00109 unsigned char *pos = pb->buf; 00110 unsigned char *ebuf = pb->ebuf; 00111 cn_cbor* parent = top_parent; 00112 int ib; 00113 unsigned int mt; 00114 int ai; 00115 uint64_t val; 00116 cn_cbor* cb = NULL; 00117 #ifndef CBOR_NO_FLOAT 00118 union { 00119 float f; 00120 uint32_t u; 00121 } u32; 00122 union { 00123 double d; 00124 uint64_t u; 00125 } u64; 00126 #endif /* CBOR_NO_FLOAT */ 00127 00128 again: 00129 TAKE(pos, ebuf, 1, ib = ntoh8p(pos) ); 00130 if (ib == IB_BREAK) { 00131 if (!(parent->flags & CN_CBOR_FL_INDEF)) 00132 CN_CBOR_FAIL(CN_CBOR_ERR_BREAK_OUTSIDE_INDEF); 00133 switch (parent->type) { 00134 case CN_CBOR_BYTES: case CN_CBOR_TEXT: 00135 parent->type += 2; /* CN_CBOR_* -> CN_CBOR_*_CHUNKED */ 00136 break; 00137 case CN_CBOR_MAP: 00138 if (parent->length & 1) 00139 CN_CBOR_FAIL(CN_CBOR_ERR_ODD_SIZE_INDEF_MAP); 00140 default:; 00141 } 00142 goto complete; 00143 } 00144 mt = ib >> 5; 00145 ai = ib & 0x1f; 00146 val = ai; 00147 00148 cb = CN_CALLOC_CONTEXT(); 00149 if (!cb) 00150 CN_CBOR_FAIL(CN_CBOR_ERR_OUT_OF_MEMORY); 00151 00152 cb->type = mt_trans[mt]; 00153 00154 cb->parent = parent; 00155 if (parent->last_child) { 00156 parent->last_child->next = cb; 00157 } else { 00158 parent->first_child = cb; 00159 } 00160 parent->last_child = cb; 00161 parent->length++; 00162 00163 switch (ai) { 00164 case AI_1: TAKE(pos, ebuf, 1, val = ntoh8p(pos)) ; cb->length = 1; break; 00165 case AI_2: TAKE(pos, ebuf, 2, val = ntoh16p(pos)) ; cb->length = 2; break; 00166 case AI_4: TAKE(pos, ebuf, 4, val = ntoh32p(pos)) ; cb->length = 4; break; 00167 case AI_8: TAKE(pos, ebuf, 8, val = ntoh64p(pos)) ; cb->length = 8; break; 00168 00169 case 28: case 29: case 30: CN_CBOR_FAIL(CN_CBOR_ERR_RESERVED_AI); 00170 case AI_INDEF: 00171 if ((mt - MT_BYTES) <= MT_MAP) { 00172 cb->flags |= CN_CBOR_FL_INDEF; 00173 goto push; 00174 } else { 00175 CN_CBOR_FAIL(CN_CBOR_ERR_MT_UNDEF_FOR_INDEF); 00176 } 00177 } 00178 // process content 00179 switch (mt) { 00180 case MT_UNSIGNED: 00181 cb->v.uint = val; /* to do: Overflow check */ 00182 /* 00183 if the integer itsef is used (ai=0..23), set the length to 4, for compliance 00184 with the definition that integer values of mbed.UseBootstrap and mbed.MemoryTotalKB 00185 is 4 bytes. 00186 This implementation might cause bugs with other parameters that has no such requirement, 00187 so the code should be changed in the future 00188 */ 00189 if (cb->length == 0) { 00190 cb->length = 4; 00191 } 00192 break; 00193 case MT_NEGATIVE: 00194 cb->v.sint = ~val; /* to do: Overflow check */ 00195 /* 00196 if the integer itsef is used (ai=0..23), set the length to 4, for compliance 00197 with the definition that integer values of mbed.UseBootstrap and mbed.MemoryTotalKB 00198 is 4 bytes. 00199 This implementation might cause bugs with other parameters that has no such requirement, 00200 so the code should be changed in the future 00201 */ 00202 if (cb->length == 0) { 00203 cb->length = 4; 00204 } 00205 break; 00206 case MT_BYTES: case MT_TEXT: 00207 cb->v.str = (char *) pos; 00208 cb->length = val; 00209 TAKE(pos, ebuf, val, ;); 00210 break; 00211 case MT_MAP: 00212 val <<= 1; 00213 /* fall through */ 00214 case MT_ARRAY: 00215 if ((cb->v.count = val)) { 00216 cb->flags |= CN_CBOR_FL_COUNT; 00217 goto push; 00218 } 00219 break; 00220 case MT_TAG: 00221 cb->v.uint = val; 00222 goto push; 00223 case MT_PRIM: 00224 switch (ai) { 00225 case VAL_FALSE: cb->type = CN_CBOR_FALSE; break; 00226 case VAL_TRUE: cb->type = CN_CBOR_TRUE; break; 00227 case VAL_NIL: cb->type = CN_CBOR_NULL; break; 00228 case VAL_UNDEF: cb->type = CN_CBOR_UNDEF; break; 00229 case AI_2: 00230 #ifndef CBOR_NO_FLOAT 00231 cb->type = CN_CBOR_DOUBLE; 00232 cb->v.dbl = decode_half(val); 00233 #else /* CBOR_NO_FLOAT */ 00234 CN_CBOR_FAIL(CN_CBOR_ERR_FLOAT_NOT_SUPPORTED); 00235 #endif /* CBOR_NO_FLOAT */ 00236 break; 00237 case AI_4: 00238 #ifndef CBOR_NO_FLOAT 00239 cb->type = CN_CBOR_DOUBLE; 00240 u32.u = val; 00241 cb->v.dbl = u32.f; 00242 #else /* CBOR_NO_FLOAT */ 00243 CN_CBOR_FAIL(CN_CBOR_ERR_FLOAT_NOT_SUPPORTED); 00244 #endif /* CBOR_NO_FLOAT */ 00245 break; 00246 case AI_8: 00247 #ifndef CBOR_NO_FLOAT 00248 cb->type = CN_CBOR_DOUBLE; 00249 u64.u = val; 00250 cb->v.dbl = u64.d; 00251 #else /* CBOR_NO_FLOAT */ 00252 CN_CBOR_FAIL(CN_CBOR_ERR_FLOAT_NOT_SUPPORTED); 00253 #endif /* CBOR_NO_FLOAT */ 00254 break; 00255 default: cb->v.uint = val; 00256 } 00257 } 00258 fill: /* emulate loops */ 00259 if (parent->flags & CN_CBOR_FL_INDEF) { 00260 if (parent->type == CN_CBOR_BYTES || parent->type == CN_CBOR_TEXT) 00261 if (cb->type != parent->type) 00262 CN_CBOR_FAIL(CN_CBOR_ERR_WRONG_NESTING_IN_INDEF_STRING); 00263 goto again; 00264 } 00265 if (parent->flags & CN_CBOR_FL_COUNT) { 00266 if (--parent->v.count) 00267 goto again; 00268 } 00269 /* so we are done filling parent. */ 00270 complete: /* emulate return from call */ 00271 if (parent == top_parent) { 00272 if (pos != ebuf) /* XXX do this outside */ 00273 CN_CBOR_FAIL(CN_CBOR_ERR_NOT_ALL_DATA_CONSUMED); 00274 pb->buf = pos; 00275 return cb; 00276 } 00277 cb = parent; 00278 parent = parent->parent; 00279 goto fill; 00280 push: /* emulate recursive call */ 00281 parent = cb; 00282 goto again; 00283 fail: 00284 pb->buf = pos; 00285 return 0; 00286 } 00287 00288 cn_cbor* cn_cbor_decode(const unsigned char* buf, size_t len CBOR_CONTEXT, cn_cbor_errback *errp) { 00289 cn_cbor catcher = {CN_CBOR_INVALID, 0, {0}, 0, NULL, NULL, NULL, NULL}; 00290 struct parse_buf pb; 00291 cn_cbor* ret; 00292 00293 pb.buf = (unsigned char *)buf; 00294 pb.ebuf = (unsigned char *)buf+len; 00295 pb.err = CN_CBOR_NO_ERROR; 00296 ret = decode_item(&pb CBOR_CONTEXT_PARAM, &catcher); 00297 if (ret != NULL) { 00298 /* mark as top node */ 00299 ret->parent = NULL; 00300 } else { 00301 00302 if (catcher.first_child) { 00303 catcher.first_child->parent = 0; 00304 cn_cbor_free(catcher.first_child CBOR_CONTEXT_PARAM); 00305 } 00306 //fail: 00307 if (errp) { 00308 errp->err = pb.err; 00309 errp->pos = pb.buf - (unsigned char *)buf; 00310 } 00311 return NULL; 00312 } 00313 return ret; 00314 } 00315 00316 00317 #ifdef __cplusplus 00318 } 00319 #endif 00320 00321 #endif /* CN_CBOR_C */
Generated on Tue Jul 12 2022 19:01:33 by 1.7.2