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 }