From 37a5e29f9f58e6229a6df8e37f834748e832c4a3 Mon Sep 17 00:00:00 2001 From: clwi Date: Sat, 23 May 2020 22:59:05 +0200 Subject: [PATCH 01/10] Release 1.2 --- README.md | 48 +-- example/README.md | 2 +- goodies/README.md | 15 + goodies/basic-contexts/README.md | 10 +- goodies/basic-contexts/basic_contexts.c | 78 ++-- goodies/basic-contexts/basic_contexts.h | 3 +- goodies/dump/README.md | 38 ++ goodies/dump/cwpack_dump.c | 232 +++++++++++ goodies/dump/runCWpack_dump.sh | 3 + goodies/numeric-extensions/README.md | 14 +- .../numeric-extensions/numeric_extensions.c | 105 +++-- .../numeric-extensions/numeric_extensions.h | 38 +- .../numeric_extensions_test.c | 37 +- goodies/objC/README.md | 40 ++ goodies/objC/cwpack_objc.h | 38 ++ goodies/objC/cwpack_objc.m | 274 +++++++++++++ goodies/utils/README.md | 52 +++ goodies/utils/cwpack_utils.c | 366 ++++++++++++++++++ goodies/utils/cwpack_utils.h | 64 +++ src/README.md | 28 ++ src/cwpack.c | 93 ++++- src/cwpack.h | 37 +- src/cwpack_config.h | 100 +++++ src/{cwpack_defines.h => cwpack_internals.h} | 159 ++++---- test/README.md | 8 +- test/cwpack_module_test.c | 13 +- test/cwpack_performance_test.c | 31 +- test/runModuleTest.sh | 2 +- 28 files changed, 1664 insertions(+), 264 deletions(-) create mode 100755 goodies/README.md create mode 100755 goodies/dump/README.md create mode 100755 goodies/dump/cwpack_dump.c create mode 100755 goodies/dump/runCWpack_dump.sh create mode 100755 goodies/objC/README.md create mode 100755 goodies/objC/cwpack_objc.h create mode 100755 goodies/objC/cwpack_objc.m create mode 100755 goodies/utils/README.md create mode 100755 goodies/utils/cwpack_utils.c create mode 100644 goodies/utils/cwpack_utils.h create mode 100755 src/README.md create mode 100644 src/cwpack_config.h rename src/{cwpack_defines.h => cwpack_internals.h} (75%) diff --git a/README.md b/README.md index a617aa2..5f2c372 100755 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ CWPack is a lightweight and yet complete implementation of the [MessagePack](http://msgpack.org) serialization format [version 5](https://github.com/msgpack/msgpack/blob/master/spec.md). +It also supports the Timestamp extension type. ## Excellent Performance @@ -11,15 +12,11 @@ Together with [MPack](https://github.com/ludocode/mpack), CWPack is the fastest ## Design -CWPack does no memory allocations and no file handling. All that is done -outside of CWPack. +CWPack does no memory allocations and no file handling in its basic setup. All that is done outside of CWPack. Example extensions are included. -CWPack is working against memory buffers. User defined handlers are called when buffers are -filled up (packing) or needs refill (unpack). +CWPack is working against memory buffers. User defined handlers are called when buffers are filled up (packing) or needs refill (unpack). -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. +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. ## Example @@ -30,7 +27,7 @@ void example (void) { cw_pack_context pc; char buffer[20]; - cw_pack_context_init (&pc, buffer, 20, 0, 0); + cw_pack_context_init (&pc, buffer, 20, 0); cw_pack_map_size (&pc, 2); cw_pack_str (&pc, "compact", 7); @@ -38,29 +35,22 @@ void example (void) cw_pack_str (&pc, "schema", 6); cw_pack_unsigned (&pc, 0); + if (pc.return_code != CWP_RC_OK) ERROR; int length = pc.current - pc.start; - if (length > 18) ERROR; + if (length != 18) ERROR; cw_unpack_context uc; - cw_unpack_context_init (&uc, pc.start, length, 0, 0); + cw_unpack_context_init (&uc, pc.start, length, 0); - cw_unpack_next(&uc); - if (uc.item.type != CWP_ITEM_MAP || uc.item.as.map.size != 2) ERROR; - - cw_unpack_next(&uc); - if (uc.item.type != CWP_ITEM_STR || uc.item.as.str.length != 7)) ERROR; + if (cw_unpack_next_map_size(&uc) != 2) ERROR; + if (cw_unpack_next_str_lengh(&uc) != 7) ERROR; if (strncmp("compact", uc.item.as.str.start, 7)) ERROR; - - cw_unpack_next(&uc); - if (uc.item.type != CWP_ITEM_BOOLEAN || uc.item.as.boolean != true) ERROR; - - cw_unpack_next(&uc); - if (uc.item.type != CWP_ITEM_STR || uc.item.as.str.length != 6)) ERROR; + if (cw_unpack_next_bool(&uc) != true) ERROR; + if (cw_unpack_next_str_lengh(&uc) != 6) ERROR; if (strncmp("schema", uc.item.as.str.start, 6)) ERROR; - - cw_unpack_next(&uc); - if (uc.item.type != CWP_ITEM_POSITIVE_INTEGER || uc.item.as.u64 != 0) ERROR; - + if (cw_unpack_next_signed32(&uc) != 0) ERROR; + + if (uc.return_code != CWP_RC_OK) ERROR; cw_unpack_next(&uc); if (uc.return_code != CWP_RC_END_OF_INPUT) ERROR; } @@ -70,19 +60,17 @@ In the examples folder there are more examples. ## Backward compatibility -CWPack may be run in compatibility mode. It affects only packing; EXT is considered illegal, BIN are transformed to STR and generation of STR8 is supressed. +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. ## Error handling -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. +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. CWPack does not check for illegal values (e.g. in STR for illegal unicode characters). ## Build -CWPack consists of a single src file and two header files. It is written -in strict ansi C and the files are together ~ 1.2K lines. No separate build is neccesary, just include the -files in your own build. +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. CWPack has no dependencies to other libraries. diff --git a/example/README.md b/example/README.md index 88d29a2..0f5d9ea 100755 --- a/example/README.md +++ b/example/README.md @@ -1,4 +1,4 @@ -#CWPack - Example +# CWPack / Example The example contains a program that takes a json file and converts it to a messagePack file, then converts the latter back to json. diff --git a/goodies/README.md b/goodies/README.md new file mode 100755 index 0000000..b6cc9e9 --- /dev/null +++ b/goodies/README.md @@ -0,0 +1,15 @@ +# CWPack / Goodies + + +Goodies contains the following: + +**basic_contexts** has contexts for dynamic memory contexts and a set of file contexts. + +**dump** presents a msgpack file in human readable form. + +**numeric_extensions** use when your Ext data is integer or real. + +**objC** Objective-C wrapper. + +**utils** convenience calls and expect api for CWPack. + diff --git a/goodies/basic-contexts/README.md b/goodies/basic-contexts/README.md index d32f6bd..7ae436d 100755 --- a/goodies/basic-contexts/README.md +++ b/goodies/basic-contexts/README.md @@ -1,7 +1,7 @@ -#CWPack - Goodies - Basic Contexts +# CWPack / Goodies / Basic Contexts -Basic contexts contains 5 contexts: +Basic contexts contains 5 contexts that meet most demands: - **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. @@ -9,10 +9,8 @@ Basic contexts contains 5 contexts: - **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. -- **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 buffer. If an item is larger than the buffer, the handler tries to reallocate the buffer so the item would fit. +- **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. - **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. -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. +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. diff --git a/goodies/basic-contexts/basic_contexts.c b/goodies/basic-contexts/basic_contexts.c index de1135c..c026e22 100644 --- a/goodies/basic-contexts/basic_contexts.c +++ b/goodies/basic-contexts/basic_contexts.c @@ -1,4 +1,4 @@ -/* CWPack/example - basic_contexts.c */ +/* CWPack/goodies - basic_contexts.c */ /* The MIT License (MIT) @@ -31,7 +31,7 @@ -/***************************************** MEMORY PACK CONTEXT ********************************/ +/***************************************** DYNAMIC MEMORY PACK CONTEXT ********************************/ static int handle_memory_pack_overflow(struct cw_pack_context* pc, unsigned long more) @@ -78,15 +78,16 @@ void free_dynamic_memory_pack_context(dynamic_memory_pack_context* dmpc) -static int flush_stream_pack_context(stream_pack_context* spc) +static int flush_stream_pack_context(struct cw_pack_context* pc) { - unsigned long contains = (unsigned long)(spc->pc.current - spc->pc.start); + stream_pack_context* spc = (stream_pack_context*)pc; + unsigned long contains = (unsigned long)(pc->current - pc->start); if (contains) { - unsigned long rc = fwrite(spc->pc.start, contains, 1, spc->file); + unsigned long rc = fwrite(pc->start, contains, 1, spc->file); if (rc != 1) { - spc->pc.err_no = ferror(spc->file); + pc->err_no = ferror(spc->file); return CWP_RC_ERROR_IN_HANDLER; } } @@ -96,7 +97,7 @@ static int flush_stream_pack_context(stream_pack_context* spc) static int handle_stream_pack_overflow(struct cw_pack_context* pc, unsigned long more) { - int rc = flush_stream_pack_context((stream_pack_context*)pc); + int rc = flush_stream_pack_context(pc); if (rc != CWP_RC_OK) return rc; @@ -131,16 +132,17 @@ void init_stream_pack_context (stream_pack_context* spc, unsigned long initial_b spc->file = file; cw_pack_context_init((cw_pack_context*)spc, buffer, buffer_length, &handle_stream_pack_overflow); + cw_pack_set_flush_handler((cw_pack_context*)spc, &flush_stream_pack_context); } void terminate_stream_pack_context(stream_pack_context* spc) { - if (spc->pc.return_code == CWP_RC_OK) - spc->pc.return_code = flush_stream_pack_context(spc); + cw_pack_context* pc = (cw_pack_context*)spc; + cw_pack_flush(pc); - if (spc->pc.return_code != CWP_RC_MALLOC_ERROR) - free(spc->pc.start); + if (pc->return_code != CWP_RC_MALLOC_ERROR) + free(pc->start); } @@ -212,27 +214,28 @@ void terminate_stream_unpack_context(stream_unpack_context* suc) /***************************************** FILE PACK CONTEXT **********************************/ -static int flush_file_pack_context(file_pack_context* fpc) +static int flush_file_pack_context(struct cw_pack_context* pc) { - uint8_t *bStart = fpc->barrier ? fpc->barrier : fpc->pc.current; - unsigned long contains = (unsigned long)(bStart - fpc->pc.start); + file_pack_context* fpc = (file_pack_context*)pc; + uint8_t *bStart = fpc->barrier ? fpc->barrier : pc->current; + unsigned long contains = (unsigned long)(bStart - pc->start); if (contains) { - long rc = write (fpc->fileDescriptor, fpc->pc.start, contains); - if (rc != contains) + long rc = write (fpc->fileDescriptor, pc->start, contains); + if (rc != (long)contains) { - fpc->pc.err_no = errno; + pc->err_no = errno; return CWP_RC_ERROR_IN_HANDLER; } } if (fpc->barrier) { - long kept = fpc->pc.current - bStart; + long kept = pc->current - bStart; if (kept) { - memcpy(fpc->pc.start, bStart, kept); + memcpy(pc->start, bStart, kept); } - fpc->barrier = fpc->pc.start; - fpc->pc.current = fpc->pc.start + kept; + fpc->barrier = pc->start; + pc->current = pc->start + kept; } else fpc->pc.current = fpc->pc.start; @@ -243,12 +246,12 @@ static int flush_file_pack_context(file_pack_context* fpc) static int handle_file_pack_overflow(struct cw_pack_context* pc, unsigned long more) { file_pack_context* fpc = (file_pack_context*)pc; - int rc = flush_file_pack_context(fpc); + int rc = flush_file_pack_context(pc); if (rc != CWP_RC_OK) return rc; - uint8_t *bStart = fpc->barrier ? fpc->barrier : fpc->pc.current; - long kept = pc->current - bStart; + uint8_t *bStart = fpc->barrier ? fpc->barrier : pc->current; + unsigned long kept = (unsigned long)(pc->current - bStart); unsigned long buffer_length = (unsigned long)(pc->end - pc->start); if (buffer_length < more + kept) { @@ -281,7 +284,7 @@ static int handle_file_pack_overflow(struct cw_pack_context* pc, unsigned long m void init_file_pack_context (file_pack_context* fpc, unsigned long initial_buffer_length, int fileDescriptor) { - unsigned long buffer_length = (initial_buffer_length > 0 ? initial_buffer_length : 4096); + unsigned long buffer_length = (initial_buffer_length > 32 ? initial_buffer_length : 4096); void *buffer = malloc (buffer_length); if (!buffer) { @@ -293,6 +296,7 @@ void init_file_pack_context (file_pack_context* fpc, unsigned long initial_buffe fpc->barrier = NULL; cw_pack_context_init((cw_pack_context*)fpc, buffer, buffer_length, &handle_file_pack_overflow); + cw_pack_set_flush_handler((cw_pack_context*)fpc, &flush_file_pack_context); } @@ -311,11 +315,11 @@ void file_pack_context_release_barrier (file_pack_context* fpc) void terminate_file_pack_context(file_pack_context* fpc) { fpc->barrier = NULL; - if (fpc->pc.return_code == CWP_RC_OK) - fpc->pc.return_code = flush_file_pack_context(fpc); + cw_pack_context* pc = (cw_pack_context*)fpc; + cw_pack_flush(pc); - if (fpc->pc.return_code != CWP_RC_MALLOC_ERROR) - free(fpc->pc.start); + if (pc->return_code != CWP_RC_MALLOC_ERROR) + free(pc->start); } @@ -327,7 +331,7 @@ static int handle_file_unpack_underflow(struct cw_unpack_context* uc, unsigned l { file_unpack_context* auc = (file_unpack_context*)uc; uint8_t *bStart = auc->barrier ? auc->barrier : uc->current; - unsigned long kept = uc->current - bStart; + unsigned long kept = (unsigned long)(uc->current - bStart); unsigned long remains = (unsigned long)(uc->end - bStart); if (remains) { @@ -347,10 +351,12 @@ static int handle_file_unpack_underflow(struct cw_unpack_context* uc, unsigned l } uc->current = uc->start + kept; uc->end = uc->start + remains; - - while (uc->end - uc->current < more) + if (auc->barrier) + auc->barrier = uc->start; + + while ((unsigned long)(uc->end - uc->current) < more) { - long l = read(auc->fileDescriptor, uc->end, auc->buffer_length - (uc->end - uc->start)); + long l = read(auc->fileDescriptor, uc->end, auc->buffer_length - (unsigned long)(uc->end - uc->start)); if (l == 0) { return CWP_RC_END_OF_INPUT; @@ -390,6 +396,11 @@ void file_unpack_context_set_barrier (file_unpack_context* fuc) } +void file_unpack_context_rescan_from_barrier (file_unpack_context* fuc) +{ + fuc->uc.current = fuc->barrier; +} + void file_unpack_context_release_barrier (file_unpack_context* fuc) { fuc->barrier = NULL; @@ -400,6 +411,7 @@ void terminate_file_unpack_context(file_unpack_context* fuc) { if (fuc->uc.return_code != CWP_RC_MALLOC_ERROR) free(fuc->uc.start); + fuc->uc.start = 0; } diff --git a/goodies/basic-contexts/basic_contexts.h b/goodies/basic-contexts/basic_contexts.h index 99b7718..ebb1427 100644 --- a/goodies/basic-contexts/basic_contexts.h +++ b/goodies/basic-contexts/basic_contexts.h @@ -1,4 +1,4 @@ -/* CWPack/example - basic_contexts.h */ +/* CWPack/goodies - basic_contexts.h */ /* The MIT License (MIT) @@ -105,6 +105,7 @@ typedef struct void init_file_unpack_context (file_unpack_context* suc, unsigned long initial_buffer_length, int fileDescriptor); void file_unpack_context_set_barrier (file_unpack_context* suc); +void file_unpack_context_rescan_from_barrier (file_unpack_context* suc); void file_unpack_context_release_barrier (file_unpack_context* suc); void terminate_file_unpack_context(file_unpack_context* suc); diff --git a/goodies/dump/README.md b/goodies/dump/README.md new file mode 100755 index 0000000..cdff3e4 --- /dev/null +++ b/goodies/dump/README.md @@ -0,0 +1,38 @@ +# CWPack / Goodies / Dump + + +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. + +Syntax: +cwpack_dump [-t 9] [-v] [-h] < msgpackFile > humanReadableFile +-t 9 Tab size +-v Version +-h Help + +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. +If Tab size isn't given, structures are written on a single line. + + +`cwpack_dump < testdump.msgpack` prints: + +``` + 0 [10000000 3.14 "åäöÅÄÖ"] + 1c {"binary": (62696e617279) "extension": (-5,68656c6c6f) "time": '2020-05-20 18:40:00'} + 49 +``` +and `cwpack_dump -t 4 < testdump.msgpack` prints: + +``` + 0 [ + 1 10000000 + 6 3.14 + f "åäöÅÄÖ" + 1c ] + 1c { + 1d "binary": (62696e617279) + 2c "extension": (-5,68656c6c6f) + 3e "time": '2020-05-20 18:40:00' + 49 } + 49 +``` + diff --git a/goodies/dump/cwpack_dump.c b/goodies/dump/cwpack_dump.c new file mode 100755 index 0000000..4e28fde --- /dev/null +++ b/goodies/dump/cwpack_dump.c @@ -0,0 +1,232 @@ +/* CWPack/goodies - cwpack_dump.c */ +/* + The MIT License (MIT) + + Copyright (c) 2017 Claes Wihlborg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#include +#include +#include +#include "basic_contexts.h" + +char tabString[21] = " "; + +#define NEW_LINE {printf ("\n%6x ",(unsigned)(context->current - context->start)); for (ti=0; tireturn_code) return; + + switch (context->item.type) + { + case CWP_ITEM_NIL: + printf("null"); + break; + + case CWP_ITEM_BOOLEAN: + if (context->item.as.boolean) + printf("true"); + else + printf("false"); + break; + + case CWP_ITEM_POSITIVE_INTEGER: + printf("%llu", context->item.as.u64); + break; + + case CWP_ITEM_NEGATIVE_INTEGER: + printf("%lld", context->item.as.i64); + break; + + case CWP_ITEM_FLOAT: + context->item.as.long_real = (double)context->item.as.real; + + case CWP_ITEM_DOUBLE: + printf ("%g", context->item.as.long_real); + break; + + case CWP_ITEM_STR: { + printf("\""); + + for (i=0; i < (int)context->item.as.str.length; i++) + { + unsigned char c = ((unsigned char*)(context->item.as.str.start))[i]; + switch (c) + { + case '"': printf("\\\""); break; + case '\\': printf("\\\\"); break; + case '\b': printf("\\b"); break; + case '\f': printf("\\f"); break; + case '\n': printf("\\n"); break; + case '\r': printf("\\r"); break; + case '\t': printf("\\t"); break; + + default: + if (c < ' ') + printf("\\u%04x",c); + else + printf("%c",c); + break; + } + } + + printf("\""); + break;} + + case CWP_ITEM_BIN: + printf("("); + dump_as_hex (context->item.as.bin.start, context->item.as.bin.length); + printf(")"); + break; + + case CWP_ITEM_ARRAY: + printf("["); + dim = context->item.as.array.size; + tabLevel++; + for (i = 0; i < dim; i++) + { + CHECK_NEW_LINE; + dump_next_item(context,tabLevel); + } + tabLevel--; + if(*tabString) NEW_LINE; + printf("]"); + break; + + case CWP_ITEM_MAP: + printf("{"); + dim = context->item.as.map.size; + tabLevel++; + for (i = 0; i < dim; i++) + { + CHECK_NEW_LINE; + dump_next_item(context,tabLevel); + printf(": "); + dump_next_item(context,tabLevel); + } + tabLevel--; + if(*tabString) NEW_LINE; + printf("}"); + break; + + case CWP_ITEM_TIMESTAMP: + printf("'"); + gmtime_r(&context->item.as.time.tv_sec,&tm); + strftime(s,128,"%F %T", &tm); + printf("%s",s); + if (context->item.as.time.tv_nsec) + { + d = (double)(context->item.as.time.tv_nsec) / 1000000000; + sprintf(s,"%f",d); + printf("%s",s+1); + } + printf("'"); + break; + + default: + if (CWP_ITEM_MIN_RESERVED_EXT <= context->item.type && context->item.type <= CWP_ITEM_MAX_USER_EXT) + { + printf("(%d,",context->item.type); + dump_as_hex (context->item.as.ext.start, context->item.as.ext.length); + printf(")"); + } + else + printf("????? type = %d", context->item.type ); + break; + } +} + + +/******************************* M A I N ******************************/ + + +int main(int argc, const char * argv[]) +{ + int i; + int t = 0; + for (i = 1; i < argc; i++) + { + if (!strcmp(argv[i],"-t") && (i++ < argc)) + { + t = *argv[i] - '0'; + if (strlen(argv[i]) != 1 || t < 1 || t > 9) { + printf("Tab size must be between 1 and 9\n"); + exit(0); + } + } + else if (!strcmp(argv[i],"-v") || !strcmp(argv[i],"--version")) + { + printf("cwpack_dump version = 1.0\n"); + exit(0); + } + else + { + printf("cwpack_dump [-t 9] [-v] [-h]\n"); + printf("-t 9 Tab size\n"); + printf("-v Version\n"); + printf("-h Help\n"); + printf("\nIf Tab size isn't given, structures are written on a single line\n"); + printf("\nInput is taken from stdin and output is written to stdout\n"); + exit(0); + } + } + tabString[t] = 0; + + file_unpack_context fuc; + cw_unpack_context *context = (cw_unpack_context*)&fuc; + + init_file_unpack_context (&fuc, 4096, STDIN_FILENO); + file_unpack_context_set_barrier (&fuc); /* keep whole file in memory buffer to simplify offset calculation */ + + while (!context->return_code) + { + dump_next_item(context,0); + } + printf("\n"); + if (context->return_code != CWP_RC_END_OF_INPUT) + printf("\nERROR RC = %d\n",context->return_code); + + terminate_file_unpack_context (&fuc); +} + diff --git a/goodies/dump/runCWpack_dump.sh b/goodies/dump/runCWpack_dump.sh new file mode 100755 index 0000000..12d0c2f --- /dev/null +++ b/goodies/dump/runCWpack_dump.sh @@ -0,0 +1,3 @@ +clang -ansi -I ../../src/ -I ../basic-contexts/ -o cwpack_dump *.c ../../src/cwpack.c ../basic-contexts/*.c +./cwpack_dump < testdump.msgpack +./cwpack_dump -t 4 < testdump.msgpack diff --git a/goodies/numeric-extensions/README.md b/goodies/numeric-extensions/README.md index 4894f9e..3772d48 100755 --- a/goodies/numeric-extensions/README.md +++ b/goodies/numeric-extensions/README.md @@ -1,11 +1,11 @@ -#CWPack - Goodies - Numeric Extensions +# CWPack / Goodies / Numeric Extensions -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_real`. +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`. ## Pack -```C +``` void cw_pack_ext_integer (cw_pack_context* pack_context, int8_t type, int64_t i); void cw_pack_ext_float (cw_pack_context* pack_context, int8_t type, float f); void cw_pack_ext_double (cw_pack_context* pack_context, int8_t type, double d); @@ -13,9 +13,9 @@ void cw_pack_ext_double (cw_pack_context* pack_context, int8_t type, double d); ## Unpack -```C -int get_ext_integer (cw_unpack_context* unpack_context, int64_t* value); -int get_ext_float (cw_unpack_context* unpack_context, float* value); -int get_ext_double (cw_unpack_context* unpack_context, double* value); +``` +int64_t get_ext_integer (cw_unpack_context* unpack_context); +float get_ext_float (cw_unpack_context* unpack_context); +double get_ext_double (cw_unpack_context* unpack_context); ``` 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. diff --git a/goodies/numeric-extensions/numeric_extensions.c b/goodies/numeric-extensions/numeric_extensions.c index 8741bd8..68c26a4 100644 --- a/goodies/numeric-extensions/numeric_extensions.c +++ b/goodies/numeric-extensions/numeric_extensions.c @@ -1,14 +1,27 @@ -// -// numeric_extensions.c -// CWPack -// -// Created by Claes Wihlborg on 2017-01-16. -// Copyright © 2017 Claes Wihlborg. All rights reserved. -// +/* CWPack/goodies - numeric_extensions.c */ +/* + The MIT License (MIT) + Copyright (c) 2017 Claes Wihlborg -#include "cwpack.h" -#include "cwpack_defines.h" + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#include "cwpack_internals.h" #include "numeric_extensions.h" @@ -90,80 +103,94 @@ void cw_pack_ext_double (cw_pack_context* pack_context, int8_t type, double d) } -int get_ext_integer (cw_unpack_context* unpack_context, int64_t* value) +int64_t get_ext_integer (cw_unpack_context* unpack_context) { + if (unpack_context->return_code != CWP_RC_OK) + { + return 0; + } + uint16_t tmpu16; uint32_t tmpu32; uint64_t tmpu64; if (unpack_context->item.type > CWP_ITEM_MAX_USER_EXT) { - return NUMEXT_ERROR_NOT_EXT; + unpack_context->return_code = CWP_RC_TYPE_ERROR; + return 0; } switch (unpack_context->item.as.ext.length) { case 1: - *value = (int64_t)*unpack_context->item.as.ext.start; - break; - + return *(int8_t*)unpack_context->item.as.ext.start; + case 2: cw_load16(unpack_context->item.as.ext.start); - *value = (int16_t)tmpu16; - break; - + return (int16_t)tmpu16; + case 4: cw_load32(unpack_context->item.as.ext.start); - *value = (int32_t)tmpu32; - break; - + return (int32_t)tmpu32; + case 8: - cw_load64(unpack_context->item.as.ext.start); - *value = (int64_t)tmpu64; - break; - + cw_load64(unpack_context->item.as.ext.start,tmpu64); + return (int64_t)tmpu64; + default: - return NUMEXT_ERROR_WRONG_LENGTH; + unpack_context->return_code = CWP_RC_VALUE_ERROR; } return 0; } -int get_ext_float (cw_unpack_context* unpack_context, float* value) +float get_ext_float (cw_unpack_context* unpack_context) { + if (unpack_context->return_code != CWP_RC_OK) + { + return 0; + } + uint32_t tmpu32; if (unpack_context->item.type > CWP_ITEM_MAX_USER_EXT) { - return NUMEXT_ERROR_NOT_EXT; + unpack_context->return_code = CWP_RC_TYPE_ERROR; + return 0.0; } - + if (unpack_context->item.as.ext.length != 4) { - return NUMEXT_ERROR_WRONG_LENGTH; + unpack_context->return_code = CWP_RC_VALUE_ERROR; + return 0.0; } cw_load32(unpack_context->item.as.ext.start); - *value = *(float*)&tmpu32; - return 0; + return *(float*)&tmpu32; } -int get_ext_double (cw_unpack_context* unpack_context, double* value) +double get_ext_double (cw_unpack_context* unpack_context) { + if (unpack_context->return_code != CWP_RC_OK) + { + return 0; + } + uint64_t tmpu64; if (unpack_context->item.type > CWP_ITEM_MAX_USER_EXT) { - return NUMEXT_ERROR_NOT_EXT; + unpack_context->return_code = CWP_RC_TYPE_ERROR; + return 0.0; } - + if (unpack_context->item.as.ext.length != 8) { - return NUMEXT_ERROR_WRONG_LENGTH; + unpack_context->return_code = CWP_RC_VALUE_ERROR; + return 0.0; } - - cw_load64(unpack_context->item.as.ext.start); - *value = *(double*)&tmpu64; - return 0; + + cw_load64(unpack_context->item.as.ext.start,tmpu64); + return *(double*)&tmpu64; } diff --git a/goodies/numeric-extensions/numeric_extensions.h b/goodies/numeric-extensions/numeric_extensions.h index 9d7dbdf..a9237a6 100644 --- a/goodies/numeric-extensions/numeric_extensions.h +++ b/goodies/numeric-extensions/numeric_extensions.h @@ -1,10 +1,24 @@ -// -// numeric_extensions.h -// CWPack -// -// Created by Claes Wihlborg on 2017-01-16. -// Copyright © 2017 Claes Wihlborg. All rights reserved. -// +/* CWPack/goodies - numeric_extensions.h */ +/* + The MIT License (MIT) + + Copyright (c) 2017 Claes Wihlborg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ #ifndef numeric_extensions_h #define numeric_extensions_h @@ -13,8 +27,8 @@ -#define NUMEXT_ERROR_NOT_EXT 1; -#define NUMEXT_ERROR_WRONG_LENGTH 2; +#define NUMEXT_ERROR_NOT_EXT CWP_RC_TYPE_ERROR; +#define NUMEXT_ERROR_WRONG_LENGTH CWP_RC_VALUE_ERROR; @@ -24,9 +38,9 @@ void cw_pack_ext_double (cw_pack_context* pack_context, int8_t type, double d); - int get_ext_integer (cw_unpack_context* unpack_context, int64_t* value); - int get_ext_float (cw_unpack_context* unpack_context, float* value); - int get_ext_double (cw_unpack_context* unpack_context, double* value); + int64_t get_ext_integer (cw_unpack_context* unpack_context); + float get_ext_float (cw_unpack_context* unpack_context); + double get_ext_double (cw_unpack_context* unpack_context); diff --git a/goodies/numeric-extensions/numeric_extensions_test.c b/goodies/numeric-extensions/numeric_extensions_test.c index 27ffa44..0ca3290 100644 --- a/goodies/numeric-extensions/numeric_extensions_test.c +++ b/goodies/numeric-extensions/numeric_extensions_test.c @@ -1,17 +1,32 @@ -// -// numeric_extensions_test.c -// CWPack -// -// Created by Claes Wihlborg on 2017-01-17. -// Copyright © 2017 Claes Wihlborg. All rights reserved. -// +/* CWPack/goodies - numeric_extensions_test.c */ +/* + The MIT License (MIT) + + Copyright (c) 2017 Claes Wihlborg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + #include #include #include #include "cwpack.h" -#include "cwpack_defines.h" +#include "cwpack_internals.h" #include "numeric_extensions.h" @@ -118,7 +133,6 @@ int main(int argc, const char * argv[]) { printf("CWPack numeric extensions test started.\n"); error_count = 0; - int i; bool endian_switch_found = false; #ifdef COMPILE_FOR_BIG_ENDIAN @@ -197,8 +211,9 @@ int main(int argc, const char * argv[]) ERROR1("In unpack_next, rc = ",unpack_ctx.return_code); \ if (unpack_ctx.item.type != etype) \ ERROR("In unpack, type error"); \ - if ((i=get_ext_##call (&unpack_ctx, &call##_var))) \ - ERROR1("In get_ext, rc = ",i); \ + call##_var = get_ext_##call (&unpack_ctx); \ + if (unpack_ctx.return_code) \ + ERROR1("In get_ext, rc = ",unpack_ctx.return_code); \ if (call##_var != value) \ ERROR("In unpack, value error"); \ } diff --git a/goodies/objC/README.md b/goodies/objC/README.md new file mode 100755 index 0000000..214c18f --- /dev/null +++ b/goodies/objC/README.md @@ -0,0 +1,40 @@ +# CWPack / Goodies / ObjC + + +ObjC contains a wrapper for objective-C in the form of a category to NSObject. +The category contains two methods: + +```C +/* *********************** P A C K *****************************/ +- (void) packIn:(cw_pack_context*) buff; + +/* *********************** U N P A C K *************************/ ++ (instancetype) unpackFrom:(cw_unpack_context*) buff; +``` + +The methods are defined for the standard classes NSString, NSData, NSNumber, NSDate, NSNull, NSDictionary, NSArray and NSSet. + +For other classes you need to define the methods yourself. E.g. + +```C +@interface myClass: NSObject { + int theInt; + NSMutableSet theSet; +} +@end + +@implementation myClass +- (void) packIn:(cw_pack_context*) buff +{ + cw_pack_signed( buff, theInt ); + [theSet packIn:buff]; +} ++ (instancetype) unpackFrom:(cw_unpack_context*) buff +{ + int anInt = cw_unpack_next_signed32( buff ); + NSMutableSet aSet = [NSMutableSet unpackFrom:buff]; + return [[self alloc] initWithInt:anInt set:aSet]; +} +@end +``` + diff --git a/goodies/objC/cwpack_objc.h b/goodies/objC/cwpack_objc.h new file mode 100755 index 0000000..8e8ce0e --- /dev/null +++ b/goodies/objC/cwpack_objc.h @@ -0,0 +1,38 @@ +/* CWPack/goodies - cwpack_objc.h */ +/* + The MIT License (MIT) + + Copyright (c) 2017 Claes Wihlborg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#import +#import "cwpack.h" + + + + +@interface NSObject (cwPack) + +/* *********************** P A C K *****************************/ +- (void) packIn:(cw_pack_context*) buff; + +/* *********************** U N P A C K *************************/ ++ (instancetype) unpackFrom:(cw_unpack_context*) buff; + +@end diff --git a/goodies/objC/cwpack_objc.m b/goodies/objC/cwpack_objc.m new file mode 100755 index 0000000..2cf6f38 --- /dev/null +++ b/goodies/objC/cwpack_objc.m @@ -0,0 +1,274 @@ +/* CWPack/goodies - cwpack_objc.m */ +/* + The MIT License (MIT) + + Copyright (c) 2017 Claes Wihlborg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#import "cwpack_objc.h" +#import "cwpack_utils.h" + + +id cwObjectFromBuffer (cw_unpack_context* inbuf); + + +@implementation NSObject (cwPack) + +- (void) packIn:(cw_pack_context*) buff +{ + buff->return_code = CWP_RC_ILLEGAL_CALL; // No pack defined for this object type + [NSException raise:@"[NSObject packIn:]" format:@"PackIn not defined for class: %@", [self class]]; +} + + ++ (instancetype) unpackFrom:(cw_unpack_context*) buff +{ + id result = cwObjectFromBuffer(buff); + + if (![[result class] isSubclassOfClass:self]) + { + if ([[result class] isSubclassOfClass:NSArray] && [self isSubclassOfClass:NSSet]) + return [self setWithArray:result]; + + if ([[result class] isSubclassOfClass:NSNull]) + return nil; + + else + { + buff->return_code = CWP_RC_TYPE_ERROR; // Unexpected object type + [NSException raise:@"[NSObject unpackFrom:]" format:@"Class %@ detected when expected class: %@", [result class], self]; + } + } + return result; +} + +@end + + +@implementation NSNull (cwPack) + +- (void) packIn:(cw_pack_context*) buff +{ + cw_pack_nil (buff); +} +@end + + +@implementation NSString (cwPack) + +- (void) packIn:(cw_pack_context*) buff +{ + cw_pack_cstr (buff, self.UTF8String); +} +@end + + +@implementation NSData (cwPack) + +- (void) packIn:(cw_pack_context*) buff +{ + cw_pack_bin(buff, self.bytes, (uint32_t)self.length); +} +@end + + +@implementation NSNumber (cwPack) + +- (void) packIn:(cw_pack_context*) buff +{ + CFNumberType numberType = CFNumberGetType((CFNumberRef)self); + switch (numberType) + { + case kCFNumberSInt8Type: + case kCFNumberSInt16Type: + case kCFNumberShortType: + case kCFNumberSInt32Type: + case kCFNumberIntType: + case kCFNumberLongType: + case kCFNumberCFIndexType: + case kCFNumberNSIntegerType: + case kCFNumberSInt64Type: + case kCFNumberLongLongType: + cw_pack_signed(buff, self.longLongValue); + return; + + case kCFNumberFloat32Type: + case kCFNumberFloatType: + case kCFNumberCGFloatType: + cw_pack_float(buff, self.floatValue); + return; + + case kCFNumberFloat64Type: + case kCFNumberDoubleType: + cw_pack_double(buff, self.doubleValue); + return; + + case kCFNumberCharType: + { + int theValue = self.intValue; + if (theValue == 0) + { + cw_pack_boolean(buff, NO); + } + if (theValue == 1) + { + cw_pack_boolean(buff, YES); + } + else + { + cw_pack_signed(buff, theValue); + } + return; + } + default: + buff->return_code = CWP_RC_ILLEGAL_CALL; // No pack defined for this object type + [NSException raise:@"[NSNumber packIn:]" format:@"Cannot recognise type of: %@", self]; + } +} +@end + + +@implementation NSArray (cwPack) + +- (void) packIn:(cw_pack_context*) buff +{ + uint32_t i, cnt = (uint32_t)self.count; + cw_pack_array_size(buff, cnt); + for (i = 0; i < cnt; i++) + [self[i] packIn:buff]; +} +@end + + +@implementation NSSet (cwPack) + +- (void) packIn:(cw_pack_context*) buff +{ + uint32_t cnt = (uint32_t)self.count; + cw_pack_array_size(buff, cnt); // Hide the set in an array + for (id object in self) + [object packIn:buff]; +} +@end + + +@implementation NSDictionary (cwPack) + +- (void) packIn:(cw_pack_context*) buff +{ + cw_pack_map_size(buff, (uint32_t)self.count); + for (id obj in self) + { + [obj packIn:buff]; + [self[obj] packIn:buff]; + } +} +@end + + +@implementation NSDate (cwPack) + +- (void) packIn:(cw_pack_context*) buff +{ + struct timespec t; + + NSTimeInterval ti = self.timeIntervalSince1970; + t.tv_sec = floor(ti); + t.tv_nsec = floor((ti - t.tv_sec)*1000000000); + cw_pack_time(buff, &t); +} +@end + + + + +/******************************* U N P A C K ******************************/ + + +id cwObjectFromBuffer (cw_unpack_context* inbuf) +{ + cw_unpack_next(inbuf); + if (inbuf->return_code) + return nil; + + switch (inbuf->item.type) + { + case CWP_ITEM_NIL: + return [NSNull null]; + + case CWP_ITEM_BOOLEAN: + return [NSNumber numberWithBool:inbuf->item.as.boolean]; + + case CWP_ITEM_POSITIVE_INTEGER: + return [NSNumber numberWithUnsignedLongLong:inbuf->item.as.u64]; + + case CWP_ITEM_NEGATIVE_INTEGER: + return [NSNumber numberWithLongLong:inbuf->item.as.i64]; + + case CWP_ITEM_FLOAT: + return [[NSNumber alloc] initWithFloat:inbuf->item.as.real]; + + case CWP_ITEM_DOUBLE: + return [NSNumber numberWithDouble:inbuf->item.as.long_real]; + + case CWP_ITEM_STR: + return [[[NSString alloc] initWithBytes:inbuf->item.as.str.start length:inbuf->item.as.str.length encoding:NSUTF8StringEncoding] autorelease]; + + case CWP_ITEM_BIN: + return [NSData dataWithBytes:inbuf->item.as.bin.start length:inbuf->item.as.bin.length]; + + case CWP_ITEM_ARRAY: + { + int i, dim = inbuf->item.as.array.size; + NSMutableArray *arr = [NSMutableArray arrayWithCapacity:dim]; + for(i = 0; i < dim; i++) + { + id item = cwObjectFromBuffer (inbuf); + if (!inbuf->return_code) + [arr addObject:item]; + } + return arr; + } + + case CWP_ITEM_MAP: + { + int i, dim = inbuf->item.as.map.size; + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:dim]; + for(i = 0; i < dim; i++) + { + id key = cwObjectFromBuffer (inbuf); + id val = cwObjectFromBuffer (inbuf); + if (!inbuf->return_code) + [dict setValue:val forKey:key]; + } + return dict; + } + + case CWP_ITEM_TIMESTAMP: + { + return [NSDate dateWithTimeIntervalSince1970:inbuf->item.as.time.tv_sec + inbuf->item.as.time.tv_nsec / 1000000000.0]; + } + + default: + return nil; + } +} + + + diff --git a/goodies/utils/README.md b/goodies/utils/README.md new file mode 100755 index 0000000..506055c --- /dev/null +++ b/goodies/utils/README.md @@ -0,0 +1,52 @@ +# CWPack / Goodies / Utils + + +Utils contains some convenience routines: + +### C string packing +```C +void cw_pack_cstr (cw_pack_context* pack_context, const char* v); +``` + +### Optimized packing of real numbers +Pack float as signed if precision isn't destroyed + +```C +void cw_pack_float_opt (cw_pack_context* pack_context, float f); +``` +Pack double as signed or float if precision isn't destroyed + +```C +void cw_pack_double_opt (cw_pack_context* pack_context, double d); +``` + +### Packing seconds and fractions thereof that have elapsed since epoch +```C +void cw_pack_time_interval (cw_pack_context* pack_context, double ti); +``` +### Easy retreival (expect api) + +```C +bool cw_unpack_next_boolean (cw_unpack_context* unpack_context); + +int64_t cw_unpack_next_signed64 (cw_unpack_context* unpack_context); +int32_t cw_unpack_next_signed32 (cw_unpack_context* unpack_context); +int16_t cw_unpack_next_signed16 (cw_unpack_context* unpack_context); +int8_t cw_unpack_next_signed8 (cw_unpack_context* unpack_context); + +uint64_t cw_unpack_next_unsigned64 (cw_unpack_context* unpack_context); +uint32_t cw_unpack_next_unsigned32 (cw_unpack_context* unpack_context); +uint16_t cw_unpack_next_unsigned16 (cw_unpack_context* unpack_context); +uint8_t cw_unpack_next_unsigned8 (cw_unpack_context* unpack_context); + +float cw_unpack_next_float (cw_unpack_context* unpack_context); +double cw_unpack_next_double (cw_unpack_context* unpack_context); +double cw_unpack_next_time_interval (cw_unpack_context* unpack_context); + +unsigned int cw_unpack_next_str_lengh (cw_unpack_context* unpack_context); + +unsigned int cw_unpack_next_array_size(cw_unpack_context* unpack_context); +unsigned int cw_unpack_next_map_size(cw_unpack_context* unpack_context); +``` +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. + diff --git a/goodies/utils/cwpack_utils.c b/goodies/utils/cwpack_utils.c new file mode 100755 index 0000000..bfdaaa9 --- /dev/null +++ b/goodies/utils/cwpack_utils.c @@ -0,0 +1,366 @@ +/* CWPack/goodies - cwpack_utils.c */ +/* + The MIT License (MIT) + + Copyright (c) 2017 Claes Wihlborg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#include "cwpack_utils.h" + + + + +/******************************* P A C K **********************************/ + + +void cw_pack_double_opt (cw_pack_context* pack_context, double d) +{ + int i = (int)d; + if (i == d) + cw_pack_signed(pack_context, i); + else + { + float f = (float)d; + if (f == d) + cw_pack_float (pack_context, f); + else + cw_pack_double (pack_context, d); + } +} + + +void cw_pack_float_opt (cw_pack_context* pack_context, float f) +{ + int i = (int)f; + if (i == f) + cw_pack_signed(pack_context, i); + else + cw_pack_float (pack_context, f); +} + +void cw_pack_time_interval (cw_pack_context* pack_context, double ti) +{ + struct timespec ts; + ts.tv_sec = (long)ti; + ts.tv_nsec = (long)((ti - (double)ts.tv_sec) * 1000000000.0); + cw_pack_time(pack_context, &ts); +} + +/******************************* U N P A C K ******************************/ + +#define NaN 0 + +float cw_unpack_next_float (cw_unpack_context* unpack_context) +{ + cw_unpack_next (unpack_context); + if (unpack_context->return_code) return NaN; + + switch (unpack_context->item.type) { + case CWP_ITEM_POSITIVE_INTEGER: return unpack_context->item.as.u64; + case CWP_ITEM_NEGATIVE_INTEGER: return unpack_context->item.as.i64; + case CWP_ITEM_FLOAT: return unpack_context->item.as.real; + case CWP_ITEM_DOUBLE: return (float)unpack_context->item.as.long_real; + default: unpack_context->return_code = CWP_RC_TYPE_ERROR; + return NaN; + } +} + +double cw_unpack_next_double (cw_unpack_context* unpack_context) +{ + cw_unpack_next (unpack_context); + if (unpack_context->return_code) return NaN; + + switch (unpack_context->item.type) { + case CWP_ITEM_POSITIVE_INTEGER: return unpack_context->item.as.u64; + case CWP_ITEM_NEGATIVE_INTEGER: return unpack_context->item.as.i64; + case CWP_ITEM_FLOAT: return unpack_context->item.as.real; + case CWP_ITEM_DOUBLE: return unpack_context->item.as.long_real; + default: unpack_context->return_code = CWP_RC_TYPE_ERROR; + return NaN; + } +} + +bool cw_unpack_next_boolean (cw_unpack_context* unpack_context) +{ + cw_unpack_next (unpack_context); + if (unpack_context->return_code) + return false; + + if (unpack_context->item.type == CWP_ITEM_BOOLEAN) + return unpack_context->item.as.boolean; + + unpack_context->return_code = CWP_RC_TYPE_ERROR; + return false; +} + + +int64_t cw_unpack_next_signed64 (cw_unpack_context* unpack_context) +{ + cw_unpack_next (unpack_context); + if (unpack_context->return_code) + return 0; + + if (unpack_context->item.type == CWP_ITEM_POSITIVE_INTEGER) + { + if (unpack_context->item.as.u64 <= INT64_MAX) + return unpack_context->item.as.i64; + else + { + unpack_context->return_code = CWP_RC_VALUE_ERROR; + return 0; + } + } + + if (unpack_context->item.type == CWP_ITEM_NEGATIVE_INTEGER) + return unpack_context->item.as.i64; + + unpack_context->return_code = CWP_RC_TYPE_ERROR; + return 0; +} + + +int32_t cw_unpack_next_signed32 (cw_unpack_context* unpack_context) +{ + cw_unpack_next (unpack_context); + if (unpack_context->return_code) + return 0; + + if (unpack_context->item.type == CWP_ITEM_POSITIVE_INTEGER) + { + if (unpack_context->item.as.u64 <= INT32_MAX) + return (int)unpack_context->item.as.i64; + else + { + unpack_context->return_code = CWP_RC_VALUE_ERROR; + return 0; + } + } + if (unpack_context->item.type == CWP_ITEM_NEGATIVE_INTEGER) + { + if (unpack_context->item.as.i64 >= INT32_MIN) + return (int)unpack_context->item.as.i64; + else + { + unpack_context->return_code = CWP_RC_VALUE_ERROR; + return 0; + } + } + + unpack_context->return_code = CWP_RC_TYPE_ERROR; + return 0; +} + + +int16_t cw_unpack_next_signed16 (cw_unpack_context* unpack_context) +{ + cw_unpack_next (unpack_context); + if (unpack_context->return_code) + return 0; + + if (unpack_context->item.type == CWP_ITEM_POSITIVE_INTEGER) + { + if (unpack_context->item.as.u64 <= INT16_MAX) + return (int16_t)unpack_context->item.as.i64; + else + { + unpack_context->return_code = CWP_RC_VALUE_ERROR; + return 0; + } + } + if (unpack_context->item.type == CWP_ITEM_NEGATIVE_INTEGER) + { + if (unpack_context->item.as.i64 >= INT16_MIN) + return (int16_t)unpack_context->item.as.i64; + else + { + unpack_context->return_code = CWP_RC_VALUE_ERROR; + return 0; + } + } + + unpack_context->return_code = CWP_RC_TYPE_ERROR; + return 0; +} + + +int8_t cw_unpack_next_signed8 (cw_unpack_context* unpack_context) +{ + cw_unpack_next (unpack_context); + if (unpack_context->return_code) + return 0; + + if (unpack_context->item.type == CWP_ITEM_POSITIVE_INTEGER) + { + if (unpack_context->item.as.u64 <= INT8_MAX) + return (int8_t)unpack_context->item.as.i64; + else + { + unpack_context->return_code = CWP_RC_VALUE_ERROR; + return 0; + } + } + if (unpack_context->item.type == CWP_ITEM_NEGATIVE_INTEGER) + { + if (unpack_context->item.as.i64 >= INT8_MIN) + return (int8_t)unpack_context->item.as.i64; + else + { + unpack_context->return_code = CWP_RC_VALUE_ERROR; + return 0; + } + } + + unpack_context->return_code = CWP_RC_TYPE_ERROR; + return 0; +} + + + +uint64_t cw_unpack_next_unsigned64 (cw_unpack_context* unpack_context) +{ + cw_unpack_next (unpack_context); + if (unpack_context->return_code) + return 0; + + if (unpack_context->item.type == CWP_ITEM_POSITIVE_INTEGER) + { + return unpack_context->item.as.u64; + } + + unpack_context->return_code = CWP_RC_TYPE_ERROR; + return 0; +} + + +uint32_t cw_unpack_next_unsigned32 (cw_unpack_context* unpack_context) +{ + cw_unpack_next (unpack_context); + if (unpack_context->return_code) + return 0; + + if (unpack_context->item.type == CWP_ITEM_POSITIVE_INTEGER) + { + if (unpack_context->item.as.u64 <= UINT32_MAX) + return (uint32_t)unpack_context->item.as.u64; + else + { + unpack_context->return_code = CWP_RC_VALUE_ERROR; + return 0; + } + } + + unpack_context->return_code = CWP_RC_TYPE_ERROR; + return 0; +} + + +uint16_t cw_unpack_next_unsigned16 (cw_unpack_context* unpack_context) +{ + cw_unpack_next (unpack_context); + if (unpack_context->return_code) + return 0; + + if (unpack_context->item.type == CWP_ITEM_POSITIVE_INTEGER) + { + if (unpack_context->item.as.u64 <= UINT16_MAX) + return (uint16_t)unpack_context->item.as.u64; + else + { + unpack_context->return_code = CWP_RC_VALUE_ERROR; + return 0; + } + } + + unpack_context->return_code = CWP_RC_TYPE_ERROR; + return 0; +} + + +uint8_t cw_unpack_next_unsigned8 (cw_unpack_context* unpack_context) +{ + cw_unpack_next (unpack_context); + if (unpack_context->return_code) + return 0; + + if (unpack_context->item.type == CWP_ITEM_POSITIVE_INTEGER) + { + if (unpack_context->item.as.u64 <= UINT8_MAX) + return (uint8_t)unpack_context->item.as.u64; + else + { + unpack_context->return_code = CWP_RC_VALUE_ERROR; + return 0; + } + } + + unpack_context->return_code = CWP_RC_TYPE_ERROR; + return 0; +} + + +double cw_unpack_next_time_interval (cw_unpack_context* unpack_context) +{ + cw_unpack_next (unpack_context); + if (unpack_context->return_code) return NaN; + + if (unpack_context->item.type == CWP_ITEM_TIMESTAMP) + { + return (double)unpack_context->item.as.time.tv_sec + (double)unpack_context->item.as.time.tv_nsec/1000000000; + } + + unpack_context->return_code = CWP_RC_TYPE_ERROR; + return NaN; +} + +unsigned int cw_unpack_next_str_lengh (cw_unpack_context* unpack_context) +{ + cw_unpack_next (unpack_context); + if (unpack_context->return_code) return 0; + + if (unpack_context->item.type == CWP_ITEM_STR) + return unpack_context->item.as.str.length; + + unpack_context->return_code = CWP_RC_TYPE_ERROR; + return NaN; +} + + +unsigned int cw_unpack_next_array_size(cw_unpack_context* unpack_context) +{ + cw_unpack_next (unpack_context); + if (unpack_context->return_code) return 0; + + if (unpack_context->item.type == CWP_ITEM_ARRAY) + return unpack_context->item.as.array.size; + + unpack_context->return_code = CWP_RC_TYPE_ERROR; + return 0; +} + +unsigned int cw_unpack_next_map_size(cw_unpack_context* unpack_context) +{ + cw_unpack_next (unpack_context); + if (unpack_context->return_code) return 0; + + if (unpack_context->item.type == CWP_ITEM_MAP) + return unpack_context->item.as.map.size; + + unpack_context->return_code = CWP_RC_TYPE_ERROR; + return 0; +} diff --git a/goodies/utils/cwpack_utils.h b/goodies/utils/cwpack_utils.h new file mode 100644 index 0000000..abb6fc4 --- /dev/null +++ b/goodies/utils/cwpack_utils.h @@ -0,0 +1,64 @@ +/* CWPack/goodies - cwpack_utils.h */ +/* + The MIT License (MIT) + + Copyright (c) 2017 Claes Wihlborg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef CWPack_utils_H__ +#define CWPack_utils_H__ + + +#include "cwpack.h" + +/******************************* P A C K **********************************/ + +#define cw_pack_cstr(context,string) cw_pack_str (context, string, (uint32)strlen(string)) + +void cw_pack_float_opt (cw_pack_context* pack_context, float f); /* Pack as signed if precision isn't destroyed */ +void cw_pack_double_opt (cw_pack_context* pack_context, double d); /* Pack as signed or float if precision isn't destroyed */ +#define cw_pack_real cw_pack_double_opt /* Backward compatibility */ + +void cw_pack_time_interval (cw_pack_context* pack_context, double ti); + +/***************************** U N P A C K ********************************/ + +bool cw_unpack_next_boolean (cw_unpack_context* unpack_context); + +int64_t cw_unpack_next_signed64 (cw_unpack_context* unpack_context); +int32_t cw_unpack_next_signed32 (cw_unpack_context* unpack_context); +int16_t cw_unpack_next_signed16 (cw_unpack_context* unpack_context); +int8_t cw_unpack_next_signed8 (cw_unpack_context* unpack_context); + +uint64_t cw_unpack_next_unsigned64 (cw_unpack_context* unpack_context); +uint32_t cw_unpack_next_unsigned32 (cw_unpack_context* unpack_context); +uint16_t cw_unpack_next_unsigned16 (cw_unpack_context* unpack_context); +uint8_t cw_unpack_next_unsigned8 (cw_unpack_context* unpack_context); + +float cw_unpack_next_float (cw_unpack_context* unpack_context); +double cw_unpack_next_double (cw_unpack_context* unpack_context); +double cw_unpack_next_time_interval (cw_unpack_context* unpack_context); +#define cw_unpack_next_real cw_unpack_next_double /* Backward compatibility */ + +unsigned int cw_unpack_next_str_lengh (cw_unpack_context* unpack_context); + +unsigned int cw_unpack_next_array_size(cw_unpack_context* unpack_context); +unsigned int cw_unpack_next_map_size(cw_unpack_context* unpack_context); + +#endif /* CWPack_utils_H__ */ + diff --git a/src/README.md b/src/README.md new file mode 100755 index 0000000..71f765b --- /dev/null +++ b/src/README.md @@ -0,0 +1,28 @@ +# CWPack / src + +The src folder contains all basic functionallity to use CWPack. + +## Files + +**cwpack.h** contains the interface to CWPack. You should include this in your code. + +**cwpack_config.h** contains info about your processor. Byte order, alignment etc. Update this file to suit you. + +**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. + +**cwpack.c** contains the code. + +## Contexts +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. + +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). + +## How to use +First you choose a context that suits your needs and initiates it. Then you can do the packing/unpacking. + +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. + +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). +You find an Objective-C wrapper in [goodies/objC](https://github.com/clwi/CWPack/tree/master/goodies/objC). + + diff --git a/src/cwpack.c b/src/cwpack.c index 269eb76..20dd064 100644 --- a/src/cwpack.c +++ b/src/cwpack.c @@ -21,9 +21,10 @@ */ #include +#include #include "cwpack.h" -#include "cwpack_defines.h" +#include "cwpack_internals.h" @@ -78,6 +79,7 @@ int cw_pack_context_init (cw_pack_context* pack_context, void* data, unsigned lo pack_context->be_compatible = false; pack_context->err_no = 0; pack_context->handle_pack_overflow = hpo; + pack_context->handle_flush = NULL; pack_context->return_code = test_byte_order(); return pack_context->return_code; } @@ -87,6 +89,11 @@ void cw_pack_set_compatibility (cw_pack_context* pack_context, bool be_compatibl pack_context->be_compatible = be_compatible; } +void cw_pack_set_flush_handler (cw_pack_context* pack_context, pack_flush_handler handle_flush) +{ + pack_context->handle_flush = handle_flush; +} + /* Packing routines -------------------------------------------------------------------------------- */ @@ -169,22 +176,11 @@ void cw_pack_double(cw_pack_context* pack_context, double d) } -void cw_pack_real (cw_pack_context* pack_context, double d) -{ - float f = (float)d; - double df = f; - if (df == d) - cw_pack_float (pack_context, f); - else - cw_pack_double (pack_context, d); -} - - void cw_pack_nil(cw_pack_context* pack_context) { if (pack_context->return_code) return; - + tryMove0(0xc0); } @@ -384,6 +380,49 @@ void cw_pack_ext (cw_pack_context* pack_context, int8_t type, const void* v, uin } +void cw_pack_time (cw_pack_context* pack_context, struct timespec* t) +{ + if (pack_context->return_code) + return; + + if (pack_context->be_compatible) + PACK_ERROR(CWP_RC_ILLEGAL_CALL); + + uint8_t *p; + + if ((t->tv_sec >> 34) == 0) { + uint64_t data64 = (uint64_t)((t->tv_nsec << 34) | t->tv_sec); + if ((data64 & 0xffffffff00000000L) == 0) { + // timestamp 32 + uint32_t data32 = (uint32_t)data64; + //serialize(0xd6, -1, data32) + cw_pack_reserve_space(6); + *p++ = (uint8_t)0xd6; + *p++ = (uint8_t)0xff; + cw_store32(data32); + } + else { + // timestamp 64 + //serialize(0xd7, -1, data64) + cw_pack_reserve_space(10); + *p++ = (uint8_t)0xd7; + *p++ = (uint8_t)0xff; + cw_store64(data64); + } + } + else { + // timestamp 96 + //serialize(0xc7, 12, -1, t->tv_nsec, t->tv_sec) + cw_pack_reserve_space(3+12); + *p++ = (uint8_t)0xc7; + *p++ = (uint8_t)12; + *p++ = (uint8_t)0xff; + cw_store32(t->tv_nsec); + cw_store64(t->tv_sec); + } +} + + void cw_pack_insert (cw_pack_context* pack_context, const void* v, uint32_t l) { uint8_t *p; @@ -391,10 +430,21 @@ void cw_pack_insert (cw_pack_context* pack_context, const void* v, uint32_t l) memcpy(p,v,l); } + +void cw_pack_flush (cw_pack_context* pack_context) +{ + if (pack_context->return_code == CWP_RC_OK) + pack_context->return_code = + pack_context->handle_flush ? + pack_context->handle_flush(pack_context) : + CWP_RC_ILLEGAL_CALL; +} + + /******************************* U N P A C K **********************************/ -int cw_unpack_context_init (cw_unpack_context* unpack_context, void* data, unsigned long length, unpack_underflow_handler huu) +int cw_unpack_context_init (cw_unpack_context* unpack_context, const void* data, unsigned long length, unpack_underflow_handler huu) { unpack_context->start = unpack_context->current = (uint8_t*)data; unpack_context->end = unpack_context->start + length; @@ -467,6 +517,19 @@ void cw_unpack_next (cw_unpack_context* unpack_context) case 0xc7: getDDItem1(CWP_ITEM_EXT, ext.length, uint8_t); // ext 8 cw_unpack_assert_space(1); unpack_context->item.type = *(int8_t*)p; + if (unpack_context->item.type == CWP_ITEM_TIMESTAMP) + { + if (unpack_context->item.as.ext.length == 12) + { + cw_unpack_assert_space(4); + cw_load32(p); + unpack_context->item.as.time.tv_nsec = (long)tmpu32; + cw_unpack_assert_space(8); + cw_load64(p,unpack_context->item.as.time.tv_sec); + return; + } + UNPACK_ERROR(CWP_RC_WRONG_TIMESTAMP_LENGTH) + } cw_unpack_assert_blob(ext); case 0xc8: getDDItem2(CWP_ITEM_EXT, ext.length, uint16_t); // ext 16 cw_unpack_assert_space(1); @@ -497,7 +560,7 @@ void cw_unpack_next (cw_unpack_context* unpack_context) if (unpack_context->item.as.i64 >= 0) unpack_context->item.type = CWP_ITEM_POSITIVE_INTEGER; return; - case 0xd3: getDDItem8(CWP_ITEM_NEGATIVE_INTEGER); // signed int 64 + case 0xd3: getDDItem8(CWP_ITEM_NEGATIVE_INTEGER); // signed int 64 if (unpack_context->item.as.i64 >= 0) unpack_context->item.type = CWP_ITEM_POSITIVE_INTEGER; return; diff --git a/src/cwpack.h b/src/cwpack.h index 02ff6bc..3e06ff6 100644 --- a/src/cwpack.h +++ b/src/cwpack.h @@ -26,21 +26,25 @@ #include #include +#include /******************************* Return Codes *****************************/ -#define CWP_RC_OK 0 -#define CWP_RC_END_OF_INPUT -1 -#define CWP_RC_BUFFER_OVERFLOW -2 -#define CWP_RC_BUFFER_UNDERFLOW -3 -#define CWP_RC_MALFORMED_INPUT -4 -#define CWP_RC_WRONG_BYTE_ORDER -5 -#define CWP_RC_ERROR_IN_HANDLER -6 -#define CWP_RC_ILLEGAL_CALL -7 -#define CWP_RC_MALLOC_ERROR -8 -#define CWP_RC_STOPPED -9 +#define CWP_RC_OK 0 +#define CWP_RC_END_OF_INPUT -1 +#define CWP_RC_BUFFER_OVERFLOW -2 +#define CWP_RC_BUFFER_UNDERFLOW -3 +#define CWP_RC_MALFORMED_INPUT -4 +#define CWP_RC_WRONG_BYTE_ORDER -5 +#define CWP_RC_ERROR_IN_HANDLER -6 +#define CWP_RC_ILLEGAL_CALL -7 +#define CWP_RC_MALLOC_ERROR -8 +#define CWP_RC_STOPPED -9 +#define CWP_RC_TYPE_ERROR -10 +#define CWP_RC_VALUE_ERROR -11 +#define CWP_RC_WRONG_TIMESTAMP_LENGTH -12 @@ -50,20 +54,24 @@ struct cw_pack_context; typedef int (*pack_overflow_handler)(struct cw_pack_context*, unsigned long); +typedef int (*pack_flush_handler)(struct cw_pack_context*); typedef struct cw_pack_context { - uint8_t* start; uint8_t* current; + uint8_t* start; uint8_t* end; bool be_compatible; int return_code; int err_no; /* handlers can save error here */ pack_overflow_handler handle_pack_overflow; + pack_flush_handler handle_flush; } cw_pack_context; int cw_pack_context_init (cw_pack_context* pack_context, void* data, unsigned long length, pack_overflow_handler hpo); void cw_pack_set_compatibility (cw_pack_context* pack_context, bool be_compatible); +void cw_pack_set_flush_handler (cw_pack_context* pack_context, pack_flush_handler handle_flush); +void cw_pack_flush (cw_pack_context* pack_context); void cw_pack_nil (cw_pack_context* pack_context); void cw_pack_true (cw_pack_context* pack_context); @@ -75,13 +83,14 @@ void cw_pack_unsigned (cw_pack_context* pack_context, uint64_t i); void cw_pack_float (cw_pack_context* pack_context, float f); void cw_pack_double (cw_pack_context* pack_context, double d); -void cw_pack_real (cw_pack_context* pack_context, double d); /* Pack as float if precision isn't destroyed */ +/* void cw_pack_real (cw_pack_context* pack_context, double d); moved to cwpack_utils */ void cw_pack_array_size (cw_pack_context* pack_context, uint32_t n); void cw_pack_map_size (cw_pack_context* pack_context, uint32_t n); void cw_pack_str (cw_pack_context* pack_context, const char* v, uint32_t l); void cw_pack_bin (cw_pack_context* pack_context, const void* v, uint32_t l); void cw_pack_ext (cw_pack_context* pack_context, int8_t type, const void* v, uint32_t l); +void cw_pack_time (cw_pack_context* pack_context, struct timespec* t); void cw_pack_insert (cw_pack_context* pack_context, const void* v, uint32_t l); @@ -92,6 +101,7 @@ void cw_pack_insert (cw_pack_context* pack_context, const void* v, uint32_t l); typedef enum { CWP_ITEM_MIN_RESERVED_EXT = -128, + CWP_ITEM_TIMESTAMP = -1, CWP_ITEM_MAX_RESERVED_EXT = -1, CWP_ITEM_MIN_USER_EXT = 0, CWP_ITEM_MAX_USER_EXT = 127, @@ -135,6 +145,7 @@ typedef struct { cwpack_blob str; cwpack_blob bin; cwpack_blob ext; + struct timespec time; } as; } cwpack_item; @@ -154,7 +165,7 @@ typedef struct cw_unpack_context { -int cw_unpack_context_init (cw_unpack_context* unpack_context, void* data, unsigned long length, unpack_underflow_handler huu); +int cw_unpack_context_init (cw_unpack_context* unpack_context, const void* data, unsigned long length, unpack_underflow_handler huu); void cw_unpack_next (cw_unpack_context* unpack_context); void cw_skip_items (cw_unpack_context* unpack_context, long item_count); diff --git a/src/cwpack_config.h b/src/cwpack_config.h new file mode 100644 index 0000000..7187f28 --- /dev/null +++ b/src/cwpack_config.h @@ -0,0 +1,100 @@ +/* CWPack - cwpack_config.h */ +/* + The MIT License (MIT) + + Copyright (c) 2017 Claes Wihlborg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#ifndef cwpack_config_h +#define cwpack_config_h + + + +/************************* A L I G N M E N T ******************************/ + +/* + * Some processors demand that integer access is to an even memory address. + * In that case define FORCE_ALIGNMENT + */ + +/* #define FORCE_ALIGNMENT */ + +/* + * Some processors demand that 64 bit integer access is aligned. + * In that case define FORCE_ALIGNMENT_64BIT + */ + +/* #define FORCE_ALIGNMENT_64BIT */ + + + +/************************* C S Y S T E M L I B R A R Y ****************/ + +/* + * The packer uses "memcpy" to move blobs. If you dont want to load C system library + * for just that, define FORCE_NO_LIBRARY and CWPack will use an internal "memcpy" + */ + +/* #define FORCE_NO_LIBRARY */ + + + +/************************* B Y T E O R D E R ****************************/ + +/* + * The pack/unpack routines are written in three versions: for big endian, for + * little endian and insensitive to byte order. As you can get some speed gain + * if the byte order is known, we try that when we can certainly detect it. + * Define COMPILE_FOR_BIG_ENDIAN or COMPILE_FOR_LITTLE_ENDIAN if you know. + */ + +#ifndef FORCE_ALIGNMENT +#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) + +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define COMPILE_FOR_BIG_ENDIAN +#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define COMPILE_FOR_LITTLE_ENDIAN +#endif + +#elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN) + +#if __BYTE_ORDER == __BIG_ENDIAN +#define COMPILE_FOR_BIG_ENDIAN +#elif __BYTE_ORDER == __LITTLE_ENDIAN +#define COMPILE_FOR_LITTLE_ENDIAN +#endif + +#elif defined(__BIG_ENDIAN__) +#define COMPILE_FOR_BIG_ENDIAN + +#elif defined(__LITTLE_ENDIAN__) +#define COMPILE_FOR_LITTLE_ENDIAN + +#elif defined(__i386__) || defined(__x86_64__) +#define COMPILE_FOR_LITTLE_ENDIAN + +#endif +#endif + +//#undef COMPILE_FOR_LITTLE_ENDIAN + + + +#endif /* cwpack_config_h */ diff --git a/src/cwpack_defines.h b/src/cwpack_internals.h similarity index 75% rename from src/cwpack_defines.h rename to src/cwpack_internals.h index 391e7fd..92c39ce 100644 --- a/src/cwpack_defines.h +++ b/src/cwpack_internals.h @@ -24,69 +24,17 @@ #ifndef cwpack_defines_h #define cwpack_defines_h +#include "cwpack_config.h" -/************************* A L I G N M E N T ******************************/ - -/* - * Sometime the processor demands that integer access is to an even memory address. - * In that case define FORCE_ALIGNMENT - */ - -/* #define FORCE_ALIGNMENT */ - - -/************************* C S Y S T E M L I B R A R Y ****************/ - -/* - * The packer uses "memcpy" to move blobs. If you dont want to load C system library - * for just that, define FORCE_NO_LIBRARY and CWPack will use an internal "memcpy" - */ - -/* #define FORCE_NO_LIBRARY */ - - - -/************************* B Y T E O R D E R ****************************/ - -/* - * The pack/unpack routines are written in three versions: for big endian, for - * little endian and insensitive to byte order. As you can get some speed gain - * if the byte order is known, we try that when we can certainly detect it. - * Define COMPILE_FOR_BIG_ENDIAN or COMPILE_FOR_LITTLE_ENDIAN if you know. - */ - -#ifndef FORCE_ALIGNMENT -#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) - -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -#define COMPILE_FOR_BIG_ENDIAN -#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -#define COMPILE_FOR_LITTLE_ENDIAN +#ifndef MOST_LIKELY +#if defined(__GNUC__) || defined(__clang__) +#define MOST_LIKELY(a,b) __builtin_expect((a),(b)) +#else +#define MOST_LIKELY(a,b) ((a) == (b)) #endif - -#elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN) - -#if __BYTE_ORDER == __BIG_ENDIAN -#define COMPILE_FOR_BIG_ENDIAN -#elif __BYTE_ORDER == __LITTLE_ENDIAN -#define COMPILE_FOR_LITTLE_ENDIAN #endif -#elif defined(__BIG_ENDIAN__) -#define COMPILE_FOR_BIG_ENDIAN - -#elif defined(__LITTLE_ENDIAN__) -#define COMPILE_FOR_LITTLE_ENDIAN - -#elif defined(__i386__) || defined(__x86_64__) -#define COMPILE_FOR_LITTLE_ENDIAN - -#endif -#endif - -//#undef COMPILE_FOR_LITTLE_ENDIAN - /******************************* P A C K **********************************/ @@ -104,7 +52,11 @@ #define cw_store16(x) *(uint16_t*)p = *(uint16_t*)&x; #define cw_store32(x) *(uint32_t*)p = *(uint32_t*)&x; +#ifndef FORCE_ALIGNMENT_64BIT #define cw_store64(x) *(uint64_t*)p = *(uint64_t*)&x; +#else +#define cw_store64(x) memcpy(p,&x,8); +#endif #else /* Byte order little endian or undetermined */ @@ -120,6 +72,7 @@ (((uint32_t)(x) & 0x0000ff00) << 8) | \ (((uint32_t)(x)) << 24))); \ +#ifndef FORCE_ALIGNMENT_64BIT #define cw_store64(x) \ *(uint64_t*)p = \ ((uint64_t)( \ @@ -130,7 +83,18 @@ (((uint64_t)(x) & 0x000000ff00000000ULL) >> 8) | \ (((uint64_t)(x) & 0x00000000ff000000ULL) << 8) | \ (((uint64_t)(x)) >> 56) | \ - (((uint64_t)(x)) << 56))); \ + (((uint64_t)(x)) << 56))); +#else +#define cw_store64(z) \ + *p = (uint8_t)(z >> 56); \ + p[1] = (uint8_t)(z >> 48); \ + p[2] = (uint8_t)(z >> 40); \ + p[3] = (uint8_t)(z >> 32); \ + p[4] = (uint8_t)(z >> 24); \ + p[5] = (uint8_t)(z >> 16); \ + p[6] = (uint8_t)(z >> 8); \ + p[7] = (uint8_t)z; +#endif #else /* Byte order undetermined */ @@ -158,17 +122,23 @@ +#define cw_pack_new_buffer(more) \ +{ \ + if (!pack_context->handle_pack_overflow) \ + PACK_ERROR(CWP_RC_BUFFER_OVERFLOW) \ + int rc = pack_context->handle_pack_overflow (pack_context, (unsigned long)(more)); \ + if (rc) \ + PACK_ERROR(rc) \ +} + + #define cw_pack_reserve_space(more) \ { \ p = pack_context->current; \ uint8_t* nyp = p + more; \ if (nyp > pack_context->end) \ { \ - if (!pack_context->handle_pack_overflow) \ - PACK_ERROR(CWP_RC_BUFFER_OVERFLOW) \ - int rc = pack_context->handle_pack_overflow (pack_context, (unsigned long)(more)); \ - if (rc) \ - PACK_ERROR(rc) \ + cw_pack_new_buffer(more) \ p = pack_context->current; \ nyp = p + more; \ } \ @@ -178,9 +148,9 @@ #define tryMove0(t) \ { \ - uint8_t *p; \ - cw_pack_reserve_space(1) \ - *p = (uint8_t)(t); \ + if (pack_context->current == pack_context->end) \ + cw_pack_new_buffer(1) \ + *pack_context->current++ = (uint8_t)(t); \ return; \ } @@ -240,7 +210,11 @@ #define cw_load16(ptr) tmpu16 = *(uint16_t*)ptr; #define cw_load32(ptr) tmpu32 = *(uint32_t*)ptr; -#define cw_load64(ptr) tmpu64 = *(uint64_t*)ptr; +#ifndef FORCE_ALIGNMENT_64BIT +#define cw_load64(ptr,dest) dest = *(uint64_t*)ptr; +#else +#define cw_store64(x) memcpy(p,&x,8); +#endif #else /* Byte order little endian or undetermined */ @@ -255,9 +229,10 @@ tmpu32 = (tmpu32<<24) | ((tmpu32 & 0xff00)<<8) | \ ((tmpu32 & 0xff0000)>>8) | (tmpu32>>24) -#define cw_load64(ptr) \ +#ifndef FORCE_ALIGNMENT_64BIT +#define cw_load64(ptr,dest) \ tmpu64 = *((uint64_t*)ptr); \ - tmpu64 = ( \ + dest = ( \ (((tmpu64 >> 40) | \ (tmpu64 << 24)) & 0x0000ff000000ff00ULL) | \ (((tmpu64 >> 24) | \ @@ -266,6 +241,17 @@ ((tmpu64 & 0x00000000ff000000ULL) << 8) | \ (tmpu64 >> 56) | \ (tmpu64 << 56) ) +#else +#define cw_load64(ptr,dest) \ + tmpu64 = ((uint64_t)*ptr++) << 56; \ + tmpu64 |= ((uint64_t)*ptr++) << 48; \ + tmpu64 |= ((uint64_t)*ptr++) << 40; \ + tmpu64 |= ((uint64_t)*ptr++) << 32; \ + tmpu64 |= ((uint64_t)*ptr++) << 24; \ + tmpu64 |= ((uint64_t)*ptr++) << 16; \ + tmpu64 |= ((uint64_t)*ptr++) << 8; \ + dest = tmpu64 | (uint64_t)*ptr++; +#endif #else /* Byte order undetermined */ @@ -279,7 +265,7 @@ tmpu32 |= (uint32_t)(*ptr++ << 8); \ tmpu32 |= (uint32_t)(*ptr++) -#define cw_load64(ptr) \ +#define cw_load64(ptr,dest) \ tmpu64 = ((uint64_t)*ptr++) << 56; \ tmpu64 |= ((uint64_t)*ptr++) << 48; \ tmpu64 |= ((uint64_t)*ptr++) << 40; \ @@ -287,7 +273,7 @@ tmpu64 |= ((uint64_t)*ptr++) << 24; \ tmpu64 |= ((uint64_t)*ptr++) << 16; \ tmpu64 |= ((uint64_t)*ptr++) << 8; \ - tmpu64 |= (uint64_t)*ptr++ + dest = tmpu64 | (uint64_t)*ptr++; #endif #endif @@ -347,15 +333,32 @@ #define getDDItem8(typ) \ unpack_context->item.type = typ; \ cw_unpack_assert_space(8); \ - cw_load64(p); \ - unpack_context->item.as.u64 = tmpu64; + cw_load64(p,unpack_context->item.as.u64); #define getDDItemFix(len) \ - cw_unpack_assert_space(1); \ - unpack_context->item.type = *(int8_t*)p; \ + cw_unpack_assert_space(len+1); \ + unpack_context->item.type = *(int8_t*)p++; \ + if (unpack_context->item.type == CWP_ITEM_TIMESTAMP) \ + { \ + if (len == 4) \ + { \ + cw_load32(p); \ + unpack_context->item.as.time.tv_sec = (long)tmpu32; \ + unpack_context->item.as.time.tv_nsec = 0; \ + return; \ + } \ + if (len == 8) \ + { \ + cw_load64(p,tmpu64); \ + unpack_context->item.as.time.tv_sec = tmpu64 & 0x00000003ffffffffL; \ + unpack_context->item.as.time.tv_nsec = tmpu64 >> 34; \ + return; \ + } \ + UNPACK_ERROR(CWP_RC_WRONG_TIMESTAMP_LENGTH) \ + } \ unpack_context->item.as.ext.length = len; \ - cw_unpack_assert_blob(ext); - + unpack_context->item.as.ext.start = p; \ + return; diff --git a/test/README.md b/test/README.md index a555414..67992c5 100755 --- a/test/README.md +++ b/test/README.md @@ -1,4 +1,4 @@ -#CWPack - Test +# CWPack / Test The folder has two tests. - A module test to check that the packer/unpacker behaves as expected. @@ -8,8 +8,8 @@ The folder has two tests. 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. -## The speed test +## The performance test -The speed 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. +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. -The speed test checks the duration of a number of calls by calling them 1.000.000 times. \ No newline at end of file +The performance test checks the duration of a number of calls by calling them 1.000.000 times. diff --git a/test/cwpack_module_test.c b/test/cwpack_module_test.c index 95ebf2e..9d260f0 100644 --- a/test/cwpack_module_test.c +++ b/test/cwpack_module_test.c @@ -1,4 +1,4 @@ -/* CWPack Module test - main.c */ +/* CWPack/test cwpack_module_test.c */ /* The MIT License (MIT) @@ -28,7 +28,8 @@ #include #include "cwpack.h" -#include "cwpack_defines.h" +#include "cwpack_config.h" +#include "cwpack_utils.h" cw_pack_context pack_ctx; @@ -251,8 +252,10 @@ int main(int argc, const char * argv[]) TESTP(double,f1,"cb40091eb860000000"); TESTP(double,3.14,"cb40091eb851eb851f"); TESTP(double,37.25,"cb4042a00000000000"); - TESTP(real,37.25,"ca42150000"); - TESTP(real,3.14,"cb40091eb851eb851f"); + TESTP(double_opt,37.25,"ca42150000"); + TESTP(double_opt,f1,"ca4048f5c3"); + TESTP(double_opt,3.14,"cb40091eb851eb851f"); + TESTP(double_opt,-32,"e0"); // TESTP array TESTP(array_size,0,"90"); @@ -331,7 +334,7 @@ int main(int argc, const char * argv[]) #define TESTUP_VAL(buffer,etype,var,val) \ TESTUP(buffer,etype); \ - if (unpack_ctx.item.as.var != val) \ + if (unpack_ctx.item.as.var != val) \ ERROR("In unpack, value error"); unsigned long blob_length = 0; diff --git a/test/cwpack_performance_test.c b/test/cwpack_performance_test.c index 0a6ac4e..edc1220 100644 --- a/test/cwpack_performance_test.c +++ b/test/cwpack_performance_test.c @@ -1,16 +1,31 @@ -// -// main.m -// st -// -// Created by Claes Wihlborg on 2017-01-20. -// Copyright © 2017 Claes Wihlborg. All rights reserved. -// +/* CWPack/test cwpack_performance_test.c */ +/* + The MIT License (MIT) + + Copyright (c) 2017 Claes Wihlborg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + #include #include #include "cwpack.h" -#include "cwpack_defines.h" #include "cmp.h" #include "mpack.h" #include "basic_contexts.h" diff --git a/test/runModuleTest.sh b/test/runModuleTest.sh index b8a54b9..aa48e59 100755 --- a/test/runModuleTest.sh +++ b/test/runModuleTest.sh @@ -1,3 +1,3 @@ -clang -O3 -I ../src/ -o cwpackModuleTest cwpack_module_test.c ../src/cwpack.c +clang -O3 -I ../src/ -I ../goodies/utils/ -o cwpackModuleTest cwpack_module_test.c ../src/cwpack.c ../goodies/utils/cwpack_utils.c ./cwpackModuleTest rm -f *.o cwpackModuleTest From abef70eaa8b6221b5949c5a2e1ff9403d0dacbd6 Mon Sep 17 00:00:00 2001 From: clwi Date: Mon, 25 May 2020 00:16:32 +0200 Subject: [PATCH 02/10] 1.2.1 --- goodies/objC/cwpack_objc.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/goodies/objC/cwpack_objc.m b/goodies/objC/cwpack_objc.m index 2cf6f38..782ced9 100755 --- a/goodies/objC/cwpack_objc.m +++ b/goodies/objC/cwpack_objc.m @@ -43,10 +43,10 @@ + (instancetype) unpackFrom:(cw_unpack_context*) buff if (![[result class] isSubclassOfClass:self]) { - if ([[result class] isSubclassOfClass:NSArray] && [self isSubclassOfClass:NSSet]) + if ([[result class] isSubclassOfClass:[NSArray class]] && [self isSubclassOfClass:[NSSet class]]) return [self setWithArray:result]; - if ([[result class] isSubclassOfClass:NSNull]) + if ([[result class] isSubclassOfClass:[NSNull class]]) return nil; else From d60634bf5667df0e59684341ae49dac560fc6e26 Mon Sep 17 00:00:00 2001 From: clwi Date: Tue, 18 Aug 2020 00:12:59 +0200 Subject: [PATCH 03/10] Fix bugs in TIMESTAMP --- goodies/objC/cwpack_objc.m | 9 +++--- goodies/utils/cwpack_utils.c | 10 +++---- goodies/utils/cwpack_utils.h | 4 ++- src/cwpack.c | 57 +++++++++++++++++++----------------- src/cwpack.h | 10 +++++-- src/cwpack_internals.h | 2 +- test/cwpack_module_test.c | 22 ++++++++++++-- 7 files changed, 71 insertions(+), 43 deletions(-) diff --git a/goodies/objC/cwpack_objc.m b/goodies/objC/cwpack_objc.m index 782ced9..11773eb 100755 --- a/goodies/objC/cwpack_objc.m +++ b/goodies/objC/cwpack_objc.m @@ -37,6 +37,9 @@ - (void) packIn:(cw_pack_context*) buff } ++ (instancetype) setWithArray:(NSArray*)array {return nil;} + + + (instancetype) unpackFrom:(cw_unpack_context*) buff { id result = cwObjectFromBuffer(buff); @@ -186,12 +189,8 @@ @implementation NSDate (cwPack) - (void) packIn:(cw_pack_context*) buff { - struct timespec t; - NSTimeInterval ti = self.timeIntervalSince1970; - t.tv_sec = floor(ti); - t.tv_nsec = floor((ti - t.tv_sec)*1000000000); - cw_pack_time(buff, &t); + cw_pack_time_interval (buff, ti); } @end diff --git a/goodies/utils/cwpack_utils.c b/goodies/utils/cwpack_utils.c index bfdaaa9..7d082b5 100755 --- a/goodies/utils/cwpack_utils.c +++ b/goodies/utils/cwpack_utils.c @@ -21,6 +21,7 @@ */ +#include #include "cwpack_utils.h" @@ -56,10 +57,9 @@ void cw_pack_float_opt (cw_pack_context* pack_context, float f) void cw_pack_time_interval (cw_pack_context* pack_context, double ti) { - struct timespec ts; - ts.tv_sec = (long)ti; - ts.tv_nsec = (long)((ti - (double)ts.tv_sec) * 1000000000.0); - cw_pack_time(pack_context, &ts); + int64_t sec = (int64_t)floor(ti); + uint32_t nsec = (uint32_t)((ti - (double)sec) * 1000000000.0); + cw_pack_time(pack_context, sec, nsec); } /******************************* U N P A C K ******************************/ @@ -337,7 +337,7 @@ unsigned int cw_unpack_next_str_lengh (cw_unpack_context* unpack_context) return unpack_context->item.as.str.length; unpack_context->return_code = CWP_RC_TYPE_ERROR; - return NaN; + return 0; } diff --git a/goodies/utils/cwpack_utils.h b/goodies/utils/cwpack_utils.h index abb6fc4..09450c2 100644 --- a/goodies/utils/cwpack_utils.h +++ b/goodies/utils/cwpack_utils.h @@ -34,7 +34,9 @@ void cw_pack_float_opt (cw_pack_context* pack_context, float f); /* Pack as s void cw_pack_double_opt (cw_pack_context* pack_context, double d); /* Pack as signed or float if precision isn't destroyed */ #define cw_pack_real cw_pack_double_opt /* Backward compatibility */ -void cw_pack_time_interval (cw_pack_context* pack_context, double ti); +#define cw_pack_timespec (pack_contextptr, timespecptr) cw_pack_time ((pack_contextptr), (int64_t)((timespecptr)->tv_sec), (uint32_t)((timespecptr)->tv_nsec)) + +void cw_pack_time_interval (cw_pack_context* pack_context, double ti); /* ti is seconds relative epoch */ /***************************** U N P A C K ********************************/ diff --git a/src/cwpack.c b/src/cwpack.c index 20dd064..6fb2710 100644 --- a/src/cwpack.c +++ b/src/cwpack.c @@ -380,19 +380,40 @@ void cw_pack_ext (cw_pack_context* pack_context, int8_t type, const void* v, uin } -void cw_pack_time (cw_pack_context* pack_context, struct timespec* t) +void cw_pack_time (cw_pack_context* pack_context, int64_t sec, uint32_t nsec) { if (pack_context->return_code) return; - + if (pack_context->be_compatible) PACK_ERROR(CWP_RC_ILLEGAL_CALL); + if (nsec >= 1000000000) + PACK_ERROR(CWP_RC_VALUE_ERROR); + uint8_t *p; - - if ((t->tv_sec >> 34) == 0) { - uint64_t data64 = (uint64_t)((t->tv_nsec << 34) | t->tv_sec); - if ((data64 & 0xffffffff00000000L) == 0) { + + if ((uint64_t)sec & 0xfffffffc00000000L) { + // timestamp 96 + //serialize(0xc7, 12, -1, nsec, sec) + cw_pack_reserve_space(15); + *p++ = (uint8_t)0xc7; + *p++ = (uint8_t)12; + *p++ = (uint8_t)0xff; + cw_store32(nsec); p += 4; + cw_store64(sec); + } + else { + uint64_t data64 = (((uint64_t)nsec << 34) | (uint64_t)sec); + if (data64 & 0xffffffff00000000L) { + // timestamp 64 + //serialize(0xd7, -1, data64) + cw_pack_reserve_space(10); + *p++ = (uint8_t)0xd7; + *p++ = (uint8_t)0xff; + cw_store64(data64); + } + else { // timestamp 32 uint32_t data32 = (uint32_t)data64; //serialize(0xd6, -1, data32) @@ -401,24 +422,6 @@ void cw_pack_time (cw_pack_context* pack_context, struct timespec* t) *p++ = (uint8_t)0xff; cw_store32(data32); } - else { - // timestamp 64 - //serialize(0xd7, -1, data64) - cw_pack_reserve_space(10); - *p++ = (uint8_t)0xd7; - *p++ = (uint8_t)0xff; - cw_store64(data64); - } - } - else { - // timestamp 96 - //serialize(0xc7, 12, -1, t->tv_nsec, t->tv_sec) - cw_pack_reserve_space(3+12); - *p++ = (uint8_t)0xc7; - *p++ = (uint8_t)12; - *p++ = (uint8_t)0xff; - cw_store32(t->tv_nsec); - cw_store64(t->tv_sec); } } @@ -523,9 +526,10 @@ void cw_unpack_next (cw_unpack_context* unpack_context) { cw_unpack_assert_space(4); cw_load32(p); - unpack_context->item.as.time.tv_nsec = (long)tmpu32; + unpack_context->item.as.time.tv_nsec = tmpu32; cw_unpack_assert_space(8); - cw_load64(p,unpack_context->item.as.time.tv_sec); + cw_load64(p,tmpu64); + unpack_context->item.as.time.tv_sec = (int64_t)tmpu64; return; } UNPACK_ERROR(CWP_RC_WRONG_TIMESTAMP_LENGTH) @@ -731,7 +735,6 @@ void cw_skip_items (cw_unpack_context* unpack_context, long item_count) UNPACK_ERROR(CWP_RC_MALFORMED_INPUT) } } - return; } /* end cwpack.c */ diff --git a/src/cwpack.h b/src/cwpack.h index 3e06ff6..c347ab9 100644 --- a/src/cwpack.h +++ b/src/cwpack.h @@ -90,7 +90,7 @@ void cw_pack_map_size (cw_pack_context* pack_context, uint32_t n); void cw_pack_str (cw_pack_context* pack_context, const char* v, uint32_t l); void cw_pack_bin (cw_pack_context* pack_context, const void* v, uint32_t l); void cw_pack_ext (cw_pack_context* pack_context, int8_t type, const void* v, uint32_t l); -void cw_pack_time (cw_pack_context* pack_context, struct timespec* t); +void cw_pack_time (cw_pack_context* pack_context, int64_t sec, uint32_t nsec); void cw_pack_insert (cw_pack_context* pack_context, const void* v, uint32_t l); @@ -131,6 +131,12 @@ typedef struct { } cwpack_container; +typedef struct { + int64_t tv_sec; + uint32_t tv_nsec; +} cwpack_timespec; + + typedef struct { cwpack_item_types type; union @@ -145,7 +151,7 @@ typedef struct { cwpack_blob str; cwpack_blob bin; cwpack_blob ext; - struct timespec time; + cwpack_timespec time; } as; } cwpack_item; diff --git a/src/cwpack_internals.h b/src/cwpack_internals.h index 92c39ce..b03b3f1 100644 --- a/src/cwpack_internals.h +++ b/src/cwpack_internals.h @@ -213,7 +213,7 @@ #ifndef FORCE_ALIGNMENT_64BIT #define cw_load64(ptr,dest) dest = *(uint64_t*)ptr; #else -#define cw_store64(x) memcpy(p,&x,8); +#define cw_load64(ptr,dest) memcpy(&dest,ptr,8); #endif #else /* Byte order little endian or undetermined */ diff --git a/test/cwpack_module_test.c b/test/cwpack_module_test.c index 9d260f0..d2889ec 100644 --- a/test/cwpack_module_test.c +++ b/test/cwpack_module_test.c @@ -230,6 +230,7 @@ int main(int argc, const char * argv[]) TESTP(unsigned,256,"cd0100"); TESTP(unsigned,65535,"cdffff"); TESTP(unsigned,65536,"ce00010000"); + TESTP(unsigned,500000000,"ce1dcd6500"); TESTP(unsigned,0xffffffffUL,"ceffffffff"); TESTP(unsigned,0x100000000ULL,"cf0000000100000000"); TESTP(unsigned,0xffffffffffffffffULL,"cfffffffffffffffff"); @@ -314,7 +315,17 @@ int main(int argc, const char * argv[]) TESTP_EXT(ext,21,65535,"c8ffff15"); TESTP_EXT(ext,21,65536,"c90001000015"); - + pack_ctx.current = outbuffer; + cw_pack_time(&pack_ctx, 1, 0); + check_pack_result("d6ff00000001", 0); + pack_ctx.current = outbuffer; + cw_pack_time(&pack_ctx, 1, 2); + check_pack_result("d7ff0000000800000001", 0); + pack_ctx.current = outbuffer; + cw_pack_time(&pack_ctx, -1, 500000000); + check_pack_result("c70cff1dcd6500ffffffffffffffff", 0); + + TESTP(time_interval,-0.5,"c70cff1dcd6500ffffffffffffffff"); //******************* TEST cwpack unpack ********************** @@ -390,7 +401,14 @@ int main(int argc, const char * argv[]) TESTUP_VAL("deffff",MAP,map.size,65535) TESTUP_VAL("df00010000",MAP,map.size,65536) - + // TESTUP timeStamp + TESTUP_VAL("d6ff00000001",TIMESTAMP,time.tv_sec,1); + TESTUP_VAL("d6ff00000001",TIMESTAMP,time.tv_nsec,0); + TESTUP_VAL("d7ff0000000800000001",TIMESTAMP,time.tv_sec,1); + TESTUP_VAL("d7ff0000000800000001",TIMESTAMP,time.tv_nsec,2); + TESTUP_VAL("c70cff1dcd6500ffffffffffffffff",TIMESTAMP,time.tv_sec,-1); + TESTUP_VAL("c70cff1dcd6500ffffffffffffffff",TIMESTAMP,time.tv_nsec,500000000); + #define TESTUP_AREA(buffer,etype,blob,len) \ blob_length = len; \ TESTUP_VAL(buffer,etype,blob.length,len) \ From 395f8246abf3bc685946d7bc4d1c414ae2031c53 Mon Sep 17 00:00:00 2001 From: clwi Date: Sat, 26 Sep 2020 01:17:38 +0200 Subject: [PATCH 04/10] Performance test updated to handle CMP v19 --- test/README.md | 2 ++ test/cwpack_performance_test.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/test/README.md b/test/README.md index 67992c5..1f795e7 100755 --- a/test/README.md +++ b/test/README.md @@ -12,4 +12,6 @@ The shell script `runModuleTest.sh` runs the module test. The test checks that i 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. +The performance test is targeted to CMP v19 and MPack v1.0. + The performance test checks the duration of a number of calls by calling them 1.000.000 times. diff --git a/test/cwpack_performance_test.c b/test/cwpack_performance_test.c index edc1220..e373bf5 100644 --- a/test/cwpack_performance_test.c +++ b/test/cwpack_performance_test.c @@ -40,7 +40,7 @@ static double milliseconds(void) { #define BEFORE_PTEST(code) \ cw_pack_context_init(&pc, buffer, BUF_Length, 0);\ - cmp_init(&cc, buffer, 0, b_writer);\ + cmp_init(&cc, buffer, 0, 0, b_writer);\ mpack_writer_init(&mw, buffer, BUF_Length); \ code; \ itemSize = (int)(pc.current - pc.start); \ @@ -171,7 +171,7 @@ static void pack_test(void) unsigned int l = (unsigned int)(pc.current - pc.start); \ cw_unpack_context_init (&uc, buffer, l, 0); \ mpack_reader_init_data (&mr, buffer, l); \ - cmp_init(&cc, buffer, b_reader, 0);\ + cmp_init(&cc, buffer, b_reader, 0, 0);\ printf("Buffer filled with: %-35s\n", #code); \ } From 9451b75964b302fda61d87664629ac5c9b8e1374 Mon Sep 17 00:00:00 2001 From: Andreas Schik Date: Fri, 8 Jan 2021 12:59:01 +0100 Subject: [PATCH 05/10] Fix storage of multi-byte integers on big endian machines. --- src/cwpack_internals.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cwpack_internals.h b/src/cwpack_internals.h index b03b3f1..6bba04d 100644 --- a/src/cwpack_internals.h +++ b/src/cwpack_internals.h @@ -50,10 +50,10 @@ #ifdef COMPILE_FOR_BIG_ENDIAN -#define cw_store16(x) *(uint16_t*)p = *(uint16_t*)&x; -#define cw_store32(x) *(uint32_t*)p = *(uint32_t*)&x; +#define cw_store16(x) *(uint16_t*)p = (uint16_t)x; +#define cw_store32(x) *(uint32_t*)p = (uint32_t)x; #ifndef FORCE_ALIGNMENT_64BIT -#define cw_store64(x) *(uint64_t*)p = *(uint64_t*)&x; +#define cw_store64(x) *(uint64_t*)p = (uint64_t)x; #else #define cw_store64(x) memcpy(p,&x,8); #endif From cebee43e9d689f0020423a0baa35daa61ac2f859 Mon Sep 17 00:00:00 2001 From: Mike Date: Wed, 10 Feb 2021 19:25:08 +0100 Subject: [PATCH 06/10] trim trailing whitespace (#12) * cosmetic: trim trailing whitespace * cosmetic: trim trailing whitespace * cosmetic: trim trailing whitespace --- README.md | 8 +- example/README.md | 2 +- example/item.c | 76 +++++------ example/item.h | 46 +++---- example/json2cwpack2json.c | 18 +-- goodies/basic-contexts/basic_contexts.c | 52 ++++---- goodies/basic-contexts/basic_contexts.h | 8 +- goodies/dump/README.md | 16 +-- goodies/dump/cwpack_dump.c | 36 ++--- .../numeric-extensions/numeric_extensions.c | 32 ++--- .../numeric-extensions/numeric_extensions.h | 10 +- .../numeric_extensions_test.c | 52 ++++---- goodies/objC/README.md | 2 +- goodies/objC/cwpack_objc.h | 8 +- goodies/objC/cwpack_objc.m | 34 ++--- goodies/utils/README.md | 2 +- goodies/utils/cwpack_utils.c | 52 ++++---- goodies/utils/cwpack_utils.h | 8 +- src/README.md | 4 +- src/cwpack.c | 82 ++++++------ src/cwpack.h | 8 +- src/cwpack_config.h | 10 +- src/cwpack_internals.h | 8 +- test/cwpack_module_test.c | 126 +++++++++--------- test/cwpack_performance_test.c | 40 +++--- 25 files changed, 370 insertions(+), 370 deletions(-) diff --git a/README.md b/README.md index 5f2c372..60e1693 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # CWPack -CWPack is a lightweight and yet complete implementation of the -[MessagePack](http://msgpack.org) serialization format +CWPack is a lightweight and yet complete implementation of the +[MessagePack](http://msgpack.org) serialization format [version 5](https://github.com/msgpack/msgpack/blob/master/spec.md). It also supports the Timestamp extension type. @@ -14,7 +14,7 @@ Together with [MPack](https://github.com/ludocode/mpack), CWPack is the fastest CWPack does no memory allocations and no file handling in its basic setup. All that is done outside of CWPack. Example extensions are included. -CWPack is working against memory buffers. User defined handlers are called when buffers are filled up (packing) or needs refill (unpack). +CWPack is working against memory buffers. User defined handlers are called when buffers are filled up (packing) or needs refill (unpack). 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. @@ -49,7 +49,7 @@ void example (void) if (cw_unpack_next_str_lengh(&uc) != 6) ERROR; if (strncmp("schema", uc.item.as.str.start, 6)) ERROR; if (cw_unpack_next_signed32(&uc) != 0) ERROR; - + if (uc.return_code != CWP_RC_OK) ERROR; cw_unpack_next(&uc); if (uc.return_code != CWP_RC_END_OF_INPUT) ERROR; diff --git a/example/README.md b/example/README.md index 0f5d9ea..5556a27 100755 --- a/example/README.md +++ b/example/README.md @@ -4,7 +4,7 @@ The example contains a program that takes a json file and converts it to a messa In the script runExample.sh the 2 json files are also diffed. -The files `item.*` contains a memory tree representation of json data and the conversion routines: +The files `item.*` contains a memory tree representation of json data and the conversion routines: - Item Tree To Json File - Item Tree To MessagePack File diff --git a/example/item.c b/example/item.c index 732084a..d49ccba 100644 --- a/example/item.c +++ b/example/item.c @@ -1,18 +1,18 @@ /* CWPack/example - item.c */ /* The MIT License (MIT) - + Copyright (c) 2017 Claes Wihlborg - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, @@ -44,7 +44,7 @@ void freeItem3 (item_root* root) { freeItem3(ic->items[i]); } - + default: free(root); } @@ -62,7 +62,7 @@ static void item32jsonFile (FILE* file, item_root* item) char c; unsigned u, ti; static unsigned tabs = 0; - + #define NEW_LINE {fprintf (file, "\n"); for (ti=0; tiitem_type) @@ -83,7 +83,7 @@ static void item32jsonFile (FILE* file, item_root* item) NEW_LINE fprintf (file, "}"); break; - + case ITEM_ARRAY: jc = (item_container*)item; fprintf (file, "["); @@ -98,23 +98,23 @@ static void item32jsonFile (FILE* file, item_root* item) NEW_LINE fprintf(file, "]"); break; - + case ITEM_NIL: fprintf (file, "null"); break; - + case ITEM_TRUE: fprintf (file, "true"); break; - + case ITEM_FALSE: fprintf (file, "false"); break; - + case ITEM_INTEGER: fprintf (file, "%lld", ((item_integer*)item)->value); break; - + case ITEM_REAL: sprintf (tmp, "%-25.15g", ((item_real*)item)->value); for (i=0;i<30;i++) @@ -129,7 +129,7 @@ static void item32jsonFile (FILE* file, item_root* item) } fprintf (file, "%s", tmp); break; - + case ITEM_STRING: fprintf (file, "\""); cp = ((item_string*)item)->string; @@ -161,7 +161,7 @@ static void item32jsonFile (FILE* file, item_root* item) case 0x0a: fprintf (file, "\\n"); break; /* LF */ case 0x0c: fprintf (file, "\\f"); break; /* FF */ case 0x0d: fprintf (file, "\\r"); break; /* CR */ - + default: fprintf (file, "%c", c); break; @@ -169,7 +169,7 @@ static void item32jsonFile (FILE* file, item_root* item) } fprintf (file, "\""); break; - + default: break; } } @@ -299,7 +299,7 @@ static item_root* jsonString2item3 (const char** ptr) { scanSpace; item_root* result = NULL; - + char c = *(*ptr)++; switch (c) { case '{': @@ -309,7 +309,7 @@ static item_root* jsonString2item3 (const char** ptr) else result = (item_root*)pullMapPair (ptr, 0); break; - + case '[': scanSpace; if (**ptr == ']') @@ -317,12 +317,12 @@ static item_root* jsonString2item3 (const char** ptr) else result = (item_root*)pullArray (ptr, 0); break; - + case '"': result = (item_root*)pullString (ptr, 0);break; case 'n': result = allocate_item(item_root,ITEM_NIL,0); *ptr+=3;break; case 't': result = allocate_item(item_root,ITEM_TRUE,0); *ptr+=3;break; case 'f': result = allocate_item(item_root,ITEM_FALSE,0); *ptr+=4;break; - + case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { @@ -355,11 +355,11 @@ static item_root* jsonString2item3 (const char** ptr) } } break; - + default: break; } - + return result; } @@ -369,7 +369,7 @@ item_root* jsonFile2item3 (FILE* file) fseek (file, 0, SEEK_END); long length = ftell(file); char* buffer = malloc (length+1); - + fseek (file, 0l, SEEK_SET); fread (buffer, 1, length, file); buffer[length] = 0; @@ -387,7 +387,7 @@ static void item32packContext(cw_pack_context* pc, item_root* item) int i; item_container* ic; char* cp; - + switch (item->item_type) { case ITEM_MAP: @@ -396,39 +396,39 @@ static void item32packContext(cw_pack_context* pc, item_root* item) for( i=0; i< ic->count; i++) item32packContext (pc, ic->items[i]); break; - + case ITEM_ARRAY: ic = (item_container*)item; cw_pack_array_size(pc, ic->count); for( i=0; i< ic->count; i++) item32packContext (pc, ic->items[i]); break; - + case ITEM_NIL: cw_pack_nil (pc); break; - + case ITEM_TRUE: cw_pack_boolean(pc, true); break; - + case ITEM_FALSE: cw_pack_boolean(pc, false); break; - + case ITEM_INTEGER: cw_pack_signed(pc, ((item_integer*)item)->value); break; - + case ITEM_REAL: cw_pack_double(pc, ((item_real*)item)->value); break; - + case ITEM_STRING: cp = ((item_string*)item)->string; cw_pack_str(pc, cp, (unsigned)strlen(cp)); break; - + default: break; } } @@ -457,7 +457,7 @@ static item_root* packContext2item3 (cw_unpack_context* uc) case CWP_ITEM_NIL: result = allocate_item(item_root,ITEM_NIL,0); break; - + case CWP_ITEM_BOOLEAN: if (uc->item.as.boolean) { @@ -474,23 +474,23 @@ static item_root* packContext2item3 (cw_unpack_context* uc) result = (item_root*)allocate_item(item_integer,ITEM_INTEGER,0); ((item_integer*)result)->value = uc->item.as.i64; break; - + case CWP_ITEM_FLOAT: result = (item_root*)allocate_item(item_real,ITEM_REAL,0); ((item_real*)result)->value = uc->item.as.real; break; - + case CWP_ITEM_DOUBLE: result = (item_root*)allocate_item(item_real,ITEM_REAL,0); ((item_real*)result)->value = uc->item.as.long_real; break; - + case CWP_ITEM_STR: result = (item_root*)allocate_item(item_string,ITEM_STRING,uc->item.as.str.length + 1); strncpy(((item_string*)result)->string, (const char*)uc->item.as.str.start, uc->item.as.str.length); ((item_string*)result)->string[uc->item.as.str.length] = 0; break; - + case CWP_ITEM_MAP: dim = 2 * uc->item.as.map.size; ic = allocate_container(ITEM_MAP, dim); @@ -500,7 +500,7 @@ static item_root* packContext2item3 (cw_unpack_context* uc) } result = (item_root*)ic; break; - + case CWP_ITEM_ARRAY: dim = uc->item.as.array.size; ic = allocate_container(ITEM_ARRAY, dim); @@ -510,7 +510,7 @@ static item_root* packContext2item3 (cw_unpack_context* uc) } result = (item_root*)ic; break; - + default: result = NULL; break; diff --git a/example/item.h b/example/item.h index 03268d7..ecaf7d4 100644 --- a/example/item.h +++ b/example/item.h @@ -1,18 +1,18 @@ /* CWPack/example - item.h */ /* The MIT License (MIT) - + Copyright (c) 2017 Claes Wihlborg - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, @@ -26,9 +26,9 @@ - + /************** ITEMS **********************/ - + typedef enum { ITEM_MAP, ITEM_ARRAY, @@ -39,47 +39,47 @@ ITEM_REAL, ITEM_STRING } item_types; - + typedef struct { item_types item_type; } item_root; - + typedef struct { item_types item_type; int count; /* in maps every association counts for 2 */ item_root* items[]; } item_container; - + typedef struct { item_types item_type; long long value; } item_integer; - + typedef struct { item_types item_type; double value; } item_real; - + typedef struct { item_types item_type; char string[]; } item_string; - - + + void freeItem3 (item_root* root); - - - + + + /************** ITEMS TO/FROM FILE **********************/ - + void item32JsonFile (FILE* file, item_root* item); - + item_root* jsonFile2item3 (FILE* file); - + void item32cwpackFile (FILE* file, item_root* item); - + item_root* cwpackFile2item3 (FILE* file); - - - + + + #endif /* item_h */ diff --git a/example/json2cwpack2json.c b/example/json2cwpack2json.c index c455dcb..d51aaac 100644 --- a/example/json2cwpack2json.c +++ b/example/json2cwpack2json.c @@ -1,18 +1,18 @@ /* CWPack/example - json2cwpack2json.c */ /* The MIT License (MIT) - + Copyright (c) 2017 Claes Wihlborg - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, @@ -37,22 +37,22 @@ int main(int argc, const char * argv[]) } char filename[200]; strcpy(filename, argv[1]); - + FILE* jsonFileIn; FILE* jsonFileOut; FILE* cwpackFileIn; FILE* cwpackFileOut; - + jsonFileIn = fopen (filename, "r"); item_root* root = jsonFile2item3 (jsonFileIn); fclose(jsonFileIn); - + strcat (filename, ".msgpack"); cwpackFileOut = fopen (filename, "w"); item32cwpackFile (cwpackFileOut, root); fclose(cwpackFileOut); freeItem3(root); - + cwpackFileIn = fopen (filename, "r"); root = cwpackFile2item3 (cwpackFileIn); fclose(cwpackFileIn); @@ -62,6 +62,6 @@ int main(int argc, const char * argv[]) item32JsonFile (jsonFileOut, root); fclose(jsonFileOut); freeItem3(root); - + return 0; } diff --git a/goodies/basic-contexts/basic_contexts.c b/goodies/basic-contexts/basic_contexts.c index c026e22..fee818f 100644 --- a/goodies/basic-contexts/basic_contexts.c +++ b/goodies/basic-contexts/basic_contexts.c @@ -1,18 +1,18 @@ /* CWPack/goodies - basic_contexts.c */ /* The MIT License (MIT) - + Copyright (c) 2017 Claes Wihlborg - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, @@ -44,7 +44,7 @@ static int handle_memory_pack_overflow(struct cw_pack_context* pc, unsigned long void *new_buffer = realloc (pc->start, buffer_length); if (!new_buffer) return CWP_RC_BUFFER_OVERFLOW; - + pc->start = (uint8_t*)new_buffer; pc->current = pc->start + contains; pc->end = pc->start + buffer_length; @@ -61,7 +61,7 @@ void init_dynamic_memory_pack_context (dynamic_memory_pack_context* dmpc, unsign dmpc->pc.return_code = CWP_RC_MALLOC_ERROR; return; } - + cw_pack_context_init((cw_pack_context*)dmpc, buffer, buffer_length, &handle_memory_pack_overflow); } @@ -106,11 +106,11 @@ static int handle_stream_pack_overflow(struct cw_pack_context* pc, unsigned long { while (buffer_length < more) buffer_length = 2 * buffer_length; - + void *new_buffer = malloc (buffer_length); if (!new_buffer) return CWP_RC_BUFFER_OVERFLOW; - + free(pc->start); pc->start = (uint8_t*)new_buffer; pc->end = pc->start + buffer_length; @@ -130,7 +130,7 @@ void init_stream_pack_context (stream_pack_context* spc, unsigned long initial_b return; } spc->file = file; - + cw_pack_context_init((cw_pack_context*)spc, buffer, buffer_length, &handle_stream_pack_overflow); cw_pack_set_flush_handler((cw_pack_context*)spc, &flush_stream_pack_context); } @@ -158,16 +158,16 @@ static int handle_stream_unpack_underflow(struct cw_unpack_context* uc, unsigned { memmove (uc->start, uc->current, remains); } - + if (suc->buffer_length < more) { while (suc->buffer_length < more) suc->buffer_length = 2 * suc->buffer_length; - + void *new_buffer = realloc (uc->start, suc->buffer_length); if (!new_buffer) return CWP_RC_BUFFER_UNDERFLOW; - + uc->start = (uint8_t*)new_buffer; } uc->current = uc->start; @@ -180,7 +180,7 @@ static int handle_stream_unpack_underflow(struct cw_unpack_context* uc, unsigned suc->uc.err_no = ferror(suc->file); return CWP_RC_ERROR_IN_HANDLER; } - + uc->end += l; return CWP_RC_OK; @@ -198,7 +198,7 @@ void init_stream_unpack_context (stream_unpack_context* suc, unsigned long initi } suc->file = file; suc->buffer_length = buffer_length; - + cw_unpack_context_init((cw_unpack_context*)suc, buffer, 0, &handle_stream_unpack_underflow); } @@ -239,7 +239,7 @@ static int flush_file_pack_context(struct cw_pack_context* pc) } else fpc->pc.current = fpc->pc.start; - + return CWP_RC_OK; } @@ -249,7 +249,7 @@ static int handle_file_pack_overflow(struct cw_pack_context* pc, unsigned long m int rc = flush_file_pack_context(pc); if (rc != CWP_RC_OK) return rc; - + uint8_t *bStart = fpc->barrier ? fpc->barrier : pc->current; unsigned long kept = (unsigned long)(pc->current - bStart); unsigned long buffer_length = (unsigned long)(pc->end - pc->start); @@ -257,7 +257,7 @@ static int handle_file_pack_overflow(struct cw_pack_context* pc, unsigned long m { while (buffer_length < more + kept) buffer_length = 2 * buffer_length; - + void *new_buffer = malloc (buffer_length); if (!new_buffer) return CWP_RC_BUFFER_OVERFLOW; @@ -271,12 +271,12 @@ static int handle_file_pack_overflow(struct cw_pack_context* pc, unsigned long m { memcpy(pc->start, bStart, kept); } - + if (fpc->barrier) { fpc->barrier = pc->start; } - + pc->current = pc->start + kept; return CWP_RC_OK; } @@ -294,7 +294,7 @@ void init_file_pack_context (file_pack_context* fpc, unsigned long initial_buffe fpc->fileDescriptor = fileDescriptor; fpc->fileDescriptor = fileDescriptor; fpc->barrier = NULL; - + cw_pack_context_init((cw_pack_context*)fpc, buffer, buffer_length, &handle_file_pack_overflow); cw_pack_set_flush_handler((cw_pack_context*)fpc, &flush_file_pack_context); } @@ -317,7 +317,7 @@ void terminate_file_pack_context(file_pack_context* fpc) fpc->barrier = NULL; cw_pack_context* pc = (cw_pack_context*)fpc; cw_pack_flush(pc); - + if (pc->return_code != CWP_RC_MALLOC_ERROR) free(pc->start); } @@ -337,16 +337,16 @@ static int handle_file_unpack_underflow(struct cw_unpack_context* uc, unsigned l { memcpy (uc->start, bStart, remains); } - + if (auc->buffer_length < more + kept) { while (auc->buffer_length < more + kept) auc->buffer_length = 2 * auc->buffer_length; - + void *new_buffer = realloc (uc->start, auc->buffer_length); if (!new_buffer) return CWP_RC_BUFFER_UNDERFLOW; - + uc->start = (uint8_t*)new_buffer; } uc->current = uc->start + kept; @@ -368,7 +368,7 @@ static int handle_file_unpack_underflow(struct cw_unpack_context* uc, unsigned l } uc->end += l; } - + return CWP_RC_OK; } @@ -385,7 +385,7 @@ void init_file_unpack_context (file_unpack_context* fuc, unsigned long initial_b fuc->fileDescriptor = fileDescriptor; fuc->barrier = NULL; fuc->buffer_length = buffer_length; - + cw_unpack_context_init((cw_unpack_context*)fuc, buffer, 0, &handle_file_unpack_underflow); } diff --git a/goodies/basic-contexts/basic_contexts.h b/goodies/basic-contexts/basic_contexts.h index ebb1427..ead648b 100644 --- a/goodies/basic-contexts/basic_contexts.h +++ b/goodies/basic-contexts/basic_contexts.h @@ -1,18 +1,18 @@ /* CWPack/goodies - basic_contexts.h */ /* The MIT License (MIT) - + Copyright (c) 2017 Claes Wihlborg - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, diff --git a/goodies/dump/README.md b/goodies/dump/README.md index cdff3e4..8d781a3 100755 --- a/goodies/dump/README.md +++ b/goodies/dump/README.md @@ -3,22 +3,22 @@ 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. -Syntax: -cwpack_dump [-t 9] [-v] [-h] < msgpackFile > humanReadableFile --t 9 Tab size --v Version --h Help +Syntax: +cwpack_dump [-t 9] [-v] [-h] < msgpackFile > humanReadableFile +-t 9 Tab size +-v Version +-h Help 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. If Tab size isn't given, structures are written on a single line. - + `cwpack_dump < testdump.msgpack` prints: ``` 0 [10000000 3.14 "åäöÅÄÖ"] 1c {"binary": (62696e617279) "extension": (-5,68656c6c6f) "time": '2020-05-20 18:40:00'} - 49 + 49 ``` and `cwpack_dump -t 4 < testdump.msgpack` prints: @@ -33,6 +33,6 @@ and `cwpack_dump -t 4 < testdump.msgpack` prints: 2c "extension": (-5,68656c6c6f) 3e "time": '2020-05-20 18:40:00' 49 } - 49 + 49 ``` diff --git a/goodies/dump/cwpack_dump.c b/goodies/dump/cwpack_dump.c index 4e28fde..045ac90 100755 --- a/goodies/dump/cwpack_dump.c +++ b/goodies/dump/cwpack_dump.c @@ -1,18 +1,18 @@ /* CWPack/goodies - cwpack_dump.c */ /* The MIT License (MIT) - + Copyright (c) 2017 Claes Wihlborg - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, @@ -47,7 +47,7 @@ static void dump_as_hex(const void* area, long length) static void dump_next_item( cw_unpack_context* context, int tabLevel) { - + long long dim =99; int i,ti; double d; @@ -63,32 +63,32 @@ static void dump_next_item( cw_unpack_context* context, int tabLevel) case CWP_ITEM_NIL: printf("null"); break; - + case CWP_ITEM_BOOLEAN: if (context->item.as.boolean) printf("true"); else printf("false"); break; - + case CWP_ITEM_POSITIVE_INTEGER: printf("%llu", context->item.as.u64); break; - + case CWP_ITEM_NEGATIVE_INTEGER: printf("%lld", context->item.as.i64); break; - + case CWP_ITEM_FLOAT: context->item.as.long_real = (double)context->item.as.real; - + case CWP_ITEM_DOUBLE: printf ("%g", context->item.as.long_real); break; - + case CWP_ITEM_STR: { printf("\""); - + for (i=0; i < (int)context->item.as.str.length; i++) { unsigned char c = ((unsigned char*)(context->item.as.str.start))[i]; @@ -113,13 +113,13 @@ static void dump_next_item( cw_unpack_context* context, int tabLevel) printf("\""); break;} - + case CWP_ITEM_BIN: printf("("); dump_as_hex (context->item.as.bin.start, context->item.as.bin.length); printf(")"); break; - + case CWP_ITEM_ARRAY: printf("["); dim = context->item.as.array.size; @@ -133,7 +133,7 @@ static void dump_next_item( cw_unpack_context* context, int tabLevel) if(*tabString) NEW_LINE; printf("]"); break; - + case CWP_ITEM_MAP: printf("{"); dim = context->item.as.map.size; @@ -149,7 +149,7 @@ static void dump_next_item( cw_unpack_context* context, int tabLevel) if(*tabString) NEW_LINE; printf("}"); break; - + case CWP_ITEM_TIMESTAMP: printf("'"); gmtime_r(&context->item.as.time.tv_sec,&tm); @@ -163,7 +163,7 @@ static void dump_next_item( cw_unpack_context* context, int tabLevel) } printf("'"); break; - + default: if (CWP_ITEM_MIN_RESERVED_EXT <= context->item.type && context->item.type <= CWP_ITEM_MAX_USER_EXT) { @@ -215,7 +215,7 @@ int main(int argc, const char * argv[]) file_unpack_context fuc; cw_unpack_context *context = (cw_unpack_context*)&fuc; - + init_file_unpack_context (&fuc, 4096, STDIN_FILENO); file_unpack_context_set_barrier (&fuc); /* keep whole file in memory buffer to simplify offset calculation */ diff --git a/goodies/numeric-extensions/numeric_extensions.c b/goodies/numeric-extensions/numeric_extensions.c index 68c26a4..a6fc7a9 100644 --- a/goodies/numeric-extensions/numeric_extensions.c +++ b/goodies/numeric-extensions/numeric_extensions.c @@ -41,32 +41,32 @@ void cw_pack_ext_integer (cw_pack_context* pack_context, int8_t type, int64_t i) { if (pack_context->return_code) return; - + uint8_t *p; if (i >= 0) { if (i < 128) cw_storeN(3,0xd4,8); - + if (i < 32768) cw_storeN(4,0xd5,16); - + if (i < 0x80000000LL) cw_storeN(6,0xd6,32); - + cw_storeN(10,0xd7,64); } - + if (i >= -128) cw_storeN(3,0xd4,8); - + if (i >= -32768) cw_storeN(4,0xd5,16); - + if (i >= (int64_t)0xffffffff80000000LL) cw_storeN(6,0xd6,32); - + cw_storeN(10,0xd7,64); } @@ -75,13 +75,13 @@ void cw_pack_ext_float (cw_pack_context* pack_context, int8_t type, float f) { if (pack_context->return_code) return; - + uint8_t *p; - + cw_pack_reserve_space(6); *p++ = (uint8_t)0xd6; *p++ = (uint8_t)type; - + uint32_t tmp = *((uint32_t*)&f); cw_store32(tmp); } @@ -91,13 +91,13 @@ void cw_pack_ext_double (cw_pack_context* pack_context, int8_t type, double d) { if (pack_context->return_code) return; - + uint8_t *p; - + cw_pack_reserve_space(10); *p++ = (uint8_t)0xd7; *p++ = (uint8_t)type; - + uint64_t tmp = *((uint64_t*)&d); cw_store64(tmp); } @@ -113,7 +113,7 @@ int64_t get_ext_integer (cw_unpack_context* unpack_context) uint16_t tmpu16; uint32_t tmpu32; uint64_t tmpu64; - + if (unpack_context->item.type > CWP_ITEM_MAX_USER_EXT) { unpack_context->return_code = CWP_RC_TYPE_ERROR; @@ -163,7 +163,7 @@ float get_ext_float (cw_unpack_context* unpack_context) unpack_context->return_code = CWP_RC_VALUE_ERROR; return 0.0; } - + cw_load32(unpack_context->item.as.ext.start); return *(float*)&tmpu32; } diff --git a/goodies/numeric-extensions/numeric_extensions.h b/goodies/numeric-extensions/numeric_extensions.h index a9237a6..6fbd1d5 100644 --- a/goodies/numeric-extensions/numeric_extensions.h +++ b/goodies/numeric-extensions/numeric_extensions.h @@ -30,18 +30,18 @@ #define NUMEXT_ERROR_NOT_EXT CWP_RC_TYPE_ERROR; #define NUMEXT_ERROR_WRONG_LENGTH CWP_RC_VALUE_ERROR; - - - + + + void cw_pack_ext_integer (cw_pack_context* pack_context, int8_t type, int64_t i); void cw_pack_ext_float (cw_pack_context* pack_context, int8_t type, float f); void cw_pack_ext_double (cw_pack_context* pack_context, int8_t type, double d); - + int64_t get_ext_integer (cw_unpack_context* unpack_context); float get_ext_float (cw_unpack_context* unpack_context); double get_ext_double (cw_unpack_context* unpack_context); - + #endif /* numeric_extensions_h */ diff --git a/goodies/numeric-extensions/numeric_extensions_test.c b/goodies/numeric-extensions/numeric_extensions_test.c index 0ca3290..0eb28c0 100644 --- a/goodies/numeric-extensions/numeric_extensions_test.c +++ b/goodies/numeric-extensions/numeric_extensions_test.c @@ -59,7 +59,7 @@ static char char2hex (char c) return c - '0'; if (c <= 'F') return c - 'A' + 10; - + return c - 'a' + 10; } @@ -70,7 +70,7 @@ static void check_pack_result(const char* expected_header, unsigned long data_le unsigned long header_length = strlen(expected_header) / 2; if (pack_ctx.current - outbuffer == (long)(header_length + data_length)) { - + if (header_length*2 == strlen(expected_header)) { unsigned long i; @@ -102,14 +102,14 @@ static void check_pack_result(const char* expected_header, unsigned long data_le hex <<= 4; hex += (uc - 'A' + 10); } - - + + if (*p++ != hex) { ERROR("Different header value"); } } - + if (data_length > 0) { ucp = TEST_area; @@ -133,18 +133,18 @@ int main(int argc, const char * argv[]) { printf("CWPack numeric extensions test started.\n"); error_count = 0; - + bool endian_switch_found = false; #ifdef COMPILE_FOR_BIG_ENDIAN printf("Compiled for big endian.\n\n"); endian_switch_found = true; #endif - + #ifdef COMPILE_FOR_LITTLE_ENDIAN printf("Compiled for little endian.\n\n"); endian_switch_found = true; #endif - + if (!endian_switch_found) { printf("Compiled for all endians.\n"); @@ -154,51 +154,51 @@ int main(int argc, const char * argv[]) case 0x31323334UL: printf("Running on big endian hardware.\n\n"); break; - + case 0x34333231UL: printf("Running on little endian hardware.\n\n"); break; - + default: printf("Running on neither little nor big endian hardware.\n\n"); break; } } - - + + //******************* TEST numeric extensions **************************** - + cw_pack_context_init (&pack_ctx, outbuffer, 70000, 0); if (pack_ctx.return_code == CWP_RC_WRONG_BYTE_ORDER) { ERROR("***** Compiled for wrong byte order, test terminated *****\n\n"); exit(1); } - - - - + + + + #define TESTP_EXT(call,type,value,header) \ pack_ctx.current = outbuffer; \ cw_pack_ext_##call (&pack_ctx, type, value); \ if(pack_ctx.return_code) \ ERROR("In pack"); \ check_pack_result(header, 0) - + // TESTP ext TESTP_EXT(integer,15,1,"d40f01"); TESTP_EXT(integer,15,128,"d50f0080"); TESTP_EXT(integer,15,-32769,"d60fffff7fff"); - + float f1 = (float)3.14; TESTP_EXT(float,15,f1,"d60f4048f5c3"); TESTP_EXT(double,15,f1,"d70f40091eb860000000"); - + int64_t integer_var; float float_var; double double_var; char inputbuf[30]; - + #define TESTUP_EXT(buffer,etype,call,value) \ { \ unsigned long ui; \ @@ -217,30 +217,30 @@ int main(int argc, const char * argv[]) if (call##_var != value) \ ERROR("In unpack, value error"); \ } - + TESTUP_EXT("d40f01",15,integer,1); TESTUP_EXT("d50f0080",15,integer,128); TESTUP_EXT("d60fffff7fff",15,integer,-32769); TESTUP_EXT("d60f4048f5c3",15,float,f1); TESTUP_EXT("d70f40091eb860000000",15,double,(double)f1); //************************************************************* - + printf("CWPack numeric extensions test completed, "); switch (error_count) { case 0: printf("no errors detected\n"); break; - + case 1: printf("1 error detected\n"); break; - + default: printf("%d errors detected\n", error_count); break; } - + return error_count; } diff --git a/goodies/objC/README.md b/goodies/objC/README.md index 214c18f..a2aa1cf 100755 --- a/goodies/objC/README.md +++ b/goodies/objC/README.md @@ -1,7 +1,7 @@ # CWPack / Goodies / ObjC -ObjC contains a wrapper for objective-C in the form of a category to NSObject. +ObjC contains a wrapper for objective-C in the form of a category to NSObject. The category contains two methods: ```C diff --git a/goodies/objC/cwpack_objc.h b/goodies/objC/cwpack_objc.h index 8e8ce0e..8affbcc 100755 --- a/goodies/objC/cwpack_objc.h +++ b/goodies/objC/cwpack_objc.h @@ -1,18 +1,18 @@ /* CWPack/goodies - cwpack_objc.h */ /* The MIT License (MIT) - + Copyright (c) 2017 Claes Wihlborg - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, diff --git a/goodies/objC/cwpack_objc.m b/goodies/objC/cwpack_objc.m index 11773eb..59330d6 100755 --- a/goodies/objC/cwpack_objc.m +++ b/goodies/objC/cwpack_objc.m @@ -1,18 +1,18 @@ /* CWPack/goodies - cwpack_objc.m */ /* The MIT License (MIT) - + Copyright (c) 2017 Claes Wihlborg - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, @@ -43,7 +43,7 @@ + (instancetype) setWithArray:(NSArray*)array {return nil;} + (instancetype) unpackFrom:(cw_unpack_context*) buff { id result = cwObjectFromBuffer(buff); - + if (![[result class] isSubclassOfClass:self]) { if ([[result class] isSubclassOfClass:[NSArray class]] && [self isSubclassOfClass:[NSSet class]]) @@ -205,33 +205,33 @@ id cwObjectFromBuffer (cw_unpack_context* inbuf) cw_unpack_next(inbuf); if (inbuf->return_code) return nil; - + switch (inbuf->item.type) { case CWP_ITEM_NIL: return [NSNull null]; - + case CWP_ITEM_BOOLEAN: return [NSNumber numberWithBool:inbuf->item.as.boolean]; - + case CWP_ITEM_POSITIVE_INTEGER: return [NSNumber numberWithUnsignedLongLong:inbuf->item.as.u64]; - + case CWP_ITEM_NEGATIVE_INTEGER: return [NSNumber numberWithLongLong:inbuf->item.as.i64]; - + case CWP_ITEM_FLOAT: return [[NSNumber alloc] initWithFloat:inbuf->item.as.real]; - + case CWP_ITEM_DOUBLE: return [NSNumber numberWithDouble:inbuf->item.as.long_real]; - + case CWP_ITEM_STR: return [[[NSString alloc] initWithBytes:inbuf->item.as.str.start length:inbuf->item.as.str.length encoding:NSUTF8StringEncoding] autorelease]; - + case CWP_ITEM_BIN: return [NSData dataWithBytes:inbuf->item.as.bin.start length:inbuf->item.as.bin.length]; - + case CWP_ITEM_ARRAY: { int i, dim = inbuf->item.as.array.size; @@ -244,7 +244,7 @@ id cwObjectFromBuffer (cw_unpack_context* inbuf) } return arr; } - + case CWP_ITEM_MAP: { int i, dim = inbuf->item.as.map.size; @@ -258,12 +258,12 @@ id cwObjectFromBuffer (cw_unpack_context* inbuf) } return dict; } - + case CWP_ITEM_TIMESTAMP: { return [NSDate dateWithTimeIntervalSince1970:inbuf->item.as.time.tv_sec + inbuf->item.as.time.tv_nsec / 1000000000.0]; } - + default: return nil; } diff --git a/goodies/utils/README.md b/goodies/utils/README.md index 506055c..8ed6894 100755 --- a/goodies/utils/README.md +++ b/goodies/utils/README.md @@ -3,7 +3,7 @@ Utils contains some convenience routines: -### C string packing +### C string packing ```C void cw_pack_cstr (cw_pack_context* pack_context, const char* v); ``` diff --git a/goodies/utils/cwpack_utils.c b/goodies/utils/cwpack_utils.c index 7d082b5..1748ce9 100755 --- a/goodies/utils/cwpack_utils.c +++ b/goodies/utils/cwpack_utils.c @@ -1,18 +1,18 @@ /* CWPack/goodies - cwpack_utils.c */ /* The MIT License (MIT) - + Copyright (c) 2017 Claes Wihlborg - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, @@ -70,7 +70,7 @@ float cw_unpack_next_float (cw_unpack_context* unpack_context) { cw_unpack_next (unpack_context); if (unpack_context->return_code) return NaN; - + switch (unpack_context->item.type) { case CWP_ITEM_POSITIVE_INTEGER: return unpack_context->item.as.u64; case CWP_ITEM_NEGATIVE_INTEGER: return unpack_context->item.as.i64; @@ -85,7 +85,7 @@ double cw_unpack_next_double (cw_unpack_context* unpack_context) { cw_unpack_next (unpack_context); if (unpack_context->return_code) return NaN; - + switch (unpack_context->item.type) { case CWP_ITEM_POSITIVE_INTEGER: return unpack_context->item.as.u64; case CWP_ITEM_NEGATIVE_INTEGER: return unpack_context->item.as.i64; @@ -101,10 +101,10 @@ bool cw_unpack_next_boolean (cw_unpack_context* unpack_context) cw_unpack_next (unpack_context); if (unpack_context->return_code) return false; - + if (unpack_context->item.type == CWP_ITEM_BOOLEAN) return unpack_context->item.as.boolean; - + unpack_context->return_code = CWP_RC_TYPE_ERROR; return false; } @@ -115,7 +115,7 @@ int64_t cw_unpack_next_signed64 (cw_unpack_context* unpack_context) cw_unpack_next (unpack_context); if (unpack_context->return_code) return 0; - + if (unpack_context->item.type == CWP_ITEM_POSITIVE_INTEGER) { if (unpack_context->item.as.u64 <= INT64_MAX) @@ -126,10 +126,10 @@ int64_t cw_unpack_next_signed64 (cw_unpack_context* unpack_context) return 0; } } - + if (unpack_context->item.type == CWP_ITEM_NEGATIVE_INTEGER) return unpack_context->item.as.i64; - + unpack_context->return_code = CWP_RC_TYPE_ERROR; return 0; } @@ -140,7 +140,7 @@ int32_t cw_unpack_next_signed32 (cw_unpack_context* unpack_context) cw_unpack_next (unpack_context); if (unpack_context->return_code) return 0; - + if (unpack_context->item.type == CWP_ITEM_POSITIVE_INTEGER) { if (unpack_context->item.as.u64 <= INT32_MAX) @@ -161,7 +161,7 @@ int32_t cw_unpack_next_signed32 (cw_unpack_context* unpack_context) return 0; } } - + unpack_context->return_code = CWP_RC_TYPE_ERROR; return 0; } @@ -172,7 +172,7 @@ int16_t cw_unpack_next_signed16 (cw_unpack_context* unpack_context) cw_unpack_next (unpack_context); if (unpack_context->return_code) return 0; - + if (unpack_context->item.type == CWP_ITEM_POSITIVE_INTEGER) { if (unpack_context->item.as.u64 <= INT16_MAX) @@ -193,7 +193,7 @@ int16_t cw_unpack_next_signed16 (cw_unpack_context* unpack_context) return 0; } } - + unpack_context->return_code = CWP_RC_TYPE_ERROR; return 0; } @@ -204,7 +204,7 @@ int8_t cw_unpack_next_signed8 (cw_unpack_context* unpack_context) cw_unpack_next (unpack_context); if (unpack_context->return_code) return 0; - + if (unpack_context->item.type == CWP_ITEM_POSITIVE_INTEGER) { if (unpack_context->item.as.u64 <= INT8_MAX) @@ -225,7 +225,7 @@ int8_t cw_unpack_next_signed8 (cw_unpack_context* unpack_context) return 0; } } - + unpack_context->return_code = CWP_RC_TYPE_ERROR; return 0; } @@ -237,12 +237,12 @@ uint64_t cw_unpack_next_unsigned64 (cw_unpack_context* unpack_context) cw_unpack_next (unpack_context); if (unpack_context->return_code) return 0; - + if (unpack_context->item.type == CWP_ITEM_POSITIVE_INTEGER) { return unpack_context->item.as.u64; } - + unpack_context->return_code = CWP_RC_TYPE_ERROR; return 0; } @@ -253,7 +253,7 @@ uint32_t cw_unpack_next_unsigned32 (cw_unpack_context* unpack_context) cw_unpack_next (unpack_context); if (unpack_context->return_code) return 0; - + if (unpack_context->item.type == CWP_ITEM_POSITIVE_INTEGER) { if (unpack_context->item.as.u64 <= UINT32_MAX) @@ -264,7 +264,7 @@ uint32_t cw_unpack_next_unsigned32 (cw_unpack_context* unpack_context) return 0; } } - + unpack_context->return_code = CWP_RC_TYPE_ERROR; return 0; } @@ -275,7 +275,7 @@ uint16_t cw_unpack_next_unsigned16 (cw_unpack_context* unpack_context) cw_unpack_next (unpack_context); if (unpack_context->return_code) return 0; - + if (unpack_context->item.type == CWP_ITEM_POSITIVE_INTEGER) { if (unpack_context->item.as.u64 <= UINT16_MAX) @@ -286,7 +286,7 @@ uint16_t cw_unpack_next_unsigned16 (cw_unpack_context* unpack_context) return 0; } } - + unpack_context->return_code = CWP_RC_TYPE_ERROR; return 0; } @@ -297,7 +297,7 @@ uint8_t cw_unpack_next_unsigned8 (cw_unpack_context* unpack_context) cw_unpack_next (unpack_context); if (unpack_context->return_code) return 0; - + if (unpack_context->item.type == CWP_ITEM_POSITIVE_INTEGER) { if (unpack_context->item.as.u64 <= UINT8_MAX) @@ -308,7 +308,7 @@ uint8_t cw_unpack_next_unsigned8 (cw_unpack_context* unpack_context) return 0; } } - + unpack_context->return_code = CWP_RC_TYPE_ERROR; return 0; } @@ -318,7 +318,7 @@ double cw_unpack_next_time_interval (cw_unpack_context* unpack_context) { cw_unpack_next (unpack_context); if (unpack_context->return_code) return NaN; - + if (unpack_context->item.type == CWP_ITEM_TIMESTAMP) { return (double)unpack_context->item.as.time.tv_sec + (double)unpack_context->item.as.time.tv_nsec/1000000000; diff --git a/goodies/utils/cwpack_utils.h b/goodies/utils/cwpack_utils.h index 09450c2..61dcbb7 100644 --- a/goodies/utils/cwpack_utils.h +++ b/goodies/utils/cwpack_utils.h @@ -1,18 +1,18 @@ /* CWPack/goodies - cwpack_utils.h */ /* The MIT License (MIT) - + Copyright (c) 2017 Claes Wihlborg - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, diff --git a/src/README.md b/src/README.md index 71f765b..62f03fe 100755 --- a/src/README.md +++ b/src/README.md @@ -13,7 +13,7 @@ The src folder contains all basic functionallity to use CWPack. **cwpack.c** contains the code. ## Contexts -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. +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. 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). @@ -22,7 +22,7 @@ First you choose a context that suits your needs and initiates it. Then you can 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. -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). +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). You find an Objective-C wrapper in [goodies/objC](https://github.com/clwi/CWPack/tree/master/goodies/objC). diff --git a/src/cwpack.c b/src/cwpack.c index 6fb2710..1982337 100644 --- a/src/cwpack.c +++ b/src/cwpack.c @@ -1,18 +1,18 @@ /* CWPack - cwpack.c */ /* The MIT License (MIT) - + Copyright (c) 2017 Claes Wihlborg - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, @@ -103,7 +103,7 @@ void cw_pack_unsigned(cw_pack_context* pack_context, uint64_t i) { if (pack_context->return_code) return; - + if (i < 128) tryMove0(i); @@ -125,27 +125,27 @@ void cw_pack_signed(cw_pack_context* pack_context, int64_t i) { if (pack_context->return_code) return; - + if (i >127) { if (i < 256) tryMove1(0xcc, i); - + if (i < 0x10000L) tryMove2(0xcd, i); - + if (i < 0x100000000LL) tryMove4(0xce, i); - + tryMove8(0xcf,i); } - + if (i >= -32) tryMove0(i); if (i >= -128) tryMove1(0xd0, i); - + if (i >= -32768) tryMove2(0xd1,i); @@ -160,7 +160,7 @@ void cw_pack_float(cw_pack_context* pack_context, float f) { if (pack_context->return_code) return; - + uint32_t tmp = *((uint32_t*)&f); tryMove4(0xca,tmp); } @@ -170,7 +170,7 @@ void cw_pack_double(cw_pack_context* pack_context, double d) { if (pack_context->return_code) return; - + uint64_t tmp = *((uint64_t*)&d); tryMove8(0xcb,tmp); } @@ -189,7 +189,7 @@ void cw_pack_true (cw_pack_context* pack_context) { if (pack_context->return_code) return; - + tryMove0(0xc3); } @@ -198,7 +198,7 @@ void cw_pack_false (cw_pack_context* pack_context) { if (pack_context->return_code) return; - + tryMove0(0xc2); } @@ -207,7 +207,7 @@ void cw_pack_boolean(cw_pack_context* pack_context, bool b) { if (pack_context->return_code) return; - + tryMove0(b? 0xc3: 0xc2); } @@ -216,7 +216,7 @@ void cw_pack_array_size(cw_pack_context* pack_context, uint32_t n) { if (pack_context->return_code) return; - + if (n < 16) tryMove0(0x90 | n); @@ -231,7 +231,7 @@ void cw_pack_map_size(cw_pack_context* pack_context, uint32_t n) { if (pack_context->return_code) return; - + if (n < 16) tryMove0(0x80 | n); @@ -246,9 +246,9 @@ void cw_pack_str(cw_pack_context* pack_context, const char* v, uint32_t l) { if (pack_context->return_code) return; - + uint8_t *p; - + if (l < 32) // Fixstr { cw_pack_reserve_space(l+1); @@ -285,15 +285,15 @@ void cw_pack_bin(cw_pack_context* pack_context, const void* v, uint32_t l) { if (pack_context->return_code) return; - + if (pack_context->be_compatible) { cw_pack_str( pack_context, v, l); return; } - + uint8_t *p; - + if (l < 256) // Bin 8 { cw_pack_reserve_space(l+2); @@ -323,12 +323,12 @@ void cw_pack_ext (cw_pack_context* pack_context, int8_t type, const void* v, uin { if (pack_context->return_code) return; - + if (pack_context->be_compatible) PACK_ERROR(CWP_RC_ILLEGAL_CALL); - + uint8_t *p; - + switch (l) { case 1: // Fixext 1 @@ -471,7 +471,7 @@ void cw_unpack_next (cw_unpack_context* unpack_context) uint32_t tmpu32; uint16_t tmpu16; uint8_t* p; - + #define buffer_end_return_code CWP_RC_END_OF_INPUT; cw_unpack_assert_space(1); uint8_t c = *p; @@ -591,7 +591,7 @@ void cw_unpack_next (cw_unpack_context* unpack_context) default: UNPACK_ERROR(CWP_RC_MALFORMED_INPUT) } - + return; } @@ -603,11 +603,11 @@ void cw_skip_items (cw_unpack_context* unpack_context, long item_count) { if (unpack_context->return_code) return; - + uint32_t tmpu32; uint16_t tmpu16; uint8_t* p; - + while (item_count-- > 0) { #undef buffer_end_return_code @@ -669,19 +669,19 @@ void cw_skip_items (cw_unpack_context* unpack_context, long item_count) cw_unpack_assert_space(1); tmpu32 = *p; cw_skip_bytes(tmpu32); - + case 0xda: // str 16 case 0xc5: // bin 16 cw_unpack_assert_space(2); cw_load16(p); cw_skip_bytes(tmpu16); - + case 0xdb: // str 32 case 0xc6: // bin 32 cw_unpack_assert_space(4); cw_load32(p); cw_skip_bytes(tmpu32); - + case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f: item_count += 2*(c & 15); // FixMap @@ -691,46 +691,46 @@ void cw_skip_items (cw_unpack_context* unpack_context, long item_count) case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: item_count += c & 15; // FixArray break; - + case 0xdc: // array 16 cw_unpack_assert_space(2); cw_load16(p); item_count += tmpu16; break; - + case 0xde: // map 16 cw_unpack_assert_space(2); cw_load16(p); item_count += 2*tmpu16; break; - + case 0xdd: // array 32 cw_unpack_assert_space(4); cw_load32(p); item_count += tmpu32; break; - + case 0xdf: // map 32 cw_unpack_assert_space(4); cw_load32(p); item_count += 2*tmpu32; break; - + case 0xc7: // ext 8 cw_unpack_assert_space(1); tmpu32 = *p; cw_skip_bytes(tmpu32 +1); - + case 0xc8: // ext 16 cw_unpack_assert_space(2); cw_load16(p); cw_skip_bytes(tmpu16 +1); - + case 0xc9: // ext 32 cw_unpack_assert_space(4); cw_load32(p); cw_skip_bytes(tmpu32 +1); - + default: // illegal UNPACK_ERROR(CWP_RC_MALFORMED_INPUT) } diff --git a/src/cwpack.h b/src/cwpack.h index c347ab9..64418fe 100644 --- a/src/cwpack.h +++ b/src/cwpack.h @@ -1,18 +1,18 @@ /* CWPack - cwpack.h */ /* The MIT License (MIT) - + Copyright (c) 2017 Claes Wihlborg - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, diff --git a/src/cwpack_config.h b/src/cwpack_config.h index 7187f28..10ec9fe 100644 --- a/src/cwpack_config.h +++ b/src/cwpack_config.h @@ -1,18 +1,18 @@ /* CWPack - cwpack_config.h */ /* The MIT License (MIT) - + Copyright (c) 2017 Claes Wihlborg - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, @@ -58,7 +58,7 @@ /************************* B Y T E O R D E R ****************************/ /* - * The pack/unpack routines are written in three versions: for big endian, for + * The pack/unpack routines are written in three versions: for big endian, for * little endian and insensitive to byte order. As you can get some speed gain * if the byte order is known, we try that when we can certainly detect it. * Define COMPILE_FOR_BIG_ENDIAN or COMPILE_FOR_LITTLE_ENDIAN if you know. diff --git a/src/cwpack_internals.h b/src/cwpack_internals.h index 6bba04d..baed055 100644 --- a/src/cwpack_internals.h +++ b/src/cwpack_internals.h @@ -1,18 +1,18 @@ /* CWPack - cwpack_defines.h */ /* The MIT License (MIT) - + Copyright (c) 2017 Claes Wihlborg - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, diff --git a/test/cwpack_module_test.c b/test/cwpack_module_test.c index d2889ec..3d5dab5 100644 --- a/test/cwpack_module_test.c +++ b/test/cwpack_module_test.c @@ -1,18 +1,18 @@ /* CWPack/test cwpack_module_test.c */ /* The MIT License (MIT) - + Copyright (c) 2017 Claes Wihlborg - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, @@ -65,7 +65,7 @@ static char char2hex (char c) return c - '0'; if (c <= 'F') return c - 'A' + 10; - + return c - 'a' + 10; } @@ -76,7 +76,7 @@ static void check_pack_result(const char* expected_header, unsigned long data_le unsigned long header_length = strlen(expected_header) / 2; if (pack_ctx.current - outbuffer == (long)(header_length + data_length)) { - + if (header_length*2 == strlen(expected_header)) { unsigned long i; @@ -108,14 +108,14 @@ static void check_pack_result(const char* expected_header, unsigned long data_le hex <<= 4; hex += (uc - 'A' + 10); } - - + + if (*p++ != hex) { ERROR("Different header value"); } } - + if (data_length > 0) { ucp = TEST_area; @@ -150,68 +150,68 @@ int main(int argc, const char * argv[]) { printf("CWPack module test started.\n"); error_count = 0; - + bool endian_switch_found = false; #ifdef COMPILE_FOR_BIG_ENDIAN printf("Compiled for big endian.\n"); endian_switch_found = true; #endif - + #ifdef COMPILE_FOR_LITTLE_ENDIAN printf("Compiled for little endian.\n"); endian_switch_found = true; #endif - + if (!endian_switch_found) printf("Compiled for all endians.\n"); - + const char *endianness = "1234"; switch (*(uint32_t*)endianness) { case 0x31323334UL: printf("Running on big endian hardware.\n\n"); break; - + case 0x34333231UL: printf("Running on little endian hardware.\n\n"); break; - + default: printf("Running on neither little nor big endian hardware.\n\n"); break; } - - + + //******************* TEST cwpack pack **************************** - - + + #define TESTP(call,data,result) \ pack_ctx.current = outbuffer; \ cw_pack_##call (&pack_ctx, data); \ if(pack_ctx.return_code) \ ERROR("In pack"); \ check_pack_result(result,0) - - - + + + cw_pack_context_init (&pack_ctx, outbuffer, 70000, 0); if (pack_ctx.return_code == CWP_RC_WRONG_BYTE_ORDER) { ERROR("***** Compiled for wrong byte order, test terminated *****\n\n"); exit(1); } - + unsigned int ui; for (ui=0; ui<70000; ui++) { TEST_area[ui] = ui & 0x7fUL; } - - + + // TESTP NIL cw_pack_nil(&pack_ctx); check_pack_result("c0",0); - + // TESTP boolean pack_ctx.current = outbuffer; cw_pack_true(&pack_ctx); @@ -221,7 +221,7 @@ int main(int argc, const char * argv[]) check_pack_result("c2",0); TESTP(boolean,0,"c2"); TESTP(boolean,1,"c3"); - + // TESTP unsigned int TESTP(unsigned,0,"00"); TESTP(unsigned,127,"7f"); @@ -234,7 +234,7 @@ int main(int argc, const char * argv[]) TESTP(unsigned,0xffffffffUL,"ceffffffff"); TESTP(unsigned,0x100000000ULL,"cf0000000100000000"); TESTP(unsigned,0xffffffffffffffffULL,"cfffffffffffffffff"); - + // TESTP signed int TESTP(signed,-1,"ff"); TESTP(signed,-32,"e0"); @@ -243,7 +243,7 @@ int main(int argc, const char * argv[]) TESTP(signed,-129,"d1ff7f"); TESTP(signed,-32768,"d18000"); TESTP(signed,-32769,"d2ffff7fff"); - + // TESTP real float f1 = (float)3.14; TESTP(float,0.0,"ca00000000"); @@ -257,29 +257,29 @@ int main(int argc, const char * argv[]) TESTP(double_opt,f1,"ca4048f5c3"); TESTP(double_opt,3.14,"cb40091eb851eb851f"); TESTP(double_opt,-32,"e0"); - + // TESTP array TESTP(array_size,0,"90"); TESTP(array_size,15,"9f"); TESTP(array_size,16,"dc0010"); TESTP(array_size,65535,"dcffff"); TESTP(array_size,65536,"dd00010000"); - + // TESTP map TESTP(map_size,0,"80"); TESTP(map_size,15,"8f"); TESTP(map_size,16,"de0010"); TESTP(map_size,65535,"deffff"); TESTP(map_size,65536,"df00010000"); - - + + #define TESTP_AREA(call,len,header) \ pack_ctx.current = outbuffer; \ cw_pack_##call (&pack_ctx, TEST_area, len); \ if(pack_ctx.return_code) \ ERROR("In pack"); \ check_pack_result(header, len) - + // TESTP str TESTP_AREA(str,0,"a0"); TESTP_AREA(str,31,"bf"); @@ -288,21 +288,21 @@ int main(int argc, const char * argv[]) TESTP_AREA(str,256,"da0100"); TESTP_AREA(str,65535,"daffff"); TESTP_AREA(str,65536,"db00010000"); - + // TESTP bin TESTP_AREA(bin,0,"c400"); TESTP_AREA(bin,255,"c4ff"); TESTP_AREA(bin,256,"c50100"); TESTP_AREA(bin,65535,"c5ffff"); TESTP_AREA(bin,65536,"c600010000"); - + #define TESTP_EXT(call,type,len,header) \ pack_ctx.current = outbuffer; \ cw_pack_##call (&pack_ctx, type, TEST_area, len); \ if(pack_ctx.return_code) \ ERROR("In pack"); \ check_pack_result(header, len) - + // TESTP ext TESTP_EXT(ext,15,1,"d40f"); TESTP_EXT(ext,16,2,"d510"); @@ -314,7 +314,7 @@ int main(int argc, const char * argv[]) TESTP_EXT(ext,21,256,"c8010015"); TESTP_EXT(ext,21,65535,"c8ffff15"); TESTP_EXT(ext,21,65536,"c90001000015"); - + pack_ctx.current = outbuffer; cw_pack_time(&pack_ctx, 1, 0); check_pack_result("d6ff00000001", 0); @@ -326,12 +326,12 @@ int main(int argc, const char * argv[]) check_pack_result("c70cff1dcd6500ffffffffffffffff", 0); TESTP(time_interval,-0.5,"c70cff1dcd6500ffffffffffffffff"); - + //******************* TEST cwpack unpack ********************** - + char inputbuf[30]; - - + + #define TESTUP(buffer,etype) \ { \ unsigned long len = strlen(buffer)/2; \ @@ -342,21 +342,21 @@ int main(int argc, const char * argv[]) if (unpack_ctx.item.type != CWP_ITEM_##etype) \ ERROR("In unpack, type error"); \ } - + #define TESTUP_VAL(buffer,etype,var,val) \ TESTUP(buffer,etype); \ if (unpack_ctx.item.as.var != val) \ ERROR("In unpack, value error"); unsigned long blob_length = 0; - + // TESTUP NIL TESTUP("c0",NIL); - + // TESTUP boolean TESTUP_VAL("c2",BOOLEAN,boolean,false); TESTUP_VAL("c3",BOOLEAN,boolean,true); - + // TESTUP unsigned int TESTUP_VAL("00",POSITIVE_INTEGER,u64,0) TESTUP_VAL("7f",POSITIVE_INTEGER,u64,127) @@ -368,7 +368,7 @@ int main(int argc, const char * argv[]) TESTUP_VAL("ceffffffff",POSITIVE_INTEGER,u64,0xffffffffUL) TESTUP_VAL("cf0000000100000000",POSITIVE_INTEGER,u64,0x100000000ULL) TESTUP_VAL("cfffffffffffffffff",POSITIVE_INTEGER,u64,0xffffffffffffffffULL) - + // TESTUP signed int TESTUP_VAL("ff",NEGATIVE_INTEGER,i64,-1) TESTUP_VAL("e0",NEGATIVE_INTEGER,i64,-32) @@ -378,7 +378,7 @@ int main(int argc, const char * argv[]) TESTUP_VAL("d18000",NEGATIVE_INTEGER,i64,-32768) TESTUP_VAL("d2ffff7fff",NEGATIVE_INTEGER,i64,-32769) TESTUP_VAL("d3ffffffff7fffffff",NEGATIVE_INTEGER,i64,-2147483649) - + // TESTUP real // float f1 = 3.14; TESTUP_VAL("ca00000000",FLOAT,real,0.0) @@ -386,21 +386,21 @@ int main(int argc, const char * argv[]) TESTUP_VAL("cb0000000000000000",DOUBLE,long_real,0.0) TESTUP_VAL("cb40091eb860000000",DOUBLE,long_real,f1) TESTUP_VAL("cb40091eb851eb851f",DOUBLE,long_real,3.14) - + // TESTUP array TESTUP_VAL("90",ARRAY,array.size,0) TESTUP_VAL("9f",ARRAY,array.size,15) TESTUP_VAL("dc0010",ARRAY,array.size,16) TESTUP_VAL("dcffff",ARRAY,array.size,65535) TESTUP_VAL("dd00010000",ARRAY,array.size,65536) - + // TESTUP map TESTUP_VAL("80",MAP,map.size,0) TESTUP_VAL("8f",MAP,map.size,15) TESTUP_VAL("de0010",MAP,map.size,16) TESTUP_VAL("deffff",MAP,map.size,65535) TESTUP_VAL("df00010000",MAP,map.size,65536) - + // TESTUP timeStamp TESTUP_VAL("d6ff00000001",TIMESTAMP,time.tv_sec,1); TESTUP_VAL("d6ff00000001",TIMESTAMP,time.tv_nsec,0); @@ -421,14 +421,14 @@ int main(int argc, const char * argv[]) TESTUP_AREA("da0100",STR,str,256); TESTUP_AREA("daffff",STR,str,65535); TESTUP_AREA("db00010000",STR,str,65536); - + // TESTUP bin TESTUP_AREA("c400",BIN,bin,0); TESTUP_AREA("c4ff",BIN,bin,255); TESTUP_AREA("c50100",BIN,bin,256); TESTUP_AREA("c5ffff",BIN,bin,65535); TESTUP_AREA("c600010000",BIN,bin,65536); - + // TESTUP ext #define CWP_ITEM_15 15 #define CWP_ITEM_16 16 @@ -437,7 +437,7 @@ int main(int argc, const char * argv[]) #define CWP_ITEM_19 19 #define CWP_ITEM_20 20 #define CWP_ITEM_21 21 - + TESTUP_AREA("d40f",15,ext,1); TESTUP_AREA("d510",16,ext,2); TESTUP_AREA("c70311",17,ext,3); @@ -448,11 +448,11 @@ int main(int argc, const char * argv[]) TESTUP_AREA("c8010015",21,ext,256); TESTUP_AREA("c8ffff15",21,ext,65535); TESTUP_AREA("c90001000015",21,ext,65536); - - + + //******************* TEST skip *************************** - + cw_pack_context_init (&pack_ctx, outbuffer, 100, 0); cw_pack_array_size(&pack_ctx,2); cw_pack_str(&pack_ctx,"Test of skip",12); //array component @@ -465,13 +465,13 @@ int main(int argc, const char * argv[]) else { cw_unpack_context_init (&unpack_ctx, pack_ctx.start, (unsigned long)(pack_ctx.current-pack_ctx.start), 0); - + cw_skip_items (&unpack_ctx, 1); /* skip whole array */ check_unpack (0x952, CWP_RC_OK); check_unpack (0, CWP_RC_END_OF_INPUT); } - - + + //************************************************************* printf("CWPack module test completed, "); @@ -480,15 +480,15 @@ int main(int argc, const char * argv[]) case 0: printf("no errors detected\n"); break; - + case 1: printf("1 error detected\n"); break; - + default: printf("%d errors detected\n", error_count); break; } - + return error_count; } diff --git a/test/cwpack_performance_test.c b/test/cwpack_performance_test.c index e373bf5..2417b1b 100644 --- a/test/cwpack_performance_test.c +++ b/test/cwpack_performance_test.c @@ -99,64 +99,64 @@ static size_t b_writer(cmp_ctx_t *ctx, const void *data, size_t count) static void pack_test(void) { /*************** Test of pack *****************/ - + cw_pack_context pc; cmp_ctx_t cc; mpack_writer_t mw; - + int ii, itemSize; for (ii=0; iibuf + limit) > (buffer + BUF_Length)) return false; - + memcpy (data,ctx->buf,limit); ctx->buf = (uint8_t*)ctx->buf + limit; return true; @@ -213,43 +213,43 @@ static bool b_reader(struct cmp_ctx_s *ctx, void *data, size_t limit) static void unpack_test(void) { /*************** Test of unpack *****************/ - + cw_pack_context pc; cw_unpack_context uc; mpack_reader_t mr; cmp_ctx_t cc; cmp_object_t cobj; - + BEFORE_UTEST(cw_pack_nil(&pc)); UTEST("CMP", cmp_read_object(&cc, &cobj)); UTEST("MPack", mpack_read_tag(&mr)); UTEST("CWPack", cw_unpack_next(&uc)); AFTER_UTEST; - + BEFORE_UTEST(cw_pack_signed(&pc, -1)); UTEST("CMP", cmp_read_object(&cc, &cobj)); UTEST("MPack", mpack_read_tag(&mr)); UTEST("CWPack", cw_unpack_next(&uc)); AFTER_UTEST; - + BEFORE_UTEST(cw_pack_signed(&pc, 100000)); UTEST("CMP", cmp_read_object(&cc, &cobj)); UTEST("MPack", mpack_read_tag(&mr)); UTEST("CWPack", cw_unpack_next(&uc)); AFTER_UTEST; - + BEFORE_UTEST(cw_pack_float(&pc, (float)3.14)); UTEST("CMP", cmp_read_object(&cc, &cobj)); UTEST("MPack", mpack_read_tag(&mr)); UTEST("CWPack", cw_unpack_next(&uc)); AFTER_UTEST; - + BEFORE_UTEST(cw_pack_double(&pc, 3.14)); UTEST("CMP", cmp_read_object(&cc, &cobj)); UTEST("MPack", mpack_read_tag(&mr)); UTEST("CWPack", cw_unpack_next(&uc)); AFTER_UTEST; - + BEFORE_UTEST(cw_pack_str(&pc, "Claes",5)); UTEST("CMP", cmp_read_object(&cc, &cobj)); UTEST("MPack", mpack_skip_bytes(&mr,mpack_expect_str(&mr));mpack_done_str(&mr)); From e547f67772fca3d6decf5fc6daf86134dbfab078 Mon Sep 17 00:00:00 2001 From: Mike Date: Wed, 10 Feb 2021 19:37:36 +0100 Subject: [PATCH 07/10] Fix compiler warnings (#13) * fix warning: trailing comma is nonstandard * fix compiler warning: statement not reachable * fix compiler warnings: type mismatch (enum <> int) Co-authored-by: Claes Wihlborg --- src/cwpack.c | 8 +++----- src/cwpack.h | 2 +- src/cwpack_internals.h | 11 +++++++---- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/cwpack.c b/src/cwpack.c index 1982337..4687227 100644 --- a/src/cwpack.c +++ b/src/cwpack.c @@ -519,7 +519,7 @@ void cw_unpack_next (cw_unpack_context* unpack_context) cw_unpack_assert_blob(bin); case 0xc7: getDDItem1(CWP_ITEM_EXT, ext.length, uint8_t); // ext 8 cw_unpack_assert_space(1); - unpack_context->item.type = *(int8_t*)p; + unpack_context->item.type = (cwpack_item_types)*(int8_t*)p; if (unpack_context->item.type == CWP_ITEM_TIMESTAMP) { if (unpack_context->item.as.ext.length == 12) @@ -537,11 +537,11 @@ void cw_unpack_next (cw_unpack_context* unpack_context) cw_unpack_assert_blob(ext); case 0xc8: getDDItem2(CWP_ITEM_EXT, ext.length, uint16_t); // ext 16 cw_unpack_assert_space(1); - unpack_context->item.type = *(int8_t*)p; + unpack_context->item.type = (cwpack_item_types)*(int8_t*)p; cw_unpack_assert_blob(ext); case 0xc9: getDDItem4(CWP_ITEM_EXT, ext.length, uint32_t); // ext 32 cw_unpack_assert_space(1); - unpack_context->item.type = *(int8_t*)p; + unpack_context->item.type = (cwpack_item_types)*(int8_t*)p; cw_unpack_assert_blob(ext); case 0xca: unpack_context->item.type = CWP_ITEM_FLOAT; // float cw_unpack_assert_space(4); @@ -591,8 +591,6 @@ void cw_unpack_next (cw_unpack_context* unpack_context) default: UNPACK_ERROR(CWP_RC_MALFORMED_INPUT) } - - return; } #define cw_skip_bytes(n) \ diff --git a/src/cwpack.h b/src/cwpack.h index 64418fe..d71da6b 100644 --- a/src/cwpack.h +++ b/src/cwpack.h @@ -116,7 +116,7 @@ typedef enum CWP_ITEM_ARRAY = 308, CWP_ITEM_MAP = 309, CWP_ITEM_EXT = 310, - CWP_NOT_AN_ITEM = 999, + CWP_NOT_AN_ITEM = 999 } cwpack_item_types; diff --git a/src/cwpack_internals.h b/src/cwpack_internals.h index baed055..e28ba5a 100644 --- a/src/cwpack_internals.h +++ b/src/cwpack_internals.h @@ -337,8 +337,8 @@ #define getDDItemFix(len) \ cw_unpack_assert_space(len+1); \ - unpack_context->item.type = *(int8_t*)p++; \ - if (unpack_context->item.type == CWP_ITEM_TIMESTAMP) \ + unpack_context->item.type = (cwpack_item_types)*(int8_t*)p++; \ + if (unpack_context->item.type == CWP_ITEM_TIMESTAMP) \ { \ if (len == 4) \ { \ @@ -347,14 +347,17 @@ unpack_context->item.as.time.tv_nsec = 0; \ return; \ } \ - if (len == 8) \ + else if (len == 8) \ { \ cw_load64(p,tmpu64); \ unpack_context->item.as.time.tv_sec = tmpu64 & 0x00000003ffffffffL; \ unpack_context->item.as.time.tv_nsec = tmpu64 >> 34; \ return; \ } \ - UNPACK_ERROR(CWP_RC_WRONG_TIMESTAMP_LENGTH) \ + else \ + { \ + UNPACK_ERROR(CWP_RC_WRONG_TIMESTAMP_LENGTH) \ + } \ } \ unpack_context->item.as.ext.length = len; \ unpack_context->item.as.ext.start = p; \ From 4f4464c40a9d5979391a49bd21e7a8a0d84d2770 Mon Sep 17 00:00:00 2001 From: clwi Date: Fri, 5 Mar 2021 16:20:33 +0100 Subject: [PATCH 08/10] 20210304 --- goodies/basic-contexts/basic_contexts.c | 2 +- goodies/dump/README.md | 21 ++- goodies/dump/cwpack_dump | Bin 0 -> 102872 bytes goodies/dump/cwpack_dump.c | 104 +++++++++++--- goodies/dump/runCWpack_dump.sh | 2 +- .../numeric-extensions/numeric_extensions.c | 3 + goodies/objC/cwpack_objc.h | 2 +- goodies/objC/cwpack_objc.m | 33 ++++- src/cwpack.h | 129 ++++++++++++++++++ 9 files changed, 267 insertions(+), 29 deletions(-) create mode 100755 goodies/dump/cwpack_dump diff --git a/goodies/basic-contexts/basic_contexts.c b/goodies/basic-contexts/basic_contexts.c index c026e22..a0646ea 100644 --- a/goodies/basic-contexts/basic_contexts.c +++ b/goodies/basic-contexts/basic_contexts.c @@ -291,7 +291,7 @@ void init_file_pack_context (file_pack_context* fpc, unsigned long initial_buffe fpc->pc.return_code = CWP_RC_MALLOC_ERROR; return; } - fpc->fileDescriptor = fileDescriptor; + fpc->fileDescriptor = fileDescriptor; fpc->barrier = NULL; diff --git a/goodies/dump/README.md b/goodies/dump/README.md index cdff3e4..39dd806 100755 --- a/goodies/dump/README.md +++ b/goodies/dump/README.md @@ -4,9 +4,10 @@ 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. Syntax: -cwpack_dump [-t 9] [-v] [-h] < msgpackFile > humanReadableFile +cwpack_dump [-t 9] [-v][-r] [-h] < msgpackFile > humanReadableFile -t 9 Tab size -v Version +-r Recognize records -h Help 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. @@ -17,10 +18,10 @@ If Tab size isn't given, structures are written on a single line. ``` 0 [10000000 3.14 "åäöÅÄÖ"] - 1c {"binary": (62696e617279) "extension": (-5,68656c6c6f) "time": '2020-05-20 18:40:00'} + 1c {"binary": <62696e617279> "extension": (-5,<68656c6c6f>) "time": '2020-05-20 18:40:00'} 49 ``` -and `cwpack_dump -t 4 < testdump.msgpack` prints: +and `cwpack_dump -t 4 < testdump.msgpack` prints: ``` 0 [ @@ -29,10 +30,20 @@ and `cwpack_dump -t 4 < testdump.msgpack` prints: f "åäöÅÄÖ" 1c ] 1c { - 1d "binary": (62696e617279) - 2c "extension": (-5,68656c6c6f) + 1d "binary": <62696e617279> + 2c "extension": (-5,<68656c6c6f>) 3e "time": '2020-05-20 18:40:00' 49 } 49 ``` +The -r option makes dump recognize Objective-C objects. `cwpack_dump < testdump2.msgpack` prints: + +``` + 0 [(127,<01>) "MyClass" [(127,<02>) "MyClass" [(127,<01>)]]] +``` +and `cwpack_dump -r < testdump2.msgpack` prints + +``` + 0 1->MyClass(2->MyClass(->1)) +``` diff --git a/goodies/dump/cwpack_dump b/goodies/dump/cwpack_dump new file mode 100755 index 0000000000000000000000000000000000000000..6684217048ce8ddd87bf873caba0db018ea59dce GIT binary patch literal 102872 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 QEYhIrF2=kLy@qA|KPWST1poj5 literal 0 HcmV?d00001 diff --git a/goodies/dump/cwpack_dump.c b/goodies/dump/cwpack_dump.c index 4e28fde..ba786c6 100755 --- a/goodies/dump/cwpack_dump.c +++ b/goodies/dump/cwpack_dump.c @@ -25,8 +25,10 @@ #include #include #include "basic_contexts.h" +#include "numeric_extensions.h" char tabString[21] = " "; +bool recognizeObjects = false; #define NEW_LINE {printf ("\n%6x ",(unsigned)(context->current - context->start)); for (ti=0; tireturn_code) return; + dump_item (context, tabLevel); +} + +static void dump_item( cw_unpack_context* context, int tabLevel) { long long dim =99; @@ -55,20 +64,18 @@ static void dump_next_item( cw_unpack_context* context, int tabLevel) char s[128]; if (!tabLevel) NEW_LINE; - cw_unpack_next (context); - if (context->return_code) return; switch (context->item.type) { case CWP_ITEM_NIL: - printf("null"); + printf("nil"); break; case CWP_ITEM_BOOLEAN: if (context->item.as.boolean) - printf("true"); + printf("YES"); else - printf("false"); + printf("NO"); break; case CWP_ITEM_POSITIVE_INTEGER: @@ -115,24 +122,79 @@ static void dump_next_item( cw_unpack_context* context, int tabLevel) break;} case CWP_ITEM_BIN: - printf("("); + printf("<"); dump_as_hex (context->item.as.bin.start, context->item.as.bin.length); - printf(")"); + printf(">"); break; case CWP_ITEM_ARRAY: - printf("["); + { dim = context->item.as.array.size; - tabLevel++; - for (i = 0; i < dim; i++) + if (!dim) + { + printf("[]"); + break; + } + + cw_unpack_next (context); + if (context->return_code) break; + + if (recognizeObjects && (context->item.type == 127)) + { + long label = get_ext_integer(context); + bool userObject = label >= 0; + if (dim == 1) /* reference */ + { + printf("->%ld",label); + break; + } + if (label) + printf("%ld->",labs(label)); + if (!userObject) + { + if (dim != 2) + { + context->return_code = CWP_RC_MALFORMED_INPUT; + break; + } + dump_next_item(context,tabLevel); + break; + } + cw_unpack_next (context); + if (context->return_code) break; + if (context->item.type != CWP_ITEM_STR) + { + context->return_code = CWP_RC_MALFORMED_INPUT; + break; + } + printf("%.*s(",context->item.as.str.length, context->item.as.str.start); + tabLevel++; + for (i = 2; i < dim; i++) + { + CHECK_NEW_LINE; + dump_next_item(context,tabLevel); + } + tabLevel--; + if(*tabString) NEW_LINE; + printf(")"); + } + else { + printf("["); + tabLevel++; CHECK_NEW_LINE; - dump_next_item(context,tabLevel); + dump_item(context,tabLevel); + for (i = 1; i < dim; i++) + { + CHECK_NEW_LINE; + dump_next_item(context,tabLevel); + } + tabLevel--; + if(*tabString) NEW_LINE; + printf("]"); } - tabLevel--; - if(*tabString) NEW_LINE; - printf("]"); break; + } case CWP_ITEM_MAP: printf("{"); @@ -152,7 +214,8 @@ static void dump_next_item( cw_unpack_context* context, int tabLevel) case CWP_ITEM_TIMESTAMP: printf("'"); - gmtime_r(&context->item.as.time.tv_sec,&tm); + time_t tv_sec = context->item.as.time.tv_sec; + gmtime_r(&tv_sec,&tm); strftime(s,128,"%F %T", &tm); printf("%s",s); if (context->item.as.time.tv_nsec) @@ -200,12 +263,17 @@ int main(int argc, const char * argv[]) printf("cwpack_dump version = 1.0\n"); exit(0); } + else if (!strcmp(argv[i],"-r")) + { + recognizeObjects = true; + } else { - printf("cwpack_dump [-t 9] [-v] [-h]\n"); + printf("cwpack_dump [-t 9] [-r] [-v] [-h]\n"); + printf("-h Help\n"); + printf("-r Recognize records\n"); printf("-t 9 Tab size\n"); printf("-v Version\n"); - printf("-h Help\n"); printf("\nIf Tab size isn't given, structures are written on a single line\n"); printf("\nInput is taken from stdin and output is written to stdout\n"); exit(0); diff --git a/goodies/dump/runCWpack_dump.sh b/goodies/dump/runCWpack_dump.sh index 12d0c2f..d9fc8fc 100755 --- a/goodies/dump/runCWpack_dump.sh +++ b/goodies/dump/runCWpack_dump.sh @@ -1,3 +1,3 @@ -clang -ansi -I ../../src/ -I ../basic-contexts/ -o cwpack_dump *.c ../../src/cwpack.c ../basic-contexts/*.c +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 ./cwpack_dump < testdump.msgpack ./cwpack_dump -t 4 < testdump.msgpack diff --git a/goodies/numeric-extensions/numeric_extensions.c b/goodies/numeric-extensions/numeric_extensions.c index 68c26a4..b6078f2 100644 --- a/goodies/numeric-extensions/numeric_extensions.c +++ b/goodies/numeric-extensions/numeric_extensions.c @@ -121,6 +121,9 @@ int64_t get_ext_integer (cw_unpack_context* unpack_context) } switch (unpack_context->item.as.ext.length) { + case 0: + return 0; + case 1: return *(int8_t*)unpack_context->item.as.ext.start; diff --git a/goodies/objC/cwpack_objc.h b/goodies/objC/cwpack_objc.h index 8e8ce0e..d02a05c 100755 --- a/goodies/objC/cwpack_objc.h +++ b/goodies/objC/cwpack_objc.h @@ -33,6 +33,6 @@ - (void) packIn:(cw_pack_context*) buff; /* *********************** U N P A C K *************************/ +- (id) initFromContext:(cw_unpack_context*) buff; + (instancetype) unpackFrom:(cw_unpack_context*) buff; - @end diff --git a/goodies/objC/cwpack_objc.m b/goodies/objC/cwpack_objc.m index 11773eb..8d55674 100755 --- a/goodies/objC/cwpack_objc.m +++ b/goodies/objC/cwpack_objc.m @@ -24,6 +24,8 @@ software and associated documentation files (the "Software"), to deal in the Sof #import "cwpack_objc.h" #import "cwpack_utils.h" +#define CWP_ITEM_CLASS_NAME 127 + id cwObjectFromBuffer (cw_unpack_context* inbuf); @@ -32,8 +34,8 @@ @implementation NSObject (cwPack) - (void) packIn:(cw_pack_context*) buff { - buff->return_code = CWP_RC_ILLEGAL_CALL; // No pack defined for this object type - [NSException raise:@"[NSObject packIn:]" format:@"PackIn not defined for class: %@", [self class]]; + const char *className= object_getClassName(self); + cw_pack_ext (buff, CWP_ITEM_CLASS_NAME, className, (uint32_t)strlen(className)); } @@ -61,6 +63,16 @@ + (instancetype) unpackFrom:(cw_unpack_context*) buff return result; } + +- (id) initFromContext:(cw_unpack_context*) buff +{ + self = [self init]; // satisfy compiler + buff->return_code = CWP_RC_ILLEGAL_CALL; // No unpack defined for this object type + [NSException raise:@"Not defined" format:@"[%@ initFromContext:]", [self class]]; + return nil; +} + + @end @@ -192,6 +204,8 @@ - (void) packIn:(cw_pack_context*) buff NSTimeInterval ti = self.timeIntervalSince1970; cw_pack_time_interval (buff, ti); } + + @end @@ -227,7 +241,7 @@ id cwObjectFromBuffer (cw_unpack_context* inbuf) return [NSNumber numberWithDouble:inbuf->item.as.long_real]; case CWP_ITEM_STR: - return [[[NSString alloc] initWithBytes:inbuf->item.as.str.start length:inbuf->item.as.str.length encoding:NSUTF8StringEncoding] autorelease]; + return [[NSString alloc] initWithBytes:inbuf->item.as.str.start length:inbuf->item.as.str.length encoding:NSUTF8StringEncoding]; case CWP_ITEM_BIN: return [NSData dataWithBytes:inbuf->item.as.bin.start length:inbuf->item.as.bin.length]; @@ -263,6 +277,19 @@ id cwObjectFromBuffer (cw_unpack_context* inbuf) { return [NSDate dateWithTimeIntervalSince1970:inbuf->item.as.time.tv_sec + inbuf->item.as.time.tv_nsec / 1000000000.0]; } + + case CWP_ITEM_CLASS_NAME: + { + NSString *cName = [[NSString alloc] initWithBytes:inbuf->item.as.ext.start length:inbuf->item.as.ext.length encoding:NSUTF8StringEncoding]; + Class objectClass = NSClassFromString(cName); + if (objectClass == NULL) + { + [NSException raise:@"cwObjectFromBuffer" format:@"Class not defined for class: %@", cName]; + } + else + return [[objectClass alloc] initFromContext:inbuf]; + } + default: return nil; diff --git a/src/cwpack.h b/src/cwpack.h index c347ab9..36d3d64 100644 --- a/src/cwpack.h +++ b/src/cwpack.h @@ -104,7 +104,136 @@ typedef enum CWP_ITEM_TIMESTAMP = -1, CWP_ITEM_MAX_RESERVED_EXT = -1, CWP_ITEM_MIN_USER_EXT = 0, + CWP_ITEM_USER_EXT_0 = 0, + CWP_ITEM_USER_EXT_1 = 1, + CWP_ITEM_USER_EXT_2 = 2, + CWP_ITEM_USER_EXT_3 = 3, + CWP_ITEM_USER_EXT_4 = 4, + CWP_ITEM_USER_EXT_5 = 5, + CWP_ITEM_USER_EXT_6 = 6, + CWP_ITEM_USER_EXT_7 = 7, + CWP_ITEM_USER_EXT_8 = 8, + CWP_ITEM_USER_EXT_9 = 9, + CWP_ITEM_USER_EXT_10 = 10, + CWP_ITEM_USER_EXT_11 = 11, + CWP_ITEM_USER_EXT_12 = 12, + CWP_ITEM_USER_EXT_13 = 13, + CWP_ITEM_USER_EXT_14 = 14, + CWP_ITEM_USER_EXT_15 = 15, + CWP_ITEM_USER_EXT_16 = 16, + CWP_ITEM_USER_EXT_17 = 17, + CWP_ITEM_USER_EXT_18 = 18, + CWP_ITEM_USER_EXT_19 = 19, + CWP_ITEM_USER_EXT_20 = 20, + CWP_ITEM_USER_EXT_21 = 21, + CWP_ITEM_USER_EXT_22 = 22, + CWP_ITEM_USER_EXT_23 = 23, + CWP_ITEM_USER_EXT_24 = 24, + CWP_ITEM_USER_EXT_25 = 25, + CWP_ITEM_USER_EXT_26 = 26, + CWP_ITEM_USER_EXT_27 = 27, + CWP_ITEM_USER_EXT_28 = 28, + CWP_ITEM_USER_EXT_29 = 29, + CWP_ITEM_USER_EXT_30 = 30, + CWP_ITEM_USER_EXT_31 = 31, + CWP_ITEM_USER_EXT_32 = 32, + CWP_ITEM_USER_EXT_33 = 33, + CWP_ITEM_USER_EXT_34 = 34, + CWP_ITEM_USER_EXT_35 = 35, + CWP_ITEM_USER_EXT_36 = 36, + CWP_ITEM_USER_EXT_37 = 37, + CWP_ITEM_USER_EXT_38 = 38, + CWP_ITEM_USER_EXT_39 = 39, + CWP_ITEM_USER_EXT_40 = 40, + CWP_ITEM_USER_EXT_41 = 41, + CWP_ITEM_USER_EXT_42 = 42, + CWP_ITEM_USER_EXT_43 = 43, + CWP_ITEM_USER_EXT_44 = 44, + CWP_ITEM_USER_EXT_45 = 45, + CWP_ITEM_USER_EXT_46 = 46, + CWP_ITEM_USER_EXT_47 = 47, + CWP_ITEM_USER_EXT_48 = 48, + CWP_ITEM_USER_EXT_49 = 49, + CWP_ITEM_USER_EXT_50 = 50, + CWP_ITEM_USER_EXT_51 = 51, + CWP_ITEM_USER_EXT_52 = 52, + CWP_ITEM_USER_EXT_53 = 53, + CWP_ITEM_USER_EXT_54 = 54, + CWP_ITEM_USER_EXT_55 = 55, + CWP_ITEM_USER_EXT_56 = 56, + CWP_ITEM_USER_EXT_57 = 57, + CWP_ITEM_USER_EXT_58 = 58, + CWP_ITEM_USER_EXT_59 = 59, + CWP_ITEM_USER_EXT_60 = 60, + CWP_ITEM_USER_EXT_61 = 61, + CWP_ITEM_USER_EXT_62 = 62, + CWP_ITEM_USER_EXT_63 = 63, + CWP_ITEM_USER_EXT_64 = 64, + CWP_ITEM_USER_EXT_65 = 65, + CWP_ITEM_USER_EXT_66 = 66, + CWP_ITEM_USER_EXT_67 = 67, + CWP_ITEM_USER_EXT_68 = 68, + CWP_ITEM_USER_EXT_69 = 69, + CWP_ITEM_USER_EXT_70 = 70, + CWP_ITEM_USER_EXT_71 = 71, + CWP_ITEM_USER_EXT_72 = 72, + CWP_ITEM_USER_EXT_73 = 73, + CWP_ITEM_USER_EXT_74 = 74, + CWP_ITEM_USER_EXT_75 = 75, + CWP_ITEM_USER_EXT_76 = 76, + CWP_ITEM_USER_EXT_77 = 77, + CWP_ITEM_USER_EXT_78 = 78, + CWP_ITEM_USER_EXT_79 = 79, + CWP_ITEM_USER_EXT_80 = 80, + CWP_ITEM_USER_EXT_81 = 81, + CWP_ITEM_USER_EXT_82 = 82, + CWP_ITEM_USER_EXT_83 = 83, + CWP_ITEM_USER_EXT_84 = 84, + CWP_ITEM_USER_EXT_85 = 85, + CWP_ITEM_USER_EXT_86 = 86, + CWP_ITEM_USER_EXT_87 = 87, + CWP_ITEM_USER_EXT_88 = 88, + CWP_ITEM_USER_EXT_89 = 89, + CWP_ITEM_USER_EXT_90 = 90, + CWP_ITEM_USER_EXT_91 = 91, + CWP_ITEM_USER_EXT_92 = 92, + CWP_ITEM_USER_EXT_93 = 93, + CWP_ITEM_USER_EXT_94 = 94, + CWP_ITEM_USER_EXT_95 = 95, + CWP_ITEM_USER_EXT_96 = 96, + CWP_ITEM_USER_EXT_97 = 97, + CWP_ITEM_USER_EXT_98 = 98, + CWP_ITEM_USER_EXT_99 = 99, + CWP_ITEM_USER_EXT_100 = 100, + CWP_ITEM_USER_EXT_101 = 101, + CWP_ITEM_USER_EXT_102 = 102, + CWP_ITEM_USER_EXT_103 = 103, + CWP_ITEM_USER_EXT_104 = 104, + CWP_ITEM_USER_EXT_105 = 105, + CWP_ITEM_USER_EXT_106 = 106, + CWP_ITEM_USER_EXT_107 = 107, + CWP_ITEM_USER_EXT_108 = 108, + CWP_ITEM_USER_EXT_109 = 109, + CWP_ITEM_USER_EXT_110 = 110, + CWP_ITEM_USER_EXT_111 = 111, + CWP_ITEM_USER_EXT_112 = 112, + CWP_ITEM_USER_EXT_113 = 113, + CWP_ITEM_USER_EXT_114 = 114, + CWP_ITEM_USER_EXT_115 = 115, + CWP_ITEM_USER_EXT_116 = 116, + CWP_ITEM_USER_EXT_117 = 117, + CWP_ITEM_USER_EXT_118 = 118, + CWP_ITEM_USER_EXT_119 = 119, + CWP_ITEM_USER_EXT_120 = 120, + CWP_ITEM_USER_EXT_121 = 121, + CWP_ITEM_USER_EXT_122 = 122, + CWP_ITEM_USER_EXT_123 = 123, + CWP_ITEM_USER_EXT_124 = 124, + CWP_ITEM_USER_EXT_125 = 125, + CWP_ITEM_USER_EXT_126 = 126, + CWP_ITEM_USER_EXT_127 = 127, CWP_ITEM_MAX_USER_EXT = 127, + CWP_ITEM_NIL = 300, CWP_ITEM_BOOLEAN = 301, CWP_ITEM_POSITIVE_INTEGER = 302, From 748097d4136e90182194e214c8009bde0a4236d5 Mon Sep 17 00:00:00 2001 From: clwi Date: Wed, 10 Mar 2021 21:49:32 +0100 Subject: [PATCH 09/10] 20210310 --- .gitignore | 1 - README.md | 12 + goodies/dump/README.md | 10 +- goodies/dump/cwpack_dump | Bin 102872 -> 0 bytes goodies/dump/cwpack_dump.c | 29 +- goodies/dump/testdump.msgpack | Bin 0 -> 73 bytes goodies/dump/testdump2.msgpack | 2 + goodies/objC/CWPackContext.h | 97 +++ goodies/objC/CWPackContext.m | 693 ++++++++++++++++++++++ goodies/objC/README.md | 106 +++- goodies/objC/Technique.md | 60 ++ goodies/objC/obsolete/README.md | 40 ++ goodies/objC/{ => obsolete}/cwpack_objc.h | 0 goodies/objC/{ => obsolete}/cwpack_objc.m | 0 14 files changed, 1009 insertions(+), 41 deletions(-) delete mode 100755 goodies/dump/cwpack_dump create mode 100644 goodies/dump/testdump.msgpack create mode 100644 goodies/dump/testdump2.msgpack create mode 100644 goodies/objC/CWPackContext.h create mode 100644 goodies/objC/CWPackContext.m create mode 100755 goodies/objC/Technique.md create mode 100755 goodies/objC/obsolete/README.md rename goodies/objC/{ => obsolete}/cwpack_objc.h (100%) rename goodies/objC/{ => obsolete}/cwpack_objc.m (100%) diff --git a/.gitignore b/.gitignore index def5edb..f350fff 100644 --- a/.gitignore +++ b/.gitignore @@ -12,5 +12,4 @@ cwpackModuleTest json2cwpack2json # Data files -*.msgpack *.msgpack.json diff --git a/README.md b/README.md index 60e1693..b1faa02 100644 --- a/README.md +++ b/README.md @@ -77,3 +77,15 @@ CWPack has no dependencies to other libraries. ## Test Included in the test folder are a module test and a performance test and shell scripts to run them. + +# Objective-C + +CWPack also contains an Objective-C interface. The MessagePack home page example would look as: + +```C +CWPackContext *pc = [CWPackContext newWithContext:my_cw_pack_context]; +[pc packObject:@{@"compact":@YES, @"schema":@0}]; + +CWUnpackContext *uc = [CWUnpackContext newWithContext:my_cw_unpack_context]; +NSDictionary *dict = [uc unpackNextObject]; +``` diff --git a/goodies/dump/README.md b/goodies/dump/README.md index 57ba2dc..69990f1 100755 --- a/goodies/dump/README.md +++ b/goodies/dump/README.md @@ -7,7 +7,7 @@ Syntax: cwpack_dump [-t 9] [-v][-r] [-h] < msgpackFile > humanReadableFile -t 9 Tab size -v Version --r Recognize records +-r Recognize records -h Help 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. @@ -39,11 +39,15 @@ and `cwpack_dump -t 4 < testdump.msgpack` prints: The -r option makes dump recognize Objective-C objects. `cwpack_dump < testdump2.msgpack` prints: ``` - 0 [(127,<01>) "MyClass" [(127,<02>) "MyClass" [(127,<01>)]]] + 0 [(127,) [[(127,)]]] + 9 [(127,<01>) "MyClass" 10 [(127,<02>) "MyClass" 20 [(127,<01>)]]] + 27 ``` and `cwpack_dump -r < testdump2.msgpack` prints ``` - 0 1->MyClass(2->MyClass(->1)) + 0 -1->[->-1] + 9 1->MyClass(10 2->MyClass(20 ->1)) + 27 ``` diff --git a/goodies/dump/cwpack_dump b/goodies/dump/cwpack_dump deleted file mode 100755 index 6684217048ce8ddd87bf873caba0db018ea59dce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102872 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 QEYhIrF2=kLy@qA|KPWST1poj5 diff --git a/goodies/dump/cwpack_dump.c b/goodies/dump/cwpack_dump.c index e706a6f..d57ad8d 100755 --- a/goodies/dump/cwpack_dump.c +++ b/goodies/dump/cwpack_dump.c @@ -1,4 +1,6 @@ -/* CWPack/goodies - cwpack_dump.c */ + +/* CWPack/goodies/dump - cwpack_dump.c */ + /* The MIT License (MIT) @@ -30,8 +32,8 @@ char tabString[21] = " "; bool recognizeObjects = false; -#define NEW_LINE {printf ("\n%6x ",(unsigned)(context->current - context->start)); for (ti=0; ticurrent - context->start)); for (ti=0; ti"); } static void dump_item( cw_unpack_context* context, int tabLevel); @@ -62,8 +66,6 @@ static void dump_item( cw_unpack_context* context, int tabLevel) struct tm tm; char s[128]; - if (!tabLevel) NEW_LINE; - switch (context->item.type) { case CWP_ITEM_NIL: @@ -121,9 +123,7 @@ static void dump_item( cw_unpack_context* context, int tabLevel) break;} case CWP_ITEM_BIN: - printf("<"); dump_as_hex (context->item.as.bin.start, context->item.as.bin.length); - printf(">"); break; case CWP_ITEM_ARRAY: @@ -148,7 +148,7 @@ static void dump_item( cw_unpack_context* context, int tabLevel) break; } if (label) - printf("%ld->",labs(label)); + printf("%ld->",label); if (!userObject) { if (dim != 2) @@ -168,19 +168,20 @@ static void dump_item( cw_unpack_context* context, int tabLevel) } printf("%.*s(",context->item.as.str.length, context->item.as.str.start); tabLevel++; - for (i = 2; i < dim; i++) + for (i = 0; i < dim-2; i++) { CHECK_NEW_LINE; dump_next_item(context,tabLevel); } tabLevel--; - if(*tabString) NEW_LINE; + if(*tabString) NEW_LINE(tabLevel); printf(")"); } else { printf("["); tabLevel++; + i = 0; CHECK_NEW_LINE; dump_item(context,tabLevel); for (i = 1; i < dim; i++) @@ -189,7 +190,7 @@ static void dump_item( cw_unpack_context* context, int tabLevel) dump_next_item(context,tabLevel); } tabLevel--; - if(*tabString) NEW_LINE; + if(*tabString) NEW_LINE(tabLevel); printf("]"); } break; @@ -203,11 +204,11 @@ static void dump_item( cw_unpack_context* context, int tabLevel) { CHECK_NEW_LINE; dump_next_item(context,tabLevel); - printf(": "); + printf(":"); dump_next_item(context,tabLevel); } tabLevel--; - if(*tabString) NEW_LINE; + if(*tabString) NEW_LINE(tabLevel); printf("}"); break; @@ -288,6 +289,8 @@ int main(int argc, const char * argv[]) while (!context->return_code) { + int ti; + NEW_LINE(0); dump_next_item(context,0); } printf("\n"); diff --git a/goodies/dump/testdump.msgpack b/goodies/dump/testdump.msgpack new file mode 100644 index 0000000000000000000000000000000000000000..0ddfac0e41b5a867418276df3d8cbfb9dc9e0db1 GIT binary patch literal 73 zcmbPyj$y{MhSLt5aytTFx5}?My!7yr!`lwG9&R~2t$A5eW?o`Z+g)zoSgh6C7HRY*Z#*Ht!w}QZhIwI literal 0 HcmV?d00001 diff --git a/goodies/dump/testdump2.msgpack b/goodies/dump/testdump2.msgpack new file mode 100644 index 0000000..6e565bc --- /dev/null +++ b/goodies/dump/testdump2.msgpack @@ -0,0 +1,2 @@ +’Ôÿ‘‘Ôÿ”Ô§MyClass +”Ô§MyClass‘Ô \ No newline at end of file diff --git a/goodies/objC/CWPackContext.h b/goodies/objC/CWPackContext.h new file mode 100644 index 0000000..69513f1 --- /dev/null +++ b/goodies/objC/CWPackContext.h @@ -0,0 +1,97 @@ + +/* CWPack/goodies/ObjC - CWPackContext.h */ + +/* + The MIT License (MIT) + + Copyright (c) 2021 Claes Wihlborg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#import +#include "cwpack.h" + +NS_ASSUME_NONNULL_BEGIN + + + + + +@interface CWPackContext : NSObject + +@property (readonly) cw_pack_context *context; +@property (readwrite) BOOL useLabels; // default NO + ++ (instancetype) newWithContext:(cw_pack_context*)context; +- (void) packObject:(nullable NSObject*)object; + +@end + + + + + +@interface CWUnpackContext : NSObject + +@property (readonly) cw_unpack_context *context; + ++ (instancetype) newWithContext:(cw_unpack_context*)context; +- (id) unpackNextObject; + +@end + + + + +@protocol CWPackable + +@required +@property (readonly) int persistentAttributeCount; +- (void) cwPackSub:(CWPackContext*)ctx; +- (void) cwUnpackSub:(CWUnpackContext*)ctx remainingAttributes:(int)remainingAttributes; + +@optional +- (instancetype) cwUnpackSubInit:(CWUnpackContext*)ctx remainingAttributes:(int)remainingAttributes; + +@end + + + + +@interface CWPackExternalItem : NSObject + +@property (readonly) int type; +@property (readwrite, strong) NSData* data; + ++ (instancetype) itemWithType:(int)type data:(NSData*)data; + +@end + + + + +@interface CWPackGenericClass : NSObject + +@property (readwrite,strong) NSString *packerClassName; +@property (readwrite,strong) NSMutableArray *attributes; + ++ (instancetype) newWithClassName:(NSString*)className; +@end + + +NS_ASSUME_NONNULL_END diff --git a/goodies/objC/CWPackContext.m b/goodies/objC/CWPackContext.m new file mode 100644 index 0000000..3038d1b --- /dev/null +++ b/goodies/objC/CWPackContext.m @@ -0,0 +1,693 @@ + +/* CWPack/goodies/ObjC - CWPackContext.m */ + +/* + The MIT License (MIT) + + Copyright (c) 2021 Claes Wihlborg + + Permission is hereby granted, free of charge, to any person obtaining a copy of this + software and associated documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#include "cwpack_internals.h" +#include "numeric_extensions.h" +#include "cwpack_utils.h" + +#import "CWPackContext.h" + + +#define CWP_ITEM_OBJECT_MARKER CWP_ITEM_USER_EXT_127 + + + + +@protocol CWPackPackerClasses +@required +- (void) cwPackPackerTo:(CWPackContext*)ctx; +@end + + +@interface CWUnpackContext () +- (id) cwUnpackNextObjectSub:(long)label; +@end + + +@interface NSObject (CWPackable) +- (void) cwPackTo:(CWPackContext*)ctx; +@end + + + + +#pragma mark - +#pragma mark ************************************** CWPackContext + + +@implementation CWPackContext +{ + CFMutableDictionaryRef _labelMap; + long userLabelGenerator; + long packerLabelGenerator; +} + +- (instancetype)initWithContext:(cw_pack_context*)context +{ + self = [super init]; + if (self) { + _context = context; + _labelMap = CFDictionaryCreateMutable(nil, 0, nil, nil); + } + return self; +} + + ++ (instancetype) newWithContext:(cw_pack_context*)context { + return [self.alloc initWithContext:context]; +} + + +- (long) labelForObject:(id)object { + return (long)CFDictionaryGetValue (_labelMap, (const void *)object); +} + + +- (long) assignLabelForObject:(id)object isMsgpackObject:(BOOL)isMsgpackObject +{ + long label = isMsgpackObject ? --packerLabelGenerator : ++userLabelGenerator; + CFDictionarySetValue (_labelMap, (const void *)object,(const void *)label); + return label; +} + + +- (void) packUserObject:(id)object +{ + [object cwPackTo:self]; +} + + +- (void) packObject:(nullable NSObject*)object +{ + if (!object) + { + cw_pack_nil(_context); + return; + } + + BOOL isMsgpackObject = [object conformsToProtocol:@protocol(CWPackPackerClasses)]; + + if (_useLabels) + { + long label = [self labelForObject:object]; + if (label) // object already packed, just pack a reference. + { + cw_pack_array_size(_context,1); + cw_pack_ext_integer(_context, CWP_ITEM_OBJECT_MARKER, label); + return; + } + + cw_pack_array_size(_context, 2 + object.persistentAttributeCount); + label = [self assignLabelForObject:object isMsgpackObject:isMsgpackObject]; + cw_pack_ext_integer (_context, CWP_ITEM_OBJECT_MARKER, label); + if (isMsgpackObject) { + [(NSObject*)object cwPackPackerTo:self]; + } + else { + [self packUserObject:object]; + } + } + else if (isMsgpackObject) + { + [(NSObject*)object cwPackPackerTo:self]; + } + else + { + cw_pack_array_size(_context, 2 + object.persistentAttributeCount); + cw_pack_ext_integer (_context, CWP_ITEM_OBJECT_MARKER, 0); + [self packUserObject:object]; + } +} + +@end + + + +#pragma mark - +#pragma mark ************************************** CWUnpackContext + + + +@implementation CWUnpackContext +{ + NSMutableArray *_userReferences; + NSMutableArray *_packerReferences; +} + +- (instancetype)initWithContext:(cw_unpack_context*)context +{ + self = [super init]; + if (self) { + _context = context; + _userReferences = [NSMutableArray arrayWithObject:NSNull.null]; //no reference has value 0 + _packerReferences = [NSMutableArray arrayWithObject:NSNull.null]; //no reference has value 0 + } + return self; +} + + ++ (instancetype) newWithContext:(cw_unpack_context*)context +{ + return [self.alloc initWithContext:context]; +} + + +- (id) cwUnpackObject:(long)label +{ + id object; + + switch (_context->item.type) + { + case CWP_ITEM_NIL: + object = [NSNull null]; + break; + + case CWP_ITEM_BOOLEAN: + object = [NSNumber numberWithBool:_context->item.as.boolean]; + break; + + case CWP_ITEM_POSITIVE_INTEGER: + object = [NSNumber numberWithUnsignedLongLong:_context->item.as.u64]; + break; + + case CWP_ITEM_NEGATIVE_INTEGER: + object = [NSNumber numberWithLongLong:_context->item.as.i64]; + break; + + case CWP_ITEM_FLOAT: + object = [[NSNumber alloc] initWithFloat:_context->item.as.real]; + break; + + case CWP_ITEM_DOUBLE: + object = [NSNumber numberWithDouble:_context->item.as.long_real]; + break; + + case CWP_ITEM_STR: + { + object = [NSString.alloc initWithBytes:_context->item.as.str.start length:_context->item.as.str.length encoding:NSUTF8StringEncoding]; + if (!object) { + _context->return_code = CWP_RC_VALUE_ERROR; + return nil; + } + break; + } + + case CWP_ITEM_BIN: + { + object = [NSData dataWithBytes:_context->item.as.bin.start length:_context->item.as.bin.length]; + break; + } + + case CWP_ITEM_TIMESTAMP: + object = [NSDate dateWithTimeIntervalSince1970:_context->item.as.time.tv_sec + _context->item.as.time.tv_nsec / 1000000000.0]; + break; + + case CWP_ITEM_MAP: + { + int i, dim = _context->item.as.map.size; + NSMutableDictionary *dict = NSMutableDictionary.new; + if (label) [_packerReferences addObject:dict]; + for(i = 0; i < dim; i++) + { + id key = [self cwUnpackNextObjectSub:0]; + id val = [self cwUnpackNextObjectSub:0]; + if (_context->return_code == CWP_RC_OK) + dict[key] = val; + } + return dict; + } + + case CWP_ITEM_ARRAY: + { + int dim = _context->item.as.array.size; + if (dim == 0) + { + object = NSMutableArray.new; + } + else + { + cw_unpack_next(_context); + if (_context->item.type == CWP_ITEM_OBJECT_MARKER) //object + { + long idx = get_ext_integer(_context); + if (dim == 1) // object reference + { + if ((idx<0)? (-idx >= _packerReferences.count) : (idx >= _userReferences.count)) + { + _context->return_code = CWP_RC_VALUE_ERROR; + return nil; + } + return idx>0 ? _userReferences[idx] : _packerReferences[-idx]; + } + if (idx < 0) // we had a labeled MessagePack object + { + if (dim != 2) + { + _context->return_code = CWP_RC_VALUE_ERROR; + return nil; + } + return [self cwUnpackNextObjectSub:idx]; + } + + NSString *objClassName = [self cwUnpackNextObjectSub:0]; + Class objClass = NSClassFromString(objClassName); + + if (!objClass) + object = [CWPackGenericClass newWithClassName:objClassName]; + else + object = [objClass alloc]; + object = [object cwUnpackSubInit:self remainingAttributes:dim - 2]; + if (idx == _userReferences.count) + { + [_userReferences addObject:object]; + } + else + { + if (idx != 0) + { + _context->return_code = CWP_RC_VALUE_ERROR; + return nil; + } + } + [object cwUnpackSub:self remainingAttributes:dim - 2]; + return object; + } + else // standard MsgPack array + { + int i; + NSMutableArray *arr = NSMutableArray.new; + if (label) [_packerReferences addObject:arr]; + id item = [self cwUnpackObject:0]; + if (_context->return_code == CWP_RC_OK) + [arr addObject:item]; + for(i = 1; i < dim; i++) + { + id item = [self cwUnpackNextObjectSub:0]; + if (_context->return_code == CWP_RC_OK) + [arr addObject:item]; + } + return arr; + } + } + } + + default: + object = [CWPackExternalItem itemWithType:_context->item.type + data:[NSData dataWithBytes:_context->item.as.ext.start length:_context->item.as.ext.length]]; + } + if (label) + { + if (label != -_packerReferences.count) + _context->return_code = CWP_RC_MALFORMED_INPUT; + else + [_packerReferences addObject:object]; + } + return object; +} + + +- (id) cwUnpackNextObjectSub:(long)label +{ + cw_unpack_next(_context); + if (_context->return_code) + return nil; + return [self cwUnpackObject:label]; +} + + +- (id) unpackNextObject +{ + id result = [self cwUnpackNextObjectSub:0]; + if (result == [NSNull null]) + return nil; + return result; +} + +@end + + + +#pragma mark ************************************** NSObject + + + +@implementation NSObject (CWPackable) + +- (int) persistentAttributeCount {return 0;} + +- (NSString*) packerClassName {return self.className;} + +- (void) cwPackTo:(CWPackContext*)ctx +{ + cw_pack_cstr(ctx.context, self.packerClassName.UTF8String); + [self cwPackSub:ctx]; +} + +- (void) cwPackSub:(CWPackContext*)ctx; +{ + [NSException raise:@"Object Not Packable" format:@"Class \"%s\" does not conform to protocol \n", object_getClassName(self)]; +} + +- (void) cwUnpackSub:(CWUnpackContext*)ctx remainingAttributes:(int)remainingAttributes +{ + [NSException raise:@"Object Not Unpackable" format:@"Class \"%s\" does not conform to protocol \n", object_getClassName(self)]; +} + +- (instancetype) cwUnpackSubInit:(CWUnpackContext*)ctx remainingAttributes:(int)remainingAttributes +{ + return self.init; +} + +@end + + +#pragma mark ************************************** NSNull + +@interface NSNull (CWPackable) +@end + + +@implementation NSNull (CWPackable) + +- (void) cwPackPackerTo:(CWPackContext*)ctx +{ + cw_pack_nil (ctx.context); +} +@end + + + +#pragma mark ************************************** NSString, NSMutableString + + +@interface NSString (CWPackable) +@end + + +@implementation NSString (CWPackable) + +- (void) cwPackPackerTo:(CWPackContext*)ctx +{ + cw_pack_cstr (ctx.context, self.UTF8String); +} +@end + + +#pragma mark ************************************** NSData + +@interface NSData (CWPackable) +@end + +@implementation NSData (CWPackable) + +- (void) cwPackPackerTo:(CWPackContext*)ctx +{ + cw_pack_bin(ctx.context, self.bytes, (uint32_t)self.length); +} +@end + + + +#pragma mark ************************************** NSDate + +@interface NSDate (CWPackable) +@end + +@implementation NSDate (CWPackable) + +- (void) cwPackPackerTo:(CWPackContext*)ctx +{ + NSTimeInterval ti = self.timeIntervalSince1970; + cw_pack_time_interval (ctx.context, ti); +} +@end + + +#pragma mark ************************************** NSNumber + +@interface NSNumber (CWPackable) +@end + +@implementation NSNumber (CWPackable) + +- (void) cwPackPackerTo:(CWPackContext*)ctx +{ + CFNumberType numberType = CFNumberGetType((CFNumberRef)self); + switch (numberType) + { + case kCFNumberSInt8Type: + case kCFNumberSInt16Type: + case kCFNumberSInt32Type: + case kCFNumberSInt64Type: + case kCFNumberShortType: + case kCFNumberIntType: + case kCFNumberLongType: + case kCFNumberCFIndexType: + case kCFNumberNSIntegerType: + case kCFNumberLongLongType: + cw_pack_signed(ctx.context, self.longLongValue); + return; + + case kCFNumberFloat32Type: + case kCFNumberFloatType: + case kCFNumberCGFloatType: + cw_pack_float(ctx.context, self.floatValue); + return; + + case kCFNumberFloat64Type: + case kCFNumberDoubleType: + cw_pack_double(ctx.context, self.doubleValue); + return; + + case kCFNumberCharType: + { + int theValue = self.intValue; + if (theValue == 0) + { + cw_pack_boolean(ctx.context, NO); + } + if (theValue == 1) + { + cw_pack_boolean(ctx.context, YES); + } + else + { + cw_pack_signed(ctx.context, theValue); + } + return; + } + default: + ctx.context->return_code = CWP_RC_ILLEGAL_CALL; // No pack defined for this object type + [NSException raise:@"[NSNumber packIn:]" format:@"Cannot recognise type (%ld) of: %@", (long)numberType, self]; + } +} +@end + + +#pragma mark ************************************** NSArray + +@interface NSArray (CWPackable) +@end + +@implementation NSArray (CWPackable) + +- (void) cwPackPackerTo:(CWPackContext*)ctx +{ + uint32_t i, cnt = (uint32_t)self.count; + cw_pack_array_size(ctx.context, cnt); + for (i = 0; i < cnt; i++) + [ctx packObject:self[i]]; +} +@end + + +#pragma mark ************************************** NSDictionary + + +@interface NSDictionary (CWPackable) +@end + + +@implementation NSDictionary (CWPackable) + +- (void) cwPackPackerTo:(CWPackContext*)ctx +{ + cw_pack_map_size(ctx.context, (uint32_t)self.count); + for (id obj in self) + { + [ctx packObject:obj]; + [ctx packObject:self[obj]]; + } +} +@end + + +#pragma mark ************************************** CWPackExternalItem + + +@interface CWPackExternalItem (CWPackable) +@end + + +@implementation CWPackExternalItem + +- (instancetype) initWithType:(int)type data:(NSData*)data +{ + self = [super init]; + if (self) { + _type = type; + _data = data; + } + return self; +} + + ++ (instancetype) itemWithType:(int)type data:(NSData*)data; +{ + return [[self alloc] initWithType:type data:data]; +} + + +- (void) cwPackPackerTo:(CWPackContext*)ctx +{ + cw_pack_ext(ctx.context, _type, _data.bytes, (int)_data.length); +} + +@end + + +#pragma mark - +#pragma mark ************************************** CWPackGenericClass + + +@implementation CWPackGenericClass + +- (instancetype)initWithClassName:(NSString*)className +{ + self = [self init]; + if (self) { + _packerClassName = className; + } + return self; +} + ++ (instancetype) newWithClassName:(NSString*)className {return [self.alloc initWithClassName:className];} + +- (int) persistentAttributeCount {return (int)_attributes.count;} + +- (void) cwPackSub:(CWPackContext*)ctx +{ + for (id o in _attributes) {[ctx packObject:o];} +} + +- (void) cwUnpackSub:(CWUnpackContext*)ctx remainingAttributes:(int)remainingAttributes +{ + _attributes = NSMutableArray.new; + int i; + for (i = 0; i < remainingAttributes; i++) { + id item = [ctx cwUnpackNextObjectSub:0]; + if (ctx.context->return_code == CWP_RC_OK) + [_attributes addObject:item]; + } +} + +@end + + +#pragma mark ************************************** NSSet + +@interface NSSet (CWPackable) +@end + +@implementation NSSet (CWPackable) +- (int) persistentAttributeCount {return (int)self.count + super.persistentAttributeCount;} + +- (NSString*) packerClassName {return @"NSSet";} + +- (void) cwPackSub:(CWPackContext*)ctx +{ + for (id object in self) + [ctx packObject:object]; +} + +- (instancetype) cwUnpackSubInit:(CWUnpackContext*)ctx remainingAttributes:(int)remainingAttributes +{ + return NSMutableSet.new; +} + +@end + + +@interface NSMutableSet (CWPackable) +@end + +@implementation NSMutableSet (CWPackable) +- (instancetype) cwUnpackSub:(CWUnpackContext*)ctx remainingAttributes:(int)remainingAttributes +{ + int i; + for (i=0; i + +@interface NSCountedSet (CWPackable) +@end + +@implementation NSCountedSet (CWPackable) +- (int) persistentAttributeCount {return 2*(int)self.count + super.persistentAttributeCount;} + +- (void) cwPackSub:(CWPackContext*)ctx +{ + for (id object in self) + { + [ctx packObject:object]; + cw_pack_signed(ctx.context, [self countForObject:object]); + } +} + +- (instancetype) cwUnpackSubInit:(CWUnpackContext*)ctx remainingAttributes:(int)remainingAttributes +{ + return [self initWithCapacity:remainingAttributes/2]; +} + +- (instancetype) cwUnpackSub:(CWUnpackContext*)ctx remainingAttributes:(int)remainingAttributes +{ + long count = remainingAttributes/2; + int i; + for (i=0; i +@property int level; +@property MyClass *link; +- (instancetype) initWithLevel:(int)level link:(MyClass*)link; @end +``` +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: -@implementation myClass -- (void) packIn:(cw_pack_context*) buff -{ - cw_pack_signed( buff, theInt ); - [theSet packIn:buff]; +```C +- (void) cwPackSub:(CWPackContext*)ctx { + [super cwPackSub:ctx]; + cw_pack_signed(ctx.context, level); + [ctx packObject:link]; } -+ (instancetype) unpackFrom:(cw_unpack_context*) buff -{ - int anInt = cw_unpack_next_signed32( buff ); - NSMutableSet aSet = [NSMutableSet unpackFrom:buff]; - return [[self alloc] initWithInt:anInt set:aSet]; +``` +If the immediate ancestor to MyClass is NSObject, then super must not be called. + +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. + +Step 1: Allocation & Initiating + +##### - (instancetype) cwUnpackSubInit:(CWUnpackContext*)ctx remainingAttributes:(int)remainingAttributes + + +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. + +Step 2: Fetching attributes. + +##### - (void) cwUnpackSub:(CWUnpackContext*)ctx remainingAttributes:(int)remainingAttributes + +In the pack example an unpack method could be: + +```C +- (void) cwUnpackSub:(CWUnpackContext*)ctx remainingAttributes:(int)remainingAttributes { + [super cwUnpackSub:ctx remainingAttributes:remainingAttributes - 2] + level = cw_unpack_next_signed32 (ctx.context); + link = [ctx unpackNextObject]; } -@end ``` +As usual, don't call super on NSObject. + +### Packable system objects +(Un)packing of the following system classes is predefined in ObjC: +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. + +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. + +### Special +There are two special cases. + +First, when the MessagePack item is of an unknown EXT type, it will be unpacked as an instance of the `CWPackExternalItem` class. +Second, when the object to be unpacked is of unknown user class, it is unpacked as an instance of the class `CWPackGenericClass`. diff --git a/goodies/objC/Technique.md b/goodies/objC/Technique.md new file mode 100755 index 0000000..34851ee --- /dev/null +++ b/goodies/objC/Technique.md @@ -0,0 +1,60 @@ +# CWPack / Goodies / ObjC / Technique + +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. + +### User objects + +We have an example: + +```C +@interface MyClass: NSObject +@property int level; +@property MyClass *link; +- (instancetype) initWithLevel:(int)level link:(MyClass*)link; +@end +``` +When packed into a MessagePack stream it may look like: + +```C +[(127,<00>) "MyClass" 37 NULL] +``` +This was the simple example where the link was nil. But look at this code fragment: + +```C +MyClass *a = [MyClass.alloc initWithLevel:10 link:nil]; +MyClass *b = [MyClass.alloc initWithLevel:20 link:a]; +a.link = b; +[myContext packObject:a]; +``` +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: + +```C +[(127,<01>) // object a got the label 1, we note that in a table +[(127,<01>) "MyClass" 10 [(127,<02>) "MyClass" 20 +``` +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: + +```C +[(127,<01>) "MyClass" 10 [(127,<02>) "MyClass" 20 [(127,<01>)]]] +``` +The cwpack dump utility "knows" object markers and prints the above message as: + +1->MyClass(10 2->MyClass(20 ->1)) + +### MessagePack objects + +It is not just user objects that can contain circular references. Take this example: + +```C +NSMutableArray *a = NSMutableArray.new; +[a addObject:a]; +[myContext packObject:a]; +``` +Obviously we need a way to label MessagePack objects also. We do as for user objects, but instead for a class-name in the second slot we put the MessagePack object. In this case, there are just 2 slots. + +There is one problem here. If the MessagePack object is a string, it looks exactly like an user object with no attributes. We solve this ambiguity by letting MessagePack objects have negative labels starting with -1. So the packing above becomes: + +```C +[(127,) [[(127,)]]] +``` +Or prettyprinted: -1->[-> -1] diff --git a/goodies/objC/obsolete/README.md b/goodies/objC/obsolete/README.md new file mode 100755 index 0000000..a2aa1cf --- /dev/null +++ b/goodies/objC/obsolete/README.md @@ -0,0 +1,40 @@ +# CWPack / Goodies / ObjC + + +ObjC contains a wrapper for objective-C in the form of a category to NSObject. +The category contains two methods: + +```C +/* *********************** P A C K *****************************/ +- (void) packIn:(cw_pack_context*) buff; + +/* *********************** U N P A C K *************************/ ++ (instancetype) unpackFrom:(cw_unpack_context*) buff; +``` + +The methods are defined for the standard classes NSString, NSData, NSNumber, NSDate, NSNull, NSDictionary, NSArray and NSSet. + +For other classes you need to define the methods yourself. E.g. + +```C +@interface myClass: NSObject { + int theInt; + NSMutableSet theSet; +} +@end + +@implementation myClass +- (void) packIn:(cw_pack_context*) buff +{ + cw_pack_signed( buff, theInt ); + [theSet packIn:buff]; +} ++ (instancetype) unpackFrom:(cw_unpack_context*) buff +{ + int anInt = cw_unpack_next_signed32( buff ); + NSMutableSet aSet = [NSMutableSet unpackFrom:buff]; + return [[self alloc] initWithInt:anInt set:aSet]; +} +@end +``` + diff --git a/goodies/objC/cwpack_objc.h b/goodies/objC/obsolete/cwpack_objc.h similarity index 100% rename from goodies/objC/cwpack_objc.h rename to goodies/objC/obsolete/cwpack_objc.h diff --git a/goodies/objC/cwpack_objc.m b/goodies/objC/obsolete/cwpack_objc.m similarity index 100% rename from goodies/objC/cwpack_objc.m rename to goodies/objC/obsolete/cwpack_objc.m From 0d36a9c1b38f6f045105258dbb76809b3ffaceaa Mon Sep 17 00:00:00 2001 From: clwi Date: Thu, 11 Mar 2021 00:48:07 +0100 Subject: [PATCH 10/10] Bugfix --- goodies/objC/CWPackContext.m | 1 + 1 file changed, 1 insertion(+) diff --git a/goodies/objC/CWPackContext.m b/goodies/objC/CWPackContext.m index 3038d1b..a5501a9 100644 --- a/goodies/objC/CWPackContext.m +++ b/goodies/objC/CWPackContext.m @@ -245,6 +245,7 @@ - (id) cwUnpackObject:(long)label if (dim == 0) { object = NSMutableArray.new; + break; } else {