forked from zephyrproject-rtos/zcbor
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathzcbor_encode.h
More file actions
333 lines (300 loc) · 15.1 KB
/
zcbor_encode.h
File metadata and controls
333 lines (300 loc) · 15.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
/*
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZCBOR_ENCODE_H__
#define ZCBOR_ENCODE_H__
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "zcbor_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/** The zcbor_encode library provides functions for encoding CBOR data elements.
*
* See The README for an introduction to CBOR, including the meaning of pint,
* nint, bstr etc.
*/
/** See @ref zcbor_new_state() */
void zcbor_new_encode_state(zcbor_state_t *state_array, size_t n_states,
uint8_t *payload, size_t payload_len, size_t elem_count);
/** Convenience macro for declaring and initializing an encoding state with backups.
*
* This gives you a state variable named @p name. The variable functions like
* a pointer.
*
* @param[in] name The name of the new state variable.
* @param[in] num_backups The number of backup slots to keep in the state.
* @param[in] payload The payload to work on.
* @param[in] payload_size The size (in bytes) of @p payload.
* @param[in] elem_count The starting elem_count (typically 1).
*/
#define ZCBOR_STATE_E(name, num_backups, payload, payload_size, elem_count) \
ZCBOR_ALIGNAS(zcbor_state_t) uint8_t name##_storage[ \
(((num_backups) + 1 + ZCBOR_CONST_STATE_SLOTS) * sizeof(zcbor_state_t)) \
]; \
zcbor_state_t *name = (zcbor_state_t *)name##_storage; \
do { \
zcbor_new_encode_state(name, ((num_backups) + 1 + ZCBOR_CONST_STATE_SLOTS), \
payload, payload_size, elem_count); \
} while(0)
/** The following applies to all _put and _encode functions listed directly below.
*
* The difference between _put and _encode is only in the argument type,
* but when a @ref zcbor_encoder_t is needed, such as for @ref zcbor_multi_encode,
* the _encode variant must be used.
*
* @param[inout] state The current state of the encoding.
* @param[in] input The value to encode.
*
* @retval true Everything is ok.
* @retval false If the payload is exhausted. Or an unexpected error happened.
* Use zcbor_peek_error() to see the error code.
*/
bool zcbor_int32_put(zcbor_state_t *state, int32_t input); /* pint/nint */
bool zcbor_int64_put(zcbor_state_t *state, int64_t input); /* pint/nint */
bool zcbor_uint32_put(zcbor_state_t *state, uint32_t input); /* pint */
bool zcbor_uint64_put(zcbor_state_t *state, uint64_t input); /* pint */
bool zcbor_size_put(zcbor_state_t *state, size_t input); /* pint */
bool zcbor_tag_put(zcbor_state_t *state, uint32_t tag); /* CBOR tag */
bool zcbor_bool_put(zcbor_state_t *state, bool input); /* boolean CBOR simple value */
bool zcbor_nil_put(zcbor_state_t *state, const void *unused); /* 'nil' CBOR simple value */
bool zcbor_undefined_put(zcbor_state_t *state, const void *unused); /* 'undefined' CBOR simple value */
bool zcbor_float16_put(zcbor_state_t *state, float input); /* IEEE754 float16 */
bool zcbor_float16_bytes_put(zcbor_state_t *state, uint16_t input); /* IEEE754 float16 raw bytes */
bool zcbor_float32_put(zcbor_state_t *state, float input); /* IEEE754 float32 */
bool zcbor_float64_put(zcbor_state_t *state, double input); /* IEEE754 float64 */
bool zcbor_int32_encode(zcbor_state_t *state, const int32_t *input); /* pint/nint */
bool zcbor_int64_encode(zcbor_state_t *state, const int64_t *input); /* pint/nint */
bool zcbor_uint32_encode(zcbor_state_t *state, const uint32_t *input); /* pint */
bool zcbor_uint64_encode(zcbor_state_t *state, const uint64_t *input); /* pint */
bool zcbor_size_encode(zcbor_state_t *state, const size_t *input); /* pint */
bool zcbor_int_encode(zcbor_state_t *state, const void *input_int, size_t int_size);
bool zcbor_uint_encode(zcbor_state_t *state, const void *input_uint, size_t uint_size);
bool zcbor_bstr_encode(zcbor_state_t *state, const struct zcbor_string *input); /* bstr */
bool zcbor_tstr_encode(zcbor_state_t *state, const struct zcbor_string *input); /* tstr */
bool zcbor_tag_encode(zcbor_state_t *state, uint32_t *tag); /* CBOR tag. Note that zcbor_tag_encode()'s argument was changed to be a pointer. See also zcbor_tag_put(). */
bool zcbor_bool_encode(zcbor_state_t *state, const bool *input); /* boolean CBOR simple value */
bool zcbor_float16_encode(zcbor_state_t *state, const float *input); /* IEEE754 float16 */
bool zcbor_float16_bytes_encode(zcbor_state_t *state, const uint16_t *input); /* IEEE754 float16 raw bytes */
bool zcbor_float32_encode(zcbor_state_t *state, const float *input); /* IEEE754 float32 */
bool zcbor_float64_encode(zcbor_state_t *state, const double *input); /* IEEE754 float64 */
/** Encode a list/map header.
*
* The contents of the list/map can be encoded via subsequent function calls.
* If ZCBOR_CANONICAL is defined, a state backup is created to keep track of the
* element count.
* When all members have been encoded, call @ref zcbor_list_end_encode /
* @ref zcbor_map_end_encode to close the list/map.
*
* @param[inout] state The current state of the encoding.
* @param[in] max_num The maximum number of members in the list/map.
* This serves as a size hint for the header. Must be
* equal to the max_num provided to the corresponding
* @ref zcbor_list_end_encode / @ref zcbor_map_end_encode
* call.
* Only used when ZCBOR_CANONICAL is defined.
*/
bool zcbor_list_start_encode(zcbor_state_t *state, size_t max_num);
bool zcbor_map_start_encode(zcbor_state_t *state, size_t max_num);
/** Encode the end of a list/map. Do some checks and deallocate backup.
*
* - Default: Adds a list terminator (0xFF) to mark the
* end of the list/map.
* - If ZCBOR_CANONICAL is defined: Instead encodes the number of members in
* the list/map header. If the header ends up a different size than expected,
* the list/map contents are moved using memmove().
*
* Use @ref zcbor_list_map_end_force_encode to forcibly consume the backup if
* something has gone wrong.
*
* @param[inout] state The current state of the encoding.
* @param[in] max_num The maximum number of members in the list/map. Must be
* equal to the max_num provided to the corresponding
* @ref zcbor_list_start_encode call.
* Only used when ZCBOR_CANONICAL is defined.
*/
bool zcbor_list_end_encode(zcbor_state_t *state, size_t max_num);
bool zcbor_map_end_encode(zcbor_state_t *state, size_t max_num);
bool zcbor_list_map_end_force_encode(zcbor_state_t *state);
/** Encode 0 or more elements with the same type and constraints.
*
* The encoded values are taken from the @p input array.
*
* The following is an example of encoding a list containing 3 INTS followed by
* 0 to 2 bstrs:
*
* @code{c}
* uint32_t ints[3] = <initialize>;
* struct zcbor_string bstrs[2] = <initialize>;
* bool res;
*
* res = zcbor_list_start_encode(state, 5);
* res = res && zcbor_multi_encode(3, zcbor_uint32_encode, state,
* ints, sizeof(uint32_t));
* res = res && zcbor_multi_encode(2, zcbor_bstr_encode, state,
* bstrs, sizeof(struct zcbor_string));
* res = res && zcbor_list_end_encode(state, 5);
* // check res
* @endcode
*
* The @ref zcbor_encoder_t type is designed to be compatible with all single-
* value encoder functions in this library, e.g. @ref zcbor_uint32_encode,
* @ref zcbor_tstr_put, @ref zcbor_nil_put, etc. For _put() functions,
* @p input will be used as a value instead of an array/pointer, so
* @p input_len will determine how much the value changes for each call.
* To encode the same value multiple times, use a @p input_len of 0.
* This function can also be used with custom decoder functions, such as those
* generated by the zcbor.py script, which for example encodes larger chunks of
* the data at once.
*
* @param[in] num_encode The actual number of elements.
* @param[in] encoder The encoder function to call under the hood. This
* function will be called with the provided arguments
* repeatedly until the function fails (returns false)
* or until it has been called @p max_encode times.
* The input pointer is moved @p input_len bytes for
* each call to @p encoder, i.e. @p input refers to an
* array of input variables.
* @param[in] input Source of the encoded values. Must be an array of
* at least @p max_encode elements.
* @param[in] input_len The length of the input variables. Must be the
* length of the individual elements in input.
*
* @retval true If at least @p min_encode variables were correctly encoded.
* @retval false If @p encoder failed before having encoded @p min_encode
* values.
*/
bool zcbor_multi_encode(size_t num_encode, zcbor_encoder_t encoder,
zcbor_state_t *state, const void *input, size_t result_len);
/** Works like @ref zcbor_multi_encode
*
* But first checks that @p num_encode is between @p min_encode and @p max_encode.
*/
bool zcbor_multi_encode_minmax(size_t min_encode, size_t max_encode,
const size_t *num_encode, zcbor_encoder_t encoder,
zcbor_state_t *state, const void *input, size_t input_len);
/**
* @brief Iterator callback for streaming encode of repeated fields.
*
* Return values:
* - 1: produced one element, stored at *elem_out
* - 0: done (normal end)
* - <0: error (negative errno-style)
*
* The pointer stored in *elem_out must remain valid until the next call to next()
* (or until encoding is finished), whichever comes first.
*/
typedef int (*zcbor_stream_iter)(void *ctx, const void **elem_out);
/**
* @brief Encode a repeated field by iterating elements from a callback.
*
* This is intended for streaming encode where the caller does not want (or
* cannot afford) to materialize an array + count upfront.
*/
bool zcbor_multi_encode_iter_minmax(size_t min_encode, size_t max_encode,
zcbor_encoder_t encoder, zcbor_state_t *state,
zcbor_stream_iter next, void *ctx);
/* Supplementary string (bstr/tstr) encoding functions: */
/** Encode a char/uint8_t pointer as a bstr/tstr.
*
* @param[inout] state The current state of the encoding.
* @param[in] str The value to encode. A pointer to the string/array.
* _term() uses strnlen(), so @p str must be null-terminated.
* _lit() uses sizeof()-1, so @p str must be a (null-terminated) string literal.
* _arr() uses sizeof(), so @p str must be a uint8_t array (not null-terminated).
* @param[in] len (if present) The length of the string pointed to by @p str
* @param[in] maxlen (if present) The maximum length of the string pointed to by @p str.
* This value is passed to strnlen.
*/
bool zcbor_bstr_encode_ptr(zcbor_state_t *state, const char *str, size_t len);
bool zcbor_tstr_encode_ptr(zcbor_state_t *state, const char *str, size_t len);
bool zcbor_bstr_put_term(zcbor_state_t *state, char const *str, size_t maxlen);
bool zcbor_tstr_put_term(zcbor_state_t *state, char const *str, size_t maxlen);
#define zcbor_bstr_put_lit(state, str) zcbor_bstr_encode_ptr(state, str, sizeof(str) - 1)
#define zcbor_tstr_put_lit(state, str) zcbor_tstr_encode_ptr(state, str, sizeof(str) - 1)
#define zcbor_bstr_put_arr(state, str) zcbor_bstr_encode_ptr(state, str, sizeof(str))
#define zcbor_tstr_put_arr(state, str) zcbor_tstr_encode_ptr(state, str, sizeof(str))
/** Encode a bstr header.
*
* The rest of the string can be encoded as CBOR.
* A state backup is created to keep track of the element count.
* Call @ref zcbor_bstr_end_encode when done encoding the contents of the bstr.
*
* @param[inout] state The current state of the encoding.
*
* @retval true Header encoded correctly
* @retval false Header encoded incorrectly, or backup failed.
*/
bool zcbor_bstr_start_encode(zcbor_state_t *state);
/** Finalize encoding a CBOR-encoded bstr.
*
* This writes the final size of the bstr to the header.
* Restore element count from backup.
*/
bool zcbor_bstr_end_encode(zcbor_state_t *state, struct zcbor_string *result);
/**
* @brief Chunk iterator for streaming encode of indefinite-length text/byte strings.
*
* Return values:
* - 1: produced one chunk (*ptr, *len)
* - 0: done (normal end)
* - <0: error (negative errno-style)
*/
typedef int (*zcbor_next_chunk_fn)(void *ctx, const uint8_t **ptr, size_t *len);
/* Encode an indefinite-length tstr using a chunk iterator. */
bool zcbor_tstr_encode_indefinite_chunks(zcbor_state_t *state,
zcbor_next_chunk_fn next_chunk, void *ctx);
bool zcbor_bstr_encode_indefinite_chunks(zcbor_state_t *state,
zcbor_next_chunk_fn next_chunk, void *ctx);
/**
* @brief Push callback for streaming encode of indefinite-length text/byte strings.
*
* The callback should emit 0 or more chunks using zcbor_*str_encode_chunk(),
* and return true on success.
*/
typedef bool (*zcbor_stream_chunk_out)(void *ctx, zcbor_state_t *state);
/* Indefinite-length tstr/bstr using a chunk callback. */
bool zcbor_tstr_chunk_out(zcbor_state_t *state,
zcbor_stream_chunk_out call, void *ctx);
bool zcbor_bstr_chunk_out(zcbor_state_t *state,
zcbor_stream_chunk_out call, void *ctx);
/* Push-oriented helpers for indefinite-length tstr/bstr. */
bool zcbor_tstr_start_encode_indefinite(zcbor_state_t *state);
bool zcbor_bstr_start_encode_indefinite(zcbor_state_t *state);
bool zcbor_tstr_encode_chunk(zcbor_state_t *state, const uint8_t *ptr, size_t len);
bool zcbor_bstr_encode_chunk(zcbor_state_t *state, const uint8_t *ptr, size_t len);
bool zcbor_tstr_end_encode_indefinite(zcbor_state_t *state);
bool zcbor_bstr_end_encode_indefinite(zcbor_state_t *state);
/** Stream write callback type.
*
* @param user_data User-provided context (e.g., UART device pointer)
* @param data Pointer to data to write
* @param len Number of bytes to write
* @return Number of bytes written (must equal len for success)
*/
typedef size_t (*zcbor_stream_write_fn)(void *user_data, const uint8_t *data, size_t len);
/** Initialize encoding state for streaming mode.
*
* Bytes are written directly via the callback instead of buffering.
* In streaming mode, arrays and maps use indefinite-length encoding
* (0x9F/0xBF + items + 0xFF) to avoid backtracking.
*
* @param state_array Array of states (must have at least 2 elements for constant_state)
* @param n_states Number of states in array
* @param stream_write Callback function to write bytes
* @param stream_user_data User data passed to callback (e.g., UART device pointer)
* @param elem_count Starting element count (typically 1)
*/
void zcbor_new_encode_state_streaming(zcbor_state_t *state_array, size_t n_states,
zcbor_stream_write_fn stream_write, void *stream_user_data, size_t elem_count);
size_t zcbor_stream_bytes_written(const zcbor_state_t *state);
int zcbor_stream_entry_function(void *input, zcbor_state_t *states, size_t n_states,
zcbor_encoder_t func, zcbor_stream_write_fn stream_write, void *stream_user_data,
size_t elem_count, size_t *bytes_written_out);
#ifdef __cplusplus
}
#endif
#endif /* ZCBOR_ENCODE_H__ */