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