Coverage Report

Created: 2025-10-10 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libcbor/src/cbor/encoding.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
3
 *
4
 * libcbor is free software; you can redistribute it and/or modify
5
 * it under the terms of the MIT license. See LICENSE for details.
6
 */
7
8
#include "encoding.h"
9
10
#include <math.h>
11
12
#include "internal/encoders.h"
13
14
size_t cbor_encode_uint8(uint8_t value, unsigned char* buffer,
15
8.51M
                         size_t buffer_size) {
16
8.51M
  return _cbor_encode_uint8(value, buffer, buffer_size, 0x00);
17
8.51M
}
18
19
size_t cbor_encode_uint16(uint16_t value, unsigned char* buffer,
20
5.54k
                          size_t buffer_size) {
21
5.54k
  return _cbor_encode_uint16(value, buffer, buffer_size, 0x00);
22
5.54k
}
23
24
size_t cbor_encode_uint32(uint32_t value, unsigned char* buffer,
25
287k
                          size_t buffer_size) {
26
287k
  return _cbor_encode_uint32(value, buffer, buffer_size, 0x00);
27
287k
}
28
29
size_t cbor_encode_uint64(uint64_t value, unsigned char* buffer,
30
5.22k
                          size_t buffer_size) {
31
5.22k
  return _cbor_encode_uint64(value, buffer, buffer_size, 0x00);
32
5.22k
}
33
34
size_t cbor_encode_uint(uint64_t value, unsigned char* buffer,
35
0
                        size_t buffer_size) {
36
0
  return _cbor_encode_uint(value, buffer, buffer_size, 0x00);
37
0
}
38
39
size_t cbor_encode_negint8(uint8_t value, unsigned char* buffer,
40
2.98M
                           size_t buffer_size) {
41
2.98M
  return _cbor_encode_uint8(value, buffer, buffer_size, 0x20);
42
2.98M
}
43
44
size_t cbor_encode_negint16(uint16_t value, unsigned char* buffer,
45
19.8k
                            size_t buffer_size) {
46
19.8k
  return _cbor_encode_uint16(value, buffer, buffer_size, 0x20);
47
19.8k
}
48
49
size_t cbor_encode_negint32(uint32_t value, unsigned char* buffer,
50
10.5k
                            size_t buffer_size) {
51
10.5k
  return _cbor_encode_uint32(value, buffer, buffer_size, 0x20);
52
10.5k
}
53
54
size_t cbor_encode_negint64(uint64_t value, unsigned char* buffer,
55
1.48k
                            size_t buffer_size) {
56
1.48k
  return _cbor_encode_uint64(value, buffer, buffer_size, 0x20);
57
1.48k
}
58
59
size_t cbor_encode_negint(uint64_t value, unsigned char* buffer,
60
0
                          size_t buffer_size) {
61
0
  return _cbor_encode_uint(value, buffer, buffer_size, 0x20);
62
0
}
63
64
size_t cbor_encode_bytestring_start(size_t length, unsigned char* buffer,
65
478k
                                    size_t buffer_size) {
66
478k
  return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0x40);
67
478k
}
68
69
size_t _cbor_encode_byte(uint8_t value, unsigned char* buffer,
70
821k
                         size_t buffer_size) {
71
821k
  if (buffer_size >= 1) {
72
821k
    buffer[0] = value;
73
821k
    return 1;
74
821k
  } else
75
0
    return 0;
76
821k
}
77
78
size_t cbor_encode_indef_bytestring_start(unsigned char* buffer,
79
566
                                          size_t buffer_size) {
80
566
  return _cbor_encode_byte(0x5F, buffer, buffer_size);
81
566
}
82
83
size_t cbor_encode_string_start(size_t length, unsigned char* buffer,
84
289k
                                size_t buffer_size) {
85
289k
  return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0x60);
86
289k
}
87
88
size_t cbor_encode_indef_string_start(unsigned char* buffer,
89
6.40k
                                      size_t buffer_size) {
90
6.40k
  return _cbor_encode_byte(0x7F, buffer, buffer_size);
91
6.40k
}
92
93
size_t cbor_encode_array_start(size_t length, unsigned char* buffer,
94
5.21M
                               size_t buffer_size) {
95
5.21M
  return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0x80);
96
5.21M
}
97
98
size_t cbor_encode_indef_array_start(unsigned char* buffer,
99
401k
                                     size_t buffer_size) {
100
401k
  return _cbor_encode_byte(0x9F, buffer, buffer_size);
101
401k
}
102
103
size_t cbor_encode_map_start(size_t length, unsigned char* buffer,
104
34.0k
                             size_t buffer_size) {
105
34.0k
  return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0xA0);
