encoding.c revision 1.3
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
11size_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
16size_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
21size_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
26size_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
31size_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
36size_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
41size_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
46size_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
51size_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
56size_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
61size_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
66size_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
75size_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
80size_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
85size_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
90size_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
95size_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
100size_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
105size_t cbor_encode_indef_map_start(unsigned char *buffer, size_t buffer_size) {
106  return _cbor_encode_byte(0xBF, buffer, buffer_size);
107}
108
109size_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
114size_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
119size_t cbor_encode_null(unsigned char *buffer, size_t buffer_size) {
120  return _cbor_encode_byte(0xF6, buffer, buffer_size);
121}
122
123size_t cbor_encode_undef(unsigned char *buffer, size_t buffer_size) {
124  return _cbor_encode_byte(0xF7, buffer, buffer_size);
125}
126
127size_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      res = (uint16_t)0x007e00; /* Not IEEE semantics - required by CBOR
139                                   [s. 3.9] */
140    } else {
141      res = (uint16_t)((val & 0x80000000u) >> 16u | 0x7C00u |
142                       (mant ? 1u : 0u) << 15u);
143    }
144  } else if (exp == 0x00) { /* Zeroes or subnorms */
145    res = (uint16_t)((val & 0x80000000u) >> 16u | mant >> 13u);
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 & 0x80000000u) >> 16u) |  // Extract sign bit
161            (uint16_t)(1u << (24u + logical_exp));
162    } else {
163      res = (uint16_t)((val & 0x80000000u) >> 16u |
164                       ((((uint8_t)logical_exp) + 15u) << 10u) |
165                       (uint16_t)(mant >> 13u));
166    }
167  }
168  return _cbor_encode_uint16(res, buffer, buffer_size, 0xE0);
169}
170
171size_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
178size_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
185size_t cbor_encode_break(unsigned char *buffer, size_t buffer_size) {
186  return _cbor_encode_byte(0xFF, buffer, buffer_size);
187}
188
189size_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