blob: fef35bf4d05d07b219b3e3821550504e378295c5 [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>
31#include <endian.h>
32#include <stdlib.h>
33#include <string.h>
34
35void cbor_encoder_init(CborEncoder *encoder, char *buffer, size_t size, int flags)
36{
37 encoder->ptr = buffer;
38 encoder->end = buffer + size;
39 encoder->flags = flags;
40}
41
42static inline void put16(char *where, uint16_t v)
43{
44 v = htobe16(v);
45 memcpy(where, &v, sizeof(v));
46}
47
48static inline void put32(char *where, uint32_t v)
49{
50 v = htobe32(v);
51 memcpy(where, &v, sizeof(v));
52}
53
54static inline void put64(char *where, uint64_t v)
55{
56 v = htobe64(v);
57 memcpy(where, &v, sizeof(v));
58}
59
60static inline CborError append_to_buffer(CborEncoder *encoder, const char *data, size_t len)
61{
62 if (encoder->ptr + len > encoder->end)
63 return CborErrorOutOfMemory;
64 memcpy(encoder->ptr, data, len);
65 encoder->ptr += len;
66 return CborNoError;
67}
68
Thiago Macieira8f7bd9e2015-05-12 13:37:46 +090069static inline CborError append_byte_to_buffer(CborEncoder *encoder, char byte)
70{
71 if (encoder->ptr == encoder->end)
72 return CborErrorOutOfMemory;
73 *encoder->ptr++ = byte;
74 return CborNoError;
75}
76
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070077static inline CborError encode_number(CborEncoder *encoder, uint64_t ui, uint8_t shiftedMajorType)
78{
Thiago Macieiraafa4ff62015-05-09 10:09:55 -070079 /* Little-endian would have been so much more convenient here:
80 * We could just write at the beginning of buf but append_to_buffer
81 * only the necessary bytes.
82 * Since it has to be big endian, do it the other way around:
83 * write from the end. */
84 char buf[1 + sizeof(ui)];
85 char *const bufend = buf + sizeof(buf);
86 char *bufstart = bufend - 1;
87 put64(buf + 1, ui); // we probably have a bunch of zeros in the beginning
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070088
89 if (ui < Value8Bit) {
Thiago Macieiraafa4ff62015-05-09 10:09:55 -070090 *bufstart += shiftedMajorType;
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070091 } else {
Thiago Macieiraafa4ff62015-05-09 10:09:55 -070092 unsigned more = 0;
93 if (ui > UINT8_MAX)
94 ++more;
95 if (ui > UINT16_MAX)
96 ++more;
97 if (ui != (uint32_t)ui)
98 ++more;
99 bufstart -= 1 << more;
100 *bufstart = shiftedMajorType + Value8Bit + more;
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700101 }
102
Thiago Macieiraafa4ff62015-05-09 10:09:55 -0700103 return append_to_buffer(encoder, bufstart, bufend - bufstart);
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700104}
105
106CborError cbor_encode_uint(CborEncoder *encoder, uint64_t value)
107{
108 return encode_number(encoder, value, UnsignedIntegerType << MajorTypeShift);
109}
110
111CborError cbor_encode_int(CborEncoder *encoder, int64_t value)
112{
113 // adapted from code in RFC 7049 appendix C (pseudocode)
114 uint64_t ui = value >> 63; // extend sign to whole length
115 uint8_t majorType = ui & 0x20; // extract major type
116 ui ^= value; // complement negatives
117 return encode_number(encoder, ui, majorType);
118}
119
120CborError cbor_encode_simple_value(CborEncoder *encoder, uint8_t value)
121{
122#ifndef CBOR_ENCODER_NO_CHECK_USER
123 // check if this is a valid simple type
124 if (value >= HalfPrecisionFloat && value <= Break)
125 return CborErrorIllegalSimpleType;
126#endif
127 return encode_number(encoder, value, SimpleTypesType << MajorTypeShift);
128}
129
130CborError cbor_encode_half_float(CborEncoder *encoder, const void *value)
131{
132 char buf[1 + sizeof(uint16_t)] = { CborHalfFloatType };
133 put16(buf + 1, *(const uint16_t*)value);
134 return append_to_buffer(encoder, buf, sizeof(buf));
135}
136
137CborError cbor_encode_float(CborEncoder *encoder, const float *value)
138{
139 char buf[1 + sizeof(uint32_t)] = { CborFloatType };
140 put32(buf + 1, *(const uint32_t*)value);
141 return append_to_buffer(encoder, buf, sizeof(buf));
142}
143
144CborError cbor_encode_double(CborEncoder *encoder, const double *value)
145{
146 char buf[1 + sizeof(uint64_t)] = { CborDoubleType };
147 put64(buf + 1, *(const uint64_t*)value);
148 return append_to_buffer(encoder, buf, sizeof(buf));
149}
Thiago Macieira8f98a112015-05-08 17:25:29 -0700150
151CborError cbor_encode_tag(CborEncoder *encoder, CborTag tag)
152{
153 return encode_number(encoder, tag, TagType << MajorTypeShift);
154}
Thiago Macieirab54debe2015-05-08 17:42:39 -0700155
156static CborError encode_string(CborEncoder *encoder, size_t length, uint8_t shiftedMajorType, const char *string)
157{
158 CborError err = encode_number(encoder, length, shiftedMajorType);
159 if (err)
160 return err;
161 return append_to_buffer(encoder, string, length);
162}
163
164CborError cbor_encode_byte_string(CborEncoder *encoder, const char *string, size_t length)
165{
166 return encode_string(encoder, length, ByteStringType << MajorTypeShift, string);
167}
168
169CborError cbor_encode_text_string(CborEncoder *encoder, const char *string, size_t length)
170{
171 return encode_string(encoder, length, TextStringType << MajorTypeShift, string);
172}
Thiago Macieira355817e2015-05-08 18:38:18 -0700173
174static CborError create_container(CborEncoder *encoder, size_t length, uint8_t shiftedMajorType, CborEncoder *container)
175{
Thiago Macieira8f7bd9e2015-05-12 13:37:46 +0900176 CborError err;
177 if (length == CborIndefiniteLength)
178 err = append_byte_to_buffer(encoder, shiftedMajorType + IndefiniteLength);
179 else
180 err = encode_number(encoder, length, shiftedMajorType);
Thiago Macieira355817e2015-05-08 18:38:18 -0700181 if (err)
182 return err;
Thiago Macieira8f7bd9e2015-05-12 13:37:46 +0900183
Thiago Macieira355817e2015-05-08 18:38:18 -0700184 *container = *encoder;
Thiago Macieira8f7bd9e2015-05-12 13:37:46 +0900185 container->flags = length == CborIndefiniteLength ? CborIteratorFlag_UnknownLength : 0;
Thiago Macieira355817e2015-05-08 18:38:18 -0700186 return CborNoError;
187}
188
189CborError cbor_encoder_create_array(CborEncoder *encoder, CborEncoder *arrayEncoder, size_t length)
190{
191 return create_container(encoder, length, ArrayType << MajorTypeShift, arrayEncoder);
192}
193
194CborError cbor_encoder_create_map(CborEncoder *encoder, CborEncoder *mapEncoder, size_t length)
195{
196 return create_container(encoder, length, MapType << MajorTypeShift, mapEncoder);
197}
198
199CborError cbor_encoder_close_container(CborEncoder *encoder, const CborEncoder *containerEncoder)
200{
Thiago Macieira8f7bd9e2015-05-12 13:37:46 +0900201 encoder->ptr = containerEncoder->ptr;
202 if (containerEncoder->flags & CborIteratorFlag_UnknownLength)
203 return append_byte_to_buffer(encoder, BreakByte);
Thiago Macieira355817e2015-05-08 18:38:18 -0700204 return CborNoError;
205}