/src/strongswan/src/libcharon/plugins/vici/vici_message.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2015 Tobias Brunner |
3 | | * Copyright (C) 2014 Martin Willi |
4 | | * |
5 | | * Copyright (C) secunet Security Networks AG |
6 | | * |
7 | | * This program is free software; you can redistribute it and/or modify it |
8 | | * under the terms of the GNU General Public License as published by the |
9 | | * Free Software Foundation; either version 2 of the License, or (at your |
10 | | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. |
11 | | * |
12 | | * This program is distributed in the hope that it will be useful, but |
13 | | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
14 | | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
15 | | * for more details. |
16 | | */ |
17 | | |
18 | | #include "vici_message.h" |
19 | | #include "vici_builder.h" |
20 | | |
21 | | #include <bio/bio_reader.h> |
22 | | #include <bio/bio_writer.h> |
23 | | |
24 | | #include <errno.h> |
25 | | |
26 | | typedef struct private_vici_message_t private_vici_message_t; |
27 | | |
28 | | /** |
29 | | * Private data of an vici_message_t object. |
30 | | */ |
31 | | struct private_vici_message_t { |
32 | | |
33 | | /** |
34 | | * Public vici_message_t interface. |
35 | | */ |
36 | | vici_message_t public; |
37 | | |
38 | | /** |
39 | | * Message encoding |
40 | | */ |
41 | | chunk_t encoding; |
42 | | |
43 | | /** |
44 | | * Free encoding during destruction? |
45 | | */ |
46 | | bool cleanup; |
47 | | |
48 | | /** |
49 | | * Allocated strings we maintain for get_str() |
50 | | */ |
51 | | linked_list_t *strings; |
52 | | }; |
53 | | |
54 | | ENUM(vici_type_names, VICI_START, VICI_END, |
55 | | "start", |
56 | | "section-start", |
57 | | "section-end", |
58 | | "key-value", |
59 | | "list-start", |
60 | | "list-item", |
61 | | "list-end", |
62 | | "end" |
63 | | ); |
64 | | |
65 | | /** |
66 | | * See header. |
67 | | */ |
68 | | bool vici_stringify(chunk_t chunk, char *buf, size_t size) |
69 | 463k | { |
70 | 463k | if (!chunk_printable(chunk, NULL, 0)) |
71 | 226 | { |
72 | 226 | return FALSE; |
73 | 226 | } |
74 | 463k | snprintf(buf, size, "%.*s", (int)chunk.len, chunk.ptr); |
75 | 463k | return TRUE; |
76 | 463k | } |
77 | | |
78 | | /** |
79 | | * See header. |
80 | | */ |
81 | | bool vici_verify_type(vici_type_t type, u_int section, bool list) |
82 | 518k | { |
83 | 518k | if (list) |
84 | 2.79k | { |
85 | 2.79k | if (type != VICI_LIST_END && type != VICI_LIST_ITEM) |
86 | 110 | { |
87 | 110 | DBG1(DBG_ENC, "'%N' within list", vici_type_names, type); |
88 | 110 | return FALSE; |
89 | 110 | } |
90 | 2.79k | } |
91 | 515k | else |
92 | 515k | { |
93 | 515k | if (type == VICI_LIST_ITEM || type == VICI_LIST_END) |
94 | 43 | { |
95 | 43 | DBG1(DBG_ENC, "'%N' outside list", vici_type_names, type); |
96 | 43 | return FALSE; |
97 | 43 | } |
98 | 515k | } |
99 | 518k | if (type == VICI_SECTION_END && section == 0) |
100 | 23 | { |
101 | 23 | DBG1(DBG_ENC, "'%N' outside of section", vici_type_names, type); |
102 | 23 | return FALSE; |
103 | 23 | } |
104 | 518k | if (type == VICI_END && section) |
105 | 71 | { |
106 | 71 | DBG1(DBG_ENC, "'%N' within section", vici_type_names, type); |
107 | 71 | return FALSE; |
108 | 71 | } |
109 | 518k | return TRUE; |
110 | 518k | } |
111 | | |
112 | | /** |
113 | | * Enumerator parsing message |
114 | | */ |
115 | | typedef struct { |
116 | | /* implements enumerator */ |
117 | | enumerator_t public; |
118 | | /** reader to parse from */ |
119 | | bio_reader_t *reader; |
120 | | /** section nesting level */ |
121 | | int section; |
122 | | /** currently parsing list? */ |
123 | | bool list; |
124 | | /** string currently enumerating */ |
125 | | char name[257]; |
126 | | } parse_enumerator_t; |
127 | | |
128 | | METHOD(enumerator_t, parse_enumerate, bool, |
129 | | parse_enumerator_t *this, va_list args) |
130 | 3.82M | { |
131 | 3.82M | vici_type_t *out; |
132 | 3.82M | chunk_t *value; |
133 | 3.82M | char **name; |
134 | 3.82M | uint8_t type; |
135 | 3.82M | chunk_t data; |
136 | | |
137 | 3.82M | VA_ARGS_VGET(args, out, name, value); |
138 | | |
139 | 3.82M | if (!this->reader->remaining(this->reader) || |
140 | 518k | !this->reader->read_uint8(this->reader, &type)) |
141 | 3.30M | { |
142 | 3.30M | *out = VICI_END; |
143 | 3.30M | return TRUE; |
144 | 3.30M | } |
145 | 518k | if (!vici_verify_type(type, this->section, this->list)) |
146 | 247 | { |
147 | 247 | return FALSE; |
148 | 247 | } |
149 | | |
150 | 518k | switch (type) |
151 | 518k | { |
152 | 452k | case VICI_SECTION_START: |
153 | 452k | if (!this->reader->read_data8(this->reader, &data) || |
154 | 452k | !vici_stringify(data, this->name, sizeof(this->name))) |
155 | 131 | { |
156 | 131 | DBG1(DBG_ENC, "invalid '%N' encoding", vici_type_names, type); |
157 | 131 | return FALSE; |
158 | 131 | } |
159 | 452k | *name = this->name; |
160 | 452k | this->section++; |
161 | 452k | break; |
162 | 48.7k | case VICI_SECTION_END: |
163 | 48.7k | this->section--; |
164 | 48.7k | break; |
165 | 9.97k | case VICI_KEY_VALUE: |
166 | 9.97k | if (!this->reader->read_data8(this->reader, &data) || |
167 | 9.91k | !vici_stringify(data, this->name, sizeof(this->name)) || |
168 | 9.79k | !this->reader->read_data16(this->reader, value)) |
169 | 283 | { |
170 | 283 | DBG1(DBG_ENC, "invalid '%N' encoding", vici_type_names, type); |
171 | 283 | return FALSE; |
172 | 283 | } |
173 | 9.69k | *name = this->name; |
174 | 9.69k | break; |
175 | 1.30k | case VICI_LIST_START: |
176 | 1.30k | if (!this->reader->read_data8(this->reader, &data) || |
177 | 1.27k | !vici_stringify(data, this->name, sizeof(this->name))) |
178 | 68 | { |
179 | 68 | DBG1(DBG_ENC, "invalid '%N' encoding", vici_type_names, type); |
180 | 68 | return FALSE; |
181 | 68 | } |
182 | 1.23k | *name = this->name; |
183 | 1.23k | this->list = TRUE; |
184 | 1.23k | break; |
185 | 1.64k | case VICI_LIST_ITEM: |
186 | 1.64k | if (!this->reader->read_data16(this->reader, value)) |
187 | 55 | { |
188 | 55 | DBG1(DBG_ENC, "invalid '%N' encoding", vici_type_names, type); |
189 | 55 | return FALSE; |
190 | 55 | } |
191 | 1.59k | break; |
192 | 1.59k | case VICI_LIST_END: |
193 | 1.03k | this->list = FALSE; |
194 | 1.03k | break; |
195 | 2.71k | case VICI_END: |
196 | 2.71k | break; |
197 | 378 | default: |
198 | 378 | DBG1(DBG_ENC, "unknown encoding type: %u", type); |
199 | 378 | return FALSE; |
200 | 518k | } |
201 | | |
202 | 517k | *out = type; |
203 | | |
204 | 517k | return TRUE; |
205 | 518k | } |
206 | | |
207 | | METHOD(enumerator_t, parse_destroy, void, |
208 | | parse_enumerator_t *this) |
209 | 3.22k | { |
210 | 3.22k | this->reader->destroy(this->reader); |
211 | 3.22k | free(this); |
212 | 3.22k | } |
213 | | |
214 | | METHOD(vici_message_t, create_enumerator, enumerator_t*, |
215 | | private_vici_message_t *this) |
216 | 3.22k | { |
217 | 3.22k | parse_enumerator_t *enumerator; |
218 | | |
219 | 3.22k | INIT(enumerator, |
220 | 3.22k | .public = { |
221 | 3.22k | .enumerate = enumerator_enumerate_default, |
222 | 3.22k | .venumerate = _parse_enumerate, |
223 | 3.22k | .destroy = _parse_destroy, |
224 | 3.22k | }, |
225 | 3.22k | .reader = bio_reader_create(this->encoding), |
226 | 3.22k | ); |
227 | | |
228 | 3.22k | return &enumerator->public; |
229 | 3.22k | } |
230 | | |
231 | | /** |
232 | | * Find a value for given vararg key |
233 | | */ |
234 | | static bool find_value(private_vici_message_t *this, chunk_t *value, |
235 | | char *fmt, va_list args) |
236 | 2.57k | { |
237 | 2.57k | enumerator_t *enumerator; |
238 | 2.57k | char buf[128], *name, *key, *dot, *next; |
239 | 2.57k | int section = 0, keysection = 0; |
240 | 2.57k | bool found = FALSE; |
241 | 2.57k | chunk_t current; |
242 | 2.57k | vici_type_t type; |
243 | | |
244 | 2.57k | vsnprintf(buf, sizeof(buf), fmt, args); |
245 | 2.57k | next = buf; |
246 | | |
247 | 2.57k | enumerator = create_enumerator(this); |
248 | | |
249 | | /* descent into section */ |
250 | 2.57k | while (TRUE) |
251 | 2.57k | { |
252 | 2.57k | dot = strchr(next, '.'); |
253 | 2.57k | if (!dot) |
254 | 2.57k | { |
255 | 2.57k | key = next; |
256 | 2.57k | break; |
257 | 2.57k | } |
258 | 0 | *dot = '\0'; |
259 | 0 | key = next; |
260 | 0 | next = dot + 1; |
261 | 0 | keysection++; |
262 | |
|
263 | 0 | while (enumerator->enumerate(enumerator, &type, &name, ¤t)) |
264 | 0 | { |
265 | 0 | switch (type) |
266 | 0 | { |
267 | 0 | case VICI_SECTION_START: |
268 | 0 | section++; |
269 | 0 | if (section == keysection && streq(name, key)) |
270 | 0 | { |
271 | 0 | break; |
272 | 0 | } |
273 | 0 | continue; |
274 | 0 | case VICI_SECTION_END: |
275 | 0 | section--; |
276 | 0 | continue; |
277 | 0 | case VICI_END: |
278 | 0 | break; |
279 | 0 | default: |
280 | 0 | continue; |
281 | 0 | } |
282 | 0 | break; |
283 | 0 | } |
284 | 0 | } |
285 | | |
286 | | /* find key/value in current section */ |
287 | 433k | while (enumerator->enumerate(enumerator, &type, &name, ¤t)) |
288 | 432k | { |
289 | 432k | switch (type) |
290 | 432k | { |
291 | 7.34k | case VICI_KEY_VALUE: |
292 | 7.34k | if (section == keysection && streq(key, name)) |
293 | 412 | { |
294 | 412 | *value = current; |
295 | 412 | found = TRUE; |
296 | 412 | break; |
297 | 412 | } |
298 | 6.93k | continue; |
299 | 383k | case VICI_SECTION_START: |
300 | 383k | section++; |
301 | 383k | continue; |
302 | 37.7k | case VICI_SECTION_END: |
303 | 37.7k | section--; |
304 | 37.7k | continue; |
305 | 1.31k | case VICI_END: |
306 | 1.31k | break; |
307 | 3.02k | default: |
308 | 3.02k | continue; |
309 | 432k | } |
310 | 1.72k | break; |
311 | 432k | } |
312 | | |
313 | 2.57k | enumerator->destroy(enumerator); |
314 | | |
315 | 2.57k | return found; |
316 | 2.57k | } |
317 | | |
318 | | METHOD(vici_message_t, vget_str, char*, |
319 | | private_vici_message_t *this, char *def, char *fmt, va_list args) |
320 | 644 | { |
321 | 644 | chunk_t value; |
322 | 644 | bool found; |
323 | 644 | char *str; |
324 | | |
325 | 644 | found = find_value(this, &value, fmt, args); |
326 | 644 | if (found) |
327 | 20 | { |
328 | 20 | if (chunk_printable(value, NULL, 0)) |
329 | 19 | { |
330 | 19 | str = strndup(value.ptr, value.len); |
331 | | /* keep a reference to string, so caller doesn't have to care */ |
332 | 19 | this->strings->insert_last(this->strings, str); |
333 | 19 | return str; |
334 | 19 | } |
335 | 20 | } |
336 | 625 | return def; |
337 | 644 | } |
338 | | |
339 | | METHOD(vici_message_t, get_str, char*, |
340 | | private_vici_message_t *this, char *def, char *fmt, ...) |
341 | 644 | { |
342 | 644 | va_list args; |
343 | 644 | char *str; |
344 | | |
345 | 644 | va_start(args, fmt); |
346 | 644 | str = vget_str(this, def, fmt, args); |
347 | 644 | va_end(args); |
348 | 644 | return str; |
349 | 644 | } |
350 | | |
351 | | METHOD(vici_message_t, vget_int, int, |
352 | | private_vici_message_t *this, int def, char *fmt, va_list args) |
353 | 644 | { |
354 | 644 | chunk_t value; |
355 | 644 | bool found; |
356 | 644 | char buf[32], *pos; |
357 | 644 | int ret; |
358 | | |
359 | 644 | found = find_value(this, &value, fmt, args); |
360 | 644 | if (found) |
361 | 68 | { |
362 | 68 | if (value.len == 0) |
363 | 39 | { |
364 | 39 | return def; |
365 | 39 | } |
366 | 29 | if (chunk_printable(value, NULL, 0)) |
367 | 4 | { |
368 | 4 | snprintf(buf, sizeof(buf), "%.*s", (int)value.len, value.ptr); |
369 | 4 | errno = 0; |
370 | 4 | ret = strtol(buf, &pos, 0); |
371 | 4 | if (errno == 0 && pos == buf + strlen(buf)) |
372 | 1 | { |
373 | 1 | return ret; |
374 | 1 | } |
375 | 4 | } |
376 | 29 | } |
377 | 604 | return def; |
378 | 644 | } |
379 | | |
380 | | METHOD(vici_message_t, get_int, int, |
381 | | private_vici_message_t *this, int def, char *fmt, ...) |
382 | 644 | { |
383 | 644 | va_list args; |
384 | 644 | int val; |
385 | | |
386 | 644 | va_start(args, fmt); |
387 | 644 | val = vget_int(this, def, fmt, args); |
388 | 644 | va_end(args); |
389 | 644 | return val; |
390 | 644 | } |
391 | | |
392 | | METHOD(vici_message_t, vget_bool, bool, |
393 | | private_vici_message_t *this, bool def, char *fmt, va_list args) |
394 | 644 | { |
395 | 644 | chunk_t value; |
396 | 644 | bool found; |
397 | 644 | char buf[16]; |
398 | | |
399 | 644 | found = find_value(this, &value, fmt, args); |
400 | 644 | if (found) |
401 | 288 | { |
402 | 288 | if (value.len == 0) |
403 | 39 | { |
404 | 39 | return def; |
405 | 39 | } |
406 | 249 | if (chunk_printable(value, NULL, 0)) |
407 | 230 | { |
408 | 230 | snprintf(buf, sizeof(buf), "%.*s", (int)value.len, value.ptr); |
409 | 230 | return settings_value_as_bool(buf, def); |
410 | 230 | } |
411 | 249 | } |
412 | 375 | return def; |
413 | 644 | } |
414 | | |
415 | | METHOD(vici_message_t, get_bool, bool, |
416 | | private_vici_message_t *this, bool def, char *fmt, ...) |
417 | 644 | { |
418 | 644 | va_list args; |
419 | 644 | bool val; |
420 | | |
421 | 644 | va_start(args, fmt); |
422 | 644 | val = vget_bool(this, def, fmt, args); |
423 | 644 | va_end(args); |
424 | 644 | return val; |
425 | 644 | } |
426 | | |
427 | | METHOD(vici_message_t, vget_value, chunk_t, |
428 | | private_vici_message_t *this, chunk_t def, char *fmt, va_list args) |
429 | 644 | { |
430 | 644 | chunk_t value; |
431 | 644 | bool found; |
432 | | |
433 | 644 | found = find_value(this, &value, fmt, args); |
434 | 644 | if (found) |
435 | 36 | { |
436 | 36 | return value; |
437 | 36 | } |
438 | 608 | return def; |
439 | 644 | } |
440 | | |
441 | | METHOD(vici_message_t, get_value, chunk_t, |
442 | | private_vici_message_t *this, chunk_t def, char *fmt, ...) |
443 | 644 | { |
444 | 644 | va_list args; |
445 | 644 | chunk_t value; |
446 | | |
447 | 644 | va_start(args, fmt); |
448 | 644 | value = vget_value(this, def, fmt, args); |
449 | 644 | va_end(args); |
450 | 644 | return value; |
451 | 644 | } |
452 | | |
453 | | METHOD(vici_message_t, get_encoding, chunk_t, |
454 | | private_vici_message_t *this) |
455 | 0 | { |
456 | 0 | return this->encoding; |
457 | 0 | } |
458 | | |
459 | | /** |
460 | | * Private parse context data |
461 | | */ |
462 | | struct vici_parse_context_t { |
463 | | /** current section nesting level */ |
464 | | int level; |
465 | | /** parse enumerator */ |
466 | | enumerator_t *e; |
467 | | }; |
468 | | |
469 | | METHOD(vici_message_t, parse, bool, |
470 | | private_vici_message_t *this, vici_parse_context_t *ctx, |
471 | | vici_section_cb_t section, vici_value_cb_t kv, vici_value_cb_t li, |
472 | | void *user) |
473 | 0 | { |
474 | 0 | vici_parse_context_t root = {}; |
475 | 0 | char *name, *list = NULL; |
476 | 0 | vici_type_t type; |
477 | 0 | chunk_t value; |
478 | 0 | int base; |
479 | 0 | bool ok = TRUE; |
480 | |
|
481 | 0 | if (!ctx) |
482 | 0 | { |
483 | 0 | ctx = &root; |
484 | 0 | root.e = create_enumerator(this); |
485 | 0 | } |
486 | |
|
487 | 0 | base = ctx->level; |
488 | |
|
489 | 0 | while (ok) |
490 | 0 | { |
491 | 0 | ok = ctx->e->enumerate(ctx->e, &type, &name, &value); |
492 | 0 | if (ok) |
493 | 0 | { |
494 | 0 | switch (type) |
495 | 0 | { |
496 | 0 | case VICI_START: |
497 | | /* should never occur */ |
498 | 0 | continue; |
499 | 0 | case VICI_KEY_VALUE: |
500 | 0 | if (ctx->level == base && kv) |
501 | 0 | { |
502 | 0 | name = strdup(name); |
503 | 0 | this->strings->insert_last(this->strings, name); |
504 | 0 | ok = kv(user, &this->public, name, value); |
505 | 0 | } |
506 | 0 | continue; |
507 | 0 | case VICI_LIST_START: |
508 | 0 | if (ctx->level == base) |
509 | 0 | { |
510 | 0 | list = strdup(name); |
511 | 0 | this->strings->insert_last(this->strings, list); |
512 | 0 | } |
513 | 0 | continue; |
514 | 0 | case VICI_LIST_ITEM: |
515 | 0 | if (list && li) |
516 | 0 | { |
517 | 0 | name = strdup(name); |
518 | 0 | this->strings->insert_last(this->strings, name); |
519 | 0 | ok = li(user, &this->public, list, value); |
520 | 0 | } |
521 | 0 | continue; |
522 | 0 | case VICI_LIST_END: |
523 | 0 | if (ctx->level == base) |
524 | 0 | { |
525 | 0 | list = NULL; |
526 | 0 | } |
527 | 0 | continue; |
528 | 0 | case VICI_SECTION_START: |
529 | 0 | if (ctx->level++ == base && section) |
530 | 0 | { |
531 | 0 | name = strdup(name); |
532 | 0 | this->strings->insert_last(this->strings, name); |
533 | 0 | ok = section(user, &this->public, ctx, name); |
534 | 0 | } |
535 | 0 | continue; |
536 | 0 | case VICI_SECTION_END: |
537 | 0 | if (ctx->level-- == base) |
538 | 0 | { |
539 | 0 | break; |
540 | 0 | } |
541 | 0 | continue; |
542 | 0 | case VICI_END: |
543 | 0 | break; |
544 | 0 | } |
545 | 0 | } |
546 | 0 | break; |
547 | 0 | } |
548 | | |
549 | 0 | if (ctx == &root) |
550 | 0 | { |
551 | 0 | root.e->destroy(root.e); |
552 | 0 | } |
553 | 0 | return ok; |
554 | 0 | } |
555 | | |
556 | | METHOD(vici_message_t, dump, bool, |
557 | | private_vici_message_t *this, char *label, bool pretty, FILE *out) |
558 | 0 | { |
559 | 0 | enumerator_t *enumerator; |
560 | 0 | int ident = 0, delta; |
561 | 0 | vici_type_t type, last_type = VICI_START; |
562 | 0 | char *name, *term, *sep, *separ, *assign; |
563 | 0 | chunk_t value; |
564 | | |
565 | | /* pretty print uses indentation on multiple lines */ |
566 | 0 | if (pretty) |
567 | 0 | { |
568 | 0 | delta = 2; |
569 | 0 | term = "\n"; |
570 | 0 | separ = ""; |
571 | 0 | assign = " = "; |
572 | 0 | } |
573 | 0 | else |
574 | 0 | { |
575 | 0 | delta = 0; |
576 | 0 | term = ""; |
577 | 0 | separ = " "; |
578 | 0 | assign = "="; |
579 | 0 | } |
580 | |
|
581 | 0 | fprintf(out, "%s {%s", label, term); |
582 | 0 | ident += delta; |
583 | |
|
584 | 0 | enumerator = create_enumerator(this); |
585 | 0 | while (enumerator->enumerate(enumerator, &type, &name, &value)) |
586 | 0 | { |
587 | 0 | switch (type) |
588 | 0 | { |
589 | 0 | case VICI_START: |
590 | | /* should never occur */ |
591 | 0 | break; |
592 | 0 | case VICI_SECTION_START: |
593 | 0 | sep = (last_type != VICI_SECTION_START && |
594 | 0 | last_type != VICI_START) ? separ : ""; |
595 | 0 | fprintf(out, "%*s%s%s {%s", ident, "", sep, name, term); |
596 | 0 | ident += delta; |
597 | 0 | break; |
598 | 0 | case VICI_SECTION_END: |
599 | 0 | ident -= delta; |
600 | 0 | fprintf(out, "%*s}%s", ident, "", term); |
601 | 0 | break; |
602 | 0 | case VICI_KEY_VALUE: |
603 | 0 | sep = (last_type != VICI_SECTION_START && |
604 | 0 | last_type != VICI_START) ? separ : ""; |
605 | 0 | if (chunk_printable(value, NULL, ' ')) |
606 | 0 | { |
607 | 0 | fprintf(out, "%*s%s%s%s%.*s%s", ident, "", sep, name, |
608 | 0 | assign, (int)value.len, value.ptr, term); |
609 | 0 | } |
610 | 0 | else |
611 | 0 | { |
612 | 0 | fprintf(out, "%*s%s%s%s0x%+#B%s", ident, "", sep, name, |
613 | 0 | assign, &value, term); |
614 | 0 | } |
615 | 0 | break; |
616 | 0 | case VICI_LIST_START: |
617 | 0 | sep = (last_type != VICI_SECTION_START && |
618 | 0 | last_type != VICI_START) ? separ : ""; |
619 | 0 | fprintf(out, "%*s%s%s%s[%s", ident, "", sep, name, assign, term); |
620 | 0 | ident += delta; |
621 | 0 | break; |
622 | 0 | case VICI_LIST_END: |
623 | 0 | ident -= delta; |
624 | 0 | fprintf(out, "%*s]%s", ident, "", term); |
625 | 0 | break; |
626 | 0 | case VICI_LIST_ITEM: |
627 | 0 | sep = (last_type != VICI_LIST_START) ? separ : ""; |
628 | 0 | if (chunk_printable(value, NULL, ' ')) |
629 | 0 | { |
630 | 0 | fprintf(out, "%*s%s%.*s%s", ident, "", sep, |
631 | 0 | (int)value.len, value.ptr, term); |
632 | 0 | } |
633 | 0 | else |
634 | 0 | { |
635 | 0 | fprintf(out, "%*s%s0x%+#B%s", ident, "", sep, |
636 | 0 | &value, term); |
637 | 0 | } |
638 | 0 | break; |
639 | 0 | case VICI_END: |
640 | 0 | fprintf(out, "}\n"); |
641 | 0 | enumerator->destroy(enumerator); |
642 | 0 | return TRUE; |
643 | 0 | } |
644 | 0 | last_type = type; |
645 | 0 | } |
646 | 0 | enumerator->destroy(enumerator); |
647 | 0 | return FALSE; |
648 | 0 | } |
649 | | |
650 | | CALLBACK(clear_strings, void, |
651 | | char *str) |
652 | 19 | { |
653 | 19 | memwipe(str, strlen(str)); |
654 | 19 | free(str); |
655 | 19 | } |
656 | | |
657 | | METHOD(vici_message_t, destroy, void, |
658 | | private_vici_message_t *this) |
659 | 644 | { |
660 | 644 | if (this->cleanup) |
661 | 0 | { |
662 | 0 | chunk_clear(&this->encoding); |
663 | 0 | } |
664 | 644 | this->strings->destroy_function(this->strings, clear_strings); |
665 | 644 | free(this); |
666 | 644 | } |
667 | | |
668 | | /** |
669 | | * See header |
670 | | */ |
671 | | vici_message_t *vici_message_create_from_data(chunk_t data, bool cleanup) |
672 | 644 | { |
673 | 644 | private_vici_message_t *this; |
674 | | |
675 | 644 | INIT(this, |
676 | 644 | .public = { |
677 | 644 | .create_enumerator = _create_enumerator, |
678 | 644 | .get_str = _get_str, |
679 | 644 | .vget_str = _vget_str, |
680 | 644 | .get_int = _get_int, |
681 | 644 | .vget_int = _vget_int, |
682 | 644 | .get_bool = _get_bool, |
683 | 644 | .vget_bool = _vget_bool, |
684 | 644 | .get_value = _get_value, |
685 | 644 | .vget_value = _vget_value, |
686 | 644 | .get_encoding = _get_encoding, |
687 | 644 | .parse = _parse, |
688 | 644 | .dump = _dump, |
689 | 644 | .destroy = _destroy, |
690 | 644 | }, |
691 | 644 | .strings = linked_list_create(), |
692 | 644 | .encoding = data, |
693 | 644 | .cleanup = cleanup, |
694 | 644 | ); |
695 | | |
696 | 644 | return &this->public; |
697 | 644 | } |
698 | | |
699 | | /** |
700 | | * See header |
701 | | */ |
702 | | vici_message_t *vici_message_create_from_enumerator(enumerator_t *enumerator) |
703 | 0 | { |
704 | 0 | vici_builder_t *builder; |
705 | 0 | vici_type_t type; |
706 | 0 | char *name; |
707 | 0 | chunk_t value; |
708 | |
|
709 | 0 | builder = vici_builder_create(); |
710 | 0 | while (enumerator->enumerate(enumerator, &type, &name, &value)) |
711 | 0 | { |
712 | 0 | switch (type) |
713 | 0 | { |
714 | 0 | case VICI_SECTION_START: |
715 | 0 | case VICI_LIST_START: |
716 | 0 | builder->add(builder, type, name); |
717 | 0 | continue; |
718 | 0 | case VICI_KEY_VALUE: |
719 | 0 | builder->add(builder, type, name, value); |
720 | 0 | continue; |
721 | 0 | case VICI_LIST_ITEM: |
722 | 0 | builder->add(builder, type, value); |
723 | 0 | continue; |
724 | 0 | case VICI_SECTION_END: |
725 | 0 | case VICI_LIST_END: |
726 | 0 | default: |
727 | 0 | builder->add(builder, type); |
728 | 0 | continue; |
729 | 0 | case VICI_END: |
730 | 0 | break; |
731 | 0 | } |
732 | 0 | break; |
733 | 0 | } |
734 | 0 | enumerator->destroy(enumerator); |
735 | |
|
736 | 0 | return builder->finalize(builder); |
737 | 0 | } |
738 | | |
739 | | /** |
740 | | * See header |
741 | | */ |
742 | | vici_message_t *vici_message_create_from_args(vici_type_t type, ...) |
743 | 0 | { |
744 | 0 | vici_builder_t *builder; |
745 | 0 | va_list args; |
746 | 0 | char *name; |
747 | 0 | chunk_t value; |
748 | |
|
749 | 0 | builder = vici_builder_create(); |
750 | 0 | va_start(args, type); |
751 | 0 | while (type != VICI_END) |
752 | 0 | { |
753 | 0 | switch (type) |
754 | 0 | { |
755 | 0 | case VICI_LIST_START: |
756 | 0 | case VICI_SECTION_START: |
757 | 0 | name = va_arg(args, char*); |
758 | 0 | builder->add(builder, type, name); |
759 | 0 | break; |
760 | 0 | case VICI_KEY_VALUE: |
761 | 0 | name = va_arg(args, char*); |
762 | 0 | value = va_arg(args, chunk_t); |
763 | 0 | builder->add(builder, type, name, value); |
764 | 0 | break; |
765 | 0 | case VICI_LIST_ITEM: |
766 | 0 | value = va_arg(args, chunk_t); |
767 | 0 | builder->add(builder, type, value); |
768 | 0 | break; |
769 | 0 | case VICI_SECTION_END: |
770 | 0 | case VICI_LIST_END: |
771 | 0 | default: |
772 | 0 | builder->add(builder, type); |
773 | 0 | break; |
774 | 0 | } |
775 | 0 | type = va_arg(args, vici_type_t); |
776 | 0 | } |
777 | 0 | va_end(args); |
778 | 0 | return builder->finalize(builder); |
779 | 0 | } |