110ff414cSEd Maste /*
210ff414cSEd Maste  * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
310ff414cSEd Maste  *
410ff414cSEd Maste  * libcbor is free software; you can redistribute it and/or modify
510ff414cSEd Maste  * it under the terms of the MIT license. See LICENSE for details.
610ff414cSEd Maste  */
710ff414cSEd Maste 
810ff414cSEd Maste #include "loaders.h"
910ff414cSEd Maste #include <math.h>
1010ff414cSEd Maste #include <string.h>
1110ff414cSEd Maste 
_cbor_load_uint8(cbor_data source)1210ff414cSEd Maste uint8_t _cbor_load_uint8(cbor_data source) { return (uint8_t)*source; }
1310ff414cSEd Maste 
_cbor_load_uint16(const unsigned char * source)1410ff414cSEd Maste uint16_t _cbor_load_uint16(const unsigned char *source) {
1510ff414cSEd Maste #ifdef IS_BIG_ENDIAN
1610ff414cSEd Maste   uint16_t result;
1710ff414cSEd Maste   memcpy(&result, source, 2);
1810ff414cSEd Maste   return result;
1910ff414cSEd Maste #else
2010ff414cSEd Maste   return ((uint16_t) * (source + 0) << 8) + (uint8_t) * (source + 1);
2110ff414cSEd Maste #endif
2210ff414cSEd Maste }
2310ff414cSEd Maste 
_cbor_load_uint32(const unsigned char * source)2410ff414cSEd Maste uint32_t _cbor_load_uint32(const unsigned char *source) {
2510ff414cSEd Maste #ifdef IS_BIG_ENDIAN
2610ff414cSEd Maste   uint32_t result;
2710ff414cSEd Maste   memcpy(&result, source, 4);
2810ff414cSEd Maste   return result;
2910ff414cSEd Maste #else
3010ff414cSEd Maste   return ((uint32_t) * (source + 0) << 0x18) +
3110ff414cSEd Maste          ((uint32_t) * (source + 1) << 0x10) +
3210ff414cSEd Maste          ((uint16_t) * (source + 2) << 0x08) + (uint8_t) * (source + 3);
3310ff414cSEd Maste #endif
3410ff414cSEd Maste }
3510ff414cSEd Maste 
_cbor_load_uint64(const unsigned char * source)3610ff414cSEd Maste uint64_t _cbor_load_uint64(const unsigned char *source) {
3710ff414cSEd Maste #ifdef IS_BIG_ENDIAN
3810ff414cSEd Maste   uint64_t result;
3910ff414cSEd Maste   memcpy(&result, source, 8);
4010ff414cSEd Maste   return result;
4110ff414cSEd Maste #else
4210ff414cSEd Maste   return ((uint64_t) * (source + 0) << 0x38) +
4310ff414cSEd Maste          ((uint64_t) * (source + 1) << 0x30) +
4410ff414cSEd Maste          ((uint64_t) * (source + 2) << 0x28) +
4510ff414cSEd Maste          ((uint64_t) * (source + 3) << 0x20) +
4610ff414cSEd Maste          ((uint32_t) * (source + 4) << 0x18) +
4710ff414cSEd Maste          ((uint32_t) * (source + 5) << 0x10) +
4810ff414cSEd Maste          ((uint16_t) * (source + 6) << 0x08) + (uint8_t) * (source + 7);
4910ff414cSEd Maste #endif
5010ff414cSEd Maste }
5110ff414cSEd Maste 
5210ff414cSEd Maste /* As per http://tools.ietf.org/html/rfc7049#appendix-D */
_cbor_decode_half(unsigned char * halfp)5310ff414cSEd Maste float _cbor_decode_half(unsigned char *halfp) {
5410ff414cSEd Maste   int half = (halfp[0] << 8) + halfp[1];
5510ff414cSEd Maste   int exp = (half >> 10) & 0x1f;
5610ff414cSEd Maste   int mant = half & 0x3ff;
5710ff414cSEd Maste   double val;
5810ff414cSEd Maste   if (exp == 0)
5910ff414cSEd Maste     val = ldexp(mant, -24);
6010ff414cSEd Maste   else if (exp != 31)
6110ff414cSEd Maste     val = ldexp(mant + 1024, exp - 25);
6210ff414cSEd Maste   else
6310ff414cSEd Maste     val = mant == 0 ? INFINITY : NAN;
6410ff414cSEd Maste   return (float)(half & 0x8000 ? -val : val);
6510ff414cSEd Maste }
6610ff414cSEd Maste 
_cbor_load_half(cbor_data source)67*5d3e7166SEd Maste float _cbor_load_half(cbor_data source) {
6810ff414cSEd Maste   /* Discard const */
6910ff414cSEd Maste   return _cbor_decode_half((unsigned char *)source);
7010ff414cSEd Maste }
7110ff414cSEd Maste 
_cbor_load_float(cbor_data source)7210ff414cSEd Maste float _cbor_load_float(cbor_data source) {
7310ff414cSEd Maste   union _cbor_float_helper helper = {.as_uint = _cbor_load_uint32(source)};
7410ff414cSEd Maste   return helper.as_float;
7510ff414cSEd Maste }
7610ff414cSEd Maste 
_cbor_load_double(cbor_data source)7710ff414cSEd Maste double _cbor_load_double(cbor_data source) {
7810ff414cSEd Maste   union _cbor_double_helper helper = {.as_uint = _cbor_load_uint64(source)};
7910ff414cSEd Maste   return helper.as_double;
8010ff414cSEd Maste }
81