Coverage Report

Created: 2025-04-22 06:18

/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
#include "internal/encoders.h"
10
11
size_t cbor_encode_uint8(uint8_t value, unsigned char *buffer,
12
159k
                         size_t buffer_size) {
13
159k
  return _cbor_encode_uint8(value, buffer, buffer_size, 0x00);
14
159k
}
15
16
size_t cbor_encode_uint16(uint16_t value, unsigned char *buffer,
17
2.56k
                          size_t buffer_size) {
18
2.56k
  return _cbor_encode_uint16(value, buffer, buffer_size, 0x00);
19
2.56k
}
20
21
size_t cbor_encode_uint32(uint32_t value, unsigned char *buffer,
22
2.80k
                          size_t buffer_size) {
23
2.80k
  return _cbor_encode_uint32(value, buffer, buffer_size, 0x00);
24
2.80k
}
25
26
size_t cbor_encode_uint64(uint64_t value, unsigned char *buffer,
27
936
                          size_t buffer_size) {
28
936
  return _cbor_encode_uint64(value, buffer, buffer_size, 0x00);
29
936
}
30
31
size_t cbor_encode_uint(uint64_t value, unsigned char *buffer,
32
0
                        size_t buffer_size) {
33
0
  return _cbor_encode_uint(value, buffer, buffer_size, 0x00);
34
0
}
35
36
size_t cbor_encode_negint8(uint8_t value, unsigned char *buffer,
37
30.8k
                           size_t buffer_size) {
38
30.8k
  return _cbor_encode_uint8(value, buffer, buffer_size, 0x20);
39
30.8k
}
40
41
size_t cbor_encode_negint16(uint16_t value, unsigned char *buffer,
42
1.68k
                            size_t buffer_size) {
43
1.68k
  return _cbor_encode_uint16(value, buffer, buffer_size, 0x20);
44
1.68k
}
45
46
size_t cbor_encode_negint32(uint32_t value, unsigned char *buffer,
47
1.81k
                            size_t buffer_size) {
48
1.81k
  return _cbor_encode_uint32(value, buffer, buffer_size, 0x20);
49
1.81k
}
50
51
size_t cbor_encode_negint64(uint64_t value, unsigned char *buffer,
52
1.13k
                            size_t buffer_size) {
53
1.13k
  return _cbor_encode_uint64(value, buffer, buffer_size, 0x20);
54
1.13k
}
55
56
size_t cbor_encode_negint(uint64_t value, unsigned char *buffer,
57
0
                          size_t buffer_size) {
58
0
  return _cbor_encode_uint(value, buffer, buffer_size, 0x20);
59
0
}
60
61
size_t cbor_encode_bytestring_start(size_t length, unsigned char *buffer,
62
91.4k
                                    size_t buffer_size) {
63
91.4k
  return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0x40);
64
91.4k
}
65
66
size_t _cbor_encode_byte(uint8_t value, unsigned char *buffer,
67
5.87k
                         size_t buffer_size) {
68
5.87k
  if (buffer_size >= 1) {
69
5.87k
    buffer[0] = value;
70
5.87k
    return 1;
71
5.87k
  } else
72
0
    return 0;
73
5.87k
}
74
75
size_t cbor_encode_indef_bytestring_start(unsigned char *buffer,
76
603
                                          size_t buffer_size) {
77
603
  return _cbor_encode_byte(0x5F, buffer, buffer_size);
78
603
}
79
80
size_t cbor_encode_string_start(size_t length, unsigned char *buffer,
81
183k
                                size_t buffer_size) {
82
183k
  return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0x60);
83
183k
}
84
85
size_t cbor_encode_indef_string_start(unsigned char *buffer,
86
444
                                      size_t buffer_size) {
87
444
  return _cbor_encode_byte(0x7F, buffer, buffer_size);
88
444
}
89
90
size_t cbor_encode_array_start(size_t length, unsigned char *buffer,
91
11.8k
                               size_t buffer_size) {
92
11.8k
  return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0x80);
93
11.8k
}
94
95
size_t cbor_encode_indef_array_start(unsigned char *buffer,
96
1.15k
                                     size_t buffer_size) {
97
1.15k
  return _cbor_encode_byte(0x9F, buffer, buffer_size);
98
1.15k
}
99
100
size_t cbor_encode_map_start(size_t length, unsigned char *buffer,
101
88.1k
                             size_t buffer_size) {
102
88.1k
  return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0xA0);
