1*1c60b9acSAndroid Build Coastguard Worker# RFC8949 CBOR Stream Parsing and Writing 2*1c60b9acSAndroid Build Coastguard Worker 3*1c60b9acSAndroid Build Coastguard Worker||| 4*1c60b9acSAndroid Build Coastguard Worker|---|---|---| 5*1c60b9acSAndroid Build Coastguard Worker|cmake| `LWS_WITH_CBOR`, `LWS_WITH_CBOR_FLOAT`| 6*1c60b9acSAndroid Build Coastguard Worker|Header| ./include/libwebsockets/lws-lecp.h| 7*1c60b9acSAndroid Build Coastguard Worker|api-test| ./minimal-examples/api-tests/api-test-lecp/| 8*1c60b9acSAndroid Build Coastguard Worker|test app| ./test-apps/test-lecp.c -> libwebsockets-test-lecp| 9*1c60b9acSAndroid Build Coastguard Worker 10*1c60b9acSAndroid Build Coastguard WorkerLECP is the RFC8949 CBOR stream parsing counterpart to LEJP for JSON. 11*1c60b9acSAndroid Build Coastguard Worker 12*1c60b9acSAndroid Build Coastguard Worker## Features 13*1c60b9acSAndroid Build Coastguard Worker 14*1c60b9acSAndroid Build Coastguard Worker - Completely immune to input fragmentation, give it any size blocks of CBOR as 15*1c60b9acSAndroid Build Coastguard Worker they become available; 1 byte, or 100K at a time give identical parsing 16*1c60b9acSAndroid Build Coastguard Worker results 17*1c60b9acSAndroid Build Coastguard Worker - Input chunks discarded as they are parsed, whole CBOR never needed in memory 18*1c60b9acSAndroid Build Coastguard Worker - Nonrecursive, fixed stack usage of a few dozen bytes 19*1c60b9acSAndroid Build Coastguard Worker - No heap allocations at all, just requires ~500 byte context usually on 20*1c60b9acSAndroid Build Coastguard Worker caller stack 21*1c60b9acSAndroid Build Coastguard Worker - Creates callbacks to a user-provided handler as members are parsed out 22*1c60b9acSAndroid Build Coastguard Worker - No payload size limit, supports huge / endless strings or blobs bigger than 23*1c60b9acSAndroid Build Coastguard Worker system memory 24*1c60b9acSAndroid Build Coastguard Worker - Collates utf-8 text and blob payloads into a 250-byte chunk buffer for ease 25*1c60b9acSAndroid Build Coastguard Worker of access 26*1c60b9acSAndroid Build Coastguard Worker - Write apis don't use any heap allocations or recursion either 27*1c60b9acSAndroid Build Coastguard Worker - Write apis use an explicit context with its own lifecycle, and printf style 28*1c60b9acSAndroid Build Coastguard Worker vaargs including sized blobs, C strings, double, int, unsigned long etc 29*1c60b9acSAndroid Build Coastguard Worker - Completely immune to output fragmentation, supports huge strings and blobs 30*1c60b9acSAndroid Build Coastguard Worker into small buffers, api returns to indicates unfinished if it needs to be 31*1c60b9acSAndroid Build Coastguard Worker called again to continue; 1 byte or 100K output buffer give same results 32*1c60b9acSAndroid Build Coastguard Worker - Write apis completely fill available buffer and if unfinished, continues 33*1c60b9acSAndroid Build Coastguard Worker into same or different buffer when called again with same args; no 34*1c60b9acSAndroid Build Coastguard Worker requirement for subsequent calls to be done sequentially or even from same 35*1c60b9acSAndroid Build Coastguard Worker function 36*1c60b9acSAndroid Build Coastguard Worker 37*1c60b9acSAndroid Build Coastguard Worker## Type limits 38*1c60b9acSAndroid Build Coastguard Worker 39*1c60b9acSAndroid Build Coastguard WorkerCBOR allows negative integers of up to 64 bits, these do not fit into a `uint64_t`. 40*1c60b9acSAndroid Build Coastguard WorkerLECP has a union for numbers that includes the types `uint64_t` and `int64_t`, 41*1c60b9acSAndroid Build Coastguard Workerbut it does not separately handle negative integers. Only -2^63.. 2^64 -1 can 42*1c60b9acSAndroid Build Coastguard Workerbe handled by the C types, the oversize negative numbers wrap and should be 43*1c60b9acSAndroid Build Coastguard Workeravoided. 44*1c60b9acSAndroid Build Coastguard Worker 45*1c60b9acSAndroid Build Coastguard Worker## Floating point support 46*1c60b9acSAndroid Build Coastguard Worker 47*1c60b9acSAndroid Build Coastguard WorkerFloats are handled using the IEEE memory format, it means they can be parsed 48*1c60b9acSAndroid Build Coastguard Workerfrom the CBOR without needing any floating point support in the build. If 49*1c60b9acSAndroid Build Coastguard Workerfloating point is available, you can also enable `LWS_WITH_CBOR_FLOAT` and 50*1c60b9acSAndroid Build Coastguard Workera `float` and `double` types are available in the number item union. Otherwise 51*1c60b9acSAndroid Build Coastguard Workerthese are handled as `ctx->item.u.u32` and `ctx->item.u.u64` union members. 52*1c60b9acSAndroid Build Coastguard Worker 53*1c60b9acSAndroid Build Coastguard WorkerHalf-float (16-bit) is defined in CBOR and always handled as a `uint16_t` 54*1c60b9acSAndroid Build Coastguard Workernumber union member `ctx->item.u.hf`. 55*1c60b9acSAndroid Build Coastguard Worker 56*1c60b9acSAndroid Build Coastguard Worker## Callback reasons 57*1c60b9acSAndroid Build Coastguard Worker 58*1c60b9acSAndroid Build Coastguard WorkerThe user callback does not have to handle any callbacks, it only needs to 59*1c60b9acSAndroid Build Coastguard Workerprocess the data for the ones it is interested in. 60*1c60b9acSAndroid Build Coastguard Worker 61*1c60b9acSAndroid Build Coastguard Worker|Callback reason|CBOR structure|Associated data| 62*1c60b9acSAndroid Build Coastguard Worker|---|---|---| 63*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_CONSTRUCTED`|Created the parse context|| 64*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_DESTRUCTED`|Destroyed the parse context|| 65*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_COMPLETE`|The parsing completed OK|| 66*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_FAILED`|The parsing failed|| 67*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_VAL_TRUE`|boolean true|| 68*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_VAL_FALSE`|boolean false|| 69*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_VAL_NULL`|explicit NULL|| 70*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_VAL_NUM_INT`|signed integer|`ctx->item.u.i64`| 71*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_VAL_STR_START`|A UTF-8 string is starting|| 72*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_VAL_STR_CHUNK`|The next string chunk|`ctx->npos` bytes in `ctx->buf`| 73*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_VAL_STR_END`|The last string chunk|`ctx->npos` bytes in `ctx->buf`| 74*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_ARRAY_START`|An array is starting|| 75*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_ARRAY_END`|An array has ended|| 76*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_OBJECT_START`|A CBOR map is starting|| 77*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_OBJECT_END`|A CBOR map has ended|| 78*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_TAG_START`|The following data has a tag index|`ctx->item.u.u64`| 79*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_TAG_END`|The end of the data referenced by the last tag|| 80*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_VAL_NUM_UINT`|Unsigned integer|`ctx->item.u.u64`| 81*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_VAL_UNDEFINED`|CBOR undefined|| 82*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_VAL_FLOAT16`|half-float available as host-endian `uint16_t`|`ctx->item.u.hf`| 83*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_VAL_FLOAT32`|`float` (`uint32_t` if no float support) available|`ctx->item.u.f`| 84*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_VAL_FLOAT64`|`double` (`uint64_t` if no float support) available|`ctx->item.u.d`| 85*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_VAL_SIMPLE`|CBOR simple|`ctx->item.u.u64`| 86*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_VAL_BLOB_START`|A binary blob is starting|| 87*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_VAL_BLOB_CHUNK`|The next blob chunk|`ctx->npos` bytes in `ctx->buf`| 88*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_VAL_BLOB_END`|The last blob chunk|`ctx->npos` bytes in `ctx->buf`| 89*1c60b9acSAndroid Build Coastguard Worker|`LECPCB_ARRAY_ITEM_START`|A logical item in an array is starting| 90*1c60b9acSAndroid Build Coastguard Worker|`LCEPDB_ARRAY_ITEM_END`|A logical item in an array has completed| 91*1c60b9acSAndroid Build Coastguard Worker 92*1c60b9acSAndroid Build Coastguard Worker## CBOR indeterminite lengths 93*1c60b9acSAndroid Build Coastguard Worker 94*1c60b9acSAndroid Build Coastguard WorkerIndeterminite lengths are supported, but are concealed in the parser as far as 95*1c60b9acSAndroid Build Coastguard Workerpossible, the CBOR lengths or its indeterminacy are not exposed in the callback 96*1c60b9acSAndroid Build Coastguard Workerinterface at all, just chunks of data that may be the start, the middle, or the 97*1c60b9acSAndroid Build Coastguard Workerend. 98*1c60b9acSAndroid Build Coastguard Worker 99*1c60b9acSAndroid Build Coastguard Worker## Handling CBOR UTF-8 strings and blobs 100*1c60b9acSAndroid Build Coastguard Worker 101*1c60b9acSAndroid Build Coastguard WorkerWhen a string or blob is parsed, an advisory callback of `LECPCB_VAL_STR_START` or 102*1c60b9acSAndroid Build Coastguard Worker`LECPCB_VAL_BLOB_START` occurs first. The `_STR_` callbacks indicate the 103*1c60b9acSAndroid Build Coastguard Workercontent is a CBOR UTF-8 string, `_BLOB_` indicates it is binary data. 104*1c60b9acSAndroid Build Coastguard Worker 105*1c60b9acSAndroid Build Coastguard WorkerStrings or blobs may have indeterminite length, but if so, they are composed 106*1c60b9acSAndroid Build Coastguard Workerof logical chunks which must have known lengths. When the `_START` callback 107*1c60b9acSAndroid Build Coastguard Workeroccurs, the logical length either of the whole string, or of the sub-chunk if 108*1c60b9acSAndroid Build Coastguard Workerindeterminite length, can be found in `ctx->item.u.u64`. 109*1c60b9acSAndroid Build Coastguard Worker 110*1c60b9acSAndroid Build Coastguard WorkerPayload is collated into `ctx->buf[]`, the valid length is in `ctx->npos`. 111*1c60b9acSAndroid Build Coastguard Worker 112*1c60b9acSAndroid Build Coastguard WorkerFor short strings or blobs where the length is known, the whole payload is 113*1c60b9acSAndroid Build Coastguard Workerdelivered in a single `LECPCB_VAL_STR_END` or `LECPCB_VAL_BLOB_END` callback. 114*1c60b9acSAndroid Build Coastguard Worker 115*1c60b9acSAndroid Build Coastguard WorkerFor payloads larger than the size of `ctx->buf[]`, `LECPCB_VAL_STR_CHUNK` or 116*1c60b9acSAndroid Build Coastguard Worker`LECPCB_VAL_BLOB_CHUNK` callbacks occur delivering each sequential bufferload. 117*1c60b9acSAndroid Build Coastguard WorkerIf the CBOR indicates the total length, the last chunk is delievered in a 118*1c60b9acSAndroid Build Coastguard Worker`LECPCB_VAL_STR_END` or `LECPCB_VAL_BLOB_END`. 119*1c60b9acSAndroid Build Coastguard Worker 120*1c60b9acSAndroid Build Coastguard WorkerIf the CBOR indicates the string end after the chunk, a zero-length `..._END` 121*1c60b9acSAndroid Build Coastguard Workercallback is provided. 122*1c60b9acSAndroid Build Coastguard Worker 123*1c60b9acSAndroid Build Coastguard Worker## Handling CBOR tags 124*1c60b9acSAndroid Build Coastguard Worker 125*1c60b9acSAndroid Build Coastguard WorkerCBOR tags are exposed as `LECPCB_TAG_START` and `LECPCB_TAG_END` pairs, at 126*1c60b9acSAndroid Build Coastguard Workerthe `_START` callback the tag index is available in `ctx->item.u.u64`. 127*1c60b9acSAndroid Build Coastguard Worker 128*1c60b9acSAndroid Build Coastguard Worker## CBOR maps 129*1c60b9acSAndroid Build Coastguard Worker 130*1c60b9acSAndroid Build Coastguard WorkerYou can check if you are on the "key" part of a map "key:value" pair using the 131*1c60b9acSAndroid Build Coastguard Workerhelper api `lecp_parse_map_is_key(ctx)`. 132*1c60b9acSAndroid Build Coastguard Worker 133*1c60b9acSAndroid Build Coastguard Worker## Parsing paths 134*1c60b9acSAndroid Build Coastguard Worker 135*1c60b9acSAndroid Build Coastguard WorkerLECP maintains a "parsing path" in `ctx->path` that represents the context of 136*1c60b9acSAndroid Build Coastguard Workerthe callback events. As a convenience, at LECP context creation time, you can 137*1c60b9acSAndroid Build Coastguard Workerpass in an array of path strings you want to match on, and have any match 138*1c60b9acSAndroid Build Coastguard Workercheckable in the callback using `ctx->path_match`, it's 0 if no active match, 139*1c60b9acSAndroid Build Coastguard Workeror the match index from your path array starting from 1 for the first entry. 140*1c60b9acSAndroid Build Coastguard Worker 141*1c60b9acSAndroid Build Coastguard Worker|CBOR element|Representation in path| 142*1c60b9acSAndroid Build Coastguard Worker|---|---| 143*1c60b9acSAndroid Build Coastguard Worker|CBOR Array|`[]`| 144*1c60b9acSAndroid Build Coastguard Worker|CBOR Map|`.`| 145*1c60b9acSAndroid Build Coastguard Worker|CBOR Map entry key string|`keystring`| 146*1c60b9acSAndroid Build Coastguard Worker 147*1c60b9acSAndroid Build Coastguard Worker## Accessing raw CBOR subtrees 148*1c60b9acSAndroid Build Coastguard Worker 149*1c60b9acSAndroid Build Coastguard WorkerSome CBOR usages like COSE require access to selected raw CBOR from the input 150*1c60b9acSAndroid Build Coastguard Workerstream. `lecp_parse_report_raw(ctx, on)` lets you turn on and off buffering of 151*1c60b9acSAndroid Build Coastguard Workerraw CBOR and reporting it in the parse callback with `LECPCB_LITERAL_CBOR` 152*1c60b9acSAndroid Build Coastguard Workercallbacks. The callbacks mean the temp buffer `ctx->cbor[]` has `ctx->cbor_pos` 153*1c60b9acSAndroid Build Coastguard Workerbytes of raw CBOR available in it. Callbacks are triggered when the buffer 154*1c60b9acSAndroid Build Coastguard Workerfills, or reporting is turned off and the buffer has something in it. 155*1c60b9acSAndroid Build Coastguard Worker 156*1c60b9acSAndroid Build Coastguard WorkerBy turning the reporting on and off according to the outer CBOR parsing state, 157*1c60b9acSAndroid Build Coastguard Workerit's possible to get exactly the raw CBOR subtree that's needed. 158*1c60b9acSAndroid Build Coastguard Worker 159*1c60b9acSAndroid Build Coastguard WorkerCapturing and reporting the raw CBOR does not change that the same CBOR is being 160*1c60b9acSAndroid Build Coastguard Workerpassed to the parser as usual as well. 161*1c60b9acSAndroid Build Coastguard Worker 162*1c60b9acSAndroid Build Coastguard Worker## Comparison with LEJP (JSON parser) 163*1c60b9acSAndroid Build Coastguard Worker 164*1c60b9acSAndroid Build Coastguard WorkerLECP is based on the same principles as LEJP and shares most of the callbacks. 165*1c60b9acSAndroid Build Coastguard WorkerThe major differences: 166*1c60b9acSAndroid Build Coastguard Worker 167*1c60b9acSAndroid Build Coastguard Worker - LEJP value callbacks all appear in `ctx->buf[]`, ie, floating-point is 168*1c60b9acSAndroid Build Coastguard Worker provided to the callback in ascii form like `"1.0"`. CBOR provides a more 169*1c60b9acSAndroid Build Coastguard Worker strict typing system, and the different type values are provided either in 170*1c60b9acSAndroid Build Coastguard Worker `ctx->buf[]` for blobs or utf-8 text strtings, or the `item.u` union for 171*1c60b9acSAndroid Build Coastguard Worker converted types, with additional callback reasons specific to each type. 172*1c60b9acSAndroid Build Coastguard Worker 173*1c60b9acSAndroid Build Coastguard Worker - CBOR "maps" use `_OBJECT_START` and `_END` parsing callbacks around the 174*1c60b9acSAndroid Build Coastguard Worker key / value pairs. LEJP has a special callback type `PAIR_NAME` for the 175*1c60b9acSAndroid Build Coastguard Worker key string / integer, but in LECP these are provided as generic callbacks 176*1c60b9acSAndroid Build Coastguard Worker dependent on type, ie, generic string callbacks or integer ones, and the 177*1c60b9acSAndroid Build Coastguard Worker value part is represented according to whatever comes. 178*1c60b9acSAndroid Build Coastguard Worker 179*1c60b9acSAndroid Build Coastguard Worker 180*1c60b9acSAndroid Build Coastguard Worker# Writing CBOR 181*1c60b9acSAndroid Build Coastguard Worker 182*1c60b9acSAndroid Build Coastguard WorkerCBOR is written into a `lws_lec_pctx_t` object that has been initialized to 183*1c60b9acSAndroid Build Coastguard Workerpoint to an output buffer of a specified size, using printf type formatting. 184*1c60b9acSAndroid Build Coastguard Worker 185*1c60b9acSAndroid Build Coastguard WorkerOutput is paused if the buffer fills, and the write api may be called again 186*1c60b9acSAndroid Build Coastguard Workerlater with the same context object, to resume emitting to the same or different 187*1c60b9acSAndroid Build Coastguard Workerbuffer. 188*1c60b9acSAndroid Build Coastguard Worker 189*1c60b9acSAndroid Build Coastguard WorkerThis allows bufferloads of encoded CBOR to be produced on demand, it's designed 190*1c60b9acSAndroid Build Coastguard Workerto fit usage in WRITEABLE callbacks and Secure Streams tx() callbacks where the 191*1c60b9acSAndroid Build Coastguard Workerbuffer size for one packet is already fixed. 192*1c60b9acSAndroid Build Coastguard Worker 193*1c60b9acSAndroid Build Coastguard WorkerCBOR array and map lengths are deduced from the format string, as is whether to 194*1c60b9acSAndroid Build Coastguard Workeruse indeterminite length formatting or not. For indeterminite text or binary 195*1c60b9acSAndroid Build Coastguard Workerstrings, a container of < > 196*1c60b9acSAndroid Build Coastguard Worker 197*1c60b9acSAndroid Build Coastguard Worker|Format|Arg(s)|Meaning| 198*1c60b9acSAndroid Build Coastguard Worker|---|---|---| 199*1c60b9acSAndroid Build Coastguard Worker|`123`||unsigned literal number| 200*1c60b9acSAndroid Build Coastguard Worker|`-123`||signed literal number| 201*1c60b9acSAndroid Build Coastguard Worker|`%u`|`unsigned int`|number| 202*1c60b9acSAndroid Build Coastguard Worker|`%lu`|`unsigned long int`|number| 203*1c60b9acSAndroid Build Coastguard Worker|`%llu`|`unsigned long long int`|number| 204*1c60b9acSAndroid Build Coastguard Worker|`%d`|`signed int`|number| 205*1c60b9acSAndroid Build Coastguard Worker|`%ld`|`signed long int`|number| 206*1c60b9acSAndroid Build Coastguard Worker|`%lld`|`signed long long int`|number| 207*1c60b9acSAndroid Build Coastguard Worker|`%f`|`double`|floating point number| 208*1c60b9acSAndroid Build Coastguard Worker|`123(...)`||literal tag and scope| 209*1c60b9acSAndroid Build Coastguard Worker|`%t(...)`|`unsigned int`|tag and scope| 210*1c60b9acSAndroid Build Coastguard Worker|`%lt(...)`|`unsigned long int`|tag and scope| 211*1c60b9acSAndroid Build Coastguard Worker|`%llt(...)`|`unsigned long long int`|tag and scope| 212*1c60b9acSAndroid Build Coastguard Worker|`[...]`||Array (fixed len if `]` in same format string)| 213*1c60b9acSAndroid Build Coastguard Worker|`{...}`||Map (fixed len if `}` in same format string)| 214*1c60b9acSAndroid Build Coastguard Worker|`<t...>`||Container for indeterminite text string frags| 215*1c60b9acSAndroid Build Coastguard Worker|`<b...>`||Container for indeterminite binary string frags| 216*1c60b9acSAndroid Build Coastguard Worker|`'string'`||Literal text of known length| 217*1c60b9acSAndroid Build Coastguard Worker|`%s`|`const char *`|NUL-terminated string| 218*1c60b9acSAndroid Build Coastguard Worker|`%.*s`|`int`, `const char *`|length-specified string| 219*1c60b9acSAndroid Build Coastguard Worker|`%.*b`|`int`, `const uint8_t *`|length-specified binary| 220*1c60b9acSAndroid Build Coastguard Worker|`:`||separator between Map items (a:b)| 221*1c60b9acSAndroid Build Coastguard Worker|`,`||separator between Map pairs or array items| 222*1c60b9acSAndroid Build Coastguard Worker 223*1c60b9acSAndroid Build Coastguard WorkerBackslash is used as an escape in `'...'` literal strings, so `'\\'` represents 224*1c60b9acSAndroid Build Coastguard Workera string consisting of a single backslash, and `'\''` a string consisting of a 225*1c60b9acSAndroid Build Coastguard Workersingle single-quote. 226*1c60b9acSAndroid Build Coastguard Worker 227*1c60b9acSAndroid Build Coastguard WorkerFor integers, various natural C types are available, but in all cases, the 228*1c60b9acSAndroid Build Coastguard Workernumber is represented in CBOR using the smallest valid way based on its value, 229*1c60b9acSAndroid Build Coastguard Workerthe long or long-long modifiers just apply to the expected C type in the args. 230*1c60b9acSAndroid Build Coastguard Worker 231*1c60b9acSAndroid Build Coastguard WorkerFor floats, the C argument is always expected to be a `double` type following 232*1c60b9acSAndroid Build Coastguard WorkerC type promotion, but again it is represented in CBOR using the smallest valid 233*1c60b9acSAndroid Build Coastguard Workerway based on value, half-floats are used for NaN / Infinity and where possible 234*1c60b9acSAndroid Build Coastguard Workerfor values like 0.0 and -1.0. 235*1c60b9acSAndroid Build Coastguard Worker 236*1c60b9acSAndroid Build Coastguard Worker## Examples 237*1c60b9acSAndroid Build Coastguard Worker 238*1c60b9acSAndroid Build Coastguard Worker### Literal ints 239*1c60b9acSAndroid Build Coastguard Worker 240*1c60b9acSAndroid Build Coastguard Worker``` 241*1c60b9acSAndroid Build Coastguard Worker uint8_t buf[128]; 242*1c60b9acSAndroid Build Coastguard Worker lws_lec_pctx_t cbw; 243*1c60b9acSAndroid Build Coastguard Worker 244*1c60b9acSAndroid Build Coastguard Worker lws_lec_init(&cbw, buf, sizeof(buf)); 245*1c60b9acSAndroid Build Coastguard Worker lws_lec_printf(ctx, "-1"); 246*1c60b9acSAndroid Build Coastguard Worker``` 247*1c60b9acSAndroid Build Coastguard Worker||| 248*1c60b9acSAndroid Build Coastguard Worker|---|---| 249*1c60b9acSAndroid Build Coastguard Worker|Return| `LWS_LECPCTX_RET_FINISHED`| 250*1c60b9acSAndroid Build Coastguard Worker|`ctx->used`|1| 251*1c60b9acSAndroid Build Coastguard Worker|`buf[]`|20| 252*1c60b9acSAndroid Build Coastguard Worker 253*1c60b9acSAndroid Build Coastguard Worker### Dynamic ints 254*1c60b9acSAndroid Build Coastguard Worker 255*1c60b9acSAndroid Build Coastguard Worker``` 256*1c60b9acSAndroid Build Coastguard Worker uint8_t buf[128]; 257*1c60b9acSAndroid Build Coastguard Worker lws_lec_pctx_t cbw; 258*1c60b9acSAndroid Build Coastguard Worker int n = -1; /* could be long */ 259*1c60b9acSAndroid Build Coastguard Worker 260*1c60b9acSAndroid Build Coastguard Worker lws_lec_init(&cbw, buf, sizeof(buf)); 261*1c60b9acSAndroid Build Coastguard Worker lws_lec_printf(ctx, "%d", n); /* use %ld for long */ 262*1c60b9acSAndroid Build Coastguard Worker``` 263*1c60b9acSAndroid Build Coastguard Worker||| 264*1c60b9acSAndroid Build Coastguard Worker|---|---| 265*1c60b9acSAndroid Build Coastguard Worker|Return| `LWS_LECPCTX_RET_FINISHED`| 266*1c60b9acSAndroid Build Coastguard Worker|`ctx->used`|1| 267*1c60b9acSAndroid Build Coastguard Worker|`buf[]`|20| 268*1c60b9acSAndroid Build Coastguard Worker 269*1c60b9acSAndroid Build Coastguard Worker### Maps, arrays and dynamic ints 270*1c60b9acSAndroid Build Coastguard Worker 271*1c60b9acSAndroid Build Coastguard Worker``` 272*1c60b9acSAndroid Build Coastguard Worker ... 273*1c60b9acSAndroid Build Coastguard Worker int args[3] = { 1, 2, 3 }; 274*1c60b9acSAndroid Build Coastguard Worker 275*1c60b9acSAndroid Build Coastguard Worker lws_lec_printf(ctx, "{'a':%d,'b':[%d,%d]}", args[0], args[1], args[2]); 276*1c60b9acSAndroid Build Coastguard Worker``` 277*1c60b9acSAndroid Build Coastguard Worker 278*1c60b9acSAndroid Build Coastguard Worker||| 279*1c60b9acSAndroid Build Coastguard Worker|---|---| 280*1c60b9acSAndroid Build Coastguard Worker|Return| `LWS_LECPCTX_RET_FINISHED`| 281*1c60b9acSAndroid Build Coastguard Worker|`ctx->used`|9| 282*1c60b9acSAndroid Build Coastguard Worker|`buf[]`|A2 61 61 01 61 62 82 02 03| 283*1c60b9acSAndroid Build Coastguard Worker 284*1c60b9acSAndroid Build Coastguard Worker### String longer than the buffer 285*1c60b9acSAndroid Build Coastguard Worker 286*1c60b9acSAndroid Build Coastguard WorkerUsing `%s` and the same string as an arg gives same results 287*1c60b9acSAndroid Build Coastguard Worker 288*1c60b9acSAndroid Build Coastguard Worker``` 289*1c60b9acSAndroid Build Coastguard Worker uint8_t buf[16]; 290*1c60b9acSAndroid Build Coastguard Worker lws_lec_pctx_t cbw; 291*1c60b9acSAndroid Build Coastguard Worker 292*1c60b9acSAndroid Build Coastguard Worker lws_lec_init(&cbw, buf, sizeof(buf)); 293*1c60b9acSAndroid Build Coastguard Worker lws_lec_printf(ctx, "'A literal string > one buf'"); 294*1c60b9acSAndroid Build Coastguard Worker /* not required to be in same function context or same buf, 295*1c60b9acSAndroid Build Coastguard Worker * but the string must remain the same */ 296*1c60b9acSAndroid Build Coastguard Worker lws_lec_setbuf(&cbw, buf, sizeof(buf)); 297*1c60b9acSAndroid Build Coastguard Worker lws_lec_printf(ctx, "'A literal string > one buf'"); 298*1c60b9acSAndroid Build Coastguard Worker``` 299*1c60b9acSAndroid Build Coastguard Worker 300*1c60b9acSAndroid Build Coastguard WorkerFirst call 301*1c60b9acSAndroid Build Coastguard Worker 302*1c60b9acSAndroid Build Coastguard Worker||| 303*1c60b9acSAndroid Build Coastguard Worker|---|---| 304*1c60b9acSAndroid Build Coastguard Worker|Return| `LWS_LECPCTX_RET_AGAIN`| 305*1c60b9acSAndroid Build Coastguard Worker|`ctx->used`|16| 306*1c60b9acSAndroid Build Coastguard Worker|`buf[]`|78 1A 41 20 6C 69 74 65 72 61 6C 20 73 74 72 69| 307*1c60b9acSAndroid Build Coastguard Worker 308*1c60b9acSAndroid Build Coastguard WorkerSecond call 309*1c60b9acSAndroid Build Coastguard Worker 310*1c60b9acSAndroid Build Coastguard Worker||| 311*1c60b9acSAndroid Build Coastguard Worker|---|---| 312*1c60b9acSAndroid Build Coastguard Worker|Return| `LWS_LECPCTX_RET_FINISHED`| 313*1c60b9acSAndroid Build Coastguard Worker|`ctx->used`|12| 314*1c60b9acSAndroid Build Coastguard Worker|`buf[]`|6E 67 20 3E 20 6F 6E 65 20 62 75 66| 315*1c60b9acSAndroid Build Coastguard Worker 316*1c60b9acSAndroid Build Coastguard Worker### Binary blob longer than the buffer 317*1c60b9acSAndroid Build Coastguard Worker 318*1c60b9acSAndroid Build Coastguard Worker``` 319*1c60b9acSAndroid Build Coastguard Worker uint8_t buf[16], blob[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; 320*1c60b9acSAndroid Build Coastguard Worker lws_lec_pctx_t cbw; 321*1c60b9acSAndroid Build Coastguard Worker 322*1c60b9acSAndroid Build Coastguard Worker lws_lec_init(&cbw, buf, sizeof(buf)); 323*1c60b9acSAndroid Build Coastguard Worker lws_lec_printf(ctx, "%.*b", (int)sizeof(blob), blob); 324*1c60b9acSAndroid Build Coastguard Worker /* not required to be in same function context or same buf, 325*1c60b9acSAndroid Build Coastguard Worker * but the length and blob must remain the same */ 326*1c60b9acSAndroid Build Coastguard Worker lws_lec_setbuf(&cbw, buf, sizeof(buf)); 327*1c60b9acSAndroid Build Coastguard Worker lws_lec_printf(ctx, "%.*b", (int)sizeof(blob), blob); 328*1c60b9acSAndroid Build Coastguard Worker``` 329*1c60b9acSAndroid Build Coastguard Worker 330*1c60b9acSAndroid Build Coastguard WorkerFirst call 331*1c60b9acSAndroid Build Coastguard Worker 332*1c60b9acSAndroid Build Coastguard Worker||| 333*1c60b9acSAndroid Build Coastguard Worker|---|---| 334*1c60b9acSAndroid Build Coastguard Worker|Return| `LWS_LECPCTX_RET_AGAIN`| 335*1c60b9acSAndroid Build Coastguard Worker|`ctx->used`|16| 336*1c60b9acSAndroid Build Coastguard Worker|`buf[]`|52 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F| 337*1c60b9acSAndroid Build Coastguard Worker 338*1c60b9acSAndroid Build Coastguard WorkerSecond call 339*1c60b9acSAndroid Build Coastguard Worker 340*1c60b9acSAndroid Build Coastguard Worker||| 341*1c60b9acSAndroid Build Coastguard Worker|---|---| 342*1c60b9acSAndroid Build Coastguard Worker|Return| `LWS_LECPCTX_RET_FINISHED`| 343*1c60b9acSAndroid Build Coastguard Worker|`ctx->used`|3| 344*1c60b9acSAndroid Build Coastguard Worker|`buf[]`|10 11 12| 345