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 CBOR_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 CBOR_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 } 35 36 bool cbor_array_replace(cbor_item_t *item, size_t index, cbor_item_t *value) { 37 if (index >= item->metadata.array_metadata.end_ptr) return false; 38 /* We cannot use cbor_array_get as that would increase the refcount */ 39 cbor_intermediate_decref(((cbor_item_t **)item->data)[index]); 40 ((cbor_item_t **)item->data)[index] = cbor_incref(value); 41 return true; 42 } 43 44 bool cbor_array_push(cbor_item_t *array, cbor_item_t *pushee) { 45 CBOR_ASSERT(cbor_isa_array(array)); 46 struct _cbor_array_metadata *metadata = 47 (struct _cbor_array_metadata *)&array->metadata; 48 cbor_item_t **data = (cbor_item_t **)array->data; 49 if (cbor_array_is_definite(array)) { 50 /* Do not reallocate definite arrays */ 51 if (metadata->end_ptr >= metadata->allocated) { 52 return false; 53 } 54 data[metadata->end_ptr++] = pushee; 55 } else { 56 /* Exponential realloc */ 57 if (metadata->end_ptr >= metadata->allocated) { 58 // Check for overflows first 59 if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, metadata->allocated)) { 60 return false; 61 } 62 63 size_t new_allocation = metadata->allocated == 0 64 ? 1 65 : CBOR_BUFFER_GROWTH * metadata->allocated; 66 67 unsigned char *new_data = _cbor_realloc_multiple( 68 array->data, sizeof(cbor_item_t *), new_allocation); 69 if (new_data == NULL) { 70 return false; 71 } 72 73 array->data = new_data; 74 metadata->allocated = new_allocation; 75 } 76 ((cbor_item_t **)array->data)[metadata->end_ptr++] = pushee; 77 } 78 cbor_incref(pushee); 79 return true; 80 } 81 82 bool cbor_array_is_definite(const cbor_item_t *item) { 83 CBOR_ASSERT(cbor_isa_array(item)); 84 return item->metadata.array_metadata.type == _CBOR_METADATA_DEFINITE; 85 } 86 87 bool cbor_array_is_indefinite(const cbor_item_t *item) { 88 CBOR_ASSERT(cbor_isa_array(item)); 89 return item->metadata.array_metadata.type == _CBOR_METADATA_INDEFINITE; 90 } 91 92 cbor_item_t **cbor_array_handle(const cbor_item_t *item) { 93 CBOR_ASSERT(cbor_isa_array(item)); 94 return (cbor_item_t **)item->data; 95 } 96 97 cbor_item_t *cbor_new_definite_array(size_t size) { 98 cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t)); 99 _CBOR_NOTNULL(item); 100 cbor_item_t **data = _cbor_alloc_multiple(sizeof(cbor_item_t *), size); 101 _CBOR_DEPENDENT_NOTNULL(item, data); 102 103 for (size_t i = 0; i < size; i++) { 104 data[i] = NULL; 105 } 106 107 *item = (cbor_item_t){ 108 .refcount = 1, 109 .type = CBOR_TYPE_ARRAY, 110 .metadata = {.array_metadata = {.type = _CBOR_METADATA_DEFINITE, 111 .allocated = size, 112 .end_ptr = 0}}, 113 .data = (unsigned char *)data}; 114 115 return item; 116 } 117 118 cbor_item_t *cbor_new_indefinite_array(void) { 119 cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t)); 120 _CBOR_NOTNULL(item); 121 122 *item = (cbor_item_t){ 123 .refcount = 1, 124 .type = CBOR_TYPE_ARRAY, 125 .metadata = {.array_metadata = {.type = _CBOR_METADATA_INDEFINITE, 126 .allocated = 0, 127 .end_ptr = 0}}, 128 .data = NULL /* Can be safely realloc-ed */ 129 }; 130 return item; 131 } 132