xref: /openbsd-src/lib/libcbor/src/cbor/arrays.c (revision 4dcc46c4d04180142eda526ce521dfb137776d05)
1da0d961cSdjm /*
2d3425be1Sdjm  * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
3da0d961cSdjm  *
4da0d961cSdjm  * libcbor is free software; you can redistribute it and/or modify
5da0d961cSdjm  * it under the terms of the MIT license. See LICENSE for details.
6da0d961cSdjm  */
7da0d961cSdjm 
8da0d961cSdjm #include "arrays.h"
99e5c2ddcSdjm #include <string.h>
10da0d961cSdjm #include "internal/memory_utils.h"
11da0d961cSdjm 
cbor_array_size(const cbor_item_t * item)129e5c2ddcSdjm size_t cbor_array_size(const cbor_item_t *item) {
13*4dcc46c4Sdjm   CBOR_ASSERT(cbor_isa_array(item));
14da0d961cSdjm   return item->metadata.array_metadata.end_ptr;
15da0d961cSdjm }
16da0d961cSdjm 
cbor_array_allocated(const cbor_item_t * item)179e5c2ddcSdjm size_t cbor_array_allocated(const cbor_item_t *item) {
18*4dcc46c4Sdjm   CBOR_ASSERT(cbor_isa_array(item));
19da0d961cSdjm   return item->metadata.array_metadata.allocated;
20da0d961cSdjm }
21da0d961cSdjm 
cbor_array_get(const cbor_item_t * item,size_t index)229e5c2ddcSdjm cbor_item_t *cbor_array_get(const cbor_item_t *item, size_t index) {
23da0d961cSdjm   return cbor_incref(((cbor_item_t **)item->data)[index]);
24da0d961cSdjm }
25da0d961cSdjm 
cbor_array_set(cbor_item_t * item,size_t index,cbor_item_t * value)269e5c2ddcSdjm bool cbor_array_set(cbor_item_t *item, size_t index, cbor_item_t *value) {
27da0d961cSdjm   if (index == item->metadata.array_metadata.end_ptr) {
28da0d961cSdjm     return cbor_array_push(item, value);
29da0d961cSdjm   } else if (index < item->metadata.array_metadata.end_ptr) {
30da0d961cSdjm     return cbor_array_replace(item, index, value);
31da0d961cSdjm   } else {
32da0d961cSdjm     return false;
33da0d961cSdjm   }
34da0d961cSdjm }
35da0d961cSdjm 
cbor_array_replace(cbor_item_t * item,size_t index,cbor_item_t * value)369e5c2ddcSdjm bool cbor_array_replace(cbor_item_t *item, size_t index, cbor_item_t *value) {
379e5c2ddcSdjm   if (index >= item->metadata.array_metadata.end_ptr) return false;
38da0d961cSdjm   /* We cannot use cbor_array_get as that would increase the refcount */
39da0d961cSdjm   cbor_intermediate_decref(((cbor_item_t **)item->data)[index]);
40da0d961cSdjm   ((cbor_item_t **)item->data)[index] = cbor_incref(value);
41da0d961cSdjm   return true;
42da0d961cSdjm }
43da0d961cSdjm 
cbor_array_push(cbor_item_t * array,cbor_item_t * pushee)449e5c2ddcSdjm bool cbor_array_push(cbor_item_t *array, cbor_item_t *pushee) {
45*4dcc46c4Sdjm   CBOR_ASSERT(cbor_isa_array(array));
469e5c2ddcSdjm   struct _cbor_array_metadata *metadata =
479e5c2ddcSdjm       (struct _cbor_array_metadata *)&array->metadata;
48da0d961cSdjm   cbor_item_t **data = (cbor_item_t **)array->data;
49da0d961cSdjm   if (cbor_array_is_definite(array)) {
50da0d961cSdjm     /* Do not reallocate definite arrays */
51da0d961cSdjm     if (metadata->end_ptr >= metadata->allocated) {
52da0d961cSdjm       return false;
53da0d961cSdjm     }
54da0d961cSdjm     data[metadata->end_ptr++] = pushee;
55da0d961cSdjm   } else {
56da0d961cSdjm     /* Exponential realloc */
57da0d961cSdjm     if (metadata->end_ptr >= metadata->allocated) {
58da0d961cSdjm       // Check for overflows first
59da0d961cSdjm       if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, metadata->allocated)) {
60da0d961cSdjm         return false;
61da0d961cSdjm       }
62da0d961cSdjm 
639e5c2ddcSdjm       size_t new_allocation = metadata->allocated == 0
649e5c2ddcSdjm                                   ? 1
659e5c2ddcSdjm                                   : CBOR_BUFFER_GROWTH * metadata->allocated;
66da0d961cSdjm 
679e5c2ddcSdjm       unsigned char *new_data = _cbor_realloc_multiple(
689e5c2ddcSdjm           array->data, sizeof(cbor_item_t *), new_allocation);
69da0d961cSdjm       if (new_data == NULL) {
70da0d961cSdjm         return false;
71da0d961cSdjm       }
72da0d961cSdjm 
73da0d961cSdjm       array->data = new_data;
74da0d961cSdjm       metadata->allocated = new_allocation;
75da0d961cSdjm     }
76da0d961cSdjm     ((cbor_item_t **)array->data)[metadata->end_ptr++] = pushee;
77da0d961cSdjm   }
78da0d961cSdjm   cbor_incref(pushee);
79da0d961cSdjm   return true;
80da0d961cSdjm }
81da0d961cSdjm 
cbor_array_is_definite(const cbor_item_t * item)829e5c2ddcSdjm bool cbor_array_is_definite(const cbor_item_t *item) {
83*4dcc46c4Sdjm   CBOR_ASSERT(cbor_isa_array(item));
84da0d961cSdjm   return item->metadata.array_metadata.type == _CBOR_METADATA_DEFINITE;
85da0d961cSdjm }
86da0d961cSdjm 
cbor_array_is_indefinite(const cbor_item_t * item)879e5c2ddcSdjm bool cbor_array_is_indefinite(const cbor_item_t *item) {
88*4dcc46c4Sdjm   CBOR_ASSERT(cbor_isa_array(item));
89da0d961cSdjm   return item->metadata.array_metadata.type == _CBOR_METADATA_INDEFINITE;
90da0d961cSdjm }
91da0d961cSdjm 
cbor_array_handle(const cbor_item_t * item)929e5c2ddcSdjm cbor_item_t **cbor_array_handle(const cbor_item_t *item) {
93*4dcc46c4Sdjm   CBOR_ASSERT(cbor_isa_array(item));
94da0d961cSdjm   return (cbor_item_t **)item->data;
95da0d961cSdjm }
96da0d961cSdjm 
cbor_new_definite_array(size_t size)979e5c2ddcSdjm cbor_item_t *cbor_new_definite_array(size_t size) {
98*4dcc46c4Sdjm   cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
999e5c2ddcSdjm   _CBOR_NOTNULL(item);
100da0d961cSdjm   cbor_item_t **data = _cbor_alloc_multiple(sizeof(cbor_item_t *), size);
1019e5c2ddcSdjm   _CBOR_DEPENDENT_NOTNULL(item, data);
102da0d961cSdjm 
1039e5c2ddcSdjm   for (size_t i = 0; i < size; i++) {
104da0d961cSdjm     data[i] = NULL;
1059e5c2ddcSdjm   }
106da0d961cSdjm 
107da0d961cSdjm   *item = (cbor_item_t){
108da0d961cSdjm       .refcount = 1,
109da0d961cSdjm       .type = CBOR_TYPE_ARRAY,
1109e5c2ddcSdjm       .metadata = {.array_metadata = {.type = _CBOR_METADATA_DEFINITE,
111da0d961cSdjm                                       .allocated = size,
1129e5c2ddcSdjm                                       .end_ptr = 0}},
1139e5c2ddcSdjm       .data = (unsigned char *)data};
114da0d961cSdjm 
115da0d961cSdjm   return item;
116da0d961cSdjm }
117da0d961cSdjm 
cbor_new_indefinite_array(void)118*4dcc46c4Sdjm cbor_item_t *cbor_new_indefinite_array(void) {
119*4dcc46c4Sdjm   cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
1209e5c2ddcSdjm   _CBOR_NOTNULL(item);
121da0d961cSdjm 
122da0d961cSdjm   *item = (cbor_item_t){
123da0d961cSdjm       .refcount = 1,
124da0d961cSdjm       .type = CBOR_TYPE_ARRAY,
1259e5c2ddcSdjm       .metadata = {.array_metadata = {.type = _CBOR_METADATA_INDEFINITE,
126da0d961cSdjm                                       .allocated = 0,
1279e5c2ddcSdjm                                       .end_ptr = 0}},
128da0d961cSdjm       .data = NULL /* Can be safely realloc-ed */
129da0d961cSdjm   };
130da0d961cSdjm   return item;
131da0d961cSdjm }
132