103
88.1k
}
104
105
735
size_t cbor_encode_indef_map_start(unsigned char *buffer, size_t buffer_size) {
106
735
  return _cbor_encode_byte(0xBF, buffer, buffer_size);
107
735
}
108
109
size_t cbor_encode_tag(uint64_t value, unsigned char *buffer,
110
10.2k
                       size_t buffer_size) {
111
10.2k
  return _cbor_encode_uint(value, buffer, buffer_size, 0xC0);
112
10.2k
}
113
114
0
size_t cbor_encode_bool(bool value, unsigned char *buffer, size_t buffer_size) {
115
0
  return value ? _cbor_encode_byte(0xF5, buffer, buffer_size)
116
0
               : _cbor_encode_byte(0xF4, buffer, buffer_size);
117
0
}
118
119
0
size_t cbor_encode_null(unsigned char *buffer, size_t buffer_size) {
120
0
  return _cbor_encode_byte(0xF6, buffer, buffer_size);
121
0
}
122
123
0
size_t cbor_encode_undef(unsigned char *buffer, size_t buffer_size) {
124
0
  return _cbor_encode_byte(0xF7, buffer, buffer_size);
125
0
}
126
127
size_t cbor_encode_half(float value, unsigned char *buffer,
128
8.87k
                        size_t buffer_size) {
129
  /* Assuming value is normalized */
130
8.87k
  uint32_t val = ((union _cbor_float_helper){.as_float = value}).as_uint;
131
8.87k
  uint16_t res;
132
8.87k
  uint8_t exp = (uint8_t)((val & 0x7F800000u) >>
133
8.87k
                          23u); /* 0b0111_1111_1000_0000_0000_0000_0000_0000 */
134
8.87k
  uint32_t mant =
135
8.87k
      val & 0x7FFFFFu; /* 0b0000_0000_0111_1111_1111_1111_1111_1111 */
136
8.87k
  if (exp == 0xFF) {   /* Infinity or NaNs */
137
980
    if (value != value) {
138
      // We discard information bits in half-float NaNs. This is
139
      // not required for the core CBOR protocol (it is only a suggestion in
140
      // Section 3.9).
141
      // See https://github.com/PJK/libcbor/issues/215
142
832
      res = (uint16_t)0x007e00;
143
832
    } else {
144
      // If the mantissa is non-zero, we have a NaN, but those are handled
145
      // above. See
146
      // https://en.wikipedia.org/wiki/Half-precision_floating-point_format
147
148
      CBOR_ASSERT(mant == 0u);
148
148
      res = (uint16_t)((val & 0x80000000u) >> 16u | 0x7C00u);
149
148
    }
150
7.89k
  } else if (exp == 0x00) { /* Zeroes or subnorms */
151
398
    res = (uint16_t)((val & 0x80000000u) >> 16u | mant >> 13u);
152
7.49k
  } else { /* Normal numbers */
153
7.49k
    int8_t logical_exp = (int8_t)(exp - 127);
154
7.49k
    CBOR_ASSERT(logical_exp == exp - 127);
155
156
    // Now we know that 2^exp <= 0 logically
157
7.49k
    if (logical_exp < -24) {
158
      /* No unambiguous representation exists, this float is not a half float
159
         and is too small to be represented using a half, round off to zero.
160
         Consistent with the reference implementation. */
161
0
      res = 0;
162
7.49k
    } else if (logical_exp < -14) {
163
      /* Offset the remaining decimal places by shifting the significand, the
164
         value is lost. This is an implementation decision that works around the
165
         absence of standard half-float in the language. */
166
696
      res = (uint16_t)((val & 0x80000000u) >> 16u) |  // Extract sign bit
167
696
            ((uint16_t)(1u << (24u + logical_exp)) +
168
696
             (uint16_t)(((mant >> (-logical_exp - 2)) + 1) >>
169
696
                        1));  // Round half away from zero for simplicity
170
6.80k
    } else {
171
6.80k
      res = (uint16_t)((val & 0x80000000u) >> 16u |
172
6.80k
                       ((((uint8_t)logical_exp) + 15u) << 10u) |
173
6.80k
                       (uint16_t)(mant >> 13u));
174
6.80k
    }
175
7.49k
  }
176
8.87k
  return _cbor_encode_uint16(res, buffer, buffer_size, 0xE0);
177
8.87k
}
178
179
size_t cbor_encode_single(float value, unsigned char *buffer,
180
1.01k
                          size_t buffer_size) {
181
1.01k
  return _cbor_encode_uint32(
182
1.01k
      ((union _cbor_float_helper){.as_float = value}).as_uint, buffer,
183
1.01k
      buffer_size, 0xE0);
184
1.01k
}
185
186
size_t cbor_encode_double(double value, unsigned char *buffer,
187
1.03k
                          size_t buffer_size) {
188
1.03k
  return _cbor_encode_uint64(
189
1.03k
      ((union _cbor_double_helper){.as_double = value}).as_uint, buffer,
190
1.03k
      buffer_size, 0xE0);
191
1.03k
}
192
193
2.93k
size_t cbor_encode_break(unsigned char *buffer, size_t buffer_size) {
194
2.93k
  return _cbor_encode_byte(0xFF, buffer, buffer_size);
195
2.93k
}
196
197
size_t cbor_encode_ctrl(uint8_t value, unsigned char *buffer,
198
5.64k
                        size_t buffer_size) {
199
5.64k
  return _cbor_encode_uint8(value, buffer, buffer_size, 0xE0);
200
5.64k
}