Home | History | Annotate | Line # | Download | only in cbor
      1 /*
      2  * Copyright (c) 2014-2019 Pavel Kalvoda <me (at) 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 & 0x7F800000) >>
    133                           23); /* 0b0111_1111_1000_0000_0000_0000_0000_0000 */
    134   uint32_t mant =
    135       val & 0x7FFFFF; /* 0b0000_0000_0111_1111_1111_1111_1111_1111 */
    136   if (exp == 0xFF) {  /* Infinity or NaNs */
    137     if (value != value) {
    138       res = (uint16_t)0x00e700; /* Not IEEE semantics - required by CBOR
    139                                    [s. 3.9] */
    140     } else {
    141       res =
    142           (uint16_t)((val & 0x80000000) >> 16 | 0x7C00 | (mant ? 1 : 0) << 15);
    143     }
    144   } else if (exp == 0x00) { /* Zeroes or subnorms */
    145     res = (uint16_t)((val & 0x80000000) >> 16 | mant >> 13);
    146   } else { /* Normal numbers */
    147     int8_t logical_exp = (int8_t)(exp - 127);
    148     assert(logical_exp == exp - 127);
    149 
    150     // Now we know that 2^exp <= 0 logically
    151     if (logical_exp < -24) {
    152       /* No unambiguous representation exists, this float is not a half float
    153          and is too small to be represented using a half, round off to zero.
    154          Consistent with the reference implementation. */
    155       res = 0;
    156     } else if (logical_exp < -14) {
    157       /* Offset the remaining decimal places by shifting the significand, the
    158          value is lost. This is an implementation decision that works around the
    159          absence of standard half-float in the language. */
    160       res = (uint16_t)(val & 0x80000000) >> 16 |
    161             (uint16_t)(1 << (24 + logical_exp));
    162     } else {
    163       res = (uint16_t)((val & 0x80000000) >> 16 |
    164                        ((((uint8_t)logical_exp) + 15) << 10) |
    165                        (uint16_t)(mant >> 13));
    166     }
    167   }
    168   return _cbor_encode_uint16(res, buffer, buffer_size, 0xE0);
    169 }
    170 
    171 size_t cbor_encode_single(float value, unsigned char *buffer,
    172                           size_t buffer_size) {
    173   return _cbor_encode_uint32(
    174       ((union _cbor_float_helper){.as_float = value}).as_uint, buffer,
    175       buffer_size, 0xE0);
    176 }
    177 
    178 size_t cbor_encode_double(double value, unsigned char *buffer,
    179                           size_t buffer_size) {
    180   return _cbor_encode_uint64(
    181       ((union _cbor_double_helper){.as_double = value}).as_uint, buffer,
    182       buffer_size, 0xE0);
    183 }
    184 
    185 size_t cbor_encode_break(unsigned char *buffer, size_t buffer_size) {
    186   return _cbor_encode_byte(0xFF, buffer, buffer_size);
    187 }
    188 
    189 size_t cbor_encode_ctrl(uint8_t value, unsigned char *buffer,
    190                         size_t buffer_size) {
    191   return _cbor_encode_uint8(value, buffer, buffer_size, 0xE0);
    192 }
    193