xref: /freebsd/contrib/libcbor/src/cbor/encoding.c (revision 18054d0220cfc8df9c9568c437bd6fbb59d53c3c)
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                          size_t buffer_size) {
13   return _cbor_encode_uint8(value, buffer, buffer_size, 0x00);
14 }
15 
16 size_t cbor_encode_uint16(uint16_t value, unsigned char *buffer,
17                           size_t buffer_size) {
18   return _cbor_encode_uint16(value, buffer, buffer_size, 0x00);
19 }
20 
21 size_t cbor_encode_uint32(uint32_t value, unsigned char *buffer,
22                           size_t buffer_size) {
23   return _cbor_encode_uint32(value, buffer, buffer_size, 0x00);
24 }
25 
26 size_t cbor_encode_uint64(uint64_t value, unsigned char *buffer,
27                           size_t buffer_size) {
28   return _cbor_encode_uint64(value, buffer, buffer_size, 0x00);
29 }
30 
31 size_t cbor_encode_uint(uint64_t value, unsigned char *buffer,
32                         size_t buffer_size) {
33   return _cbor_encode_uint(value, buffer, buffer_size, 0x00);
34 }
35 
36 size_t cbor_encode_negint8(uint8_t value, unsigned char *buffer,
37                            size_t buffer_size) {
38   return _cbor_encode_uint8(value, buffer, buffer_size, 0x20);
39 }
40 
41 size_t cbor_encode_negint16(uint16_t value, unsigned char *buffer,
42                             size_t buffer_size) {
43   return _cbor_encode_uint16(value, buffer, buffer_size, 0x20);
44 }
45 
46 size_t cbor_encode_negint32(uint32_t value, unsigned char *buffer,
47                             size_t buffer_size) {
48   return _cbor_encode_uint32(value, buffer, buffer_size, 0x20);
49 }
50 
51 size_t cbor_encode_negint64(uint64_t value, unsigned char *buffer,
52                             size_t buffer_size) {
53   return _cbor_encode_uint64(value, buffer, buffer_size, 0x20);
54 }
55 
56 size_t cbor_encode_negint(uint64_t value, unsigned char *buffer,
57                           size_t buffer_size) {
58   return _cbor_encode_uint(value, buffer, buffer_size, 0x20);
59 }
60 
61 size_t cbor_encode_bytestring_start(size_t length, unsigned char *buffer,
62                                     size_t buffer_size) {
63   return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0x40);
64 }
65 
66 size_t _cbor_encode_byte(uint8_t value, unsigned char *buffer,
67                          size_t buffer_size) {
68   if (buffer_size >= 1) {
69     buffer[0] = value;
70     return 1;
71   } else
72     return 0;
73 }
74 
75 size_t cbor_encode_indef_bytestring_start(unsigned char *buffer,
76                                           size_t buffer_size) {
77   return _cbor_encode_byte(0x5F, buffer, buffer_size);
78 }
79 
80 size_t cbor_encode_string_start(size_t length, unsigned char *buffer,
81                                 size_t buffer_size) {
82   return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0x60);
83 }
84 
85 size_t cbor_encode_indef_string_start(unsigned char *buffer,
86                                       size_t buffer_size) {
87   return _cbor_encode_byte(0x7F, buffer, buffer_size);
88 }
89 
90 size_t cbor_encode_array_start(size_t length, unsigned char *buffer,
91                                size_t buffer_size) {
92   return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0x80);
93 }
94 
95 size_t cbor_encode_indef_array_start(unsigned char *buffer,
96                                      size_t buffer_size) {
97   return _cbor_encode_byte(0x9F, buffer, buffer_size);
98 }
99 
100 size_t cbor_encode_map_start(size_t length, unsigned char *buffer,
101                              size_t buffer_size) {
102   return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0xA0);
103 }
104 
105 size_t cbor_encode_indef_map_start(unsigned char *buffer, size_t buffer_size) {
106   return _cbor_encode_byte(0xBF, buffer, buffer_size);
107 }
108 
109 size_t cbor_encode_tag(uint64_t value, unsigned char *buffer,
110                        size_t buffer_size) {
111   return _cbor_encode_uint(value, buffer, buffer_size, 0xC0);
112 }
113 
114 size_t cbor_encode_bool(bool value, unsigned char *buffer, size_t buffer_size) {
115   return value ? _cbor_encode_byte(0xF5, buffer, buffer_size)
116                : _cbor_encode_byte(0xF4, buffer, buffer_size);
117 }
118 
119 size_t cbor_encode_null(unsigned char *buffer, size_t buffer_size) {
120   return _cbor_encode_byte(0xF6, buffer, buffer_size);
121 }
122 
123 size_t cbor_encode_undef(unsigned char *buffer, size_t buffer_size) {
124   return _cbor_encode_byte(0xF7, buffer, buffer_size);
125 }
126 
127 size_t cbor_encode_half(float value, unsigned char *buffer,
128                         size_t buffer_size) {
129   /* Assuming value is normalized */
130   uint32_t val = ((union _cbor_float_helper){.as_float = value}).as_uint;
131   uint16_t res;
132   uint8_t exp = (uint8_t)((val & 0x7F800000u) >>
133                           23u); /* 0b0111_1111_1000_0000_0000_0000_0000_0000 */
134   uint32_t mant =
135       val & 0x7FFFFFu; /* 0b0000_0000_0111_1111_1111_1111_1111_1111 */
136   if (exp == 0xFF) {   /* Infinity or NaNs */
137     if (value != value) {
138       res = (uint16_t)0x007e00; /* Not IEEE semantics - required by CBOR
139                                    [s. 3.9] */
140     } else {
141       res = (uint16_t)((val & 0x80000000u) >> 16u | 0x7C00u |
142                        (mant ? 1u : 0u) << 15u);
143     }
144   } else if (exp == 0x00) { /* Zeroes or subnorms */
145     res = (uint16_t)((val & 0x80000000u) >> 16u | mant >> 13u);
146   } else { /* Normal numbers */
147     int8_t logical_exp = (int8_t)(exp - 127);
148     assert(logical_exp == exp - 127);
149 
150     // Now we know that 2^exp <= 0 logically
151     if (logical_exp < -24) {
152       /* No unambiguous representation exists, this float is not a half float
153          and is too small to be represented using a half, round off to zero.
154          Consistent with the reference implementation. */
155       res = 0;
156     } else if (logical_exp < -14) {
157       /* Offset the remaining decimal places by shifting the significand, the
158          value is lost. This is an implementation decision that works around the
159          absence of standard half-float in the language. */
160       res = (uint16_t)((val & 0x80000000u) >> 16u) |  // Extract sign bit
161             (uint16_t)(1u << (24u + logical_exp));
162     } else {
163       res = (uint16_t)((val & 0x80000000u) >> 16u |
164                        ((((uint8_t)logical_exp) + 15u) << 10u) |
165                        (uint16_t)(mant >> 13u));
166     }
167   }
168   return _cbor_encode_uint16(res, buffer, buffer_size, 0xE0);
169 }
170 
171 size_t cbor_encode_single(float value, unsigned char *buffer,
172                           size_t buffer_size) {
173   return _cbor_encode_uint32(
174       ((union _cbor_float_helper){.as_float = value}).as_uint, buffer,
175       buffer_size, 0xE0);
176 }
177 
178 size_t cbor_encode_double(double value, unsigned char *buffer,
179                           size_t buffer_size) {
180   return _cbor_encode_uint64(
181       ((union _cbor_double_helper){.as_double = value}).as_uint, buffer,
182       buffer_size, 0xE0);
183 }
184 
185 size_t cbor_encode_break(unsigned char *buffer, size_t buffer_size) {
186   return _cbor_encode_byte(0xFF, buffer, buffer_size);
187 }
188 
189 size_t cbor_encode_ctrl(uint8_t value, unsigned char *buffer,
190                         size_t buffer_size) {
191   return _cbor_encode_uint8(value, buffer, buffer_size, 0xE0);
192 }
193