xref: /freebsd/contrib/libcbor/src/cbor/arrays.c (revision 5d3e7166f6a0187fa3f8831b16a06bd9955c21ff)
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