blob: 4cb96c7c6cb2b54cd1aceea929d732e4ecb4dd6c [file] [log] [blame]
Thiago Macieiraf1cadf02015-05-08 17:19:17 -07001/****************************************************************************
2**
3** Copyright (C) 2015 Intel Corporation
4**
5** Permission is hereby granted, free of charge, to any person obtaining a copy
6** of this software and associated documentation files (the "Software"), to deal
7** in the Software without restriction, including without limitation the rights
8** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9** copies of the Software, and to permit persons to whom the Software is
10** furnished to do so, subject to the following conditions:
11**
12** The above copyright notice and this permission notice shall be included in
13** all copies or substantial portions of the Software.
14**
15** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21** THE SOFTWARE.
22**
23****************************************************************************/
24
25#define _BSD_SOURCE
26#include "cbor.h"
27#include "cborconstants_p.h"
28#include "compilersupport_p.h"
29
30#include <assert.h>
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070031#include <stdlib.h>
32#include <string.h>
33
Thiago Macieira5752ce52015-06-16 12:10:03 -070034void cbor_encoder_init(CborEncoder *encoder, uint8_t *buffer, size_t size, int flags)
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070035{
36 encoder->ptr = buffer;
37 encoder->end = buffer + size;
38 encoder->flags = flags;
39}
40
Thiago Macieira5752ce52015-06-16 12:10:03 -070041static inline void put16(void *where, uint16_t v)
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070042{
Thiago Macieira5934a9f2015-06-16 11:55:28 -070043 v = cbor_htons(v);
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070044 memcpy(where, &v, sizeof(v));
45}
46
Thiago Macieira5752ce52015-06-16 12:10:03 -070047static inline void put32(void *where, uint32_t v)
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070048{
Thiago Macieira5934a9f2015-06-16 11:55:28 -070049 v = cbor_htonl(v);
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070050 memcpy(where, &v, sizeof(v));
51}
52
Thiago Macieira5752ce52015-06-16 12:10:03 -070053static inline void put64(void *where, uint64_t v)
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070054{
Thiago Macieira5934a9f2015-06-16 11:55:28 -070055 v = cbor_htonll(v);
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070056 memcpy(where, &v, sizeof(v));
57}
58
Thiago Macieira5752ce52015-06-16 12:10:03 -070059static inline CborError append_to_buffer(CborEncoder *encoder, const void *data, size_t len)
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070060{
61 if (encoder->ptr + len > encoder->end)
62 return CborErrorOutOfMemory;
63 memcpy(encoder->ptr, data, len);
64 encoder->ptr += len;
65 return CborNoError;
66}
67
Thiago Macieira5752ce52015-06-16 12:10:03 -070068static inline CborError append_byte_to_buffer(CborEncoder *encoder, uint8_t byte)
Thiago Macieira8f7bd9e2015-05-12 13:37:46 +090069{
70 if (encoder->ptr == encoder->end)
71 return CborErrorOutOfMemory;
72 *encoder->ptr++ = byte;
73 return CborNoError;
74}
75
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070076static inline CborError encode_number(CborEncoder *encoder, uint64_t ui, uint8_t shiftedMajorType)
77{
Thiago Macieiraafa4ff62015-05-09 10:09:55 -070078 /* Little-endian would have been so much more convenient here:
79 * We could just write at the beginning of buf but append_to_buffer
80 * only the necessary bytes.
81 * Since it has to be big endian, do it the other way around:
82 * write from the end. */
Thiago Macieira5752ce52015-06-16 12:10:03 -070083 uint8_t buf[1 + sizeof(ui)];
84 uint8_t *const bufend = buf + sizeof(buf);
85 uint8_t *bufstart = bufend - 1;
Thiago Macieiraafa4ff62015-05-09 10:09:55 -070086 put64(buf + 1, ui); // we probably have a bunch of zeros in the beginning
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070087
88 if (ui < Value8Bit) {
Thiago Macieiraafa4ff62015-05-09 10:09:55 -070089 *bufstart += shiftedMajorType;
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070090 } else {
Thiago Macieiraafa4ff62015-05-09 10:09:55 -070091 unsigned more = 0;
92 if (ui > UINT8_MAX)
93 ++more;
94 if (ui > UINT16_MAX)
95 ++more;
96 if (ui != (uint32_t)ui)
97 ++more;
98 bufstart -= 1 << more;
99 *bufstart = shiftedMajorType + Value8Bit + more;
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700100 }
101
Thiago Macieiraafa4ff62015-05-09 10:09:55 -0700102 return append_to_buffer(encoder, bufstart, bufend - bufstart);
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700103}
104
105CborError cbor_encode_uint(CborEncoder *encoder, uint64_t value)
106{
107 return encode_number(encoder, value, UnsignedIntegerType << MajorTypeShift);
108}
109
110CborError cbor_encode_int(CborEncoder *encoder, int64_t value)
111{
112 // adapted from code in RFC 7049 appendix C (pseudocode)
113 uint64_t ui = value >> 63; // extend sign to whole length
114 uint8_t majorType = ui & 0x20; // extract major type
115 ui ^= value; // complement negatives
116 return encode_number(encoder, ui, majorType);
117}
118
119CborError cbor_encode_simple_value(CborEncoder *encoder, uint8_t value)
120{
121#ifndef CBOR_ENCODER_NO_CHECK_USER
122 // check if this is a valid simple type
123 if (value >= HalfPrecisionFloat && value <= Break)
124 return CborErrorIllegalSimpleType;
125#endif
126 return encode_number(encoder, value, SimpleTypesType << MajorTypeShift);
127}
128
129CborError cbor_encode_half_float(CborEncoder *encoder, const void *value)
130{
Thiago Macieira5752ce52015-06-16 12:10:03 -0700131 uint8_t buf[1 + sizeof(uint16_t)] = { CborHalfFloatType };
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700132 put16(buf + 1, *(const uint16_t*)value);
133 return append_to_buffer(encoder, buf, sizeof(buf));
134}
135
136CborError cbor_encode_float(CborEncoder *encoder, const float *value)
137{
Thiago Macieira5752ce52015-06-16 12:10:03 -0700138 uint8_t buf[1 + sizeof(uint32_t)] = { CborFloatType };
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700139 put32(buf + 1, *(const uint32_t*)value);
140 return append_to_buffer(encoder, buf, sizeof(buf));
141}
142
143CborError cbor_encode_double(CborEncoder *encoder, const double *value)
144{
Thiago Macieira5752ce52015-06-16 12:10:03 -0700145 uint8_t buf[1 + sizeof(uint64_t)] = { CborDoubleType };
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700146 put64(buf + 1, *(const uint64_t*)value);
147 return append_to_buffer(encoder, buf, sizeof(buf));
148}
Thiago Macieira8f98a112015-05-08 17:25:29 -0700149
150CborError cbor_encode_tag(CborEncoder *encoder, CborTag tag)
151{
152 return encode_number(encoder, tag, TagType << MajorTypeShift);
153}
Thiago Macieirab54debe2015-05-08 17:42:39 -0700154
Thiago Macieira5752ce52015-06-16 12:10:03 -0700155static CborError encode_string(CborEncoder *encoder, size_t length, uint8_t shiftedMajorType, const void *string)
Thiago Macieirab54debe2015-05-08 17:42:39 -0700156{
157 CborError err = encode_number(encoder, length, shiftedMajorType);
158 if (err)
159 return err;
160 return append_to_buffer(encoder, string, length);
161}
162
Thiago Macieira5752ce52015-06-16 12:10:03 -0700163CborError cbor_encode_byte_string(CborEncoder *encoder, const uint8_t *string, size_t length)
Thiago Macieirab54debe2015-05-08 17:42:39 -0700164{
165 return encode_string(encoder, length, ByteStringType << MajorTypeShift, string);
166}
167
168CborError cbor_encode_text_string(CborEncoder *encoder, const char *string, size_t length)
169{
170 return encode_string(encoder, length, TextStringType << MajorTypeShift, string);
171}
Thiago Macieira355817e2015-05-08 18:38:18 -0700172
173static CborError create_container(CborEncoder *encoder, size_t length, uint8_t shiftedMajorType, CborEncoder *container)
174{
Thiago Macieira8f7bd9e2015-05-12 13:37:46 +0900175 CborError err;
176 if (length == CborIndefiniteLength)
177 err = append_byte_to_buffer(encoder, shiftedMajorType + IndefiniteLength);
178 else
179 err = encode_number(encoder, length, shiftedMajorType);
Thiago Macieira355817e2015-05-08 18:38:18 -0700180 if (err)
181 return err;
Thiago Macieira8f7bd9e2015-05-12 13:37:46 +0900182
Thiago Macieira355817e2015-05-08 18:38:18 -0700183 *container = *encoder;
Thiago Macieira8f7bd9e2015-05-12 13:37:46 +0900184 container->flags = length == CborIndefiniteLength ? CborIteratorFlag_UnknownLength : 0;
Thiago Macieira355817e2015-05-08 18:38:18 -0700185 return CborNoError;
186}
187
188CborError cbor_encoder_create_array(CborEncoder *encoder, CborEncoder *arrayEncoder, size_t length)
189{
190 return create_container(encoder, length, ArrayType << MajorTypeShift, arrayEncoder);
191}
192
193CborError cbor_encoder_create_map(CborEncoder *encoder, CborEncoder *mapEncoder, size_t length)
194{
195 return create_container(encoder, length, MapType << MajorTypeShift, mapEncoder);
196}
197
198CborError cbor_encoder_close_container(CborEncoder *encoder, const CborEncoder *containerEncoder)
199{
Thiago Macieira8f7bd9e2015-05-12 13:37:46 +0900200 encoder->ptr = containerEncoder->ptr;
201 if (containerEncoder->flags & CborIteratorFlag_UnknownLength)
202 return append_byte_to_buffer(encoder, BreakByte);
Thiago Macieira355817e2015-05-08 18:38:18 -0700203 return CborNoError;
204}