1 /*
2 * Copyright (c) 2014-2019 Pavel Kalvoda <me@pavelkalvoda.com>
3 *
4 * libcbor is free software; you can redistribute it and/or modify
5 * it under the terms of the MIT license. See LICENSE for details.
6 */
7
8 #include "maps.h"
9 #include "internal/memory_utils.h"
10
cbor_map_size(const cbor_item_t * item)11 size_t cbor_map_size(const cbor_item_t *item) {
12 assert(cbor_isa_map(item));
13 return item->metadata.map_metadata.end_ptr;
14 }
15
cbor_map_allocated(const cbor_item_t * item)16 size_t cbor_map_allocated(const cbor_item_t *item) {
17 assert(cbor_isa_map(item));
18 return item->metadata.map_metadata.allocated;
19 }
20
cbor_new_definite_map(size_t size)21 cbor_item_t *cbor_new_definite_map(size_t size) {
22 cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
23 _CBOR_NOTNULL(item);
24
25 *item = (cbor_item_t){
26 .refcount = 1,
27 .type = CBOR_TYPE_MAP,
28 .metadata = {.map_metadata = {.allocated = size,
29 .type = _CBOR_METADATA_DEFINITE,
30 .end_ptr = 0}},
31 .data = _cbor_alloc_multiple(sizeof(struct cbor_pair), size)};
32 _CBOR_DEPENDENT_NOTNULL(item, item->data);
33
34 return item;
35 }
36
cbor_new_indefinite_map()37 cbor_item_t *cbor_new_indefinite_map() {
38 cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
39 _CBOR_NOTNULL(item);
40
41 *item = (cbor_item_t){
42 .refcount = 1,
43 .type = CBOR_TYPE_MAP,
44 .metadata = {.map_metadata = {.allocated = 0,
45 .type = _CBOR_METADATA_INDEFINITE,
46 .end_ptr = 0}},
47 .data = NULL};
48
49 return item;
50 }
51
_cbor_map_add_key(cbor_item_t * item,cbor_item_t * key)52 bool _cbor_map_add_key(cbor_item_t *item, cbor_item_t *key) {
53 assert(cbor_isa_map(item));
54 struct _cbor_map_metadata *metadata =
55 (struct _cbor_map_metadata *)&item->metadata;
56 if (cbor_map_is_definite(item)) {
57 struct cbor_pair *data = cbor_map_handle(item);
58 if (metadata->end_ptr >= metadata->allocated) {
59 /* Don't realloc definite preallocated map */
60 return false;
61 }
62
63 data[metadata->end_ptr].key = key;
64 data[metadata->end_ptr++].value = NULL;
65 } else {
66 if (metadata->end_ptr >= metadata->allocated) {
67 /* Exponential realloc */
68 // Check for overflows first
69 // TODO: Explicitly test this
70 if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, metadata->allocated)) {
71 return false;
72 }
73
74 size_t new_allocation = metadata->allocated == 0
75 ? 1
76 : CBOR_BUFFER_GROWTH * metadata->allocated;
77
78 unsigned char *new_data = _cbor_realloc_multiple(
79 item->data, sizeof(struct cbor_pair), new_allocation);
80
81 if (new_data == NULL) {
82 return false;
83 }
84
85 item->data = new_data;
86 metadata->allocated = new_allocation;
87 }
88 struct cbor_pair *data = cbor_map_handle(item);
89 data[metadata->end_ptr].key = key;
90 data[metadata->end_ptr++].value = NULL;
91 }
92 cbor_incref(key);
93 return true;
94 }
95
_cbor_map_add_value(cbor_item_t * item,cbor_item_t * value)96 bool _cbor_map_add_value(cbor_item_t *item, cbor_item_t *value) {
97 assert(cbor_isa_map(item));
98 cbor_incref(value);
99 cbor_map_handle(item)[
100 /* Move one back since we are assuming _add_key (which increased the ptr)
101 * was the previous operation on this object */
102 item->metadata.map_metadata.end_ptr - 1]
103 .value = value;
104 return true;
105 }
106
cbor_map_add(cbor_item_t * item,struct cbor_pair pair)107 bool cbor_map_add(cbor_item_t *item, struct cbor_pair pair) {
108 assert(cbor_isa_map(item));
109 if (!_cbor_map_add_key(item, pair.key)) return false;
110 return _cbor_map_add_value(item, pair.value);
111 }
112
cbor_map_is_definite(const cbor_item_t * item)113 bool cbor_map_is_definite(const cbor_item_t *item) {
114 assert(cbor_isa_map(item));
115 return item->metadata.map_metadata.type == _CBOR_METADATA_DEFINITE;
116 }
117
cbor_map_is_indefinite(const cbor_item_t * item)118 bool cbor_map_is_indefinite(const cbor_item_t *item) {
119 return !cbor_map_is_definite(item);
120 }
121
cbor_map_handle(const cbor_item_t * item)122 struct cbor_pair *cbor_map_handle(const cbor_item_t *item) {
123 assert(cbor_isa_map(item));
124 return (struct cbor_pair *)item->data;
125 }
126