roo_io
API Documentation for roo_io
Loading...
Searching...
No Matches
cobs.c
Go to the documentation of this file.
1// SPDX-License-Identifier: Unlicense OR 0BSD
2#include "cobs.h"
3
4#define COBS_TFSV COBS_TINYFRAME_SENTINEL_VALUE
5
6typedef unsigned char cobs_byte_t;
7
8cobs_ret_t cobs_encode_tinyframe(void *buf, size_t len) {
9 if (!buf || (len < 2)) {
11 }
12
13 cobs_byte_t *const src = (cobs_byte_t *)buf;
14 if ((src[0] != COBS_TFSV) || (src[len - 1] != COBS_TFSV)) {
16 }
17
18 size_t patch = 0, cur = 1;
19 while (cur < len - 1) {
20 if (src[cur] == COBS_FRAME_DELIMITER) {
21 size_t const ofs = cur - patch;
22 if (ofs > 255) {
24 }
25 src[patch] = (cobs_byte_t)ofs;
26 patch = cur;
27 }
28 ++cur;
29 }
30 size_t const ofs = cur - patch;
31 if (ofs > 255) {
33 }
34 src[patch] = (cobs_byte_t)ofs;
35 src[cur] = 0;
36 return COBS_RET_SUCCESS;
37}
38
39cobs_ret_t cobs_decode_tinyframe(void *buf, size_t const len) {
40 if (!buf || (len < 2)) {
42 }
43
44 cobs_byte_t *const src = (cobs_byte_t *)buf;
45 size_t ofs, cur = 0;
46 while ((cur < len) && ((ofs = src[cur]) != COBS_FRAME_DELIMITER)) {
47 src[cur] = 0;
48 for (size_t i = 1; i < ofs; ++i) {
49 if (src[cur + i] == 0) {
51 }
52 }
53 cur += ofs;
54 }
55
56 if (cur != len - 1) {
58 }
59 src[0] = COBS_TFSV;
60 src[len - 1] = COBS_TFSV;
61 return COBS_RET_SUCCESS;
62}
63
64cobs_ret_t cobs_encode(void const *dec,
65 size_t dec_len,
66 void *out_enc,
67 size_t enc_max,
68 size_t *out_enc_len) {
69 if (!out_enc_len) {
71 }
72
74 cobs_ret_t r;
75 if ((r = cobs_encode_inc_begin(out_enc, enc_max, &ctx)) != COBS_RET_SUCCESS) {
76 return r;
77 }
78 if ((r = cobs_encode_inc(&ctx, dec, dec_len)) != COBS_RET_SUCCESS) {
79 return r;
80 }
81 return cobs_encode_inc_end(&ctx, out_enc_len);
82}
83
84cobs_ret_t cobs_encode_inc_begin(void *out_enc, size_t enc_max, cobs_enc_ctx_t *out_ctx) {
85 if (!out_enc || !out_ctx) {
87 }
88 if (enc_max < 2) {
90 }
91
92 out_ctx->dst = out_enc;
93 out_ctx->dst_max = enc_max;
94 out_ctx->cur = 1;
95 out_ctx->code = 1;
96 out_ctx->code_idx = 0;
97 out_ctx->need_advance = 0;
98 return COBS_RET_SUCCESS;
99}
100
101cobs_ret_t cobs_encode_inc(cobs_enc_ctx_t *ctx, void const *dec, size_t dec_len) {
102 if (!ctx || !dec) {
104 }
105 size_t dst_idx = ctx->cur;
106 size_t const enc_max = ctx->dst_max;
107 if ((enc_max - dst_idx) < dec_len) {
109 }
110 if (!dec_len) {
111 return COBS_RET_SUCCESS;
112 }
113
114 size_t dst_code_idx = ctx->code_idx;
115 unsigned code = ctx->code;
116 int need_advance = ctx->need_advance;
117
118 cobs_byte_t const *const src = (cobs_byte_t const *)dec;
119 cobs_byte_t *const dst = (cobs_byte_t *)ctx->dst;
120 size_t src_idx = 0;
121
122 if (need_advance) {
123 if (++dst_idx >= enc_max) {
125 }
126 need_advance = 0;
127 }
128
129 while (dec_len--) {
130 cobs_byte_t const byte = src[src_idx];
131 if (byte) {
132 dst[dst_idx] = byte;
133 if (++dst_idx >= enc_max) {
135 }
136 ++code;
137 }
138
139 if ((byte == 0) || (code == 0xFF)) {
140 dst[dst_code_idx] = (cobs_byte_t)code;
141 dst_code_idx = dst_idx;
142 code = 1;
143
144 if ((byte == 0) || dec_len) {
145 if (++dst_idx >= enc_max) {
147 }
148 } else {
149 need_advance = !dec_len;
150 }
151 }
152 ++src_idx;
153 }
154
155 ctx->cur = dst_idx;
156 ctx->code = code;
157 ctx->code_idx = dst_code_idx;
158 ctx->need_advance = need_advance;
159 return COBS_RET_SUCCESS;
160}
161
163 if (!ctx || !out_enc_len) {
165 }
166
167 cobs_byte_t *const dst = (cobs_byte_t *)ctx->dst;
168 size_t cur = ctx->cur;
169 dst[ctx->code_idx] = (cobs_byte_t)ctx->code;
170 dst[cur++] = COBS_FRAME_DELIMITER;
171 *out_enc_len = cur;
172 return COBS_RET_SUCCESS;
173}
174
175cobs_ret_t cobs_decode(void const *enc,
176 size_t enc_len,
177 void *out_dec,
178 size_t dec_max,
179 size_t *out_dec_len) {
180 if (!enc || !out_dec || !out_dec_len) {
182 }
183 if (enc_len < 2) {
185 }
186
189 if (r != COBS_RET_SUCCESS) {
190 return r;
191 }
192
193 size_t src_len;
194 bool decode_complete;
195 if ((r = cobs_decode_inc(&ctx,
196 &(cobs_decode_inc_args_t){ .enc_src = enc,
197 .dec_dst = out_dec,
198 .enc_src_max = enc_len,
199 .dec_dst_max = dec_max },
200 &src_len,
201 out_dec_len,
202 &decode_complete)) != COBS_RET_SUCCESS) {
203 return r;
204 }
205 return decode_complete ? COBS_RET_SUCCESS : COBS_RET_ERR_EXHAUSTED;
206}
207
209 if (!ctx) {
211 }
212 ctx->state = COBS_DECODE_READ_CODE;
213 return COBS_RET_SUCCESS;
214}
215
217 cobs_decode_inc_args_t const *args,
218 size_t *out_enc_src_len,
219 size_t *out_dec_dst_len,
220 bool *out_decode_complete) {
221 if (!ctx || !args || !out_enc_src_len || !out_dec_dst_len || !out_decode_complete ||
222 !args->dec_dst || !args->enc_src) {
224 }
225
226 bool decode_complete = false;
227 size_t src_idx = 0, dst_idx = 0;
228
229 size_t const src_max = args->enc_src_max;
230 size_t const dst_max = args->dec_dst_max;
231 cobs_byte_t const *src_b = (cobs_byte_t const *)args->enc_src;
232 cobs_byte_t *dst_b = (cobs_byte_t *)args->dec_dst;
233 unsigned block = ctx->block, code = ctx->code;
234 enum cobs_decode_inc_state state = ctx->state;
235
236 while (src_idx < src_max) {
237 switch (state) {
238 case COBS_DECODE_READ_CODE: {
239 block = code = src_b[src_idx++];
240 state = COBS_DECODE_RUN;
241 } break;
242
243 case COBS_DECODE_FINISH_RUN: {
244 if (!src_b[src_idx]) {
245 decode_complete = true;
246 goto done;
247 }
248
249 if (code != 0xFF) {
250 if (dst_idx >= dst_max) {
251 goto done;
252 }
253 dst_b[dst_idx++] = 0;
254 }
255 state = COBS_DECODE_READ_CODE;
256 } break;
257
258 case COBS_DECODE_RUN: {
259 while (block - 1) {
260 if ((src_idx >= src_max) || (dst_idx >= dst_max)) {
261 goto done;
262 }
263
264 --block;
265 cobs_byte_t const b = src_b[src_idx++];
266 if (!b) {
268 }
269
270 dst_b[dst_idx++] = b;
271 }
272 state = COBS_DECODE_FINISH_RUN;
273 } break;
274 }
275 }
276
277done:
278 ctx->state = state;
279 ctx->code = (uint8_t)code;
280 ctx->block = (uint8_t)block;
281 *out_dec_dst_len = dst_idx;
282 *out_enc_src_len = src_idx;
283 *out_decode_complete = decode_complete;
284 return COBS_RET_SUCCESS;
285}
cobs_ret_t cobs_decode_inc_begin(cobs_decode_inc_ctx_t *ctx)
Definition cobs.c:208
#define COBS_TFSV
Definition cobs.c:4
cobs_ret_t cobs_encode_tinyframe(void *buf, size_t len)
Definition cobs.c:8
cobs_ret_t cobs_decode(void const *enc, size_t enc_len, void *out_dec, size_t dec_max, size_t *out_dec_len)
Definition cobs.c:175
cobs_ret_t cobs_encode(void const *dec, size_t dec_len, void *out_enc, size_t enc_max, size_t *out_enc_len)
Definition cobs.c:64
cobs_ret_t cobs_encode_inc_begin(void *out_enc, size_t enc_max, cobs_enc_ctx_t *out_ctx)
Definition cobs.c:84
cobs_ret_t cobs_encode_inc(cobs_enc_ctx_t *ctx, void const *dec, size_t dec_len)
Definition cobs.c:101
cobs_ret_t cobs_encode_inc_end(cobs_enc_ctx_t *ctx, size_t *out_enc_len)
Definition cobs.c:162
cobs_ret_t cobs_decode_inc(cobs_decode_inc_ctx_t *ctx, cobs_decode_inc_args_t const *args, size_t *out_enc_src_len, size_t *out_dec_dst_len, bool *out_decode_complete)
Definition cobs.c:216
cobs_ret_t cobs_decode_tinyframe(void *buf, size_t const len)
Definition cobs.c:39
unsigned char cobs_byte_t
Definition cobs.c:6
@ COBS_FRAME_DELIMITER
Definition cobs.h:25
cobs_ret_t
Definition cobs.h:14
@ COBS_RET_ERR_BAD_PAYLOAD
Definition cobs.h:17
@ COBS_RET_ERR_EXHAUSTED
Definition cobs.h:18
@ COBS_RET_SUCCESS
Definition cobs.h:15
@ COBS_RET_ERR_BAD_ARG
Definition cobs.h:16
size_t dec_dst_max
Definition cobs.h:193
size_t enc_src_max
Definition cobs.h:192
void const * enc_src
Definition cobs.h:190
enum cobs_decode_inc_ctx::cobs_decode_inc_state state
uint8_t block
Definition cobs.h:186
size_t cur
Definition cobs.h:131
size_t dst_max
Definition cobs.h:130
unsigned code
Definition cobs.h:133
size_t code_idx
Definition cobs.h:132
void * dst
Definition cobs.h:129
int need_advance
Definition cobs.h:134