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