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