106
34.0k
}
107
108
2.12k
size_t cbor_encode_indef_map_start(unsigned char* buffer, size_t buffer_size) {
109
2.12k
  return _cbor_encode_byte(0xBF, buffer, buffer_size);
110
2.12k
}
111
112
size_t cbor_encode_tag(uint64_t value, unsigned char* buffer,
113
154k
                       size_t buffer_size) {
114
154k
  return _cbor_encode_uint(value, buffer, buffer_size, 0xC0);
115
154k
}
116
117
0
size_t cbor_encode_bool(bool value, unsigned char* buffer, size_t buffer_size) {
118
0
  return value ? _cbor_encode_byte(0xF5, buffer, buffer_size)
119
0
               : _cbor_encode_byte(0xF4, buffer, buffer_size);
120
0
}
121
122
0
size_t cbor_encode_null(unsigned char* buffer, size_t buffer_size) {
123
0
  return _cbor_encode_byte(0xF6, buffer, buffer_size);
124
0
}
125
126
0
size_t cbor_encode_undef(unsigned char* buffer, size_t buffer_size) {
127
0
  return _cbor_encode_byte(0xF7, buffer, buffer_size);
128
0
}
129
130
size_t cbor_encode_half(float value, unsigned char* buffer,
131
59.3k
                        size_t buffer_size) {
132
  // TODO: Broken on systems that do not use IEEE 754
133
  /* Assuming value is normalized */
134
59.3k
  uint32_t val = ((union _cbor_float_helper){.as_float = value}).as_uint;
135
59.3k
  uint16_t res;
136
59.3k
  uint8_t exp = (uint8_t)((val & 0x7F800000u) >>
137
59.3k
                          23u); /* 0b0111_1111_1000_0000_0000_0000_0000_0000 */
138
59.3k
  uint32_t mant =
139
59.3k
      val & 0x7FFFFFu; /* 0b0000_0000_0111_1111_1111_1111_1111_1111 */
140
59.3k
  if (exp == 0xFF) {   /* Infinity or NaNs */
141
4.66k
    if (isnan(value)) {
142
      // Note: Values of signaling NaNs are discarded. See `cbor_encode_single`.
143
3.60k
      res = (uint16_t)0x007e00;
144
3.60k
    } else {
145
      // If the mantissa is non-zero, we have a NaN, but those are handled
146
      // above. See
147
      // https://en.wikipedia.org/wiki/Half-precision_floating-point_format
148
1.06k
      CBOR_ASSERT(mant == 0u);
149
1.06k
      res = (uint16_t)((val & 0x80000000u) >> 16u | 0x7C00u);
150
1.06k
    }
151
54.6k
  } else if (exp == 0x00) { /* Zeroes or subnorms */
152
612
    res = (uint16_t)((val & 0x80000000u) >> 16u | mant >> 13u);
153
54.0k
  } else { /* Normal numbers */
154
54.0k
    int8_t logical_exp = (int8_t)(exp - 127);
155
54.0k
    CBOR_ASSERT(logical_exp == exp - 127);
156
157
    // Now we know that 2^exp <= 0 logically
158
54.0k
    if (logical_exp < -24) {
159
      /* No unambiguous representation exists, this float is not a half float
160
         and is too small to be represented using a half, round off to zero.
161
         Consistent with the reference implementation. */
162
0
      res = 0;
163
54.0k
    } else if (logical_exp < -14) {
164
      /* Offset the remaining decimal places by shifting the significand, the
165
         value is lost. This is an implementation decision that works around the
166
         absence of standard half-float in the language. */
167
15.1k
      res = (uint16_t)((val & 0x80000000u) >> 16u) |  // Extract sign bit
168
15.1k
            ((uint16_t)(1u << (24u + logical_exp)) +
169
15.1k
             (uint16_t)(((mant >> (-logical_exp - 2)) + 1) >>
170
15.1k
                        1));  // Round half away from zero for simplicity
171
38.9k
    } else {
172
38.9k
      res = (uint16_t)((val & 0x80000000u) >> 16u |
173
38.9k
                       ((((uint8_t)logical_exp) + 15u) << 10u) |
174
38.9k
                       (uint16_t)(mant >> 13u));
175
38.9k
    }
176
54.0k
  }
177
59.3k
  return _cbor_encode_uint16(res, buffer, buffer_size, 0xE0);
178
59.3k
}
179
180
size_t cbor_encode_single(float value, unsigned char* buffer,
181
12.4k
                          size_t buffer_size) {
182
  // Note: Values of signaling NaNs are discarded. There is no standard
183
  // way to extract it without assumptions about the internal float
184
  // representation.
185
12.4k
  if (isnan(value)) {
186
350
    return _cbor_encode_uint32(0x7FC0 << 16, buffer, buffer_size, 0xE0);
187
350
  }
188
  // TODO: Broken on systems that do not use IEEE 754
189
12.1k
  return _cbor_encode_uint32(
190
12.1k
      ((union _cbor_float_helper){.as_float = value}).as_uint, buffer,
191
12.1k
      buffer_size, 0xE0);
192
12.4k
}
193
194
size_t cbor_encode_double(double value, unsigned char* buffer,
195
7.67k
                          size_t buffer_size) {
196
  // Note: Values of signaling NaNs are discarded. See `cbor_encode_single`.
197
7.67k
  if (isnan(value)) {
198
2.04k
    return _cbor_encode_uint64((uint64_t)0x7FF8 << 48, buffer, buffer_size,
199
2.04k
                               0xE0);
200
2.04k
  }
201
  // TODO: Broken on systems that do not use IEEE 754
202
5.62k
  return _cbor_encode_uint64(
203
5.62k
      ((union _cbor_double_helper){.as_double = value}).as_uint, buffer,
204
5.62k
      buffer_size, 0xE0);
205
7.67k
}
206
207
410k
size_t cbor_encode_break(unsigned char* buffer, size_t buffer_size) {
208
410k
  return _cbor_encode_byte(0xFF, buffer, buffer_size);
209
410k
}
210
211
size_t cbor_encode_ctrl(uint8_t value, unsigned char* buffer,
212
448k
                        size_t buffer_size) {
213
448k
  return _cbor_encode_uint8(value, buffer, buffer_size, 0xE0);
214
448k
}