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
cbor_array_size(const cbor_item_t * item)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
cbor_array_allocated(const cbor_item_t * item)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
cbor_array_get(const cbor_item_t * item,size_t index)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
cbor_array_set(cbor_item_t * item,size_t index,cbor_item_t * value)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
cbor_array_replace(cbor_item_t * item,size_t index,cbor_item_t * value)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
cbor_array_push(cbor_item_t * array,cbor_item_t * pushee)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
cbor_array_is_definite(const cbor_item_t * item)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
cbor_array_is_indefinite(const cbor_item_t * item)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
cbor_array_handle(const cbor_item_t * item)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
cbor_new_definite_array(size_t size)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
cbor_new_indefinite_array(void)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