Host C Specs


Directory: src/c/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 11 / 0 / 11
Functions: 100.0% 2 / 0 / 2
Branches: 93.8% 15 / 0 / 16

core/wire/wire_read.h
Line Branch Exec Source
1 /**
2 * @file wire_read.h
3 * @brief Reads the values the phone packs into a message.
4 *
5 * The phone is free to send an integer one, two, or four bytes wide, and it says which by the
6 * length it puts beside the value rather than by the type. The values sit back to back with
7 * nothing between them, so a reader that takes the type's word for the width and grabs four bytes
8 * off a one-byte value walks straight into whatever is packed behind it. That is what these are
9 * for: the width decides how many bytes get read, and anything else is refused.
10 *
11 * Header only on purpose. There is one caller on the watch (tuple_read.c) and the bodies are
12 * smaller than a call would be, so they fold into it and nothing is spent on getting there.
13 *
14 * @ingroup lib_core
15 */
16 #pragma once
17 #include <stdbool.h>
18 #include <stdint.h>
19
20 #include "io/bytes_le.h"
21
22 /**
23 * @addtogroup lib_core
24 * @{
25 */
26
27 /**
28 * @brief Reads a little-endian integer of exactly @p length bytes.
29 *
30 * @param is_signed Whether the value is signed. Decides only what the top bit means.
31 * @param length How many bytes the value occupies. 1, 2, and 4 are the widths a sender may use,
32 * and anything else is refused rather than guessed at.
33 * @param value The first byte of the value.
34 * @param fallback Returned when the width is not one a sender may use, or there is no value.
35 * @return The value, or @p fallback.
36 */
37 10 static inline int32_t wire_int_or(bool is_signed, uint16_t length, const uint8_t *value, int32_t fallback)
38 {
39
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 9 times.
10 if (!value)
40 {
41 1 return fallback;
42 }
43
44
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
9 switch (length)
45 {
46 // a byte read signed is -128 to 127 and unsigned is 0 to 255
47 // that is the only thing the signedness decides at this width
48
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
3 case 1: return is_signed ? (int32_t)(int8_t)value[0] : (int32_t)value[0];
49
50 // read the pair as signed and take the sign back off when it is not wanted
51 // so the unsigned half lands on 0 to 65535 rather than going negative at the top
52 1 case 2: return is_signed ? (int32_t)read_i16_le(value)
53
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
3 : (int32_t)(uint16_t)read_i16_le(value);
54
55 // four bytes fill the whole width either way so the bits are the same
56 // and only the caller's reading of the top one differs
57 2 case 4: return read_i32_le(value);
58
59 2 default: return fallback;
60 }
61 }
62
63 /**
64 * @brief Whether a string of @p length bytes carries its terminator inside itself.
65 *
66 * A sender is supposed to include the terminator and nothing re-checks that it did. A string
67 * without one is not a string: reading it runs on past the end looking for a zero byte that
68 * belongs to something else, or to nothing at all.
69 *
70 * @param s The first byte of the string.
71 * @param length How many bytes the string occupies, terminator included.
72 * @return Whether it is safe to read as a C string.
73 */
74 5 static inline bool wire_cstring_terminated(const char *s, uint16_t length)
75 {
76
5/6
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 2 times.
5 return s && length > 0 && s[length - 1] == '\0';
77 }
78
79 /** @} */
80