blob: 0cfef7c8052fcaafac27d9c48b855bead592610d [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
69static inline CborError encode_number(CborEncoder *encoder, uint64_t ui, uint8_t shiftedMajorType)
70{
Thiago Macieiraafa4ff62015-05-09 10:09:55 -070071 /* Little-endian would have been so much more convenient here:
72 * We could just write at the beginning of buf but append_to_buffer
73 * only the necessary bytes.
74 * Since it has to be big endian, do it the other way around:
75 * write from the end. */
76 char buf[1 + sizeof(ui)];
77 char *const bufend = buf + sizeof(buf);
78 char *bufstart = bufend - 1;
79 put64(buf + 1, ui); // we probably have a bunch of zeros in the beginning
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070080
81 if (ui < Value8Bit) {
Thiago Macieiraafa4ff62015-05-09 10:09:55 -070082 *bufstart += shiftedMajorType;
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070083 } else {
Thiago Macieiraafa4ff62015-05-09 10:09:55 -070084 unsigned more = 0;
85 if (ui > UINT8_MAX)
86 ++more;
87 if (ui > UINT16_MAX)
88 ++more;
89 if (ui != (uint32_t)ui)
90 ++more;
91 bufstart -= 1 << more;
92 *bufstart = shiftedMajorType + Value8Bit + more;
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070093 }
94
Thiago Macieiraafa4ff62015-05-09 10:09:55 -070095 return append_to_buffer(encoder, bufstart, bufend - bufstart);
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070096}
97
98CborError cbor_encode_uint(CborEncoder *encoder, uint64_t value)
99{
100 return encode_number(encoder, value, UnsignedIntegerType << MajorTypeShift);
101}
102
103CborError cbor_encode_int(CborEncoder *encoder, int64_t value)
104{
105 // adapted from code in RFC 7049 appendix C (pseudocode)
106 uint64_t ui = value >> 63; // extend sign to whole length
107 uint8_t majorType = ui & 0x20; // extract major type
108 ui ^= value; // complement negatives
109 return encode_number(encoder, ui, majorType);
110}
111
112CborError cbor_encode_simple_value(CborEncoder *encoder, uint8_t value)
113{
114#ifndef CBOR_ENCODER_NO_CHECK_USER
115 // check if this is a valid simple type
116 if (value >= HalfPrecisionFloat && value <= Break)
117 return CborErrorIllegalSimpleType;
118#endif
119 return encode_number(encoder, value, SimpleTypesType << MajorTypeShift);
120}
121
122CborError cbor_encode_half_float(CborEncoder *encoder, const void *value)
123{
124 char buf[1 + sizeof(uint16_t)] = { CborHalfFloatType };
125 put16(buf + 1, *(const uint16_t*)value);
126 return append_to_buffer(encoder, buf, sizeof(buf));
127}
128
129CborError cbor_encode_float(CborEncoder *encoder, const float *value)
130{
131 char buf[1 + sizeof(uint32_t)] = { CborFloatType };
132 put32(buf + 1, *(const uint32_t*)value);
133 return append_to_buffer(encoder, buf, sizeof(buf));
134}
135
136CborError cbor_encode_double(CborEncoder *encoder, const double *value)
137{
138 char buf[1 + sizeof(uint64_t)] = { CborDoubleType };
139 put64(buf + 1, *(const uint64_t*)value);
140 return append_to_buffer(encoder, buf, sizeof(buf));
141}
Thiago Macieira8f98a112015-05-08 17:25:29 -0700142
143CborError cbor_encode_tag(CborEncoder *encoder, CborTag tag)
144{
145 return encode_number(encoder, tag, TagType << MajorTypeShift);
146}
Thiago Macieirab54debe2015-05-08 17:42:39 -0700147
148static CborError encode_string(CborEncoder *encoder, size_t length, uint8_t shiftedMajorType, const char *string)
149{
150 CborError err = encode_number(encoder, length, shiftedMajorType);
151 if (err)
152 return err;
153 return append_to_buffer(encoder, string, length);
154}
155
156CborError cbor_encode_byte_string(CborEncoder *encoder, const char *string, size_t length)
157{
158 return encode_string(encoder, length, ByteStringType << MajorTypeShift, string);
159}
160
161CborError cbor_encode_text_string(CborEncoder *encoder, const char *string, size_t length)
162{
163 return encode_string(encoder, length, TextStringType << MajorTypeShift, string);
164}
Thiago Macieira355817e2015-05-08 18:38:18 -0700165
166static CborError create_container(CborEncoder *encoder, size_t length, uint8_t shiftedMajorType, CborEncoder *container)
167{
168 CborError err = encode_number(encoder, length, shiftedMajorType);
169 if (err)
170 return err;
171 *container = *encoder;
172 return CborNoError;
173}
174
175CborError cbor_encoder_create_array(CborEncoder *encoder, CborEncoder *arrayEncoder, size_t length)
176{
177 return create_container(encoder, length, ArrayType << MajorTypeShift, arrayEncoder);
178}
179
180CborError cbor_encoder_create_map(CborEncoder *encoder, CborEncoder *mapEncoder, size_t length)
181{
182 return create_container(encoder, length, MapType << MajorTypeShift, mapEncoder);
183}
184
185CborError cbor_encoder_close_container(CborEncoder *encoder, const CborEncoder *containerEncoder)
186{
187 *encoder = *containerEncoder;
188 return CborNoError;
189}