1 /*
2 * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <stddef.h>
8 #include <string.h>
9 #include <qcbor/qcbor_decode.h>
10 #include "cbor_dump.h"
11
12 /* Dump context structure */
13 struct dump_context
14 {
15 FILE *outfile;
16 unsigned int initial_indent;
17 const char *root_label;
18 const struct cbor_dictionary_entry *dictionary;
19 unsigned int dictionary_len;
20 };
21
22 static int dump_next_item(QCBORDecodeContext *decode_ctx, struct dump_context *dump_ctx);
23 static void dump_indent(struct dump_context *dump_ctx, const QCBORItem *item);
24 static void dump_label(struct dump_context *dump_ctx, const QCBORItem *item);
25 static void dump_value_separator(struct dump_context *dump_ctx, const QCBORItem *item);
26 static void dump_value(struct dump_context *dump_ctx, const QCBORItem *item);
27 static void dump_text_string(struct dump_context *dump_ctx, const char *data, size_t len);
28 static void dump_byte_string(struct dump_context *dump_ctx, const uint8_t *data, size_t len);
29 static const char *dictionary_lookup(struct dump_context *dump_ctx, int64_t id);
30
cbor_dump(FILE * file,const uint8_t * cbor,size_t cbor_len,unsigned int indent,const char * root_label,const struct cbor_dictionary_entry * dictionary,unsigned int dictionary_len)31 int cbor_dump(FILE *file,
32 const uint8_t *cbor, size_t cbor_len,
33 unsigned int indent, const char *root_label,
34 const struct cbor_dictionary_entry *dictionary, unsigned int dictionary_len)
35 {
36 int status = -1;
37 UsefulBufC cbor_buf;
38 UsefulBuf mem_pool;
39 uint8_t mem_pool_space[cbor_len + QCBOR_DECODE_MIN_MEM_POOL_SIZE];
40
41 cbor_buf.ptr = cbor;
42 cbor_buf.len = cbor_len;
43
44 mem_pool.ptr = mem_pool_space;
45 mem_pool.len = sizeof(mem_pool_space);
46
47 QCBORDecodeContext decode_ctx;
48
49 QCBORDecode_Init(&decode_ctx, cbor_buf, QCBOR_DECODE_MODE_NORMAL);
50 status = QCBORDecode_SetMemPool(&decode_ctx, mem_pool, true);
51
52 if (status == QCBOR_SUCCESS) {
53
54 struct dump_context dump_ctx;
55
56 dump_ctx.outfile = file;
57 dump_ctx.initial_indent = indent;
58 dump_ctx.root_label = root_label;
59 dump_ctx.dictionary = dictionary;
60 dump_ctx.dictionary_len = dictionary_len;
61
62 while ((status = dump_next_item(&decode_ctx, &dump_ctx)) == QCBOR_SUCCESS);
63
64 // Hitting the end of data is not an error.
65 if (status == QCBOR_ERR_NO_MORE_ITEMS)
66 status=QCBOR_SUCCESS;
67 }
68
69 return status;
70 }
71
dump_next_item(QCBORDecodeContext * decode_ctx,struct dump_context * dump_ctx)72 static int dump_next_item(QCBORDecodeContext *decode_ctx, struct dump_context *dump_ctx)
73 {
74 int status = -1;
75 QCBORItem item;
76
77 status = QCBORDecode_GetNext(decode_ctx, &item);
78
79 if (status == QCBOR_SUCCESS) {
80
81 dump_indent(dump_ctx, &item);
82 dump_label(dump_ctx, &item);
83 dump_value_separator(dump_ctx, &item);
84 dump_value(dump_ctx, &item);
85 }
86
87 return status;
88 }
89
dump_indent(struct dump_context * dump_ctx,const QCBORItem * item)90 static void dump_indent(struct dump_context *dump_ctx, const QCBORItem *item)
91 {
92 unsigned int num_tabs = dump_ctx->initial_indent + item->uNestingLevel;
93
94 for (unsigned int i = 0; i < num_tabs; ++i) {
95
96 fprintf(dump_ctx->outfile, " ");
97 }
98 }
99
dump_label(struct dump_context * dump_ctx,const QCBORItem * item)100 static void dump_label(struct dump_context *dump_ctx, const QCBORItem *item)
101 {
102 switch (item->uLabelType)
103 {
104 case QCBOR_TYPE_INT64:
105 case QCBOR_TYPE_UINT64:
106 {
107 const char *label_string = dictionary_lookup(dump_ctx, item->label.int64);
108 if (label_string)
109 fprintf(dump_ctx->outfile, "%s:", label_string);
110 else
111 fprintf(dump_ctx->outfile, "%ld:", item->label.int64);
112 break;
113 }
114 case QCBOR_TYPE_TEXT_STRING:
115 fprintf(dump_ctx->outfile, "%s:", (const char*)item->label.string.ptr);
116 break;
117 case QCBOR_TYPE_NONE:
118 if (item->uNestingLevel == 0 && dump_ctx->root_label) {
119 fprintf(dump_ctx->outfile, "%s:", dump_ctx->root_label);
120 }
121 break;
122 default:
123 break;
124 }
125 }
126
dump_value_separator(struct dump_context * dump_ctx,const QCBORItem * item)127 static void dump_value_separator(struct dump_context *dump_ctx, const QCBORItem *item)
128 {
129 if ((item->uDataType == QCBOR_TYPE_ARRAY) ||
130 (item->uDataType == QCBOR_TYPE_MAP)) {
131
132 fprintf(dump_ctx->outfile, "\n");
133 }
134 else {
135
136 fprintf(dump_ctx->outfile, "\t");
137 }
138
139 }
140
dump_value(struct dump_context * dump_ctx,const QCBORItem * item)141 static void dump_value(struct dump_context *dump_ctx, const QCBORItem *item)
142 {
143 if (item->uDataType == QCBOR_TYPE_TEXT_STRING) {
144
145 dump_text_string(dump_ctx, (const char*)item->val.string.ptr, item->val.string.len);
146 fprintf(dump_ctx->outfile, "\n");
147 }
148 else if (item->uDataType == QCBOR_TYPE_BYTE_STRING) {
149
150 dump_byte_string(dump_ctx, (const uint8_t*)item->val.string.ptr, item->val.string.len);
151 fprintf(dump_ctx->outfile, "\n");
152 }
153 else if (item->uDataType == QCBOR_TYPE_INT64) {
154
155 fprintf(dump_ctx->outfile, "%ld\n", item->val.int64);
156 }
157 else if (item->uDataType == QCBOR_TYPE_UINT64) {
158
159 fprintf(dump_ctx->outfile, "%lu\n", item->val.uint64);
160 }
161 else if ((item->uDataType != QCBOR_TYPE_NONE) &&
162 (item->uDataType != QCBOR_TYPE_ARRAY) &&
163 (item->uDataType != QCBOR_TYPE_MAP))
164 {
165
166 fprintf(dump_ctx->outfile, "value %d", item->uDataType);
167 }
168 }
169
dump_text_string(struct dump_context * dump_ctx,const char * data,size_t len)170 static void dump_text_string(struct dump_context *dump_ctx, const char *data, size_t len)
171 {
172 char text_buf[len + 1];
173
174 memcpy(text_buf, data, len);
175 text_buf[len] = '\0';
176
177 fprintf(dump_ctx->outfile, "%s", text_buf);
178 }
179
dump_byte_string(struct dump_context * dump_ctx,const uint8_t * data,size_t len)180 static void dump_byte_string(struct dump_context *dump_ctx, const uint8_t *data, size_t len)
181 {
182 for (size_t i = 0; i < len; ++i) {
183
184 fprintf(dump_ctx->outfile, "%02x ", data[i]);
185 }
186 }
187
dictionary_lookup(struct dump_context * dump_ctx,int64_t id)188 static const char *dictionary_lookup(struct dump_context *dump_ctx, int64_t id)
189 {
190 const char *match = NULL;
191
192 if (dump_ctx->dictionary) {
193
194 for (size_t i = 0; i < dump_ctx->dictionary_len; ++i) {
195
196 if (dump_ctx->dictionary[i].id == id) {
197
198 match = dump_ctx->dictionary[i].string;
199 break;
200 }
201 }
202 }
203
204 return match;
205 }
206