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 // 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 res = (uint16_t)0x007e00; 143 } 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 CBOR_ASSERT(mant == 0u); 148 res = (uint16_t)((val & 0x80000000u) >> 16u | 0x7C00u); 149 } 150 } else if (exp == 0x00) { /* Zeroes or subnorms */ 151 res = (uint16_t)((val & 0x80000000u) >> 16u | mant >> 13u); 152 } else { /* Normal numbers */ 153 int8_t logical_exp = (int8_t)(exp - 127); 154 CBOR_ASSERT(logical_exp == exp - 127); 155 156 // Now we know that 2^exp <= 0 logically 157 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 res = 0; 162 } 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 res = (uint16_t)((val & 0x80000000u) >> 16u) | // Extract sign bit 167 ((uint16_t)(1u << (24u + logical_exp)) + 168 (uint16_t)(((mant >> (-logical_exp - 2)) + 1) >> 169 1)); // Round half away from zero for simplicity 170 } else { 171 res = (uint16_t)((val & 0x80000000u) >> 16u | 172 ((((uint8_t)logical_exp) + 15u) << 10u) | 173 (uint16_t)(mant >> 13u)); 174 } 175 } 176 return _cbor_encode_uint16(res, buffer, buffer_size, 0xE0); 177 } 178 179 size_t cbor_encode_single(float value, unsigned char *buffer, 180 size_t buffer_size) { 181 return _cbor_encode_uint32( 182 ((union _cbor_float_helper){.as_float = value}).as_uint, buffer, 183 buffer_size, 0xE0); 184 } 185 186 size_t cbor_encode_double(double value, unsigned char *buffer, 187 size_t buffer_size) { 188 return _cbor_encode_uint64( 189 ((union _cbor_double_helper){.as_double = value}).as_uint, buffer, 190 buffer_size, 0xE0); 191 } 192 193 size_t cbor_encode_break(unsigned char *buffer, size_t buffer_size) { 194 return _cbor_encode_byte(0xFF, buffer, buffer_size); 195 } 196 197 size_t cbor_encode_ctrl(uint8_t value, unsigned char *buffer, 198 size_t buffer_size) { 199 return _cbor_encode_uint8(value, buffer, buffer_size, 0xE0); 200 } 201