blob: 5c8d484858c7401ffd981c09af0f6faa9fef4870 [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 Macieira8f3fb782015-06-16 16:27:01 -070034#include "assert_p.h" /* Always include last */
35
Thiago Macieira5752ce52015-06-16 12:10:03 -070036void cbor_encoder_init(CborEncoder *encoder, uint8_t *buffer, size_t size, int flags)
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070037{
38 encoder->ptr = buffer;
39 encoder->end = buffer + size;
40 encoder->flags = flags;
41}
42
Thiago Macieira5752ce52015-06-16 12:10:03 -070043static inline void put16(void *where, uint16_t v)
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070044{
Thiago Macieira5934a9f2015-06-16 11:55:28 -070045 v = cbor_htons(v);
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070046 memcpy(where, &v, sizeof(v));
47}
48
Thiago Macieira5752ce52015-06-16 12:10:03 -070049static inline void put32(void *where, uint32_t v)
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070050{
Thiago Macieira5934a9f2015-06-16 11:55:28 -070051 v = cbor_htonl(v);
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070052 memcpy(where, &v, sizeof(v));
53}
54
Thiago Macieira5752ce52015-06-16 12:10:03 -070055static inline void put64(void *where, uint64_t v)
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070056{
Thiago Macieira5934a9f2015-06-16 11:55:28 -070057 v = cbor_htonll(v);
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070058 memcpy(where, &v, sizeof(v));
59}
60
Thiago Macieira5752ce52015-06-16 12:10:03 -070061static inline CborError append_to_buffer(CborEncoder *encoder, const void *data, size_t len)
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070062{
63 if (encoder->ptr + len > encoder->end)
64 return CborErrorOutOfMemory;
65 memcpy(encoder->ptr, data, len);
66 encoder->ptr += len;
67 return CborNoError;
68}
69
Thiago Macieira5752ce52015-06-16 12:10:03 -070070static inline CborError append_byte_to_buffer(CborEncoder *encoder, uint8_t byte)
Thiago Macieira8f7bd9e2015-05-12 13:37:46 +090071{
72 if (encoder->ptr == encoder->end)
73 return CborErrorOutOfMemory;
74 *encoder->ptr++ = byte;
75 return CborNoError;
76}
77
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070078static inline CborError encode_number(CborEncoder *encoder, uint64_t ui, uint8_t shiftedMajorType)
79{
Thiago Macieiraafa4ff62015-05-09 10:09:55 -070080 /* Little-endian would have been so much more convenient here:
81 * We could just write at the beginning of buf but append_to_buffer
82 * only the necessary bytes.
83 * Since it has to be big endian, do it the other way around:
84 * write from the end. */
Thiago Macieira5752ce52015-06-16 12:10:03 -070085 uint8_t buf[1 + sizeof(ui)];
86 uint8_t *const bufend = buf + sizeof(buf);
87 uint8_t *bufstart = bufend - 1;
Thiago Macieiraafa4ff62015-05-09 10:09:55 -070088 put64(buf + 1, ui); // we probably have a bunch of zeros in the beginning
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070089
90 if (ui < Value8Bit) {
Thiago Macieiraafa4ff62015-05-09 10:09:55 -070091 *bufstart += shiftedMajorType;
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070092 } else {
Thiago Macieiraafa4ff62015-05-09 10:09:55 -070093 unsigned more = 0;
94 if (ui > UINT8_MAX)
95 ++more;
96 if (ui > UINT16_MAX)
97 ++more;
98 if (ui != (uint32_t)ui)
99 ++more;
100 bufstart -= 1 << more;
101 *bufstart = shiftedMajorType + Value8Bit + more;
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700102 }
103
Thiago Macieiraafa4ff62015-05-09 10:09:55 -0700104 return append_to_buffer(encoder, bufstart, bufend - bufstart);
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700105}
106
107CborError cbor_encode_uint(CborEncoder *encoder, uint64_t value)
108{
109 return encode_number(encoder, value, UnsignedIntegerType << MajorTypeShift);
110}
111
112CborError cbor_encode_int(CborEncoder *encoder, int64_t value)
113{
114 // adapted from code in RFC 7049 appendix C (pseudocode)
115 uint64_t ui = value >> 63; // extend sign to whole length
116 uint8_t majorType = ui & 0x20; // extract major type
117 ui ^= value; // complement negatives
118 return encode_number(encoder, ui, majorType);
119}
120
121CborError cbor_encode_simple_value(CborEncoder *encoder, uint8_t value)
122{
123#ifndef CBOR_ENCODER_NO_CHECK_USER
124 // check if this is a valid simple type
125 if (value >= HalfPrecisionFloat && value <= Break)
126 return CborErrorIllegalSimpleType;
127#endif
128 return encode_number(encoder, value, SimpleTypesType << MajorTypeShift);
129}
130
Thiago Macieira81f33432015-07-02 16:16:28 -0700131CborError cbor_encode_floating_point(CborEncoder *encoder, CborType fpType, const void *value)
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700132{
Thiago Macieira81f33432015-07-02 16:16:28 -0700133 uint8_t buf[1 + sizeof(uint64_t)];
134 assert(fpType == CborHalfFloatType || fpType == CborFloatType || fpType == CborDoubleType);
135 buf[0] = fpType;
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700136
Thiago Macieira81f33432015-07-02 16:16:28 -0700137 unsigned size = 2U << (fpType - CborHalfFloatType);
138 if (size == 8)
139 put64(buf + 1, *(const uint64_t*)value);
140 else if (size == 4)
141 put32(buf + 1, *(const uint32_t*)value);
142 else
143 put16(buf + 1, *(const uint16_t*)value);
144 return append_to_buffer(encoder, buf, size + 1);
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700145}
Thiago Macieira8f98a112015-05-08 17:25:29 -0700146
147CborError cbor_encode_tag(CborEncoder *encoder, CborTag tag)
148{
149 return encode_number(encoder, tag, TagType << MajorTypeShift);
150}
Thiago Macieirab54debe2015-05-08 17:42:39 -0700151
Thiago Macieira5752ce52015-06-16 12:10:03 -0700152static CborError encode_string(CborEncoder *encoder, size_t length, uint8_t shiftedMajorType, const void *string)
Thiago Macieirab54debe2015-05-08 17:42:39 -0700153{
154 CborError err = encode_number(encoder, length, shiftedMajorType);
155 if (err)
156 return err;
157 return append_to_buffer(encoder, string, length);
158}
159
Thiago Macieira5752ce52015-06-16 12:10:03 -0700160CborError cbor_encode_byte_string(CborEncoder *encoder, const uint8_t *string, size_t length)
Thiago Macieirab54debe2015-05-08 17:42:39 -0700161{
162 return encode_string(encoder, length, ByteStringType << MajorTypeShift, string);
163}
164
165CborError cbor_encode_text_string(CborEncoder *encoder, const char *string, size_t length)
166{
167 return encode_string(encoder, length, TextStringType << MajorTypeShift, string);
168}
Thiago Macieira355817e2015-05-08 18:38:18 -0700169
170static CborError create_container(CborEncoder *encoder, size_t length, uint8_t shiftedMajorType, CborEncoder *container)
171{
Thiago Macieira8f7bd9e2015-05-12 13:37:46 +0900172 CborError err;
173 if (length == CborIndefiniteLength)
174 err = append_byte_to_buffer(encoder, shiftedMajorType + IndefiniteLength);
175 else
176 err = encode_number(encoder, length, shiftedMajorType);
Thiago Macieira355817e2015-05-08 18:38:18 -0700177 if (err)
178 return err;
Thiago Macieira8f7bd9e2015-05-12 13:37:46 +0900179
Thiago Macieira355817e2015-05-08 18:38:18 -0700180 *container = *encoder;
Thiago Macieira8f7bd9e2015-05-12 13:37:46 +0900181 container->flags = length == CborIndefiniteLength ? CborIteratorFlag_UnknownLength : 0;
Thiago Macieira355817e2015-05-08 18:38:18 -0700182 return CborNoError;
183}
184
185CborError cbor_encoder_create_array(CborEncoder *encoder, CborEncoder *arrayEncoder, size_t length)
186{
187 return create_container(encoder, length, ArrayType << MajorTypeShift, arrayEncoder);
188}
189
190CborError cbor_encoder_create_map(CborEncoder *encoder, CborEncoder *mapEncoder, size_t length)
191{
192 return create_container(encoder, length, MapType << MajorTypeShift, mapEncoder);
193}
194
195CborError cbor_encoder_close_container(CborEncoder *encoder, const CborEncoder *containerEncoder)
196{
Thiago Macieira8f7bd9e2015-05-12 13:37:46 +0900197 encoder->ptr = containerEncoder->ptr;
198 if (containerEncoder->flags & CborIteratorFlag_UnknownLength)
199 return append_byte_to_buffer(encoder, BreakByte);
Thiago Macieira355817e2015-05-08 18:38:18 -0700200 return CborNoError;
201}