libsheepy

C lib for handling text files, strings and json like data structure with an object oriented system
git clone https://spartatek.se/git/libsheepy.git
Log | Files | Refs | README | LICENSE

libsheepySmall.c (53276B)


      1 // MIT License
      2 //
      3 // Copyright (c) 2026 Remy Noulin
      4 //
      5 // Permission is hereby granted, free of charge, to any person obtaining a copy
      6 // of this software and associated documentation files (the "Software"), to deal
      7 // in the Software without restriction, including without limitation the rights
      8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      9 // copies of the Software, and to permit persons to whom the Software is
     10 // furnished to do so, subject to the following conditions:
     11 //
     12 // The above copyright notice and this permission notice shall be included in all
     13 // copies or substantial portions of the Software.
     14 //
     15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     21 // SOFTWARE.
     22 
     23 #include "libsheepySmall.h"
     24 #include <inttypes.h>
     25 
     26 #define internal static
     27 
     28 #include <stdint.h>
     29 #include <stdlib.h>
     30 #include <stdbool.h>
     31 #include <string.h>
     32 #include <stdio.h>
     33 
     34 bool isSTypeF(smallt *obj, char sType);
     35 size_t sSizeTiny(smallt *obj);
     36 sBoolt* allocSBool(bool value);
     37 sContainert* allocSContainer(void *data);
     38 sDictt* allocSDict(void);
     39 sDoublet* allocSDouble(double value);
     40 sIntt* allocSInt(int64_t value);
     41 sStringt* allocSStringTiny(const char* data);
     42 sArrayt* allocSArray(void);
     43 sUndefinedt* allocSUndefined(void);
     44 sBytest* allocSBytes(void);
     45 void sFree(smallt *obj);
     46 void sFreeTiny(smallt *obj);
     47 void sDictFreeElement(sDictElemt *e);
     48 void sDictFreeElements(sDictt *dict);
     49 void sDictFreeTiny(sDictt *dict);
     50 void sArrayFreeElements(sArrayt *array);
     51 void sArrayFreeTiny(sArrayt *array);
     52 smallt* sDuplicate(smallt *o);
     53 smallt* sDuplicateTiny(smallt *obj);
     54 sDictt* sDictDuplicateTiny(sDictt *dict);
     55 sArrayt* sArrayDuplicateTiny(sArrayt *array);
     56 char* sToStringTiny(smallt *obj);
     57 char* sToString(smallt *obj);
     58 char* sBoolToStringTiny(sBoolt* obj);
     59 char* sContainerToStringTiny(sContainert* obj UNUSED);
     60 char* sDictToStringTiny(sDictt* obj);
     61 char* sDoubleToStringTiny(sDoublet* obj);
     62 char* sIntToStringTiny(sIntt* obj);
     63 char* sStringToStringTiny(sStringt* obj);
     64 char* sArrayToStringTiny(sArrayt* obj);
     65 char* sUndefinedToStringTiny(sUndefinedt* obj UNUSED);
     66 char* sBytesToStringTiny(sBytest* obj);
     67 char* sEscapeTiny(smallt *obj);
     68 char* sEscape(smallt *obj);
     69 char* sDictEscapeTiny(sDictt* obj);
     70 char* sStringEscapeTiny(sStringt* obj);
     71 char* sArrayEscapeTiny(sArrayt* obj);
     72 char* sTypesTiny(smallt* obj);
     73 sBytest* sTypesToBytesTiny(smallt *obj);
     74 const char** sDictTypeStrings(sDictt* obj);
     75 const char ** sTypesToStrings(sBytest *types);
     76 sBytest* sDictTypes(sDictt* obj);
     77 sBytest* sDictTypesTiny(sDictt* obj);
     78 const char** sArrayTypeStrings(sArrayt* obj);
     79 sBytest* sArrayTypes(sArrayt* obj);
     80 sBytest* sArrayTypesTiny(sArrayt* obj);
     81 smallt* sDictGet(sDictt *dict, const char *key);
     82 smallt** sDictGetP(sDictt *dict, const char *key);
     83 smallt* sDictGetTiny(sDictt *dict, const char *key);
     84 void sDictSetP(sDictt **dict, const char *key, smallt *data);
     85 void sDictSetTiny(sDictt **dict, const char *key, smallt *data);
     86 void sDictPushTiny(sDictt **dict, const char *key, smallt *data);
     87 void sDictDelTiny(sDictt *dict, const char *key);
     88 char* sStringGetTiny(sStringt *string);
     89 void sStringSetTiny(sStringt **string, const char *news);
     90 void sArrayPushTiny(sArrayt **array, smallt* data);
     91 void sArrayPrependTiny(sArrayt **array, smallt* data);
     92 smallt* sArrayPopTiny(sArrayt *array);
     93 smallt* sArrayDequeueTiny(sArrayt *array);
     94 smallt** sArrayGetP(sArrayt *array, uint32_t index);
     95 smallt* sArrayGetTiny(sArrayt *array, uint32_t index);
     96 void sArraySetShortTiny(sArrayt *array, uint32_t index, smallt *value);
     97 void sArraySetP(sArrayt *array, uint32_t index, smallt *value);
     98 void sArraySetTiny(sArrayt *array, uint32_t index, smallt *value);
     99 int sArrayReverseTiny(sArrayt *array);
    100 void sArrayDelTiny(sArrayt *array, uint32_t index);
    101 void sArrayDelRangeTiny(sArrayt *array, uint32_t start, uint32_t end);
    102 void* sBytesGet(sBytest *bytes);
    103 void* sBytesGetTiny(sBytest *bytes);
    104 void sBytesPush(sBytest **bytes, char data);
    105 void sBytesPushBuffer(sBytest **bytes, void* data, uint32_t size);
    106 void sBytesPushBufferTiny(sBytest **bytes, void* data, uint32_t size);
    107 sBytest *sSerial(smallt *obj);
    108 sBytest *sSerialTiny(smallt *obj);
    109 void sDictSerialElementsTiny(sBytest **r, sDictt *dict);
    110 void sArraySerialElementsTiny(sBytest **r, sArrayt *array);
    111 smallt* sDeserial(sBytest *obj);
    112 smallt* sDeserialTiny(sBytest *obj);
    113 void sDictDeserialElementsTiny(sDictt **dict, char **data);
    114 void sArrayDeserialElementsTiny(sArrayt **array, char **data);
    115 
    116 /** \file
    117  * Functions for the small objects smallt
    118  *
    119  * The small objects are used internally in the small baset objects: smallBoolt, smallContainert...
    120  *
    121  * The functions here implement basic functionnality.
    122  *
    123  * The *Tiny functions dont sanitize the parameters.
    124  * The *Short functions dont create objects and do the minimum possible and have no checks.
    125  *
    126  * Adjust SDICT_MIN_ELEMENTS, SDICT_REALLOC_STEPS, SARRAY_MIN_ELEMENTS and SARRAY_REALLOC_STEPS to balance speed
    127  * and memory usage.
    128  */
    129 
    130 // min MIN_ELEMENTS is 1
    131 #define SDICT_MIN_ELEMENTS     12
    132 #define SDICT_REALLOC_STEPS    4
    133 // min MIN_ELEMENTS is 1
    134 #define SARRAY_MIN_ELEMENTS    4
    135 #define SARRAY_REALLOC_STEPS   4
    136 
    137 /**
    138  * is Small Type
    139  * true if obj has type sType
    140  *
    141  * \param
    142  *    obj small object to check
    143  * \return
    144  *    true if object has type sType
    145  */
    146 bool isSTypeF(smallt *obj, char sType) {
    147 
    148   if (!obj) {
    149     return(false);
    150   }
    151   return(isSType(obj, sType));
    152 }
    153 
    154 /**
    155  * unused function and wrong result
    156  * TODO update or remove
    157  */
    158 size_t sSizeTiny(smallt *obj) {
    159   size_t r = 0;;
    160 
    161   /* if !obj */
    162   /*   return 0 */
    163 
    164   switch(obj->type) {
    165     case UNDEFINED:
    166       r = sizeof(sUndefinedt);
    167       break;
    168     case BOOL:
    169       r = sizeof(sBoolt);
    170       break;
    171     case CONTAINER:
    172       r = sizeof(sContainert);
    173       break;
    174     case DICT:
    175       if (!((sDictt *)obj)->count) {
    176         r = sizeof(sDictt);
    177       }
    178       else {
    179         r = sizeof(sDictt) + sizeof(sDictElemt) * (((sDictt *)obj)->count - 1);
    180       }
    181       break;
    182     case DOUBLE:
    183       r = sizeof(sDoublet);
    184       break;
    185     case INT:
    186       r = sizeof(sIntt);
    187       break;
    188     case STRING:
    189       r = sizeof(sStringt) + strlen(&(((sStringt *)obj)->data));
    190       break;
    191     case ARRAY:
    192       if (!((sArrayt* )obj)->count) {
    193         r = sizeof(sArrayt);
    194       }
    195       else {
    196         r = sizeof(sArrayt) + sizeof(smallt *) * (((sArrayt* )obj)->count - 1);
    197       }
    198       break;
    199     case BYTES:
    200       if (!((sBytest* )obj)->count) {
    201         r = sizeof(sBytest);
    202       }
    203       else {
    204         r = sizeof(sBytest) + sizeof(char) * (((sBytest* )obj)->count - 1);
    205       }
    206       break;
    207     default:;
    208       // return 0
    209   }
    210   return(r);
    211 }
    212 
    213 /**
    214  * allocate a small bool
    215  *
    216  * \param
    217  *    value initialize object with value
    218  * \return
    219  *    new object initialized with value
    220  */
    221 sBoolt* allocSBool(bool value) {
    222   sBoolt *r = NULL;
    223 
    224   isError(r, malloc(sizeof(sBoolt))) return(NULL);
    225   r->type  = BOOL;
    226   r->value = value;
    227   return(r);
    228 }
    229 
    230 /**
    231  * allocate a small container
    232  * The container holds a pointer to a user buffer
    233  *
    234  * \param
    235  *    data initialize object with data pointer
    236  * \return
    237  *    new object initialized with data pointer
    238  */
    239 sContainert* allocSContainer(void *data) {
    240   sContainert *r = NULL;
    241 
    242   isError(r, malloc(sizeof(sContainert))) return(NULL);
    243   r->type     = CONTAINER;
    244   r->dataType = SH_DT_UNKNOWN;
    245   r->data     = data;
    246   r->free     = NULL;
    247   return(r);
    248 }
    249 
    250 /**
    251  * allocate a small dict
    252  *
    253  * \return
    254  *    new empty dict
    255  */
    256 sDictt* allocSDict(void) {
    257   sDictt *r = NULL;
    258 
    259   isError(r, malloc(sizeof(sDictt) + sizeof(sDictElemt) * (SDICT_MIN_ELEMENTS-1))) return(NULL);
    260   r->type     = DICT;
    261   r->count    = 0;
    262   r->maxCount = SDICT_MIN_ELEMENTS;
    263   return(r);
    264 }
    265 
    266 /**
    267  * allocate a small double
    268  *
    269  * \param
    270  *    value initialize object with value
    271  * \return
    272  *    new object initialized with value
    273  */
    274 sDoublet* allocSDouble(double value) {
    275   sDoublet *r = NULL;
    276 
    277   isError(r, malloc(sizeof(sDoublet))) return(NULL);
    278   r->type  = DOUBLE;
    279   r->value = value;
    280   return(r);
    281 }
    282 
    283 /**
    284  * allocate a small int
    285  *
    286  * \param
    287  *    value initialize object with value
    288  * \return
    289  *    new object initialized with value
    290  */
    291 sIntt* allocSInt(int64_t value) {
    292   sIntt *r = NULL;
    293 
    294   isError(r, malloc(sizeof(sIntt))) return(NULL);
    295   r->type  = INT;
    296   r->value = value;
    297   return(r);
    298 }
    299 
    300 /**
    301  * allocate a small string
    302  *
    303  * \param
    304  *    value initialize object with value
    305  * \return
    306  *    new object initialized with value
    307  */
    308 sStringt* allocSStringTiny(const char* data) {
    309   sStringt *r = NULL;
    310   size_t len;
    311   char *T = NULL;
    312 
    313   len      = strlen(data);
    314   isError(r, malloc(sizeof(sStringt) + len)) return(NULL);
    315   r->type  = STRING;
    316   // should be: strcpy(&(r->data), data); but it fails (Abort trap 6) with clang / macOS
    317   T = &(r->data);;
    318   strcpy(T, data);
    319   return(r);
    320 }
    321 
    322 /**
    323  * allocate a small array
    324  *
    325  * \return
    326  *    new empty array
    327  */
    328 // keep data uninitialized (count)
    329 sArrayt* allocSArray(void) {
    330   sArrayt *r = NULL;
    331 
    332   isError(r, malloc(sizeof(sArrayt) + sizeof(smallt *) * SARRAY_MIN_ELEMENTS)) return(NULL);
    333   r->type     = ARRAY;
    334   r->count    = 0;
    335   r->maxCount = SARRAY_MIN_ELEMENTS;
    336   return(r);
    337 }
    338 
    339 /**
    340  * allocate a small undefined object
    341  *
    342  * \return
    343  *    new undefined object
    344  */
    345 sUndefinedt* allocSUndefined(void) {
    346   sUndefinedt *r = NULL;
    347 
    348   isError(r, malloc(sizeof(sUndefinedt))) return(NULL);
    349   r->type = UNDEFINED;
    350   return(r);
    351 }
    352 
    353 /**
    354  * allocate a small bytes object
    355  *
    356  * \return
    357  *    new small bytes object
    358  */
    359 sBytest* allocSBytes(void) {
    360   sBytest *r = NULL;
    361 
    362   isError(r, malloc(sizeof(sBytest))) return(NULL);
    363   r->type     = BYTES;
    364   r->count    = 0;
    365   return(r);
    366 }
    367 
    368 /**
    369  * free non null objects
    370  */
    371 void sFree(smallt *obj) {
    372 
    373   if (obj) {
    374     sFreeTiny(obj);
    375 }
    376   }
    377 
    378 /**
    379  * free any type of small object
    380  *
    381  * objects that are not of type sDict or sArray are freed with the standard free
    382  *
    383  * \param
    384  *    obj object to free
    385  */
    386 void sFreeTiny(smallt *obj) {
    387   sContainert *c = NULL;
    388 
    389   switch(obj->type) {
    390     case DICT:
    391       sDictFreeTiny((sDictt *) obj);
    392       break;
    393     case ARRAY:
    394       sArrayFreeTiny((sArrayt *) obj);
    395       break;
    396     case CONTAINER:
    397       c = (sContainert*)obj;
    398       if (c->free) {
    399         c->free(c->data);
    400         c->data = NULL;
    401       }
    402       free(obj);
    403       break;
    404     default:
    405       free(obj);
    406   }
    407 }
    408 
    409 /**
    410  * free a dictionary element
    411  *
    412  * the key and the object are freed
    413  *
    414  * \param
    415  *    e element to free
    416  */
    417 void sDictFreeElement(sDictElemt *e) {
    418 
    419   if (e->key) {
    420     free(e->key);
    421     sFreeTiny(e->data);
    422     e->key = NULL;
    423 }
    424   }
    425 
    426 /**
    427  * free dictionary elements
    428  *
    429  * \param
    430  *    dict dictionary to free
    431  */
    432 void sDictFreeElements(sDictt *dict) {
    433 
    434   forEachSDict(dict, e) {
    435       sDictFreeElement(e);
    436 }
    437   }
    438 
    439 /**
    440  * free dictionary elements and dictionary object
    441  *
    442  * \param
    443  *    dict dictionary to free
    444  */
    445 void sDictFreeTiny(sDictt *dict) {
    446 
    447   sDictFreeElements(dict);
    448   free(dict);
    449 }
    450 
    451 /**
    452  * free array elements
    453  *
    454  * \param
    455  *    array array to free
    456  */
    457 void sArrayFreeElements(sArrayt *array) {
    458 
    459   forEachSArray(array, e) {
    460     sFree(e);
    461 }
    462   }
    463 
    464 /**
    465  * free array elements and array object
    466  *
    467  * \param
    468  *    array array to free
    469  */
    470 void sArrayFreeTiny(sArrayt *array) {
    471 
    472   sArrayFreeElements(array);
    473   free(array);
    474 }
    475 
    476 /**
    477  * duplicate small object
    478  *
    479  * \param
    480  *    o small object
    481  * \return
    482  *    duplicated object
    483  *    NULL when o is NULL
    484  */
    485 smallt* sDuplicate(smallt *o) {
    486 
    487   if (!o) {
    488     return(NULL);
    489   }
    490 
    491   return(sDuplicateTiny(o));
    492 }
    493 
    494 /**
    495  * duplicate small object
    496  *
    497  * for containers, the pointer is copied to new object
    498  *
    499  * \param
    500  *    obj small object
    501  * \return
    502  *    duplicated object
    503  */
    504 smallt* sDuplicateTiny(smallt *obj) {
    505   smallt *r = NULL;
    506   sBytest *B = NULL;
    507   sContainert *c = NULL;
    508 
    509   switch(obj->type) {
    510     case UNDEFINED:
    511       r = (smallt *)allocSUndefined();
    512       break;
    513     case BOOL:
    514       r = (smallt *)allocSBool(((sBoolt *)obj)->value);
    515       break;
    516     case CONTAINER:
    517       // data is not copied, same data pointer is used
    518       isError(c, allocSContainer(((sContainert *)obj)->data)) return(NULL);
    519       c->dataType = ((sContainert *)obj)->dataType;
    520       c->free     = ((sContainert *)obj)->free;
    521       r           = (smallt *)c;
    522       break;
    523     case DICT:
    524       r = (smallt *)sDictDuplicateTiny((sDictt *)obj);
    525       break;
    526     case DOUBLE:
    527       r = (smallt *)allocSDouble(((sDoublet *)obj)->value);
    528       break;
    529     case INT:
    530       r = (smallt *)allocSInt(((sIntt *)obj)->value);
    531       break;
    532     case STRING:
    533       r = (smallt *) strdup((char *) obj);;
    534       break;
    535     case ARRAY:
    536       r = (smallt *)sArrayDuplicateTiny((sArrayt *)obj);
    537       break;
    538     case BYTES:
    539       isError(B, allocSBytes()) return(NULL);
    540       if (((sBytest *)obj)->count) {
    541         sBytesPushBuffer(&B, sBytesGetTiny((sBytest *)obj), ((sBytest *)obj)->count);
    542       }
    543       r = (smallt *) B;
    544       break;
    545     default:
    546       logME(libsheepyErrorMask, "Unsupported object type.");
    547   }
    548   return(r);
    549 }
    550 
    551 /**
    552  * duplicate dictionary
    553  *
    554  * \param
    555  *    dict dictionary to duplicate
    556  * \return
    557  *    duplicated dictionary
    558  */
    559 sDictt* sDictDuplicateTiny(sDictt *dict) {
    560 
    561   sDictt *d = allocSDict();
    562   if (!d) {
    563     return(NULL);
    564   }
    565 
    566   forEachSDict(dict, e) {
    567     if (e->key) {
    568       smallt *eDup = sDuplicateTiny(e->data);
    569       sDictPushTiny(&d, e->key, eDup);
    570   }
    571     }
    572   return(d);
    573 }
    574 
    575 /**
    576  * duplicate array
    577  *
    578  * \param
    579  *    array array to duplicate
    580  * \return
    581  *    duplicated array
    582  */
    583 sArrayt* sArrayDuplicateTiny(sArrayt *array) {
    584 
    585   sArrayt *a = allocSArray();
    586   if (!a) {
    587     return(NULL);
    588   }
    589 
    590   forEachSArray(array, e) {
    591     sArrayPushTiny(&a, sDuplicate(e));
    592   }
    593   return(a);
    594 }
    595 
    596 /**
    597  * stringify a small object
    598  *
    599  * the returned string has to be freed
    600  *
    601  * \param
    602  *    obj object
    603  * \return
    604  *    string representing the object
    605  */
    606 char* sToStringTiny(smallt *obj) {
    607   char *r = NULL;
    608 
    609   switch(obj->type) {
    610     case UNDEFINED:
    611       r = sUndefinedToStringTiny((sUndefinedt *)obj);
    612       break;
    613     case BOOL:
    614       r = sBoolToStringTiny((sBoolt *)obj);
    615       break;
    616     case CONTAINER:
    617       r = sContainerToStringTiny((sContainert *)obj);
    618       break;
    619     case DICT:
    620       r = sDictToStringTiny((sDictt *)obj);
    621       break;
    622     case DOUBLE:
    623       r = sDoubleToStringTiny((sDoublet *)obj);
    624       break;
    625     case INT:
    626       r = sIntToStringTiny((sIntt *)obj);
    627       break;
    628     case STRING:
    629       r = sStringToStringTiny((sStringt *)obj);
    630       break;
    631     case ARRAY:
    632       r = sArrayToStringTiny((sArrayt* )obj);
    633       break;
    634     case BYTES:
    635       r = sBytesToStringTiny((sBytest* )obj);
    636       break;
    637     default:
    638       logME(libsheepyErrorMask, "Unsupported object type.");
    639   }
    640   return(r);
    641 }
    642 
    643 /**
    644  * stringify object
    645  *
    646  * the returned string has to be freed
    647  *
    648  * \param
    649  *    obj object
    650  * \return
    651  *    string representing the object
    652  *    NULL when obj is NULL
    653  */
    654 char* sToString(smallt *obj) {
    655 
    656   if (obj) {
    657     return(sToStringTiny(obj));
    658   }
    659   return(NULL);
    660 }
    661 
    662 /**
    663  * stringify bool
    664  *
    665  * the returned string has to be freed
    666  *
    667  * \param
    668  *    obj object
    669  * \return
    670  *    string representing the object
    671  */
    672 char* sBoolToStringTiny(sBoolt* obj) {
    673 
    674   if (obj->value) {
    675     return(strdup("true"));
    676   }
    677   else {
    678     return(strdup("false"));
    679 }
    680   }
    681 
    682 /**
    683  * stringify container
    684  *
    685  * \return
    686  *    <data container> string
    687  */
    688 char* sContainerToStringTiny(sContainert* obj UNUSED) {
    689 
    690   return(strdup("<data container>"));
    691 }
    692 
    693 /**
    694  * stringify dictionary
    695  *
    696  * the returned string has to be freed
    697  *
    698  * \param
    699  *    obj object
    700  * \return
    701  *    string representing the object
    702  */
    703 char* sDictToStringTiny(sDictt* obj) {
    704   char *s = NULL;
    705 
    706   if (!obj->count) {
    707     return(strdup("{}"));
    708   }
    709 
    710   char *r = strdup("{");
    711 
    712   bool hasAtLeastOneElement = no;
    713 
    714   forEachSDict(obj, e) {
    715     if (e->key) {
    716       hasAtLeastOneElement = yes;
    717       pErrorNULL(iAppendS(&r, "\""));
    718       pErrorNULL(iAppendS(&r, e->key));
    719       pErrorNULL(iAppendS(&r, "\""));
    720       if (isSType(e->data, STRING) || isSType(e->data, CONTAINER)) {
    721         // add quotes for strings
    722         pErrorNULL(iAppendS(&r, ":\""));
    723         s = sToStringTiny(e->data);
    724         pErrorNULL(iAppendS(&r, s));
    725         free(s);
    726         pErrorNULL(iAppendS(&r, "\","));
    727       }
    728       else {
    729         pErrorNULL(iAppendS(&r, ":"));
    730         s = sToStringTiny(e->data);
    731         pErrorNULL(iAppendS(&r, s));
    732         free(s);
    733         pErrorNULL(iAppendS(&r, ","));
    734   }
    735     }
    736       }
    737 
    738   if (hasAtLeastOneElement) {
    739     pErrorNULL(setS(r, -1, '}'));
    740   }
    741   else {
    742     pErrorNULL(iAppendS(&r, "}"));
    743   }
    744   return(r);
    745 }
    746 
    747 /**
    748  * stringify double
    749  *
    750  * the returned string has to be freed
    751  *
    752  * \param
    753  *    obj object
    754  * \return
    755  *    string representing the object
    756  */
    757 char* sDoubleToStringTiny(sDoublet* obj) {
    758   char *s = NULL;
    759 
    760   isError(s, malloc(256*sizeof(char))) return(NULL);
    761   snprintf(s,256, "%e", obj->value);
    762 
    763   return(s);
    764 }
    765 
    766 /**
    767  * stringify int
    768  *
    769  * the returned string has to be freed
    770  *
    771  * \param
    772  *    obj object
    773  * \return
    774  *    string representing the object
    775  */
    776 char* sIntToStringTiny(sIntt* obj) {
    777   char *s = NULL;
    778 
    779   isError(s, malloc(256*sizeof(char))) return(NULL);
    780   snprintf(s,256, "%" PRIi64, obj->value);
    781 
    782   return(s);
    783 }
    784 
    785 /**
    786  * stringify string
    787  *
    788  * the returned string has to be freed
    789  *
    790  * \param
    791  *    obj object
    792  * \return
    793  *    string representing the object
    794  */
    795 char* sStringToStringTiny(sStringt* obj) {
    796 
    797   return(strdup(sStringGetTiny(obj)));
    798 }
    799 
    800 /**
    801  * stringify array
    802  *
    803  * the returned string has to be freed
    804  *
    805  * \param
    806  *    obj object
    807  * \return
    808  *    string representing the object
    809  */
    810 char* sArrayToStringTiny(sArrayt* obj) {
    811   char *s = NULL;
    812 
    813   if (!obj->count) {
    814     return(strdup("[]"));
    815   }
    816 
    817   char *r      = strdup("[");
    818   uint32_t cnt   = 0;;
    819   bool emptySlot = false;;
    820   forEachSArray(obj, o) {
    821     if (!o) {
    822       // empty slot
    823       emptySlot = true;;
    824       continue;
    825     }
    826     emptySlot = false;;
    827     cnt++;
    828     if (isSType(o, STRING) || isSType(o, CONTAINER)) {
    829       // add quotes for strings
    830       pErrorNULL(iAppendS(&r, "\""));
    831       s = sToStringTiny(o);
    832       pErrorNULL(iAppendS(&r, s));
    833       free(s);
    834       pErrorNULL(iAppendS(&r, "\""));
    835     }
    836     else {
    837       s = sToStringTiny(o);
    838       pErrorNULL(iAppendS(&r, s));
    839       free(s);
    840     }
    841     pErrorNULL(iAppendS(&r, ","));
    842   }
    843   if (!cnt && emptySlot) {
    844     pErrorNULL(iAppendS(&r, "]"));
    845   }
    846   else {
    847     pErrorNULL(setS(r, -1, ']'));
    848   }
    849   return(r);
    850 }
    851 
    852 /**
    853  * stringify undefined
    854  *
    855  * the returned string has to be freed
    856  *
    857  * \param
    858  *    obj object
    859  * \return
    860  *    "null" string
    861  */
    862 char* sUndefinedToStringTiny(sUndefinedt* obj UNUSED) {
    863 
    864   return(strdup("null"));
    865 }
    866 
    867 /**
    868  * stringify small bytes
    869  *
    870  * the returned string has to be freed
    871  *
    872  * \param
    873  *    obj object
    874  * \return
    875  *    bytes converted to decimal string representing the object
    876  */
    877 char* sBytesToStringTiny(sBytest* obj) {
    878 
    879   if (!obj->count) {
    880     return(strdup("[]"));
    881   }
    882 
    883   char *r = toHexSepS(&(obj->data), obj->count, ",");
    884   pErrorNULL(iPrependS(&r, "["));
    885   pErrorNULL(iAppendS(&r, "]"));
    886   return(r);
    887 }
    888 
    889 /**
    890  * stringify a small object
    891  *
    892  * Escape characters to produce a parsable json
    893  *
    894  * the returned string has to be freed
    895  *
    896  * \param
    897  *    obj object
    898  * \return
    899  *    string representing the object
    900  */
    901 char* sEscapeTiny(smallt *obj) {
    902   char *r = NULL;
    903 
    904   switch(obj->type) {
    905     case UNDEFINED:
    906       r = sUndefinedToStringTiny((sUndefinedt *)obj);
    907       break;
    908     case BOOL:
    909       r = sBoolToStringTiny((sBoolt *)obj);
    910       break;
    911     case CONTAINER:
    912       r = sContainerToStringTiny((sContainert *)obj);
    913       break;
    914     case DICT:
    915       r = sDictEscapeTiny((sDictt *)obj);
    916       break;
    917     case DOUBLE:
    918       r = sDoubleToStringTiny((sDoublet *)obj);
    919       break;
    920     case INT:
    921       r = sIntToStringTiny((sIntt *)obj);
    922       break;
    923     case STRING:
    924       r = sStringEscapeTiny((sStringt *)obj);
    925       break;
    926     case ARRAY:
    927       r = sArrayEscapeTiny((sArrayt* )obj);
    928       break;
    929     case BYTES:
    930       r = sBytesToStringTiny((sBytest* )obj);
    931       break;
    932     default:
    933       logME(libsheepyErrorMask, "Unsupported object type.");
    934   }
    935   return(r);
    936 }
    937 
    938 /**
    939  * stringify object
    940  *
    941  * the returned string has to be freed
    942  *
    943  * \param
    944  *    obj object
    945  * \return
    946  *    string representing the object
    947  *    NULL when obj is NULL
    948  */
    949 char* sEscape(smallt *obj) {
    950 
    951   if (obj) {
    952     return(sEscapeTiny(obj));
    953   }
    954   return(NULL);
    955 }
    956 
    957 /**
    958  * stringify dictionary
    959  *
    960  * the returned string has to be freed
    961  *
    962  * \param
    963  *    obj object
    964  * \return
    965  *    string representing the object
    966  */
    967 char* sDictEscapeTiny(sDictt* obj) {
    968   char *s = NULL;
    969 
    970   if (!obj->count) {
    971     return(strdup("{}"));
    972   }
    973 
    974   char *r = strdup("{");
    975 
    976   bool hasAtLeastOneElement = no;
    977 
    978   forEachSDict(obj, e) {
    979     if (e->key) {
    980       hasAtLeastOneElement = yes;
    981       pErrorNULL(iAppendS(&r, "\""));
    982       pErrorNULL(iAppendNFreeS(&r, escapeS(e->key, '\"')));
    983       pErrorNULL(iAppendS(&r, "\""));
    984       if (isSType(e->data, STRING)) {
    985         // add quotes for strings
    986         pErrorNULL(iAppendS(&r, ":\""));
    987         s = sEscapeTiny(e->data);
    988         pErrorNULL(iAppendS(&r, s));
    989         free(s);
    990         pErrorNULL(iAppendS(&r, "\","));
    991       }
    992       else if (isSType(e->data, CONTAINER)) {
    993         // add quotes for strings
    994         pErrorNULL(iAppendS(&r, ":\""));
    995         s = sToStringTiny(e->data);
    996         pErrorNULL(iAppendS(&r, s));
    997         free(s);
    998         pErrorNULL(iAppendS(&r, "\","));
    999       }
   1000       else {
   1001         pErrorNULL(iAppendS(&r, ":"));
   1002         s = sEscapeTiny(e->data);
   1003         pErrorNULL(iAppendS(&r, s));
   1004         free(s);
   1005         pErrorNULL(iAppendS(&r, ","));
   1006   }
   1007     }
   1008       }
   1009 
   1010   if (hasAtLeastOneElement) {
   1011     pErrorNULL(setS(r, -1, '}'));
   1012   }
   1013   else {
   1014     pErrorNULL(iAppendS(&r, "}"));
   1015   }
   1016   return(r);
   1017 }
   1018 
   1019 /**
   1020  * stringify string
   1021  *
   1022  * the returned string has to be freed
   1023  *
   1024  * \param
   1025  *    obj object
   1026  * \return
   1027  *    string representing the object
   1028  */
   1029 char* sStringEscapeTiny(sStringt* obj) {
   1030 
   1031   return(escapeS(sStringGetTiny(obj), '\"'));
   1032 }
   1033 
   1034 /**
   1035  * stringify array
   1036  *
   1037  * the returned string has to be freed
   1038  *
   1039  * \param
   1040  *    obj object
   1041  * \return
   1042  *    string representing the object
   1043  */
   1044 char* sArrayEscapeTiny(sArrayt* obj) {
   1045   char *s = NULL;
   1046 
   1047   if (!obj->count) {
   1048     return(strdup("[]"));
   1049   }
   1050 
   1051   char *r      = strdup("[");
   1052   uint32_t cnt   = 0;;
   1053   bool emptySlot = false;;
   1054   forEachSArray(obj, o) {
   1055     if (!o) {
   1056       // empty slot
   1057       emptySlot = true;;
   1058       continue;
   1059     }
   1060     emptySlot = false;;
   1061     cnt++;
   1062     if (isSType(o, STRING)) {
   1063       // add quotes for strings
   1064       pErrorNULL(iAppendS(&r, "\""));
   1065       s = sEscapeTiny(o);
   1066       pErrorNULL(iAppendS(&r, s));
   1067       free(s);
   1068       pErrorNULL(iAppendS(&r, "\""));
   1069     }
   1070     else if (isSType(o, CONTAINER)) {
   1071       // add quotes for strings
   1072       pErrorNULL(iAppendS(&r, "\""));
   1073       s = sToStringTiny(o);
   1074       pErrorNULL(iAppendS(&r, s));
   1075       free(s);
   1076       pErrorNULL(iAppendS(&r, "\""));
   1077     }
   1078     else {
   1079       s = sEscapeTiny(o);
   1080       pErrorNULL(iAppendS(&r, s));
   1081       free(s);
   1082     }
   1083     pErrorNULL(iAppendS(&r, ","));
   1084   }
   1085   if (!cnt && emptySlot) {
   1086     pErrorNULL(iAppendS(&r, "]"));
   1087   }
   1088   else {
   1089     pErrorNULL(setS(r, -1, ']'));
   1090   }
   1091   return(r);
   1092 }
   1093 
   1094 /**
   1095  * get list of object types string
   1096  *
   1097  * only the types in the first level are listed
   1098  *
   1099  * \param
   1100  *    obj small array or dictionary
   1101  * \return
   1102  *    string listing types in array or dictionary
   1103  */
   1104 char* sTypesTiny(smallt* obj) {
   1105   char *r = NULL;
   1106   sArrayt *a = NULL;
   1107   sBytest *types = NULL;
   1108 
   1109   isError(types, sTypesToBytesTiny(obj)) return(NULL);
   1110 
   1111   for (uint32_t i = 0; i < types->count;i++) {
   1112     char b = (&(types->data))[i];
   1113     if ((size_t)b >= ARRAY_SIZE(SMALL_TYPE_NAMES)) {
   1114       free(types);
   1115       if (a) {
   1116         sArrayFreeTiny(a);
   1117       }
   1118       return(NULL);
   1119     }
   1120     sStringt *s = allocSStringTiny(SMALL_TYPE_NAMES[(size_t) b]);
   1121     if (!s) {
   1122       free(types);
   1123       if (a) {
   1124         sArrayFreeTiny(a);
   1125       }
   1126       return(NULL);
   1127     }
   1128     sArrayPushTiny(&a, (smallt *) s);
   1129   }
   1130 
   1131   r = sArrayToStringTiny(a);
   1132   free(types);
   1133   sArrayFreeTiny(a);
   1134   return(r);
   1135 }
   1136 
   1137 /**
   1138  * collect the types in an array or dictionary
   1139  *
   1140  * \param
   1141  *    obj array or dictionary
   1142  * \return
   1143  *    sBytes list of types in array or dictionary
   1144  */
   1145 sBytest* sTypesToBytesTiny(smallt *obj) {
   1146   sBytest *r = NULL;
   1147 
   1148   switch(obj->type) {
   1149     case DICT:
   1150       r = sDictTypesTiny((sDictt *) obj);;
   1151       break;
   1152     case ARRAY:
   1153       r = sArrayTypesTiny((sArrayt *) obj);;
   1154       break;
   1155     default:;
   1156   }
   1157   return(r);
   1158 }
   1159 
   1160 /**
   1161  * list first level of dictionary types in a list of strings
   1162  *
   1163  * free the return value because the strings are const - dont use listFreeS
   1164  *
   1165  * \param
   1166  *    obj dictionary
   1167  * \return
   1168  *    list of strings representing the types
   1169  */
   1170 const char** sDictTypeStrings(sDictt* obj) {
   1171 
   1172   sBytest *types  = sDictTypes(obj);
   1173 
   1174   return(sTypesToStrings(types));
   1175 }
   1176 
   1177 /**
   1178  * convert a list of object types to a list of strings
   1179  *
   1180  * \param
   1181  *    types object types in a sBytes object, this parameter is freed at the end of the function, except when there is an error
   1182  * \return
   1183  *    list of strings representing the object types, use free to free the list (not listFreeS)
   1184  *    NULL error, types is not freed
   1185  */
   1186 const char ** sTypesToStrings(sBytest *types) {
   1187   const char **r = NULL;
   1188 
   1189   if (!types) {
   1190     return(NULL);
   1191   }
   1192 
   1193   isError(r, malloc((types->count+1) * sizeof(char *))) return(NULL);
   1194   r[types->count] = NULL;
   1195 
   1196   for (uint32_t i = 0 ; i < types->count ; i++) {
   1197     char b = (&(types->data))[i];
   1198     if ((size_t)b >= ARRAY_SIZE(SMALL_TYPE_NAMES)) {
   1199       free(r);
   1200       return(NULL);
   1201     }
   1202     r[i]   = SMALL_TYPE_NAMES[(size_t) b];
   1203   }
   1204 
   1205   free(types);
   1206   return(r);
   1207 }
   1208 
   1209 /**
   1210  * list first level of object types in dictionary
   1211  *
   1212  * \param
   1213  *    obj dictionary
   1214  * \return
   1215  *    list of object types in a sBytes object
   1216  *    NULL when obj is NULL or not a dictionary
   1217  */
   1218 sBytest* sDictTypes(sDictt* obj) {
   1219 
   1220   if (!obj || !isSType(obj, DICT)) {
   1221     return(NULL);
   1222   }
   1223 
   1224   return(sDictTypesTiny(obj));
   1225 }
   1226 
   1227 /**
   1228  * list first level of object types in dictionary
   1229  *
   1230  * \param
   1231  *    obj dictionary
   1232  * \return
   1233  *    list of object types in a sBytes object
   1234  */
   1235 sBytest* sDictTypesTiny(sDictt* obj) {
   1236   sBytest *r = NULL;
   1237 
   1238   forEachSDict(obj, e) {
   1239     if (e->key) {
   1240       sBytesPush(&r, e->data->type);
   1241   }
   1242     }
   1243 
   1244   return(r);
   1245 }
   1246 
   1247 /**
   1248  * list first level of array types in a list of strings
   1249  *
   1250  * free the return because the strings are const - dont use listFreeS
   1251  *
   1252  * \param
   1253  *    obj array
   1254  * \return
   1255  *    list of strings representing the types
   1256  */
   1257 const char** sArrayTypeStrings(sArrayt* obj) {
   1258 
   1259   sBytest *types  = sArrayTypes(obj);
   1260 
   1261   return(sTypesToStrings(types));
   1262 }
   1263 
   1264 /**
   1265  * list first level of object types in array
   1266  *
   1267  * \param
   1268  *    obj array
   1269  * \return
   1270  *    list of object types in a sBytes object
   1271  *    NULL when obj is NULL or not an array
   1272  */
   1273 sBytest* sArrayTypes(sArrayt* obj) {
   1274 
   1275   if (!obj || !isSType(obj, ARRAY)) {
   1276     return(NULL);
   1277   }
   1278 
   1279   return(sArrayTypesTiny(obj));
   1280 }
   1281 
   1282 /**
   1283  * list first level of object types in array
   1284  *
   1285  * \param
   1286  *    obj array
   1287  * \return
   1288  *    list of object types in a sBytes object
   1289  */
   1290 sBytest* sArrayTypesTiny(sArrayt* obj) {
   1291   sBytest *r = NULL;
   1292 
   1293   forEachSArray(obj, e) {
   1294     if (e) {
   1295       sBytesPush(&r, e->type);
   1296   }
   1297     }
   1298 
   1299   return(r);
   1300 }
   1301 
   1302 /**
   1303  * get object stored at key
   1304  *
   1305  * \param
   1306  *    dict dictionary
   1307  *    key key to search in dictionary
   1308  * \return
   1309  *    object stored at key
   1310  *    NULL when dict is NULL or when key is NULL
   1311  */
   1312 smallt* sDictGet(sDictt *dict, const char *key) {
   1313 
   1314   if (!dict || !key) {
   1315     return(NULL);
   1316   }
   1317 
   1318   return(sDictGetTiny(dict, key));
   1319 }
   1320 
   1321 /**
   1322  * get pointer to object at key
   1323  *
   1324  * \param
   1325  *   dict dictionary
   1326  * \param
   1327  *   key key to search in dictionary
   1328  * \return
   1329  *   pointer to object stored at key
   1330  *   NULL when the key is not found
   1331  */
   1332 smallt** sDictGetP(sDictt *dict, const char *key) {
   1333 
   1334   if (!dict || !key) {
   1335     return(NULL);
   1336   }
   1337 
   1338   forEachSDict(dict, e) {
   1339     if (e->key && eqS(key, e->key)) {
   1340         return(&(e->data));
   1341   }
   1342     }
   1343 
   1344   return(NULL);
   1345 }
   1346 
   1347 /**
   1348  * get object stored at key
   1349  *
   1350  * \param
   1351  *    dict dictionary
   1352  *    key key to search in dictionary
   1353  * \return
   1354  *    object stored at key
   1355  *    NULL when the key is not found
   1356  */
   1357 smallt* sDictGetTiny(sDictt *dict, const char *key) {
   1358 
   1359   forEachSDict(dict, e) {
   1360     if (e->key && strEq(key, e->key)) {
   1361         return(e->data);
   1362   }
   1363     }
   1364 
   1365   return(NULL);
   1366 }
   1367 
   1368 /**
   1369  * dictionary set pointer
   1370  *
   1371  * when the key already exists, the associated object is not freed.
   1372  * This is useful for updating arrays, dictionaries and strings in the dictionary
   1373  *
   1374  * when dict is NULL, a new dictionary is allocated
   1375  *
   1376  * when the key doesn't exist, a new element is created
   1377  *
   1378  * when data is NULL, the element is not set
   1379  *
   1380  * \param
   1381  *    dict dictionary
   1382  *    key key associated with data
   1383  *    data object to store
   1384  */
   1385 // TODO create SetShort - create element and add - no alloc
   1386 void sDictSetP(sDictt **dict, const char *key, smallt *data) {
   1387 
   1388   if (!(*dict)) {
   1389     sDictPushTiny(dict, key, data);
   1390     return;
   1391   }
   1392 
   1393   if (!data) {
   1394     // NULL not inserted in dictionary
   1395     return;
   1396   }
   1397 
   1398   forEachSDict(*dict, e) {
   1399     if (e->key && strEq(key, e->key)) {
   1400       e->data = data;
   1401       return;
   1402   }
   1403     }
   1404 
   1405   // create new element
   1406   sDictPushTiny(dict, key, data);
   1407 }
   1408 
   1409 /**
   1410  * dictionary set key, value
   1411  *
   1412  * when the key already exists, the associated object is freed.
   1413  * The new data replaces the previous data
   1414  *
   1415  * when dict is NULL, a new dictionary is allocated
   1416  *
   1417  * when the key doesn't exist, a new element is created
   1418  *
   1419  * when data is NULL, the element is not set
   1420  *
   1421  * \param
   1422  *    dict dictionary
   1423  *    key key associated with data
   1424  *    data object to store
   1425  */
   1426 void sDictSetTiny(sDictt **dict, const char *key, smallt *data) {
   1427 
   1428   if (!(*dict)) {
   1429     sDictPushTiny(dict, key, data);
   1430     return;
   1431   }
   1432 
   1433   if (!data) {
   1434     // NULL not inserted in dictionary
   1435     return;
   1436   }
   1437 
   1438   forEachSDict(*dict, e) {
   1439     if (e->key && strEq(key, e->key)) {
   1440       sFree(e->data);
   1441       e->data = data;
   1442       return;
   1443   }
   1444     }
   1445 
   1446   // create new element
   1447   sDictPushTiny(dict, key, data);
   1448 }
   1449 
   1450 /**
   1451  * push new key-value
   1452  *
   1453  * when data is NULL, the element is not created
   1454  *
   1455  * this function doesnt check if key already exists
   1456  *
   1457  * when dict is NULL, a new dictionary is allocated
   1458  *
   1459  * the dictionary is reallocated when count is greater than
   1460  * maxCount
   1461  *
   1462  * \param
   1463  *    dict dictionary
   1464  *    key key associated with data
   1465  *    data object to store
   1466  */
   1467 // TODO create PushShort - create element and add - no alloc
   1468 void sDictPushTiny(sDictt **dict, const char *key, smallt *data) {
   1469 
   1470   /* // sanity checks */
   1471   /* if !dict */
   1472   /*   return */
   1473 
   1474   if (!(*dict)) {
   1475     // create dict
   1476     isError(*dict, allocSDict()) {
   1477       return;
   1478     }
   1479   }
   1480 
   1481   if (!data) {
   1482     // NULL not inserted in dictionary
   1483     return;
   1484   }
   1485 
   1486   if ((*dict)->count == 0) {
   1487     (*dict)->elements.key  = strdup(key);
   1488     (*dict)->elements.data = data;
   1489   }
   1490   else {
   1491     if ((*dict)->count >= (*dict)->maxCount) {
   1492       // realloc
   1493       sDictt *tmp = realloc(*dict, sizeof(sDictt) + sizeof(sDictElemt) * ((*dict)->count + SDICT_REALLOC_STEPS-1));
   1494       if (!tmp) {
   1495         return;
   1496       }
   1497       else {
   1498         *dict = tmp;
   1499         (*dict)->maxCount = 1 + (*dict)->count + SDICT_REALLOC_STEPS-1;
   1500     }
   1501       }
   1502     sDictElemt *di = &((*dict)->elements);
   1503     di[(*dict)->count].key  = strdup(key);
   1504     di[(*dict)->count].data = data;
   1505   }
   1506 
   1507   (*dict)->count++;
   1508   return;
   1509 }
   1510 
   1511 /**
   1512  * delete dictionary element
   1513  *
   1514  * \param
   1515  *    dict dictionary
   1516  *    key key to search
   1517  */
   1518 void sDictDelTiny(sDictt *dict, const char *key) {
   1519 
   1520   forEachSDict(dict, e) {
   1521     if (e->key && strEq(key, e->key)) {
   1522       sDictFreeElement(e);
   1523       return;
   1524 }
   1525   }
   1526     }
   1527 
   1528 /**
   1529  * get string in a small string object
   1530  *
   1531  * \param
   1532  *    string small string object
   1533  * \return
   1534  *    string in small string
   1535  *    the returned value can't be reallocated since
   1536  *    it is not a pointer to a mallocated buffer
   1537  */
   1538 char* sStringGetTiny(sStringt *string) {
   1539 
   1540   return(&(string->data));
   1541 }
   1542 
   1543 /**
   1544  * set string in small string
   1545  *
   1546  * \param
   1547  *    string small string
   1548  *    news new string
   1549  */
   1550 void sStringSetTiny(sStringt **string, const char *news) {
   1551 
   1552   free(*string);
   1553   *string = allocSStringTiny(news);
   1554 }
   1555 
   1556 /**
   1557  * push data to array
   1558  *
   1559  * when array is NULL, a new array is allocated
   1560  *
   1561  * the array is reallocated when count is greater than
   1562  * maxCount
   1563  *
   1564  * \param
   1565  *    array
   1566  *    data data to store
   1567  */
   1568 // TODO create PushShort - create element and add - no alloc
   1569 void sArrayPushTiny(sArrayt **array, smallt* data) {
   1570 
   1571   /* // sanity checks */
   1572   /* if !array */
   1573   /*   return */
   1574 
   1575   if (!(*array)) {
   1576     // create array
   1577     isError(*array, allocSArray())
   1578       return;
   1579   }
   1580 
   1581   if ((*array)->count == 0) {
   1582     (*array)->data = data;;
   1583   }
   1584   else {
   1585     if ((*array)->count >= (*array)->maxCount) {
   1586       // realloc
   1587       //print 'ARRAY REALLOC'
   1588       sArrayt *tmp = realloc(*array, sizeof(sArrayt) + sizeof(smallt *) * ((*array)->count + SARRAY_REALLOC_STEPS));
   1589       if (!tmp) {
   1590         return;
   1591       }
   1592       else {
   1593         *array = tmp;
   1594         (*array)->maxCount = 1 + (*array)->count + SARRAY_REALLOC_STEPS-1;
   1595     }
   1596       }
   1597     smallt **arr = &((*array)->data);
   1598     arr[(*array)->count] = data;
   1599   }
   1600 
   1601   (*array)->count++;
   1602   return;
   1603 }
   1604 
   1605 /**
   1606  * prepend data in array
   1607  *
   1608  * when array is NULL, a new array is allocated
   1609  *
   1610  * the array is reallocated when count is greater than
   1611  * maxCount
   1612  *
   1613  * \param
   1614  *    array
   1615  *    data data to store
   1616  */
   1617 void sArrayPrependTiny(sArrayt **array, smallt* data) {
   1618 
   1619   /* // sanity checks */
   1620   /* if !array */
   1621   /*   return */
   1622 
   1623   if (!(*array)) {
   1624     // create array
   1625     isError(*array, allocSArray())
   1626       return;
   1627   }
   1628 
   1629   if ((*array)->count == 0) {
   1630     (*array)->data = data;;
   1631   }
   1632   else {
   1633     if ((*array)->count >= (*array)->maxCount) {
   1634       // realloc
   1635       //print 'ARRAY REALLOC'
   1636       sArrayt *tmp = realloc(*array, sizeof(sArrayt) + sizeof(smallt *) * ((*array)->count + SARRAY_REALLOC_STEPS));
   1637       if (!tmp) {
   1638         return;
   1639       }
   1640       else {
   1641         *array = tmp;
   1642         (*array)->maxCount = 1 + (*array)->count + SARRAY_REALLOC_STEPS-1;
   1643     }
   1644       }
   1645     smallt **arr = &((*array)->data);
   1646     // shift list
   1647     for (uint32_t i = (*array)->count; i > 0; i--) {
   1648       arr[i] = arr[i-1];
   1649     }
   1650     arr[0] = data;
   1651   }
   1652 
   1653   (*array)->count++;
   1654   return;
   1655 }
   1656 
   1657 /**
   1658  * pop object from array
   1659  */
   1660 smallt* sArrayPopTiny(sArrayt *array) {
   1661   smallt *r = NULL;
   1662 
   1663   /* if !array->count */
   1664   /*   return NULL */
   1665 
   1666   r = sArrayGetTiny(array, array->count -1);
   1667   array->count--;
   1668   return(r);
   1669 }
   1670 
   1671 /**
   1672  * dequeue object from array
   1673  */
   1674 smallt* sArrayDequeueTiny(sArrayt *array) {
   1675   smallt *r = NULL;
   1676 
   1677   /* if !array->count */
   1678   /*   return NULL */
   1679 
   1680   smallt **arr = &(array->data);
   1681   r            = arr[0];
   1682   // shift list
   1683   for (uint32_t i = 1 ; i < array->count ; i++) {
   1684     arr[i-1] = arr[i];
   1685   }
   1686   array->count--;
   1687   return(r);
   1688 }
   1689 
   1690 /**
   1691  * get pointer to object at index
   1692  *
   1693  * \param
   1694  *    array
   1695  *    index in array
   1696  * \return
   1697  *    pointer to object at index
   1698  */
   1699 smallt** sArrayGetP(sArrayt *array, uint32_t index) {
   1700 
   1701   return(&(((smallt **) &(array->data))[index]));
   1702 }
   1703 
   1704 /**
   1705  * get object at index
   1706  *
   1707  * \param
   1708  *    array
   1709  *    index in array
   1710  * \return
   1711  *    object at index
   1712  */
   1713 smallt* sArrayGetTiny(sArrayt *array, uint32_t index) {
   1714 
   1715   return(((smallt **) &(array->data))[index]);
   1716 }
   1717 
   1718 /**
   1719  * set value at index
   1720  *
   1721  * the previous element is not freed.
   1722  * This is useful for updating arrays, dictionaries and strings in the array
   1723  *
   1724  * \param
   1725  *    array
   1726  *    index where the value is set
   1727  *    value to store
   1728  */
   1729 void sArraySetShortTiny(sArrayt *array, uint32_t index, smallt *value) {
   1730 
   1731   ((smallt **) &(array->data))[index] = value;
   1732 }
   1733 
   1734 /**
   1735  * set value at index
   1736  *
   1737  * the previous element is not freed.
   1738  * This is useful for updating arrays, dictionaries and strings in the array
   1739  *
   1740  * \param
   1741  *    array
   1742  *    index where the value is set
   1743  *    value to store
   1744  */
   1745 void sArraySetP(sArrayt *array, uint32_t index, smallt *value) {
   1746 
   1747   sArraySetShortTiny(array, index, value);
   1748 }
   1749 
   1750 /**
   1751  * set value at index
   1752  *
   1753  * the previous element is freed.
   1754  * The new data replaces the previous data
   1755  *
   1756  * \param
   1757  *    array
   1758  *    index where the value is set
   1759  *    value to store
   1760  */
   1761 void sArraySetTiny(sArrayt *array, uint32_t index, smallt *value) {
   1762 
   1763   if (value == (((smallt **) &(array->data))[index])) {
   1764     // value is same element as the element already in the array
   1765     return;
   1766   }
   1767   sFree(((smallt **) &(array->data))[index]);
   1768   sArraySetShortTiny(array, index, value);
   1769 }
   1770 
   1771 /**
   1772  * reverse element order
   1773  *
   1774  * the last element becomes the first one
   1775  *
   1776  * \param
   1777  *    array to reverse
   1778  * \return
   1779  *    1 success
   1780  *    0 error
   1781  */
   1782 int sArrayReverseTiny(sArrayt *array) {
   1783 
   1784   /* if !array->count */
   1785   /*   return -1 */
   1786 
   1787   smallt **arr = &(array->data);
   1788   for (uint32_t i = 0 ; i < array->count/2 ; i++) {
   1789     smallt *a              = arr[i];
   1790     arr[i]                 = arr[array->count-1 -i];
   1791     arr[array->count-1 -i] = a;
   1792   }
   1793   return(1);
   1794 }
   1795 
   1796 /**
   1797  * delete element at index
   1798  *
   1799  * the element is freed and NULL is set at index
   1800  * count is unchanged
   1801  *
   1802  * \param
   1803  *    array
   1804  *    index
   1805  */
   1806 void sArrayDelTiny(sArrayt *array, uint32_t index) {
   1807 
   1808   sArraySetTiny(array, index, NULL);
   1809 }
   1810 
   1811 /**
   1812  * delete range and shift elements
   1813  *
   1814  * the elements are freed
   1815  * and count is reduced
   1816  *
   1817  * the range [start, end] is not checked for validity
   1818  *
   1819  * \param
   1820  *    array
   1821  * \param
   1822  *    start
   1823  * \param
   1824  *    end
   1825  */
   1826 void sArrayDelRangeTiny(sArrayt *array, uint32_t start, uint32_t end) {
   1827 
   1828   smallt **arr = &(array->data);
   1829 
   1830   // free elements in range start, end
   1831   for (uint32_t i = start ; i < end ; i++) {
   1832     sFree(arr[i]);
   1833   }
   1834 
   1835   // copy pointers from range end, array->count to start
   1836   for (uint32_t i = 0 ; i < (array->count - end) ; i ++) {
   1837     arr[start+i] = arr[end + i];;
   1838   }
   1839 
   1840   array->count -= end - start;
   1841 }
   1842 
   1843 /**
   1844  * get buffer in small bytes
   1845  *
   1846  * \param
   1847  *    bytes small bytes
   1848  * \return
   1849  *    pointer to data in small bytes
   1850  *    NULL when bytes is NULL or bytes is not of type sBytes
   1851  */
   1852 void* sBytesGet(sBytest *bytes) {
   1853 
   1854   if (!bytes || !isSType(bytes, BYTES)) {
   1855     return(NULL);
   1856   }
   1857 
   1858   return(sBytesGetTiny(bytes));
   1859 }
   1860 
   1861 /**
   1862  * get buffer in small bytes
   1863  *
   1864  * \param
   1865  *    bytes small bytes
   1866  * \return
   1867  *    pointer to data in small bytes
   1868  */
   1869 void* sBytesGetTiny(sBytest *bytes) {
   1870 
   1871   return(&(bytes->data));
   1872 }
   1873 
   1874 /**
   1875  * push char to bytes
   1876  *
   1877  * when bytes is NULL, a new small bytes object is allocated
   1878  *
   1879  * the small bytes object is reallocated
   1880  *
   1881  * \param
   1882  *    bytes small bytes
   1883  *    data char to push
   1884  */
   1885 void sBytesPush(sBytest **bytes, char data) {
   1886 
   1887   if (!(*bytes)) {
   1888     // create bytes
   1889     isError(*bytes, allocSBytes())
   1890       return;
   1891   }
   1892 
   1893   if ((*bytes)->count == 0) {
   1894     (*bytes)->data = data;;
   1895   }
   1896   else {
   1897     sBytest *tmp = realloc(*bytes, sizeof(sBytest) + sizeof(char) * ((*bytes)->count));
   1898     if (!tmp) {
   1899       return;
   1900     }
   1901     else {
   1902       *bytes = tmp;
   1903       (&((*bytes)->data))[(*bytes)->count] = data;
   1904   }
   1905     }
   1906 
   1907   (*bytes)->count++;
   1908   return;
   1909 }
   1910 
   1911 /**
   1912  * push data buffer to bytes
   1913  *
   1914  * when bytes is NULL, a new small bytes object is allocated
   1915  *
   1916  * the small bytes object is reallocated
   1917  *
   1918  * when data is NULL, the function does nothing
   1919  *
   1920  * \param
   1921  *    bytes small bytes
   1922  *    data buffer to push
   1923  *    size size of buffer
   1924  */
   1925 void sBytesPushBuffer(sBytest **bytes, void* data, uint32_t size) {
   1926 
   1927   if (!(*bytes)) {
   1928     // create bytes
   1929     *bytes          = allocSBytes();
   1930   }
   1931 
   1932   if (!data || !size) {
   1933     return;
   1934   }
   1935 
   1936   sBytesPushBufferTiny(bytes, data, size);
   1937 }
   1938 
   1939 
   1940 /**
   1941  * push data buffer to bytes
   1942  *
   1943  * the small bytes object is reallocated
   1944  *
   1945  * \param
   1946  *    bytes small bytes
   1947  *    data buffer to push
   1948  *    size size of buffer
   1949  */
   1950 void sBytesPushBufferTiny(sBytest **bytes, void* data, uint32_t size) {
   1951 
   1952   if ((*bytes)->count == 0) {
   1953     sBytest *tmp = realloc(*bytes, sizeof(sBytest) + sizeof(char) * (size-1));
   1954     if (!tmp) {
   1955       return;
   1956     }
   1957     else {
   1958       *bytes = tmp;
   1959       memcpy(&((*bytes)->data), data, size);
   1960       (*bytes)->count = size;;
   1961   }
   1962     }
   1963   else {
   1964     sBytest *tmp = realloc(*bytes, sizeof(sBytest) + sizeof(char) * ((*bytes)->count + size-1));
   1965     if (!tmp) {
   1966       return;
   1967     }
   1968     else {
   1969       *bytes = tmp;
   1970       memcpy((&((*bytes)->data))+(*bytes)->count, data, size);
   1971       (*bytes)->count += size;;
   1972   }
   1973     }
   1974   return;
   1975 }
   1976 
   1977 /**
   1978  * serialize object to small bytes
   1979  *
   1980  * \param
   1981  *    obj object
   1982  * \return
   1983  *    small bytes object representing obj
   1984  *    NULL when obj is NULL
   1985  */
   1986 sBytest *sSerial(smallt *obj) {
   1987 
   1988   if (!obj) {
   1989     return(NULL);
   1990   }
   1991 
   1992   return(sSerialTiny(obj));
   1993 }
   1994 
   1995 /**
   1996  * serialize object to small bytes
   1997  *
   1998  * All elements are serialized recursively
   1999  *
   2000  * the data in containers is not serialized
   2001  *
   2002  * \param
   2003  *    obj object
   2004  * \return
   2005  *    small bytes object representing obj
   2006  */
   2007 // TODO reimplement using loops
   2008 // TODO serialize simple types
   2009 sBytest *sSerialTiny(smallt *obj) {
   2010   sBytest *r = NULL;
   2011   sBytest *B = NULL;
   2012 
   2013   switch(obj->type) {
   2014     case UNDEFINED:
   2015       sBytesPush(&r, obj->type);
   2016       break;
   2017     case BOOL:
   2018       sBytesPush(&r, obj->type);
   2019       sBytesPushBuffer(&r, &((sBoolt *)&(obj->type))->value, sizeof(bool));
   2020       break;
   2021     case CONTAINER:
   2022       sBytesPush(&r, obj->type);
   2023       break;
   2024     case DICT:
   2025       sDictSerialElementsTiny(&r, (sDictt *)&(obj->type));
   2026       break;
   2027     case DOUBLE:
   2028       sBytesPush(&r, obj->type);
   2029       sBytesPushBuffer(&r, &((sDoublet *)&(obj->type))->value, sizeof(double));
   2030       break;
   2031     case INT:
   2032       sBytesPush(&r, obj->type);
   2033       sBytesPushBuffer(&r, &((sIntt *)&(obj->type))->value, sizeof(int64_t));
   2034       break;
   2035     case STRING:
   2036       sBytesPush(&r, obj->type);
   2037       sBytesPushBuffer(&r, &((sStringt *)&(obj->type))->data, (uint32_t)sizeof(sStringt) + (uint32_t)strlen(&(((sStringt *)&(obj->type))->data)) -1);
   2038       break;
   2039     case ARRAY:
   2040       sArraySerialElementsTiny(&r, (sArrayt *)&(obj->type));
   2041       break;
   2042     case BYTES:
   2043       sBytesPush(&r, obj->type);
   2044       B = (sBytest *)&(obj->type);
   2045       sBytesPushBuffer(&r, &(B->count), sizeof(uint32_t));
   2046       sBytesPushBuffer(&r, &(B->data), B->count);
   2047       break;
   2048     default:
   2049       logME(libsheepyErrorMask, "Unsupported object type.");
   2050   }
   2051   return(r);
   2052 }
   2053 
   2054 /**
   2055  * serialize dictionary
   2056  *
   2057  * the serialized dict is pushed to r.
   2058  * All elements are serialized recursively
   2059  *
   2060  * the data in containers is not serialized
   2061  *
   2062  * \param
   2063  *   r small bytes object
   2064  *   dict dictionary to serialize
   2065  */
   2066 void sDictSerialElementsTiny(sBytest **r, sDictt *dict) {
   2067   sBytest *B = NULL;
   2068 
   2069   sBytesPush(r, dict->type);
   2070   sBytesPushBuffer(r, &(dict->count), sizeof(uint32_t));
   2071 
   2072   forEachSDict(dict, e) {
   2073     if (e->key) {
   2074       sBytesPushBuffer(r, e->key, (uint32_t)strlen(e->key) + 1);
   2075       sBytesPush(r, e->data->type);
   2076 
   2077       switch(e->data->type) {
   2078         case UNDEFINED:
   2079           break;
   2080         case BOOL:
   2081           sBytesPushBuffer(r, &((sBoolt *)(e->data))->value, sizeof(bool));
   2082           break;
   2083         case CONTAINER:
   2084           break;
   2085         case DICT:
   2086           // decrease to overwrite the e->type since sDictSerialElementsTiny stores the type
   2087           // again
   2088           (*r)->count--;
   2089           sDictSerialElementsTiny(r, (sDictt *)(e->data));
   2090           break;
   2091         case DOUBLE:
   2092           sBytesPushBuffer(r, &((sDoublet *)(e->data))->value, sizeof(double));
   2093           break;
   2094         case INT:
   2095           sBytesPushBuffer(r, &((sIntt *)(e->data))->value, sizeof(int64_t));
   2096           break;
   2097         case STRING:
   2098           sBytesPushBuffer(r, &((sStringt *)(e->data))->data, (uint32_t)sizeof(sStringt) + (uint32_t)strlen(&(((sStringt *)(e->data))->data)) -1);
   2099           break;
   2100         case ARRAY:
   2101           // decrease to overwrite the e->type since sDictSerialElementsTiny stores the type
   2102           // again
   2103           (*r)->count--;
   2104           sArraySerialElementsTiny(r, (sArrayt *)(e->data));
   2105           break;
   2106         case BYTES:
   2107           B = (sBytest *)(e->data);
   2108           sBytesPushBuffer(r, &(B->count), sizeof(uint32_t));
   2109           sBytesPushBuffer(r, &(B->data), B->count);
   2110           break;
   2111         default:
   2112           logME(libsheepyErrorMask, "Unsupported object type.");
   2113       }
   2114   }
   2115     }
   2116   return;
   2117 }
   2118 
   2119 /**
   2120  * serialize array
   2121  *
   2122  * the serialized array is pushed to r.
   2123  * All elements are serialized recursively
   2124  *
   2125  * the data in containers is not serialized
   2126  *
   2127  * \param
   2128  *   r small bytes object
   2129  *   array to serialize
   2130  */
   2131 void sArraySerialElementsTiny(sBytest **r, sArrayt *array) {
   2132   sBytest *B = NULL;
   2133 
   2134   sBytesPush(r, array->type);
   2135   sBytesPushBuffer(r, &(array->count), sizeof(uint32_t));
   2136 
   2137   forEachSArray(array, e) {
   2138     if (!e) {
   2139       // empty slots are represented as undefined elements
   2140       sBytesPush(r, UNDEFINED);
   2141     }
   2142     else {
   2143       sBytesPush(r, e->type);
   2144 
   2145       switch(e->type) {
   2146         case UNDEFINED:
   2147           break;
   2148         case BOOL:
   2149           sBytesPushBuffer(r, &((sBoolt *)e)->value, sizeof(bool));
   2150           break;
   2151         case CONTAINER:
   2152           break;
   2153         case DICT:
   2154           // decrease to overwrite the e->type since sDictSerialElementsTiny stores the type
   2155           // again
   2156           (*r)->count--;
   2157           sDictSerialElementsTiny(r, (sDictt *)e);
   2158           break;
   2159         case DOUBLE:
   2160           sBytesPushBuffer(r, &((sDoublet *)e)->value, sizeof(double));
   2161           break;
   2162         case INT:
   2163           sBytesPushBuffer(r, &((sIntt *)e)->value, sizeof(int64_t));
   2164           break;
   2165         case STRING:
   2166           sBytesPushBuffer(r, &((sStringt *)e)->data, (uint32_t)sizeof(sStringt) + (uint32_t)strlen(&(((sStringt *)e)->data)) -1);
   2167           break;
   2168         case ARRAY:
   2169           // decrease to overwrite the e->type since sDictSerialElementsTiny stores the type
   2170           // again
   2171           (*r)->count--;
   2172           sArraySerialElementsTiny(r, (sArrayt *)e);
   2173           break;
   2174         case BYTES:
   2175           B = (sBytest *)e;
   2176           sBytesPushBuffer(r, &(B->count), sizeof(uint32_t));
   2177           sBytesPushBuffer(r, &(B->data), B->count);
   2178           break;
   2179         default:
   2180           logME(libsheepyErrorMask, "Unsupported object type.");
   2181       }
   2182   }
   2183     }
   2184   return;
   2185 }
   2186 
   2187 /**
   2188  * deserialize small bytes object
   2189  *
   2190  * \param
   2191  *    obj small bytes
   2192  * \return
   2193  *    new deserialized object
   2194  *    NULL when obj is NULL or obj is empty
   2195  */
   2196 smallt* sDeserial(sBytest *obj) {
   2197 
   2198   if (!obj || !obj->count) {
   2199     return(NULL);
   2200   }
   2201 
   2202   return(sDeserialTiny(obj));
   2203 }
   2204 
   2205 /**
   2206  * deserialize small bytes object
   2207  *
   2208  * \param
   2209  *    obj small bytes
   2210  * \return
   2211  *    new deserialized object
   2212  *    NULL when there is a malloc error
   2213  */
   2214 // TODO reimplement using loops
   2215 smallt* sDeserialTiny(sBytest *obj) {
   2216   smallt   *r = NULL;
   2217   bool *b = NULL;
   2218   double *D = NULL;
   2219   int64_t *i = NULL;
   2220   char *s = NULL;
   2221   sBytest *B = NULL;
   2222   uint32_t *count = NULL;
   2223   char *data = NULL;
   2224 
   2225   switch(obj->data) {
   2226     case UNDEFINED:
   2227       r = (smallt *) allocSUndefined();
   2228       break;
   2229     case BOOL:
   2230       data = &(obj->data)+1;
   2231       b = (bool *)data;
   2232       r = (smallt *) allocSBool(*b);
   2233       break;
   2234     case CONTAINER:
   2235       r = (smallt *) allocSContainer(NULL);
   2236       break;
   2237     case DICT:
   2238       data = (char *)&(obj->data)+1;
   2239       sDictDeserialElementsTiny((sDictt **)&r, &data);
   2240       break;
   2241     case DOUBLE:
   2242       data = &(obj->data)+1;
   2243       D = (double *)data;
   2244       r = (smallt *) allocSDouble(*D);
   2245       break;
   2246     case INT:
   2247       data = &(obj->data)+1;
   2248       i = (int64_t *)data;
   2249       r = (smallt *) allocSInt(*i);
   2250       break;
   2251     case STRING:
   2252       s = (char *)&(obj->data)+1;
   2253       r = (smallt *) allocSStringTiny(s);
   2254       break;
   2255     case ARRAY:
   2256       data = (char *)&(obj->data)+1;
   2257       sArrayDeserialElementsTiny((sArrayt **)&r, &data);
   2258       break;
   2259     case BYTES:
   2260       isError(B, allocSBytes()) return(NULL);
   2261       data  = &(obj->data)+1;
   2262       count = (uint32_t *)data;
   2263       s     = (char *)data + sizeof(uint32_t);
   2264       sBytesPushBuffer(&B, s, *count);
   2265       r = (smallt *)B;
   2266       break;
   2267     default:
   2268       logME(libsheepyErrorMask, "Unsupported object type.");
   2269   }
   2270 
   2271   return(r);
   2272 }
   2273 
   2274 /**
   2275  * deserialize dictionary from data
   2276  *
   2277  * a new dictionary is allocated
   2278  *
   2279  * \param
   2280  *    dict dictionary holding the elements
   2281  *    data serialized dictionary
   2282  */
   2283 void sDictDeserialElementsTiny(sDictt **dict, char **data) {
   2284   sUndefinedt *u = NULL;
   2285   bool *b = NULL;
   2286   sBoolt *bo = NULL;
   2287   sContainert *c = NULL;
   2288   double *D = NULL;
   2289   sDoublet *Do = NULL;
   2290   sDictt *d = NULL;
   2291   int64_t *i = NULL;
   2292   sIntt *io = NULL;
   2293   char *s = NULL;
   2294   sStringt *so = NULL;
   2295   sArrayt *a = NULL;
   2296   sBytest *B = NULL;
   2297   uint32_t *count = NULL;
   2298   uint32_t dictCount;
   2299 
   2300   dictCount  = *((uint32_t *)(*data));
   2301   *data     += sizeof(uint32_t);
   2302 
   2303   if (!dictCount) {
   2304     *dict = allocSDict();
   2305     return;
   2306   }
   2307 
   2308   for (uint32_t counter = 0 ; counter < dictCount ; counter++) {
   2309     char type;
   2310     char *key;
   2311     key    = *data;
   2312     *data += strlen(key)+1;
   2313     type   = *((*data)++);
   2314 
   2315     switch(type) {
   2316       case UNDEFINED:
   2317         u = allocSUndefined();
   2318         sDictPushTiny(dict, key, (smallt *) u);
   2319         break;
   2320       case BOOL:
   2321         b      = (bool *)(*data);
   2322         *data += sizeof(bool);
   2323         bo     = allocSBool(*b);
   2324         sDictPushTiny(dict, key, (smallt *) bo);
   2325         break;
   2326       case CONTAINER:
   2327         c = allocSContainer(NULL);
   2328         sDictPushTiny(dict, key, (smallt *) c);
   2329         break;
   2330       case DICT:
   2331         d = NULL;
   2332         sDictDeserialElementsTiny(&d, data);
   2333         sDictPushTiny(dict, key, (smallt *) d);
   2334         break;
   2335       case DOUBLE:
   2336         D      = (double *)(*data);
   2337         *data += sizeof(double);
   2338         Do     = allocSDouble(*D);
   2339         sDictPushTiny(dict, key, (smallt *) Do);
   2340         break;
   2341       case INT:
   2342         i      = (int64_t *)(*data);
   2343         *data += sizeof(int64_t);
   2344         io     = allocSInt(*i);
   2345         sDictPushTiny(dict, key, (smallt *) io);
   2346         break;
   2347       case STRING:
   2348         s      = (char *)(*data);
   2349         *data += strlen(s)+1;
   2350         so     = allocSStringTiny(s);
   2351         sDictPushTiny(dict, key, (smallt *) so);
   2352         break;
   2353       case ARRAY:
   2354         a = NULL;
   2355         sArrayDeserialElementsTiny(&a, data);
   2356         sDictPushTiny(dict, key, (smallt *) a);
   2357         break;
   2358       case BYTES:
   2359         isError(B, allocSBytes()) {
   2360           return;
   2361         }
   2362         count  = (uint32_t *)(*data);
   2363         *data += sizeof(uint32_t);
   2364         s      = *data;
   2365         *data += *count;
   2366         sBytesPushBuffer(&B, s, *count);
   2367         sDictPushTiny(dict, key, (smallt *) B);
   2368         break;
   2369       default:
   2370         logME(libsheepyErrorMask, "Unsupported object type.");
   2371     }
   2372 }
   2373   }
   2374 
   2375 /**
   2376  * deserialize array from data
   2377  *
   2378  * a new array is allocated
   2379  *
   2380  * \param
   2381  *    array holding the elements
   2382  *    data serialized dictionary
   2383  */
   2384 void sArrayDeserialElementsTiny(sArrayt **array, char **data) {
   2385   sUndefinedt *u = NULL;
   2386   bool *b = NULL;
   2387   sBoolt *bo = NULL;
   2388   sContainert *c = NULL;
   2389   double *D = NULL;
   2390   sDoublet *Do = NULL;
   2391   sDictt *d = NULL;
   2392   int64_t *i = NULL;
   2393   sIntt *io = NULL;
   2394   char *s = NULL;
   2395   sStringt *so = NULL;
   2396   sArrayt *a = NULL;
   2397   sBytest *B = NULL;
   2398   uint32_t *count = NULL;
   2399   uint32_t arrayCount;
   2400 
   2401   arrayCount  = *((uint32_t *)(*data));
   2402   *data     += sizeof(uint32_t);
   2403 
   2404   if (!arrayCount) {
   2405     *array = allocSArray();
   2406     return;
   2407   }
   2408 
   2409   for (uint32_t counter = 0 ; counter < arrayCount ; counter++) {
   2410     char type;
   2411     type  = *((*data)++);
   2412 
   2413     switch(type) {
   2414       case UNDEFINED:
   2415         u = allocSUndefined();
   2416         sArrayPushTiny(array, (smallt *) u);
   2417         break;
   2418       case BOOL:
   2419         b      = (bool *)(*data);
   2420         *data += sizeof(bool);
   2421         bo     = allocSBool(*b);
   2422         sArrayPushTiny(array, (smallt *) bo);
   2423         break;
   2424       case CONTAINER:
   2425         c = allocSContainer(NULL);
   2426         sArrayPushTiny(array, (smallt *) c);
   2427         break;
   2428       case DICT:
   2429         d = NULL;
   2430         sDictDeserialElementsTiny(&d, data);
   2431         sArrayPushTiny(array, (smallt *) d);
   2432         break;
   2433       case DOUBLE:
   2434         D      = (double *)(*data);
   2435         *data += sizeof(double);
   2436         Do     = allocSDouble(*D);
   2437         sArrayPushTiny(array, (smallt *) Do);
   2438         break;
   2439       case INT:
   2440         i      = (int64_t *)(*data);
   2441         *data += sizeof(int64_t);
   2442         io     = allocSInt(*i);
   2443         sArrayPushTiny(array, (smallt *) io);
   2444         break;
   2445       case STRING:
   2446         s      = (char *)(*data);
   2447         *data += strlen(s)+1;
   2448         so     = allocSStringTiny(s);
   2449         sArrayPushTiny(array, (smallt *) so);
   2450         break;
   2451       case ARRAY:
   2452         a = NULL;
   2453         sArrayDeserialElementsTiny(&a, data);
   2454         sArrayPushTiny(array, (smallt *) a);
   2455         break;
   2456       case BYTES:
   2457         isError(B, allocSBytes()) {
   2458           return;
   2459         }
   2460         count  = (uint32_t *)(*data);
   2461         *data += sizeof(uint32_t);
   2462         s      = *data;
   2463         *data += *count;
   2464         sBytesPushBuffer(&B, s, *count);
   2465         sArrayPushTiny(array, (smallt *) B);
   2466         break;
   2467       default:
   2468         logME(libsheepyErrorMask, "Unsupported object type.");
   2469     }
   2470 }
   2471   }