1da0d961cSdjm /*
2d3425be1Sdjm * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
3da0d961cSdjm *
4da0d961cSdjm * libcbor is free software; you can redistribute it and/or modify
5da0d961cSdjm * it under the terms of the MIT license. See LICENSE for details.
6da0d961cSdjm */
7da0d961cSdjm
8da0d961cSdjm #include "encoding.h"
9da0d961cSdjm #include "internal/encoders.h"
10da0d961cSdjm
cbor_encode_uint8(uint8_t value,unsigned char * buffer,size_t buffer_size)119e5c2ddcSdjm size_t cbor_encode_uint8(uint8_t value, unsigned char *buffer,
129e5c2ddcSdjm size_t buffer_size) {
13da0d961cSdjm return _cbor_encode_uint8(value, buffer, buffer_size, 0x00);
14da0d961cSdjm }
15da0d961cSdjm
cbor_encode_uint16(uint16_t value,unsigned char * buffer,size_t buffer_size)169e5c2ddcSdjm size_t cbor_encode_uint16(uint16_t value, unsigned char *buffer,
179e5c2ddcSdjm size_t buffer_size) {
18da0d961cSdjm return _cbor_encode_uint16(value, buffer, buffer_size, 0x00);
19da0d961cSdjm }
20da0d961cSdjm
cbor_encode_uint32(uint32_t value,unsigned char * buffer,size_t buffer_size)219e5c2ddcSdjm size_t cbor_encode_uint32(uint32_t value, unsigned char *buffer,
229e5c2ddcSdjm size_t buffer_size) {
23da0d961cSdjm return _cbor_encode_uint32(value, buffer, buffer_size, 0x00);
24da0d961cSdjm }
25da0d961cSdjm
cbor_encode_uint64(uint64_t value,unsigned char * buffer,size_t buffer_size)269e5c2ddcSdjm size_t cbor_encode_uint64(uint64_t value, unsigned char *buffer,
279e5c2ddcSdjm size_t buffer_size) {
28da0d961cSdjm return _cbor_encode_uint64(value, buffer, buffer_size, 0x00);
29da0d961cSdjm }
30da0d961cSdjm
cbor_encode_uint(uint64_t value,unsigned char * buffer,size_t buffer_size)319e5c2ddcSdjm size_t cbor_encode_uint(uint64_t value, unsigned char *buffer,
329e5c2ddcSdjm size_t buffer_size) {
33da0d961cSdjm return _cbor_encode_uint(value, buffer, buffer_size, 0x00);
34da0d961cSdjm }
35da0d961cSdjm
cbor_encode_negint8(uint8_t value,unsigned char * buffer,size_t buffer_size)369e5c2ddcSdjm size_t cbor_encode_negint8(uint8_t value, unsigned char *buffer,
379e5c2ddcSdjm size_t buffer_size) {
38da0d961cSdjm return _cbor_encode_uint8(value, buffer, buffer_size, 0x20);
39da0d961cSdjm }
40da0d961cSdjm
cbor_encode_negint16(uint16_t value,unsigned char * buffer,size_t buffer_size)419e5c2ddcSdjm size_t cbor_encode_negint16(uint16_t value, unsigned char *buffer,
429e5c2ddcSdjm size_t buffer_size) {
43da0d961cSdjm return _cbor_encode_uint16(value, buffer, buffer_size, 0x20);
44da0d961cSdjm }
45da0d961cSdjm
cbor_encode_negint32(uint32_t value,unsigned char * buffer,size_t buffer_size)469e5c2ddcSdjm size_t cbor_encode_negint32(uint32_t value, unsigned char *buffer,
479e5c2ddcSdjm size_t buffer_size) {
48da0d961cSdjm return _cbor_encode_uint32(value, buffer, buffer_size, 0x20);
49da0d961cSdjm }
50da0d961cSdjm
cbor_encode_negint64(uint64_t value,unsigned char * buffer,size_t buffer_size)519e5c2ddcSdjm size_t cbor_encode_negint64(uint64_t value, unsigned char *buffer,
529e5c2ddcSdjm size_t buffer_size) {
53da0d961cSdjm return _cbor_encode_uint64(value, buffer, buffer_size, 0x20);
54da0d961cSdjm }
55da0d961cSdjm
cbor_encode_negint(uint64_t value,unsigned char * buffer,size_t buffer_size)569e5c2ddcSdjm size_t cbor_encode_negint(uint64_t value, unsigned char *buffer,
579e5c2ddcSdjm size_t buffer_size) {
58da0d961cSdjm return _cbor_encode_uint(value, buffer, buffer_size, 0x20);
59da0d961cSdjm }
60da0d961cSdjm
cbor_encode_bytestring_start(size_t length,unsigned char * buffer,size_t buffer_size)619e5c2ddcSdjm size_t cbor_encode_bytestring_start(size_t length, unsigned char *buffer,
629e5c2ddcSdjm size_t buffer_size) {
63da0d961cSdjm return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0x40);
64da0d961cSdjm }
65da0d961cSdjm
_cbor_encode_byte(uint8_t value,unsigned char * buffer,size_t buffer_size)669e5c2ddcSdjm size_t _cbor_encode_byte(uint8_t value, unsigned char *buffer,
679e5c2ddcSdjm size_t buffer_size) {
68da0d961cSdjm if (buffer_size >= 1) {
69da0d961cSdjm buffer[0] = value;
70da0d961cSdjm return 1;
71da0d961cSdjm } else
72da0d961cSdjm return 0;
73da0d961cSdjm }
74da0d961cSdjm
cbor_encode_indef_bytestring_start(unsigned char * buffer,size_t buffer_size)759e5c2ddcSdjm size_t cbor_encode_indef_bytestring_start(unsigned char *buffer,
769e5c2ddcSdjm size_t buffer_size) {
77da0d961cSdjm return _cbor_encode_byte(0x5F, buffer, buffer_size);
78da0d961cSdjm }
79da0d961cSdjm
cbor_encode_string_start(size_t length,unsigned char * buffer,size_t buffer_size)809e5c2ddcSdjm size_t cbor_encode_string_start(size_t length, unsigned char *buffer,
819e5c2ddcSdjm size_t buffer_size) {
82da0d961cSdjm return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0x60);
83da0d961cSdjm }
84da0d961cSdjm
cbor_encode_indef_string_start(unsigned char * buffer,size_t buffer_size)859e5c2ddcSdjm size_t cbor_encode_indef_string_start(unsigned char *buffer,
869e5c2ddcSdjm size_t buffer_size) {
87da0d961cSdjm return _cbor_encode_byte(0x7F, buffer, buffer_size);
88da0d961cSdjm }
89da0d961cSdjm
cbor_encode_array_start(size_t length,unsigned char * buffer,size_t buffer_size)909e5c2ddcSdjm size_t cbor_encode_array_start(size_t length, unsigned char *buffer,
919e5c2ddcSdjm size_t buffer_size) {
92da0d961cSdjm return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0x80);
93da0d961cSdjm }
94da0d961cSdjm
cbor_encode_indef_array_start(unsigned char * buffer,size_t buffer_size)959e5c2ddcSdjm size_t cbor_encode_indef_array_start(unsigned char *buffer,
969e5c2ddcSdjm size_t buffer_size) {
97da0d961cSdjm return _cbor_encode_byte(0x9F, buffer, buffer_size);
98da0d961cSdjm }
99da0d961cSdjm
cbor_encode_map_start(size_t length,unsigned char * buffer,size_t buffer_size)1009e5c2ddcSdjm size_t cbor_encode_map_start(size_t length, unsigned char *buffer,
1019e5c2ddcSdjm size_t buffer_size) {
102da0d961cSdjm return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0xA0);
103da0d961cSdjm }
104da0d961cSdjm
cbor_encode_indef_map_start(unsigned char * buffer,size_t buffer_size)1059e5c2ddcSdjm size_t cbor_encode_indef_map_start(unsigned char *buffer, size_t buffer_size) {
106da0d961cSdjm return _cbor_encode_byte(0xBF, buffer, buffer_size);
107da0d961cSdjm }
108da0d961cSdjm
cbor_encode_tag(uint64_t value,unsigned char * buffer,size_t buffer_size)1099e5c2ddcSdjm size_t cbor_encode_tag(uint64_t value, unsigned char *buffer,
1109e5c2ddcSdjm size_t buffer_size) {
111da0d961cSdjm return _cbor_encode_uint(value, buffer, buffer_size, 0xC0);
112da0d961cSdjm }
113da0d961cSdjm
cbor_encode_bool(bool value,unsigned char * buffer,size_t buffer_size)1149e5c2ddcSdjm size_t cbor_encode_bool(bool value, unsigned char *buffer, size_t buffer_size) {
1159e5c2ddcSdjm return value ? _cbor_encode_byte(0xF5, buffer, buffer_size)
1169e5c2ddcSdjm : _cbor_encode_byte(0xF4, buffer, buffer_size);
117da0d961cSdjm }
118da0d961cSdjm
cbor_encode_null(unsigned char * buffer,size_t buffer_size)1199e5c2ddcSdjm size_t cbor_encode_null(unsigned char *buffer, size_t buffer_size) {
120da0d961cSdjm return _cbor_encode_byte(0xF6, buffer, buffer_size);
121da0d961cSdjm }
122da0d961cSdjm
cbor_encode_undef(unsigned char * buffer,size_t buffer_size)1239e5c2ddcSdjm size_t cbor_encode_undef(unsigned char *buffer, size_t buffer_size) {
124da0d961cSdjm return _cbor_encode_byte(0xF7, buffer, buffer_size);
125da0d961cSdjm }
126da0d961cSdjm
cbor_encode_half(float value,unsigned char * buffer,size_t buffer_size)1279e5c2ddcSdjm size_t cbor_encode_half(float value, unsigned char *buffer,
1289e5c2ddcSdjm size_t buffer_size) {
129da0d961cSdjm /* Assuming value is normalized */
130da0d961cSdjm uint32_t val = ((union _cbor_float_helper){.as_float = value}).as_uint;
131da0d961cSdjm uint16_t res;
132d3425be1Sdjm uint8_t exp = (uint8_t)((val & 0x7F800000u) >>
133d3425be1Sdjm 23u); /* 0b0111_1111_1000_0000_0000_0000_0000_0000 */
1349e5c2ddcSdjm uint32_t mant =
135d3425be1Sdjm val & 0x7FFFFFu; /* 0b0000_0000_0111_1111_1111_1111_1111_1111 */
136da0d961cSdjm if (exp == 0xFF) { /* Infinity or NaNs */
137da0d961cSdjm if (value != value) {
138*4dcc46c4Sdjm // We discard information bits in half-float NaNs. This is
139*4dcc46c4Sdjm // not required for the core CBOR protocol (it is only a suggestion in
140*4dcc46c4Sdjm // Section 3.9).
141*4dcc46c4Sdjm // See https://github.com/PJK/libcbor/issues/215
142*4dcc46c4Sdjm res = (uint16_t)0x007e00;
143da0d961cSdjm } else {
144*4dcc46c4Sdjm // If the mantissa is non-zero, we have a NaN, but those are handled
145*4dcc46c4Sdjm // above. See
146*4dcc46c4Sdjm // https://en.wikipedia.org/wiki/Half-precision_floating-point_format
147*4dcc46c4Sdjm CBOR_ASSERT(mant == 0u);
148*4dcc46c4Sdjm res = (uint16_t)((val & 0x80000000u) >> 16u | 0x7C00u);
149da0d961cSdjm }
150da0d961cSdjm } else if (exp == 0x00) { /* Zeroes or subnorms */
151d3425be1Sdjm res = (uint16_t)((val & 0x80000000u) >> 16u | mant >> 13u);
152da0d961cSdjm } else { /* Normal numbers */
153da0d961cSdjm int8_t logical_exp = (int8_t)(exp - 127);
154*4dcc46c4Sdjm CBOR_ASSERT(logical_exp == exp - 127);
155da0d961cSdjm
156da0d961cSdjm // Now we know that 2^exp <= 0 logically
157da0d961cSdjm if (logical_exp < -24) {
1589e5c2ddcSdjm /* No unambiguous representation exists, this float is not a half float
1599e5c2ddcSdjm and is too small to be represented using a half, round off to zero.
1609e5c2ddcSdjm Consistent with the reference implementation. */
161da0d961cSdjm res = 0;
162da0d961cSdjm } else if (logical_exp < -14) {
1639e5c2ddcSdjm /* Offset the remaining decimal places by shifting the significand, the
1649e5c2ddcSdjm value is lost. This is an implementation decision that works around the
1659e5c2ddcSdjm absence of standard half-float in the language. */
166d3425be1Sdjm res = (uint16_t)((val & 0x80000000u) >> 16u) | // Extract sign bit
167*4dcc46c4Sdjm ((uint16_t)(1u << (24u + logical_exp)) +
168*4dcc46c4Sdjm (uint16_t)(((mant >> (-logical_exp - 2)) + 1) >>
169*4dcc46c4Sdjm 1)); // Round half away from zero for simplicity
170da0d961cSdjm } else {
171d3425be1Sdjm res = (uint16_t)((val & 0x80000000u) >> 16u |
172d3425be1Sdjm ((((uint8_t)logical_exp) + 15u) << 10u) |
173d3425be1Sdjm (uint16_t)(mant >> 13u));
174da0d961cSdjm }
175da0d961cSdjm }
176da0d961cSdjm return _cbor_encode_uint16(res, buffer, buffer_size, 0xE0);
177da0d961cSdjm }
178da0d961cSdjm
cbor_encode_single(float value,unsigned char * buffer,size_t buffer_size)1799e5c2ddcSdjm size_t cbor_encode_single(float value, unsigned char *buffer,
1809e5c2ddcSdjm size_t buffer_size) {
1819e5c2ddcSdjm return _cbor_encode_uint32(
1829e5c2ddcSdjm ((union _cbor_float_helper){.as_float = value}).as_uint, buffer,
1839e5c2ddcSdjm buffer_size, 0xE0);
184da0d961cSdjm }
185da0d961cSdjm
cbor_encode_double(double value,unsigned char * buffer,size_t buffer_size)1869e5c2ddcSdjm size_t cbor_encode_double(double value, unsigned char *buffer,
1879e5c2ddcSdjm size_t buffer_size) {
1889e5c2ddcSdjm return _cbor_encode_uint64(
1899e5c2ddcSdjm ((union _cbor_double_helper){.as_double = value}).as_uint, buffer,
1909e5c2ddcSdjm buffer_size, 0xE0);
191da0d961cSdjm }
192da0d961cSdjm
cbor_encode_break(unsigned char * buffer,size_t buffer_size)1939e5c2ddcSdjm size_t cbor_encode_break(unsigned char *buffer, size_t buffer_size) {
194da0d961cSdjm return _cbor_encode_byte(0xFF, buffer, buffer_size);
195da0d961cSdjm }
196da0d961cSdjm
cbor_encode_ctrl(uint8_t value,unsigned char * buffer,size_t buffer_size)1979e5c2ddcSdjm size_t cbor_encode_ctrl(uint8_t value, unsigned char *buffer,
1989e5c2ddcSdjm size_t buffer_size) {
199da0d961cSdjm return _cbor_encode_uint8(value, buffer, buffer_size, 0xE0);
200da0d961cSdjm }
201