Coverage Report

Created: 2025-08-26 06:22

/src/libcbor/src/cbor/encoding.c
Line
Count
Source (jump to first uncovered line)
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
9.65M
                         size_t buffer_size) {
16
9.65M
  return _cbor_encode_uint8(value, buffer, buffer_size, 0x00);
17
9.65M
}
18
19
size_t cbor_encode_uint16(uint16_t value, unsigned char* buffer,
20
7.21k
                          size_t buffer_size) {
21
7.21k
  return _cbor_encode_uint16(value, buffer, buffer_size, 0x00);
22
7.21k
}
23
24
size_t cbor_encode_uint32(uint32_t value, unsigned char* buffer,
25
422k
                          size_t buffer_size) {
26
422k
  return _cbor_encode_uint32(value, buffer, buffer_size, 0x00);
27
422k
}
28
29
size_t cbor_encode_uint64(uint64_t value, unsigned char* buffer,
30
10.5k
                          size_t buffer_size) {
31
10.5k
  return _cbor_encode_uint64(value, buffer, buffer_size, 0x00);
32
10.5k
}
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
1.78M
                           size_t buffer_size) {
41
1.78M
  return _cbor_encode_uint8(value, buffer, buffer_size, 0x20);
42
1.78M
}
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
12.7k
                            size_t buffer_size) {
51
12.7k
  return _cbor_encode_uint32(value, buffer, buffer_size, 0x20);
52
12.7k
}
53
54
size_t cbor_encode_negint64(uint64_t value, unsigned char* buffer,
55
1.66k
                            size_t buffer_size) {
56
1.66k
  return _cbor_encode_uint64(value, buffer, buffer_size, 0x20);
57
1.66k
}
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
554k
                                    size_t buffer_size) {
66
554k
  return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0x40);
67
554k
}
68
69
size_t _cbor_encode_byte(uint8_t value, unsigned char* buffer,
70
774k
                         size_t buffer_size) {
71
774k
  if (buffer_size >= 1) {
72
774k
    buffer[0] = value;
73
774k
    return 1;
74
774k
  } else
75
0
    return 0;
76
774k
}
77
78
size_t cbor_encode_indef_bytestring_start(unsigned char* buffer,
79
556
                                          size_t buffer_size) {
80
556
  return _cbor_encode_byte(0x5F, buffer, buffer_size);
81
556
}
82
83
size_t cbor_encode_string_start(size_t length, unsigned char* buffer,
84
313k
                                size_t buffer_size) {
85
313k
  return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0x60);
86
313k
}
87
88
size_t cbor_encode_indef_string_start(unsigned char* buffer,
89
7.56k
                                      size_t buffer_size) {
90
7.56k
  return _cbor_encode_byte(0x7F, buffer, buffer_size);
91
7.56k
}
92
93
size_t cbor_encode_array_start(size_t length, unsigned char* buffer,
94
5.31M
                               size_t buffer_size) {
95
5.31M
  return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0x80);
96
5.31M
}
97
98
size_t cbor_encode_indef_array_start(unsigned char* buffer,
99
377k
                                     size_t buffer_size) {
100
377k
  return _cbor_encode_byte(0x9F, buffer, buffer_size);
101
377k
}
102
103
size_t cbor_encode_map_start(size_t length, unsigned char* buffer,
104
36.4k
                             size_t buffer_size) {
105
36.4k
  return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0xA0);
