Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libxo/encoder/cbor/enc_cbor.c
48255 views
1
/*
2
* Copyright (c) 2015, Juniper Networks, Inc.
3
* All rights reserved.
4
* This SOFTWARE is licensed under the LICENSE provided in the
5
* ../Copyright file. By downloading, installing, copying, or otherwise
6
* using the SOFTWARE, you agree to be bound by the terms of that
7
* LICENSE.
8
* Phil Shafer, August 2015
9
*/
10
11
/*
12
* CBOR (RFC 7049) mades a suitable test case for libxo's external
13
* encoder API. It's simple, streaming, well documented, and an
14
* IETF standard.
15
*
16
* This encoder uses the "pretty" flag for diagnostics, which isn't
17
* really kosher, but it's example code.
18
*/
19
20
#include <string.h>
21
#include <sys/types.h>
22
#include <unistd.h>
23
#include <stdint.h>
24
#include <ctype.h>
25
#include <stdlib.h>
26
#include <limits.h>
27
28
#include "xo.h"
29
#include "xo_encoder.h"
30
#include "xo_buf.h"
31
32
/*
33
* memdump(): dump memory contents in hex/ascii
34
0 1 2 3 4 5 6 7
35
0123456789012345678901234567890123456789012345678901234567890123456789012345
36
XX XX XX XX XX XX XX XX - XX XX XX XX XX XX XX XX abcdefghijklmnop
37
*/
38
static void
39
cbor_memdump (FILE *fp, const char *title, const char *data,
40
size_t len, const char *tag, int indent)
41
{
42
enum { MAX_PER_LINE = 16 };
43
char buf[ 80 ];
44
char text[ 80 ];
45
char *bp, *tp;
46
size_t i;
47
#if 0
48
static const int ends[ MAX_PER_LINE ] = { 2, 5, 8, 11, 15, 18, 21, 24,
49
29, 32, 35, 38, 42, 45, 48, 51 };
50
#endif
51
52
if (fp == NULL)
53
fp = stdout;
54
if (tag == NULL)
55
tag = "";
56
57
fprintf(fp, "%*s[%s] @ %p (%lx/%lu)\n", indent + 1, tag,
58
title, data, (unsigned long) len, (unsigned long) len);
59
60
while (len > 0) {
61
bp = buf;
62
tp = text;
63
64
for (i = 0; i < MAX_PER_LINE && i < len; i++) {
65
if (i && (i % 4) == 0) *bp++ = ' ';
66
if (i == 8) {
67
*bp++ = '-';
68
*bp++ = ' ';
69
}
70
sprintf(bp, "%02x ", (unsigned char) *data);
71
bp += strlen(bp);
72
*tp++ = (isprint((int) *data) && *data >= ' ') ? *data : '.';
73
data += 1;
74
}
75
76
*tp = 0;
77
*bp = 0;
78
fprintf(fp, "%*s%-54s%s\n", indent + 1, tag, buf, text);
79
len -= i;
80
}
81
}
82
83
/*
84
* CBOR breaks the first byte into two pieces, the major type in the
85
* top 3 bits and the minor value in the low 5 bits. The value can be
86
* a small value (0 .. 23), an 8-bit value (24), a 16-bit value (25),
87
* a 32-bit value (26), or a 64-bit value (27). A value of 31
88
* represents an unknown length, which we'll use extensively for
89
* streaming our content.
90
*/
91
#define CBOR_MAJOR_MASK 0xE0
92
#define CBOR_MINOR_MASK 0x1F
93
#define CBOR_MAJOR_SHIFT 5
94
95
#define CBOR_MAJOR(_x) ((_x) & CBOR_MAJOR_MASK)
96
#define CBOR_MAJOR_VAL(_x) ((_x) << CBOR_MAJOR_SHIFT)
97
#define CBOR_MINOR_VAL(_x) ((_x) & CBOR_MINOR_MASK)
98
99
/* Major type codes */
100
#define CBOR_UNSIGNED CBOR_MAJOR_VAL(0) /* 0x00 */
101
#define CBOR_NEGATIVE CBOR_MAJOR_VAL(1) /* 0x20 */
102
#define CBOR_BYTES CBOR_MAJOR_VAL(2) /* 0x40 */
103
#define CBOR_STRING CBOR_MAJOR_VAL(3) /* 0x60 */
104
#define CBOR_ARRAY CBOR_MAJOR_VAL(4) /* 0x80 */
105
#define CBOR_MAP CBOR_MAJOR_VAL(5) /* 0xa0 */
106
#define CBOR_SEMANTIC CBOR_MAJOR_VAL(6) /* 0xc0 */
107
#define CBOR_SPECIAL CBOR_MAJOR_VAL(7) /* 0xe0 */
108
109
#define CBOR_ULIMIT 24 /* Largest unsigned value */
110
#define CBOR_NLIMIT 23 /* Largest negative value */
111
112
#define CBOR_BREAK 0xFF
113
#define CBOR_INDEF 0x1F
114
115
#define CBOR_FALSE 0xF4
116
#define CBOR_TRUE 0xF5
117
#define CBOR_NULL 0xF6
118
#define CBOR_UNDEF 0xF7
119
120
#define CBOR_LEN8 0x18 /* 24 - 8-bit value */
121
#define CBOR_LEN16 0x19 /* 25 - 16-bit value */
122
#define CBOR_LEN32 0x1a /* 26 - 32-bit value */
123
#define CBOR_LEN64 0x1b /* 27 - 64-bit value */
124
#define CBOR_LEN128 0x1c /* 28 - 128-bit value */
125
126
typedef struct cbor_private_s {
127
xo_buffer_t c_data; /* Our data buffer */
128
unsigned c_indent; /* Indent level */
129
unsigned c_open_leaf_list; /* Open leaf list construct? */
130
} cbor_private_t;
131
132
static void
133
cbor_encode_uint (xo_buffer_t *xbp, uint64_t minor, unsigned limit)
134
{
135
char *bp = xbp->xb_curp;
136
int i, m;
137
138
if (minor > (1ULL << 32)) {
139
*bp++ |= CBOR_LEN64;
140
m = 64;
141
142
} else if (minor > (1<<16)) {
143
*bp++ |= CBOR_LEN32;
144
m = 32;
145
146
} else if (minor > (1<<8)) {
147
*bp++ |= CBOR_LEN16;
148
m = 16;
149
150
} else if (minor > limit) {
151
*bp++ |= CBOR_LEN8;
152
m = 8;
153
} else {
154
*bp++ |= minor & CBOR_MINOR_MASK;
155
m = 0;
156
}
157
158
if (m) {
159
for (i = m - 8; i >= 0; i -= 8)
160
*bp++ = minor >> i;
161
}
162
163
xbp->xb_curp = bp;
164
}
165
166
static void
167
cbor_append (xo_handle_t *xop, cbor_private_t *cbor, xo_buffer_t *xbp,
168
unsigned major, unsigned minor, const char *data)
169
{
170
if (!xo_buf_has_room(xbp, minor + 2))
171
return;
172
173
unsigned offset = xo_buf_offset(xbp);
174
175
*xbp->xb_curp = major;
176
cbor_encode_uint(xbp, minor, CBOR_ULIMIT);
177
if (data)
178
xo_buf_append(xbp, data, minor);
179
180
if (xo_get_flags(xop) & XOF_PRETTY)
181
cbor_memdump(stdout, "append", xo_buf_data(xbp, offset),
182
xbp->xb_curp - xbp->xb_bufp - offset, "",
183
cbor->c_indent * 2);
184
}
185
186
static int
187
cbor_create (xo_handle_t *xop)
188
{
189
cbor_private_t *cbor = xo_realloc(NULL, sizeof(*cbor));
190
if (cbor == NULL)
191
return -1;
192
193
bzero(cbor, sizeof(*cbor));
194
xo_buf_init(&cbor->c_data);
195
196
xo_set_private(xop, cbor);
197
198
cbor_append(xop, cbor, &cbor->c_data, CBOR_MAP | CBOR_INDEF, 0, NULL);
199
200
return 0;
201
}
202
203
static int
204
cbor_content (xo_handle_t *xop, cbor_private_t *cbor, xo_buffer_t *xbp,
205
const char *value)
206
{
207
int rc = 0;
208
209
unsigned offset = xo_buf_offset(xbp);
210
211
if (value == NULL || *value == '\0' || xo_streq(value, "true"))
212
cbor_append(xop, cbor, &cbor->c_data, CBOR_TRUE, 0, NULL);
213
else if (xo_streq(value, "false"))
214
cbor_append(xop, cbor, &cbor->c_data, CBOR_FALSE, 0, NULL);
215
else {
216
int negative = 0;
217
if (*value == '-') {
218
value += 1;
219
negative = 1;
220
}
221
222
char *ep;
223
unsigned long long ival;
224
ival = strtoull(value, &ep, 0);
225
if (ival == ULLONG_MAX) /* Sometimes a string is just a string */
226
cbor_append(xop, cbor, xbp, CBOR_STRING, strlen(value), value);
227
else {
228
*xbp->xb_curp = negative ? CBOR_NEGATIVE : CBOR_UNSIGNED;
229
if (negative)
230
ival -= 1; /* Don't waste a negative zero */
231
cbor_encode_uint(xbp, ival, negative ? CBOR_NLIMIT : CBOR_ULIMIT);
232
}
233
}
234
235
if (xo_get_flags(xop) & XOF_PRETTY)
236
cbor_memdump(stdout, "content", xo_buf_data(xbp, offset),
237
xbp->xb_curp - xbp->xb_bufp - offset, "",
238
cbor->c_indent * 2);
239
240
return rc;
241
}
242
243
static int
244
cbor_handler (XO_ENCODER_HANDLER_ARGS)
245
{
246
int rc = 0;
247
cbor_private_t *cbor = private;
248
xo_buffer_t *xbp = cbor ? &cbor->c_data : NULL;
249
250
if (xo_get_flags(xop) & XOF_PRETTY) {
251
printf("%*sop %s: [%s] [%s]\n", cbor ? cbor->c_indent * 2 + 4 : 0, "",
252
xo_encoder_op_name(op), name, value);
253
fflush(stdout);
254
}
255
256
/* If we don't have private data, we're sunk */
257
if (cbor == NULL && op != XO_OP_CREATE)
258
return -1;
259
260
switch (op) {
261
case XO_OP_CREATE: /* Called when the handle is init'd */
262
rc = cbor_create(xop);
263
break;
264
265
case XO_OP_OPEN_CONTAINER:
266
cbor_append(xop, cbor, xbp, CBOR_STRING, strlen(name), name);
267
cbor_append(xop, cbor, xbp, CBOR_MAP | CBOR_INDEF, 0, NULL);
268
cbor->c_indent += 1;
269
break;
270
271
case XO_OP_CLOSE_CONTAINER:
272
cbor_append(xop, cbor, xbp, CBOR_BREAK, 0, NULL);
273
cbor->c_indent -= 1;
274
break;
275
276
case XO_OP_OPEN_LIST:
277
cbor_append(xop, cbor, xbp, CBOR_STRING, strlen(name), name);
278
cbor_append(xop, cbor, xbp, CBOR_ARRAY | CBOR_INDEF, 0, NULL);
279
cbor->c_indent += 1;
280
break;
281
282
case XO_OP_CLOSE_LIST:
283
cbor_append(xop, cbor, xbp, CBOR_BREAK, 0, NULL);
284
cbor->c_indent -= 1;
285
break;
286
287
case XO_OP_OPEN_LEAF_LIST:
288
cbor_append(xop, cbor, xbp, CBOR_STRING, strlen(name), name);
289
cbor_append(xop, cbor, xbp, CBOR_ARRAY | CBOR_INDEF, 0, NULL);
290
cbor->c_indent += 1;
291
cbor->c_open_leaf_list = 1;
292
break;
293
294
case XO_OP_CLOSE_LEAF_LIST:
295
cbor_append(xop, cbor, xbp, CBOR_BREAK, 0, NULL);
296
cbor->c_indent -= 1;
297
cbor->c_open_leaf_list = 0;
298
break;
299
300
case XO_OP_OPEN_INSTANCE:
301
cbor_append(xop, cbor, xbp, CBOR_MAP | CBOR_INDEF, 0, NULL);
302
cbor->c_indent += 1;
303
break;
304
305
case XO_OP_CLOSE_INSTANCE:
306
cbor_append(xop, cbor, xbp, CBOR_BREAK, 0, NULL);
307
cbor->c_indent -= 1;
308
break;
309
310
case XO_OP_STRING: /* Quoted UTF-8 string */
311
if (!cbor->c_open_leaf_list)
312
cbor_append(xop, cbor, xbp, CBOR_STRING, strlen(name), name);
313
cbor_append(xop, cbor, xbp, CBOR_STRING, strlen(value), value);
314
break;
315
316
case XO_OP_CONTENT: /* Other content */
317
if (!cbor->c_open_leaf_list)
318
cbor_append(xop, cbor, xbp, CBOR_STRING, strlen(name), name);
319
320
/*
321
* It's content, not string, so we need to look at the
322
* string and build some content. Turns out we only
323
* care about true, false, null, and numbers.
324
*/
325
cbor_content(xop, cbor, xbp, value);
326
break;
327
328
case XO_OP_FINISH: /* Clean up function */
329
cbor_append(xop, cbor, xbp, CBOR_BREAK, 0, NULL);
330
cbor->c_indent -= 1;
331
break;
332
333
case XO_OP_FLUSH: /* Clean up function */
334
if (xo_get_flags(xop) & XOF_PRETTY)
335
cbor_memdump(stdout, "cbor",
336
xbp->xb_bufp, xbp->xb_curp - xbp->xb_bufp,
337
">", 0);
338
else {
339
rc = write(1, xbp->xb_bufp, xbp->xb_curp - xbp->xb_bufp);
340
if (rc > 0)
341
rc = 0;
342
}
343
break;
344
345
case XO_OP_DESTROY: /* Clean up function */
346
break;
347
348
case XO_OP_ATTRIBUTE: /* Attribute name/value */
349
break;
350
351
case XO_OP_VERSION: /* Version string */
352
break;
353
354
}
355
356
return rc;
357
}
358
359
int
360
xo_encoder_library_init (XO_ENCODER_INIT_ARGS)
361
{
362
arg->xei_handler = cbor_handler;
363
arg->xei_version = XO_ENCODER_VERSION;
364
365
return 0;
366
}
367
368