├── .gitignore ├── LICENSE ├── README.md ├── example ├── README.md ├── item.c ├── item.h ├── json2cwpack2json.c ├── runExample.sh └── test1.json ├── goodies ├── README.md ├── basic-contexts │ ├── README.md │ ├── basic_contexts.c │ └── basic_contexts.h ├── dump │ ├── README.md │ ├── cwpack_dump.c │ ├── runCWpack_dump.sh │ ├── testdump.msgpack │ └── testdump2.msgpack ├── numeric-extensions │ ├── README.md │ ├── numeric_extensions.c │ ├── numeric_extensions.h │ ├── numeric_extensions_test.c │ └── runNumericExtensionsTest.sh ├── objC │ ├── CWPackContext.h │ ├── CWPackContext.m │ ├── README.md │ ├── Technique.md │ └── obsolete │ │ ├── README.md │ │ ├── cwpack_objc.h │ │ └── cwpack_objc.m ├── swift │ ├── CWPack.swift │ ├── CWPackable.swift │ └── README.md └── utils │ ├── README.md │ ├── cwpack_utils.c │ └── cwpack_utils.h ├── src ├── README.md ├── cwpack.c ├── cwpack.h ├── cwpack_config.h └── cwpack_internals.h └── test ├── README.md ├── cwpack_module_test.c ├── cwpack_performance_test.c ├── runModuleTest.sh └── runPerformanceTest.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Finder --------------------------- 2 | .DS_Store 3 | 4 | # Explicit no GIT 5 | *.noGIT 6 | 7 | # Object files 8 | *.o 9 | 10 | # Executables 11 | cwpack_dump 12 | cwpackModuleTest 13 | json2cwpack2json 14 | 15 | # Data files 16 | *.msgpack.json 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Claes Wihlborg 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CWPack 2 | 3 | CWPack is a lightweight and yet complete implementation of the 4 | [MessagePack](http://msgpack.org) serialization format 5 | [version 5](https://github.com/msgpack/msgpack/blob/master/spec.md). 6 | It also supports the Timestamp extension type. 7 | 8 | ## Excellent Performance 9 | 10 | Together with [MPack](https://github.com/ludocode/mpack), CWPack is the fastest open-source messagepack implementation. Both totally outperform 11 | [CMP](https://github.com/camgunz/cmp) and [msgpack-c](https://github.com/msgpack/msgpack-c) 12 | 13 | ## Design 14 | 15 | CWPack does no memory allocations and no file handling in its basic setup. All that is done outside of CWPack. Example extensions are included. 16 | 17 | CWPack is working against memory buffers. User defined handlers are called when buffers are filled up (packing) or needs refill (unpack). 18 | 19 | Containers (arrays, maps) are read/written in parts, first the item containing the size and then the contained items one by one. Exception to this is the `cw_skip_items` function which skip whole containers. 20 | 21 | ## Example 22 | 23 | Pack and unpack example from the MessagePack home page: 24 | 25 | ```c 26 | void example (void) 27 | { 28 | cw_pack_context pc; 29 | char buffer[20]; 30 | cw_pack_context_init (&pc, buffer, 20, 0); 31 | 32 | cw_pack_map_size (&pc, 2); 33 | cw_pack_str (&pc, "compact", 7); 34 | cw_pack_boolean (&pc, true); 35 | cw_pack_str (&pc, "schema", 6); 36 | cw_pack_unsigned (&pc, 0); 37 | 38 | if (pc.return_code != CWP_RC_OK) ERROR; 39 | int length = pc.current - pc.start; 40 | if (length != 18) ERROR; 41 | 42 | cw_unpack_context uc; 43 | cw_unpack_context_init (&uc, pc.start, length, 0); 44 | 45 | if (cw_unpack_next_map_size(&uc) != 2) ERROR; 46 | if (cw_unpack_next_str_lengh(&uc) != 7) ERROR; 47 | if (strncmp("compact", uc.item.as.str.start, 7)) ERROR; 48 | if (cw_unpack_next_boolean(&uc) != true) ERROR; 49 | if (cw_unpack_next_str_lengh(&uc) != 6) ERROR; 50 | if (strncmp("schema", uc.item.as.str.start, 6)) ERROR; 51 | if (cw_unpack_next_signed32(&uc) != 0) ERROR; 52 | 53 | if (uc.return_code != CWP_RC_OK) ERROR; 54 | cw_unpack_next(&uc); 55 | if (uc.return_code != CWP_RC_END_OF_INPUT) ERROR; 56 | } 57 | ``` 58 | 59 | In the examples folder there are more examples. 60 | 61 | ## Backward compatibility 62 | 63 | CWPack may be run in compatibility mode. It affects only packing; EXT & TIMESTAMP is considered illegal, BIN are transformed to STR and generation of STR8 is supressed. 64 | 65 | ## Error handling 66 | 67 | When an error is detected in a context, the context is stopped and all future calls to that context are immediatly returned without any actions. Thus it is possible to make some calls and delay error checking until all calls are done. 68 | 69 | CWPack does not check for illegal values (e.g. in STR for illegal unicode characters). 70 | 71 | ## Build 72 | 73 | CWPack consists of a single src file and three header files. It is written in strict ansi C and the files are together ~ 1.4K lines. No separate build is neccesary, just include the files in your own build. 74 | 75 | CWPack has no dependencies to other libraries. 76 | 77 | ## Test 78 | 79 | Included in the test folder are a module test and a performance test and shell scripts to run them. 80 | 81 | # Objective-C 82 | 83 | CWPack also contains an Objective-C interface. The MessagePack home page example would look like: 84 | 85 | ```C 86 | CWPackContext *pc = [CWPackContext newWithContext:my_cw_pack_context]; 87 | [pc packObject:@{@"compact":@YES, @"schema":@0}]; 88 | 89 | CWUnpackContext *uc = [CWUnpackContext newWithContext:my_cw_unpack_context]; 90 | NSDictionary *dict = [uc unpackNextObject]; 91 | ``` 92 | 93 | # Swift 94 | 95 | CWPack also contains a Swift interface. The MessagePack home page example would pack like: 96 | 97 | ``` 98 | let packer = CWDataPacker() 99 | packer + DictionaryHeader(2) + "compact" + true + "schema" + 0 100 | let data = packer.data 101 | 102 | ``` 103 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # CWPack / Example 2 | 3 | The example contains a program that takes a json file and converts it to a messagePack file, then converts the latter back to json. 4 | 5 | In the script runExample.sh the 2 json files are also diffed. 6 | 7 | The files `item.*` contains a memory tree representation of json data and the conversion routines: 8 | 9 | - Item Tree To Json File 10 | - Item Tree To MessagePack File 11 | - Json File To Item Tree 12 | - MessagePack File To Item Tree 13 | 14 | The conversion routines are just examples and not of production quality. 15 | -------------------------------------------------------------------------------- /example/item.c: -------------------------------------------------------------------------------- 1 | /* CWPack/example - item.c */ 2 | /* 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2017 Claes Wihlborg 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 8 | software and associated documentation files (the "Software"), to deal in the Software 9 | without restriction, including without limitation the rights to use, copy, modify, 10 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 11 | persons to whom the Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or 14 | substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 17 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | DAMAGES OR OTHER 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 SOFTWARE. 21 | */ 22 | 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "item.h" 30 | #include "basic_contexts.h" 31 | 32 | 33 | 34 | void freeItem3 (item_root* root) 35 | { 36 | int i; 37 | item_container* ic; 38 | switch (root->item_type) 39 | { 40 | case ITEM_MAP: 41 | case ITEM_ARRAY: 42 | ic = (item_container*)root; 43 | for (i=0; i < ic->count; i++) 44 | { 45 | freeItem3(ic->items[i]); 46 | } 47 | 48 | default: 49 | free(root); 50 | } 51 | } 52 | 53 | /********************************** ITEM-TREE to JSON FILE *********************/ 54 | 55 | 56 | static void item32jsonFile (FILE* file, item_root* item) 57 | { 58 | char tmp[30]; 59 | int i,j = 0; 60 | item_container* jc; 61 | char* cp; 62 | char c; 63 | unsigned u, ti; 64 | static unsigned tabs = 0; 65 | 66 | #define NEW_LINE {fprintf (file, "\n"); for (ti=0; tiitem_type) 69 | { 70 | case ITEM_MAP: 71 | jc = (item_container*)item; 72 | fprintf (file, "{"); 73 | tabs++; 74 | for( i=0; i< jc->count; i++) 75 | { 76 | if (i) fprintf (file, ","); 77 | NEW_LINE 78 | item32jsonFile (file, jc->items[i++]); 79 | fprintf(file, ": "); 80 | item32jsonFile (file, jc->items[i]); 81 | } 82 | tabs--; 83 | NEW_LINE 84 | fprintf (file, "}"); 85 | break; 86 | 87 | case ITEM_ARRAY: 88 | jc = (item_container*)item; 89 | fprintf (file, "["); 90 | tabs++; 91 | for( i=0; i< jc->count; i++) 92 | { 93 | if (i) fprintf (file, ","); 94 | NEW_LINE 95 | item32jsonFile (file, jc->items[i]); 96 | } 97 | tabs--; 98 | NEW_LINE 99 | fprintf(file, "]"); 100 | break; 101 | 102 | case ITEM_NIL: 103 | fprintf (file, "null"); 104 | break; 105 | 106 | case ITEM_TRUE: 107 | fprintf (file, "true"); 108 | break; 109 | 110 | case ITEM_FALSE: 111 | fprintf (file, "false"); 112 | break; 113 | 114 | case ITEM_INTEGER: 115 | fprintf (file, "%lld", ((item_integer*)item)->value); 116 | break; 117 | 118 | case ITEM_REAL: 119 | sprintf (tmp, "%-25.15g", ((item_real*)item)->value); 120 | for (i=0;i<30;i++) 121 | { 122 | if(tmp[i] == 0) 123 | break; 124 | if(tmp[i] == ' ') 125 | { 126 | tmp[i] = 0; 127 | break; 128 | } 129 | } 130 | fprintf (file, "%s", tmp); 131 | break; 132 | 133 | case ITEM_STRING: 134 | fprintf (file, "\""); 135 | cp = ((item_string*)item)->string; 136 | while ((c = *cp++)) 137 | { 138 | if (c & 0x80) { /* unicode, codepoint at most 16 bits */ 139 | if (c & 0x20) 140 | { 141 | u = c & 0x0f; 142 | j = 2; 143 | } 144 | else 145 | { 146 | u = c & 0x1f; 147 | j = 1; 148 | } 149 | for (i=0; i < j; i++) { 150 | u = (u << 6) | (*cp++ & 0x3f); 151 | } 152 | fprintf (file, "\\u%04x", u); 153 | } 154 | else 155 | switch (c) { 156 | case '"': fprintf (file, "\\\""); break; 157 | case '/': fprintf (file, "\\/"); break; 158 | case '\\': fprintf (file, "\\\\"); break; 159 | case 0x08: fprintf (file, "\\b"); break; /* BS */ 160 | case 0x09: fprintf (file, "\\t"); break; /* HT */ 161 | case 0x0a: fprintf (file, "\\n"); break; /* LF */ 162 | case 0x0c: fprintf (file, "\\f"); break; /* FF */ 163 | case 0x0d: fprintf (file, "\\r"); break; /* CR */ 164 | 165 | default: 166 | fprintf (file, "%c", c); 167 | break; 168 | } 169 | } 170 | fprintf (file, "\""); 171 | break; 172 | 173 | default: break; 174 | } 175 | } 176 | 177 | void item32JsonFile (FILE* file, item_root* item) 178 | { 179 | item32jsonFile (file, item); 180 | fprintf(file, "\n"); 181 | } 182 | 183 | 184 | 185 | /********************************** JSON FILE to ITEM-TREE *********************/ 186 | /* correct JSON is assumed. No error checks whatsoever!!! */ 187 | 188 | #define scanSpace while (**ptr == ' ' || **ptr == '\n' || **ptr == '\t') (*ptr)++ 189 | 190 | #define allocate_item(typ, typeMark, extra) \ 191 | malloc (sizeof(typ) + extra); \ 192 | result->item_type = typeMark 193 | 194 | 195 | static item_container* allocate_container(item_types type, int cnt) 196 | { 197 | item_container* result = allocate_item(item_container, type, cnt*sizeof(void*)); 198 | result->count = cnt; 199 | return result; 200 | } 201 | 202 | 203 | static item_root* jsonString2item3 (const char** ptr); /* prototype */ 204 | 205 | static item_container* pullMapPair (const char** ptr, int count) 206 | { 207 | item_container* result; 208 | scanSpace; 209 | item_root* it1 = jsonString2item3(ptr); 210 | scanSpace; 211 | (*ptr)++; /* ':' */ 212 | scanSpace; 213 | item_root* it2 = jsonString2item3(ptr); 214 | scanSpace; 215 | char c = *(*ptr)++; 216 | if (c == ',') 217 | result = pullMapPair (ptr, count + 2); 218 | else 219 | result = allocate_container (ITEM_MAP, count + 2); 220 | result->items[count] = it1; 221 | result->items[count+1] = it2; 222 | return result; 223 | } 224 | 225 | static item_container* pullArray (const char** ptr, int count) 226 | { 227 | item_container* result; 228 | scanSpace; 229 | item_root* it = jsonString2item3 (ptr); 230 | scanSpace; 231 | char c = *(*ptr)++; 232 | if (c == ',') 233 | result = pullArray (ptr, count + 1); 234 | else 235 | result = allocate_container (ITEM_ARRAY, count + 1); 236 | result->items[count] = it; 237 | return result; 238 | } 239 | 240 | static item_string* pullString (const char** ptr, int length) 241 | { 242 | item_string* result; 243 | char c = *(*ptr)++; 244 | if (c != '"') 245 | { 246 | int cl = 0; 247 | unsigned mask = 0; 248 | unsigned codepoint = (uint8_t)c; 249 | if (c == '\\') 250 | { 251 | c = *(*ptr)++; 252 | switch (c) { 253 | case '\\': codepoint = '\\'; break; 254 | case '/': codepoint = '/'; break; 255 | case '"': codepoint = '"'; break; 256 | case 'b': codepoint = '\b'; break; 257 | case 't': codepoint = '\t'; break; 258 | case 'n': codepoint = '\n'; break; 259 | case 'f': codepoint = '\f'; break; 260 | case 'r': codepoint = '\r'; break; 261 | case 'u': 262 | sscanf(*ptr,"%4x",&codepoint); 263 | *ptr += 4; 264 | if (codepoint & 0xff80) 265 | { 266 | if (codepoint & 0xf800) 267 | { 268 | cl = 2; 269 | mask = 0xe0; 270 | } 271 | else 272 | { 273 | cl = 1; 274 | mask = 0xc0; 275 | } 276 | } 277 | 278 | default: 279 | break; 280 | } 281 | } 282 | result = pullString (ptr, length + cl + 1); 283 | for (;cl > 0;cl--) 284 | { 285 | result->string[length+cl] = (codepoint & 0x3F) | 0x80; 286 | codepoint >>= 6; 287 | } 288 | result->string[length] = (char)(codepoint | mask); 289 | } 290 | else 291 | { 292 | result = allocate_item(item_string,ITEM_STRING,length + 1); 293 | result->string[length] = 0; 294 | } 295 | return result; 296 | } 297 | 298 | static item_root* jsonString2item3 (const char** ptr) 299 | { 300 | scanSpace; 301 | item_root* result = NULL; 302 | 303 | char c = *(*ptr)++; 304 | switch (c) { 305 | case '{': 306 | scanSpace; 307 | if (**ptr == '}') 308 | result = (item_root*)allocate_container (ITEM_MAP, 0); 309 | else 310 | result = (item_root*)pullMapPair (ptr, 0); 311 | break; 312 | 313 | case '[': 314 | scanSpace; 315 | if (**ptr == ']') 316 | result = (item_root*)allocate_container (ITEM_ARRAY, 0); 317 | else 318 | result = (item_root*)pullArray (ptr, 0); 319 | break; 320 | 321 | case '"': result = (item_root*)pullString (ptr, 0);break; 322 | case 'n': result = allocate_item(item_root,ITEM_NIL,0); *ptr+=3;break; 323 | case 't': result = allocate_item(item_root,ITEM_TRUE,0); *ptr+=3;break; 324 | case 'f': result = allocate_item(item_root,ITEM_FALSE,0); *ptr+=4;break; 325 | 326 | case '-': 327 | case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': 328 | { 329 | char buffer[100]; 330 | int i = 0; 331 | bool real = false;; 332 | buffer[i++] = c; 333 | c = **ptr; 334 | while (c == '-' || c == '+' || c == '.' || c == 'e' || c == 'E' || (('0' <= c) && (c <= '9'))) 335 | { 336 | buffer[i++] = c; 337 | if (c == '.' || c == 'e' || c == 'E') 338 | real = true; 339 | c = *++*ptr; 340 | } 341 | buffer[i++] = 0; 342 | if (real) 343 | { 344 | result = (item_root*)allocate_item(item_real,ITEM_REAL,0); 345 | double d; 346 | sscanf(buffer,"%lg",&d); 347 | ((item_real*)result)->value = d; 348 | } 349 | else 350 | { 351 | result = (item_root*)allocate_item(item_integer,ITEM_INTEGER,0); 352 | long d; 353 | sscanf(buffer,"%ld",&d); 354 | ((item_integer*)result)->value = d; 355 | } 356 | } 357 | break; 358 | 359 | default: 360 | break; 361 | } 362 | 363 | return result; 364 | } 365 | 366 | 367 | item_root* jsonFile2item3 (FILE* file) 368 | { 369 | fseek (file, 0, SEEK_END); 370 | long length = ftell(file); 371 | char* buffer = malloc (length+1); 372 | 373 | fseek (file, 0l, SEEK_SET); 374 | fread (buffer, 1, length, file); 375 | buffer[length] = 0; 376 | const char* ptr = buffer; 377 | item_root* result = jsonString2item3(&ptr); 378 | free(buffer); 379 | return result; 380 | } 381 | 382 | 383 | /********************************** ITEM-TREE to cwpack FILE *********************/ 384 | 385 | static void item32packContext(cw_pack_context* pc, item_root* item) 386 | { 387 | int i; 388 | item_container* ic; 389 | char* cp; 390 | 391 | switch (item->item_type) 392 | { 393 | case ITEM_MAP: 394 | ic = (item_container*)item; 395 | cw_pack_map_size(pc, ic->count / 2); 396 | for( i=0; i< ic->count; i++) 397 | item32packContext (pc, ic->items[i]); 398 | break; 399 | 400 | case ITEM_ARRAY: 401 | ic = (item_container*)item; 402 | cw_pack_array_size(pc, ic->count); 403 | for( i=0; i< ic->count; i++) 404 | item32packContext (pc, ic->items[i]); 405 | break; 406 | 407 | case ITEM_NIL: 408 | cw_pack_nil (pc); 409 | break; 410 | 411 | case ITEM_TRUE: 412 | cw_pack_boolean(pc, true); 413 | break; 414 | 415 | case ITEM_FALSE: 416 | cw_pack_boolean(pc, false); 417 | break; 418 | 419 | case ITEM_INTEGER: 420 | cw_pack_signed(pc, ((item_integer*)item)->value); 421 | break; 422 | 423 | case ITEM_REAL: 424 | cw_pack_double(pc, ((item_real*)item)->value); 425 | break; 426 | 427 | case ITEM_STRING: 428 | cp = ((item_string*)item)->string; 429 | cw_pack_str(pc, cp, (unsigned)strlen(cp)); 430 | break; 431 | 432 | default: break; 433 | } 434 | } 435 | 436 | void item32cwpackFile (FILE* file, item_root* item) 437 | { 438 | stream_pack_context spc; 439 | init_stream_pack_context(&spc, 10, file); 440 | item32packContext (&spc.pc, item); 441 | terminate_stream_pack_context(&spc); 442 | } 443 | 444 | 445 | /********************************** CWPACK FILE to ITEM-TREE *********************/ 446 | 447 | static item_root* packContext2item3 (cw_unpack_context* uc) 448 | { 449 | int i,dim; 450 | item_root* result; 451 | cw_unpack_next(uc); 452 | if (uc->return_code) 453 | exit(uc->return_code); 454 | item_container* ic; 455 | switch (uc->item.type) 456 | { 457 | case CWP_ITEM_NIL: 458 | result = allocate_item(item_root,ITEM_NIL,0); 459 | break; 460 | 461 | case CWP_ITEM_BOOLEAN: 462 | if (uc->item.as.boolean) 463 | { 464 | result = allocate_item(item_root,ITEM_TRUE,0); 465 | } 466 | else 467 | { 468 | result = allocate_item(item_root,ITEM_FALSE,0); 469 | } 470 | break; 471 | 472 | case CWP_ITEM_POSITIVE_INTEGER: 473 | case CWP_ITEM_NEGATIVE_INTEGER: 474 | result = (item_root*)allocate_item(item_integer,ITEM_INTEGER,0); 475 | ((item_integer*)result)->value = uc->item.as.i64; 476 | break; 477 | 478 | case CWP_ITEM_FLOAT: 479 | result = (item_root*)allocate_item(item_real,ITEM_REAL,0); 480 | ((item_real*)result)->value = uc->item.as.real; 481 | break; 482 | 483 | case CWP_ITEM_DOUBLE: 484 | result = (item_root*)allocate_item(item_real,ITEM_REAL,0); 485 | ((item_real*)result)->value = uc->item.as.long_real; 486 | break; 487 | 488 | case CWP_ITEM_STR: 489 | result = (item_root*)allocate_item(item_string,ITEM_STRING,uc->item.as.str.length + 1); 490 | strncpy(((item_string*)result)->string, (const char*)uc->item.as.str.start, uc->item.as.str.length); 491 | ((item_string*)result)->string[uc->item.as.str.length] = 0; 492 | break; 493 | 494 | case CWP_ITEM_MAP: 495 | dim = 2 * uc->item.as.map.size; 496 | ic = allocate_container(ITEM_MAP, dim); 497 | for (i=0; iitems[i] = packContext2item3 (uc); 500 | } 501 | result = (item_root*)ic; 502 | break; 503 | 504 | case CWP_ITEM_ARRAY: 505 | dim = uc->item.as.array.size; 506 | ic = allocate_container(ITEM_ARRAY, dim); 507 | for (i=0; iitems[i] = packContext2item3 (uc); 510 | } 511 | result = (item_root*)ic; 512 | break; 513 | 514 | default: 515 | result = NULL; 516 | break; 517 | } 518 | return result; 519 | } 520 | 521 | item_root* cwpackFile2item3 (FILE* file) 522 | { 523 | stream_unpack_context suc; 524 | init_stream_unpack_context(&suc, 0, file); 525 | item_root* result = packContext2item3(&suc.uc); 526 | terminate_stream_unpack_context(&suc); 527 | return result; 528 | } 529 | 530 | 531 | 532 | -------------------------------------------------------------------------------- /example/item.h: -------------------------------------------------------------------------------- 1 | /* CWPack/example - item.h */ 2 | /* 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2017 Claes Wihlborg 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 8 | software and associated documentation files (the "Software"), to deal in the Software 9 | without restriction, including without limitation the rights to use, copy, modify, 10 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 11 | persons to whom the Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or 14 | substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 17 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | DAMAGES OR OTHER 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 SOFTWARE. 21 | */ 22 | 23 | 24 | #ifndef item_h 25 | #define item_h 26 | 27 | 28 | 29 | 30 | /************** ITEMS **********************/ 31 | 32 | typedef enum { 33 | ITEM_MAP, 34 | ITEM_ARRAY, 35 | ITEM_NIL, 36 | ITEM_TRUE, 37 | ITEM_FALSE, 38 | ITEM_INTEGER, 39 | ITEM_REAL, 40 | ITEM_STRING 41 | } item_types; 42 | 43 | typedef struct { 44 | item_types item_type; 45 | } item_root; 46 | 47 | typedef struct { 48 | item_types item_type; 49 | int count; /* in maps every association counts for 2 */ 50 | item_root* items[]; 51 | } item_container; 52 | 53 | typedef struct { 54 | item_types item_type; 55 | long long value; 56 | } item_integer; 57 | 58 | typedef struct { 59 | item_types item_type; 60 | double value; 61 | } item_real; 62 | 63 | typedef struct { 64 | item_types item_type; 65 | char string[]; 66 | } item_string; 67 | 68 | 69 | void freeItem3 (item_root* root); 70 | 71 | 72 | 73 | /************** ITEMS TO/FROM FILE **********************/ 74 | 75 | void item32JsonFile (FILE* file, item_root* item); 76 | 77 | item_root* jsonFile2item3 (FILE* file); 78 | 79 | void item32cwpackFile (FILE* file, item_root* item); 80 | 81 | item_root* cwpackFile2item3 (FILE* file); 82 | 83 | 84 | 85 | #endif /* item_h */ 86 | -------------------------------------------------------------------------------- /example/json2cwpack2json.c: -------------------------------------------------------------------------------- 1 | /* CWPack/example - json2cwpack2json.c */ 2 | /* 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2017 Claes Wihlborg 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 8 | software and associated documentation files (the "Software"), to deal in the Software 9 | without restriction, including without limitation the rights to use, copy, modify, 10 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 11 | persons to whom the Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or 14 | substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 17 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | DAMAGES OR OTHER 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 SOFTWARE. 21 | */ 22 | 23 | 24 | #include 25 | #include 26 | 27 | #include "item.h" 28 | #include "basic_contexts.h" 29 | 30 | 31 | int main(int argc, const char * argv[]) 32 | { 33 | if (argc < 2) 34 | { 35 | printf("Call: json2cwpack2json \n"); 36 | return 1; 37 | } 38 | char filename[200]; 39 | strcpy(filename, argv[1]); 40 | 41 | FILE* jsonFileIn; 42 | FILE* jsonFileOut; 43 | FILE* cwpackFileIn; 44 | FILE* cwpackFileOut; 45 | 46 | jsonFileIn = fopen (filename, "r"); 47 | item_root* root = jsonFile2item3 (jsonFileIn); 48 | fclose(jsonFileIn); 49 | 50 | strcat (filename, ".msgpack"); 51 | cwpackFileOut = fopen (filename, "w"); 52 | item32cwpackFile (cwpackFileOut, root); 53 | fclose(cwpackFileOut); 54 | freeItem3(root); 55 | 56 | cwpackFileIn = fopen (filename, "r"); 57 | root = cwpackFile2item3 (cwpackFileIn); 58 | fclose(cwpackFileIn); 59 | 60 | strcat (filename, ".json"); 61 | jsonFileOut = fopen (filename, "w"); 62 | item32JsonFile (jsonFileOut, root); 63 | fclose(jsonFileOut); 64 | freeItem3(root); 65 | 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /example/runExample.sh: -------------------------------------------------------------------------------- 1 | clang -ansi -I ../src/ -I ../goodies/basic-contexts/ *.c ../src/*.c ../goodies/basic-contexts/*.c -o json2cwpack2json 2 | ./json2cwpack2json test1.json 3 | diff -a test1.json test1.json.msgpack.json 4 | rm -f *.o json2cwpack2json 5 | -------------------------------------------------------------------------------- /example/test1.json: -------------------------------------------------------------------------------- 1 | { 2 | "a": 3, 3 | "b": -30714, 4 | "special": [ 5 | true, 6 | false, 7 | null 8 | ], 9 | "long string": "an even longer string to trigger handler, in an attempt to test if it's functioning OK", 10 | "pi": 3.14, 11 | "l": 6.1e-28, 12 | "k": 1.23456789012345e-17 13 | } 14 | -------------------------------------------------------------------------------- /goodies/README.md: -------------------------------------------------------------------------------- 1 | # CWPack / Goodies 2 | 3 | 4 | Goodies contains the following: 5 | 6 | **basic_contexts** has contexts for dynamic memory contexts and a set of file contexts. 7 | 8 | **dump** presents a msgpack file in human readable form. 9 | 10 | **numeric_extensions** use when your Ext data is integer or real. 11 | 12 | **objC** Objective-C wrapper. 13 | 14 | **swift** Swift wrapper. 15 | 16 | **utils** convenience calls and expect api for CWPack. 17 | 18 | -------------------------------------------------------------------------------- /goodies/basic-contexts/README.md: -------------------------------------------------------------------------------- 1 | # CWPack / Goodies / Basic Contexts 2 | 3 | 4 | Basic contexts contains 5 contexts that meet most demands: 5 | 6 | - **Dynamic Memory Pack Context** is used when you want to pack to a malloc´d memory buffer. At buffer overflow the context handler tries to reallocate the buffer to a larger size. 7 | 8 | - **Stream Pack Context** is used when you pack to a C stream. At buffer overflow the context handler writes the buffer out and then reuses it. If an item is larger than the buffer, the handler tries to reallocate the buffer so the item would fit. 9 | 10 | - **Stream Unpack Context** is used when you unpack from a C stream. As with Stream Pack Context, the handler asserts that an item will always fit in the buffer. 11 | 12 | - **File Pack Context** is used when you pack to a file descriptor. At buffer overflow the context handler writes the buffer out and then reuses it. However, if the barrier is active, the subsequent content is kept in the buffer. If an item is larger than the buffer, the handler tries to reallocate the buffer so the item would fit. 13 | 14 | - **File Unpack Context** is used when you unpack from a file descriptor. If the barrier is active, the subsequent content is always kept in buffer. The handler asserts that an item will always fit in the buffer. 15 | 16 | With the stream/file contexts, it is assumed that the stream/file has been opened before the context is initialized. Before a packed stream/file is closed, the corresponding terminate context should be called so the last buffer is saved. 17 | -------------------------------------------------------------------------------- /goodies/basic-contexts/basic_contexts.c: -------------------------------------------------------------------------------- 1 | /* CWPack/goodies - basic_contexts.c */ 2 | /* 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2017 Claes Wihlborg 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 8 | software and associated documentation files (the "Software"), to deal in the Software 9 | without restriction, including without limitation the rights to use, copy, modify, 10 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 11 | persons to whom the Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or 14 | substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 17 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | DAMAGES OR OTHER 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 SOFTWARE. 21 | */ 22 | 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "basic_contexts.h" 30 | 31 | 32 | 33 | 34 | /***************************************** DYNAMIC MEMORY PACK CONTEXT ********************************/ 35 | 36 | 37 | static int handle_memory_pack_overflow(struct cw_pack_context* pc, unsigned long more) 38 | { 39 | unsigned long contains = (unsigned long)(pc->current - pc->start); 40 | unsigned long tot_len = contains + more; 41 | unsigned long buffer_length = (unsigned long)(pc->end - pc->start); 42 | while (buffer_length < tot_len) 43 | buffer_length = 2 * buffer_length; 44 | void *new_buffer = realloc (pc->start, buffer_length); 45 | if (!new_buffer) 46 | return CWP_RC_BUFFER_OVERFLOW; 47 | 48 | pc->start = (uint8_t*)new_buffer; 49 | pc->current = pc->start + contains; 50 | pc->end = pc->start + buffer_length; 51 | return CWP_RC_OK; 52 | } 53 | 54 | 55 | void init_dynamic_memory_pack_context (dynamic_memory_pack_context* dmpc, unsigned long initial_buffer_length) 56 | { 57 | unsigned long buffer_length = (initial_buffer_length > 0 ? initial_buffer_length : 1024); 58 | void *buffer = malloc (buffer_length); 59 | if (!buffer) 60 | { 61 | dmpc->pc.return_code = CWP_RC_MALLOC_ERROR; 62 | return; 63 | } 64 | 65 | cw_pack_context_init((cw_pack_context*)dmpc, buffer, buffer_length, &handle_memory_pack_overflow); 66 | } 67 | 68 | 69 | void free_dynamic_memory_pack_context(dynamic_memory_pack_context* dmpc) 70 | { 71 | if (dmpc->pc.return_code != CWP_RC_MALLOC_ERROR) 72 | free(dmpc->pc.start); 73 | } 74 | 75 | 76 | 77 | /***************************************** STREAM PACK CONTEXT *********************************/ 78 | 79 | 80 | 81 | static int flush_stream_pack_context(struct cw_pack_context* pc) 82 | { 83 | stream_pack_context* spc = (stream_pack_context*)pc; 84 | unsigned long contains = (unsigned long)(pc->current - pc->start); 85 | if (contains) 86 | { 87 | unsigned long rc = fwrite(pc->start, contains, 1, spc->file); 88 | if (rc != 1) 89 | { 90 | pc->err_no = ferror(spc->file); 91 | return CWP_RC_ERROR_IN_HANDLER; 92 | } 93 | } 94 | return CWP_RC_OK; 95 | } 96 | 97 | 98 | static int handle_stream_pack_overflow(struct cw_pack_context* pc, unsigned long more) 99 | { 100 | int rc = flush_stream_pack_context(pc); 101 | if (rc != CWP_RC_OK) 102 | return rc; 103 | 104 | unsigned long buffer_length = (unsigned long)(pc->end - pc->start); 105 | if (buffer_length < more) 106 | { 107 | while (buffer_length < more) 108 | buffer_length = 2 * buffer_length; 109 | 110 | void *new_buffer = malloc (buffer_length); 111 | if (!new_buffer) 112 | return CWP_RC_BUFFER_OVERFLOW; 113 | 114 | free(pc->start); 115 | pc->start = (uint8_t*)new_buffer; 116 | pc->end = pc->start + buffer_length; 117 | } 118 | pc->current = pc->start; 119 | return CWP_RC_OK; 120 | } 121 | 122 | 123 | void init_stream_pack_context (stream_pack_context* spc, unsigned long initial_buffer_length, FILE* file) 124 | { 125 | unsigned long buffer_length = (initial_buffer_length > 0 ? initial_buffer_length : 4096); 126 | void *buffer = malloc (buffer_length); 127 | if (!buffer) 128 | { 129 | spc->pc.return_code = CWP_RC_MALLOC_ERROR; 130 | return; 131 | } 132 | spc->file = file; 133 | 134 | cw_pack_context_init((cw_pack_context*)spc, buffer, buffer_length, &handle_stream_pack_overflow); 135 | cw_pack_set_flush_handler((cw_pack_context*)spc, &flush_stream_pack_context); 136 | } 137 | 138 | 139 | void terminate_stream_pack_context(stream_pack_context* spc) 140 | { 141 | cw_pack_context* pc = (cw_pack_context*)spc; 142 | cw_pack_flush(pc); 143 | 144 | if (pc->return_code != CWP_RC_MALLOC_ERROR) 145 | free(pc->start); 146 | } 147 | 148 | 149 | 150 | /***************************************** STREAM UNPACK CONTEXT *******************************/ 151 | 152 | 153 | static int handle_stream_unpack_underflow(struct cw_unpack_context* uc, unsigned long more) 154 | { 155 | stream_unpack_context* suc = (stream_unpack_context*)uc; 156 | unsigned long remains = (unsigned long)(uc->end - uc->current); 157 | if (remains) 158 | { 159 | memmove (uc->start, uc->current, remains); 160 | } 161 | 162 | if (suc->buffer_length < more) 163 | { 164 | while (suc->buffer_length < more) 165 | suc->buffer_length = 2 * suc->buffer_length; 166 | 167 | void *new_buffer = realloc (uc->start, suc->buffer_length); 168 | if (!new_buffer) 169 | return CWP_RC_BUFFER_UNDERFLOW; 170 | 171 | uc->start = (uint8_t*)new_buffer; 172 | } 173 | uc->current = uc->start; 174 | uc->end = uc->start + remains; 175 | unsigned long l = fread(uc->end, 1, suc->buffer_length - remains, suc->file); 176 | if (!l) 177 | { 178 | if (feof(suc->file)) 179 | return CWP_RC_END_OF_INPUT; 180 | suc->uc.err_no = ferror(suc->file); 181 | return CWP_RC_ERROR_IN_HANDLER; 182 | } 183 | 184 | uc->end += l; 185 | 186 | return CWP_RC_OK; 187 | } 188 | 189 | 190 | void init_stream_unpack_context (stream_unpack_context* suc, unsigned long initial_buffer_length, FILE* file) 191 | { 192 | unsigned long buffer_length = (initial_buffer_length > 0? initial_buffer_length : 1024); 193 | void *buffer = malloc (buffer_length); 194 | if (!buffer) 195 | { 196 | suc->uc.return_code = CWP_RC_MALLOC_ERROR; 197 | return; 198 | } 199 | suc->file = file; 200 | suc->buffer_length = buffer_length; 201 | 202 | cw_unpack_context_init((cw_unpack_context*)suc, buffer, 0, &handle_stream_unpack_underflow); 203 | } 204 | 205 | 206 | void terminate_stream_unpack_context(stream_unpack_context* suc) 207 | { 208 | if (suc->uc.return_code != CWP_RC_MALLOC_ERROR) 209 | free(suc->uc.start); 210 | } 211 | 212 | 213 | 214 | /***************************************** FILE PACK CONTEXT **********************************/ 215 | 216 | 217 | static int flush_file_pack_context(struct cw_pack_context* pc) 218 | { 219 | file_pack_context* fpc = (file_pack_context*)pc; 220 | uint8_t *bStart = fpc->barrier ? fpc->barrier : pc->current; 221 | unsigned long contains = (unsigned long)(bStart - pc->start); 222 | if (contains) 223 | { 224 | long rc = write (fpc->fileDescriptor, pc->start, contains); 225 | if (rc != (long)contains) 226 | { 227 | pc->err_no = errno; 228 | return CWP_RC_ERROR_IN_HANDLER; 229 | } 230 | } 231 | if (fpc->barrier) 232 | { 233 | long kept = pc->current - bStart; 234 | if (kept) { 235 | memcpy(pc->start, bStart, kept); 236 | } 237 | fpc->barrier = pc->start; 238 | pc->current = pc->start + kept; 239 | } 240 | else 241 | fpc->pc.current = fpc->pc.start; 242 | 243 | return CWP_RC_OK; 244 | } 245 | 246 | static int handle_file_pack_overflow(struct cw_pack_context* pc, unsigned long more) 247 | { 248 | file_pack_context* fpc = (file_pack_context*)pc; 249 | int rc = flush_file_pack_context(pc); 250 | if (rc != CWP_RC_OK) 251 | return rc; 252 | 253 | uint8_t *bStart = fpc->barrier ? fpc->barrier : pc->current; 254 | unsigned long kept = (unsigned long)(pc->current - bStart); 255 | unsigned long buffer_length = (unsigned long)(pc->end - pc->start); 256 | if (buffer_length < more + kept) 257 | { 258 | while (buffer_length < more + kept) 259 | buffer_length = 2 * buffer_length; 260 | 261 | void *new_buffer = malloc (buffer_length); 262 | if (!new_buffer) 263 | return CWP_RC_BUFFER_OVERFLOW; 264 | if (kept) { 265 | memcpy(new_buffer, bStart, kept); 266 | } 267 | pc->start = (uint8_t*)new_buffer; 268 | pc->end = pc->start + buffer_length; 269 | } 270 | else if (kept) 271 | { 272 | memcpy(pc->start, bStart, kept); 273 | } 274 | 275 | if (fpc->barrier) 276 | { 277 | fpc->barrier = pc->start; 278 | } 279 | 280 | pc->current = pc->start + kept; 281 | return CWP_RC_OK; 282 | } 283 | 284 | 285 | void init_file_pack_context (file_pack_context* fpc, unsigned long initial_buffer_length, int fileDescriptor) 286 | { 287 | unsigned long buffer_length = (initial_buffer_length > 32 ? initial_buffer_length : 4096); 288 | void *buffer = malloc (buffer_length); 289 | if (!buffer) 290 | { 291 | fpc->pc.return_code = CWP_RC_MALLOC_ERROR; 292 | return; 293 | } 294 | 295 | fpc->fileDescriptor = fileDescriptor; 296 | fpc->barrier = NULL; 297 | 298 | cw_pack_context_init((cw_pack_context*)fpc, buffer, buffer_length, &handle_file_pack_overflow); 299 | cw_pack_set_flush_handler((cw_pack_context*)fpc, &flush_file_pack_context); 300 | } 301 | 302 | 303 | void file_pack_context_set_barrier (file_pack_context* fpc) 304 | { 305 | fpc->barrier = fpc->pc.current; 306 | } 307 | 308 | 309 | void file_pack_context_release_barrier (file_pack_context* fpc) 310 | { 311 | fpc->barrier = NULL; 312 | } 313 | 314 | 315 | void terminate_file_pack_context(file_pack_context* fpc) 316 | { 317 | fpc->barrier = NULL; 318 | cw_pack_context* pc = (cw_pack_context*)fpc; 319 | cw_pack_flush(pc); 320 | 321 | if (pc->return_code != CWP_RC_MALLOC_ERROR) 322 | free(pc->start); 323 | } 324 | 325 | 326 | 327 | /***************************************** FILE UNPACK CONTEXT ********************************/ 328 | 329 | 330 | static int handle_file_unpack_underflow(struct cw_unpack_context* uc, unsigned long more) 331 | { 332 | file_unpack_context* auc = (file_unpack_context*)uc; 333 | uint8_t *bStart = auc->barrier ? auc->barrier : uc->current; 334 | unsigned long kept = (unsigned long)(uc->current - bStart); 335 | unsigned long remains = (unsigned long)(uc->end - bStart); 336 | if (remains) 337 | { 338 | memcpy (uc->start, bStart, remains); 339 | } 340 | 341 | if (auc->buffer_length < more + kept) 342 | { 343 | while (auc->buffer_length < more + kept) 344 | auc->buffer_length = 2 * auc->buffer_length; 345 | 346 | void *new_buffer = realloc (uc->start, auc->buffer_length); 347 | if (!new_buffer) 348 | return CWP_RC_BUFFER_UNDERFLOW; 349 | 350 | uc->start = (uint8_t*)new_buffer; 351 | } 352 | uc->current = uc->start + kept; 353 | uc->end = uc->start + remains; 354 | if (auc->barrier) 355 | auc->barrier = uc->start; 356 | 357 | while ((unsigned long)(uc->end - uc->current) < more) 358 | { 359 | long l = read(auc->fileDescriptor, uc->end, auc->buffer_length - (unsigned long)(uc->end - uc->start)); 360 | if (l == 0) 361 | { 362 | return CWP_RC_END_OF_INPUT; 363 | } 364 | if (l < 0) 365 | { 366 | auc->uc.err_no = errno; 367 | return CWP_RC_ERROR_IN_HANDLER; 368 | } 369 | uc->end += l; 370 | } 371 | 372 | return CWP_RC_OK; 373 | } 374 | 375 | 376 | void init_file_unpack_context (file_unpack_context* fuc, unsigned long initial_buffer_length, int fileDescriptor) 377 | { 378 | unsigned long buffer_length = (initial_buffer_length > 0? initial_buffer_length : 1024); 379 | void *buffer = malloc (buffer_length); 380 | if (!buffer) 381 | { 382 | fuc->uc.return_code = CWP_RC_MALLOC_ERROR; 383 | return; 384 | } 385 | fuc->fileDescriptor = fileDescriptor; 386 | fuc->barrier = NULL; 387 | fuc->buffer_length = buffer_length; 388 | 389 | cw_unpack_context_init((cw_unpack_context*)fuc, buffer, 0, &handle_file_unpack_underflow); 390 | } 391 | 392 | 393 | void file_unpack_context_set_barrier (file_unpack_context* fuc) 394 | { 395 | fuc->barrier = fuc->uc.current; 396 | } 397 | 398 | 399 | void file_unpack_context_rescan_from_barrier (file_unpack_context* fuc) 400 | { 401 | fuc->uc.current = fuc->barrier; 402 | } 403 | 404 | void file_unpack_context_release_barrier (file_unpack_context* fuc) 405 | { 406 | fuc->barrier = NULL; 407 | } 408 | 409 | 410 | void terminate_file_unpack_context(file_unpack_context* fuc) 411 | { 412 | if (fuc->uc.return_code != CWP_RC_MALLOC_ERROR) 413 | free(fuc->uc.start); 414 | fuc->uc.start = 0; 415 | } 416 | 417 | 418 | -------------------------------------------------------------------------------- /goodies/basic-contexts/basic_contexts.h: -------------------------------------------------------------------------------- 1 | /* CWPack/goodies - basic_contexts.h */ 2 | /* 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2017 Claes Wihlborg 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 8 | software and associated documentation files (the "Software"), to deal in the Software 9 | without restriction, including without limitation the rights to use, copy, modify, 10 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 11 | persons to whom the Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or 14 | substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 17 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | DAMAGES OR OTHER 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 SOFTWARE. 21 | */ 22 | 23 | #ifndef basic_contexts_h 24 | #define basic_contexts_h 25 | 26 | #include 27 | #include "cwpack.h" 28 | 29 | 30 | /***************************************** DYNAMIC MEMORY PACK CONTEXT ************************/ 31 | 32 | typedef struct 33 | { 34 | cw_pack_context pc; 35 | } dynamic_memory_pack_context; 36 | 37 | 38 | void init_dynamic_memory_pack_context (dynamic_memory_pack_context* dmpc, unsigned long initial_buffer_length); 39 | 40 | void free_dynamic_memory_pack_context(dynamic_memory_pack_context* dmpc); 41 | 42 | 43 | 44 | /***************************************** STREAM PACK CONTEXT ********************************/ 45 | 46 | typedef struct 47 | { 48 | cw_pack_context pc; 49 | FILE* file; 50 | } stream_pack_context; 51 | 52 | 53 | void init_stream_pack_context (stream_pack_context* spc, unsigned long initial_buffer_length, FILE* file); 54 | 55 | void terminate_stream_pack_context(stream_pack_context* spc); 56 | 57 | 58 | 59 | /***************************************** STREAM UNPACK CONTEXT ******************************/ 60 | 61 | typedef struct 62 | { 63 | cw_unpack_context uc; 64 | unsigned long buffer_length; 65 | FILE* file; 66 | } stream_unpack_context; 67 | 68 | 69 | void init_stream_unpack_context (stream_unpack_context* suc, unsigned long initial_buffer_length, FILE* file); 70 | 71 | void terminate_stream_unpack_context(stream_unpack_context* suc); 72 | 73 | 74 | 75 | /***************************************** FILE PACK CONTEXT ********************************/ 76 | 77 | typedef struct 78 | { 79 | cw_pack_context pc; 80 | int fileDescriptor; 81 | uint8_t *barrier; 82 | } file_pack_context; 83 | 84 | 85 | void init_file_pack_context (file_pack_context* spc, unsigned long initial_buffer_length, int fileDescriptor); 86 | 87 | void file_pack_context_set_barrier (file_pack_context* spc); 88 | void file_pack_context_release_barrier (file_pack_context* spc); 89 | 90 | void terminate_file_pack_context(file_pack_context* spc); 91 | 92 | 93 | 94 | /***************************************** FILE UNPACK CONTEXT ******************************/ 95 | 96 | typedef struct 97 | { 98 | cw_unpack_context uc; 99 | unsigned long buffer_length; 100 | int fileDescriptor; 101 | uint8_t *barrier; 102 | } file_unpack_context; 103 | 104 | 105 | void init_file_unpack_context (file_unpack_context* suc, unsigned long initial_buffer_length, int fileDescriptor); 106 | 107 | void file_unpack_context_set_barrier (file_unpack_context* suc); 108 | void file_unpack_context_rescan_from_barrier (file_unpack_context* suc); 109 | void file_unpack_context_release_barrier (file_unpack_context* suc); 110 | 111 | void terminate_file_unpack_context(file_unpack_context* suc); 112 | 113 | 114 | 115 | /***************************************** E P I L O G U E **********************************/ 116 | 117 | 118 | #endif /* basic_contexts_h */ 119 | -------------------------------------------------------------------------------- /goodies/dump/README.md: -------------------------------------------------------------------------------- 1 | # CWPack / Goodies / Dump 2 | 3 | 4 | Dump is a small program taking a msgpack file as input and produces a human readable file as output. The output is not json as msgpack is more feature-rich. 5 | 6 | Syntax: 7 | cwpack_dump [-t 9] [-v][-r] [-h] < msgpackFile > humanReadableFile 8 | -t 9 Tab size 9 | -v Version 10 | -r Recognize records 11 | -h Help 12 | 13 | Each topmost msgpack item in the file starts on a new line. Each line starts with a file offset (hex) of the first item on the line. 14 | If Tab size isn't given, structures are written on a single line. 15 | 16 | 17 | `cwpack_dump < testdump.msgpack` prints: 18 | 19 | ``` 20 | 0 [10000000 3.14 "åäöÅÄÖ"] 21 | 1c {"binary": <62696e617279> "extension": (-5,<68656c6c6f>) "time": '2020-05-20 18:40:00'} 22 | 49 23 | ``` 24 | and `cwpack_dump -t 4 < testdump.msgpack` prints: 25 | 26 | ``` 27 | 0 [ 28 | 1 10000000 29 | 6 3.14 30 | f "åäöÅÄÖ" 31 | 1c ] 32 | 1c { 33 | 1d "binary": <62696e617279> 34 | 2c "extension": (-5,<68656c6c6f>) 35 | 3e "time": '2020-05-20 18:40:00' 36 | 49 } 37 | 49 38 | ``` 39 | The -r option makes dump recognize Objective-C objects. `cwpack_dump < testdump2.msgpack` prints: 40 | 41 | ``` 42 | 0 [(127,) [[(127,)]]] 43 | 9 [(127,<01>) "MyClass" 10 [(127,<02>) "MyClass" 20 [(127,<01>)]]] 44 | 27 45 | ``` 46 | and `cwpack_dump -r < testdump2.msgpack` prints 47 | 48 | ``` 49 | 0 -1->[->-1] 50 | 9 1->MyClass(10 2->MyClass(20 ->1)) 51 | 27 52 | ``` 53 | 54 | -------------------------------------------------------------------------------- /goodies/dump/cwpack_dump.c: -------------------------------------------------------------------------------- 1 | 2 | /* CWPack/goodies/dump - cwpack_dump.c */ 3 | 4 | /* 5 | The MIT License (MIT) 6 | 7 | Copyright (c) 2017 Claes Wihlborg 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 10 | software and associated documentation files (the "Software"), to deal in the Software 11 | without restriction, including without limitation the rights to use, copy, modify, 12 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 13 | persons to whom the Software is furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in all copies or 16 | substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 19 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 21 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | 26 | #include 27 | #include 28 | #include 29 | #include "basic_contexts.h" 30 | #include "numeric_extensions.h" 31 | 32 | char tabString[21] = " "; 33 | bool recognizeObjects = false; 34 | 35 | #define NEW_LINE(tablevel) {printf ("\n%6x %6ld ",(unsigned)(context->current - context->start),(context->current - context->start)); for (ti=0; ti"); 51 | } 52 | static void dump_item( cw_unpack_context* context, int tabLevel); 53 | 54 | static void dump_next_item( cw_unpack_context* context, int tabLevel) 55 | { 56 | cw_unpack_next (context); 57 | if (context->return_code) return; 58 | dump_item (context, tabLevel); 59 | } 60 | 61 | static void dump_item( cw_unpack_context* context, int tabLevel) 62 | { 63 | long long dim =99; 64 | int i,ti; 65 | double d; 66 | struct tm tm; 67 | char s[128]; 68 | 69 | switch (context->item.type) 70 | { 71 | case CWP_ITEM_NIL: 72 | printf("nil"); 73 | break; 74 | 75 | case CWP_ITEM_BOOLEAN: 76 | if (context->item.as.boolean) 77 | printf("YES"); 78 | else 79 | printf("NO"); 80 | break; 81 | 82 | case CWP_ITEM_POSITIVE_INTEGER: 83 | printf("%llu", context->item.as.u64); 84 | break; 85 | 86 | case CWP_ITEM_NEGATIVE_INTEGER: 87 | printf("%lld", context->item.as.i64); 88 | break; 89 | 90 | case CWP_ITEM_FLOAT: 91 | context->item.as.long_real = (double)context->item.as.real; 92 | 93 | case CWP_ITEM_DOUBLE: 94 | printf ("%g", context->item.as.long_real); 95 | break; 96 | 97 | case CWP_ITEM_STR: { 98 | printf("\""); 99 | 100 | for (i=0; i < (int)context->item.as.str.length; i++) 101 | { 102 | unsigned char c = ((unsigned char*)(context->item.as.str.start))[i]; 103 | switch (c) 104 | { 105 | case '"': printf("\\\""); break; 106 | case '\\': printf("\\\\"); break; 107 | case '\b': printf("\\b"); break; 108 | case '\f': printf("\\f"); break; 109 | case '\n': printf("\\n"); break; 110 | case '\r': printf("\\r"); break; 111 | case '\t': printf("\\t"); break; 112 | 113 | default: 114 | if (c < ' ') 115 | printf("\\u%04x",c); 116 | else 117 | printf("%c",c); 118 | break; 119 | } 120 | } 121 | 122 | printf("\""); 123 | break;} 124 | 125 | case CWP_ITEM_BIN: 126 | dump_as_hex (context->item.as.bin.start, context->item.as.bin.length); 127 | break; 128 | 129 | case CWP_ITEM_ARRAY: 130 | { 131 | dim = context->item.as.array.size; 132 | if (!dim) 133 | { 134 | printf("[]"); 135 | break; 136 | } 137 | 138 | cw_unpack_next (context); 139 | if (context->return_code) break; 140 | 141 | if (recognizeObjects && (context->item.type == 127)) 142 | { 143 | long label = get_ext_integer(context); 144 | bool userObject = label >= 0; 145 | if (dim == 1) /* reference */ 146 | { 147 | printf("->%ld",label); 148 | break; 149 | } 150 | if (label) 151 | printf("%ld->",label); 152 | if (!userObject) 153 | { 154 | if (dim != 2) 155 | { 156 | context->return_code = CWP_RC_MALFORMED_INPUT; 157 | break; 158 | } 159 | dump_next_item(context,tabLevel); 160 | break; 161 | } 162 | cw_unpack_next (context); 163 | if (context->return_code) break; 164 | if (context->item.type != CWP_ITEM_STR) 165 | { 166 | context->return_code = CWP_RC_MALFORMED_INPUT; 167 | break; 168 | } 169 | printf("%.*s(",context->item.as.str.length, context->item.as.str.start); 170 | tabLevel++; 171 | for (i = 0; i < dim-2; i++) 172 | { 173 | CHECK_NEW_LINE; 174 | dump_next_item(context,tabLevel); 175 | } 176 | tabLevel--; 177 | if(*tabString) NEW_LINE(tabLevel); 178 | printf(")"); 179 | } 180 | else 181 | { 182 | printf("["); 183 | tabLevel++; 184 | i = 0; 185 | CHECK_NEW_LINE; 186 | dump_item(context,tabLevel); 187 | for (i = 1; i < dim; i++) 188 | { 189 | CHECK_NEW_LINE; 190 | dump_next_item(context,tabLevel); 191 | } 192 | tabLevel--; 193 | if(*tabString) NEW_LINE(tabLevel); 194 | printf("]"); 195 | } 196 | break; 197 | } 198 | 199 | case CWP_ITEM_MAP: 200 | dim = context->item.as.map.size; 201 | if (!dim) 202 | { 203 | printf("{}"); 204 | break; 205 | } 206 | 207 | printf("{"); 208 | dim = context->item.as.map.size; 209 | tabLevel++; 210 | for (i = 0; i < dim; i++) 211 | { 212 | CHECK_NEW_LINE; 213 | dump_next_item(context,tabLevel); 214 | printf(":"); 215 | dump_next_item(context,tabLevel); 216 | } 217 | tabLevel--; 218 | if(*tabString) NEW_LINE(tabLevel); 219 | printf("}"); 220 | break; 221 | 222 | case CWP_ITEM_TIMESTAMP: 223 | printf("'"); 224 | time_t tv_sec = context->item.as.time.tv_sec; 225 | gmtime_r(&tv_sec,&tm); 226 | strftime(s,128,"%F %T", &tm); 227 | printf("%s",s); 228 | if (context->item.as.time.tv_nsec) 229 | { 230 | d = (double)(context->item.as.time.tv_nsec) / 1000000000; 231 | sprintf(s,"%f",d); 232 | printf("%s",s+1); 233 | } 234 | printf("'"); 235 | break; 236 | 237 | default: 238 | if (CWP_ITEM_MIN_RESERVED_EXT <= context->item.type && context->item.type <= CWP_ITEM_MAX_USER_EXT) 239 | { 240 | printf("(%d,",context->item.type); 241 | dump_as_hex (context->item.as.ext.start, context->item.as.ext.length); 242 | printf(")"); 243 | } 244 | else 245 | printf("????? type = %d", context->item.type ); 246 | break; 247 | } 248 | } 249 | 250 | 251 | /******************************* M A I N ******************************/ 252 | 253 | 254 | int main(int argc, const char * argv[]) 255 | { 256 | int i; 257 | int t = 0; 258 | for (i = 1; i < argc; i++) 259 | { 260 | if (!strcmp(argv[i],"-t") && (i++ < argc)) 261 | { 262 | t = *argv[i] - '0'; 263 | if (strlen(argv[i]) != 1 || t < 1 || t > 9) { 264 | printf("Tab size must be between 1 and 9\n"); 265 | exit(0); 266 | } 267 | } 268 | else if (!strcmp(argv[i],"-v") || !strcmp(argv[i],"--version")) 269 | { 270 | printf("cwpack_dump version = 1.0\n"); 271 | exit(0); 272 | } 273 | else if (!strcmp(argv[i],"-r")) 274 | { 275 | recognizeObjects = true; 276 | } 277 | else 278 | { 279 | printf("cwpack_dump [-t 9] [-r] [-v] [-h]\n"); 280 | printf("-h Help\n"); 281 | printf("-r Recognize records\n"); 282 | printf("-t 9 Tab size\n"); 283 | printf("-v Version\n"); 284 | printf("\nIf Tab size isn't given, structures are written on a single line\n"); 285 | printf("\nInput is taken from stdin and output is written to stdout\n"); 286 | exit(0); 287 | } 288 | } 289 | tabString[t] = 0; 290 | 291 | file_unpack_context fuc; 292 | cw_unpack_context *context = (cw_unpack_context*)&fuc; 293 | 294 | init_file_unpack_context (&fuc, 4096, STDIN_FILENO); 295 | file_unpack_context_set_barrier (&fuc); /* keep whole file in memory buffer to simplify offset calculation */ 296 | 297 | while (!context->return_code) 298 | { 299 | int ti; 300 | NEW_LINE(0); 301 | dump_next_item(context,0); 302 | } 303 | printf("\n"); 304 | if (context->return_code != CWP_RC_END_OF_INPUT) 305 | printf("\nERROR RC = %d\n",context->return_code); 306 | 307 | terminate_file_unpack_context (&fuc); 308 | } 309 | 310 | -------------------------------------------------------------------------------- /goodies/dump/runCWpack_dump.sh: -------------------------------------------------------------------------------- 1 | clang -ansi -I ../../src/ -I ../basic-contexts/ -I ../numeric-extensions/ -o cwpack_dump *.c ../../src/cwpack.c ../basic-contexts/*.c ../numeric-extensions/numeric_extensions.c 2 | ./cwpack_dump < testdump.msgpack 3 | ./cwpack_dump -t 4 < testdump.msgpack 4 | -------------------------------------------------------------------------------- /goodies/dump/testdump.msgpack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clwi/CWPack/833fec93903f047ae5c47936f884ba27fc4c7a4c/goodies/dump/testdump.msgpack -------------------------------------------------------------------------------- /goodies/dump/testdump2.msgpack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clwi/CWPack/833fec93903f047ae5c47936f884ba27fc4c7a4c/goodies/dump/testdump2.msgpack -------------------------------------------------------------------------------- /goodies/numeric-extensions/README.md: -------------------------------------------------------------------------------- 1 | # CWPack / Goodies / Numeric Extensions 2 | 3 | 4 | Numeric Extensions solves the byte order problem when the value of an extension item is a numeric entity. It uses the same byte order as `cw_pack_signed` and `cw_pack_double`. 5 | 6 | ## Pack 7 | 8 | ``` 9 | void cw_pack_ext_integer (cw_pack_context* pack_context, int8_t type, int64_t i); 10 | void cw_pack_ext_float (cw_pack_context* pack_context, int8_t type, float f); 11 | void cw_pack_ext_double (cw_pack_context* pack_context, int8_t type, double d); 12 | ``` 13 | 14 | ## Unpack 15 | 16 | ``` 17 | int64_t get_ext_integer (cw_unpack_context* unpack_context); 18 | float get_ext_float (cw_unpack_context* unpack_context); 19 | double get_ext_double (cw_unpack_context* unpack_context); 20 | ``` 21 | The `get_ext_...` functions assume that the user first has done a successful `cw_unpack_next` call. They return error if the unpacked item isn't an ext item or if the item has wrong length. 22 | -------------------------------------------------------------------------------- /goodies/numeric-extensions/numeric_extensions.c: -------------------------------------------------------------------------------- 1 | /* CWPack/goodies - numeric_extensions.c */ 2 | /* 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2017 Claes Wihlborg 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 8 | software and associated documentation files (the "Software"), to deal in the Software 9 | without restriction, including without limitation the rights to use, copy, modify, 10 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 11 | persons to whom the Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or 14 | substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 17 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | DAMAGES OR OTHER 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 SOFTWARE. 21 | */ 22 | 23 | 24 | #include "cwpack_internals.h" 25 | #include "numeric_extensions.h" 26 | 27 | 28 | #define cw_storeN(n,op,ant) \ 29 | { \ 30 | cw_pack_reserve_space(n); \ 31 | *p++ = (uint8_t)op; \ 32 | *p++ = (uint8_t)type; \ 33 | cw_store##ant(i); \ 34 | return; \ 35 | } 36 | 37 | #define cw_store8(i) *p = (uint8_t)i; 38 | 39 | 40 | void cw_pack_ext_integer (cw_pack_context* pack_context, int8_t type, int64_t i) 41 | { 42 | if (pack_context->return_code) 43 | return; 44 | 45 | uint8_t *p; 46 | 47 | if (i >= 0) 48 | { 49 | if (i < 128) 50 | cw_storeN(3,0xd4,8); 51 | 52 | if (i < 32768) 53 | cw_storeN(4,0xd5,16); 54 | 55 | if (i < 0x80000000LL) 56 | cw_storeN(6,0xd6,32); 57 | 58 | cw_storeN(10,0xd7,64); 59 | } 60 | 61 | if (i >= -128) 62 | cw_storeN(3,0xd4,8); 63 | 64 | if (i >= -32768) 65 | cw_storeN(4,0xd5,16); 66 | 67 | if (i >= (int64_t)0xffffffff80000000LL) 68 | cw_storeN(6,0xd6,32); 69 | 70 | cw_storeN(10,0xd7,64); 71 | } 72 | 73 | 74 | void cw_pack_ext_float (cw_pack_context* pack_context, int8_t type, float f) 75 | { 76 | if (pack_context->return_code) 77 | return; 78 | 79 | uint8_t *p; 80 | 81 | cw_pack_reserve_space(6); 82 | *p++ = (uint8_t)0xd6; 83 | *p++ = (uint8_t)type; 84 | 85 | uint32_t tmp = *((uint32_t*)&f); 86 | cw_store32(tmp); 87 | } 88 | 89 | 90 | void cw_pack_ext_double (cw_pack_context* pack_context, int8_t type, double d) 91 | { 92 | if (pack_context->return_code) 93 | return; 94 | 95 | uint8_t *p; 96 | 97 | cw_pack_reserve_space(10); 98 | *p++ = (uint8_t)0xd7; 99 | *p++ = (uint8_t)type; 100 | 101 | uint64_t tmp = *((uint64_t*)&d); 102 | cw_store64(tmp); 103 | } 104 | 105 | 106 | int64_t get_ext_integer (cw_unpack_context* unpack_context) 107 | { 108 | if (unpack_context->return_code != CWP_RC_OK) 109 | { 110 | return 0; 111 | } 112 | 113 | uint16_t tmpu16; 114 | uint32_t tmpu32; 115 | uint64_t tmpu64; 116 | 117 | if (unpack_context->item.type > CWP_ITEM_MAX_USER_EXT) 118 | { 119 | unpack_context->return_code = CWP_RC_TYPE_ERROR; 120 | return 0; 121 | } 122 | 123 | switch (unpack_context->item.as.ext.length) { 124 | case 0: 125 | return 0; 126 | 127 | case 1: 128 | return *(int8_t*)unpack_context->item.as.ext.start; 129 | 130 | case 2: 131 | cw_load16(unpack_context->item.as.ext.start); 132 | return (int16_t)tmpu16; 133 | 134 | case 4: 135 | cw_load32(unpack_context->item.as.ext.start); 136 | return (int32_t)tmpu32; 137 | 138 | case 8: 139 | cw_load64(unpack_context->item.as.ext.start,tmpu64); 140 | return (int64_t)tmpu64; 141 | 142 | default: 143 | unpack_context->return_code = CWP_RC_VALUE_ERROR; 144 | } 145 | return 0; 146 | } 147 | 148 | 149 | float get_ext_float (cw_unpack_context* unpack_context) 150 | { 151 | if (unpack_context->return_code != CWP_RC_OK) 152 | { 153 | return 0; 154 | } 155 | 156 | uint32_t tmpu32; 157 | 158 | if (unpack_context->item.type > CWP_ITEM_MAX_USER_EXT) 159 | { 160 | unpack_context->return_code = CWP_RC_TYPE_ERROR; 161 | return 0.0; 162 | } 163 | 164 | if (unpack_context->item.as.ext.length != 4) 165 | { 166 | unpack_context->return_code = CWP_RC_VALUE_ERROR; 167 | return 0.0; 168 | } 169 | 170 | cw_load32(unpack_context->item.as.ext.start); 171 | return *(float*)&tmpu32; 172 | } 173 | 174 | 175 | double get_ext_double (cw_unpack_context* unpack_context) 176 | { 177 | if (unpack_context->return_code != CWP_RC_OK) 178 | { 179 | return 0; 180 | } 181 | 182 | uint64_t tmpu64; 183 | 184 | if (unpack_context->item.type > CWP_ITEM_MAX_USER_EXT) 185 | { 186 | unpack_context->return_code = CWP_RC_TYPE_ERROR; 187 | return 0.0; 188 | } 189 | 190 | if (unpack_context->item.as.ext.length != 8) 191 | { 192 | unpack_context->return_code = CWP_RC_VALUE_ERROR; 193 | return 0.0; 194 | } 195 | 196 | cw_load64(unpack_context->item.as.ext.start,tmpu64); 197 | return *(double*)&tmpu64; 198 | } 199 | 200 | -------------------------------------------------------------------------------- /goodies/numeric-extensions/numeric_extensions.h: -------------------------------------------------------------------------------- 1 | /* CWPack/goodies - numeric_extensions.h */ 2 | /* 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2017 Claes Wihlborg 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 8 | software and associated documentation files (the "Software"), to deal in the Software 9 | without restriction, including without limitation the rights to use, copy, modify, 10 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 11 | persons to whom the Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or 14 | substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 17 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | DAMAGES OR OTHER 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 SOFTWARE. 21 | */ 22 | 23 | #ifndef numeric_extensions_h 24 | #define numeric_extensions_h 25 | 26 | #include "cwpack.h" 27 | 28 | 29 | 30 | #define NUMEXT_ERROR_NOT_EXT CWP_RC_TYPE_ERROR; 31 | #define NUMEXT_ERROR_WRONG_LENGTH CWP_RC_VALUE_ERROR; 32 | 33 | 34 | 35 | 36 | void cw_pack_ext_integer (cw_pack_context* pack_context, int8_t type, int64_t i); 37 | void cw_pack_ext_float (cw_pack_context* pack_context, int8_t type, float f); 38 | void cw_pack_ext_double (cw_pack_context* pack_context, int8_t type, double d); 39 | 40 | 41 | int64_t get_ext_integer (cw_unpack_context* unpack_context); 42 | float get_ext_float (cw_unpack_context* unpack_context); 43 | double get_ext_double (cw_unpack_context* unpack_context); 44 | 45 | 46 | 47 | #endif /* numeric_extensions_h */ 48 | -------------------------------------------------------------------------------- /goodies/numeric-extensions/numeric_extensions_test.c: -------------------------------------------------------------------------------- 1 | /* CWPack/goodies - numeric_extensions_test.c */ 2 | /* 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2017 Claes Wihlborg 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 8 | software and associated documentation files (the "Software"), to deal in the Software 9 | without restriction, including without limitation the rights to use, copy, modify, 10 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 11 | persons to whom the Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or 14 | substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 17 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | DAMAGES OR OTHER 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 SOFTWARE. 21 | */ 22 | 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include "cwpack.h" 29 | #include "cwpack_internals.h" 30 | #include "numeric_extensions.h" 31 | 32 | 33 | 34 | 35 | cw_pack_context pack_ctx; 36 | cw_unpack_context unpack_ctx; 37 | char TEST_area[70000]; 38 | uint8_t outbuffer[70000]; 39 | 40 | int error_count; 41 | 42 | static void ERROR(const char* msg) 43 | { 44 | error_count++; 45 | printf("ERROR: %s\n", msg); 46 | } 47 | 48 | 49 | static void ERROR1(const char* msg, int i) 50 | { 51 | error_count++; 52 | printf("ERROR: %s%d\n", msg, i); 53 | } 54 | 55 | 56 | static char char2hex (char c) 57 | { 58 | if (c <= '9') 59 | return c - '0'; 60 | if (c <= 'F') 61 | return c - 'A' + 10; 62 | 63 | return c - 'a' + 10; 64 | } 65 | 66 | 67 | static void check_pack_result(const char* expected_header, unsigned long data_length) 68 | { 69 | // expected contains the result in HEX 70 | unsigned long header_length = strlen(expected_header) / 2; 71 | if (pack_ctx.current - outbuffer == (long)(header_length + data_length)) 72 | { 73 | 74 | if (header_length*2 == strlen(expected_header)) 75 | { 76 | unsigned long i; 77 | uint8_t *p = (uint8_t*)outbuffer; 78 | const char *ucp = expected_header; 79 | for (i = 0; i < header_length; i++) 80 | { 81 | long hex = 0; 82 | int j; 83 | for(j=0; j<2; j++) 84 | { 85 | char uc = *(ucp++); 86 | if (uc >= '0' && uc <= '9') 87 | { 88 | hex <<= 4; 89 | hex += (uc - '0'); 90 | continue; 91 | } 92 | if (uc >= 'a' && uc <='f') 93 | { 94 | hex <<= 4; 95 | hex += (uc - 'a' + 10); 96 | continue; 97 | } 98 | if (uc < 'A' || uc >'F') 99 | { 100 | ERROR("Not a HEX value"); 101 | } 102 | hex <<= 4; 103 | hex += (uc - 'A' + 10); 104 | } 105 | 106 | 107 | if (*p++ != hex) 108 | { 109 | ERROR("Different header value"); 110 | } 111 | } 112 | 113 | if (data_length > 0) 114 | { 115 | ucp = TEST_area; 116 | for (i = 0; i < data_length; i++) 117 | if (*p++ != *ucp++) 118 | { 119 | ERROR("Different data value"); 120 | } 121 | } 122 | } 123 | else 124 | ERROR("Odd header"); 125 | } 126 | else 127 | ERROR("Wrong total length"); 128 | } 129 | 130 | 131 | 132 | int main(int argc, const char * argv[]) 133 | { 134 | printf("CWPack numeric extensions test started.\n"); 135 | error_count = 0; 136 | 137 | bool endian_switch_found = false; 138 | #ifdef COMPILE_FOR_BIG_ENDIAN 139 | printf("Compiled for big endian.\n\n"); 140 | endian_switch_found = true; 141 | #endif 142 | 143 | #ifdef COMPILE_FOR_LITTLE_ENDIAN 144 | printf("Compiled for little endian.\n\n"); 145 | endian_switch_found = true; 146 | #endif 147 | 148 | if (!endian_switch_found) 149 | { 150 | printf("Compiled for all endians.\n"); 151 | const char *endianness = "1234"; 152 | switch (*(uint32_t*)endianness) 153 | { 154 | case 0x31323334UL: 155 | printf("Running on big endian hardware.\n\n"); 156 | break; 157 | 158 | case 0x34333231UL: 159 | printf("Running on little endian hardware.\n\n"); 160 | break; 161 | 162 | default: 163 | printf("Running on neither little nor big endian hardware.\n\n"); 164 | break; 165 | } 166 | } 167 | 168 | 169 | //******************* TEST numeric extensions **************************** 170 | 171 | cw_pack_context_init (&pack_ctx, outbuffer, 70000, 0); 172 | if (pack_ctx.return_code == CWP_RC_WRONG_BYTE_ORDER) 173 | { 174 | ERROR("***** Compiled for wrong byte order, test terminated *****\n\n"); 175 | exit(1); 176 | } 177 | 178 | 179 | 180 | 181 | #define TESTP_EXT(call,type,value,header) \ 182 | pack_ctx.current = outbuffer; \ 183 | cw_pack_ext_##call (&pack_ctx, type, value); \ 184 | if(pack_ctx.return_code) \ 185 | ERROR("In pack"); \ 186 | check_pack_result(header, 0) 187 | 188 | // TESTP ext 189 | TESTP_EXT(integer,15,1,"d40f01"); 190 | TESTP_EXT(integer,15,128,"d50f0080"); 191 | TESTP_EXT(integer,15,-32769,"d60fffff7fff"); 192 | 193 | float f1 = (float)3.14; 194 | TESTP_EXT(float,15,f1,"d60f4048f5c3"); 195 | TESTP_EXT(double,15,f1,"d70f40091eb860000000"); 196 | 197 | int64_t integer_var; 198 | float float_var; 199 | double double_var; 200 | char inputbuf[30]; 201 | 202 | #define TESTUP_EXT(buffer,etype,call,value) \ 203 | { \ 204 | unsigned long ui; \ 205 | unsigned long len = strlen(buffer)/2; \ 206 | for (ui = 0; ui < len; ui++) \ 207 | inputbuf[ui] = (uint8_t)(char2hex(buffer[2*ui])<<4) + char2hex(buffer[2*ui +1]); \ 208 | cw_unpack_context_init (&unpack_ctx, inputbuf, len, 0); \ 209 | cw_unpack_next(&unpack_ctx); \ 210 | if (unpack_ctx.return_code) \ 211 | ERROR1("In unpack_next, rc = ",unpack_ctx.return_code); \ 212 | if (unpack_ctx.item.type != etype) \ 213 | ERROR("In unpack, type error"); \ 214 | call##_var = get_ext_##call (&unpack_ctx); \ 215 | if (unpack_ctx.return_code) \ 216 | ERROR1("In get_ext, rc = ",unpack_ctx.return_code); \ 217 | if (call##_var != value) \ 218 | ERROR("In unpack, value error"); \ 219 | } 220 | 221 | TESTUP_EXT("d40f01",15,integer,1); 222 | TESTUP_EXT("d50f0080",15,integer,128); 223 | TESTUP_EXT("d60fffff7fff",15,integer,-32769); 224 | TESTUP_EXT("d60f4048f5c3",15,float,f1); 225 | TESTUP_EXT("d70f40091eb860000000",15,double,(double)f1); 226 | //************************************************************* 227 | 228 | printf("CWPack numeric extensions test completed, "); 229 | switch (error_count) 230 | { 231 | case 0: 232 | printf("no errors detected\n"); 233 | break; 234 | 235 | case 1: 236 | printf("1 error detected\n"); 237 | break; 238 | 239 | default: 240 | printf("%d errors detected\n", error_count); 241 | break; 242 | } 243 | 244 | return error_count; 245 | } 246 | 247 | 248 | -------------------------------------------------------------------------------- /goodies/numeric-extensions/runNumericExtensionsTest.sh: -------------------------------------------------------------------------------- 1 | clang -ansi -I ../../src/ -o numericExtensionsTest *.c ../../src/cwpack.c 2 | ./numericExtensionsTest 3 | rm -f *.o numericExtensionsTest 4 | -------------------------------------------------------------------------------- /goodies/objC/CWPackContext.h: -------------------------------------------------------------------------------- 1 | 2 | /* CWPack/goodies/ObjC - CWPackContext.h */ 3 | 4 | /* 5 | The MIT License (MIT) 6 | 7 | Copyright (c) 2021 Claes Wihlborg 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 10 | software and associated documentation files (the "Software"), to deal in the Software 11 | without restriction, including without limitation the rights to use, copy, modify, 12 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 13 | persons to whom the Software is furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in all copies or 16 | substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 19 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 21 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | 26 | #import 27 | #include "cwpack.h" 28 | 29 | NS_ASSUME_NONNULL_BEGIN 30 | 31 | 32 | 33 | 34 | 35 | @interface CWPackContext : NSObject 36 | 37 | @property (readonly) cw_pack_context *context; 38 | @property (readwrite) BOOL useLabels; // default NO 39 | 40 | + (instancetype) newWithContext:(cw_pack_context*)context; 41 | - (void) packObject:(nullable NSObject*)object; 42 | 43 | @end 44 | 45 | 46 | 47 | 48 | 49 | @interface CWUnpackContext : NSObject 50 | 51 | @property (readonly) cw_unpack_context *context; 52 | 53 | + (instancetype) newWithContext:(cw_unpack_context*)context; 54 | - (id) unpackNextObject; 55 | 56 | @end 57 | 58 | 59 | 60 | 61 | @protocol CWPackable 62 | 63 | @required 64 | @property (readonly) int persistentAttributeCount; 65 | - (void) cwPackSub:(CWPackContext*)ctx; 66 | - (void) cwUnpackSub:(CWUnpackContext*)ctx remainingAttributes:(int)remainingAttributes; 67 | 68 | @optional 69 | - (instancetype) cwUnpackSubInit:(CWUnpackContext*)ctx remainingAttributes:(int)remainingAttributes; 70 | 71 | @end 72 | 73 | 74 | 75 | 76 | @interface CWPackExternalItem : NSObject 77 | 78 | @property (readonly) int type; 79 | @property (readwrite, strong) NSData* data; 80 | 81 | + (instancetype) itemWithType:(int)type data:(NSData*)data; 82 | 83 | @end 84 | 85 | 86 | 87 | 88 | @interface CWPackGenericClass : NSObject 89 | 90 | @property (readwrite,strong) NSString *packerClassName; 91 | @property (readwrite,strong) NSMutableArray *attributes; 92 | 93 | + (instancetype) newWithClassName:(NSString*)className; 94 | @end 95 | 96 | 97 | NS_ASSUME_NONNULL_END 98 | -------------------------------------------------------------------------------- /goodies/objC/README.md: -------------------------------------------------------------------------------- 1 | # CWPack / Goodies / ObjC 2 | 3 | 4 | ObjC contains a pack and an unpack context to enable Objective-C objects in the MessagePack stream. The implementation also has the capability to keep the references between objects. 5 | 6 | ## Contexts 7 | 8 | ObjC contains 2 contexts `CWPackContext` and `CWPUnpackContext`. 9 | 10 | #### Pack 11 | 12 | `CWPackContext` is layered on top of a `cw_pack_context`, which it receives at initiation. 13 | The `cw_pack_context` is then accessible through the property `context`. 14 | 15 | The other property on `CWPackContext` is the boolean property `useLabels`. It is defaulted to NO, but should be set to YES if you want references between objects to be kept. This makes the MessagePack stream more verbose so don't use it if you don't have to. 16 | 17 | To pack an object you just call: `[myPackContext packObject:anObject]`. 18 | 19 | #### Unpack 20 | 21 | `CWUnpackContext` is layered on top of a `cw_unpack_context`, which it receives at initiation. 22 | The `cw_unpack_context` is then accessible through the property `context`. 23 | 24 | To retreive an object you call `[myUnpackContext unpackNextObject]`. 25 | 26 | 27 | ## Packable objects 28 | 29 | When choosing if the packing should be automatic by inspection or explicit, we have chosen the latter, as it gives better control over the (un)packing, which can be important when communicating with others. For that reason, to be packable, objects need to fulfill the protocol `CWPackable`. 30 | 31 | ##### @property (readonly) int persistentAttributeCount 32 | 33 | This is the number of MessagePack items that the description of the object take. If you have a long prefix chain you normally defines it as 34 | 35 | ```C 36 | - (int) persistentAttributeCount { 37 | return myAttributeCount + super.persistentAttributeCount;} 38 | ``` 39 | On the next outermost level, where NSObject is the prefix class, you must not call `super`. 40 | 41 | ##### - (void) cwPackSub:(CWPackContext*)ctx 42 | 43 | This is the routine where you pack. Let´s take an example: 44 | 45 | ```C 46 | @interface MyClass: SomeOtherClass 47 | @property int level; 48 | @property MyClass *link; 49 | - (instancetype) initWithLevel:(int)level link:(MyClass*)link; 50 | @end 51 | ``` 52 | Note first, one attribute is a link to another instance, so here we should set useLabels to YES. Our pack method could be like this: 53 | 54 | ```C 55 | - (void) cwPackSub:(CWPackContext*)ctx { 56 | [super cwPackSub:ctx]; 57 | cw_pack_signed(ctx.context, level); 58 | [ctx packObject:link]; 59 | } 60 | ``` 61 | If the immediate ancestor to MyClass is NSObject, then super must not be called. 62 | 63 | Unpacking can be a little more tangled due to the possibility of circular references, that is a referenced object has a reference back to the root object. Unpacking happens in two steps: first the object is allocated and in the next step the attributes are set. 64 | 65 | Step 1: Allocation & Initiating 66 | 67 | ##### - (instancetype) cwUnpackSubInit:(CWUnpackContext*)ctx remainingAttributes:(int)remainingAttributes 68 | 69 | 70 | When `cwUnpackSubInit` is called, self is allocated but not inited. The sole purpose of the method is to return a suitable inited object. It is not neccesary to be the same object as self. If it is sufficient to sent init to the preallocated object (self), this method could be skipped, it's optional. 71 | 72 | Step 2: Fetching attributes. 73 | 74 | ##### - (void) cwUnpackSub:(CWUnpackContext*)ctx remainingAttributes:(int)remainingAttributes 75 | 76 | In the pack example an unpack method could be: 77 | 78 | ```C 79 | - (void) cwUnpackSub:(CWUnpackContext*)ctx remainingAttributes:(int)remainingAttributes { 80 | [super cwUnpackSub:ctx remainingAttributes:remainingAttributes - 2] 81 | level = cw_unpack_next_signed32 (ctx.context); 82 | link = [ctx unpackNextObject]; 83 | } 84 | ``` 85 | As usual, don't call super on NSObject. 86 | 87 | ### Packable system objects 88 | (Un)packing of the following system classes is predefined in ObjC: 89 | NSArray, NSDictionary, NSData, NSDate, NSNull, NSNumber, NSSet, NSCountableSet and NSString. In most cases they are mapped at their corresponding MessagePack item. !WARNING! MessagePack has an arbitrary type as key in map. Objective-C demands a string key in the corresponding NSDictionary. 90 | 91 | Of those who have both mutable and immutable versions, NSData and NSString are created immutable, and NSArray, NSDictionary and NSSet are created mutable at unpack. 92 | 93 | ### Special 94 | There are two special cases. 95 | 96 | First, when the MessagePack item is of an unknown EXT type, it will be unpacked as an instance of the `CWPackExternalItem` class. 97 | 98 | Second, when the object to be unpacked is of unknown user class, it is unpacked as an instance of the class `CWPackGenericClass`. 99 | -------------------------------------------------------------------------------- /goodies/objC/Technique.md: -------------------------------------------------------------------------------- 1 | # CWPack / Goodies / ObjC / Technique 2 | 3 | We have choosen to represent objects as arrays. To be able to differentiate objects from normal arrays we have put an object marker as the first slot of the array. The object marker is an EXT item with type 127. The second array slot is kept by the class name. The rest of the array slots are kept by the objects attributes. 4 | 5 | ### User objects 6 | 7 | We have an example: 8 | 9 | ```C 10 | @interface MyClass: NSObject 11 | @property int level; 12 | @property MyClass *link; 13 | - (instancetype) initWithLevel:(int)level link:(MyClass*)link; 14 | @end 15 | ``` 16 | When packed into a MessagePack stream it may look like: 17 | 18 | ```C 19 | [(127,<00>) "MyClass" 37 NULL] 20 | ``` 21 | This was the simple example where the link was nil. But look at this code fragment: 22 | 23 | ```C 24 | MyClass *a = [MyClass.alloc initWithLevel:10 link:nil]; 25 | MyClass *b = [MyClass.alloc initWithLevel:20 link:a]; 26 | a.link = b; 27 | [myContext packObject:a]; 28 | ``` 29 | To not fall into eternal recursion we need to break the circular reference in some way. We do it by giving the objects labels (set useLabel = YES on pack context). The labels are just consecutive numbers starting at 1. We store the label in the objects markers payload. Let´s start packing: 30 | 31 | ```C 32 | [(127,<01>) // object a got the label 1, we note that in a table 33 | [(127,<01>) "MyClass" 10 [(127,<02>) "MyClass" 20 34 | ``` 35 | Now it is time to insert object *a* again. But this time we have the object in our table and instead of packing the object we just pack a reference to it. A reference is an array with a single slot that is the object marker. The final result becomes: 36 | 37 | ```C 38 | [(127,<01>) "MyClass" 10 [(127,<02>) "MyClass" 20 [(127,<01>)]]] 39 | ``` 40 | The cwpack dump utility "knows" object markers and prints the above message as: 41 | 42 | 1->MyClass(10 2->MyClass(20 ->1)) 43 | 44 | ### MessagePack items 45 | 46 | It is not just user objects that can contain circular references. Take this example: 47 | 48 | ```C 49 | NSMutableArray *a = NSMutableArray.new; 50 | [a addObject:a]; 51 | [myContext packObject:a]; 52 | ``` 53 | Obviously we need a way to label MessagePack objects also. To that point we divide the MessagePack items in two cathegories: references and values. Arrays and maps are references and all other items are values. For references we do as for user objects, but instead of a class-name in the second slot we put the MessagePack object. In this case, there are just 2 slots. So the packing above becomes: 54 | 55 | ```C 56 | [(127,<01>) [[(127,<01>)]]] 57 | ``` 58 | Or prettyprinted: 1->[->1] 59 | -------------------------------------------------------------------------------- /goodies/objC/obsolete/README.md: -------------------------------------------------------------------------------- 1 | # CWPack / Goodies / ObjC 2 | 3 | 4 | ObjC contains a wrapper for objective-C in the form of a category to NSObject. 5 | The category contains two methods: 6 | 7 | ```C 8 | /* *********************** P A C K *****************************/ 9 | - (void) packIn:(cw_pack_context*) buff; 10 | 11 | /* *********************** U N P A C K *************************/ 12 | + (instancetype) unpackFrom:(cw_unpack_context*) buff; 13 | ``` 14 | 15 | The methods are defined for the standard classes NSString, NSData, NSNumber, NSDate, NSNull, NSDictionary, NSArray and NSSet. 16 | 17 | For other classes you need to define the methods yourself. E.g. 18 | 19 | ```C 20 | @interface myClass: NSObject { 21 | int theInt; 22 | NSMutableSet theSet; 23 | } 24 | @end 25 | 26 | @implementation myClass 27 | - (void) packIn:(cw_pack_context*) buff 28 | { 29 | cw_pack_signed( buff, theInt ); 30 | [theSet packIn:buff]; 31 | } 32 | + (instancetype) unpackFrom:(cw_unpack_context*) buff 33 | { 34 | int anInt = cw_unpack_next_signed32( buff ); 35 | NSMutableSet aSet = [NSMutableSet unpackFrom:buff]; 36 | return [[self alloc] initWithInt:anInt set:aSet]; 37 | } 38 | @end 39 | ``` 40 | 41 | -------------------------------------------------------------------------------- /goodies/objC/obsolete/cwpack_objc.h: -------------------------------------------------------------------------------- 1 | /* CWPack/goodies - cwpack_objc.h */ 2 | /* 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2017 Claes Wihlborg 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 8 | software and associated documentation files (the "Software"), to deal in the Software 9 | without restriction, including without limitation the rights to use, copy, modify, 10 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 11 | persons to whom the Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or 14 | substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 17 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | DAMAGES OR OTHER 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 SOFTWARE. 21 | */ 22 | 23 | 24 | #import 25 | #import "cwpack.h" 26 | 27 | 28 | 29 | 30 | @interface NSObject (cwPack) 31 | 32 | /* *********************** P A C K *****************************/ 33 | - (void) packIn:(cw_pack_context*) buff; 34 | 35 | /* *********************** U N P A C K *************************/ 36 | - (id) initFromContext:(cw_unpack_context*) buff; 37 | + (instancetype) unpackFrom:(cw_unpack_context*) buff; 38 | @end 39 | -------------------------------------------------------------------------------- /goodies/objC/obsolete/cwpack_objc.m: -------------------------------------------------------------------------------- 1 | /* CWPack/goodies - cwpack_objc.m */ 2 | /* 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2017 Claes Wihlborg 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 8 | software and associated documentation files (the "Software"), to deal in the Software 9 | without restriction, including without limitation the rights to use, copy, modify, 10 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 11 | persons to whom the Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or 14 | substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 17 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | DAMAGES OR OTHER 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 SOFTWARE. 21 | */ 22 | 23 | 24 | #import "cwpack_objc.h" 25 | #import "cwpack_utils.h" 26 | 27 | #define CWP_ITEM_CLASS_NAME 127 28 | 29 | 30 | id cwObjectFromBuffer (cw_unpack_context* inbuf); 31 | 32 | 33 | @implementation NSObject (cwPack) 34 | 35 | - (void) packIn:(cw_pack_context*) buff 36 | { 37 | const char *className= object_getClassName(self); 38 | cw_pack_ext (buff, CWP_ITEM_CLASS_NAME, className, (uint32_t)strlen(className)); 39 | } 40 | 41 | 42 | + (instancetype) setWithArray:(NSArray*)array {return nil;} 43 | 44 | 45 | + (instancetype) unpackFrom:(cw_unpack_context*) buff 46 | { 47 | id result = cwObjectFromBuffer(buff); 48 | 49 | if (![[result class] isSubclassOfClass:self]) 50 | { 51 | if ([[result class] isSubclassOfClass:[NSArray class]] && [self isSubclassOfClass:[NSSet class]]) 52 | return [self setWithArray:result]; 53 | 54 | if ([[result class] isSubclassOfClass:[NSNull class]]) 55 | return nil; 56 | 57 | else 58 | { 59 | buff->return_code = CWP_RC_TYPE_ERROR; // Unexpected object type 60 | [NSException raise:@"[NSObject unpackFrom:]" format:@"Class %@ detected when expected class: %@", [result class], self]; 61 | } 62 | } 63 | return result; 64 | } 65 | 66 | 67 | - (id) initFromContext:(cw_unpack_context*) buff 68 | { 69 | self = [self init]; // satisfy compiler 70 | buff->return_code = CWP_RC_ILLEGAL_CALL; // No unpack defined for this object type 71 | [NSException raise:@"Not defined" format:@"[%@ initFromContext:]", [self class]]; 72 | return nil; 73 | } 74 | 75 | 76 | @end 77 | 78 | 79 | @implementation NSNull (cwPack) 80 | 81 | - (void) packIn:(cw_pack_context*) buff 82 | { 83 | cw_pack_nil (buff); 84 | } 85 | @end 86 | 87 | 88 | @implementation NSString (cwPack) 89 | 90 | - (void) packIn:(cw_pack_context*) buff 91 | { 92 | cw_pack_cstr (buff, self.UTF8String); 93 | } 94 | @end 95 | 96 | 97 | @implementation NSData (cwPack) 98 | 99 | - (void) packIn:(cw_pack_context*) buff 100 | { 101 | cw_pack_bin(buff, self.bytes, (uint32_t)self.length); 102 | } 103 | @end 104 | 105 | 106 | @implementation NSNumber (cwPack) 107 | 108 | - (void) packIn:(cw_pack_context*) buff 109 | { 110 | CFNumberType numberType = CFNumberGetType((CFNumberRef)self); 111 | switch (numberType) 112 | { 113 | case kCFNumberSInt8Type: 114 | case kCFNumberSInt16Type: 115 | case kCFNumberShortType: 116 | case kCFNumberSInt32Type: 117 | case kCFNumberIntType: 118 | case kCFNumberLongType: 119 | case kCFNumberCFIndexType: 120 | case kCFNumberNSIntegerType: 121 | case kCFNumberSInt64Type: 122 | case kCFNumberLongLongType: 123 | cw_pack_signed(buff, self.longLongValue); 124 | return; 125 | 126 | case kCFNumberFloat32Type: 127 | case kCFNumberFloatType: 128 | case kCFNumberCGFloatType: 129 | cw_pack_float(buff, self.floatValue); 130 | return; 131 | 132 | case kCFNumberFloat64Type: 133 | case kCFNumberDoubleType: 134 | cw_pack_double(buff, self.doubleValue); 135 | return; 136 | 137 | case kCFNumberCharType: 138 | { 139 | int theValue = self.intValue; 140 | if (theValue == 0) 141 | { 142 | cw_pack_boolean(buff, NO); 143 | } 144 | if (theValue == 1) 145 | { 146 | cw_pack_boolean(buff, YES); 147 | } 148 | else 149 | { 150 | cw_pack_signed(buff, theValue); 151 | } 152 | return; 153 | } 154 | default: 155 | buff->return_code = CWP_RC_ILLEGAL_CALL; // No pack defined for this object type 156 | [NSException raise:@"[NSNumber packIn:]" format:@"Cannot recognise type of: %@", self]; 157 | } 158 | } 159 | @end 160 | 161 | 162 | @implementation NSArray (cwPack) 163 | 164 | - (void) packIn:(cw_pack_context*) buff 165 | { 166 | uint32_t i, cnt = (uint32_t)self.count; 167 | cw_pack_array_size(buff, cnt); 168 | for (i = 0; i < cnt; i++) 169 | [self[i] packIn:buff]; 170 | } 171 | @end 172 | 173 | 174 | @implementation NSSet (cwPack) 175 | 176 | - (void) packIn:(cw_pack_context*) buff 177 | { 178 | uint32_t cnt = (uint32_t)self.count; 179 | cw_pack_array_size(buff, cnt); // Hide the set in an array 180 | for (id object in self) 181 | [object packIn:buff]; 182 | } 183 | @end 184 | 185 | 186 | @implementation NSDictionary (cwPack) 187 | 188 | - (void) packIn:(cw_pack_context*) buff 189 | { 190 | cw_pack_map_size(buff, (uint32_t)self.count); 191 | for (id obj in self) 192 | { 193 | [obj packIn:buff]; 194 | [self[obj] packIn:buff]; 195 | } 196 | } 197 | @end 198 | 199 | 200 | @implementation NSDate (cwPack) 201 | 202 | - (void) packIn:(cw_pack_context*) buff 203 | { 204 | NSTimeInterval ti = self.timeIntervalSince1970; 205 | cw_pack_time_interval (buff, ti); 206 | } 207 | 208 | 209 | @end 210 | 211 | 212 | 213 | 214 | /******************************* U N P A C K ******************************/ 215 | 216 | 217 | id cwObjectFromBuffer (cw_unpack_context* inbuf) 218 | { 219 | cw_unpack_next(inbuf); 220 | if (inbuf->return_code) 221 | return nil; 222 | 223 | switch (inbuf->item.type) 224 | { 225 | case CWP_ITEM_NIL: 226 | return [NSNull null]; 227 | 228 | case CWP_ITEM_BOOLEAN: 229 | return [NSNumber numberWithBool:inbuf->item.as.boolean]; 230 | 231 | case CWP_ITEM_POSITIVE_INTEGER: 232 | return [NSNumber numberWithUnsignedLongLong:inbuf->item.as.u64]; 233 | 234 | case CWP_ITEM_NEGATIVE_INTEGER: 235 | return [NSNumber numberWithLongLong:inbuf->item.as.i64]; 236 | 237 | case CWP_ITEM_FLOAT: 238 | return [[NSNumber alloc] initWithFloat:inbuf->item.as.real]; 239 | 240 | case CWP_ITEM_DOUBLE: 241 | return [NSNumber numberWithDouble:inbuf->item.as.long_real]; 242 | 243 | case CWP_ITEM_STR: 244 | return [[NSString alloc] initWithBytes:inbuf->item.as.str.start length:inbuf->item.as.str.length encoding:NSUTF8StringEncoding]; 245 | 246 | case CWP_ITEM_BIN: 247 | return [NSData dataWithBytes:inbuf->item.as.bin.start length:inbuf->item.as.bin.length]; 248 | 249 | case CWP_ITEM_ARRAY: 250 | { 251 | int i, dim = inbuf->item.as.array.size; 252 | NSMutableArray *arr = [NSMutableArray arrayWithCapacity:dim]; 253 | for(i = 0; i < dim; i++) 254 | { 255 | id item = cwObjectFromBuffer (inbuf); 256 | if (!inbuf->return_code) 257 | [arr addObject:item]; 258 | } 259 | return arr; 260 | } 261 | 262 | case CWP_ITEM_MAP: 263 | { 264 | int i, dim = inbuf->item.as.map.size; 265 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:dim]; 266 | for(i = 0; i < dim; i++) 267 | { 268 | id key = cwObjectFromBuffer (inbuf); 269 | id val = cwObjectFromBuffer (inbuf); 270 | if (!inbuf->return_code) 271 | [dict setValue:val forKey:key]; 272 | } 273 | return dict; 274 | } 275 | 276 | case CWP_ITEM_TIMESTAMP: 277 | { 278 | return [NSDate dateWithTimeIntervalSince1970:inbuf->item.as.time.tv_sec + inbuf->item.as.time.tv_nsec / 1000000000.0]; 279 | } 280 | 281 | case CWP_ITEM_CLASS_NAME: 282 | { 283 | NSString *cName = [[NSString alloc] initWithBytes:inbuf->item.as.ext.start length:inbuf->item.as.ext.length encoding:NSUTF8StringEncoding]; 284 | Class objectClass = NSClassFromString(cName); 285 | if (objectClass == NULL) 286 | { 287 | [NSException raise:@"cwObjectFromBuffer" format:@"Class not defined for class: %@", cName]; 288 | } 289 | else 290 | return [[objectClass alloc] initFromContext:inbuf]; 291 | } 292 | 293 | default: 294 | return nil; 295 | } 296 | } 297 | 298 | 299 | 300 | -------------------------------------------------------------------------------- /goodies/swift/CWPack.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CWPack.swift 3 | // CWPack 4 | // 5 | // Created by Claes Wihlborg on 2022-01-17. 6 | // 7 | 8 | /* 9 | The MIT License (MIT) 10 | 11 | Copyright (c) 2021 Claes Wihlborg 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 14 | software and associated documentation files (the "Software"), to deal in the Software 15 | without restriction, including without limitation the rights to use, copy, modify, 16 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 17 | persons to whom the Software is furnished to do so, subject to the following conditions: 18 | 19 | The above copyright notice and this permission notice shall be included in all copies or 20 | substantial portions of the Software. 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 23 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 25 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | 30 | import Foundation 31 | //import AppKit 32 | 33 | 34 | enum CWPackError: Error { 35 | case fileError(_ errNo:Int) 36 | case contextError(_ err:Int32) 37 | case packerError(_ err:String) 38 | case unpackerError(_ err:String) 39 | } 40 | 41 | 42 | // MARK: ------------------------------ MessagePack Objects 43 | 44 | struct CWNil { 45 | } 46 | 47 | struct ArrayHeader { 48 | let count:Int 49 | init (_ count:Int) {self.count = count} 50 | init () {count = 0} 51 | } 52 | 53 | struct DictionaryHeader { 54 | let count:UInt32 55 | init (_ count:UInt32) {self.count = count} 56 | init () {count = 0} 57 | } 58 | 59 | struct MsgPackExt { 60 | let type: Int8 61 | let data: Data 62 | init (_ type:Int8, _ data: Data) { 63 | self.type = type 64 | self.data = data 65 | } 66 | } 67 | 68 | 69 | // MARK: ------------------------------ MessagePacker 70 | 71 | class CWPacker { 72 | let p: UnsafeMutablePointer 73 | 74 | var optimizeReal: Bool = true 75 | var OK: Bool {p.pointee.return_code == CWP_RC_OK} 76 | 77 | init(_ p:UnsafeMutablePointer) { 78 | self.p = p 79 | } 80 | } 81 | 82 | 83 | class CWDataPacker: CWPacker { 84 | private var context = dynamic_memory_pack_context() 85 | 86 | var data: Data { 87 | let c:Int = context.pc.current - context.pc.start 88 | return Data(bytes:context.pc.start, count:c)} 89 | 90 | init() { 91 | super.init(&context.pc) 92 | init_dynamic_memory_pack_context(&context, 1024) 93 | } 94 | } 95 | 96 | 97 | class CWFilePacker: CWPacker { 98 | private var context = file_pack_context() 99 | private let ownsChannel: Bool 100 | let fh: FileHandle? 101 | 102 | func flush() {cw_pack_flush(&context.pc)} 103 | 104 | init(to descriptor:Int32) { 105 | ownsChannel = false 106 | fh = nil 107 | super.init(&context.pc) 108 | init_file_pack_context(&context, 1024, descriptor) 109 | } 110 | 111 | init(to url:URL) throws { 112 | fh = try FileHandle(forWritingTo: url) 113 | ownsChannel = true 114 | super.init(&context.pc) 115 | init_file_pack_context(&context, 1024, fh!.fileDescriptor) 116 | } 117 | 118 | deinit { 119 | terminate_file_pack_context(&context) 120 | // if ownsChannel {close(context.fileDescriptor)} 121 | } 122 | } 123 | 124 | 125 | // MARK: ------------------------------ MessageUnpacker 126 | 127 | class CWUnpacker { 128 | let p: UnsafeMutablePointer 129 | var OK: Bool {p.pointee.return_code == CWP_RC_OK} 130 | 131 | init(_ p:UnsafeMutablePointer) { 132 | self.p = p 133 | } 134 | } 135 | 136 | 137 | class CWDataUnpacker: CWUnpacker { 138 | private var context = cw_unpack_context() 139 | private var buffer: [UInt8] 140 | init(from data: Data) { 141 | buffer = Array(repeating: UInt8(0), count: data.count) 142 | super.init(&context) 143 | data.copyBytes(to: &buffer, count: data.count) 144 | cw_unpack_context_init(&context, buffer, UInt(data.count), nil) 145 | } 146 | } 147 | 148 | 149 | class CWFileUnpacker: CWUnpacker { 150 | private var context = file_unpack_context() 151 | private let ownsChannel: Bool 152 | let fh: FileHandle? 153 | 154 | init(from descriptor:Int32) { 155 | ownsChannel = false 156 | fh = nil 157 | super.init(&context.uc) 158 | init_file_unpack_context(&context, 1024, descriptor) 159 | } 160 | 161 | init(from url:URL) throws { 162 | fh = try FileHandle(forReadingFrom: url) 163 | ownsChannel = true 164 | super.init(&context.uc) 165 | init_file_unpack_context(&context, 1024, fh!.fileDescriptor) 166 | } 167 | 168 | deinit { 169 | terminate_file_unpack_context(&context) 170 | // if ownsChannel {close(context.fileDescriptor)} 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /goodies/swift/CWPackable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CWPackable.swift 3 | // CWPack 4 | // 5 | // Created by Claes Wihlborg on 2022-01-17. 6 | // 7 | 8 | /* 9 | The MIT License (MIT) 10 | 11 | Copyright (c) 2021 Claes Wihlborg 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 14 | software and associated documentation files (the "Software"), to deal in the Software 15 | without restriction, including without limitation the rights to use, copy, modify, 16 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 17 | persons to whom the Software is furnished to do so, subject to the following conditions: 18 | 19 | The above copyright notice and this permission notice shall be included in all copies or 20 | substantial portions of the Software. 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 23 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 25 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | 30 | import Foundation 31 | 32 | 33 | // MARK: ----------------------------------------------- CWPackable protocol 34 | 35 | 36 | protocol CWPackable { 37 | @discardableResult static func + (lhs: CWPacker, rhs: Self) -> CWPacker 38 | 39 | func cwPack(_ packer: CWPacker) 40 | 41 | @discardableResult static func - (lhs: CWUnpacker, rhs: inout Self) throws -> CWUnpacker 42 | 43 | init (_ unpacker: CWUnpacker) throws 44 | } 45 | 46 | 47 | extension CWPackable { 48 | @discardableResult static func + (lhs: CWPacker, rhs: Self) -> CWPacker { 49 | rhs.cwPack(lhs) 50 | return lhs 51 | } 52 | 53 | @discardableResult static func - (lhs: CWUnpacker, rhs: inout Self) throws -> CWUnpacker { 54 | rhs = try self.init(lhs) 55 | return lhs 56 | } 57 | } 58 | 59 | // MARK: ----------------------------------------------- MessagePack type extensions 60 | 61 | extension CWNil: CWPackable { 62 | func cwPack(_ packer: CWPacker) { 63 | cw_pack_nil(packer.p)} 64 | 65 | init (_ unpacker: CWUnpacker) throws { 66 | cw_unpack_next_nil(unpacker.p) 67 | guard unpacker.OK else {throw CWPackError.unpackerError("CWNil")} 68 | } 69 | } 70 | 71 | extension ArrayHeader: CWPackable { 72 | func cwPack(_ packer: CWPacker) { 73 | cw_pack_array_size(packer.p, UInt32(self.count))} 74 | 75 | init (_ unpacker: CWUnpacker) throws { 76 | self.count = Int(cw_unpack_next_array_size(unpacker.p)) 77 | guard unpacker.OK else {throw CWPackError.unpackerError("ArrayHeader")} 78 | } 79 | } 80 | 81 | extension DictionaryHeader: CWPackable { 82 | func cwPack(_ packer: CWPacker) { 83 | cw_pack_map_size(packer.p, UInt32(self.count))} 84 | 85 | init (_ unpacker: CWUnpacker) throws { 86 | self.count = cw_unpack_next_map_size(unpacker.p) 87 | guard unpacker.OK else {throw CWPackError.unpackerError("DictionaryHeader")} 88 | } 89 | } 90 | 91 | extension MsgPackExt: CWPackable { 92 | func cwPack(_ packer: CWPacker) { 93 | data.withUnsafeBytes {ptr in cw_pack_ext (packer.p, type, ptr.baseAddress, UInt32(data.count))} 94 | } 95 | init (_ unpacker: CWUnpacker) throws { 96 | cw_unpack_next(unpacker.p) 97 | guard unpacker.OK && unpacker.p.pointee.item.type.rawValue <= CWP_ITEM_MAX_USER_EXT.rawValue 98 | else {throw CWPackError.unpackerError("MsgPackExt")} 99 | self.init ( Int8(unpacker.p.pointee.item.type.rawValue), Data(bytes: unpacker.p.pointee.item.as.ext.start, count: Int(unpacker.p.pointee.item.as.ext.length))) 100 | } 101 | } 102 | 103 | 104 | // MARK: ----------------------------------------------- System type extensions 105 | 106 | extension Bool: CWPackable { 107 | func cwPack(_ packer: CWPacker) { 108 | cw_pack_boolean(packer.p, self)} 109 | 110 | init (_ unpacker: CWUnpacker) throws { 111 | self = cw_unpack_next_boolean(unpacker.p) 112 | guard unpacker.OK else {throw CWPackError.unpackerError("Bool")} 113 | } 114 | } 115 | 116 | extension Int: CWPackable { 117 | func cwPack(_ packer: CWPacker) { 118 | cw_pack_signed(packer.p, Int64(self))} 119 | 120 | init (_ unpacker: CWUnpacker) throws { 121 | self = Int(cw_unpack_next_signed64(unpacker.p)) 122 | guard unpacker.OK else {throw CWPackError.unpackerError("Int")} 123 | } 124 | } 125 | 126 | extension Int8: CWPackable { 127 | func cwPack(_ packer: CWPacker) { 128 | cw_pack_signed(packer.p, Int64(self))} 129 | 130 | init (_ unpacker: CWUnpacker) throws { 131 | self = cw_unpack_next_signed8(unpacker.p) 132 | guard unpacker.OK else {throw CWPackError.unpackerError("Int8")} 133 | } 134 | } 135 | 136 | extension Int16: CWPackable { 137 | func cwPack(_ packer: CWPacker) { 138 | cw_pack_signed(packer.p, Int64(self))} 139 | 140 | init (_ unpacker: CWUnpacker) throws { 141 | self = cw_unpack_next_signed16(unpacker.p) 142 | guard unpacker.OK else {throw CWPackError.unpackerError("Int16")} 143 | } 144 | } 145 | 146 | extension Int32: CWPackable { 147 | func cwPack(_ packer: CWPacker) { 148 | cw_pack_signed(packer.p, Int64(self))} 149 | 150 | init (_ unpacker: CWUnpacker) throws { 151 | self = cw_unpack_next_signed32(unpacker.p) 152 | guard unpacker.OK else {throw CWPackError.unpackerError("Int32")} 153 | } 154 | } 155 | 156 | extension Int64: CWPackable { 157 | func cwPack(_ packer: CWPacker) { 158 | cw_pack_signed(packer.p, Int64(self))} 159 | 160 | init (_ unpacker: CWUnpacker) throws { 161 | self = cw_unpack_next_signed64(unpacker.p) 162 | guard unpacker.OK else {throw CWPackError.unpackerError("Int64")} 163 | } 164 | } 165 | 166 | extension UInt: CWPackable { 167 | func cwPack(_ packer: CWPacker) { 168 | cw_pack_unsigned(packer.p, UInt64(self))} 169 | 170 | init (_ unpacker: CWUnpacker) throws { 171 | self = UInt(cw_unpack_next_unsigned64(unpacker.p)) 172 | guard unpacker.OK else {throw CWPackError.unpackerError("UInt")} 173 | } 174 | } 175 | 176 | extension UInt8: CWPackable { 177 | func cwPack(_ packer: CWPacker) { 178 | cw_pack_unsigned(packer.p, UInt64(self))} 179 | 180 | init (_ unpacker: CWUnpacker) throws { 181 | self = cw_unpack_next_unsigned8(unpacker.p) 182 | guard unpacker.OK else {throw CWPackError.unpackerError("UInt8")} 183 | } 184 | } 185 | 186 | extension UInt16: CWPackable { 187 | func cwPack(_ packer: CWPacker) { 188 | cw_pack_unsigned(packer.p, UInt64(self))} 189 | 190 | init (_ unpacker: CWUnpacker) throws { 191 | self = cw_unpack_next_unsigned16(unpacker.p) 192 | guard unpacker.OK else {throw CWPackError.unpackerError("UInt16")} 193 | } 194 | } 195 | 196 | extension UInt32: CWPackable { 197 | func cwPack(_ packer: CWPacker) { 198 | cw_pack_unsigned(packer.p, UInt64(self))} 199 | 200 | init (_ unpacker: CWUnpacker) throws { 201 | self = cw_unpack_next_unsigned32(unpacker.p) 202 | guard unpacker.OK else {throw CWPackError.unpackerError("UInt32")} 203 | } 204 | } 205 | 206 | extension UInt64: CWPackable { 207 | func cwPack(_ packer: CWPacker) { 208 | cw_pack_unsigned(packer.p, UInt64(self))} 209 | 210 | init (_ unpacker: CWUnpacker) throws { 211 | self = cw_unpack_next_unsigned64(unpacker.p) 212 | guard unpacker.OK else {throw CWPackError.unpackerError("UInt64")} 213 | } 214 | } 215 | 216 | extension Float: CWPackable { 217 | func cwPack(_ packer: CWPacker) { 218 | if packer.optimizeReal { cw_pack_float_opt(packer.p, self) } 219 | else { cw_pack_float(packer.p, self) } 220 | } 221 | 222 | init (_ unpacker: CWUnpacker) throws { 223 | self = cw_unpack_next_float(unpacker.p) 224 | guard unpacker.OK else {throw CWPackError.unpackerError("Float")} 225 | } 226 | } 227 | 228 | extension Double: CWPackable { 229 | func cwPack(_ packer: CWPacker) { 230 | if packer.optimizeReal { cw_pack_double_opt(packer.p, self) } 231 | else { cw_pack_double(packer.p, self) } 232 | } 233 | 234 | init (_ unpacker: CWUnpacker) throws { 235 | self = cw_unpack_next_double(unpacker.p) 236 | guard unpacker.OK else {throw CWPackError.unpackerError("Double")} 237 | } 238 | } 239 | 240 | extension Date: CWPackable { 241 | func cwPack(_ packer: CWPacker) { 242 | cw_pack_time_interval(packer.p, self.timeIntervalSince1970)} 243 | 244 | init (_ unpacker: CWUnpacker) throws { 245 | self.init(timeIntervalSince1970: cw_unpack_next_time_interval(unpacker.p)) 246 | guard unpacker.OK else {throw CWPackError.unpackerError("Date")} 247 | } 248 | } 249 | 250 | extension Data: CWPackable { 251 | func cwPack(_ packer: CWPacker) { 252 | self.withUnsafeBytes {ptr in cw_pack_bin (packer.p, ptr.baseAddress, UInt32(ptr.count))} 253 | } 254 | 255 | init (_ unpacker: CWUnpacker) throws { 256 | let l = cw_unpack_next_bin_lengh(unpacker.p) 257 | guard unpacker.OK else {throw CWPackError.unpackerError("Data")} 258 | if l > 0 {self.init(bytes: unpacker.p.pointee.item.as.bin.start, count: Int(l))} 259 | else {self.init()} 260 | } 261 | } 262 | 263 | extension String: CWPackable { 264 | func cwPack(_ packer: CWPacker) { 265 | let s = self.utf8CString 266 | s.withUnsafeBufferPointer {ptr in cw_pack_str (packer.p, ptr.baseAddress, UInt32(strlen(ptr.baseAddress!)))} 267 | } 268 | 269 | init (_ unpacker: CWUnpacker) throws { 270 | let l = cw_unpack_next_str_lengh(unpacker.p) 271 | guard unpacker.OK else {throw CWPackError.unpackerError("String")} 272 | if l > 0 {self.init(NSString(bytes: unpacker.p.pointee.item.as.str.start, length: Int(l), encoding: String.Encoding.utf8.rawValue)!)} 273 | else {self.init()} 274 | } 275 | } 276 | 277 | extension Array: CWPackable where Element: CWPackable { 278 | func cwPack(_ packer: CWPacker) { 279 | packer + ArrayHeader(self.count) 280 | if self.count > 0 { 281 | for i in 0.. 0 { 291 | for _ in 1...ah.count { 292 | let e: Element = try Element(unpacker) 293 | self.append(e) 294 | } 295 | } 296 | } 297 | } 298 | 299 | extension ArraySlice: CWPackable where Element: CWPackable { 300 | func cwPack(_ packer: CWPacker) { 301 | packer + ArrayHeader(self.count) 302 | if self.count > 0 { 303 | for i in startIndex.. 0 { 313 | for _ in 1...ah.count { 314 | let e: Element = try Element(unpacker) 315 | self.append(e) 316 | } 317 | } 318 | } 319 | } 320 | 321 | extension Dictionary: CWPackable where Key: CWPackable , Value: CWPackable { 322 | func cwPack(_ packer: CWPacker) { 323 | packer + DictionaryHeader(UInt32(self.count)) 324 | if self.count > 0 { 325 | for key in self.keys { 326 | packer + key + self[key]! 327 | } 328 | } 329 | } 330 | 331 | init (_ unpacker: CWUnpacker) throws { 332 | let ah = try DictionaryHeader(unpacker) 333 | self.init() 334 | if ah.count > 0 { 335 | for _ in 1...ah.count { 336 | let k: Key = try Key(unpacker) 337 | let v: Value = try Value(unpacker) 338 | self[k] = v 339 | } 340 | } 341 | } 342 | } 343 | 344 | -------------------------------------------------------------------------------- /goodies/swift/README.md: -------------------------------------------------------------------------------- 1 | # CWPack / Goodies / Swift 2 | 3 | This folder contains a pack and an unpack context and a packable protocol to enable Swift items in the MessagePack stream. 4 | 5 | ## Contexts 6 | 7 | The swift interface contains 4 contexts `CWDataPacker`, `CWFilePacker`, `CWDataUnpacker` and `CWFileUnpacker`. All are layered on the corresponding c structures accessable though the property `p`. 8 | 9 | The file packer/unpacker comes in 2 flavours, inited with an URL or with a file descriptor. 10 | 11 | #### Pack 12 | 13 | `CWDataPacker` is layered on top of a `dynamic_memory_pack_context` and `CWFilePacker` is layerd on top of a `file_pack_context`. 14 | 15 | To pack an item you call: `item.cwPack(packer)` 16 | 17 | After packing you can check the result by inspecting the packer property `OK`. 18 | 19 | The packers have a property `optimizeReal`. When true, a check is performed to see if real items losslessly could be casted to a shorter representation, e.g. 0.0 is saved as an (1 byte) integer and Double 0.5 is saved as a Float. 20 | 21 | #### Unpack 22 | 23 | `CWDataUnpacker` is layered on top of a `cw_unpack_context` and 24 | `CWFileUnpacker` is layered on `file_unpack_context`. 25 | 26 | To retreive items you call the init(_ unpacker: CWUnpacker) initializer e.g: 27 | `let i = Int(unpacker)` and 28 | `let ar: [String] = Array(unpacker)` 29 | 30 | If the messagepack stream doesn't contain the expected item, an exception is thrown. 31 | 32 | Doubles accept both Float and Integer as valid values at unpack. 33 | 34 | ## Conveniance operators '+' and '-' 35 | 36 | To simplify packing and unpacking two operators are defined for packers/unpackers. When packing you can write: 37 | 38 | `packer + value1 + value2 ...` (think of it as adding values to the packer stream) and when unpacking you can write: 39 | 40 | `unpacker - variable1 - variable2...` 41 | 42 | Note however, this has limited usage in inits, as the variables are handled as `inout` parameters and if they are properties, they are considered used before assigned by the compiler. 43 | 44 | ## Packable items 45 | 46 | When choosing if the packing should be automatic by inspection or explicit, we have chosen the latter, as it gives better control over the (un)packing, which can be important when communicating with others. For that reason, to be packable, objects need to fulfill the protocol `CWPackable`. 47 | 48 | To fulfill the `CWPackable` protocol, an item must implement 2 methods: 49 | 50 | - `init(_ unpacker:CWUnpacker) throws` and 51 | - `cwPack(_ packer:CWPacker)` 52 | 53 | The file CWPackable.swift contains CWPackable exstensions of some system types. 54 | 55 | ### MessagePack items 56 | 57 | MessagePack has some types that don't have exact match in Swift. To simplify usage they are defined in CWPack.swift. They are: 58 | 59 | - `CWNil` to be able to handle nil items. 60 | - `ArrayHeader` and 61 | - `DictionaryHeader` to be able to pack/unpack structures in an incremental fashion. 62 | - `MsgPackExt` to handle extension types. However, the standard extension type Timestamp is mapped to Swift type Date. 63 | 64 | ## Installation 65 | 66 | The interface is delivered as source files that you include in your project. The following source files (and corresponding header files) must be included: 67 | 68 | - CWPack/src/cwpack.c 69 | - CWPack/goodies/basic-contexts/basic_contexts.c 70 | - CWPack/goodies/utils/cwpack_utils.c 71 | - CWPack/goodies/swift/CWPack.swift 72 | - CWPack/goodies/swift/CWPackable.swift 73 | 74 | If you use XCode you should place this snippet in the file xxx-Bridging-Header.h 75 | 76 | ``` 77 | #include "cwpack.h" 78 | #include "cwpack_utils.h" 79 | #include "basic_contexts.h" 80 | ``` 81 | 82 | ## Example 83 | 84 | When you write pack code it's a good routine to contain struct and class properties in an array. This way it works if you in turn put those structures in other containers (Arrays and Dictionaries) 85 | 86 | ``` 87 | struct RGB { 88 | let r,g,b: UInt8 89 | cwPack(_ packer:CWPacker) { 90 | packer + ArrayHeader(3) + r + g + b 91 | } 92 | init(_ unpacker:CWUnpacker) throws { 93 | guard try ArrayHeader(unpacker).count == 3 else {throw some error} 94 | r = try UInt8(unpacker) 95 | g = try UInt8(unpacker) 96 | b = try UInt8(unpacker) 97 | } 98 | } 99 | ``` 100 | The packing line above could also be written as: 101 | `packer + [r,g,b]` with the same result. 102 | 103 | Now you can use this struct in another struct: 104 | 105 | ``` 106 | struct palette { 107 | colors: [RGB] 108 | alpha: UInt8 109 | cwPack(_ packer:CWPacker) { 110 | packer + ArrayHeader(2) + colors + alpha 111 | } 112 | init(_ unpacker:CWUnpacker) throws { 113 | guard try ArrayHeader(unpacker).count == 2 else {throw some error} 114 | colors = try Array(unpacker) 115 | alpha = try UInt8(unpacker) 116 | } 117 | } 118 | ``` 119 | 120 | ## Failings 121 | 122 | I'm sorry for this section but one has to face the facts. To be able to unpack (at least with this library), you must know the type of the next item. So if you have a definition like: 123 | `var ar: [Any]`, you can't write: 124 | `ar = try Array(unpacker)` 125 | 126 | The same problem arises with subclasses. In both cases one can often solv the dilemma with incremental unpacking and intelligent lookahead of what's coming next. 127 | -------------------------------------------------------------------------------- /goodies/utils/README.md: -------------------------------------------------------------------------------- 1 | # CWPack / Goodies / Utils 2 | 3 | 4 | Utils contains some convenience routines: 5 | 6 | ### C string packing 7 | ```C 8 | void cw_pack_cstr (cw_pack_context* pack_context, const char* v); 9 | ``` 10 | 11 | ### Optimized packing of real numbers 12 | Pack float as signed if precision isn't destroyed 13 | 14 | ```C 15 | void cw_pack_float_opt (cw_pack_context* pack_context, float f); 16 | ``` 17 | Pack double as signed or float if precision isn't destroyed 18 | 19 | ```C 20 | void cw_pack_double_opt (cw_pack_context* pack_context, double d); 21 | ``` 22 | 23 | ### Packing seconds and fractions thereof that have elapsed since epoch 24 | ```C 25 | void cw_pack_time_interval (cw_pack_context* pack_context, double ti); 26 | ``` 27 | ### Easy retreival (expect api) 28 | 29 | ```C 30 | bool cw_unpack_next_boolean (cw_unpack_context* unpack_context); 31 | 32 | int64_t cw_unpack_next_signed64 (cw_unpack_context* unpack_context); 33 | int32_t cw_unpack_next_signed32 (cw_unpack_context* unpack_context); 34 | int16_t cw_unpack_next_signed16 (cw_unpack_context* unpack_context); 35 | int8_t cw_unpack_next_signed8 (cw_unpack_context* unpack_context); 36 | 37 | uint64_t cw_unpack_next_unsigned64 (cw_unpack_context* unpack_context); 38 | uint32_t cw_unpack_next_unsigned32 (cw_unpack_context* unpack_context); 39 | uint16_t cw_unpack_next_unsigned16 (cw_unpack_context* unpack_context); 40 | uint8_t cw_unpack_next_unsigned8 (cw_unpack_context* unpack_context); 41 | 42 | float cw_unpack_next_float (cw_unpack_context* unpack_context); 43 | double cw_unpack_next_double (cw_unpack_context* unpack_context); 44 | double cw_unpack_next_time_interval (cw_unpack_context* unpack_context); 45 | 46 | unsigned int cw_unpack_next_str_lengh (cw_unpack_context* unpack_context); 47 | 48 | unsigned int cw_unpack_next_array_size(cw_unpack_context* unpack_context); 49 | unsigned int cw_unpack_next_map_size(cw_unpack_context* unpack_context); 50 | ``` 51 | The functions signals `CWP_RC_TYPE_ERROR` if next item isn't compatible with the expected type. For int and uint types the functions signals `CWP_RC_VALUE_ERROR` if value is compatible but out of range. 52 | 53 | -------------------------------------------------------------------------------- /goodies/utils/cwpack_utils.c: -------------------------------------------------------------------------------- 1 | /* CWPack/goodies - cwpack_utils.c */ 2 | /* 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2017 Claes Wihlborg 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 8 | software and associated documentation files (the "Software"), to deal in the Software 9 | without restriction, including without limitation the rights to use, copy, modify, 10 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 11 | persons to whom the Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or 14 | substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 17 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | DAMAGES OR OTHER 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 SOFTWARE. 21 | */ 22 | 23 | 24 | #include 25 | #include "cwpack_utils.h" 26 | 27 | 28 | 29 | 30 | /******************************* P A C K **********************************/ 31 | 32 | 33 | void cw_pack_double_opt (cw_pack_context* pack_context, double d) 34 | { 35 | int i = (int)d; 36 | if ((i == d) && (i >= INT32_MIN) && (i <= UINT32_MAX)) 37 | cw_pack_signed(pack_context, i); 38 | else 39 | { 40 | float f = (float)d; 41 | if (f == d) 42 | cw_pack_float (pack_context, f); 43 | else 44 | cw_pack_double (pack_context, d); 45 | } 46 | } 47 | 48 | 49 | void cw_pack_float_opt (cw_pack_context* pack_context, float f) 50 | { 51 | int i = (int)f; 52 | if ((i == f) && (i >= INT16_MIN) && (i <= UINT16_MAX)) 53 | cw_pack_signed(pack_context, i); 54 | else 55 | cw_pack_float (pack_context, f); 56 | } 57 | 58 | void cw_pack_time_interval (cw_pack_context* pack_context, double ti) 59 | { 60 | int64_t sec = (int64_t)floor(ti); 61 | uint32_t nsec = (uint32_t)((ti - (double)sec) * 1000000000.0); 62 | cw_pack_time(pack_context, sec, nsec); 63 | } 64 | 65 | /******************************* U N P A C K ******************************/ 66 | 67 | #define NaN 0 68 | 69 | float cw_unpack_next_float (cw_unpack_context* unpack_context) 70 | { 71 | cw_unpack_next (unpack_context); 72 | if (unpack_context->return_code) return NaN; 73 | 74 | switch (unpack_context->item.type) { 75 | case CWP_ITEM_POSITIVE_INTEGER: return unpack_context->item.as.u64; 76 | case CWP_ITEM_NEGATIVE_INTEGER: return unpack_context->item.as.i64; 77 | case CWP_ITEM_FLOAT: return unpack_context->item.as.real; 78 | case CWP_ITEM_DOUBLE: return (float)unpack_context->item.as.long_real; 79 | default: unpack_context->return_code = CWP_RC_TYPE_ERROR; 80 | return NaN; 81 | } 82 | } 83 | 84 | double cw_unpack_next_double (cw_unpack_context* unpack_context) 85 | { 86 | cw_unpack_next (unpack_context); 87 | if (unpack_context->return_code) return NaN; 88 | 89 | switch (unpack_context->item.type) { 90 | case CWP_ITEM_POSITIVE_INTEGER: return unpack_context->item.as.u64; 91 | case CWP_ITEM_NEGATIVE_INTEGER: return unpack_context->item.as.i64; 92 | case CWP_ITEM_FLOAT: return unpack_context->item.as.real; 93 | case CWP_ITEM_DOUBLE: return unpack_context->item.as.long_real; 94 | default: unpack_context->return_code = CWP_RC_TYPE_ERROR; 95 | return NaN; 96 | } 97 | } 98 | 99 | void cw_unpack_next_nil (cw_unpack_context* unpack_context) 100 | { 101 | cw_unpack_next (unpack_context); 102 | if (unpack_context->return_code) 103 | return; 104 | if (unpack_context->item.type == CWP_ITEM_NIL) 105 | return; 106 | 107 | unpack_context->return_code = CWP_RC_TYPE_ERROR; 108 | return; 109 | } 110 | 111 | 112 | 113 | bool cw_unpack_next_boolean (cw_unpack_context* unpack_context) 114 | { 115 | cw_unpack_next (unpack_context); 116 | if (unpack_context->return_code) 117 | return false; 118 | 119 | if (unpack_context->item.type == CWP_ITEM_BOOLEAN) 120 | return unpack_context->item.as.boolean; 121 | 122 | unpack_context->return_code = CWP_RC_TYPE_ERROR; 123 | return false; 124 | } 125 | 126 | 127 | int64_t cw_unpack_next_signed64 (cw_unpack_context* unpack_context) 128 | { 129 | cw_unpack_next (unpack_context); 130 | if (unpack_context->return_code) 131 | return 0; 132 | 133 | if (unpack_context->item.type == CWP_ITEM_POSITIVE_INTEGER) 134 | { 135 | if (unpack_context->item.as.u64 <= INT64_MAX) 136 | return unpack_context->item.as.i64; 137 | else 138 | { 139 | unpack_context->return_code = CWP_RC_VALUE_ERROR; 140 | return 0; 141 | } 142 | } 143 | 144 | if (unpack_context->item.type == CWP_ITEM_NEGATIVE_INTEGER) 145 | return unpack_context->item.as.i64; 146 | 147 | unpack_context->return_code = CWP_RC_TYPE_ERROR; 148 | return 0; 149 | } 150 | 151 | 152 | int32_t cw_unpack_next_signed32 (cw_unpack_context* unpack_context) 153 | { 154 | cw_unpack_next (unpack_context); 155 | if (unpack_context->return_code) 156 | return 0; 157 | 158 | if (unpack_context->item.type == CWP_ITEM_POSITIVE_INTEGER) 159 | { 160 | if (unpack_context->item.as.u64 <= INT32_MAX) 161 | return (int)unpack_context->item.as.i64; 162 | else 163 | { 164 | unpack_context->return_code = CWP_RC_VALUE_ERROR; 165 | return 0; 166 | } 167 | } 168 | if (unpack_context->item.type == CWP_ITEM_NEGATIVE_INTEGER) 169 | { 170 | if (unpack_context->item.as.i64 >= INT32_MIN) 171 | return (int)unpack_context->item.as.i64; 172 | else 173 | { 174 | unpack_context->return_code = CWP_RC_VALUE_ERROR; 175 | return 0; 176 | } 177 | } 178 | 179 | unpack_context->return_code = CWP_RC_TYPE_ERROR; 180 | return 0; 181 | } 182 | 183 | 184 | int16_t cw_unpack_next_signed16 (cw_unpack_context* unpack_context) 185 | { 186 | cw_unpack_next (unpack_context); 187 | if (unpack_context->return_code) 188 | return 0; 189 | 190 | if (unpack_context->item.type == CWP_ITEM_POSITIVE_INTEGER) 191 | { 192 | if (unpack_context->item.as.u64 <= INT16_MAX) 193 | return (int16_t)unpack_context->item.as.i64; 194 | else 195 | { 196 | unpack_context->return_code = CWP_RC_VALUE_ERROR; 197 | return 0; 198 | } 199 | } 200 | if (unpack_context->item.type == CWP_ITEM_NEGATIVE_INTEGER) 201 | { 202 | if (unpack_context->item.as.i64 >= INT16_MIN) 203 | return (int16_t)unpack_context->item.as.i64; 204 | else 205 | { 206 | unpack_context->return_code = CWP_RC_VALUE_ERROR; 207 | return 0; 208 | } 209 | } 210 | 211 | unpack_context->return_code = CWP_RC_TYPE_ERROR; 212 | return 0; 213 | } 214 | 215 | 216 | int8_t cw_unpack_next_signed8 (cw_unpack_context* unpack_context) 217 | { 218 | cw_unpack_next (unpack_context); 219 | if (unpack_context->return_code) 220 | return 0; 221 | 222 | if (unpack_context->item.type == CWP_ITEM_POSITIVE_INTEGER) 223 | { 224 | if (unpack_context->item.as.u64 <= INT8_MAX) 225 | return (int8_t)unpack_context->item.as.i64; 226 | else 227 | { 228 | unpack_context->return_code = CWP_RC_VALUE_ERROR; 229 | return 0; 230 | } 231 | } 232 | if (unpack_context->item.type == CWP_ITEM_NEGATIVE_INTEGER) 233 | { 234 | if (unpack_context->item.as.i64 >= INT8_MIN) 235 | return (int8_t)unpack_context->item.as.i64; 236 | else 237 | { 238 | unpack_context->return_code = CWP_RC_VALUE_ERROR; 239 | return 0; 240 | } 241 | } 242 | 243 | unpack_context->return_code = CWP_RC_TYPE_ERROR; 244 | return 0; 245 | } 246 | 247 | 248 | 249 | uint64_t cw_unpack_next_unsigned64 (cw_unpack_context* unpack_context) 250 | { 251 | cw_unpack_next (unpack_context); 252 | if (unpack_context->return_code) 253 | return 0; 254 | 255 | if (unpack_context->item.type == CWP_ITEM_POSITIVE_INTEGER) 256 | { 257 | return unpack_context->item.as.u64; 258 | } 259 | 260 | unpack_context->return_code = CWP_RC_TYPE_ERROR; 261 | return 0; 262 | } 263 | 264 | 265 | uint32_t cw_unpack_next_unsigned32 (cw_unpack_context* unpack_context) 266 | { 267 | cw_unpack_next (unpack_context); 268 | if (unpack_context->return_code) 269 | return 0; 270 | 271 | if (unpack_context->item.type == CWP_ITEM_POSITIVE_INTEGER) 272 | { 273 | if (unpack_context->item.as.u64 <= UINT32_MAX) 274 | return (uint32_t)unpack_context->item.as.u64; 275 | else 276 | { 277 | unpack_context->return_code = CWP_RC_VALUE_ERROR; 278 | return 0; 279 | } 280 | } 281 | 282 | unpack_context->return_code = CWP_RC_TYPE_ERROR; 283 | return 0; 284 | } 285 | 286 | 287 | uint16_t cw_unpack_next_unsigned16 (cw_unpack_context* unpack_context) 288 | { 289 | cw_unpack_next (unpack_context); 290 | if (unpack_context->return_code) 291 | return 0; 292 | 293 | if (unpack_context->item.type == CWP_ITEM_POSITIVE_INTEGER) 294 | { 295 | if (unpack_context->item.as.u64 <= UINT16_MAX) 296 | return (uint16_t)unpack_context->item.as.u64; 297 | else 298 | { 299 | unpack_context->return_code = CWP_RC_VALUE_ERROR; 300 | return 0; 301 | } 302 | } 303 | 304 | unpack_context->return_code = CWP_RC_TYPE_ERROR; 305 | return 0; 306 | } 307 | 308 | 309 | uint8_t cw_unpack_next_unsigned8 (cw_unpack_context* unpack_context) 310 | { 311 | cw_unpack_next (unpack_context); 312 | if (unpack_context->return_code) 313 | return 0; 314 | 315 | if (unpack_context->item.type == CWP_ITEM_POSITIVE_INTEGER) 316 | { 317 | if (unpack_context->item.as.u64 <= UINT8_MAX) 318 | return (uint8_t)unpack_context->item.as.u64; 319 | else 320 | { 321 | unpack_context->return_code = CWP_RC_VALUE_ERROR; 322 | return 0; 323 | } 324 | } 325 | 326 | unpack_context->return_code = CWP_RC_TYPE_ERROR; 327 | return 0; 328 | } 329 | 330 | 331 | double cw_unpack_next_time_interval (cw_unpack_context* unpack_context) 332 | { 333 | cw_unpack_next (unpack_context); 334 | if (unpack_context->return_code) return NaN; 335 | 336 | if (unpack_context->item.type == CWP_ITEM_TIMESTAMP) 337 | { 338 | return (double)unpack_context->item.as.time.tv_sec + (double)unpack_context->item.as.time.tv_nsec/1000000000; 339 | } 340 | 341 | unpack_context->return_code = CWP_RC_TYPE_ERROR; 342 | return NaN; 343 | } 344 | 345 | unsigned int cw_unpack_next_str_lengh (cw_unpack_context* unpack_context) 346 | { 347 | cw_unpack_next (unpack_context); 348 | if (unpack_context->return_code) return 0; 349 | 350 | if (unpack_context->item.type == CWP_ITEM_STR) 351 | return unpack_context->item.as.str.length; 352 | 353 | unpack_context->return_code = CWP_RC_TYPE_ERROR; 354 | return 0; 355 | } 356 | 357 | 358 | unsigned int cw_unpack_next_bin_lengh (cw_unpack_context* unpack_context) 359 | { 360 | cw_unpack_next (unpack_context); 361 | if (unpack_context->return_code) return 0; 362 | 363 | if (unpack_context->item.type == CWP_ITEM_BIN) 364 | return unpack_context->item.as.bin.length; 365 | 366 | unpack_context->return_code = CWP_RC_TYPE_ERROR; 367 | return 0; 368 | } 369 | 370 | 371 | unsigned int cw_unpack_next_array_size(cw_unpack_context* unpack_context) 372 | { 373 | cw_unpack_next (unpack_context); 374 | if (unpack_context->return_code) return 0; 375 | 376 | if (unpack_context->item.type == CWP_ITEM_ARRAY) 377 | return unpack_context->item.as.array.size; 378 | 379 | unpack_context->return_code = CWP_RC_TYPE_ERROR; 380 | return 0; 381 | } 382 | 383 | unsigned int cw_unpack_next_map_size(cw_unpack_context* unpack_context) 384 | { 385 | cw_unpack_next (unpack_context); 386 | if (unpack_context->return_code) return 0; 387 | 388 | if (unpack_context->item.type == CWP_ITEM_MAP) 389 | return unpack_context->item.as.map.size; 390 | 391 | unpack_context->return_code = CWP_RC_TYPE_ERROR; 392 | return 0; 393 | } 394 | 395 | -------------------------------------------------------------------------------- /goodies/utils/cwpack_utils.h: -------------------------------------------------------------------------------- 1 | /* CWPack/goodies - cwpack_utils.h */ 2 | /* 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2017 Claes Wihlborg 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 8 | software and associated documentation files (the "Software"), to deal in the Software 9 | without restriction, including without limitation the rights to use, copy, modify, 10 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 11 | persons to whom the Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or 14 | substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 17 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | DAMAGES OR OTHER 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 SOFTWARE. 21 | */ 22 | 23 | #ifndef CWPack_utils_H__ 24 | #define CWPack_utils_H__ 25 | 26 | 27 | #include "cwpack.h" 28 | 29 | /******************************* P A C K **********************************/ 30 | 31 | #define cw_pack_cstr(context,string) cw_pack_str (context, string, (uint32)strlen(string)) 32 | 33 | void cw_pack_float_opt (cw_pack_context* pack_context, float f); /* Pack as signed if precision isn't destroyed */ 34 | void cw_pack_double_opt (cw_pack_context* pack_context, double d); /* Pack as signed or float if precision isn't destroyed */ 35 | #define cw_pack_real cw_pack_double_opt /* Backward compatibility */ 36 | 37 | #define cw_pack_timespec (pack_contextptr, timespecptr) cw_pack_time ((pack_contextptr), (int64_t)((timespecptr)->tv_sec), (uint32_t)((timespecptr)->tv_nsec)) 38 | 39 | void cw_pack_time_interval (cw_pack_context* pack_context, double ti); /* ti is seconds relative epoch */ 40 | 41 | /***************************** U N P A C K ********************************/ 42 | 43 | void cw_unpack_next_nil (cw_unpack_context* unpack_context); 44 | bool cw_unpack_next_boolean (cw_unpack_context* unpack_context); 45 | 46 | int64_t cw_unpack_next_signed64 (cw_unpack_context* unpack_context); 47 | int32_t cw_unpack_next_signed32 (cw_unpack_context* unpack_context); 48 | int16_t cw_unpack_next_signed16 (cw_unpack_context* unpack_context); 49 | int8_t cw_unpack_next_signed8 (cw_unpack_context* unpack_context); 50 | 51 | uint64_t cw_unpack_next_unsigned64 (cw_unpack_context* unpack_context); 52 | uint32_t cw_unpack_next_unsigned32 (cw_unpack_context* unpack_context); 53 | uint16_t cw_unpack_next_unsigned16 (cw_unpack_context* unpack_context); 54 | uint8_t cw_unpack_next_unsigned8 (cw_unpack_context* unpack_context); 55 | 56 | float cw_unpack_next_float (cw_unpack_context* unpack_context); 57 | double cw_unpack_next_double (cw_unpack_context* unpack_context); 58 | double cw_unpack_next_time_interval (cw_unpack_context* unpack_context); 59 | #define cw_unpack_next_real cw_unpack_next_double /* Backward compatibility */ 60 | 61 | unsigned int cw_unpack_next_str_lengh (cw_unpack_context* unpack_context); 62 | unsigned int cw_unpack_next_bin_lengh (cw_unpack_context* unpack_context); 63 | 64 | unsigned int cw_unpack_next_array_size(cw_unpack_context* unpack_context); 65 | unsigned int cw_unpack_next_map_size(cw_unpack_context* unpack_context); 66 | 67 | #endif /* CWPack_utils_H__ */ 68 | 69 | -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | # CWPack / src 2 | 3 | The src folder contains all basic functionallity to use CWPack. 4 | 5 | ## Files 6 | 7 | **cwpack.h** contains the interface to CWPack. You should include this in your code. 8 | 9 | **cwpack_config.h** contains info about your processor. Byte order, alignment etc. Update this file to suit you. 10 | 11 | **cwpack_internals.h** contains internal macros for cwpack.c. If you are an experienced developer you can use them to access the inner mechanics of CWPack. 12 | 13 | **cwpack.c** contains the code. 14 | 15 | ## Contexts 16 | Central to CWPack is the concept of contexts. There are two: `cw_pack_context` and `cw_unpack_context`. They contains all the necessary bookkeeping and a reference to the appropriate context is given in all routine calls. 17 | 18 | CWPack is working against memory buffers. Handlers, stored in the context, are called when a buffer is filled up (packing) or needs refill (unpack). The contexts in this folder handles static memory buffers, but more complex contexts that handles dynamic memory, files and sockets can be found in [goodies/basic-contexts](https://github.com/clwi/CWPack/tree/master/goodies/basic-contexts). 19 | 20 | ## How to use 21 | First you choose a context that suits your needs and initiates it. Then you can do the packing/unpacking. 22 | 23 | CWpack is using a streaming model, containers (arrays, maps) are read/written in parts, first the item containing the size and then the contained items one by one. Exception to this is the `cw_skip_items` function which skips whole containers. 24 | 25 | You find some convenience routines for packing and an expect api for unpacking in [goodies/utils](https://github.com/clwi/CWPack/tree/master/goodies/utils). 26 | You find an Objective-C wrapper in [goodies/objC](https://github.com/clwi/CWPack/tree/master/goodies/objC). 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/cwpack.h: -------------------------------------------------------------------------------- 1 | /* CWPack - cwpack.h */ 2 | /* 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2017 Claes Wihlborg 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 8 | software and associated documentation files (the "Software"), to deal in the Software 9 | without restriction, including without limitation the rights to use, copy, modify, 10 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 11 | persons to whom the Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or 14 | substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 17 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | DAMAGES OR OTHER 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 SOFTWARE. 21 | */ 22 | 23 | #ifndef CWPack_H__ 24 | #define CWPack_H__ 25 | 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | 32 | 33 | /******************************* Return Codes *****************************/ 34 | 35 | #define CWP_RC_OK 0 36 | #define CWP_RC_END_OF_INPUT -1 37 | #define CWP_RC_BUFFER_OVERFLOW -2 38 | #define CWP_RC_BUFFER_UNDERFLOW -3 39 | #define CWP_RC_MALFORMED_INPUT -4 40 | #define CWP_RC_WRONG_BYTE_ORDER -5 41 | #define CWP_RC_ERROR_IN_HANDLER -6 42 | #define CWP_RC_ILLEGAL_CALL -7 43 | #define CWP_RC_MALLOC_ERROR -8 44 | #define CWP_RC_STOPPED -9 45 | #define CWP_RC_TYPE_ERROR -10 46 | #define CWP_RC_VALUE_ERROR -11 47 | #define CWP_RC_WRONG_TIMESTAMP_LENGTH -12 48 | 49 | 50 | 51 | /******************************* P A C K **********************************/ 52 | 53 | 54 | struct cw_pack_context; 55 | 56 | typedef int (*pack_overflow_handler)(struct cw_pack_context*, unsigned long); 57 | typedef int (*pack_flush_handler)(struct cw_pack_context*); 58 | 59 | typedef struct cw_pack_context { 60 | uint8_t* current; 61 | uint8_t* start; 62 | uint8_t* end; 63 | bool be_compatible; 64 | int return_code; 65 | int err_no; /* handlers can save error here */ 66 | pack_overflow_handler handle_pack_overflow; 67 | pack_flush_handler handle_flush; 68 | } cw_pack_context; 69 | 70 | 71 | int cw_pack_context_init (cw_pack_context* pack_context, void* data, unsigned long length, pack_overflow_handler hpo); 72 | void cw_pack_set_compatibility (cw_pack_context* pack_context, bool be_compatible); 73 | void cw_pack_set_flush_handler (cw_pack_context* pack_context, pack_flush_handler handle_flush); 74 | void cw_pack_flush (cw_pack_context* pack_context); 75 | 76 | void cw_pack_nil (cw_pack_context* pack_context); 77 | void cw_pack_true (cw_pack_context* pack_context); 78 | void cw_pack_false (cw_pack_context* pack_context); 79 | void cw_pack_boolean (cw_pack_context* pack_context, bool b); 80 | 81 | void cw_pack_signed (cw_pack_context* pack_context, int64_t i); 82 | void cw_pack_unsigned (cw_pack_context* pack_context, uint64_t i); 83 | 84 | void cw_pack_float (cw_pack_context* pack_context, float f); 85 | void cw_pack_double (cw_pack_context* pack_context, double d); 86 | /* void cw_pack_real (cw_pack_context* pack_context, double d); moved to cwpack_utils */ 87 | 88 | void cw_pack_array_size (cw_pack_context* pack_context, uint32_t n); 89 | void cw_pack_map_size (cw_pack_context* pack_context, uint32_t n); 90 | void cw_pack_str (cw_pack_context* pack_context, const char* v, uint32_t l); 91 | void cw_pack_bin (cw_pack_context* pack_context, const void* v, uint32_t l); 92 | void cw_pack_ext (cw_pack_context* pack_context, int8_t type, const void* v, uint32_t l); 93 | void cw_pack_time (cw_pack_context* pack_context, int64_t sec, uint32_t nsec); 94 | 95 | void cw_pack_insert (cw_pack_context* pack_context, const void* v, uint32_t l); 96 | 97 | 98 | /***************************** U N P A C K ********************************/ 99 | 100 | 101 | typedef enum 102 | { 103 | CWP_ITEM_MIN_RESERVED_EXT = -128, 104 | CWP_ITEM_TIMESTAMP = -1, 105 | CWP_ITEM_MAX_RESERVED_EXT = -1, 106 | CWP_ITEM_MIN_USER_EXT = 0, 107 | CWP_ITEM_USER_EXT_0 = 0, 108 | CWP_ITEM_USER_EXT_1 = 1, 109 | CWP_ITEM_USER_EXT_2 = 2, 110 | CWP_ITEM_USER_EXT_3 = 3, 111 | CWP_ITEM_USER_EXT_4 = 4, 112 | CWP_ITEM_USER_EXT_5 = 5, 113 | CWP_ITEM_USER_EXT_6 = 6, 114 | CWP_ITEM_USER_EXT_7 = 7, 115 | CWP_ITEM_USER_EXT_8 = 8, 116 | CWP_ITEM_USER_EXT_9 = 9, 117 | CWP_ITEM_USER_EXT_10 = 10, 118 | CWP_ITEM_USER_EXT_11 = 11, 119 | CWP_ITEM_USER_EXT_12 = 12, 120 | CWP_ITEM_USER_EXT_13 = 13, 121 | CWP_ITEM_USER_EXT_14 = 14, 122 | CWP_ITEM_USER_EXT_15 = 15, 123 | CWP_ITEM_USER_EXT_16 = 16, 124 | CWP_ITEM_USER_EXT_17 = 17, 125 | CWP_ITEM_USER_EXT_18 = 18, 126 | CWP_ITEM_USER_EXT_19 = 19, 127 | CWP_ITEM_USER_EXT_20 = 20, 128 | CWP_ITEM_USER_EXT_21 = 21, 129 | CWP_ITEM_USER_EXT_22 = 22, 130 | CWP_ITEM_USER_EXT_23 = 23, 131 | CWP_ITEM_USER_EXT_24 = 24, 132 | CWP_ITEM_USER_EXT_25 = 25, 133 | CWP_ITEM_USER_EXT_26 = 26, 134 | CWP_ITEM_USER_EXT_27 = 27, 135 | CWP_ITEM_USER_EXT_28 = 28, 136 | CWP_ITEM_USER_EXT_29 = 29, 137 | CWP_ITEM_USER_EXT_30 = 30, 138 | CWP_ITEM_USER_EXT_31 = 31, 139 | CWP_ITEM_USER_EXT_32 = 32, 140 | CWP_ITEM_USER_EXT_33 = 33, 141 | CWP_ITEM_USER_EXT_34 = 34, 142 | CWP_ITEM_USER_EXT_35 = 35, 143 | CWP_ITEM_USER_EXT_36 = 36, 144 | CWP_ITEM_USER_EXT_37 = 37, 145 | CWP_ITEM_USER_EXT_38 = 38, 146 | CWP_ITEM_USER_EXT_39 = 39, 147 | CWP_ITEM_USER_EXT_40 = 40, 148 | CWP_ITEM_USER_EXT_41 = 41, 149 | CWP_ITEM_USER_EXT_42 = 42, 150 | CWP_ITEM_USER_EXT_43 = 43, 151 | CWP_ITEM_USER_EXT_44 = 44, 152 | CWP_ITEM_USER_EXT_45 = 45, 153 | CWP_ITEM_USER_EXT_46 = 46, 154 | CWP_ITEM_USER_EXT_47 = 47, 155 | CWP_ITEM_USER_EXT_48 = 48, 156 | CWP_ITEM_USER_EXT_49 = 49, 157 | CWP_ITEM_USER_EXT_50 = 50, 158 | CWP_ITEM_USER_EXT_51 = 51, 159 | CWP_ITEM_USER_EXT_52 = 52, 160 | CWP_ITEM_USER_EXT_53 = 53, 161 | CWP_ITEM_USER_EXT_54 = 54, 162 | CWP_ITEM_USER_EXT_55 = 55, 163 | CWP_ITEM_USER_EXT_56 = 56, 164 | CWP_ITEM_USER_EXT_57 = 57, 165 | CWP_ITEM_USER_EXT_58 = 58, 166 | CWP_ITEM_USER_EXT_59 = 59, 167 | CWP_ITEM_USER_EXT_60 = 60, 168 | CWP_ITEM_USER_EXT_61 = 61, 169 | CWP_ITEM_USER_EXT_62 = 62, 170 | CWP_ITEM_USER_EXT_63 = 63, 171 | CWP_ITEM_USER_EXT_64 = 64, 172 | CWP_ITEM_USER_EXT_65 = 65, 173 | CWP_ITEM_USER_EXT_66 = 66, 174 | CWP_ITEM_USER_EXT_67 = 67, 175 | CWP_ITEM_USER_EXT_68 = 68, 176 | CWP_ITEM_USER_EXT_69 = 69, 177 | CWP_ITEM_USER_EXT_70 = 70, 178 | CWP_ITEM_USER_EXT_71 = 71, 179 | CWP_ITEM_USER_EXT_72 = 72, 180 | CWP_ITEM_USER_EXT_73 = 73, 181 | CWP_ITEM_USER_EXT_74 = 74, 182 | CWP_ITEM_USER_EXT_75 = 75, 183 | CWP_ITEM_USER_EXT_76 = 76, 184 | CWP_ITEM_USER_EXT_77 = 77, 185 | CWP_ITEM_USER_EXT_78 = 78, 186 | CWP_ITEM_USER_EXT_79 = 79, 187 | CWP_ITEM_USER_EXT_80 = 80, 188 | CWP_ITEM_USER_EXT_81 = 81, 189 | CWP_ITEM_USER_EXT_82 = 82, 190 | CWP_ITEM_USER_EXT_83 = 83, 191 | CWP_ITEM_USER_EXT_84 = 84, 192 | CWP_ITEM_USER_EXT_85 = 85, 193 | CWP_ITEM_USER_EXT_86 = 86, 194 | CWP_ITEM_USER_EXT_87 = 87, 195 | CWP_ITEM_USER_EXT_88 = 88, 196 | CWP_ITEM_USER_EXT_89 = 89, 197 | CWP_ITEM_USER_EXT_90 = 90, 198 | CWP_ITEM_USER_EXT_91 = 91, 199 | CWP_ITEM_USER_EXT_92 = 92, 200 | CWP_ITEM_USER_EXT_93 = 93, 201 | CWP_ITEM_USER_EXT_94 = 94, 202 | CWP_ITEM_USER_EXT_95 = 95, 203 | CWP_ITEM_USER_EXT_96 = 96, 204 | CWP_ITEM_USER_EXT_97 = 97, 205 | CWP_ITEM_USER_EXT_98 = 98, 206 | CWP_ITEM_USER_EXT_99 = 99, 207 | CWP_ITEM_USER_EXT_100 = 100, 208 | CWP_ITEM_USER_EXT_101 = 101, 209 | CWP_ITEM_USER_EXT_102 = 102, 210 | CWP_ITEM_USER_EXT_103 = 103, 211 | CWP_ITEM_USER_EXT_104 = 104, 212 | CWP_ITEM_USER_EXT_105 = 105, 213 | CWP_ITEM_USER_EXT_106 = 106, 214 | CWP_ITEM_USER_EXT_107 = 107, 215 | CWP_ITEM_USER_EXT_108 = 108, 216 | CWP_ITEM_USER_EXT_109 = 109, 217 | CWP_ITEM_USER_EXT_110 = 110, 218 | CWP_ITEM_USER_EXT_111 = 111, 219 | CWP_ITEM_USER_EXT_112 = 112, 220 | CWP_ITEM_USER_EXT_113 = 113, 221 | CWP_ITEM_USER_EXT_114 = 114, 222 | CWP_ITEM_USER_EXT_115 = 115, 223 | CWP_ITEM_USER_EXT_116 = 116, 224 | CWP_ITEM_USER_EXT_117 = 117, 225 | CWP_ITEM_USER_EXT_118 = 118, 226 | CWP_ITEM_USER_EXT_119 = 119, 227 | CWP_ITEM_USER_EXT_120 = 120, 228 | CWP_ITEM_USER_EXT_121 = 121, 229 | CWP_ITEM_USER_EXT_122 = 122, 230 | CWP_ITEM_USER_EXT_123 = 123, 231 | CWP_ITEM_USER_EXT_124 = 124, 232 | CWP_ITEM_USER_EXT_125 = 125, 233 | CWP_ITEM_USER_EXT_126 = 126, 234 | CWP_ITEM_USER_EXT_127 = 127, 235 | CWP_ITEM_MAX_USER_EXT = 127, 236 | 237 | CWP_ITEM_NIL = 300, 238 | CWP_ITEM_BOOLEAN = 301, 239 | CWP_ITEM_POSITIVE_INTEGER = 302, 240 | CWP_ITEM_NEGATIVE_INTEGER = 303, 241 | CWP_ITEM_FLOAT = 304, 242 | CWP_ITEM_DOUBLE = 305, 243 | CWP_ITEM_STR = 306, 244 | CWP_ITEM_BIN = 307, 245 | CWP_ITEM_ARRAY = 308, 246 | CWP_ITEM_MAP = 309, 247 | CWP_ITEM_EXT = 310, 248 | CWP_NOT_AN_ITEM = 999 249 | } cwpack_item_types; 250 | 251 | 252 | typedef struct { 253 | const void* start; 254 | uint32_t length; 255 | } cwpack_blob; 256 | 257 | 258 | typedef struct { 259 | uint32_t size; 260 | } cwpack_container; 261 | 262 | 263 | typedef struct { 264 | int64_t tv_sec; 265 | uint32_t tv_nsec; 266 | } cwpack_timespec; 267 | 268 | 269 | typedef struct { 270 | cwpack_item_types type; 271 | union 272 | { 273 | bool boolean; 274 | uint64_t u64; 275 | int64_t i64; 276 | float real; 277 | double long_real; 278 | cwpack_container array; 279 | cwpack_container map; 280 | cwpack_blob str; 281 | cwpack_blob bin; 282 | cwpack_blob ext; 283 | cwpack_timespec time; 284 | } as; 285 | } cwpack_item; 286 | 287 | struct cw_unpack_context; 288 | 289 | typedef int (*unpack_underflow_handler)(struct cw_unpack_context*, unsigned long); 290 | 291 | typedef struct cw_unpack_context { 292 | cwpack_item item; 293 | uint8_t* start; 294 | uint8_t* current; 295 | uint8_t* end; /* logical end of buffer */ 296 | int return_code; 297 | int err_no; /* handlers can save error here */ 298 | unpack_underflow_handler handle_unpack_underflow; 299 | } cw_unpack_context; 300 | 301 | 302 | 303 | int cw_unpack_context_init (cw_unpack_context* unpack_context, const void* data, unsigned long length, unpack_underflow_handler huu); 304 | 305 | void cw_unpack_next (cw_unpack_context* unpack_context); 306 | void cw_skip_items (cw_unpack_context* unpack_context, long item_count); 307 | cwpack_item_types cw_look_ahead (cw_unpack_context* unpack_context); 308 | 309 | 310 | #endif /* CWPack_H__ */ 311 | -------------------------------------------------------------------------------- /src/cwpack_config.h: -------------------------------------------------------------------------------- 1 | /* CWPack - cwpack_config.h */ 2 | /* 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2017 Claes Wihlborg 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 8 | software and associated documentation files (the "Software"), to deal in the Software 9 | without restriction, including without limitation the rights to use, copy, modify, 10 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 11 | persons to whom the Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or 14 | substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 17 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | DAMAGES OR OTHER 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 SOFTWARE. 21 | */ 22 | 23 | 24 | #ifndef cwpack_config_h 25 | #define cwpack_config_h 26 | 27 | 28 | 29 | /************************* A L I G N M E N T ******************************/ 30 | 31 | /* 32 | * Some processors demand that integer access is to an even memory address. 33 | * In that case define FORCE_ALIGNMENT 34 | */ 35 | 36 | /* #define FORCE_ALIGNMENT */ 37 | 38 | /* 39 | * Some processors demand that 64 bit integer access is aligned. 40 | * In that case define FORCE_ALIGNMENT_64BIT 41 | */ 42 | 43 | /* #define FORCE_ALIGNMENT_64BIT */ 44 | 45 | 46 | 47 | /************************* C S Y S T E M L I B R A R Y ****************/ 48 | 49 | /* 50 | * The packer uses "memcpy" to move blobs. If you dont want to load C system library 51 | * for just that, define FORCE_NO_LIBRARY and CWPack will use an internal "memcpy" 52 | */ 53 | 54 | /* #define FORCE_NO_LIBRARY */ 55 | 56 | 57 | 58 | /************************* B Y T E O R D E R ****************************/ 59 | 60 | /* 61 | * The pack/unpack routines are written in three versions: for big endian, for 62 | * little endian and insensitive to byte order. As you can get some speed gain 63 | * if the byte order is known, we try that when we can certainly detect it. 64 | * Define COMPILE_FOR_BIG_ENDIAN or COMPILE_FOR_LITTLE_ENDIAN if you know. 65 | */ 66 | 67 | #ifndef FORCE_ALIGNMENT 68 | #if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) 69 | 70 | #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 71 | #define COMPILE_FOR_BIG_ENDIAN 72 | #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 73 | #define COMPILE_FOR_LITTLE_ENDIAN 74 | #endif 75 | 76 | #elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN) 77 | 78 | #if __BYTE_ORDER == __BIG_ENDIAN 79 | #define COMPILE_FOR_BIG_ENDIAN 80 | #elif __BYTE_ORDER == __LITTLE_ENDIAN 81 | #define COMPILE_FOR_LITTLE_ENDIAN 82 | #endif 83 | 84 | #elif defined(__BIG_ENDIAN__) 85 | #define COMPILE_FOR_BIG_ENDIAN 86 | 87 | #elif defined(__LITTLE_ENDIAN__) 88 | #define COMPILE_FOR_LITTLE_ENDIAN 89 | 90 | #elif defined(__i386__) || defined(__x86_64__) 91 | #define COMPILE_FOR_LITTLE_ENDIAN 92 | 93 | #endif 94 | #endif 95 | 96 | //#undef COMPILE_FOR_LITTLE_ENDIAN 97 | 98 | 99 | 100 | #endif /* cwpack_config_h */ 101 | -------------------------------------------------------------------------------- /src/cwpack_internals.h: -------------------------------------------------------------------------------- 1 | /* CWPack - cwpack_defines.h */ 2 | /* 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2017 Claes Wihlborg 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 8 | software and associated documentation files (the "Software"), to deal in the Software 9 | without restriction, including without limitation the rights to use, copy, modify, 10 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 11 | persons to whom the Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or 14 | substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 17 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | DAMAGES OR OTHER 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 SOFTWARE. 21 | */ 22 | 23 | 24 | #ifndef cwpack_defines_h 25 | #define cwpack_defines_h 26 | 27 | #include "cwpack_config.h" 28 | 29 | 30 | #ifndef MOST_LIKELY 31 | #if defined(__GNUC__) || defined(__clang__) 32 | #define MOST_LIKELY(a,b) __builtin_expect((a),(b)) 33 | #else 34 | #define MOST_LIKELY(a,b) ((a) == (b)) 35 | #endif 36 | #endif 37 | 38 | 39 | /******************************* P A C K **********************************/ 40 | 41 | 42 | 43 | #define PACK_ERROR(error_code) \ 44 | { \ 45 | pack_context->return_code = error_code; \ 46 | return; \ 47 | } 48 | 49 | 50 | 51 | #ifdef COMPILE_FOR_BIG_ENDIAN 52 | 53 | #define cw_store16(x) *(uint16_t*)p = (uint16_t)x; 54 | #define cw_store32(x) *(uint32_t*)p = (uint32_t)x; 55 | #ifndef FORCE_ALIGNMENT_64BIT 56 | #define cw_store64(x) *(uint64_t*)p = (uint64_t)x; 57 | #else 58 | #define cw_store64(x) memcpy(p,&x,8); 59 | #endif 60 | 61 | #else /* Byte order little endian or undetermined */ 62 | 63 | #ifdef COMPILE_FOR_LITTLE_ENDIAN 64 | 65 | #define cw_store16(d) \ 66 | *(uint16_t*)p = (uint16_t)((((d) >> 8) & 0x0ff) | (d) << 8) 67 | 68 | #define cw_store32(x) \ 69 | *(uint32_t*)p = \ 70 | ((uint32_t)((((uint32_t)(x)) >> 24) | \ 71 | (((uint32_t)(x) & 0x00ff0000) >> 8) | \ 72 | (((uint32_t)(x) & 0x0000ff00) << 8) | \ 73 | (((uint32_t)(x)) << 24))); \ 74 | 75 | #ifndef FORCE_ALIGNMENT_64BIT 76 | #define cw_store64(x) \ 77 | *(uint64_t*)p = \ 78 | ((uint64_t)( \ 79 | (((((uint64_t)(x)) >> 40) | \ 80 | (((uint64_t)(x)) << 24)) & 0x0000ff000000ff00ULL) | \ 81 | (((((uint64_t)(x)) >> 24) | \ 82 | (((uint64_t)(x)) << 40)) & 0x00ff000000ff0000ULL) | \ 83 | (((uint64_t)(x) & 0x000000ff00000000ULL) >> 8) | \ 84 | (((uint64_t)(x) & 0x00000000ff000000ULL) << 8) | \ 85 | (((uint64_t)(x)) >> 56) | \ 86 | (((uint64_t)(x)) << 56))); 87 | #else 88 | #define cw_store64(z) \ 89 | *p = (uint8_t)(z >> 56); \ 90 | p[1] = (uint8_t)(z >> 48); \ 91 | p[2] = (uint8_t)(z >> 40); \ 92 | p[3] = (uint8_t)(z >> 32); \ 93 | p[4] = (uint8_t)(z >> 24); \ 94 | p[5] = (uint8_t)(z >> 16); \ 95 | p[6] = (uint8_t)(z >> 8); \ 96 | p[7] = (uint8_t)z; 97 | #endif 98 | 99 | #else /* Byte order undetermined */ 100 | 101 | #define cw_store16(d) \ 102 | *p = (uint8_t)(d >> 8); \ 103 | p[1] = (uint8_t)d; 104 | 105 | #define cw_store32(d) \ 106 | *p = (uint8_t)(d >> 24); \ 107 | p[1] = (uint8_t)(d >> 16); \ 108 | p[2] = (uint8_t)(d >> 8); \ 109 | p[3] = (uint8_t)d; 110 | 111 | #define cw_store64(z) \ 112 | *p = (uint8_t)(z >> 56); \ 113 | p[1] = (uint8_t)(z >> 48); \ 114 | p[2] = (uint8_t)(z >> 40); \ 115 | p[3] = (uint8_t)(z >> 32); \ 116 | p[4] = (uint8_t)(z >> 24); \ 117 | p[5] = (uint8_t)(z >> 16); \ 118 | p[6] = (uint8_t)(z >> 8); \ 119 | p[7] = (uint8_t)z; 120 | #endif 121 | #endif 122 | 123 | 124 | 125 | #define cw_pack_new_buffer(more) \ 126 | { \ 127 | if (!pack_context->handle_pack_overflow) \ 128 | PACK_ERROR(CWP_RC_BUFFER_OVERFLOW) \ 129 | int rc = pack_context->handle_pack_overflow (pack_context, (unsigned long)(more)); \ 130 | if (rc) \ 131 | PACK_ERROR(rc) \ 132 | } 133 | 134 | 135 | #define cw_pack_reserve_space(more) \ 136 | { \ 137 | p = pack_context->current; \ 138 | uint8_t* nyp = p + more; \ 139 | if (nyp > pack_context->end) \ 140 | { \ 141 | cw_pack_new_buffer(more) \ 142 | p = pack_context->current; \ 143 | nyp = p + more; \ 144 | } \ 145 | pack_context->current = nyp; \ 146 | } 147 | 148 | 149 | #define tryMove0(t) \ 150 | { \ 151 | if (pack_context->current == pack_context->end) \ 152 | cw_pack_new_buffer(1) \ 153 | *pack_context->current++ = (uint8_t)(t); \ 154 | return; \ 155 | } 156 | 157 | #define tryMove1(t,d) \ 158 | { \ 159 | uint8_t *p; \ 160 | cw_pack_reserve_space(2) \ 161 | *p++ = (uint8_t)t; \ 162 | *p = (uint8_t)d; \ 163 | return; \ 164 | } 165 | 166 | #define tryMove2(t,d) \ 167 | { \ 168 | uint8_t *p; \ 169 | cw_pack_reserve_space(3) \ 170 | *p++ = (uint8_t)t; \ 171 | cw_store16(d); \ 172 | return; \ 173 | } 174 | 175 | #define tryMove4(t,d) \ 176 | { \ 177 | uint8_t *p; \ 178 | cw_pack_reserve_space(5) \ 179 | *p++ = (uint8_t)t; \ 180 | cw_store32(d); \ 181 | return; \ 182 | } 183 | 184 | #define tryMove8(t,d) \ 185 | { \ 186 | uint8_t *p; \ 187 | cw_pack_reserve_space(9) \ 188 | *p++ = (uint8_t)t; \ 189 | cw_store64(d); \ 190 | return; \ 191 | } 192 | 193 | 194 | 195 | 196 | /******************************* U N P A C K **********************************/ 197 | 198 | 199 | 200 | #define UNPACK_ERROR_SUB(error_code,abortValue) \ 201 | { \ 202 | unpack_context->item.type = CWP_NOT_AN_ITEM; \ 203 | unpack_context->return_code = error_code; \ 204 | return abortValue; \ 205 | } 206 | 207 | #define UNPACK_ERROR(error_code) UNPACK_ERROR_SUB(error_code,) 208 | 209 | 210 | #ifdef COMPILE_FOR_BIG_ENDIAN 211 | 212 | #define cw_load16(ptr) tmpu16 = *(uint16_t*)ptr; 213 | #define cw_load32(ptr) tmpu32 = *(uint32_t*)ptr; 214 | #ifndef FORCE_ALIGNMENT_64BIT 215 | #define cw_load64(ptr,dest) dest = *(uint64_t*)ptr; 216 | #else 217 | #define cw_load64(ptr,dest) memcpy(&dest,ptr,8); 218 | #endif 219 | 220 | #else /* Byte order little endian or undetermined */ 221 | 222 | #ifdef COMPILE_FOR_LITTLE_ENDIAN 223 | 224 | #define cw_load16(ptr) \ 225 | tmpu16 = *(uint16_t*)ptr; \ 226 | tmpu16 = (uint16_t)((tmpu16<<8) | (tmpu16>>8)) 227 | 228 | #define cw_load32(ptr) \ 229 | tmpu32 = *(uint32_t*)ptr; \ 230 | tmpu32 = (tmpu32<<24) | ((tmpu32 & 0xff00)<<8) | \ 231 | ((tmpu32 & 0xff0000)>>8) | (tmpu32>>24) 232 | 233 | #ifndef FORCE_ALIGNMENT_64BIT 234 | #define cw_load64(ptr,dest) \ 235 | tmpu64 = *((uint64_t*)ptr); \ 236 | dest = ( \ 237 | (((tmpu64 >> 40) | \ 238 | (tmpu64 << 24)) & 0x0000ff000000ff00ULL) | \ 239 | (((tmpu64 >> 24) | \ 240 | (tmpu64 << 40)) & 0x00ff000000ff0000ULL) | \ 241 | ((tmpu64 & 0x000000ff00000000ULL) >> 8) | \ 242 | ((tmpu64 & 0x00000000ff000000ULL) << 8) | \ 243 | (tmpu64 >> 56) | \ 244 | (tmpu64 << 56) ) 245 | #else 246 | #define cw_load64(ptr,dest) \ 247 | tmpu64 = ((uint64_t)*ptr++) << 56; \ 248 | tmpu64 |= ((uint64_t)*ptr++) << 48; \ 249 | tmpu64 |= ((uint64_t)*ptr++) << 40; \ 250 | tmpu64 |= ((uint64_t)*ptr++) << 32; \ 251 | tmpu64 |= ((uint64_t)*ptr++) << 24; \ 252 | tmpu64 |= ((uint64_t)*ptr++) << 16; \ 253 | tmpu64 |= ((uint64_t)*ptr++) << 8; \ 254 | dest = tmpu64 | (uint64_t)*ptr++; 255 | #endif 256 | 257 | #else /* Byte order undetermined */ 258 | 259 | #define cw_load16(ptr) \ 260 | tmpu16 = (uint16_t)((*ptr++) << 8); \ 261 | tmpu16 |= (uint16_t)(*ptr++) 262 | 263 | #define cw_load32(ptr) \ 264 | tmpu32 = (uint32_t)(*ptr++ << 24); \ 265 | tmpu32 |= (uint32_t)(*ptr++ << 16); \ 266 | tmpu32 |= (uint32_t)(*ptr++ << 8); \ 267 | tmpu32 |= (uint32_t)(*ptr++) 268 | 269 | #define cw_load64(ptr,dest) \ 270 | tmpu64 = ((uint64_t)*ptr++) << 56; \ 271 | tmpu64 |= ((uint64_t)*ptr++) << 48; \ 272 | tmpu64 |= ((uint64_t)*ptr++) << 40; \ 273 | tmpu64 |= ((uint64_t)*ptr++) << 32; \ 274 | tmpu64 |= ((uint64_t)*ptr++) << 24; \ 275 | tmpu64 |= ((uint64_t)*ptr++) << 16; \ 276 | tmpu64 |= ((uint64_t)*ptr++) << 8; \ 277 | dest = tmpu64 | (uint64_t)*ptr++; 278 | 279 | #endif 280 | #endif 281 | 282 | 283 | 284 | #define cw_unpack_assert_space_sub(more,abortValue) \ 285 | { \ 286 | p = unpack_context->current; \ 287 | uint8_t* nyp = p + more; \ 288 | if (nyp > unpack_context->end) \ 289 | { \ 290 | if (!unpack_context->handle_unpack_underflow) \ 291 | UNPACK_ERROR_SUB(buffer_end_return_code,abortValue) \ 292 | int rc = unpack_context->handle_unpack_underflow (unpack_context, (unsigned long)(more)); \ 293 | if (rc != CWP_RC_OK) \ 294 | { \ 295 | if (rc != CWP_RC_END_OF_INPUT) \ 296 | UNPACK_ERROR_SUB(rc,abortValue) \ 297 | else \ 298 | UNPACK_ERROR_SUB(buffer_end_return_code,abortValue) \ 299 | } \ 300 | p = unpack_context->current; \ 301 | nyp = p + more; \ 302 | } \ 303 | unpack_context->current = nyp; \ 304 | } 305 | 306 | #define cw_unpack_assert_space(more) cw_unpack_assert_space_sub(more,) 307 | 308 | 309 | #define cw_unpack_assert_blob(blob) \ 310 | cw_unpack_assert_space(unpack_context->item.as.blob.length); \ 311 | unpack_context->item.as.blob.start = p; \ 312 | return; 313 | 314 | 315 | #define getDDItem(typ,var,val) \ 316 | unpack_context->item.type = typ; \ 317 | unpack_context->item.as.var = val; 318 | 319 | #define getDDItem1(typ,var,cast) \ 320 | unpack_context->item.type = typ; \ 321 | cw_unpack_assert_space(1); \ 322 | unpack_context->item.as.var = (cast)*p; 323 | 324 | #define getDDItem2(typ,var,cast) \ 325 | unpack_context->item.type = typ; \ 326 | cw_unpack_assert_space(2); \ 327 | cw_load16(p); \ 328 | unpack_context->item.as.var = (cast)tmpu16; 329 | 330 | #define getDDItem4(typ,var,cast) \ 331 | unpack_context->item.type = typ; \ 332 | cw_unpack_assert_space(4); \ 333 | cw_load32(p); \ 334 | unpack_context->item.as.var = (cast)tmpu32; 335 | 336 | #define getDDItem8(typ) \ 337 | unpack_context->item.type = typ; \ 338 | cw_unpack_assert_space(8); \ 339 | cw_load64(p,unpack_context->item.as.u64); 340 | 341 | #define getDDItemFix(len) \ 342 | cw_unpack_assert_space(len+1); \ 343 | unpack_context->item.type = (cwpack_item_types)*(int8_t*)p++; \ 344 | if (unpack_context->item.type == CWP_ITEM_TIMESTAMP) \ 345 | { \ 346 | if (len == 4) \ 347 | { \ 348 | cw_load32(p); \ 349 | unpack_context->item.as.time.tv_sec = (long)tmpu32; \ 350 | unpack_context->item.as.time.tv_nsec = 0; \ 351 | return; \ 352 | } \ 353 | else if (len == 8) \ 354 | { \ 355 | cw_load64(p,tmpu64); \ 356 | unpack_context->item.as.time.tv_sec = tmpu64 & 0x00000003ffffffffLL; \ 357 | unpack_context->item.as.time.tv_nsec = tmpu64 >> 34; \ 358 | return; \ 359 | } \ 360 | else \ 361 | { \ 362 | UNPACK_ERROR(CWP_RC_WRONG_TIMESTAMP_LENGTH) \ 363 | } \ 364 | } \ 365 | unpack_context->item.as.ext.length = len; \ 366 | unpack_context->item.as.ext.start = p; \ 367 | return; 368 | 369 | 370 | 371 | #endif /* cwpack_defines_h */ 372 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | # CWPack / Test 2 | 3 | The folder has two tests. 4 | - A module test to check that the packer/unpacker behaves as expected. 5 | - A comparative speed test between CWPack, MPack and CMP. 6 | 7 | ## The module test 8 | 9 | The shell script `runModuleTest.sh` runs the module test. The test checks that it is compiled with compatible byte order and then checks the different calls to CWPack. 10 | 11 | ## The performance test 12 | 13 | The performance test is run by the shell script `runPerformanceTest.sh`. The script assumes that the repositories for CWPack, MPack and CMP are side by side in the same folder. 14 | 15 | The performance test is targeted to CMP v19 and MPack v1.0. 16 | 17 | The performance test checks the duration of a number of calls by calling them 1.000.000 times. 18 | -------------------------------------------------------------------------------- /test/cwpack_module_test.c: -------------------------------------------------------------------------------- 1 | /* CWPack/test cwpack_module_test.c */ 2 | /* 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2017 Claes Wihlborg 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 8 | software and associated documentation files (the "Software"), to deal in the Software 9 | without restriction, including without limitation the rights to use, copy, modify, 10 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 11 | persons to whom the Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or 14 | substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 17 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | DAMAGES OR OTHER 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 SOFTWARE. 21 | */ 22 | 23 | 24 | 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | #include "cwpack.h" 31 | #include "cwpack_config.h" 32 | #include "cwpack_utils.h" 33 | 34 | 35 | cw_pack_context pack_ctx; 36 | cw_unpack_context unpack_ctx; 37 | char TEST_area[70000]; 38 | uint8_t outbuffer[70000]; 39 | 40 | int error_count; 41 | 42 | static void ERROR(const char* msg) 43 | { 44 | error_count++; 45 | printf("ERROR: %s\n", msg); 46 | } 47 | 48 | /* 49 | static void ERROR1(const char* msg, int i) 50 | { 51 | error_count++; 52 | printf("ERROR: %s%d\n", msg, i); 53 | } 54 | */ 55 | 56 | static void ERROR2(const char* msg, int i, int j) 57 | { 58 | error_count++; 59 | printf("ERROR: %s%d != %d\n", msg, i, j); 60 | } 61 | 62 | 63 | static char char2hex (char c) 64 | { 65 | if (c <= '9') 66 | return c - '0'; 67 | if (c <= 'F') 68 | return c - 'A' + 10; 69 | 70 | return c - 'a' + 10; 71 | } 72 | 73 | 74 | static void check_pack_result(const char* expected_header, unsigned long data_length)__attribute__ ((optnone)) 75 | { 76 | // expected contains the result in HEX 77 | unsigned long header_length = strlen(expected_header) / 2; 78 | if (pack_ctx.current - outbuffer == (long)(header_length + data_length)) 79 | { 80 | 81 | if (header_length*2 == strlen(expected_header)) 82 | { 83 | unsigned long i; 84 | uint8_t *p = (uint8_t*)outbuffer; 85 | const char *ucp = expected_header; 86 | for (i = 0; i < header_length; i++) 87 | { 88 | long hex = 0; 89 | int j; 90 | for(j=0; j<2; j++) 91 | { 92 | char uc = *(ucp++); 93 | if (uc >= '0' && uc <= '9') 94 | { 95 | hex <<= 4; 96 | hex += (uc - '0'); 97 | continue; 98 | } 99 | if (uc >= 'a' && uc <='f') 100 | { 101 | hex <<= 4; 102 | hex += (uc - 'a' + 10); 103 | continue; 104 | } 105 | if (uc < 'A' || uc >'F') 106 | { 107 | ERROR("Not a HEX value"); 108 | } 109 | hex <<= 4; 110 | hex += (uc - 'A' + 10); 111 | } 112 | 113 | 114 | if (*p++ != hex) 115 | { 116 | ERROR("Different header value"); 117 | } 118 | } 119 | 120 | if (data_length > 0) 121 | { 122 | ucp = TEST_area; 123 | for (i = 0; i < data_length; i++) 124 | if (*p++ != *ucp++) 125 | { 126 | ERROR("Different data value"); 127 | } 128 | } 129 | } 130 | else 131 | ERROR("Odd header"); 132 | } 133 | else 134 | ERROR("Wrong total length"); 135 | } 136 | 137 | 138 | static void check_unpack(int val, int result) 139 | { 140 | cw_unpack_next(&unpack_ctx); 141 | if (unpack_ctx.return_code != result) 142 | ERROR2("rc=", unpack_ctx.return_code, result); 143 | if (unpack_ctx.return_code == 0 && unpack_ctx.item.type != CWP_ITEM_POSITIVE_INTEGER && unpack_ctx.item.as.i64 != val) 144 | ERROR("Wrong item"); 145 | } 146 | 147 | 148 | 149 | 150 | int main(int argc, const char * argv[]) 151 | { 152 | (void)argc;(void)argv; 153 | 154 | printf("CWPack module test started.\n"); 155 | error_count = 0; 156 | 157 | bool endian_switch_found = false; 158 | #ifdef COMPILE_FOR_BIG_ENDIAN 159 | printf("Compiled for big endian.\n"); 160 | endian_switch_found = true; 161 | #endif 162 | 163 | #ifdef COMPILE_FOR_LITTLE_ENDIAN 164 | printf("Compiled for little endian.\n"); 165 | endian_switch_found = true; 166 | #endif 167 | 168 | if (!endian_switch_found) 169 | printf("Compiled for all endians.\n"); 170 | 171 | const char *endianness = "1234"; 172 | switch (*(uint32_t*)endianness) 173 | { 174 | case 0x31323334UL: 175 | printf("Running on big endian hardware.\n\n"); 176 | break; 177 | 178 | case 0x34333231UL: 179 | printf("Running on little endian hardware.\n\n"); 180 | break; 181 | 182 | default: 183 | printf("Running on neither little nor big endian hardware.\n\n"); 184 | break; 185 | } 186 | 187 | 188 | //******************* TEST cwpack pack **************************** 189 | 190 | 191 | #define TESTP(call,data,result) \ 192 | pack_ctx.current = outbuffer; \ 193 | cw_pack_##call (&pack_ctx, data); \ 194 | if(pack_ctx.return_code) \ 195 | ERROR("In pack"); \ 196 | check_pack_result(result,0) 197 | 198 | 199 | 200 | cw_pack_context_init (&pack_ctx, outbuffer, 70000, 0); 201 | if (pack_ctx.return_code == CWP_RC_WRONG_BYTE_ORDER) 202 | { 203 | ERROR("***** Compiled for wrong byte order, test terminated *****\n\n"); 204 | exit(1); 205 | } 206 | 207 | unsigned int ui; 208 | for (ui=0; ui<70000; ui++) 209 | { 210 | TEST_area[ui] = ui & 0x7fUL; 211 | } 212 | 213 | 214 | // TESTP NIL 215 | cw_pack_nil(&pack_ctx); 216 | check_pack_result("c0",0); 217 | 218 | // TESTP boolean 219 | pack_ctx.current = outbuffer; 220 | cw_pack_true(&pack_ctx); 221 | check_pack_result("c3",0); 222 | pack_ctx.current = outbuffer; 223 | cw_pack_false(&pack_ctx); 224 | check_pack_result("c2",0); 225 | TESTP(boolean,0,"c2"); 226 | TESTP(boolean,1,"c3"); 227 | 228 | // TESTP unsigned int 229 | TESTP(unsigned,0,"00"); 230 | TESTP(unsigned,127,"7f"); 231 | TESTP(unsigned,128,"cc80"); 232 | TESTP(unsigned,255,"ccff"); 233 | TESTP(unsigned,256,"cd0100"); 234 | TESTP(unsigned,65535,"cdffff"); 235 | TESTP(unsigned,65536,"ce00010000"); 236 | TESTP(unsigned,500000000,"ce1dcd6500"); 237 | TESTP(unsigned,0xffffffffUL,"ceffffffff"); 238 | TESTP(unsigned,0x100000000ULL,"cf0000000100000000"); 239 | TESTP(unsigned,0xffffffffffffffffULL,"cfffffffffffffffff"); 240 | 241 | // TESTP signed int 242 | TESTP(signed,-1,"ff"); 243 | TESTP(signed,-32,"e0"); 244 | TESTP(signed,-33,"d0df"); 245 | TESTP(signed,-128,"d080"); 246 | TESTP(signed,-129,"d1ff7f"); 247 | TESTP(signed,-32768,"d18000"); 248 | TESTP(signed,-32769,"d2ffff7fff"); 249 | 250 | // TESTP real 251 | float f1 = (float)3.14; 252 | TESTP(float,0.0,"ca00000000"); 253 | TESTP(float,f1,"ca4048f5c3"); 254 | TESTP(float,37.25,"ca42150000"); 255 | TESTP(double,0.0,"cb0000000000000000"); 256 | TESTP(double,f1,"cb40091eb860000000"); 257 | TESTP(double,3.14,"cb40091eb851eb851f"); 258 | TESTP(double,37.25,"cb4042a00000000000"); 259 | TESTP(double_opt,37.25,"ca42150000"); 260 | TESTP(double_opt,f1,"ca4048f5c3"); 261 | TESTP(double_opt,3.14,"cb40091eb851eb851f"); 262 | TESTP(double_opt,-32,"e0"); 263 | 264 | // TESTP array 265 | TESTP(array_size,0,"90"); 266 | TESTP(array_size,15,"9f"); 267 | TESTP(array_size,16,"dc0010"); 268 | TESTP(array_size,65535,"dcffff"); 269 | TESTP(array_size,65536,"dd00010000"); 270 | 271 | // TESTP map 272 | TESTP(map_size,0,"80"); 273 | TESTP(map_size,15,"8f"); 274 | TESTP(map_size,16,"de0010"); 275 | TESTP(map_size,65535,"deffff"); 276 | TESTP(map_size,65536,"df00010000"); 277 | 278 | 279 | #define TESTP_AREA(call,len,header) \ 280 | pack_ctx.current = outbuffer; \ 281 | cw_pack_##call (&pack_ctx, TEST_area, len); \ 282 | if(pack_ctx.return_code) \ 283 | ERROR("In pack"); \ 284 | check_pack_result(header, len) 285 | 286 | // TESTP str 287 | TESTP_AREA(str,0,"a0"); 288 | TESTP_AREA(str,31,"bf"); 289 | TESTP_AREA(str,32,"d920"); 290 | TESTP_AREA(str,255,"d9ff"); 291 | TESTP_AREA(str,256,"da0100"); 292 | TESTP_AREA(str,65535,"daffff"); 293 | TESTP_AREA(str,65536,"db00010000"); 294 | 295 | // TESTP bin 296 | TESTP_AREA(bin,0,"c400"); 297 | TESTP_AREA(bin,255,"c4ff"); 298 | TESTP_AREA(bin,256,"c50100"); 299 | TESTP_AREA(bin,65535,"c5ffff"); 300 | TESTP_AREA(bin,65536,"c600010000"); 301 | 302 | #define TESTP_EXT(call,type,len,header) \ 303 | pack_ctx.current = outbuffer; \ 304 | cw_pack_##call (&pack_ctx, type, TEST_area, len); \ 305 | if(pack_ctx.return_code) \ 306 | ERROR("In pack"); \ 307 | check_pack_result(header, len) 308 | 309 | // TESTP ext 310 | TESTP_EXT(ext,15,1,"d40f"); 311 | TESTP_EXT(ext,16,2,"d510"); 312 | TESTP_EXT(ext,17,3,"c70311"); 313 | TESTP_EXT(ext,18,4,"d612"); 314 | TESTP_EXT(ext,19,8,"d713"); 315 | TESTP_EXT(ext,20,16,"d814"); 316 | TESTP_EXT(ext,21,255,"c7ff15"); 317 | TESTP_EXT(ext,21,256,"c8010015"); 318 | TESTP_EXT(ext,21,65535,"c8ffff15"); 319 | TESTP_EXT(ext,21,65536,"c90001000015"); 320 | 321 | pack_ctx.current = outbuffer; 322 | cw_pack_time(&pack_ctx, 1, 0); 323 | check_pack_result("d6ff00000001", 0); 324 | pack_ctx.current = outbuffer; 325 | cw_pack_time(&pack_ctx, 1, 2); 326 | check_pack_result("d7ff0000000800000001", 0); 327 | pack_ctx.current = outbuffer; 328 | cw_pack_time(&pack_ctx, -1, 500000000); 329 | check_pack_result("c70cff1dcd6500ffffffffffffffff", 0); 330 | 331 | TESTP(time_interval,-0.5,"c70cff1dcd6500ffffffffffffffff"); 332 | 333 | //******************* TEST cwpack unpack ********************** 334 | 335 | char inputbuf[30]; 336 | 337 | 338 | #define TESTUP(buffer,etype) \ 339 | { \ 340 | unsigned long len = strlen(buffer)/2; \ 341 | for (ui = 0; ui < len; ui++) \ 342 | inputbuf[ui] = (uint8_t)(char2hex(buffer[2*ui])<<4) + char2hex(buffer[2*ui +1]); \ 343 | cw_unpack_context_init (&unpack_ctx, inputbuf, len+blob_length, 0); \ 344 | cit = cw_look_ahead(&unpack_ctx); \ 345 | if (cit != CWP_ITEM_##etype) \ 346 | ERROR("In lookahead, type error"); \ 347 | cw_unpack_next(&unpack_ctx); \ 348 | if (unpack_ctx.item.type != CWP_ITEM_##etype) \ 349 | ERROR("In unpack, type error"); \ 350 | } 351 | 352 | #define TESTUP_VAL(buffer,etype,var,val) \ 353 | TESTUP(buffer,etype); \ 354 | if (unpack_ctx.item.as.var != val) \ 355 | ERROR("In unpack, value error"); 356 | 357 | unsigned long blob_length = 0; 358 | cwpack_item_types cit; 359 | 360 | // TESTUP NIL 361 | TESTUP("c0",NIL); 362 | 363 | // TESTUP boolean 364 | TESTUP_VAL("c2",BOOLEAN,boolean,false); 365 | TESTUP_VAL("c3",BOOLEAN,boolean,true); 366 | 367 | // TESTUP unsigned int 368 | TESTUP_VAL("00",POSITIVE_INTEGER,u64,0) 369 | TESTUP_VAL("7f",POSITIVE_INTEGER,u64,127) 370 | TESTUP_VAL("cc80",POSITIVE_INTEGER,u64,128) 371 | TESTUP_VAL("ccff",POSITIVE_INTEGER,u64,255) 372 | TESTUP_VAL("cd0100",POSITIVE_INTEGER,u64,256) 373 | TESTUP_VAL("cdffff",POSITIVE_INTEGER,u64,65535) 374 | TESTUP_VAL("ce00010000",POSITIVE_INTEGER,u64,65536) 375 | TESTUP_VAL("ceffffffff",POSITIVE_INTEGER,u64,0xffffffffUL) 376 | TESTUP_VAL("cf0000000100000000",POSITIVE_INTEGER,u64,0x100000000ULL) 377 | TESTUP_VAL("cfffffffffffffffff",POSITIVE_INTEGER,u64,0xffffffffffffffffULL) 378 | 379 | // TESTUP signed int 380 | TESTUP_VAL("ff",NEGATIVE_INTEGER,i64,-1) 381 | TESTUP_VAL("e0",NEGATIVE_INTEGER,i64,-32) 382 | TESTUP_VAL("d0df",NEGATIVE_INTEGER,i64,-33) 383 | TESTUP_VAL("d080",NEGATIVE_INTEGER,i64,-128) 384 | TESTUP_VAL("d1ff7f",NEGATIVE_INTEGER,i64,-129) 385 | TESTUP_VAL("d18000",NEGATIVE_INTEGER,i64,-32768) 386 | TESTUP_VAL("d2ffff7fff",NEGATIVE_INTEGER,i64,-32769) 387 | TESTUP_VAL("d3ffffffff7fffffff",NEGATIVE_INTEGER,i64,-2147483649) 388 | 389 | // TESTUP real 390 | // float f1 = 3.14; 391 | TESTUP_VAL("ca00000000",FLOAT,real,0.0) 392 | TESTUP_VAL("ca4048f5c3",FLOAT,real,f1) 393 | TESTUP_VAL("cb0000000000000000",DOUBLE,long_real,0.0) 394 | TESTUP_VAL("cb40091eb860000000",DOUBLE,long_real,f1) 395 | TESTUP_VAL("cb40091eb851eb851f",DOUBLE,long_real,3.14) 396 | 397 | // TESTUP array 398 | TESTUP_VAL("90",ARRAY,array.size,0) 399 | TESTUP_VAL("9f",ARRAY,array.size,15) 400 | TESTUP_VAL("dc0010",ARRAY,array.size,16) 401 | TESTUP_VAL("dcffff",ARRAY,array.size,65535) 402 | TESTUP_VAL("dd00010000",ARRAY,array.size,65536) 403 | 404 | // TESTUP map 405 | TESTUP_VAL("80",MAP,map.size,0) 406 | TESTUP_VAL("8f",MAP,map.size,15) 407 | TESTUP_VAL("de0010",MAP,map.size,16) 408 | TESTUP_VAL("deffff",MAP,map.size,65535) 409 | TESTUP_VAL("df00010000",MAP,map.size,65536) 410 | 411 | // TESTUP timeStamp 412 | TESTUP_VAL("d6ff00000001",TIMESTAMP,time.tv_sec,1); 413 | TESTUP_VAL("d6ff00000001",TIMESTAMP,time.tv_nsec,0); 414 | TESTUP_VAL("d7ff0000000800000001",TIMESTAMP,time.tv_sec,1); 415 | TESTUP_VAL("d7ff0000000800000001",TIMESTAMP,time.tv_nsec,2); 416 | TESTUP_VAL("c70cff1dcd6500ffffffffffffffff",TIMESTAMP,time.tv_sec,-1); 417 | TESTUP_VAL("c70cff1dcd6500ffffffffffffffff",TIMESTAMP,time.tv_nsec,500000000); 418 | 419 | #define TESTUP_AREA(buffer,etype,blob,len) \ 420 | blob_length = len; \ 421 | TESTUP_VAL(buffer,etype,blob.length,len) \ 422 | TESTUP_VAL(buffer,etype,blob.start,inputbuf + strlen(buffer)/2) 423 | 424 | // TESTUP str 425 | TESTUP_AREA("a0",STR,str,0); 426 | TESTUP_AREA("bf",STR,str,31); 427 | TESTUP_AREA("d920",STR,str,32); 428 | TESTUP_AREA("d9ff",STR,str,255); 429 | TESTUP_AREA("da0100",STR,str,256); 430 | TESTUP_AREA("daffff",STR,str,65535); 431 | TESTUP_AREA("db00010000",STR,str,65536); 432 | 433 | // TESTUP bin 434 | TESTUP_AREA("c400",BIN,bin,0); 435 | TESTUP_AREA("c4ff",BIN,bin,255); 436 | TESTUP_AREA("c50100",BIN,bin,256); 437 | TESTUP_AREA("c5ffff",BIN,bin,65535); 438 | TESTUP_AREA("c600010000",BIN,bin,65536); 439 | 440 | // TESTUP ext 441 | #define CWP_ITEM_15 15 442 | #define CWP_ITEM_16 16 443 | #define CWP_ITEM_17 17 444 | #define CWP_ITEM_18 18 445 | #define CWP_ITEM_19 19 446 | #define CWP_ITEM_20 20 447 | #define CWP_ITEM_21 21 448 | 449 | TESTUP_AREA("d40f",15,ext,1); 450 | TESTUP_AREA("d510",16,ext,2); 451 | TESTUP_AREA("c70311",17,ext,3); 452 | TESTUP_AREA("d612",18,ext,4); 453 | TESTUP_AREA("d713",19,ext,8); 454 | TESTUP_AREA("d814",20,ext,16); 455 | TESTUP_AREA("c7ff15",21,ext,255); 456 | TESTUP_AREA("c8010015",21,ext,256); 457 | TESTUP_AREA("c8ffff15",21,ext,65535); 458 | TESTUP_AREA("c90001000015",21,ext,65536); 459 | 460 | 461 | 462 | //******************* TEST skip *************************** 463 | 464 | cw_pack_context_init (&pack_ctx, outbuffer, 100, 0); 465 | cw_pack_array_size(&pack_ctx,2); 466 | cw_pack_str(&pack_ctx,"Test of skip",12); //array component 467 | cw_pack_unsigned(&pack_ctx,0x68357); //array component 468 | cw_pack_unsigned(&pack_ctx,0x952); //first item after array 469 | if(pack_ctx.return_code) 470 | { 471 | ERROR("Couldn't generate testdata for skip_items"); 472 | } 473 | else 474 | { 475 | cw_unpack_context_init (&unpack_ctx, pack_ctx.start, (unsigned long)(pack_ctx.current-pack_ctx.start), 0); 476 | 477 | cw_skip_items (&unpack_ctx, 1); /* skip whole array */ 478 | check_unpack (0x952, CWP_RC_OK); 479 | check_unpack (0, CWP_RC_END_OF_INPUT); 480 | } 481 | 482 | 483 | //************************************************************* 484 | 485 | printf("CWPack module test completed, "); 486 | switch (error_count) 487 | { 488 | case 0: 489 | printf("no errors detected\n"); 490 | break; 491 | 492 | case 1: 493 | printf("1 error detected\n"); 494 | break; 495 | 496 | default: 497 | printf("%d errors detected\n", error_count); 498 | break; 499 | } 500 | 501 | return error_count; 502 | } 503 | -------------------------------------------------------------------------------- /test/cwpack_performance_test.c: -------------------------------------------------------------------------------- 1 | /* CWPack/test cwpack_performance_test.c */ 2 | /* 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2017 Claes Wihlborg 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 8 | software and associated documentation files (the "Software"), to deal in the Software 9 | without restriction, including without limitation the rights to use, copy, modify, 10 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 11 | persons to whom the Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or 14 | substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 17 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | DAMAGES OR OTHER 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 SOFTWARE. 21 | */ 22 | 23 | 24 | 25 | #include 26 | #include 27 | 28 | #include "cwpack.h" 29 | #include "cmp.h" 30 | #include "mpack.h" 31 | #include "basic_contexts.h" 32 | 33 | 34 | 35 | 36 | static double milliseconds(void) { 37 | return (double)clock_gettime_nsec_np(CLOCK_PROCESS_CPUTIME_ID)/1000000.0; 38 | } 39 | 40 | 41 | #define BEFORE_PTEST(code) \ 42 | cw_pack_context_init(&pc, buffer, BUF_Length, 0);\ 43 | cmp_init(&cc, buffer, 0, 0, b_writer);\ 44 | mpack_writer_init(&mw, buffer, BUF_Length); \ 45 | code; \ 46 | itemSize = (int)(pc.current - pc.start); \ 47 | memcpy(item, buffer, itemSize); \ 48 | cw_pack_context_init(&pc, buffer, BUF_Length, 0);\ 49 | 50 | 51 | #define PTEST(packer,code) { \ 52 | int n, max = ITERATIONS/100; \ 53 | double duration[10]; \ 54 | for (n=0; n<(ITERATIONS*itemSize)+1; n++) buffer[n] = (char)(0xc1); \ 55 | for (n=0; n<10; n++) \ 56 | { \ 57 | double start = milliseconds(); \ 58 | int i; \ 59 | for (i = 0; ibuf + count) > (buffer + BUF_Length)) 92 | return 0; 93 | 94 | memcpy (ctx->buf,data,count); 95 | ctx->buf = (uint8_t*)ctx->buf + count; 96 | return count; 97 | } 98 | 99 | static void pack_test(void) 100 | { 101 | /*************** Test of pack *****************/ 102 | 103 | cw_pack_context pc; 104 | cmp_ctx_t cc; 105 | mpack_writer_t mw; 106 | 107 | int ii, itemSize; 108 | for (ii=0; iibuf + limit) > (buffer + BUF_Length)) 206 | return false; 207 | 208 | memcpy (data,ctx->buf,limit); 209 | ctx->buf = (uint8_t*)ctx->buf + limit; 210 | return true; 211 | } 212 | 213 | static void unpack_test(void) 214 | { 215 | /*************** Test of unpack *****************/ 216 | 217 | cw_pack_context pc; 218 | cw_unpack_context uc; 219 | mpack_reader_t mr; 220 | cmp_ctx_t cc; 221 | cmp_object_t cobj; 222 | 223 | BEFORE_UTEST(cw_pack_nil(&pc)); 224 | UTEST("CMP", cmp_read_object(&cc, &cobj)); 225 | UTEST("MPack", mpack_read_tag(&mr)); 226 | UTEST("CWPack", cw_unpack_next(&uc)); 227 | AFTER_UTEST; 228 | 229 | BEFORE_UTEST(cw_pack_signed(&pc, -1)); 230 | UTEST("CMP", cmp_read_object(&cc, &cobj)); 231 | UTEST("MPack", mpack_read_tag(&mr)); 232 | UTEST("CWPack", cw_unpack_next(&uc)); 233 | AFTER_UTEST; 234 | 235 | BEFORE_UTEST(cw_pack_signed(&pc, 100000)); 236 | UTEST("CMP", cmp_read_object(&cc, &cobj)); 237 | UTEST("MPack", mpack_read_tag(&mr)); 238 | UTEST("CWPack", cw_unpack_next(&uc)); 239 | AFTER_UTEST; 240 | 241 | BEFORE_UTEST(cw_pack_float(&pc, (float)3.14)); 242 | UTEST("CMP", cmp_read_object(&cc, &cobj)); 243 | UTEST("MPack", mpack_read_tag(&mr)); 244 | UTEST("CWPack", cw_unpack_next(&uc)); 245 | AFTER_UTEST; 246 | 247 | BEFORE_UTEST(cw_pack_double(&pc, 3.14)); 248 | UTEST("CMP", cmp_read_object(&cc, &cobj)); 249 | UTEST("MPack", mpack_read_tag(&mr)); 250 | UTEST("CWPack", cw_unpack_next(&uc)); 251 | AFTER_UTEST; 252 | 253 | BEFORE_UTEST(cw_pack_str(&pc, "Claes",5)); 254 | UTEST("CMP", cmp_read_object(&cc, &cobj)); 255 | UTEST("MPack", mpack_skip_bytes(&mr,mpack_expect_str(&mr));mpack_done_str(&mr)); 256 | UTEST("CWPack", cw_unpack_next(&uc)); 257 | AFTER_UTEST; 258 | 259 | 260 | } 261 | 262 | 263 | int main(int argc, const char * argv[]) 264 | { 265 | printf("\n***************************** PERFORMANCE TEST *****************************\n\n"); 266 | pack_test(); 267 | unpack_test(); 268 | exit (0); 269 | } 270 | -------------------------------------------------------------------------------- /test/runModuleTest.sh: -------------------------------------------------------------------------------- 1 | clang -O3 -I ../src/ -I ../goodies/utils/ -o cwpackModuleTest cwpack_module_test.c ../src/cwpack.c ../goodies/utils/cwpack_utils.c 2 | ./cwpackModuleTest 3 | rm -f *.o cwpackModuleTest 4 | -------------------------------------------------------------------------------- /test/runPerformanceTest.sh: -------------------------------------------------------------------------------- 1 | clang -O3 -flto -I ../src/ -I ../goodies/basic-contexts/ -I ../../cmp-master/ -I ../../mpack/src/mpack/ cwpack_performance_test.c ../src/cwpack.c ../goodies/basic-contexts/basic_contexts.c ../../cmp-master/cmp.c ../../mpack/src/mpack/*.c -o cwpackPerformanceTest 2 | 3 | ./cwpackPerformanceTest 4 | rm -f *.o cwpackPerformanceTest 5 | --------------------------------------------------------------------------------