1 /* 2 * Copyright (c) 2014-2020 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 11 size_t cbor_map_size(const cbor_item_t *item) { 12 CBOR_ASSERT(cbor_isa_map(item)); 13 return item->metadata.map_metadata.end_ptr; 14 } 15 16 size_t cbor_map_allocated(const cbor_item_t *item) { 17 CBOR_ASSERT(cbor_isa_map(item)); 18 return item->metadata.map_metadata.allocated; 19 } 20 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 37 cbor_item_t *cbor_new_indefinite_map(void) { 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 52 bool _cbor_map_add_key(cbor_item_t *item, cbor_item_t *key) { 53 CBOR_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 if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, metadata->allocated)) { 70 return false; 71 } 72 73 size_t new_allocation = metadata->allocated == 0 74 ? 1 75 : CBOR_BUFFER_GROWTH * metadata->allocated; 76 77 unsigned char *new_data = _cbor_realloc_multiple( 78 item->data, sizeof(struct cbor_pair), new_allocation); 79 80 if (new_data == NULL) { 81 return false; 82 } 83 84 item->data = new_data; 85 metadata->allocated = new_allocation; 86 } 87 struct cbor_pair *data = cbor_map_handle(item); 88 data[metadata->end_ptr].key = key; 89 data[metadata->end_ptr++].value = NULL; 90 } 91 cbor_incref(key); 92 return true; 93 } 94 95 bool _cbor_map_add_value(cbor_item_t *item, cbor_item_t *value) { 96 CBOR_ASSERT(cbor_isa_map(item)); 97 cbor_incref(value); 98 cbor_map_handle(item)[ 99 /* Move one back since we are assuming _add_key (which increased the ptr) 100 * was the previous operation on this object */ 101 item->metadata.map_metadata.end_ptr - 1] 102 .value = value; 103 return true; 104 } 105 106 // TODO: Add a more convenient API like add(item, key, val) 107 bool cbor_map_add(cbor_item_t *item, struct cbor_pair pair) { 108 CBOR_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 113 bool cbor_map_is_definite(const cbor_item_t *item) { 114 CBOR_ASSERT(cbor_isa_map(item)); 115 return item->metadata.map_metadata.type == _CBOR_METADATA_DEFINITE; 116 } 117 118 bool cbor_map_is_indefinite(const cbor_item_t *item) { 119 return !cbor_map_is_definite(item); 120 } 121 122 struct cbor_pair *cbor_map_handle(const cbor_item_t *item) { 123 CBOR_ASSERT(cbor_isa_map(item)); 124 return (struct cbor_pair *)item->data; 125 } 126