1 /**
2 *
3 * getdns dict management functions, note that the internal storage is
4 * accomplished via an _getdns_rbtree_t
5 *
6 * Interfaces originally taken from the getdns API description pseudo implementation.
7 *
8 */
9
10 /*
11 * Copyright (c) 2013, NLnet Labs, Verisign, Inc.
12 * All rights reserved.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are met:
16 * * Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * * Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * * Neither the names of the copyright holders nor the
22 * names of its contributors may be used to endorse or promote products
23 * derived from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
27 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28 * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY
29 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
32 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 */
36
37 #include "config.h"
38 #include <ctype.h>
39 #ifndef USE_WINSOCK
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 #endif
45
46 #include "types-internal.h"
47 #include "util-internal.h"
48 #include "dict.h"
49 #include "list.h"
50 #include "rr-dict.h"
51 #include "const-info.h"
52 #include "gldns/gbuffer.h"
53 #include "gldns/wire2str.h"
54 #include "gldns/parseutil.h"
55
56
_json_ptr_first(const struct mem_funcs * mf,const char * jptr,char * first,ssize_t first_sz)57 static char *_json_ptr_first(const struct mem_funcs *mf,
58 const char *jptr, char *first, ssize_t first_sz)
59 {
60 const char *next_ref, *k;
61 char *j;
62
63 if (*jptr != '/')
64 return (char *)jptr;
65 jptr++;
66 if (!(next_ref = strchr(jptr, '/')))
67 next_ref = strchr(jptr, '\0');
68
69 if ((ssize_t)(next_ref - jptr + 1) > first_sz || !first)
70 first = GETDNS_XMALLOC(*mf, char, next_ref - jptr + 1);
71
72 for (j = first, k = jptr; k < next_ref; j++, k++)
73 *j = k[0] == '~' && k[1] == '1' ? (k++, '/') : *k;
74 *j = '\0';
75 for (j = first, k = first; *k; j++, k++)
76 *j = k[0] == '~' && k[1] == '0' ? (k++, '~') : *k;
77 *j = '\0';
78
79 return first;
80 }
81
82
83 static struct getdns_dict_item *
_find_dict_item(const getdns_dict * dict,const char * jptr)84 _find_dict_item(const getdns_dict *dict, const char *jptr)
85 {
86 char first_spc[1024], *first;
87 struct getdns_dict_item *d;
88
89 first = _json_ptr_first(&dict->mf, jptr,
90 first_spc, sizeof(first_spc));
91
92 d = (struct getdns_dict_item *) _getdns_rbtree_search(
93 (_getdns_rbtree_t *)&(dict->root), first);
94
95 if (first && first != jptr && first != first_spc)
96 GETDNS_FREE(dict->mf, first);
97
98 return d;
99 }
100
101
102 static struct getdns_dict_item *
_delete_dict_item(const getdns_dict * dict,const char * jptr)103 _delete_dict_item(const getdns_dict *dict, const char *jptr)
104 {
105 char first_spc[1024], *first;
106 struct getdns_dict_item *d;
107
108 first = _json_ptr_first(&dict->mf, jptr,
109 first_spc, sizeof(first_spc));
110
111 d = (struct getdns_dict_item *) _getdns_rbtree_delete(
112 (_getdns_rbtree_t *)&(dict->root), first);
113
114 if (first && first != jptr && first != first_spc)
115 GETDNS_FREE(dict->mf, first);
116
117 return d;
118 }
119
120
121 static char *
_json_ptr_keydup(const struct mem_funcs * mf,const char * jptr)122 _json_ptr_keydup(const struct mem_funcs *mf, const char *jptr)
123 {
124 char *first = _json_ptr_first(mf, jptr, NULL, 0);
125
126 if (first == jptr || first == jptr + 1) {
127 size_t sz = strlen(jptr) + 1;
128
129 if ((first = GETDNS_XMALLOC(*mf, char, sz)))
130 memcpy(first, jptr, sz);
131 }
132 return first;
133 }
134
135
136 getdns_return_t
_getdns_dict_find(const getdns_dict * dict,const char * key,getdns_item ** item)137 _getdns_dict_find(const getdns_dict *dict, const char *key, getdns_item **item)
138 {
139 const char *next;
140 struct getdns_dict_item *d;
141
142 if (!(d = _find_dict_item(dict, key)))
143 return GETDNS_RETURN_NO_SUCH_DICT_NAME;
144
145 if (*key != '/' || !(next = strchr(key + 1, '/'))) {
146 *item = &d->i;
147 return GETDNS_RETURN_GOOD;
148
149 } else switch (d->i.dtype) { /* Key was nested reference */
150 case t_dict: return _getdns_dict_find(d->i.data.dict, next, item);
151 case t_list: return _getdns_list_find(d->i.data.list, next, item);
152 default : /* Trying to dereference a non list or dict */
153 return GETDNS_RETURN_WRONG_TYPE_REQUESTED;
154 }
155 }
156
157
158 /*---------------------------------------- getdns_dict_item_free */
159 /**
160 * private function used to release storage associated with a dictionary item
161 * @param node all memory in this structure and its children will be freed
162 * @param arg is a dict who's custom memory function will be used
163 * to free the items
164 * @return void
165 */
166 static void
getdns_dict_item_free(_getdns_rbnode_t * node,void * arg)167 getdns_dict_item_free(_getdns_rbnode_t *node, void *arg)
168 {
169 struct getdns_dict_item *d = (struct getdns_dict_item *)node;
170 struct getdns_dict *dict = (struct getdns_dict *)arg;
171
172 assert(node);
173 assert(arg);
174
175 switch (d->i.dtype) {
176 case t_dict : getdns_dict_destroy(d->i.data.dict); break;
177 case t_list : getdns_list_destroy(d->i.data.list); break;
178 case t_bindata: _getdns_bindata_destroy(&dict->mf, d->i.data.bindata);
179 default : break;
180 }
181 if (node->key)
182 GETDNS_FREE(dict->mf, (void *)node->key);
183 GETDNS_FREE(dict->mf, node);
184 } /* getdns_dict_item_free */
185
186
187 getdns_return_t
getdns_dict_remove_name(getdns_dict * dict,const char * name)188 getdns_dict_remove_name(getdns_dict *dict, const char *name)
189 {
190 const char *next;
191 struct getdns_dict_item *d;
192
193 if (!dict || !name)
194 return GETDNS_RETURN_INVALID_PARAMETER;
195
196 if (!(d = _find_dict_item(dict, name)))
197 return GETDNS_RETURN_NO_SUCH_DICT_NAME;
198
199 if (*name != '/' || !(next = strchr(name + 1, '/'))) {
200 d = _delete_dict_item(dict, name);
201 getdns_dict_item_free(&d->node, dict);
202 return GETDNS_RETURN_GOOD;
203
204 } else switch (d->i.dtype) {
205 case t_dict: return getdns_dict_remove_name(d->i.data.dict, next);
206 case t_list: return _getdns_list_remove_name(d->i.data.list, next);
207 default : /* Trying to dereference a non list or dict */
208 return GETDNS_RETURN_WRONG_TYPE_REQUESTED;
209 }
210 }
211
212
213 getdns_return_t
_getdns_dict_find_and_add(getdns_dict * dict,const char * key,getdns_item ** item)214 _getdns_dict_find_and_add(
215 getdns_dict *dict, const char *key, getdns_item **item)
216 {
217 const char *next;
218 struct getdns_dict_item *d;
219
220 if (!(d = _find_dict_item(dict, key))) {
221 /* add a node */
222 d = GETDNS_MALLOC(dict->mf, struct getdns_dict_item);
223 d->node.key = _json_ptr_keydup(&dict->mf, key);
224 _getdns_rbtree_insert(&(dict->root), (_getdns_rbnode_t *) d);
225 if (*key != '/' || !(next = strchr(key + 1, '/'))) {
226 (void) memset(&d->i.data, 0, sizeof(d->i.data));
227 d->i.dtype = t_int;
228 d->i.data.n = 55555333;
229 *item = &d->i;
230 return GETDNS_RETURN_GOOD;
231 }
232 if ((next[1] == '0' || next[1] == '-') &&
233 (next[2] == '/' || next[2] == '\0')) {
234
235 d->i.dtype = t_list;
236 d->i.data.list =_getdns_list_create_with_mf(&dict->mf);
237 return _getdns_list_find_and_add(
238 d->i.data.list, next, item);
239 }
240 d->i.dtype = t_dict;
241 d->i.data.dict = _getdns_dict_create_with_mf(&dict->mf);
242 return _getdns_dict_find_and_add(d->i.data.dict, next, item);
243 }
244 if (*key != '/' || !(next = strchr(key + 1, '/'))) {
245 switch (d->i.dtype) {
246 case t_dict : getdns_dict_destroy(d->i.data.dict); break;
247 case t_list : getdns_list_destroy(d->i.data.list); break;
248 case t_bindata: _getdns_bindata_destroy(
249 &dict->mf, d->i.data.bindata); break;
250 default : break;
251 }
252 d->i.dtype = t_int;
253 d->i.data.n = 33355555;
254 *item = &d->i;
255 return GETDNS_RETURN_GOOD;
256
257 } else switch (d->i.dtype) { /* Key was nested reference */
258 case t_dict:return _getdns_dict_find_and_add(d->i.data.dict,next,item);
259 case t_list:return _getdns_list_find_and_add(d->i.data.list,next,item);
260 default :/* Trying to dereference a non list or dict */
261 return GETDNS_RETURN_WRONG_TYPE_REQUESTED;
262 }
263 } /* getdns_dict_find_and_add */
264
265
266 /*---------------------------------------- getdns_dict_get_names
267 */
268 getdns_return_t
getdns_dict_get_names(const getdns_dict * dict,getdns_list ** answer)269 getdns_dict_get_names(const getdns_dict *dict, getdns_list **answer)
270 {
271 struct getdns_dict_item *item;
272
273 if (!dict || !answer)
274 return GETDNS_RETURN_INVALID_PARAMETER;
275
276 *answer = getdns_list_create_with_extended_memory_functions(
277 dict->mf.mf_arg, dict->mf.mf.ext.malloc,
278 dict->mf.mf.ext.realloc, dict->mf.mf.ext.free);
279 if (!*answer)
280 return GETDNS_RETURN_NO_SUCH_DICT_NAME;
281
282 RBTREE_FOR(item, struct getdns_dict_item *,
283 (_getdns_rbtree_t *)&(dict->root)) {
284 _getdns_list_append_string(*answer, item->node.key);
285 }
286 return GETDNS_RETURN_GOOD;
287 } /* getdns_dict_get_names */
288
289 /*---------------------------------------- getdns_dict_get_data_type */
290 getdns_return_t
getdns_dict_get_data_type(const getdns_dict * dict,const char * name,getdns_data_type * answer)291 getdns_dict_get_data_type(
292 const getdns_dict *dict, const char *name, getdns_data_type *answer)
293 {
294 getdns_return_t r;
295 getdns_item *item;
296
297 if (!dict || !name || !answer)
298 return GETDNS_RETURN_INVALID_PARAMETER;
299
300 if ((r = _getdns_dict_find(dict, name, &item)))
301 return r;
302
303 *answer = item->dtype;
304 return GETDNS_RETURN_GOOD;
305 } /* getdns_dict_get_data_type */
306
307 /*---------------------------------------- getdns_dict_get_dict */
308 getdns_return_t
getdns_dict_get_dict(const getdns_dict * dict,const char * name,getdns_dict ** answer)309 getdns_dict_get_dict(
310 const getdns_dict *dict, const char *name, getdns_dict **answer)
311 {
312 getdns_return_t r;
313 getdns_item *item;
314
315 if (!dict || !name || !answer)
316 return GETDNS_RETURN_INVALID_PARAMETER;
317
318 if ((r = _getdns_dict_find(dict, name, &item)))
319 return r;
320
321 if (item->dtype != t_dict)
322 return GETDNS_RETURN_WRONG_TYPE_REQUESTED;
323
324 *answer = item->data.dict;
325 return GETDNS_RETURN_GOOD;
326 } /* getdns_dict_get_dict */
327
328 /*---------------------------------------- getdns_dict_get_list */
329 getdns_return_t
getdns_dict_get_list(const getdns_dict * dict,const char * name,getdns_list ** answer)330 getdns_dict_get_list(
331 const getdns_dict *dict, const char *name, getdns_list **answer)
332 {
333 getdns_return_t r;
334 getdns_item *item;
335
336 if (!dict || !name || !answer)
337 return GETDNS_RETURN_INVALID_PARAMETER;
338
339 if ((r = _getdns_dict_find(dict, name, &item)))
340 return r;
341
342 if (item->dtype != t_list)
343 return GETDNS_RETURN_WRONG_TYPE_REQUESTED;
344
345 *answer = item->data.list;
346 return GETDNS_RETURN_GOOD;
347 } /* getdns_dict_get_list */
348
349 /*---------------------------------------- getdns_dict_get_bindata */
350 getdns_return_t
getdns_dict_get_bindata(const getdns_dict * dict,const char * name,getdns_bindata ** answer)351 getdns_dict_get_bindata(
352 const getdns_dict *dict, const char *name, getdns_bindata **answer)
353 {
354 getdns_return_t r;
355 getdns_item *item;
356
357 if (!dict || !name || !answer)
358 return GETDNS_RETURN_INVALID_PARAMETER;
359
360 if ((r = _getdns_dict_find(dict, name, &item)))
361 return GETDNS_RETURN_NO_SUCH_DICT_NAME;
362
363 if (item->dtype != t_bindata)
364 return GETDNS_RETURN_WRONG_TYPE_REQUESTED;
365
366 *answer = item->data.bindata;
367 return GETDNS_RETURN_GOOD;
368 } /* getdns_dict_get_bindata */
369
370 /*---------------------------------------- getdns_dict_get_int */
371 getdns_return_t
getdns_dict_get_int(const getdns_dict * dict,const char * name,uint32_t * answer)372 getdns_dict_get_int(
373 const getdns_dict *dict, const char *name, uint32_t *answer)
374 {
375 getdns_return_t r;
376 getdns_item *item;
377
378 if (!dict || !name || !answer)
379 return GETDNS_RETURN_INVALID_PARAMETER;
380
381 if ((r = _getdns_dict_find(dict, name, &item)))
382 return r;
383
384 if (item->dtype != t_int)
385 return GETDNS_RETURN_WRONG_TYPE_REQUESTED;
386
387 *answer = item->data.n;
388 return GETDNS_RETURN_GOOD;
389 } /* getdns_dict_get_int */
390
391 struct getdns_dict *
getdns_dict_create_with_extended_memory_functions(void * userarg,void * (* malloc)(void * userarg,size_t),void * (* realloc)(void * userarg,void *,size_t),void (* free)(void * userarg,void *))392 getdns_dict_create_with_extended_memory_functions(
393 void *userarg,
394 void *(*malloc)(void *userarg, size_t),
395 void *(*realloc)(void *userarg, void *, size_t),
396 void (*free)(void *userarg, void *))
397 {
398 struct getdns_dict *dict;
399 mf_union mf;
400
401 if (!malloc || !realloc || !free)
402 return NULL;
403
404 mf.ext.malloc = malloc;
405 dict = userarg == MF_PLAIN
406 ? (struct getdns_dict*)(*mf.pln.malloc)(
407 sizeof(struct getdns_dict))
408 : (struct getdns_dict*)(*mf.ext.malloc)(userarg,
409 sizeof(struct getdns_dict));
410 if (!dict)
411 return NULL;
412
413 dict->mf.mf_arg = userarg;
414 dict->mf.mf.ext.malloc = malloc;
415 dict->mf.mf.ext.realloc = realloc;
416 dict->mf.mf.ext.free = free;
417
418 _getdns_rbtree_init(&(dict->root),
419 (int (*)(const void *, const void *)) strcmp);
420 return dict;
421 }
422
423 struct getdns_dict *
getdns_dict_create_with_memory_functions(void * (* malloc)(size_t),void * (* realloc)(void *,size_t),void (* free)(void *))424 getdns_dict_create_with_memory_functions(void *(*malloc)(size_t),
425 void *(*realloc)(void *, size_t), void (*free)(void *))
426 {
427 mf_union mf;
428 mf.pln.malloc = malloc;
429 mf.pln.realloc = realloc;
430 mf.pln.free = free;
431 return getdns_dict_create_with_extended_memory_functions(
432 MF_PLAIN, mf.ext.malloc, mf.ext.realloc, mf.ext.free);
433 }
434
435 /*-------------------------- getdns_dict_create_with_context */
436 struct getdns_dict *
getdns_dict_create_with_context(const getdns_context * context)437 getdns_dict_create_with_context(const getdns_context *context)
438 {
439 if (context)
440 return getdns_dict_create_with_extended_memory_functions(
441 context->mf.mf_arg, context->mf.mf.ext.malloc,
442 context->mf.mf.ext.realloc, context->mf.mf.ext.free);
443 else
444 return getdns_dict_create_with_memory_functions(&malloc,
445 &realloc, &free);
446 } /* getdns_dict_create_with_context */
447
448 /*---------------------------------------- getdns_dict_create */
449 struct getdns_dict *
getdns_dict_create()450 getdns_dict_create()
451 {
452 return getdns_dict_create_with_context(NULL);
453 } /* getdns_dict_create */
454
455 /*---------------------------------------- _getdns_dict_copy */
456 /**
457 * private function used to make a copy of a dict structure,
458 * the caller is responsible * for freeing storage allocated to returned value
459 * @param srcdict the dictionary structure to copy
460 * @param dstdict the copy destination
461 * @return the address of the copy of the dictionary structure on success
462 * @return NULL on error (out of memory, invalid srcdict)
463 */
464 getdns_return_t
_getdns_dict_copy(const struct getdns_dict * srcdict,struct getdns_dict ** dstdict)465 _getdns_dict_copy(const struct getdns_dict * srcdict,
466 struct getdns_dict ** dstdict)
467 {
468 struct getdns_dict_item *item;
469 char *key;
470 getdns_return_t retval;
471
472 if (!dstdict)
473 return GETDNS_RETURN_INVALID_PARAMETER;
474
475 if (!srcdict) {
476 *dstdict = NULL;
477 return GETDNS_RETURN_GOOD;
478 }
479 *dstdict = getdns_dict_create_with_extended_memory_functions(
480 srcdict->mf.mf_arg,
481 srcdict->mf.mf.ext.malloc,
482 srcdict->mf.mf.ext.realloc,
483 srcdict->mf.mf.ext.free);
484 if (!*dstdict)
485 return GETDNS_RETURN_GENERIC_ERROR;
486
487 RBTREE_FOR(item, struct getdns_dict_item *,
488 (struct _getdns_rbtree_t *)&(srcdict->root)) {
489 key = (char *) item->node.key;
490 switch (item->i.dtype) {
491 case t_bindata:
492 retval = getdns_dict_set_bindata(*dstdict, key,
493 item->i.data.bindata);
494 break;
495
496 case t_dict:
497 retval = getdns_dict_set_dict(*dstdict, key,
498 item->i.data.dict);
499 break;
500
501 case t_int:
502 retval = getdns_dict_set_int(*dstdict, key,
503 item->i.data.n);
504 break;
505
506 case t_list:
507 retval = getdns_dict_set_list(*dstdict, key,
508 item->i.data.list);
509 break;
510 default:
511 retval = GETDNS_RETURN_WRONG_TYPE_REQUESTED;
512 break;
513 }
514 if (retval != GETDNS_RETURN_GOOD) {
515 getdns_dict_destroy(*dstdict);;
516 *dstdict = NULL;
517 return retval;
518 }
519 }
520 return GETDNS_RETURN_GOOD;
521 } /* _getdns_dict_copy */
522
523
524 /*---------------------------------------- getdns_dict_destroy */
525 void
getdns_dict_destroy(struct getdns_dict * dict)526 getdns_dict_destroy(struct getdns_dict *dict)
527 {
528 if (!dict) return;
529 _getdns_traverse_postorder(&(dict->root), getdns_dict_item_free, dict);
530 GETDNS_FREE(dict->mf, dict);
531 } /* getdns_dict_destroy */
532
533 /*---------------------------------------- getdns_dict_set_dict */
534 getdns_return_t
_getdns_dict_set_this_dict(getdns_dict * dict,const char * name,getdns_dict * child_dict)535 _getdns_dict_set_this_dict(
536 getdns_dict *dict, const char *name, getdns_dict *child_dict)
537 {
538 getdns_item *item;
539 getdns_return_t r;
540
541 if (!dict || !name || !child_dict)
542 return GETDNS_RETURN_INVALID_PARAMETER;
543
544 if ((r = _getdns_dict_find_and_add(dict, name, &item)))
545 return r;
546
547 item->dtype = t_dict;
548 item->data.dict = child_dict;
549 return GETDNS_RETURN_GOOD;
550 } /* getdns_dict_set_dict */
551
552 getdns_return_t
getdns_dict_set_dict(getdns_dict * dict,const char * name,const getdns_dict * child_dict)553 getdns_dict_set_dict(
554 getdns_dict *dict, const char *name, const getdns_dict *child_dict)
555 {
556 getdns_dict *newdict;
557 getdns_return_t r;
558
559 if ((r = _getdns_dict_copy(child_dict, &newdict)))
560 return r;
561
562 if ((r = _getdns_dict_set_this_dict(dict, name, newdict)))
563 getdns_dict_destroy(newdict);
564
565 return r;
566 }
567
568
569 /*---------------------------------------- getdns_dict_set_list */
570 getdns_return_t
_getdns_dict_set_this_list(getdns_dict * dict,const char * name,getdns_list * child_list)571 _getdns_dict_set_this_list(
572 getdns_dict *dict, const char *name, getdns_list *child_list)
573 {
574 getdns_item *item;
575 getdns_return_t r;
576
577 if (!dict || !name || !child_list)
578 return GETDNS_RETURN_INVALID_PARAMETER;
579
580 if ((r = _getdns_dict_find_and_add(dict, name, &item)))
581 return r;
582
583 item->dtype = t_list;
584 item->data.list = child_list;
585 return GETDNS_RETURN_GOOD;
586 } /* getdns_dict_set_list */
587
588 getdns_return_t
getdns_dict_set_list(getdns_dict * dict,const char * name,const getdns_list * child_list)589 getdns_dict_set_list(
590 getdns_dict *dict, const char *name, const getdns_list *child_list)
591 {
592 getdns_list *newlist;
593 getdns_return_t r;
594
595 if ((r = _getdns_list_copy(child_list, &newlist)))
596 return r;
597
598 if ((r = _getdns_dict_set_this_list(dict, name, newlist)))
599 getdns_list_destroy(newlist);
600
601 return r;
602 }
603
604
605 /*---------------------------------------- getdns_dict_set_bindata */
606 getdns_return_t
_getdns_dict_set_this_bindata(getdns_dict * dict,const char * name,getdns_bindata * bindata)607 _getdns_dict_set_this_bindata(
608 getdns_dict *dict, const char *name, getdns_bindata *bindata)
609 {
610 getdns_item *item;
611 getdns_return_t r;
612
613 if (!dict || !name || !bindata)
614 return GETDNS_RETURN_INVALID_PARAMETER;
615
616 if ((r = _getdns_dict_find_and_add(dict, name, &item)))
617 return r;
618
619 item->dtype = t_bindata;
620 item->data.bindata = bindata;
621 return GETDNS_RETURN_GOOD;
622 }
623
624 getdns_return_t
_getdns_dict_set_const_bindata(getdns_dict * dict,const char * name,size_t size,const void * data)625 _getdns_dict_set_const_bindata(
626 getdns_dict *dict, const char *name, size_t size, const void *data)
627 {
628 getdns_item *item;
629 getdns_bindata *newbindata;
630 getdns_return_t r;
631
632 if (!dict || !name)
633 return GETDNS_RETURN_INVALID_PARAMETER;
634
635 if (!(newbindata = _getdns_bindata_copy(&dict->mf, size, data)))
636 return GETDNS_RETURN_MEMORY_ERROR;
637
638 if ((r = _getdns_dict_find_and_add(dict, name, &item))) {
639 _getdns_bindata_destroy(&dict->mf, newbindata);
640 return r;
641 }
642 item->dtype = t_bindata;
643 item->data.bindata = newbindata;
644 return GETDNS_RETURN_GOOD;
645 }
646
647 getdns_return_t
getdns_dict_set_bindata(getdns_dict * dict,const char * name,const getdns_bindata * child_bindata)648 getdns_dict_set_bindata(
649 getdns_dict *dict, const char *name, const getdns_bindata *child_bindata)
650 {
651 return !child_bindata ? GETDNS_RETURN_INVALID_PARAMETER
652 : _getdns_dict_set_const_bindata(
653 dict, name, child_bindata->size, child_bindata->data);
654 }
655
656 /*---------------------------------------- getdns_dict_set_bindata */
657 getdns_return_t
getdns_dict_util_set_string(getdns_dict * dict,const char * name,const char * value)658 getdns_dict_util_set_string(getdns_dict *dict,
659 const char *name, const char *value)
660 {
661 getdns_item *item;
662 getdns_bindata *newbindata;
663 getdns_return_t r;
664
665 if (!dict || !name || !value)
666 return GETDNS_RETURN_INVALID_PARAMETER;
667
668 if (!(newbindata = _getdns_bindata_copy(
669 &dict->mf, strlen(value) + 1, (uint8_t *)value)))
670 return GETDNS_RETURN_MEMORY_ERROR;
671
672 newbindata->size -= 1;
673
674 if ((r = _getdns_dict_find_and_add(dict, name, &item))) {
675 _getdns_bindata_destroy(&dict->mf, newbindata);
676 return r;
677 }
678 item->dtype = t_bindata;
679 item->data.bindata = newbindata;
680 return GETDNS_RETURN_GOOD;
681 } /* getdns_dict_util_set_dict */
682
683 /*---------------------------------------- getdns_dict_set_int */
684 getdns_return_t
getdns_dict_set_int(getdns_dict * dict,const char * name,uint32_t child_uint32)685 getdns_dict_set_int(getdns_dict *dict, const char *name, uint32_t child_uint32)
686 {
687 getdns_item *item;
688 getdns_return_t r;
689
690 if (!dict || !name)
691 return GETDNS_RETURN_INVALID_PARAMETER;
692
693 if ((r = _getdns_dict_find_and_add(dict, name, &item)))
694 return r;
695
696 item->dtype = t_int;
697 item->data.n = child_uint32;
698 return GETDNS_RETURN_GOOD;
699 } /* getdns_dict_set_int */
700
701 /*---------------------------------------- getdns_pp_dict */
702 /**
703 * private function to help with indenting.
704 * @param indent number of spaces to return
705 * @return a character string containing min(80, indent) spaces
706 */
707 static const char *
getdns_indent(size_t indent)708 getdns_indent(size_t indent)
709 {
710 static const char *spaces = " "
711 " ";
712 return spaces + 80 - (indent < 80 ? indent : 0);
713 } /* getdns_indent */
714
715 int
_getdns_bindata_is_dname(getdns_bindata * bindata)716 _getdns_bindata_is_dname(getdns_bindata *bindata)
717 {
718 size_t i = 0, n_labels = 0;
719
720 while (i < bindata->size && bindata->data[i]) {
721 if (bindata->data[i] & 0xC0) /* Compression pointer! */
722 return 0;
723
724 i += ((size_t)bindata->data[i]) + 1;
725 n_labels++;
726 }
727 if (i < bindata->size && !bindata->data[i]) {
728 n_labels++;
729 i++;
730 }
731
732 return i == bindata->size && n_labels > 1 &&
733 bindata->data[bindata->size - 1] == 0;
734 }
735
736 static int
getdns_pp_base64(gldns_buffer * buf,getdns_bindata * bindata)737 getdns_pp_base64(gldns_buffer *buf, getdns_bindata *bindata)
738 {
739 size_t p = gldns_buffer_position(buf);
740 size_t base64str_sz;
741
742 if (gldns_buffer_printf(buf, " <bindata of ") < 0)
743 return -1;
744
745 base64str_sz = gldns_b64_ntop_calculate_size(bindata->size);
746 if (!gldns_buffer_reserve(buf, base64str_sz))
747 return -1;
748
749 gldns_buffer_skip(buf, gldns_b64_ntop(bindata->data, bindata->size,
750 (char *)gldns_buffer_current(buf), base64str_sz));
751
752 if (gldns_buffer_printf(buf, ">") < 0)
753 return -1;
754
755 return gldns_buffer_position(buf) - p;
756 }
757
758 /*---------------------------------------- getdns_pp_bindata */
759 /**
760 * private function to pretty print bindata to a gldns_buffer
761 * @param buf buffer to write to
762 * @param bindata the bindata to print
763 * @return on success the number of written characters
764 * if an output error is encountered, a negative value
765 */
766 static int
getdns_pp_bindata(gldns_buffer * buf,getdns_bindata * bindata,int rdata_raw,int json)767 getdns_pp_bindata(gldns_buffer *buf, getdns_bindata *bindata,
768 int rdata_raw, int json)
769 {
770 size_t i, p = gldns_buffer_position(buf);
771 uint8_t *dptr;
772 char spc[1024];
773
774 if (!json && gldns_buffer_printf(buf, " <bindata ") < 0)
775 return -1;
776
777 /* Walk through all printable characters */
778 i = 0;
779 if (!rdata_raw)
780 while (i < bindata->size && isprint(bindata->data[i]))
781 i++;
782
783 if (bindata->size > 0 && i == bindata->size) { /* all printable? */
784
785 if (json) {
786 const uint8_t *s = bindata->data;
787 const uint8_t *e = s + bindata->size;
788 const uint8_t *b;
789
790 if (!gldns_buffer_reserve(buf, (e - s) + 2))
791 return -1;
792 gldns_buffer_write_u8(buf, '"');
793 for (;;) {
794 for ( b = s
795 ; b < e && *b != '\\' && *b != '"'
796 ; b++)
797 ; /* pass */
798 if (b == e)
799 break;
800 if (!gldns_buffer_reserve(buf, (b - s) + 3))
801 return -1;
802 gldns_buffer_write(buf, s, b - s);
803 gldns_buffer_write_u8(buf, '\\');
804 gldns_buffer_write_u8(buf, *b);
805 s = b + 1;
806 }
807 if (s < e)
808 gldns_buffer_write(buf, s, e - s);
809 gldns_buffer_write_u8(buf, '"');
810 } else {
811 (void)snprintf(spc, sizeof(spc), "of \"%%.%ds\"%s>",
812 (int)(i > 32 ? 32 : i), (i > 32 ? "..." : ""));
813 if (gldns_buffer_printf(buf, spc, bindata->data) < 0)
814 return -1;
815 }
816
817 } else if (bindata->size > 1 && /* null terminated printable */
818 i == bindata->size - 1 && bindata->data[i] == 0) {
819
820 if (gldns_buffer_printf(
821 buf, (json ? "\"%s\"" : "of \"%s\">"), bindata->data) < 0)
822 return -1;
823
824 } else if (bindata->size == 1 && *bindata->data == 0) {
825 if (gldns_buffer_printf(buf, json ? "\".\"" : "for .>") < 0)
826 return -1;
827
828 } else if (_getdns_bindata_is_dname(bindata)) {
829 (void)gldns_wire2str_dname_buf(
830 bindata->data, bindata->size, spc, sizeof(spc));
831 if (gldns_buffer_printf(
832 buf, (json ? "\"%s\"" : "for %s>"), spc) < 0)
833 return -1;
834 } else if (json) {
835 if (gldns_buffer_printf(buf, "[") < 0)
836 return -1;
837 for (dptr = bindata->data;
838 dptr < bindata->data + bindata->size; dptr++) {
839 if (dptr > bindata->data) {
840 if (gldns_buffer_printf(buf, ",") < 0)
841 return -1;
842 }
843 if (gldns_buffer_printf(buf, "%d", (int)*dptr) < 0)
844 return -1;
845 }
846 if (gldns_buffer_printf(buf, "]") < 0)
847 return -1;
848 } else {
849 if (gldns_buffer_printf(buf, "of 0x") < 0)
850 return -1;
851 for (dptr = bindata->data;
852 dptr < bindata->data + bindata->size; dptr++) {
853 if (dptr - bindata->data >= 16) {
854 if (gldns_buffer_printf(buf, "...") < 0)
855 return -1;
856 break;
857 }
858 if (gldns_buffer_printf(buf, "%.2x", *dptr) < 0)
859 return -1;
860 }
861 if (gldns_buffer_printf(buf, ">") < 0)
862 return -1;
863 }
864 return gldns_buffer_position(buf) - p;
865 } /* getdns_pp_bindata */
866
867 static int
868 getdns_pp_dict(gldns_buffer * buf, size_t indent,
869 const getdns_dict *dict, int json);
870
871 static const char *unknown_str_l[] = {" <unknown>", " null", "null"};
872
873 /*---------------------------------------- getdns_pp_list */
874 /**
875 * private function to pretty print list to a gldns_buffer
876 * @param buf buffer to write to
877 * @param indent number of spaces to append after newline
878 * @param list the to list print
879 * @param for_literals The list is a list of literals.
880 * Show the literal instead of the value.
881 * @return on success the number of written characters
882 * if an output error is encountered, a negative value
883 */
884 static int
getdns_pp_list(gldns_buffer * buf,size_t indent,const getdns_list * list,int for_literals,int json)885 getdns_pp_list(gldns_buffer *buf, size_t indent, const getdns_list *list,
886 int for_literals, int json)
887 {
888 size_t i, length, p = gldns_buffer_position(buf);
889 getdns_data_type dtype;
890 struct getdns_dict *dict_item;
891 struct getdns_list *list_item;
892 struct getdns_bindata *bindata_item;
893 uint32_t int_item;
894 const char *strval;
895
896 if (list == NULL)
897 return 0;
898
899 if (gldns_buffer_printf(buf, "[") < 0)
900 return -1;
901
902 if (getdns_list_get_length(list, &length) != GETDNS_RETURN_GOOD)
903 return -1;
904
905 indent += 2;
906 for (i = 0; i < length; i++) {
907 if (i && gldns_buffer_printf(buf, ",") < 0)
908 return -1;
909 if (json < 2 && gldns_buffer_printf(buf, "\n%s",
910 getdns_indent(indent)) < 0)
911 return -1;
912
913 if (getdns_list_get_data_type(list, i, &dtype) !=
914 GETDNS_RETURN_GOOD)
915 return -1;
916
917 switch (dtype) {
918 case t_int:
919
920 if (getdns_list_get_int(list, i, &int_item))
921 return -1;
922 if (!json && for_literals &&
923 (strval =
924 _getdns_get_const_info(int_item)->name)) {
925 if (gldns_buffer_printf(buf, "%s", strval) < 0)
926 return -1;
927 } else if (0 >
928 gldns_buffer_printf(buf, "%d", (int)int_item))
929 return -1;
930 break;
931
932 case t_bindata:
933 if (getdns_list_get_bindata(list, i, &bindata_item) !=
934 GETDNS_RETURN_GOOD)
935 return -1;
936 if (getdns_pp_bindata(
937 buf, bindata_item, 0, json) < 0)
938 return -1;
939 break;
940
941 case t_list:
942 if (getdns_list_get_list(list, i, &list_item) !=
943 GETDNS_RETURN_GOOD)
944 return -1;
945 if (getdns_pp_list(
946 buf, indent, list_item, 0, json) < 0)
947 return -1;
948 break;
949
950 case t_dict:
951 if (getdns_list_get_dict(list, i, &dict_item) !=
952 GETDNS_RETURN_GOOD)
953 return -1;
954 if (getdns_pp_dict(buf, indent, dict_item, json) < 0)
955 return -1;
956 break;
957
958 default:
959 if (gldns_buffer_printf(
960 buf, "%s", unknown_str_l[json]) < 0)
961 return -1;
962 }
963 }
964 indent -= 2;
965 if (json < 2 && i && gldns_buffer_printf(
966 buf, "\n%s", getdns_indent(indent)) < 0)
967 return -1;
968 if (gldns_buffer_printf(buf, "]") < 0)
969 return -1;
970
971 return gldns_buffer_position(buf) - p;
972 } /* getdns_pp_list */
973
974 static int
_getdns_print_class(gldns_buffer * buf,uint32_t klass)975 _getdns_print_class(gldns_buffer *buf, uint32_t klass)
976 {
977 switch (klass) {
978 case GETDNS_RRCLASS_IN:
979 (void) gldns_buffer_printf(buf, " GETDNS_RRCLASS_IN");
980 return 1;
981 case GETDNS_RRCLASS_CH:
982 (void) gldns_buffer_printf(buf, " GETDNS_RRCLASS_CH");
983 return 1;
984 case GETDNS_RRCLASS_HS:
985 (void) gldns_buffer_printf(buf, " GETDNS_RRCLASS_HS");
986 return 1;
987 case GETDNS_RRCLASS_NONE:
988 (void) gldns_buffer_printf(buf, " GETDNS_RRCLASS_NONE");
989 return 1;
990 case GETDNS_RRCLASS_ANY:
991 (void) gldns_buffer_printf(buf, " GETDNS_RRCLASS_ANY");
992 return 1;
993 }
994 return 0;
995 }
996
997 static int
_getdns_print_opcode(gldns_buffer * buf,uint32_t opcode)998 _getdns_print_opcode(gldns_buffer *buf, uint32_t opcode)
999 {
1000 switch (opcode) {
1001 case GETDNS_OPCODE_QUERY:
1002 (void) gldns_buffer_printf(buf, " GETDNS_OPCODE_QUERY");
1003 return 1;
1004 case GETDNS_OPCODE_IQUERY:
1005 (void) gldns_buffer_printf(buf, " GETDNS_OPCODE_IQUERY");
1006 return 1;
1007 case GETDNS_OPCODE_STATUS:
1008 (void) gldns_buffer_printf(buf, " GETDNS_OPCODE_STATUS");
1009 return 1;
1010 case GETDNS_OPCODE_NOTIFY:
1011 (void) gldns_buffer_printf(buf, " GETDNS_OPCODE_NOTIFY");
1012 return 1;
1013 case GETDNS_OPCODE_UPDATE:
1014 (void) gldns_buffer_printf(buf, " GETDNS_OPCODE_UPDATE");
1015 return 1;
1016 }
1017 return 0;
1018 }
1019
1020 static int
_getdns_print_rcode(gldns_buffer * buf,uint32_t rcode)1021 _getdns_print_rcode(gldns_buffer *buf, uint32_t rcode)
1022 {
1023 static const char *rcodes[] = {
1024 " GETDNS_RCODE_NOERROR" , " GETDNS_RCODE_FORMERR" ,
1025 " GETDNS_RCODE_SERVFAIL", " GETDNS_RCODE_NXDOMAIN",
1026 " GETDNS_RCODE_NOTIMP" , " GETDNS_RCODE_REFUSED" ,
1027 " GETDNS_RCODE_YXDOMAIN", " GETDNS_RCODE_YXRRSET" ,
1028 " GETDNS_RCODE_NXRRSET" , " GETDNS_RCODE_NOTAUTH" ,
1029 " GETDNS_RCODE_NOTZONE" ,
1030 " GETDNS_RCODE_BADSIG" , " GETDNS_RCODE_BADKEY" ,
1031 " GETDNS_RCODE_BADTIME" , " GETDNS_RCODE_BADMODE" ,
1032 " GETDNS_RCODE_BADNAME" , " GETDNS_RCODE_BADALG" ,
1033 " GETDNS_RCODE_BADTRUNC"
1034 };
1035 if (rcode <= 10)
1036 (void) gldns_buffer_printf(buf, "%s", rcodes[rcode]);
1037 else if (rcode >= 16 && rcode <= 22)
1038 (void) gldns_buffer_printf(buf, "%s", rcodes[rcode-6]);
1039 else
1040 return 0;
1041 return 1;
1042 }
1043
1044 /*---------------------------------------- getdns_pp_dict */
1045 /**
1046 * private function to pretty print dict to a gldns_buffer
1047 * @param buf buffer to write to
1048 * @param indent number of spaces to append after newline
1049 * @param dict the dict to print
1050 * @return on success the number of written characters
1051 * if an output error is encountered, a negative value
1052 */
1053 static int
getdns_pp_dict(gldns_buffer * buf,size_t indent,const getdns_dict * dict,int json)1054 getdns_pp_dict(gldns_buffer * buf, size_t indent,
1055 const getdns_dict *dict, int json)
1056 {
1057 size_t i, length, p = gldns_buffer_position(buf);
1058 struct getdns_dict_item *item;
1059 const char *strval;
1060
1061 char abuf[80];
1062
1063 if (dict == NULL)
1064 return 0;
1065
1066 if (gldns_buffer_printf(buf, "{") < 0)
1067 return -1;
1068
1069 i = 0;
1070 indent += 2;
1071 RBTREE_FOR(item, struct getdns_dict_item *,
1072 (_getdns_rbtree_t *)&(dict->root)) {
1073
1074 if (i && gldns_buffer_printf(buf, ",") < 0)
1075 return -1;
1076 if (json < 2 && gldns_buffer_printf(
1077 buf, "\n%s", getdns_indent(indent)) < 0)
1078 return -1;
1079 if (gldns_buffer_printf(
1080 buf, "\"%s\":",(const char *)item->node.key) < 0)
1081 return -1;
1082
1083 switch (item->i.dtype) {
1084 case t_int:
1085 if (!json &&
1086 (strcmp(item->node.key, "type") == 0 ||
1087 strcmp(item->node.key, "type_covered") == 0 ||
1088 strcmp(item->node.key, "query_type") == 0 ||
1089 strcmp(item->node.key, "qtype") == 0) &&
1090 (strval = _getdns_rr_type_name(item->i.data.n))) {
1091 if (gldns_buffer_printf(
1092 buf, " GETDNS_RRTYPE_%s", strval) < 0)
1093 return -1;
1094 break;
1095 }
1096 if (!json &&
1097 (strcmp(item->node.key, "answer_type") == 0 ||
1098 strcmp(item->node.key, "dnssec_status") == 0 ||
1099 strcmp(item->node.key, "tsig_status") == 0 ||
1100 strcmp(item->node.key, "status") == 0 ||
1101 strcmp(item->node.key, "append_name") == 0 ||
1102 strcmp(item->node.key, "follow_redirects") == 0 ||
1103 strcmp(item->node.key, "transport") == 0 ||
1104 strcmp(item->node.key, "resolution_type") == 0 ||
1105 strcmp(item->node.key, "tls_authentication") == 0 ||
1106 strcmp(item->node.key, "tls_min_version") == 0 ||
1107 strcmp(item->node.key, "tls_max_version") == 0 ||
1108
1109 /* extensions */
1110 strcmp(item->node.key, "add_warning_for_bad_dns") == 0 ||
1111 strcmp(item->node.key, "dnssec") == 0 ||
1112 strcmp(item->node.key, "dnssec_return_all_statuses") == 0 ||
1113 strcmp(item->node.key, "dnssec_return_full_validation_chain") == 0 ||
1114 strcmp(item->node.key, "dnssec_return_only_secure") == 0 ||
1115 strcmp(item->node.key, "dnssec_return_status") == 0 ||
1116 strcmp(item->node.key, "dnssec_return_validation_chain") == 0 ||
1117 #if defined(DNSSEC_ROADBLOCK_AVOIDANCE) && defined(HAVE_LIBUNBOUND)
1118 strcmp(item->node.key, "dnssec_roadblock_avoidance") == 0 ||
1119 #endif
1120 #ifdef EDNS_COOKIES
1121 strcmp(item->node.key, "edns_cookies") == 0 ||
1122 #endif
1123 strcmp(item->node.key, "return_api_information") == 0 ||
1124 strcmp(item->node.key, "return_both_v4_and_v6") == 0 ||
1125 strcmp(item->node.key, "return_call_reporting") == 0
1126 ) &&
1127 (strval =
1128 _getdns_get_const_info(item->i.data.n)->name)) {
1129 if (gldns_buffer_printf(buf, " %s", strval) < 0)
1130 return -1;
1131 break;
1132 }
1133 if (!json &&
1134 (strcmp(item->node.key, "class") == 0 ||
1135 strcmp(item->node.key, "qclass") == 0) &&
1136 _getdns_print_class(buf, item->i.data.n))
1137 break;
1138 if (!json && strcmp(item->node.key, "opcode") == 0 &&
1139 _getdns_print_opcode(buf, item->i.data.n))
1140 break;
1141 if (!json && strcmp(item->node.key, "rcode") == 0 &&
1142 _getdns_print_rcode(buf, item->i.data.n))
1143 break;
1144 if (gldns_buffer_printf(
1145 buf,(json < 2 ? " %d" : "%d"), item->i.data.n) < 0)
1146 return -1;
1147 break;
1148
1149 case t_bindata:
1150 if ((strcmp(item->node.key, "address_data") == 0 ||
1151 strcmp(item->node.key, "ipv4_address") == 0 ||
1152 strcmp(item->node.key, "ipv6_address") == 0 ) &&
1153 (item->i.data.bindata->size == 4 ||
1154 item->i.data.bindata->size == 16 )) {
1155
1156 if (gldns_buffer_printf(buf,
1157 (json ? "\"%s\"" : " <bindata for %s>"),
1158 inet_ntop(( item->i.data.bindata->size == 4
1159 ? AF_INET : AF_INET6)
1160 , item->i.data.bindata->data
1161 , abuf
1162 , 40
1163 )) < 0)
1164 return -1;
1165
1166 } else if (!json &&
1167 (strcmp(item->node.key, "pin-sha256") == 0 ||
1168 strcmp(item->node.key, "value") == 0) &&
1169 item->i.data.bindata->size > 0 &&
1170 item->i.data.bindata->size % 4 == 0) {
1171
1172 if (getdns_pp_base64(buf,
1173 item->i.data.bindata) < 0)
1174 return -1;
1175
1176 } else if (getdns_pp_bindata(
1177 buf, item->i.data.bindata,
1178 (strcmp(item->node.key, "rdata_raw") == 0),
1179 json) < 0)
1180 return -1;
1181 break;
1182
1183 case t_list: /* Don't put empty lists on a new line */
1184
1185 if (getdns_list_get_length(item->i.data.list, &length) !=
1186 GETDNS_RETURN_GOOD)
1187 return -1;
1188 if (length == 0) {
1189 if (gldns_buffer_printf(
1190 buf, (json < 2 ? " []" : "[]")) < 0)
1191 return -1;
1192 break;
1193 }
1194 if (json < 2 && gldns_buffer_printf(buf, "\n%s",
1195 getdns_indent(indent)) < 0)
1196 return -1;
1197 if (getdns_pp_list(buf, indent, item->i.data.list,
1198 (strcmp(item->node.key, "namespaces") == 0 ||
1199 strcmp(item->node.key, "dns_transport_list") == 0
1200 || strcmp(item->node.key, "bad_dns") == 0),
1201 json) < 0)
1202 return -1;
1203 break;
1204
1205 case t_dict:
1206 if (json < 2 && gldns_buffer_printf(buf, "\n%s",
1207 getdns_indent(indent)) < 0)
1208 return -1;
1209 if (getdns_pp_dict(
1210 buf, indent, item->i.data.dict, json) < 0)
1211 return -1;
1212 break;
1213
1214 default:
1215 if (gldns_buffer_printf(
1216 buf, "%s", unknown_str_l[json]) < 0)
1217 return -1;
1218 }
1219 i++;
1220 }
1221 indent -= 2;
1222 if (json < 2 && i && gldns_buffer_printf(
1223 buf, "\n%s", getdns_indent(indent)) < 0)
1224 return -1;
1225 if (gldns_buffer_printf(buf, "}") < 0)
1226 return -1;
1227
1228 return gldns_buffer_position(buf) - p;
1229 } /* getdns_pp_dict */
1230
1231 /*---------------------------------------- getdns_pretty_print_dict */
1232 /**
1233 * Return a character string containing a "human readable" representation
1234 * of dict.
1235 * @param dict the dict to pretty print
1236 * @return the "human readable" representation of dict
1237 * or NULL on error
1238 */
1239 char *
getdns_pretty_print_dict(const struct getdns_dict * dict)1240 getdns_pretty_print_dict(const struct getdns_dict *dict)
1241 {
1242 gldns_buffer *buf;
1243 char *ret;
1244
1245 if (!dict)
1246 return NULL;
1247
1248 buf = gldns_buffer_new(8192);
1249 if (!buf)
1250 return NULL;
1251
1252 if (getdns_pp_dict(buf, 0, dict, 0) < 0) {
1253 gldns_buffer_free(buf);
1254 return NULL;
1255 }
1256 ret = (char *) gldns_buffer_export(buf);
1257 gldns_buffer_free(buf);
1258 return ret;
1259 } /* getdns_pretty_print_dict */
1260
1261 int
getdns_pretty_snprint_dict(char * str,size_t size,const getdns_dict * dict)1262 getdns_pretty_snprint_dict(char *str, size_t size, const getdns_dict *dict)
1263 {
1264 gldns_buffer buf;
1265
1266 if (!dict) return -1;
1267
1268 gldns_buffer_init_vfixed_frm_data(&buf, str, size);
1269 return getdns_pp_dict(&buf, 0, dict, 0) < 0
1270 ? -1 : (int)gldns_buffer_position(&buf);
1271 }
1272
1273 char *
getdns_pretty_print_list(const getdns_list * list)1274 getdns_pretty_print_list(const getdns_list *list)
1275 {
1276 gldns_buffer *buf;
1277 char *ret;
1278
1279 if (!list)
1280 return NULL;
1281
1282 buf = gldns_buffer_new(4096);
1283 if (!buf)
1284 return NULL;
1285
1286 if (getdns_pp_list(buf, 0, list, 0, 0) < 0) {
1287 gldns_buffer_free(buf);
1288 return NULL;
1289 }
1290 ret = (char *) gldns_buffer_export(buf);
1291 gldns_buffer_free(buf);
1292 return ret;
1293 }
1294
1295 int
getdns_pretty_snprint_list(char * str,size_t size,const getdns_list * list)1296 getdns_pretty_snprint_list(char *str, size_t size, const getdns_list *list)
1297 {
1298 gldns_buffer buf;
1299
1300 if (!list) return -1;
1301
1302 gldns_buffer_init_vfixed_frm_data(&buf, str, size);
1303 return getdns_pp_list(&buf, 0, list, 0, 0) < 0
1304 ? -1 : (int)gldns_buffer_position(&buf);
1305 }
1306
1307 char *
getdns_print_json_dict(const getdns_dict * dict,int pretty)1308 getdns_print_json_dict(const getdns_dict *dict, int pretty)
1309 {
1310 gldns_buffer *buf;
1311 char *ret;
1312
1313 if (!dict)
1314 return NULL;
1315
1316 buf = gldns_buffer_new(8192);
1317 if (!buf)
1318 return NULL;
1319
1320 if (getdns_pp_dict(buf, 0, dict, pretty ? 1 : 2) < 0) {
1321 gldns_buffer_free(buf);
1322 return NULL;
1323 }
1324 ret = (char *) gldns_buffer_export(buf);
1325 gldns_buffer_free(buf);
1326 return ret;
1327 } /* getdns_print_json_dict */
1328
1329 int
getdns_snprint_json_dict(char * str,size_t size,const getdns_dict * dict,int pretty)1330 getdns_snprint_json_dict(
1331 char *str, size_t size, const getdns_dict *dict, int pretty)
1332 {
1333 gldns_buffer buf;
1334
1335 if (!dict) return -1;
1336
1337 gldns_buffer_init_vfixed_frm_data(&buf, str, size);
1338 return getdns_pp_dict(&buf, 0, dict, pretty ? 1 : 2) < 0
1339 ? -1 : (int)gldns_buffer_position(&buf);
1340 }
1341
1342 char *
getdns_print_json_list(const getdns_list * list,int pretty)1343 getdns_print_json_list(const getdns_list *list, int pretty)
1344 {
1345 gldns_buffer *buf;
1346 char *ret;
1347
1348 if (!list)
1349 return NULL;
1350
1351 buf = gldns_buffer_new(4096);
1352 if (!buf)
1353 return NULL;
1354
1355 if (getdns_pp_list(buf, 0, list, 0, pretty ? 1 : 2) < 0) {
1356 gldns_buffer_free(buf);
1357 return NULL;
1358 }
1359 ret = (char *) gldns_buffer_export(buf);
1360 gldns_buffer_free(buf);
1361 return ret;
1362 }
1363
1364 int
getdns_snprint_json_list(char * str,size_t size,const getdns_list * list,int pretty)1365 getdns_snprint_json_list(
1366 char *str, size_t size, const getdns_list *list, int pretty)
1367 {
1368 gldns_buffer buf;
1369
1370 if (!list) return -1;
1371
1372 gldns_buffer_init_vfixed_frm_data(&buf, str, size);
1373 return getdns_pp_list(&buf, 0, list, 0, pretty ? 1 : 2) < 0
1374 ? -1 : (int)gldns_buffer_position(&buf);
1375 }
1376
1377 /* dict.c */
1378