Path: blob/main/contrib/libcbor/src/cbor/encoding.c
39534 views
/*1* Copyright (c) 2014-2020 Pavel Kalvoda <[email protected]>2*3* libcbor is free software; you can redistribute it and/or modify4* it under the terms of the MIT license. See LICENSE for details.5*/67#include "encoding.h"8#include "internal/encoders.h"910size_t cbor_encode_uint8(uint8_t value, unsigned char *buffer,11size_t buffer_size) {12return _cbor_encode_uint8(value, buffer, buffer_size, 0x00);13}1415size_t cbor_encode_uint16(uint16_t value, unsigned char *buffer,16size_t buffer_size) {17return _cbor_encode_uint16(value, buffer, buffer_size, 0x00);18}1920size_t cbor_encode_uint32(uint32_t value, unsigned char *buffer,21size_t buffer_size) {22return _cbor_encode_uint32(value, buffer, buffer_size, 0x00);23}2425size_t cbor_encode_uint64(uint64_t value, unsigned char *buffer,26size_t buffer_size) {27return _cbor_encode_uint64(value, buffer, buffer_size, 0x00);28}2930size_t cbor_encode_uint(uint64_t value, unsigned char *buffer,31size_t buffer_size) {32return _cbor_encode_uint(value, buffer, buffer_size, 0x00);33}3435size_t cbor_encode_negint8(uint8_t value, unsigned char *buffer,36size_t buffer_size) {37return _cbor_encode_uint8(value, buffer, buffer_size, 0x20);38}3940size_t cbor_encode_negint16(uint16_t value, unsigned char *buffer,41size_t buffer_size) {42return _cbor_encode_uint16(value, buffer, buffer_size, 0x20);43}4445size_t cbor_encode_negint32(uint32_t value, unsigned char *buffer,46size_t buffer_size) {47return _cbor_encode_uint32(value, buffer, buffer_size, 0x20);48}4950size_t cbor_encode_negint64(uint64_t value, unsigned char *buffer,51size_t buffer_size) {52return _cbor_encode_uint64(value, buffer, buffer_size, 0x20);53}5455size_t cbor_encode_negint(uint64_t value, unsigned char *buffer,56size_t buffer_size) {57return _cbor_encode_uint(value, buffer, buffer_size, 0x20);58}5960size_t cbor_encode_bytestring_start(size_t length, unsigned char *buffer,61size_t buffer_size) {62return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0x40);63}6465size_t _cbor_encode_byte(uint8_t value, unsigned char *buffer,66size_t buffer_size) {67if (buffer_size >= 1) {68buffer[0] = value;69return 1;70} else71return 0;72}7374size_t cbor_encode_indef_bytestring_start(unsigned char *buffer,75size_t buffer_size) {76return _cbor_encode_byte(0x5F, buffer, buffer_size);77}7879size_t cbor_encode_string_start(size_t length, unsigned char *buffer,80size_t buffer_size) {81return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0x60);82}8384size_t cbor_encode_indef_string_start(unsigned char *buffer,85size_t buffer_size) {86return _cbor_encode_byte(0x7F, buffer, buffer_size);87}8889size_t cbor_encode_array_start(size_t length, unsigned char *buffer,90size_t buffer_size) {91return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0x80);92}9394size_t cbor_encode_indef_array_start(unsigned char *buffer,95size_t buffer_size) {96return _cbor_encode_byte(0x9F, buffer, buffer_size);97}9899size_t cbor_encode_map_start(size_t length, unsigned char *buffer,100size_t buffer_size) {101return _cbor_encode_uint((size_t)length, buffer, buffer_size, 0xA0);102}103104size_t cbor_encode_indef_map_start(unsigned char *buffer, size_t buffer_size) {105return _cbor_encode_byte(0xBF, buffer, buffer_size);106}107108size_t cbor_encode_tag(uint64_t value, unsigned char *buffer,109size_t buffer_size) {110return _cbor_encode_uint(value, buffer, buffer_size, 0xC0);111}112113size_t cbor_encode_bool(bool value, unsigned char *buffer, size_t buffer_size) {114return value ? _cbor_encode_byte(0xF5, buffer, buffer_size)115: _cbor_encode_byte(0xF4, buffer, buffer_size);116}117118size_t cbor_encode_null(unsigned char *buffer, size_t buffer_size) {119return _cbor_encode_byte(0xF6, buffer, buffer_size);120}121122size_t cbor_encode_undef(unsigned char *buffer, size_t buffer_size) {123return _cbor_encode_byte(0xF7, buffer, buffer_size);124}125126size_t cbor_encode_half(float value, unsigned char *buffer,127size_t buffer_size) {128/* Assuming value is normalized */129uint32_t val = ((union _cbor_float_helper){.as_float = value}).as_uint;130uint16_t res;131uint8_t exp = (uint8_t)((val & 0x7F800000u) >>13223u); /* 0b0111_1111_1000_0000_0000_0000_0000_0000 */133uint32_t mant =134val & 0x7FFFFFu; /* 0b0000_0000_0111_1111_1111_1111_1111_1111 */135if (exp == 0xFF) { /* Infinity or NaNs */136if (value != value) {137// We discard information bits in half-float NaNs. This is138// not required for the core CBOR protocol (it is only a suggestion in139// Section 3.9).140// See https://github.com/PJK/libcbor/issues/215141res = (uint16_t)0x007e00;142} else {143// If the mantissa is non-zero, we have a NaN, but those are handled144// above. See145// https://en.wikipedia.org/wiki/Half-precision_floating-point_format146CBOR_ASSERT(mant == 0u);147res = (uint16_t)((val & 0x80000000u) >> 16u | 0x7C00u);148}149} else if (exp == 0x00) { /* Zeroes or subnorms */150res = (uint16_t)((val & 0x80000000u) >> 16u | mant >> 13u);151} else { /* Normal numbers */152int8_t logical_exp = (int8_t)(exp - 127);153CBOR_ASSERT(logical_exp == exp - 127);154155// Now we know that 2^exp <= 0 logically156if (logical_exp < -24) {157/* No unambiguous representation exists, this float is not a half float158and is too small to be represented using a half, round off to zero.159Consistent with the reference implementation. */160res = 0;161} else if (logical_exp < -14) {162/* Offset the remaining decimal places by shifting the significand, the163value is lost. This is an implementation decision that works around the164absence of standard half-float in the language. */165res = (uint16_t)((val & 0x80000000u) >> 16u) | // Extract sign bit166((uint16_t)(1u << (24u + logical_exp)) +167(uint16_t)(((mant >> (-logical_exp - 2)) + 1) >>1681)); // Round half away from zero for simplicity169} else {170res = (uint16_t)((val & 0x80000000u) >> 16u |171((((uint8_t)logical_exp) + 15u) << 10u) |172(uint16_t)(mant >> 13u));173}174}175return _cbor_encode_uint16(res, buffer, buffer_size, 0xE0);176}177178size_t cbor_encode_single(float value, unsigned char *buffer,179size_t buffer_size) {180return _cbor_encode_uint32(181((union _cbor_float_helper){.as_float = value}).as_uint, buffer,182buffer_size, 0xE0);183}184185size_t cbor_encode_double(double value, unsigned char *buffer,186size_t buffer_size) {187return _cbor_encode_uint64(188((union _cbor_double_helper){.as_double = value}).as_uint, buffer,189buffer_size, 0xE0);190}191192size_t cbor_encode_break(unsigned char *buffer, size_t buffer_size) {193return _cbor_encode_byte(0xFF, buffer, buffer_size);194}195196size_t cbor_encode_ctrl(uint8_t value, unsigned char *buffer,197size_t buffer_size) {198return _cbor_encode_uint8(value, buffer, buffer_size, 0xE0);199}200201202