xref: /freebsd/contrib/libcbor/src/cbor/encoding.c (revision 5d3e7166f6a0187fa3f8831b16a06bd9955c21ff)
110ff414cSEd Maste /*
210ff414cSEd Maste  * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
310ff414cSEd Maste  *
410ff414cSEd Maste  * libcbor is free software; you can redistribute it and/or modify
510ff414cSEd Maste  * it under the terms of the MIT license. See LICENSE for details.
610ff414cSEd Maste  */
710ff414cSEd Maste 
810ff414cSEd Maste #include "encoding.h"
910ff414cSEd Maste #include "internal/encoders.h"
1010ff414cSEd Maste 
cbor_encode_uint8(uint8_t value,unsigned char * buffer,size_t buffer_size)1110ff414cSEd Maste size_t cbor_encode_uint8(uint8_t value, unsigned char *buffer,
1210ff414cSEd Maste                          size_t buffer_size) {
1310ff414cSEd Maste   return _cbor_encode_uint8(value, buffer, buffer_size, 0x00);
1410ff414cSEd Maste }
1510ff414cSEd Maste 
cbor_encode_uint16(uint16_t value,unsigned char * buffer,size_t buffer_size)1610ff414cSEd Maste size_t cbor_encode_uint16(uint16_t value, unsigned char *buffer,
1710ff414cSEd Maste                           size_t buffer_size) {
1810ff414cSEd Maste   return _cbor_encode_uint16(value, buffer, buffer_size, 0x00);
1910ff414cSEd Maste }
2010ff414cSEd Maste 
cbor_encode_uint32(uint32_t value,unsigned char * buffer,size_t buffer_size)2110ff414cSEd Maste size_t cbor_encode_uint32(uint32_t value, unsigned char *buffer,
2210ff414cSEd Maste                           size_t buffer_size) {
2310ff414cSEd Maste   return _cbor_encode_uint32(value, buffer, buffer_size, 0x00);
2410ff414cSEd Maste }
2510ff414cSEd Maste 
cbor_encode_uint64(uint64_t value,unsigned char * buffer,size_t buffer_size)2610ff414cSEd Maste size_t cbor_encode_uint64(uint64_t value, unsigned char *buffer,
2710ff414cSEd Maste                           size_t buffer_size) {
2810ff414cSEd Maste   return _cbor_encode_uint64(value, buffer, buffer_size, 0x00);
2910ff414cSEd Maste }
3010ff414cSEd Maste 
cbor_encode_uint(uint64_t value,unsigned char * buffer,size_t buffer_size)3110ff414cSEd Maste size_t cbor_encode_uint(uint64_t value, unsigned char *buffer,
3210ff414cSEd Maste                         size_t buffer_size) {
3310ff414cSEd Maste   return _cbor_encode_uint(value, buffer, buffer_size, 0x00);
3410ff414cSEd Maste }
3510ff414cSEd Maste 
cbor_encode_negint8(uint8_t value,unsigned char * buffer,size_t buffer_size)3610ff414cSEd Maste size_t cbor_encode_negint8(uint8_t value, unsigned char *buffer,
3710ff414cSEd Maste                            size_t buffer_size) {
3810ff414cSEd Maste   return _cbor_encode_uint8(value, buffer, buffer_size, 0x20);
3910ff414cSEd Maste }
4010ff414cSEd Maste 
cbor_encode_negint16(uint16_t value,unsigned char * buffer,size_t buffer_size)4110ff414cSEd Maste size_t cbor_encode_negint16(uint16_t value, unsigned char *buffer,
4210ff414cSEd Maste                             size_t buffer_size) {
4310ff414cSEd Maste   return _cbor_encode_uint16(value, buffer, buffer_size, 0x20);
4410ff414cSEd Maste }
4510ff414cSEd Maste 
cbor_encode_negint32(uint32_t value,unsigned char * buffer,size_t buffer_size)4610ff414cSEd Maste size_t cbor_encode_negint32(uint32_t value, unsigned char *buffer,
4710ff414cSEd Maste                             size_t buffer_size) {
4810ff414cSEd Maste   return _cbor_encode_uint32(value, buffer, buffer_size, 0x20);
4910ff414cSEd Maste }
5010ff414cSEd Maste 
cbor_encode_negint64(uint64_t value,unsigned char * buffer,size_t buffer_size)5110ff414cSEd Maste size_t cbor_encode_negint64(uint64_t value, unsigned char *buffer,
5210ff414cSEd Maste                             size_t buffer_size) {
5310ff414cSEd Maste   return _cbor_encode_uint64(value, buffer, buffer_size, 0x20);
5410ff414cSEd Maste }
5510ff414cSEd Maste 
cbor_encode_negint(uint64_t value,unsigned char * buffer,size_t buffer_size)5610ff414cSEd Maste size_t cbor_encode_negint(uint64_t value, unsigned char *buffer,
5710ff414cSEd Maste                           size_t buffer_size) {
5810ff414cSEd Maste   return _cbor_encode_uint(value, buffer, buffer_size, 0x20);
5910ff414cSEd Maste }
6010ff414cSEd Maste 
cbor_encode_bytestring_start(size_t length,unsigned char * buffer,size_t buffer_size)6110ff414cSEd Maste size_t cbor_encode_bytestring_start(size_t length, unsigned char *buffer,
6210ff414cSEd Maste                                     size_t buffer_size) {
6310ff414cSEd Maste   return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0x40);
6410ff414cSEd Maste }
6510ff414cSEd Maste 
_cbor_encode_byte(uint8_t value,unsigned char * buffer,size_t buffer_size)6610ff414cSEd Maste size_t _cbor_encode_byte(uint8_t value, unsigned char *buffer,
6710ff414cSEd Maste                          size_t buffer_size) {
6810ff414cSEd Maste   if (buffer_size >= 1) {
6910ff414cSEd Maste     buffer[0] = value;
7010ff414cSEd Maste     return 1;
7110ff414cSEd Maste   } else
7210ff414cSEd Maste     return 0;
7310ff414cSEd Maste }
7410ff414cSEd Maste 
cbor_encode_indef_bytestring_start(unsigned char * buffer,size_t buffer_size)7510ff414cSEd Maste size_t cbor_encode_indef_bytestring_start(unsigned char *buffer,
7610ff414cSEd Maste                                           size_t buffer_size) {
7710ff414cSEd Maste   return _cbor_encode_byte(0x5F, buffer, buffer_size);
7810ff414cSEd Maste }
7910ff414cSEd Maste 
cbor_encode_string_start(size_t length,unsigned char * buffer,size_t buffer_size)8010ff414cSEd Maste size_t cbor_encode_string_start(size_t length, unsigned char *buffer,
8110ff414cSEd Maste                                 size_t buffer_size) {
8210ff414cSEd Maste   return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0x60);
8310ff414cSEd Maste }
8410ff414cSEd Maste 
cbor_encode_indef_string_start(unsigned char * buffer,size_t buffer_size)8510ff414cSEd Maste size_t cbor_encode_indef_string_start(unsigned char *buffer,
8610ff414cSEd Maste                                       size_t buffer_size) {
8710ff414cSEd Maste   return _cbor_encode_byte(0x7F, buffer, buffer_size);
8810ff414cSEd Maste }
8910ff414cSEd Maste 
cbor_encode_array_start(size_t length,unsigned char * buffer,size_t buffer_size)9010ff414cSEd Maste size_t cbor_encode_array_start(size_t length, unsigned char *buffer,
9110ff414cSEd Maste                                size_t buffer_size) {
9210ff414cSEd Maste   return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0x80);
9310ff414cSEd Maste }
9410ff414cSEd Maste 
cbor_encode_indef_array_start(unsigned char * buffer,size_t buffer_size)9510ff414cSEd Maste size_t cbor_encode_indef_array_start(unsigned char *buffer,
9610ff414cSEd Maste                                      size_t buffer_size) {
9710ff414cSEd Maste   return _cbor_encode_byte(0x9F, buffer, buffer_size);
9810ff414cSEd Maste }
9910ff414cSEd Maste 
cbor_encode_map_start(size_t length,unsigned char * buffer,size_t buffer_size)10010ff414cSEd Maste size_t cbor_encode_map_start(size_t length, unsigned char *buffer,
10110ff414cSEd Maste                              size_t buffer_size) {
10210ff414cSEd Maste   return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0xA0);
10310ff414cSEd Maste }
10410ff414cSEd Maste 
cbor_encode_indef_map_start(unsigned char * buffer,size_t buffer_size)10510ff414cSEd Maste size_t cbor_encode_indef_map_start(unsigned char *buffer, size_t buffer_size) {
10610ff414cSEd Maste   return _cbor_encode_byte(0xBF, buffer, buffer_size);
10710ff414cSEd Maste }
10810ff414cSEd Maste 
cbor_encode_tag(uint64_t value,unsigned char * buffer,size_t buffer_size)10910ff414cSEd Maste size_t cbor_encode_tag(uint64_t value, unsigned char *buffer,
11010ff414cSEd Maste                        size_t buffer_size) {
11110ff414cSEd Maste   return _cbor_encode_uint(value, buffer, buffer_size, 0xC0);
11210ff414cSEd Maste }
11310ff414cSEd Maste 
cbor_encode_bool(bool value,unsigned char * buffer,size_t buffer_size)11410ff414cSEd Maste size_t cbor_encode_bool(bool value, unsigned char *buffer, size_t buffer_size) {
11510ff414cSEd Maste   return value ? _cbor_encode_byte(0xF5, buffer, buffer_size)
11610ff414cSEd Maste                : _cbor_encode_byte(0xF4, buffer, buffer_size);
11710ff414cSEd Maste }
11810ff414cSEd Maste 
cbor_encode_null(unsigned char * buffer,size_t buffer_size)11910ff414cSEd Maste size_t cbor_encode_null(unsigned char *buffer, size_t buffer_size) {
12010ff414cSEd Maste   return _cbor_encode_byte(0xF6, buffer, buffer_size);
12110ff414cSEd Maste }
12210ff414cSEd Maste 
cbor_encode_undef(unsigned char * buffer,size_t buffer_size)12310ff414cSEd Maste size_t cbor_encode_undef(unsigned char *buffer, size_t buffer_size) {
12410ff414cSEd Maste   return _cbor_encode_byte(0xF7, buffer, buffer_size);
12510ff414cSEd Maste }
12610ff414cSEd Maste 
cbor_encode_half(float value,unsigned char * buffer,size_t buffer_size)12710ff414cSEd Maste size_t cbor_encode_half(float value, unsigned char *buffer,
12810ff414cSEd Maste                         size_t buffer_size) {
12910ff414cSEd Maste   /* Assuming value is normalized */
13010ff414cSEd Maste   uint32_t val = ((union _cbor_float_helper){.as_float = value}).as_uint;
13110ff414cSEd Maste   uint16_t res;
13210ff414cSEd Maste   uint8_t exp = (uint8_t)((val & 0x7F800000u) >>
13310ff414cSEd Maste                           23u); /* 0b0111_1111_1000_0000_0000_0000_0000_0000 */
13410ff414cSEd Maste   uint32_t mant =
13510ff414cSEd Maste       val & 0x7FFFFFu; /* 0b0000_0000_0111_1111_1111_1111_1111_1111 */
13610ff414cSEd Maste   if (exp == 0xFF) {   /* Infinity or NaNs */
13710ff414cSEd Maste     if (value != value) {
138*5d3e7166SEd Maste       // We discard information bits in half-float NaNs. This is
139*5d3e7166SEd Maste       // not required for the core CBOR protocol (it is only a suggestion in
140*5d3e7166SEd Maste       // Section 3.9).
141*5d3e7166SEd Maste       // See https://github.com/PJK/libcbor/issues/215
142*5d3e7166SEd Maste       res = (uint16_t)0x007e00;
14310ff414cSEd Maste     } else {
144*5d3e7166SEd Maste       // If the mantissa is non-zero, we have a NaN, but those are handled
145*5d3e7166SEd Maste       // above. See
146*5d3e7166SEd Maste       // https://en.wikipedia.org/wiki/Half-precision_floating-point_format
147*5d3e7166SEd Maste       CBOR_ASSERT(mant == 0u);
148*5d3e7166SEd Maste       res = (uint16_t)((val & 0x80000000u) >> 16u | 0x7C00u);
14910ff414cSEd Maste     }
15010ff414cSEd Maste   } else if (exp == 0x00) { /* Zeroes or subnorms */
15110ff414cSEd Maste     res = (uint16_t)((val & 0x80000000u) >> 16u | mant >> 13u);
15210ff414cSEd Maste   } else { /* Normal numbers */
15310ff414cSEd Maste     int8_t logical_exp = (int8_t)(exp - 127);
154*5d3e7166SEd Maste     CBOR_ASSERT(logical_exp == exp - 127);
15510ff414cSEd Maste 
15610ff414cSEd Maste     // Now we know that 2^exp <= 0 logically
15710ff414cSEd Maste     if (logical_exp < -24) {
15810ff414cSEd Maste       /* No unambiguous representation exists, this float is not a half float
15910ff414cSEd Maste          and is too small to be represented using a half, round off to zero.
16010ff414cSEd Maste          Consistent with the reference implementation. */
16110ff414cSEd Maste       res = 0;
16210ff414cSEd Maste     } else if (logical_exp < -14) {
16310ff414cSEd Maste       /* Offset the remaining decimal places by shifting the significand, the
16410ff414cSEd Maste          value is lost. This is an implementation decision that works around the
16510ff414cSEd Maste          absence of standard half-float in the language. */
16610ff414cSEd Maste       res = (uint16_t)((val & 0x80000000u) >> 16u) |  // Extract sign bit
167*5d3e7166SEd Maste             ((uint16_t)(1u << (24u + logical_exp)) +
168*5d3e7166SEd Maste              (uint16_t)(((mant >> (-logical_exp - 2)) + 1) >>
169*5d3e7166SEd Maste                         1));  // Round half away from zero for simplicity
17010ff414cSEd Maste     } else {
17110ff414cSEd Maste       res = (uint16_t)((val & 0x80000000u) >> 16u |
17210ff414cSEd Maste                        ((((uint8_t)logical_exp) + 15u) << 10u) |
17310ff414cSEd Maste                        (uint16_t)(mant >> 13u));
17410ff414cSEd Maste     }
17510ff414cSEd Maste   }
17610ff414cSEd Maste   return _cbor_encode_uint16(res, buffer, buffer_size, 0xE0);
17710ff414cSEd Maste }
17810ff414cSEd Maste 
cbor_encode_single(float value,unsigned char * buffer,size_t buffer_size)17910ff414cSEd Maste size_t cbor_encode_single(float value, unsigned char *buffer,
18010ff414cSEd Maste                           size_t buffer_size) {
18110ff414cSEd Maste   return _cbor_encode_uint32(
18210ff414cSEd Maste       ((union _cbor_float_helper){.as_float = value}).as_uint, buffer,
18310ff414cSEd Maste       buffer_size, 0xE0);
18410ff414cSEd Maste }
18510ff414cSEd Maste 
cbor_encode_double(double value,unsigned char * buffer,size_t buffer_size)18610ff414cSEd Maste size_t cbor_encode_double(double value, unsigned char *buffer,
18710ff414cSEd Maste                           size_t buffer_size) {
18810ff414cSEd Maste   return _cbor_encode_uint64(
18910ff414cSEd Maste       ((union _cbor_double_helper){.as_double = value}).as_uint, buffer,
19010ff414cSEd Maste       buffer_size, 0xE0);
19110ff414cSEd Maste }
19210ff414cSEd Maste 
cbor_encode_break(unsigned char * buffer,size_t buffer_size)19310ff414cSEd Maste size_t cbor_encode_break(unsigned char *buffer, size_t buffer_size) {
19410ff414cSEd Maste   return _cbor_encode_byte(0xFF, buffer, buffer_size);
19510ff414cSEd Maste }
19610ff414cSEd Maste 
cbor_encode_ctrl(uint8_t value,unsigned char * buffer,size_t buffer_size)19710ff414cSEd Maste size_t cbor_encode_ctrl(uint8_t value, unsigned char *buffer,
19810ff414cSEd Maste                         size_t buffer_size) {
19910ff414cSEd Maste   return _cbor_encode_uint8(value, buffer, buffer_size, 0xE0);
20010ff414cSEd Maste }
201