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 size_t buffer_size) { 16 return _cbor_encode_uint8(value, buffer, buffer_size, 0x00); 17 } 18 19 size_t cbor_encode_uint16(uint16_t value, unsigned char* buffer, 20 size_t buffer_size) { 21 return _cbor_encode_uint16(value, buffer, buffer_size, 0x00); 22 } 23 24 size_t cbor_encode_uint32(uint32_t value, unsigned char* buffer, 25 size_t buffer_size) { 26 return _cbor_encode_uint32(value, buffer, buffer_size, 0x00); 27 } 28 29 size_t cbor_encode_uint64(uint64_t value, unsigned char* buffer, 30 size_t buffer_size) { 31 return _cbor_encode_uint64(value, buffer, buffer_size, 0x00); 32 } 33 34 size_t cbor_encode_uint(uint64_t value, unsigned char* buffer, 35 size_t buffer_size) { 36 return _cbor_encode_uint(value, buffer, buffer_size, 0x00); 37 } 38 39 size_t cbor_encode_negint8(uint8_t value, unsigned char* buffer, 40 size_t buffer_size) { 41 return _cbor_encode_uint8(value, buffer, buffer_size, 0x20); 42 } 43 44 size_t cbor_encode_negint16(uint16_t value, unsigned char* buffer, 45 size_t buffer_size) { 46 return _cbor_encode_uint16(value, buffer, buffer_size, 0x20); 47 } 48 49 size_t cbor_encode_negint32(uint32_t value, unsigned char* buffer, 50 size_t buffer_size) { 51 return _cbor_encode_uint32(value, buffer, buffer_size, 0x20); 52 } 53 54 size_t cbor_encode_negint64(uint64_t value, unsigned char* buffer, 55 size_t buffer_size) { 56 return _cbor_encode_uint64(value, buffer, buffer_size, 0x20); 57 } 58 59 size_t cbor_encode_negint(uint64_t value, unsigned char* buffer, 60 size_t buffer_size) { 61 return _cbor_encode_uint(value, buffer, buffer_size, 0x20); 62 } 63 64 size_t cbor_encode_bytestring_start(size_t length, unsigned char* buffer, 65 size_t buffer_size) { 66 return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0x40); 67 } 68 69 size_t _cbor_encode_byte(uint8_t value, unsigned char* buffer, 70 size_t buffer_size) { 71 if (buffer_size >= 1) { 72 buffer[0] = value; 73 return 1; 74 } else 75 return 0; 76 } 77 78 size_t cbor_encode_indef_bytestring_start(unsigned char* buffer, 79 size_t buffer_size) { 80 return _cbor_encode_byte(0x5F, buffer, buffer_size); 81 } 82 83 size_t cbor_encode_string_start(size_t length, unsigned char* buffer, 84 size_t buffer_size) { 85 return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0x60); 86 } 87 88 size_t cbor_encode_indef_string_start(unsigned char* buffer, 89 size_t buffer_size) { 90 return _cbor_encode_byte(0x7F, buffer, buffer_size); 91 } 92 93 size_t cbor_encode_array_start(size_t length, unsigned char* buffer, 94 size_t buffer_size) { 95 return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0x80); 96 } 97 98 size_t cbor_encode_indef_array_start(unsigned char* buffer, 99 size_t buffer_size) { 100 return _cbor_encode_byte(0x9F, buffer, buffer_size); 101 } 102 103 size_t cbor_encode_map_start(size_t length, unsigned char* buffer, 104 size_t buffer_size) { 105 return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0xA0); 106 } 107 108 size_t cbor_encode_indef_map_start(unsigned char* buffer, size_t buffer_size) { 109 return _cbor_encode_byte(0xBF, buffer, buffer_size); 110 } 111 112 size_t cbor_encode_tag(uint64_t value, unsigned char* buffer, 113 size_t buffer_size) { 114 return _cbor_encode_uint(value, buffer, buffer_size, 0xC0); 115 } 116 117 size_t cbor_encode_bool(bool value, unsigned char* buffer, size_t buffer_size) { 118 return value ? _cbor_encode_byte(0xF5, buffer, buffer_size) 119 : _cbor_encode_byte(0xF4, buffer, buffer_size); 120 } 121 122 size_t cbor_encode_null(unsigned char* buffer, size_t buffer_size) { 123 return _cbor_encode_byte(0xF6, buffer, buffer_size); 124 } 125 126 size_t cbor_encode_undef(unsigned char* buffer, size_t buffer_size) { 127 return _cbor_encode_byte(0xF7, buffer, buffer_size); 128 } 129 130 size_t cbor_encode_half(float value, unsigned char* buffer, 131 size_t buffer_size) { 132 // TODO: Broken on systems that do not use IEEE 754 133 /* Assuming value is normalized */ 134 uint32_t val = ((union _cbor_float_helper){.as_float = value}).as_uint; 135 uint16_t res; 136 uint8_t exp = (uint8_t)((val & 0x7F800000u) >> 137 23u); /* 0b0111_1111_1000_0000_0000_0000_0000_0000 */ 138 uint32_t mant = 139 val & 0x7FFFFFu; /* 0b0000_0000_0111_1111_1111_1111_1111_1111 */ 140 if (exp == 0xFF) { /* Infinity or NaNs */ 141 if (isnan(value)) { 142 // Note: Values of signaling NaNs are discarded. See `cbor_encode_single`. 143 res = (uint16_t)0x007e00; 144 } 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 CBOR_ASSERT(mant == 0u); 149 res = (uint16_t)((val & 0x80000000u) >> 16u | 0x7C00u); 150 } 151 } else if (exp == 0x00) { /* Zeroes or subnorms */ 152 res = (uint16_t)((val & 0x80000000u) >> 16u | mant >> 13u); 153 } else { /* Normal numbers */ 154 int8_t logical_exp = (int8_t)(exp - 127); 155 CBOR_ASSERT(logical_exp == exp - 127); 156 157 // Now we know that 2^exp <= 0 logically 158 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 res = 0; 163 } 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 res = (uint16_t)((val & 0x80000000u) >> 16u) | // Extract sign bit 168 ((uint16_t)(1u << (24u + logical_exp)) + 169 (uint16_t)(((mant >> (-logical_exp - 2)) + 1) >> 170 1)); // Round half away from zero for simplicity 171 } else { 172 res = (uint16_t)((val & 0x80000000u) >> 16u | 173 ((((uint8_t)logical_exp) + 15u) << 10u) | 174 (uint16_t)(mant >> 13u)); 175 } 176 } 177 return _cbor_encode_uint16(res, buffer, buffer_size, 0xE0); 178 } 179 180 size_t cbor_encode_single(float value, unsigned char* buffer, 181 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 if (isnan(value)) { 186 return _cbor_encode_uint32(0x7FC0 << 16, buffer, buffer_size, 0xE0); 187 } 188 // TODO: Broken on systems that do not use IEEE 754 189 return _cbor_encode_uint32( 190 ((union _cbor_float_helper){.as_float = value}).as_uint, buffer, 191 buffer_size, 0xE0); 192 } 193 194 size_t cbor_encode_double(double value, unsigned char* buffer, 195 size_t buffer_size) { 196 // Note: Values of signaling NaNs are discarded. See `cbor_encode_single`. 197 if (isnan(value)) { 198 return _cbor_encode_uint64((uint64_t)0x7FF8 << 48, buffer, buffer_size, 199 0xE0); 200 } 201 // TODO: Broken on systems that do not use IEEE 754 202 return _cbor_encode_uint64( 203 ((union _cbor_double_helper){.as_double = value}).as_uint, buffer, 204 buffer_size, 0xE0); 205 } 206 207 size_t cbor_encode_break(unsigned char* buffer, size_t buffer_size) { 208 return _cbor_encode_byte(0xFF, buffer, buffer_size); 209 } 210 211 size_t cbor_encode_ctrl(uint8_t value, unsigned char* buffer, 212 size_t buffer_size) { 213 return _cbor_encode_uint8(value, buffer, buffer_size, 0xE0); 214 } 215