blob: 679936221e0aac33ed62858ddb46af9a877ffe74 [file] [log] [blame]
Jim Schaada402ba12015-06-07 11:16:29 -07001#ifndef CN_PRINT_C
2#define CN_PRINT_C
Jim Schaad395ce052015-09-02 18:54:13 -07003#define CN_INCLUDE_DUMPER
Jim Schaada402ba12015-06-07 11:16:29 -07004#ifdef CN_INCLUDE_DUMPER
5#define _CRT_SECURE_NO_WARNINGS 1
6
7#include <stdio.h>
Jim Schaad395ce052015-09-02 18:54:13 -07008#include <stdio.h>
Jim Schaada402ba12015-06-07 11:16:29 -07009
10#ifdef __cplusplus
11extern "C" {
12#endif
13#ifdef EMACS_INDENTATION_HELPER
14} /* Duh. */
15#endif
16
17#include <stdio.h>
Jim Schaad395ce052015-09-02 18:54:13 -070018#ifdef MSV_CRT
Jim Schaada402ba12015-06-07 11:16:29 -070019#include <winsock2.h>
Jim Schaad395ce052015-09-02 18:54:13 -070020#else
21#define _snprintf snprintf
22#endif
Jim Schaada402ba12015-06-07 11:16:29 -070023#include <string.h>
24#include <stdbool.h>
25#include <assert.h>
26
27#include "cn-cbor/cn-cbor.h"
28#include "cbor.h"
29
30typedef struct _write_state
31{
32 char * rgbOutput;
33 ssize_t ib;
34 size_t cbLeft;
Jim Schaad395ce052015-09-02 18:54:13 -070035 uint8_t * rgFlags;
Jim Schaada402ba12015-06-07 11:16:29 -070036 const char * szIndentWith;
37 const char * szEndOfLine;
38} cn_write_state;
39
40typedef void(*cn_visit_func)(const cn_cbor *cb, int depth, void *context);
41extern void _visit(const cn_cbor *cb,
42 cn_visit_func visitor,
43 cn_visit_func breaker,
44 void *context);
45
46const char RgchHex[] = { '0', '1', '2', '3', '4', '5', '6', '7',
47'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
48
Jim Schaad395ce052015-09-02 18:54:13 -070049bool _isWritable(cn_write_state * ws, size_t cb)
Jim Schaada402ba12015-06-07 11:16:29 -070050{
51 if (ws->rgbOutput == NULL) return true;
52 if ((ws->ib < 0) || (ws->ib + cb > ws->cbLeft)) {
53 ws->ib = -1;
54 return false;
55 }
56 return true;
57}
58
Jim Schaad395ce052015-09-02 18:54:13 -070059void write_data(cn_write_state * ws, const char * sz, size_t cb)
Jim Schaada402ba12015-06-07 11:16:29 -070060{
61 if (_isWritable(ws, cb)) {
62 if (ws->rgbOutput != NULL) memcpy(ws->rgbOutput + ws->ib, sz, cb);
63 ws->ib += cb;
64 }
65}
66
Jim Schaad395ce052015-09-02 18:54:13 -070067void _doIndent(cn_write_state * ws, int depth)
Jim Schaada402ba12015-06-07 11:16:29 -070068{
69 int i;
70 char * sz = ws->rgbOutput + ws->ib;
71 size_t cbIndentWith = strlen(ws->szIndentWith);
72 int cbIndent = depth * cbIndentWith;
73
74
75 if (ws->rgbOutput == NULL) {
76 ws->ib += cbIndent;
77 return;
78 }
79
80 if (_isWritable(ws, cbIndent)) {
81 for (i = 0; i < depth; i++) {
82 memcpy(sz, ws->szIndentWith, cbIndentWith);
83 sz += cbIndentWith;
84 }
85 }
86
87 ws->ib += cbIndent;
88
89 return;
90}
91
92void _print_encoder(const cn_cbor * cb, int depth, void * context)
93{
94 int i;
95 char rgchT[256];
96 int cch;
97 cn_write_state * ws = (cn_write_state *)context;
Jim Schaad395ce052015-09-02 18:54:13 -070098 uint8_t flags = ws->rgFlags[depth];
Jim Schaada402ba12015-06-07 11:16:29 -070099
100 if (flags & 1) {
101 write_data(ws, ", ", 2);
102 ws->rgFlags[depth] &= 0xfe;
103
104 if (ws->szIndentWith) {
105 write_data(ws, ws->szEndOfLine, strlen(ws->szEndOfLine));
106 _doIndent(ws, depth);
107 }
108 }
109
110 if (flags & 2) {
111 write_data(ws, ": ", 2);
112 ws->rgFlags[depth] &= 0xfd;
113 }
114
115 switch (cb->type) {
Jim Schaad395ce052015-09-02 18:54:13 -0700116 case CN_CBOR_BYTES_CHUNKED:
117 case CN_CBOR_TEXT_CHUNKED:
118 break;
119
Jim Schaada402ba12015-06-07 11:16:29 -0700120 case CN_CBOR_ARRAY:
121 write_data(ws, "[", 1);
122 ws->rgFlags[depth] |= 4;
123
124 if (ws->szIndentWith) {
125 write_data(ws, ws->szEndOfLine, strlen(ws->szEndOfLine));
126 _doIndent(ws, depth + 1);
127 }
128 break;
129
130 case CN_CBOR_MAP:
131 write_data(ws, "{", 1);
132 ws->rgFlags[depth] |= 8;
133
134 if (ws->szIndentWith) {
135 write_data(ws, ws->szEndOfLine, strlen(ws->szEndOfLine));
136 _doIndent(ws, depth + 1);
137 }
138 break;
139
140 case CN_CBOR_TAG:
141 case CN_CBOR_UINT:
142 case CN_CBOR_SIMPLE:
Jim Schaad395ce052015-09-02 18:54:13 -0700143 cch = _snprintf(rgchT, sizeof(rgchT), "%u", (unsigned int) cb->v.uint);
Jim Schaada402ba12015-06-07 11:16:29 -0700144 write_data(ws, rgchT, cch);
145 break;
146
147 case CN_CBOR_FALSE:
148 write_data(ws, "false", 5);
149 break;
150
151 case CN_CBOR_TRUE:
152 write_data(ws, "true", 4);
153 break;
154
155 case CN_CBOR_NULL:
156 write_data(ws, "null", 4);
157 break;
158
159 case CN_CBOR_UNDEF:
160 write_data(ws, "undef", 5);
161 break;
162
163 case CN_CBOR_INT:
Jim Schaad395ce052015-09-02 18:54:13 -0700164 cch = _snprintf(rgchT, sizeof(rgchT), "%d", (unsigned int) cb->v.sint);
Jim Schaada402ba12015-06-07 11:16:29 -0700165 write_data(ws, rgchT, cch);
166 break;
167
Jim Schaad264684f2020-04-08 12:28:34 -0700168 case CN_CBOR_FLOAT:
169 cch = _snprintf(rgchT, sizeof(rgchT), "%f", cb->v.f);
170 write_data(ws, rgchT, cch);
171 break;
172
173 case CN_CBOR_DOUBLE:
Jim Schaada402ba12015-06-07 11:16:29 -0700174 cch = _snprintf(rgchT, sizeof(rgchT), "%f", cb->v.dbl);
175 write_data(ws, rgchT, cch);
176 break;
177
178 case CN_CBOR_INVALID:
179 write_data(ws, "invalid", 7);
180 break;
181
182 case CN_CBOR_TEXT:
183 write_data(ws, "\"", 1);
184 write_data(ws, cb->v.str, cb->length);
185 write_data(ws, "\"", 1);
186 break;
187
188 case CN_CBOR_BYTES:
189 write_data(ws, "h'", 2);
190 for (i = 0; i < cb->length; i++) {
191 write_data(ws, &RgchHex[(cb->v.str[i] / 16) & 0xf], 1);
192 write_data(ws, &RgchHex[cb->v.str[i] & 0xf], 1);
193 }
194 write_data(ws, "\'", 1);
195 break;
Jim Schaad264684f2020-04-08 12:28:34 -0700196
Jim Schaada402ba12015-06-07 11:16:29 -0700197 }
198
199 if (depth > 0) {
200 if (ws->rgFlags[depth - 1] & 4) ws->rgFlags[depth] |= 1;
201 else if (ws->rgFlags[depth - 1] & 8) {
202 if (flags & 2) ws->rgFlags[depth] |= 1;
203 else ws->rgFlags[depth] |= 2;
204 }
205 }
206}
207
208void _print_breaker(const cn_cbor * cb, int depth, void * context)
209{
210 cn_write_state * ws = (cn_write_state *)context;
211
212 switch (cb->type) {
213 case CN_CBOR_ARRAY:
214 if (ws->szIndentWith) {
215 write_data(ws, ws->szEndOfLine, strlen(ws->szEndOfLine));
216 _doIndent(ws, depth);
217 }
218
219 write_data(ws, "]", 1);
220 ws->rgFlags[depth + 1] = 0;
221 break;
222
223 case CN_CBOR_MAP:
224 if (ws->szIndentWith) {
225 write_data(ws, ws->szEndOfLine, strlen(ws->szEndOfLine));
226 _doIndent(ws, depth);
227 }
228
229 write_data(ws, "}", 1);
230 ws->rgFlags[depth + 1] = 0;
231 break;
Jim Schaad395ce052015-09-02 18:54:13 -0700232
233 default:
234 break;
Jim Schaada402ba12015-06-07 11:16:29 -0700235 }
236}
237
238ssize_t cn_cbor_printer_write(char * rgbBuffer, size_t cbBuffer, const cn_cbor * cb, const char * szIndentWith, const char * szEndOfLine)
239{
Jim Schaad395ce052015-09-02 18:54:13 -0700240 uint8_t flags[128] = { 0 };
Jim Schaada402ba12015-06-07 11:16:29 -0700241 char rgchZero[1] = { 0 };
242
243 cn_write_state ws = { rgbBuffer, 0, cbBuffer, flags, szIndentWith, szEndOfLine };
244 _visit(cb, _print_encoder, _print_breaker, &ws);
245 write_data(&ws, rgchZero, 1);
246
247 return ws.ib;
248}
249
250#ifdef EMACS_INDENTATION_HELPER
251{ /* Duh. */
252#endif
253#ifdef _cplusplus
254} /* extern "C" */
255#endif
256
257#endif // CN_INCLUDE_DUMPER
258#endif // CN_PRINT_C
Jim Schaad395ce052015-09-02 18:54:13 -0700259