ctf: compile plugin as C++
[babeltrace.git] / src / plugins / ctf / common / bfcr / bfcr.cpp
CommitLineData
5cd6d0e5 1/*
0235b0db 2 * SPDX-License-Identifier: MIT
5cd6d0e5
PP
3 *
4 * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
5 * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
6 *
0235b0db 7 * Babeltrace - CTF binary field class reader (BFCR)
5cd6d0e5
PP
8 */
9
c4a714d2 10#define BT_COMP_LOG_SELF_COMP (bfcr->self_comp)
80870e64 11#define BT_LOG_OUTPUT_LEVEL (bfcr->log_level)
350ad6c1 12#define BT_LOG_TAG "PLUGIN/CTF/BFCR"
d9c39b0a 13#include "logging/comp-logging.h"
5cd6d0e5
PP
14
15#include <stdlib.h>
16#include <stdint.h>
17#include <inttypes.h>
18#include <stdio.h>
19#include <stddef.h>
20#include <stdbool.h>
578e048b 21#include "common/assert.h"
5cd6d0e5 22#include <string.h>
578e048b
MJ
23#include "compat/bitfield.h"
24#include "common/common.h"
3fadfbc0 25#include <babeltrace2/babeltrace.h>
578e048b 26#include "common/align.h"
5cd6d0e5
PP
27#include <glib.h>
28
087cd0f5
SM
29#include "bfcr.hpp"
30#include "../metadata/ctf-meta.hpp"
5cd6d0e5
PP
31
32#define DIV8(_x) ((_x) >> 3)
33#define BYTES_TO_BITS(_x) ((_x) * 8)
34#define BITS_TO_BYTES_FLOOR(_x) DIV8(_x)
35#define BITS_TO_BYTES_CEIL(_x) DIV8((_x) + 7)
36#define IN_BYTE_OFFSET(_at) ((_at) & 7)
37
38/* A visit stack entry */
39struct stack_entry {
40 /*
41 * Current class of base field, one of:
42 *
43 * * Structure
44 * * Array
45 * * Sequence
46 * * Variant
47 */
48 struct ctf_field_class *base_class;
49
50 /* Length of base field (always 1 for a variant class) */
51 int64_t base_len;
52
53 /* Index of next field to read */
54 int64_t index;
55};
56
80870e64
PP
57struct bt_bfcr;
58
5cd6d0e5
PP
59/* Visit stack */
60struct stack {
80870e64
PP
61 struct bt_bfcr *bfcr;
62
5cd6d0e5
PP
63 /* Entries (struct stack_entry) */
64 GArray *entries;
65
66 /* Number of active entries */
67 size_t size;
68};
69
70/* Reading states */
71enum bfcr_state {
72 BFCR_STATE_NEXT_FIELD,
73 BFCR_STATE_ALIGN_BASIC,
74 BFCR_STATE_ALIGN_COMPOUND,
75 BFCR_STATE_READ_BASIC_BEGIN,
76 BFCR_STATE_READ_BASIC_CONTINUE,
77 BFCR_STATE_DONE,
78};
79
80/* Binary class reader */
81struct bt_bfcr {
80870e64
PP
82 bt_logging_level log_level;
83
c4a714d2
PP
84 /* Weak */
85 bt_self_component *self_comp;
86
80870e64 87 /* BFCR stack */
5cd6d0e5
PP
88 struct stack *stack;
89
90 /* Current basic field class */
91 struct ctf_field_class *cur_basic_field_class;
92
93 /* Current state */
94 enum bfcr_state state;
95
96 /*
97 * Last basic field class's byte order.
98 *
99 * This is used to detect errors since two contiguous basic
100 * classes for which the common boundary is not the boundary of
101 * a byte cannot have different byte orders.
102 *
e2bd7d40
JR
103 * This is set to CTF_BYTE_ORDER_UNKNOWN on reset and when the last
104 * basic field class was a string class.
5cd6d0e5
PP
105 */
106 enum ctf_byte_order last_bo;
107
108 /* Current byte order (copied to last_bo after a successful read) */
109 enum ctf_byte_order cur_bo;
110
111 /* Stitch buffer infos */
112 struct {
113 /* Stitch buffer */
114 uint8_t buf[16];
115
116 /* Offset, within stitch buffer, of first bit */
117 size_t offset;
118
119 /* Length (bits) of data in stitch buffer from offset */
120 size_t at;
121 } stitch;
122
123 /* User buffer infos */
124 struct {
125 /* Address */
126 const uint8_t *addr;
127
128 /* Offset of data from address (bits) */
129 size_t offset;
130
131 /* Current position from offset (bits) */
132 size_t at;
133
134 /* Offset of offset within whole packet (bits) */
135 size_t packet_offset;
136
137 /* Data size in buffer (bits) */
138 size_t sz;
139
140 /* Buffer size (bytes) */
141 size_t buf_sz;
142 } buf;
143
144 /* User stuff */
145 struct {
146 /* Callback functions */
147 struct bt_bfcr_cbs cbs;
148
149 /* Private data */
150 void *data;
151 } user;
152};
153
154static inline
155const char *bfcr_state_string(enum bfcr_state state)
156{
157 switch (state) {
158 case BFCR_STATE_NEXT_FIELD:
8a432889 159 return "NEXT_FIELD";
5cd6d0e5 160 case BFCR_STATE_ALIGN_BASIC:
8a432889 161 return "ALIGN_BASIC";
5cd6d0e5 162 case BFCR_STATE_ALIGN_COMPOUND:
8a432889 163 return "ALIGN_COMPOUND";
5cd6d0e5 164 case BFCR_STATE_READ_BASIC_BEGIN:
8a432889 165 return "READ_BASIC_BEGIN";
5cd6d0e5 166 case BFCR_STATE_READ_BASIC_CONTINUE:
8a432889 167 return "READ_BASIC_CONTINUE";
5cd6d0e5 168 case BFCR_STATE_DONE:
8a432889 169 return "DONE";
5cd6d0e5 170 }
00dff0ec
SM
171
172 bt_common_abort();
5cd6d0e5
PP
173}
174
175static
80870e64 176struct stack *stack_new(struct bt_bfcr *bfcr)
5cd6d0e5
PP
177{
178 struct stack *stack = NULL;
179
180 stack = g_new0(struct stack, 1);
181 if (!stack) {
c4a714d2 182 BT_COMP_LOGE_STR("Failed to allocate one stack.");
5cd6d0e5
PP
183 goto error;
184 }
185
80870e64 186 stack->bfcr = bfcr;
5cd6d0e5
PP
187 stack->entries = g_array_new(FALSE, TRUE, sizeof(struct stack_entry));
188 if (!stack->entries) {
c4a714d2 189 BT_COMP_LOGE_STR("Failed to allocate a GArray.");
5cd6d0e5
PP
190 goto error;
191 }
192
c4a714d2 193 BT_COMP_LOGD("Created stack: addr=%p", stack);
5cd6d0e5
PP
194 return stack;
195
196error:
197 g_free(stack);
198 return NULL;
199}
200
201static
202void stack_destroy(struct stack *stack)
203{
80870e64
PP
204 struct bt_bfcr *bfcr;
205
5cd6d0e5
PP
206 if (!stack) {
207 return;
208 }
209
80870e64 210 bfcr = stack->bfcr;
c4a714d2 211 BT_COMP_LOGD("Destroying stack: addr=%p", stack);
5cd6d0e5
PP
212
213 if (stack->entries) {
214 g_array_free(stack->entries, TRUE);
215 }
216
217 g_free(stack);
218}
219
220static
221int stack_push(struct stack *stack, struct ctf_field_class *base_class,
222 size_t base_len)
223{
224 struct stack_entry *entry;
80870e64 225 struct bt_bfcr *bfcr;
5cd6d0e5 226
98b15851
PP
227 BT_ASSERT_DBG(stack);
228 BT_ASSERT_DBG(base_class);
80870e64 229 bfcr = stack->bfcr;
ef267d12 230 BT_COMP_LOGT("Pushing field class on stack: stack-addr=%p, "
864cad70 231 "fc-addr=%p, fc-type=%d, base-length=%zu, "
5cd6d0e5 232 "stack-size-before=%zu, stack-size-after=%zu",
864cad70 233 stack, base_class, base_class->type,
5cd6d0e5
PP
234 base_len, stack->size, stack->size + 1);
235
236 if (stack->entries->len == stack->size) {
237 g_array_set_size(stack->entries, stack->size + 1);
238 }
239
240 entry = &g_array_index(stack->entries, struct stack_entry, stack->size);
241 entry->base_class = base_class;
242 entry->base_len = base_len;
243 entry->index = 0;
244 stack->size++;
245 return 0;
246}
247
248static inline
249int64_t get_compound_field_class_length(struct bt_bfcr *bfcr,
250 struct ctf_field_class *fc)
251{
252 int64_t length;
253
864cad70
PP
254 switch (fc->type) {
255 case CTF_FIELD_CLASS_TYPE_STRUCT:
5cd6d0e5 256 {
087cd0f5 257 ctf_field_class_struct *struct_fc = ctf_field_class_as_struct(fc);
5cd6d0e5
PP
258
259 length = (int64_t) struct_fc->members->len;
260 break;
261 }
864cad70 262 case CTF_FIELD_CLASS_TYPE_VARIANT:
5cd6d0e5
PP
263 {
264 /* Variant field classes always "contain" a single class */
265 length = 1;
266 break;
267 }
864cad70 268 case CTF_FIELD_CLASS_TYPE_ARRAY:
5cd6d0e5 269 {
087cd0f5 270 struct ctf_field_class_array *array_fc = ctf_field_class_as_array(fc);
5cd6d0e5
PP
271
272 length = (int64_t) array_fc->length;
273 break;
274 }
864cad70 275 case CTF_FIELD_CLASS_TYPE_SEQUENCE:
5cd6d0e5
PP
276 length = bfcr->user.cbs.query.get_sequence_length(fc,
277 bfcr->user.data);
278 break;
279 default:
498e7994 280 bt_common_abort();
5cd6d0e5
PP
281 }
282
283 return length;
284}
285
286static
287int stack_push_with_len(struct bt_bfcr *bfcr, struct ctf_field_class *base_class)
288{
289 int ret;
290 int64_t length = get_compound_field_class_length(bfcr, base_class);
291
292 if (length < 0) {
c4a714d2 293 BT_COMP_LOGW("Cannot get compound field class's field count: "
864cad70
PP
294 "bfcr-addr=%p, fc-addr=%p, fc-type=%d",
295 bfcr, base_class, base_class->type);
5cd6d0e5
PP
296 ret = BT_BFCR_STATUS_ERROR;
297 goto end;
298 }
299
300 ret = stack_push(bfcr->stack, base_class, (size_t) length);
301
302end:
303 return ret;
304}
305
306static inline
307unsigned int stack_size(struct stack *stack)
308{
98b15851 309 BT_ASSERT_DBG(stack);
5cd6d0e5
PP
310 return stack->size;
311}
312
313static
314void stack_pop(struct stack *stack)
315{
80870e64
PP
316 struct bt_bfcr *bfcr;
317
98b15851
PP
318 BT_ASSERT_DBG(stack);
319 BT_ASSERT_DBG(stack_size(stack));
80870e64 320 bfcr = stack->bfcr;
ef267d12 321 BT_COMP_LOGT("Popping from stack: "
5cd6d0e5
PP
322 "stack-addr=%p, stack-size-before=%u, stack-size-after=%u",
323 stack, stack->entries->len, stack->entries->len - 1);
324 stack->size--;
325}
326
327static inline
328bool stack_empty(struct stack *stack)
329{
330 return stack_size(stack) == 0;
331}
332
333static
334void stack_clear(struct stack *stack)
335{
98b15851 336 BT_ASSERT_DBG(stack);
5cd6d0e5
PP
337 stack->size = 0;
338}
339
340static inline
341struct stack_entry *stack_top(struct stack *stack)
342{
98b15851
PP
343 BT_ASSERT_DBG(stack);
344 BT_ASSERT_DBG(stack_size(stack));
5cd6d0e5
PP
345 return &g_array_index(stack->entries, struct stack_entry,
346 stack->size - 1);
347}
348
349static inline
350size_t available_bits(struct bt_bfcr *bfcr)
351{
352 return bfcr->buf.sz - bfcr->buf.at;
353}
354
355static inline
356void consume_bits(struct bt_bfcr *bfcr, size_t incr)
357{
ef267d12 358 BT_COMP_LOGT("Advancing cursor: bfcr-addr=%p, cur-before=%zu, cur-after=%zu",
5cd6d0e5
PP
359 bfcr, bfcr->buf.at, bfcr->buf.at + incr);
360 bfcr->buf.at += incr;
361}
362
363static inline
364bool has_enough_bits(struct bt_bfcr *bfcr, size_t sz)
365{
366 return available_bits(bfcr) >= sz;
367}
368
369static inline
370bool at_least_one_bit_left(struct bt_bfcr *bfcr)
371{
372 return has_enough_bits(bfcr, 1);
373}
374
375static inline
376size_t packet_at(struct bt_bfcr *bfcr)
377{
378 return bfcr->buf.packet_offset + bfcr->buf.at;
379}
380
381static inline
382size_t buf_at_from_addr(struct bt_bfcr *bfcr)
383{
384 /*
385 * Considering this:
386 *
387 * ====== offset ===== (17)
388 *
389 * xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
390 * ^
391 * addr (0) ==== at ==== (12)
392 *
393 * We want this:
394 *
395 * =============================== (29)
396 */
397 return bfcr->buf.offset + bfcr->buf.at;
398}
399
400static
401void stitch_reset(struct bt_bfcr *bfcr)
402{
403 bfcr->stitch.offset = 0;
404 bfcr->stitch.at = 0;
405}
406
407static inline
408size_t stitch_at_from_addr(struct bt_bfcr *bfcr)
409{
410 return bfcr->stitch.offset + bfcr->stitch.at;
411}
412
413static
414void stitch_append_from_buf(struct bt_bfcr *bfcr, size_t sz)
415{
416 size_t stitch_byte_at;
417 size_t buf_byte_at;
418 size_t nb_bytes;
419
420 if (sz == 0) {
421 return;
422 }
423
424 stitch_byte_at =
425 BITS_TO_BYTES_FLOOR(stitch_at_from_addr(bfcr));
426 buf_byte_at = BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr));
427 nb_bytes = BITS_TO_BYTES_CEIL(sz);
428 BT_ASSERT(nb_bytes > 0);
429 BT_ASSERT(bfcr->buf.addr);
430 memcpy(&bfcr->stitch.buf[stitch_byte_at], &bfcr->buf.addr[buf_byte_at],
431 nb_bytes);
432 bfcr->stitch.at += sz;
433 consume_bits(bfcr, sz);
434}
435
436static
437void stitch_append_from_remaining_buf(struct bt_bfcr *bfcr)
438{
439 stitch_append_from_buf(bfcr, available_bits(bfcr));
440}
441
442static
443void stitch_set_from_remaining_buf(struct bt_bfcr *bfcr)
444{
445 stitch_reset(bfcr);
446 bfcr->stitch.offset = IN_BYTE_OFFSET(buf_at_from_addr(bfcr));
447 stitch_append_from_remaining_buf(bfcr);
448}
449
450static inline
80870e64 451void read_unsigned_bitfield(struct bt_bfcr *bfcr, const uint8_t *buf, size_t at,
5cd6d0e5
PP
452 unsigned int field_size, enum ctf_byte_order bo,
453 uint64_t *v)
454{
455 switch (bo) {
456 case CTF_BYTE_ORDER_BIG:
457 bt_bitfield_read_be(buf, uint8_t, at, field_size, v);
458 break;
459 case CTF_BYTE_ORDER_LITTLE:
460 bt_bitfield_read_le(buf, uint8_t, at, field_size, v);
461 break;
462 default:
498e7994 463 bt_common_abort();
5cd6d0e5
PP
464 }
465
ef267d12 466 BT_COMP_LOGT("Read unsigned bit array: cur=%zu, size=%u, "
5cd6d0e5
PP
467 "bo=%d, val=%" PRIu64, at, field_size, bo, *v);
468}
469
470static inline
80870e64 471void read_signed_bitfield(struct bt_bfcr *bfcr, const uint8_t *buf, size_t at,
5cd6d0e5
PP
472 unsigned int field_size, enum ctf_byte_order bo, int64_t *v)
473{
474 switch (bo) {
475 case CTF_BYTE_ORDER_BIG:
476 bt_bitfield_read_be(buf, uint8_t, at, field_size, v);
477 break;
478 case CTF_BYTE_ORDER_LITTLE:
479 bt_bitfield_read_le(buf, uint8_t, at, field_size, v);
480 break;
481 default:
498e7994 482 bt_common_abort();
5cd6d0e5
PP
483 }
484
ef267d12 485 BT_COMP_LOGT("Read signed bit array: cur=%zu, size=%u, "
5cd6d0e5
PP
486 "bo=%d, val=%" PRId64, at, field_size, bo, *v);
487}
488
489typedef enum bt_bfcr_status (* read_basic_and_call_cb_t)(struct bt_bfcr *,
490 const uint8_t *, size_t);
491
492static inline
493enum bt_bfcr_status validate_contiguous_bo(struct bt_bfcr *bfcr,
494 enum ctf_byte_order next_bo)
495{
496 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
497
498 /* Always valid when at a byte boundary */
499 if (packet_at(bfcr) % 8 == 0) {
500 goto end;
501 }
502
503 /* Always valid if last byte order is unknown */
e2bd7d40 504 if (bfcr->last_bo == CTF_BYTE_ORDER_UNKNOWN) {
5cd6d0e5
PP
505 goto end;
506 }
507
508 /* Always valid if next byte order is unknown */
e2bd7d40 509 if (next_bo == CTF_BYTE_ORDER_UNKNOWN) {
5cd6d0e5
PP
510 goto end;
511 }
512
513 /* Make sure last byte order is compatible with the next byte order */
514 switch (bfcr->last_bo) {
515 case CTF_BYTE_ORDER_BIG:
516 if (next_bo != CTF_BYTE_ORDER_BIG) {
517 status = BT_BFCR_STATUS_ERROR;
518 }
519 break;
520 case CTF_BYTE_ORDER_LITTLE:
521 if (next_bo != CTF_BYTE_ORDER_LITTLE) {
522 status = BT_BFCR_STATUS_ERROR;
523 }
524 break;
525 default:
526 status = BT_BFCR_STATUS_ERROR;
527 }
528
529end:
530 if (status < 0) {
c4a714d2 531 BT_COMP_LOGW("Cannot read bit array: two different byte orders not at a byte boundary: "
5cd6d0e5
PP
532 "bfcr-addr=%p, last-bo=%d, next-bo=%d",
533 bfcr, bfcr->last_bo, next_bo);
534 }
535
536 return status;
537}
538
539static
540enum bt_bfcr_status read_basic_float_and_call_cb(struct bt_bfcr *bfcr,
541 const uint8_t *buf, size_t at)
542{
543 double dblval;
544 unsigned int field_size;
545 enum ctf_byte_order bo;
546 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
087cd0f5 547 ctf_field_class_float *fc = ctf_field_class_as_float(bfcr->cur_basic_field_class);
5cd6d0e5 548
98b15851 549 BT_ASSERT_DBG(fc);
5cd6d0e5
PP
550 field_size = fc->base.size;
551 bo = fc->base.byte_order;
552 bfcr->cur_bo = bo;
553
554 switch (field_size) {
555 case 32:
556 {
557 uint64_t v;
558 union {
559 uint32_t u;
560 float f;
561 } f32;
562
80870e64 563 read_unsigned_bitfield(bfcr, buf, at, field_size, bo, &v);
5cd6d0e5
PP
564 f32.u = (uint32_t) v;
565 dblval = (double) f32.f;
566 break;
567 }
568 case 64:
569 {
570 union {
571 uint64_t u;
572 double d;
573 } f64;
574
80870e64 575 read_unsigned_bitfield(bfcr, buf, at, field_size, bo, &f64.u);
5cd6d0e5
PP
576 dblval = f64.d;
577 break;
578 }
579 default:
580 /* Only 32-bit and 64-bit fields are supported currently */
498e7994 581 bt_common_abort();
5cd6d0e5
PP
582 }
583
ef267d12 584 BT_COMP_LOGT("Read floating point number value: bfcr=%p, cur=%zu, val=%f",
5cd6d0e5
PP
585 bfcr, at, dblval);
586
587 if (bfcr->user.cbs.classes.floating_point) {
ef267d12 588 BT_COMP_LOGT("Calling user function (floating point number).");
5cd6d0e5
PP
589 status = bfcr->user.cbs.classes.floating_point(dblval,
590 bfcr->cur_basic_field_class, bfcr->user.data);
ef267d12 591 BT_COMP_LOGT("User function returned: status=%s",
5cd6d0e5
PP
592 bt_bfcr_status_string(status));
593 if (status != BT_BFCR_STATUS_OK) {
c4a714d2 594 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s",
5cd6d0e5
PP
595 bfcr, bt_bfcr_status_string(status));
596 }
597 }
598
599 return status;
600}
601
602static inline
603enum bt_bfcr_status read_basic_int_and_call_cb(struct bt_bfcr *bfcr,
604 const uint8_t *buf, size_t at)
605{
606 unsigned int field_size;
607 enum ctf_byte_order bo;
608 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
087cd0f5 609 ctf_field_class_int *fc = ctf_field_class_as_int(bfcr->cur_basic_field_class);
5cd6d0e5
PP
610
611 field_size = fc->base.size;
612 bo = fc->base.byte_order;
613
614 /*
615 * Update current byte order now because we could be reading
616 * the integer value of an enumeration class, and thus we know
617 * here the actual supporting integer class's byte order.
618 */
619 bfcr->cur_bo = bo;
620
621 if (fc->is_signed) {
622 int64_t v;
623
80870e64 624 read_signed_bitfield(bfcr, buf, at, field_size, bo, &v);
5cd6d0e5
PP
625
626 if (bfcr->user.cbs.classes.signed_int) {
ef267d12 627 BT_COMP_LOGT("Calling user function (signed integer).");
5cd6d0e5
PP
628 status = bfcr->user.cbs.classes.signed_int(v,
629 bfcr->cur_basic_field_class, bfcr->user.data);
ef267d12 630 BT_COMP_LOGT("User function returned: status=%s",
5cd6d0e5
PP
631 bt_bfcr_status_string(status));
632 if (status != BT_BFCR_STATUS_OK) {
c4a714d2 633 BT_COMP_LOGW("User function failed: "
5cd6d0e5
PP
634 "bfcr-addr=%p, status=%s",
635 bfcr, bt_bfcr_status_string(status));
636 }
637 }
638 } else {
639 uint64_t v;
640
80870e64 641 read_unsigned_bitfield(bfcr, buf, at, field_size, bo, &v);
5cd6d0e5
PP
642
643 if (bfcr->user.cbs.classes.unsigned_int) {
ef267d12 644 BT_COMP_LOGT("Calling user function (unsigned integer).");
5cd6d0e5
PP
645 status = bfcr->user.cbs.classes.unsigned_int(v,
646 bfcr->cur_basic_field_class, bfcr->user.data);
ef267d12 647 BT_COMP_LOGT("User function returned: status=%s",
5cd6d0e5
PP
648 bt_bfcr_status_string(status));
649 if (status != BT_BFCR_STATUS_OK) {
c4a714d2 650 BT_COMP_LOGW("User function failed: "
5cd6d0e5
PP
651 "bfcr-addr=%p, status=%s",
652 bfcr, bt_bfcr_status_string(status));
653 }
654 }
655 }
656
657 return status;
658}
659
660static inline
661enum bt_bfcr_status read_bit_array_class_and_call_continue(struct bt_bfcr *bfcr,
662 read_basic_and_call_cb_t read_basic_and_call_cb)
663{
664 size_t available;
665 size_t needed_bits;
666 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
087cd0f5 667 ctf_field_class_bit_array *fc = ctf_field_class_as_bit_array(bfcr->cur_basic_field_class);
5cd6d0e5
PP
668
669 if (!at_least_one_bit_left(bfcr)) {
ef267d12 670 BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr);
5cd6d0e5
PP
671 status = BT_BFCR_STATUS_EOF;
672 goto end;
673 }
674
675 available = available_bits(bfcr);
676 needed_bits = fc->size - bfcr->stitch.at;
ef267d12 677 BT_COMP_LOGT("Continuing basic field decoding: "
fca9fd7d 678 "bfcr-addr=%p, field-size=%u, needed-size=%zu, "
5cd6d0e5
PP
679 "available-size=%zu",
680 bfcr, fc->size, needed_bits, available);
681 if (needed_bits <= available) {
682 /* We have all the bits; append to stitch, then decode */
683 stitch_append_from_buf(bfcr, needed_bits);
684 status = read_basic_and_call_cb(bfcr, bfcr->stitch.buf,
685 bfcr->stitch.offset);
686 if (status != BT_BFCR_STATUS_OK) {
c4a714d2 687 BT_COMP_LOGW("Cannot read basic field: "
5cd6d0e5
PP
688 "bfcr-addr=%p, fc-addr=%p, status=%s",
689 bfcr, bfcr->cur_basic_field_class,
690 bt_bfcr_status_string(status));
691 goto end;
692 }
693
694 if (stack_empty(bfcr->stack)) {
695 /* Root is a basic class */
696 bfcr->state = BFCR_STATE_DONE;
697 } else {
698 /* Go to next field */
699 stack_top(bfcr->stack)->index++;
700 bfcr->state = BFCR_STATE_NEXT_FIELD;
701 bfcr->last_bo = bfcr->cur_bo;
702 }
703 goto end;
704 }
705
706 /* We are here; it means we don't have enough data to decode this */
ef267d12 707 BT_COMP_LOGT_STR("Not enough data to read the next basic field: appending to stitch buffer.");
5cd6d0e5
PP
708 stitch_append_from_remaining_buf(bfcr);
709 status = BT_BFCR_STATUS_EOF;
710
711end:
712 return status;
713}
714
715static inline
716enum bt_bfcr_status read_bit_array_class_and_call_begin(struct bt_bfcr *bfcr,
717 read_basic_and_call_cb_t read_basic_and_call_cb)
718{
719 size_t available;
720 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
087cd0f5 721 ctf_field_class_bit_array *fc = ctf_field_class_as_bit_array(bfcr->cur_basic_field_class);
5cd6d0e5
PP
722
723 if (!at_least_one_bit_left(bfcr)) {
ef267d12 724 BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr);
5cd6d0e5
PP
725 status = BT_BFCR_STATUS_EOF;
726 goto end;
727 }
728
729 status = validate_contiguous_bo(bfcr, fc->byte_order);
730 if (status != BT_BFCR_STATUS_OK) {
731 /* validate_contiguous_bo() logs errors */
732 goto end;
733 }
734
735 available = available_bits(bfcr);
736
737 if (fc->size <= available) {
738 /* We have all the bits; decode and set now */
98b15851 739 BT_ASSERT_DBG(bfcr->buf.addr);
5cd6d0e5
PP
740 status = read_basic_and_call_cb(bfcr, bfcr->buf.addr,
741 buf_at_from_addr(bfcr));
742 if (status != BT_BFCR_STATUS_OK) {
c4a714d2 743 BT_COMP_LOGW("Cannot read basic field: "
5cd6d0e5
PP
744 "bfcr-addr=%p, fc-addr=%p, status=%s",
745 bfcr, bfcr->cur_basic_field_class,
746 bt_bfcr_status_string(status));
747 goto end;
748 }
749
750 consume_bits(bfcr, fc->size);
751
752 if (stack_empty(bfcr->stack)) {
753 /* Root is a basic class */
754 bfcr->state = BFCR_STATE_DONE;
755 } else {
756 /* Go to next field */
757 stack_top(bfcr->stack)->index++;
758 bfcr->state = BFCR_STATE_NEXT_FIELD;
759 bfcr->last_bo = bfcr->cur_bo;
760 }
761
762 goto end;
763 }
764
765 /* We are here; it means we don't have enough data to decode this */
ef267d12 766 BT_COMP_LOGT_STR("Not enough data to read the next basic field: setting stitch buffer.");
5cd6d0e5
PP
767 stitch_set_from_remaining_buf(bfcr);
768 bfcr->state = BFCR_STATE_READ_BASIC_CONTINUE;
769 status = BT_BFCR_STATUS_EOF;
770
771end:
772 return status;
773}
774
775static inline
776enum bt_bfcr_status read_basic_int_class_and_call_begin(
777 struct bt_bfcr *bfcr)
778{
779 return read_bit_array_class_and_call_begin(bfcr, read_basic_int_and_call_cb);
780}
781
782static inline
783enum bt_bfcr_status read_basic_int_class_and_call_continue(
784 struct bt_bfcr *bfcr)
785{
786 return read_bit_array_class_and_call_continue(bfcr,
787 read_basic_int_and_call_cb);
788}
789
790static inline
791enum bt_bfcr_status read_basic_float_class_and_call_begin(
792 struct bt_bfcr *bfcr)
793{
794 return read_bit_array_class_and_call_begin(bfcr,
795 read_basic_float_and_call_cb);
796}
797
798static inline
799enum bt_bfcr_status read_basic_float_class_and_call_continue(
800 struct bt_bfcr *bfcr)
801{
802 return read_bit_array_class_and_call_continue(bfcr,
803 read_basic_float_and_call_cb);
804}
805
806static inline
807enum bt_bfcr_status read_basic_string_class_and_call(
808 struct bt_bfcr *bfcr, bool begin)
809{
810 size_t buf_at_bytes;
811 const uint8_t *result;
812 size_t available_bytes;
813 const uint8_t *first_chr;
814 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
815
816 if (!at_least_one_bit_left(bfcr)) {
ef267d12 817 BT_COMP_LOGT("Reached end of data: bfcr-addr=%p", bfcr);
5cd6d0e5
PP
818 status = BT_BFCR_STATUS_EOF;
819 goto end;
820 }
821
98b15851 822 BT_ASSERT_DBG(buf_at_from_addr(bfcr) % 8 == 0);
5cd6d0e5
PP
823 available_bytes = BITS_TO_BYTES_FLOOR(available_bits(bfcr));
824 buf_at_bytes = BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr));
98b15851 825 BT_ASSERT_DBG(bfcr->buf.addr);
5cd6d0e5 826 first_chr = &bfcr->buf.addr[buf_at_bytes];
087cd0f5 827 result = (const uint8_t *) memchr(first_chr, '\0', available_bytes);
5cd6d0e5
PP
828
829 if (begin && bfcr->user.cbs.classes.string_begin) {
ef267d12 830 BT_COMP_LOGT("Calling user function (string, beginning).");
5cd6d0e5
PP
831 status = bfcr->user.cbs.classes.string_begin(
832 bfcr->cur_basic_field_class, bfcr->user.data);
ef267d12 833 BT_COMP_LOGT("User function returned: status=%s",
5cd6d0e5
PP
834 bt_bfcr_status_string(status));
835 if (status != BT_BFCR_STATUS_OK) {
c4a714d2 836 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s",
5cd6d0e5
PP
837 bfcr, bt_bfcr_status_string(status));
838 goto end;
839 }
840 }
841
842 if (!result) {
843 /* No null character yet */
844 if (bfcr->user.cbs.classes.string) {
ef267d12 845 BT_COMP_LOGT("Calling user function (substring).");
5cd6d0e5
PP
846 status = bfcr->user.cbs.classes.string(
847 (const char *) first_chr,
848 available_bytes, bfcr->cur_basic_field_class,
849 bfcr->user.data);
ef267d12 850 BT_COMP_LOGT("User function returned: status=%s",
5cd6d0e5
PP
851 bt_bfcr_status_string(status));
852 if (status != BT_BFCR_STATUS_OK) {
c4a714d2 853 BT_COMP_LOGW("User function failed: "
5cd6d0e5
PP
854 "bfcr-addr=%p, status=%s",
855 bfcr, bt_bfcr_status_string(status));
856 goto end;
857 }
858 }
859
860 consume_bits(bfcr, BYTES_TO_BITS(available_bytes));
861 bfcr->state = BFCR_STATE_READ_BASIC_CONTINUE;
862 status = BT_BFCR_STATUS_EOF;
863 } else {
864 /* Found the null character */
865 size_t result_len = (size_t) (result - first_chr);
866
867 if (bfcr->user.cbs.classes.string && result_len) {
ef267d12 868 BT_COMP_LOGT("Calling user function (substring).");
5cd6d0e5
PP
869 status = bfcr->user.cbs.classes.string(
870 (const char *) first_chr,
871 result_len, bfcr->cur_basic_field_class,
872 bfcr->user.data);
ef267d12 873 BT_COMP_LOGT("User function returned: status=%s",
5cd6d0e5
PP
874 bt_bfcr_status_string(status));
875 if (status != BT_BFCR_STATUS_OK) {
c4a714d2 876 BT_COMP_LOGW("User function failed: "
5cd6d0e5
PP
877 "bfcr-addr=%p, status=%s",
878 bfcr, bt_bfcr_status_string(status));
879 goto end;
880 }
881 }
882
883 if (bfcr->user.cbs.classes.string_end) {
ef267d12 884 BT_COMP_LOGT("Calling user function (string, end).");
5cd6d0e5
PP
885 status = bfcr->user.cbs.classes.string_end(
886 bfcr->cur_basic_field_class, bfcr->user.data);
ef267d12 887 BT_COMP_LOGT("User function returned: status=%s",
5cd6d0e5
PP
888 bt_bfcr_status_string(status));
889 if (status != BT_BFCR_STATUS_OK) {
c4a714d2 890 BT_COMP_LOGW("User function failed: "
5cd6d0e5
PP
891 "bfcr-addr=%p, status=%s",
892 bfcr, bt_bfcr_status_string(status));
893 goto end;
894 }
895 }
896
897 consume_bits(bfcr, BYTES_TO_BITS(result_len + 1));
898
899 if (stack_empty(bfcr->stack)) {
900 /* Root is a basic class */
901 bfcr->state = BFCR_STATE_DONE;
902 } else {
903 /* Go to next field */
904 stack_top(bfcr->stack)->index++;
905 bfcr->state = BFCR_STATE_NEXT_FIELD;
906 bfcr->last_bo = bfcr->cur_bo;
907 }
908 }
909
910end:
911 return status;
912}
913
914static inline
915enum bt_bfcr_status read_basic_begin_state(struct bt_bfcr *bfcr)
916{
917 enum bt_bfcr_status status;
918
98b15851 919 BT_ASSERT_DBG(bfcr->cur_basic_field_class);
5cd6d0e5 920
864cad70
PP
921 switch (bfcr->cur_basic_field_class->type) {
922 case CTF_FIELD_CLASS_TYPE_INT:
923 case CTF_FIELD_CLASS_TYPE_ENUM:
5cd6d0e5
PP
924 status = read_basic_int_class_and_call_begin(bfcr);
925 break;
864cad70 926 case CTF_FIELD_CLASS_TYPE_FLOAT:
5cd6d0e5
PP
927 status = read_basic_float_class_and_call_begin(bfcr);
928 break;
864cad70 929 case CTF_FIELD_CLASS_TYPE_STRING:
5cd6d0e5
PP
930 status = read_basic_string_class_and_call(bfcr, true);
931 break;
932 default:
498e7994 933 bt_common_abort();
5cd6d0e5
PP
934 }
935
936 return status;
937}
938
939static inline
940enum bt_bfcr_status read_basic_continue_state(struct bt_bfcr *bfcr)
941{
942 enum bt_bfcr_status status;
943
98b15851 944 BT_ASSERT_DBG(bfcr->cur_basic_field_class);
5cd6d0e5 945
864cad70
PP
946 switch (bfcr->cur_basic_field_class->type) {
947 case CTF_FIELD_CLASS_TYPE_INT:
948 case CTF_FIELD_CLASS_TYPE_ENUM:
5cd6d0e5
PP
949 status = read_basic_int_class_and_call_continue(bfcr);
950 break;
864cad70 951 case CTF_FIELD_CLASS_TYPE_FLOAT:
5cd6d0e5
PP
952 status = read_basic_float_class_and_call_continue(bfcr);
953 break;
864cad70 954 case CTF_FIELD_CLASS_TYPE_STRING:
5cd6d0e5
PP
955 status = read_basic_string_class_and_call(bfcr, false);
956 break;
957 default:
498e7994 958 bt_common_abort();
5cd6d0e5
PP
959 }
960
961 return status;
962}
963
964static inline
965size_t bits_to_skip_to_align_to(struct bt_bfcr *bfcr, size_t align)
966{
967 size_t aligned_packet_at;
968
328342cd 969 aligned_packet_at = BT_ALIGN(packet_at(bfcr), align);
5cd6d0e5
PP
970 return aligned_packet_at - packet_at(bfcr);
971}
972
973static inline
974enum bt_bfcr_status align_class_state(struct bt_bfcr *bfcr,
975 struct ctf_field_class *field_class, enum bfcr_state next_state)
976{
977 unsigned int field_alignment;
978 size_t skip_bits;
979 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
980
981 /* Get field's alignment */
982 field_alignment = field_class->alignment;
983
984 /*
985 * 0 means "undefined" for variants; what we really want is 1
986 * (always aligned)
987 */
98b15851 988 BT_ASSERT_DBG(field_alignment >= 1);
5cd6d0e5
PP
989
990 /* Compute how many bits we need to skip */
991 skip_bits = bits_to_skip_to_align_to(bfcr, (size_t) field_alignment);
992
993 /* Nothing to skip? aligned */
994 if (skip_bits == 0) {
995 bfcr->state = next_state;
996 goto end;
997 }
998
999 /* Make sure there's at least one bit left */
1000 if (!at_least_one_bit_left(bfcr)) {
1001 status = BT_BFCR_STATUS_EOF;
1002 goto end;
1003 }
1004
1005 /* Consume as many bits as possible in what's left */
1006 consume_bits(bfcr, MIN(available_bits(bfcr), skip_bits));
1007
1008 /* Are we done now? */
1009 skip_bits = bits_to_skip_to_align_to(bfcr, field_alignment);
1010 if (skip_bits == 0) {
1011 /* Yes: go to next state */
1012 bfcr->state = next_state;
1013 goto end;
1014 } else {
1015 /* No: need more data */
ef267d12 1016 BT_COMP_LOGT("Reached end of data when aligning: bfcr-addr=%p", bfcr);
5cd6d0e5
PP
1017 status = BT_BFCR_STATUS_EOF;
1018 }
1019
1020end:
1021 return status;
1022}
1023
1024static inline
1025enum bt_bfcr_status next_field_state(struct bt_bfcr *bfcr)
1026{
1027 int ret;
1028 struct stack_entry *top;
1029 struct ctf_field_class *next_field_class = NULL;
1030 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
1031
1032 if (stack_empty(bfcr->stack)) {
1033 goto end;
1034 }
1035
1036 top = stack_top(bfcr->stack);
1037
1038 /* Are we done with this base class? */
1039 while (top->index == top->base_len) {
1040 if (bfcr->user.cbs.classes.compound_end) {
ef267d12 1041 BT_COMP_LOGT("Calling user function (compound, end).");
5cd6d0e5
PP
1042 status = bfcr->user.cbs.classes.compound_end(
1043 top->base_class, bfcr->user.data);
ef267d12 1044 BT_COMP_LOGT("User function returned: status=%s",
5cd6d0e5
PP
1045 bt_bfcr_status_string(status));
1046 if (status != BT_BFCR_STATUS_OK) {
c4a714d2 1047 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s",
5cd6d0e5
PP
1048 bfcr, bt_bfcr_status_string(status));
1049 goto end;
1050 }
1051 }
1052
1053 stack_pop(bfcr->stack);
1054
1055 /* Are we done with the root class? */
1056 if (stack_empty(bfcr->stack)) {
1057 bfcr->state = BFCR_STATE_DONE;
1058 goto end;
1059 }
1060
1061 top = stack_top(bfcr->stack);
1062 top->index++;
1063 }
1064
1065 /* Get next field's class */
864cad70
PP
1066 switch (top->base_class->type) {
1067 case CTF_FIELD_CLASS_TYPE_STRUCT:
5cd6d0e5 1068 next_field_class = ctf_field_class_struct_borrow_member_by_index(
087cd0f5 1069 ctf_field_class_as_struct(top->base_class), (uint64_t) top->index)->fc;
5cd6d0e5 1070 break;
864cad70
PP
1071 case CTF_FIELD_CLASS_TYPE_ARRAY:
1072 case CTF_FIELD_CLASS_TYPE_SEQUENCE:
5cd6d0e5 1073 {
087cd0f5
SM
1074 ctf_field_class_array_base *array_fc =
1075 ctf_field_class_as_array_base(top->base_class);
5cd6d0e5
PP
1076
1077 next_field_class = array_fc->elem_fc;
1078 break;
1079 }
864cad70 1080 case CTF_FIELD_CLASS_TYPE_VARIANT:
5cd6d0e5
PP
1081 /* Variant classes are dynamic: the user should know! */
1082 next_field_class =
1083 bfcr->user.cbs.query.borrow_variant_selected_field_class(
1084 top->base_class, bfcr->user.data);
1085 break;
1086 default:
1087 break;
1088 }
1089
1090 if (!next_field_class) {
c4a714d2 1091 BT_COMP_LOGW("Cannot get the field class of the next field: "
864cad70 1092 "bfcr-addr=%p, base-fc-addr=%p, base-fc-type=%d, "
5cd6d0e5 1093 "index=%" PRId64,
864cad70
PP
1094 bfcr, top->base_class, top->base_class->type,
1095 top->index);
5cd6d0e5
PP
1096 status = BT_BFCR_STATUS_ERROR;
1097 goto end;
1098 }
1099
1100 if (next_field_class->is_compound) {
1101 if (bfcr->user.cbs.classes.compound_begin) {
ef267d12 1102 BT_COMP_LOGT("Calling user function (compound, begin).");
5cd6d0e5
PP
1103 status = bfcr->user.cbs.classes.compound_begin(
1104 next_field_class, bfcr->user.data);
ef267d12 1105 BT_COMP_LOGT("User function returned: status=%s",
5cd6d0e5
PP
1106 bt_bfcr_status_string(status));
1107 if (status != BT_BFCR_STATUS_OK) {
c4a714d2 1108 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s",
5cd6d0e5
PP
1109 bfcr, bt_bfcr_status_string(status));
1110 goto end;
1111 }
1112 }
1113
1114 ret = stack_push_with_len(bfcr, next_field_class);
1115 if (ret) {
1116 /* stack_push_with_len() logs errors */
1117 status = BT_BFCR_STATUS_ERROR;
1118 goto end;
1119 }
1120
1121 /* Next state: align a compound class */
1122 bfcr->state = BFCR_STATE_ALIGN_COMPOUND;
1123 } else {
1124 /* Replace current basic field class */
ef267d12 1125 BT_COMP_LOGT("Replacing current basic field class: "
5cd6d0e5
PP
1126 "bfcr-addr=%p, cur-basic-fc-addr=%p, "
1127 "next-basic-fc-addr=%p",
1128 bfcr, bfcr->cur_basic_field_class, next_field_class);
1129 bfcr->cur_basic_field_class = next_field_class;
1130
1131 /* Next state: align a basic class */
1132 bfcr->state = BFCR_STATE_ALIGN_BASIC;
1133 }
1134
1135end:
1136 return status;
1137}
1138
1139static inline
1140enum bt_bfcr_status handle_state(struct bt_bfcr *bfcr)
1141{
1142 enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
1143
ef267d12 1144 BT_COMP_LOGT("Handling state: bfcr-addr=%p, state=%s",
5cd6d0e5
PP
1145 bfcr, bfcr_state_string(bfcr->state));
1146
1147 switch (bfcr->state) {
1148 case BFCR_STATE_NEXT_FIELD:
1149 status = next_field_state(bfcr);
1150 break;
1151 case BFCR_STATE_ALIGN_BASIC:
1152 status = align_class_state(bfcr, bfcr->cur_basic_field_class,
1153 BFCR_STATE_READ_BASIC_BEGIN);
1154 break;
1155 case BFCR_STATE_ALIGN_COMPOUND:
1156 status = align_class_state(bfcr, stack_top(bfcr->stack)->base_class,
1157 BFCR_STATE_NEXT_FIELD);
1158 break;
1159 case BFCR_STATE_READ_BASIC_BEGIN:
1160 status = read_basic_begin_state(bfcr);
1161 break;
1162 case BFCR_STATE_READ_BASIC_CONTINUE:
1163 status = read_basic_continue_state(bfcr);
1164 break;
1165 case BFCR_STATE_DONE:
1166 break;
1167 }
1168
ef267d12 1169 BT_COMP_LOGT("Handled state: bfcr-addr=%p, status=%s",
5cd6d0e5
PP
1170 bfcr, bt_bfcr_status_string(status));
1171 return status;
1172}
1173
1174BT_HIDDEN
80870e64 1175struct bt_bfcr *bt_bfcr_create(struct bt_bfcr_cbs cbs, void *data,
c4a714d2 1176 bt_logging_level log_level, bt_self_component *self_comp)
5cd6d0e5
PP
1177{
1178 struct bt_bfcr *bfcr;
1179
c4a714d2 1180 BT_COMP_LOG_CUR_LVL(BT_LOG_DEBUG, log_level, self_comp,
80870e64 1181 "Creating binary field class reader (BFCR).");
5cd6d0e5
PP
1182 bfcr = g_new0(struct bt_bfcr, 1);
1183 if (!bfcr) {
c4a714d2 1184 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_comp,
80870e64 1185 "Failed to allocate one binary class reader.");
5cd6d0e5
PP
1186 goto end;
1187 }
1188
80870e64 1189 bfcr->log_level = log_level;
c4a714d2 1190 bfcr->self_comp = self_comp;
80870e64 1191 bfcr->stack = stack_new(bfcr);
5cd6d0e5 1192 if (!bfcr->stack) {
c4a714d2 1193 BT_COMP_LOGE_STR("Cannot create BFCR's stack.");
5cd6d0e5
PP
1194 bt_bfcr_destroy(bfcr);
1195 bfcr = NULL;
1196 goto end;
1197 }
1198
1199 bfcr->state = BFCR_STATE_NEXT_FIELD;
1200 bfcr->user.cbs = cbs;
1201 bfcr->user.data = data;
c4a714d2 1202 BT_COMP_LOGD("Created BFCR: addr=%p", bfcr);
5cd6d0e5
PP
1203
1204end:
1205 return bfcr;
1206}
1207
1208BT_HIDDEN
1209void bt_bfcr_destroy(struct bt_bfcr *bfcr)
1210{
1211 if (bfcr->stack) {
1212 stack_destroy(bfcr->stack);
1213 }
1214
c4a714d2 1215 BT_COMP_LOGD("Destroying BFCR: addr=%p", bfcr);
5cd6d0e5
PP
1216 g_free(bfcr);
1217}
1218
1219static
1220void reset(struct bt_bfcr *bfcr)
1221{
c4a714d2 1222 BT_COMP_LOGD("Resetting BFCR: addr=%p", bfcr);
5cd6d0e5
PP
1223 stack_clear(bfcr->stack);
1224 stitch_reset(bfcr);
1225 bfcr->buf.addr = NULL;
e2bd7d40 1226 bfcr->last_bo = CTF_BYTE_ORDER_UNKNOWN;
5cd6d0e5
PP
1227}
1228
1229static
1230void update_packet_offset(struct bt_bfcr *bfcr)
1231{
ef267d12 1232 BT_COMP_LOGT("Updating packet offset for next call: "
5cd6d0e5
PP
1233 "bfcr-addr=%p, cur-packet-offset=%zu, next-packet-offset=%zu",
1234 bfcr, bfcr->buf.packet_offset,
1235 bfcr->buf.packet_offset + bfcr->buf.at);
1236 bfcr->buf.packet_offset += bfcr->buf.at;
1237}
1238
1239BT_HIDDEN
1240size_t bt_bfcr_start(struct bt_bfcr *bfcr,
1241 struct ctf_field_class *cls, const uint8_t *buf,
1242 size_t offset, size_t packet_offset, size_t sz,
1243 enum bt_bfcr_status *status)
1244{
98b15851
PP
1245 BT_ASSERT_DBG(bfcr);
1246 BT_ASSERT_DBG(BYTES_TO_BITS(sz) >= offset);
5cd6d0e5
PP
1247 reset(bfcr);
1248 bfcr->buf.addr = buf;
1249 bfcr->buf.offset = offset;
1250 bfcr->buf.at = 0;
1251 bfcr->buf.packet_offset = packet_offset;
1252 bfcr->buf.buf_sz = sz;
1253 bfcr->buf.sz = BYTES_TO_BITS(sz) - offset;
1254 *status = BT_BFCR_STATUS_OK;
1255
ef267d12 1256 BT_COMP_LOGT("Starting decoding: bfcr-addr=%p, fc-addr=%p, "
5cd6d0e5
PP
1257 "buf-addr=%p, buf-size=%zu, offset=%zu, "
1258 "packet-offset=%zu",
1259 bfcr, cls, buf, sz, offset, packet_offset);
1260
1261 /* Set root class */
1262 if (cls->is_compound) {
1263 /* Compound class: push on visit stack */
1264 int stack_ret;
1265
1266 if (bfcr->user.cbs.classes.compound_begin) {
ef267d12 1267 BT_COMP_LOGT("Calling user function (compound, begin).");
5cd6d0e5
PP
1268 *status = bfcr->user.cbs.classes.compound_begin(
1269 cls, bfcr->user.data);
ef267d12 1270 BT_COMP_LOGT("User function returned: status=%s",
5cd6d0e5
PP
1271 bt_bfcr_status_string(*status));
1272 if (*status != BT_BFCR_STATUS_OK) {
c4a714d2 1273 BT_COMP_LOGW("User function failed: bfcr-addr=%p, status=%s",
5cd6d0e5
PP
1274 bfcr, bt_bfcr_status_string(*status));
1275 goto end;
1276 }
1277 }
1278
1279 stack_ret = stack_push_with_len(bfcr, cls);
1280 if (stack_ret) {
1281 /* stack_push_with_len() logs errors */
1282 *status = BT_BFCR_STATUS_ERROR;
1283 goto end;
1284 }
1285
1286 bfcr->state = BFCR_STATE_ALIGN_COMPOUND;
1287 } else {
1288 /* Basic class: set as current basic class */
1289 bfcr->cur_basic_field_class = cls;
1290 bfcr->state = BFCR_STATE_ALIGN_BASIC;
1291 }
1292
1293 /* Run the machine! */
ef267d12 1294 BT_COMP_LOGT_STR("Running the state machine.");
5cd6d0e5
PP
1295
1296 while (true) {
1297 *status = handle_state(bfcr);
1298 if (*status != BT_BFCR_STATUS_OK ||
1299 bfcr->state == BFCR_STATE_DONE) {
1300 break;
1301 }
1302 }
1303
1304 /* Update packet offset for next time */
1305 update_packet_offset(bfcr);
1306
1307end:
1308 return bfcr->buf.at;
1309}
1310
1311BT_HIDDEN
1312size_t bt_bfcr_continue(struct bt_bfcr *bfcr, const uint8_t *buf, size_t sz,
1313 enum bt_bfcr_status *status)
1314{
98b15851
PP
1315 BT_ASSERT_DBG(bfcr);
1316 BT_ASSERT_DBG(buf);
1317 BT_ASSERT_DBG(sz > 0);
5cd6d0e5
PP
1318 bfcr->buf.addr = buf;
1319 bfcr->buf.offset = 0;
1320 bfcr->buf.at = 0;
1321 bfcr->buf.buf_sz = sz;
1322 bfcr->buf.sz = BYTES_TO_BITS(sz);
1323 *status = BT_BFCR_STATUS_OK;
1324
ef267d12 1325 BT_COMP_LOGT("Continuing decoding: bfcr-addr=%p, buf-addr=%p, buf-size=%zu",
5cd6d0e5
PP
1326 bfcr, buf, sz);
1327
1328 /* Continue running the machine */
ef267d12 1329 BT_COMP_LOGT_STR("Running the state machine.");
5cd6d0e5
PP
1330
1331 while (true) {
1332 *status = handle_state(bfcr);
1333 if (*status != BT_BFCR_STATUS_OK ||
1334 bfcr->state == BFCR_STATE_DONE) {
1335 break;
1336 }
1337 }
1338
1339 /* Update packet offset for next time */
1340 update_packet_offset(bfcr);
1341 return bfcr->buf.at;
1342}
1343
1344BT_HIDDEN
1345void bt_bfcr_set_unsigned_int_cb(struct bt_bfcr *bfcr,
1346 bt_bfcr_unsigned_int_cb_func cb)
1347{
98b15851
PP
1348 BT_ASSERT_DBG(bfcr);
1349 BT_ASSERT_DBG(cb);
5cd6d0e5
PP
1350 bfcr->user.cbs.classes.unsigned_int = cb;
1351}
This page took 0.140274 seconds and 4 git commands to generate.