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 "arrays.h" 9 #include <string.h> 10 #include "internal/memory_utils.h" 11 12 size_t cbor_array_size(const cbor_item_t *item) { 13 assert(cbor_isa_array(item)); 14 return item->metadata.array_metadata.end_ptr; 15 } 16 17 size_t cbor_array_allocated(const cbor_item_t *item) { 18 assert(cbor_isa_array(item)); 19 return item->metadata.array_metadata.allocated; 20 } 21 22 cbor_item_t *cbor_array_get(const cbor_item_t *item, size_t index) { 23 return cbor_incref(((cbor_item_t **)item->data)[index]); 24 } 25 26 bool cbor_array_set(cbor_item_t *item, size_t index, cbor_item_t *value) { 27 if (index == item->metadata.array_metadata.end_ptr) { 28 return cbor_array_push(item, value); 29 } else if (index < item->metadata.array_metadata.end_ptr) { 30 return cbor_array_replace(item, index, value); 31 } else { 32 return false; 33 } 34 // TODO: This is unreachable and the index checking logic above seems 35 // suspicious -- out of bounds index is a caller error. Figure out & fix. 36 return true; 37 } 38 39 bool cbor_array_replace(cbor_item_t *item, size_t index, cbor_item_t *value) { 40 if (index >= item->metadata.array_metadata.end_ptr) return false; 41 /* We cannot use cbor_array_get as that would increase the refcount */ 42 cbor_intermediate_decref(((cbor_item_t **)item->data)[index]); 43 ((cbor_item_t **)item->data)[index] = cbor_incref(value); 44 return true; 45 } 46 47 bool cbor_array_push(cbor_item_t *array, cbor_item_t *pushee) { 48 assert(cbor_isa_array(array)); 49 struct _cbor_array_metadata *metadata = 50 (struct _cbor_array_metadata *)&array->metadata; 51 cbor_item_t **data = (cbor_item_t **)array->data; 52 if (cbor_array_is_definite(array)) { 53 /* Do not reallocate definite arrays */ 54 if (metadata->end_ptr >= metadata->allocated) { 55 return false; 56 } 57 data[metadata->end_ptr++] = pushee; 58 } else { 59 /* Exponential realloc */ 60 if (metadata->end_ptr >= metadata->allocated) { 61 // Check for overflows first 62 // TODO: Explicitly test this 63 if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, metadata->allocated)) { 64 return false; 65 } 66 67 size_t new_allocation = metadata->allocated == 0 68 ? 1 69 : CBOR_BUFFER_GROWTH * metadata->allocated; 70 71 unsigned char *new_data = _cbor_realloc_multiple( 72 array->data, sizeof(cbor_item_t *), new_allocation); 73 if (new_data == NULL) { 74 return false; 75 } 76 77 array->data = new_data; 78 metadata->allocated = new_allocation; 79 } 80 ((cbor_item_t **)array->data)[metadata->end_ptr++] = pushee; 81 } 82 cbor_incref(pushee); 83 return true; 84 } 85 86 bool cbor_array_is_definite(const cbor_item_t *item) { 87 assert(cbor_isa_array(item)); 88 return item->metadata.array_metadata.type == _CBOR_METADATA_DEFINITE; 89 } 90 91 bool cbor_array_is_indefinite(const cbor_item_t *item) { 92 assert(cbor_isa_array(item)); 93 return item->metadata.array_metadata.type == _CBOR_METADATA_INDEFINITE; 94 } 95 96 cbor_item_t **cbor_array_handle(const cbor_item_t *item) { 97 assert(cbor_isa_array(item)); 98 return (cbor_item_t **)item->data; 99 } 100 101 cbor_item_t *cbor_new_definite_array(size_t size) { 102 cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t)); 103 _CBOR_NOTNULL(item); 104 cbor_item_t **data = _cbor_alloc_multiple(sizeof(cbor_item_t *), size); 105 _CBOR_DEPENDENT_NOTNULL(item, data); 106 107 for (size_t i = 0; i < size; i++) { 108 data[i] = NULL; 109 } 110 111 *item = (cbor_item_t){ 112 .refcount = 1, 113 .type = CBOR_TYPE_ARRAY, 114 .metadata = {.array_metadata = {.type = _CBOR_METADATA_DEFINITE, 115 .allocated = size, 116 .end_ptr = 0}}, 117 .data = (unsigned char *)data}; 118 119 return item; 120 } 121 122 cbor_item_t *cbor_new_indefinite_array() { 123 cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t)); 124 _CBOR_NOTNULL(item); 125 126 *item = (cbor_item_t){ 127 .refcount = 1, 128 .type = CBOR_TYPE_ARRAY, 129 .metadata = {.array_metadata = {.type = _CBOR_METADATA_INDEFINITE, 130 .allocated = 0, 131 .end_ptr = 0}}, 132 .data = NULL /* Can be safely realloc-ed */ 133 }; 134 return item; 135 } 136