/
githubmirror
/
libcbor
Обзор
Документация
Войти
/
githubmirror
/
libcbor
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/cbor/internal/loaders.c
97 строк
3 KB
Pavel Kalvoda
Preserve NaN sign+payload and tiny-float sign in cbor_encode_half (#412)
23 мар 2026, 00:18
Не верифицирован
23 мар 2026, 00:18
bdf710e
Код
Авторство
О чём код?
/* * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com> * * libcbor is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include "loaders.h" #include <math.h> #include <string.h> uint8_t _cbor_load_uint8(cbor_data source) { return (uint8_t)*source; } uint16_t _cbor_load_uint16(const unsigned char* source) { #ifdef IS_BIG_ENDIAN uint16_t result; memcpy(&result, source, 2); return result; #else return ((uint16_t) * (source + 0) << 8) + (uint8_t) * (source + 1); #endif } uint32_t _cbor_load_uint32(const unsigned char* source) { #ifdef IS_BIG_ENDIAN uint32_t result; memcpy(&result, source, 4); return result; #else return ((uint32_t) * (source + 0) << 0x18) + ((uint32_t) * (source + 1) << 0x10) + ((uint16_t) * (source + 2) << 0x08) + (uint8_t) * (source + 3); #endif } uint64_t _cbor_load_uint64(const unsigned char* source) { #ifdef IS_BIG_ENDIAN uint64_t result; memcpy(&result, source, 8); return result; #else return ((uint64_t) * (source + 0) << 0x38) + ((uint64_t) * (source + 1) << 0x30) + ((uint64_t) * (source + 2) << 0x28) + ((uint64_t) * (source + 3) << 0x20) + ((uint32_t) * (source + 4) << 0x18) + ((uint32_t) * (source + 5) << 0x10) + ((uint16_t) * (source + 6) << 0x08) + (uint8_t) * (source + 7); #endif } /* As per https://www.rfc-editor.org/rfc/rfc8949.html#name-half-precision */ float _cbor_decode_half(unsigned char* halfp) { // TODO: Broken if we are not on IEEE 754 // (https://github.com/PJK/libcbor/issues/336) int half = (halfp[0] << 8) + halfp[1]; int exp = (half >> 10) & 0x1f; int mant = half & 0x3ff; if (exp == 31 && mant != 0) { /* NaN: reconstruct as a single-precision NaN, preserving the sign bit and * the 10-bit half-precision payload by placing it in the top 10 bits of * the 23-bit single-precision mantissa. This ensures round-trip fidelity * with cbor_encode_half's NaN encoding. */ union _cbor_float_helper helper = { .as_uint = ((uint32_t)(half & 0x8000) << 16) | /* sign */ 0x7F800000u | /* exponent (all 1s) */ ((uint32_t)mant << 13)}; /* payload */ return helper.as_float; } double val; if (exp == 0) val = ldexp(mant, -24); else if (exp != 31) val = ldexp(mant + 1024, exp - 25); else val = INFINITY; /* exp == 31, mant == 0: the NaN case is handled above */ return (float)(half & 0x8000 ? -val : val); } float _cbor_load_half(cbor_data source) { /* Discard const */ return _cbor_decode_half((unsigned char*)source); } float _cbor_load_float(cbor_data source) { // TODO: Broken if we are not on IEEE 754 // (https://github.com/PJK/libcbor/issues/336) union _cbor_float_helper helper = {.as_uint = _cbor_load_uint32(source)}; return helper.as_float; } double _cbor_load_double(cbor_data source) { // TODO: Broken if we are not on IEEE 754 // (https://github.com/PJK/libcbor/issues/336) union _cbor_double_helper helper = {.as_uint = _cbor_load_uint64(source)}; return helper.as_double; }