xref: /aosp_15_r20/external/libwebsockets/READMEs/README.cbor-lecp.md (revision 1c60b9aca93fdbc9b5f19b2d2194c91294b22281)
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