1 /*
2 * Copyright (c) 2014-2019 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 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 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 // 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
cbor_array_replace(cbor_item_t * item,size_t index,cbor_item_t * value)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
cbor_array_push(cbor_item_t * array,cbor_item_t * pushee)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
cbor_array_is_definite(const cbor_item_t * item)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
cbor_array_is_indefinite(const cbor_item_t * item)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
cbor_array_handle(const cbor_item_t * item)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
cbor_new_definite_array(size_t size)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
cbor_new_indefinite_array()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