106
36.4k
}
107
108
1.95k
size_t cbor_encode_indef_map_start(unsigned char* buffer, size_t buffer_size) {
109
1.95k
  return _cbor_encode_byte(0xBF, buffer, buffer_size);
110
1.95k
}
111
112
size_t cbor_encode_tag(uint64_t value, unsigned char* buffer,
113
205k
                       size_t buffer_size) {
114
205k
  return _cbor_encode_uint(value, buffer, buffer_size, 0xC0);
115
205k
}
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
63.5k
                        size_t buffer_size) {
132
  // TODO: Broken on systems that do not use IEEE 754
133
  /* Assuming value is normalized */
134
63.5k
  uint32_t val = ((union _cbor_float_helper){.as_float = value}).as_uint;
135
63.5k
  uint16_t res;
136
63.5k
  uint8_t exp = (uint8_t)((val & 0x7F800000u) >>
137
63.5k
                          23u); /* 0b0111_1111_1000_0000_0000_0000_0000_0000 */
138
63.5k
  uint32_t mant =
139
63.5k
      val & 0x7FFFFFu; /* 0b0000_0000_0111_1111_1111_1111_1111_1111 */
140
63.5k
  if (exp == 0xFF) {   /* Infinity or NaNs */
141
6.06k
    if (isnan(value)) {
142
      // Note: Values of signaling NaNs are discarded. See `cbor_encode_single`.
143
5.05k
      res = (uint16_t)0x007e00;
144
5.05k
    } 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.00k
      CBOR_ASSERT(mant == 0u);
149
1.00k
      res = (uint16_t)((val & 0x80000000u) >> 16u | 0x7C00u);
150
1.00k
    }
151
57.5k
  } else if (exp == 0x00) { /* Zeroes or subnorms */
152
373
    res = (uint16_t)((val & 0x80000000u) >> 16u | mant >> 13u);
153
57.1k
  } else { /* Normal numbers */
154
57.1k
    int8_t logical_exp = (int8_t)(exp - 127);
155
57.1k
    CBOR_ASSERT(logical_exp == exp - 127);
156
157
    // Now we know that 2^exp <= 0 logically
158
57.1k
    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
57.1k
    } 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
22.7k
      res = (uint16_t)((val & 0x80000000u) >> 16u) |  // Extract sign bit
168
22.7k
            ((uint16_t)(1u << (24u + logical_exp)) +
169
22.7k
             (uint16_t)(((mant >> (-logical_exp - 2)) + 1) >>
170
22.7k
                        1));  // Round half away from zero for simplicity
171
34.4k
    } else {
172
34.4k
      res = (uint16_t)((val & 0x80000000u) >> 16u |
173
34.4k
                       ((((uint8_t)logical_exp) + 15u) << 10u) |
174
34.4k
                       (uint16_t)(mant >> 13u));
175
34.4k
    }
176
57.1k
  }
177
63.5k
  return _cbor_encode_uint16(res, buffer, buffer_size, 0xE0);
178
63.5k
}
179
180
size_t cbor_encode_single(float value, unsigned char* buffer,
181
10.8k
                          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
10.8k
  if (isnan(value)) {
186
354
    return _cbor_encode_uint32(0x7FC0 << 16, buffer, buffer_size, 0xE0);
187
354
  }
188
  // TODO: Broken on systems that do not use IEEE 754
189
10.5k
  return _cbor_encode_uint32(
190
10.5k
      ((union _cbor_float_helper){.as_float = value}).as_uint, buffer,
191
10.5k
      buffer_size, 0xE0);
192
10.8k
}
193
194
size_t cbor_encode_double(double value, unsigned char* buffer,
195
9.92k
                          size_t buffer_size) {
196
  // Note: Values of signaling NaNs are discarded. See `cbor_encode_single`.
197
9.92k
  if (isnan(value)) {
198
2.22k
    return _cbor_encode_uint64((uint64_t)0x7FF8 << 48, buffer, buffer_size,
199
2.22k
                               0xE0);
200
2.22k
  }
201
  // TODO: Broken on systems that do not use IEEE 754
202
7.70k
  return _cbor_encode_uint64(
203
7.70k
      ((union _cbor_double_helper){.as_double = value}).as_uint, buffer,
204
7.70k
      buffer_size, 0xE0);
205
9.92k
}
206
207
387k
size_t cbor_encode_break(unsigned char* buffer, size_t buffer_size) {
208
387k
  return _cbor_encode_byte(0xFF, buffer, buffer_size);
209
387k
}
210
211
size_t cbor_encode_ctrl(uint8_t value, unsigned char* buffer,
212
778k
                        size_t buffer_size) {
213
778k
  return _cbor_encode_uint8(value, buffer, buffer_size, 0xE0);
214
778k
}