Simulated product dispenser

Dependencies:   HTS221

Fork of mbed-cloud-workshop-connect-HTS221 by Jim Carver

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers cn-cbor.c Source File

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