xref: /openbsd-src/lib/libcbor/src/cbor/maps.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 "maps.h"
9da0d961cSdjm #include "internal/memory_utils.h"
10da0d961cSdjm 
cbor_map_size(const cbor_item_t * item)119e5c2ddcSdjm size_t cbor_map_size(const cbor_item_t *item) {
12*4dcc46c4Sdjm   CBOR_ASSERT(cbor_isa_map(item));
13da0d961cSdjm   return item->metadata.map_metadata.end_ptr;
14da0d961cSdjm }
15da0d961cSdjm 
cbor_map_allocated(const cbor_item_t * item)169e5c2ddcSdjm size_t cbor_map_allocated(const cbor_item_t *item) {
17*4dcc46c4Sdjm   CBOR_ASSERT(cbor_isa_map(item));
18da0d961cSdjm   return item->metadata.map_metadata.allocated;
19da0d961cSdjm }
20da0d961cSdjm 
cbor_new_definite_map(size_t size)219e5c2ddcSdjm cbor_item_t *cbor_new_definite_map(size_t size) {
22*4dcc46c4Sdjm   cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
239e5c2ddcSdjm   _CBOR_NOTNULL(item);
249e5c2ddcSdjm 
25da0d961cSdjm   *item = (cbor_item_t){
26da0d961cSdjm       .refcount = 1,
27da0d961cSdjm       .type = CBOR_TYPE_MAP,
289e5c2ddcSdjm       .metadata = {.map_metadata = {.allocated = size,
29da0d961cSdjm                                     .type = _CBOR_METADATA_DEFINITE,
309e5c2ddcSdjm                                     .end_ptr = 0}},
319e5c2ddcSdjm       .data = _cbor_alloc_multiple(sizeof(struct cbor_pair), size)};
329e5c2ddcSdjm   _CBOR_DEPENDENT_NOTNULL(item, item->data);
339e5c2ddcSdjm 
34da0d961cSdjm   return item;
35da0d961cSdjm }
36da0d961cSdjm 
cbor_new_indefinite_map(void)37*4dcc46c4Sdjm cbor_item_t *cbor_new_indefinite_map(void) {
38*4dcc46c4Sdjm   cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
399e5c2ddcSdjm   _CBOR_NOTNULL(item);
409e5c2ddcSdjm 
41da0d961cSdjm   *item = (cbor_item_t){
42da0d961cSdjm       .refcount = 1,
43da0d961cSdjm       .type = CBOR_TYPE_MAP,
449e5c2ddcSdjm       .metadata = {.map_metadata = {.allocated = 0,
45da0d961cSdjm                                     .type = _CBOR_METADATA_INDEFINITE,
469e5c2ddcSdjm                                     .end_ptr = 0}},
479e5c2ddcSdjm       .data = NULL};
48da0d961cSdjm 
49da0d961cSdjm   return item;
50da0d961cSdjm }
51da0d961cSdjm 
_cbor_map_add_key(cbor_item_t * item,cbor_item_t * key)529e5c2ddcSdjm bool _cbor_map_add_key(cbor_item_t *item, cbor_item_t *key) {
53*4dcc46c4Sdjm   CBOR_ASSERT(cbor_isa_map(item));
549e5c2ddcSdjm   struct _cbor_map_metadata *metadata =
559e5c2ddcSdjm       (struct _cbor_map_metadata *)&item->metadata;
56da0d961cSdjm   if (cbor_map_is_definite(item)) {
57da0d961cSdjm     struct cbor_pair *data = cbor_map_handle(item);
58da0d961cSdjm     if (metadata->end_ptr >= metadata->allocated) {
59da0d961cSdjm       /* Don't realloc definite preallocated map */
60da0d961cSdjm       return false;
61da0d961cSdjm     }
62da0d961cSdjm 
63da0d961cSdjm     data[metadata->end_ptr].key = key;
64da0d961cSdjm     data[metadata->end_ptr++].value = NULL;
65da0d961cSdjm   } else {
66da0d961cSdjm     if (metadata->end_ptr >= metadata->allocated) {
67da0d961cSdjm       /* Exponential realloc */
68da0d961cSdjm       // Check for overflows first
69da0d961cSdjm       if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, metadata->allocated)) {
70da0d961cSdjm         return false;
71da0d961cSdjm       }
72da0d961cSdjm 
739e5c2ddcSdjm       size_t new_allocation = metadata->allocated == 0
749e5c2ddcSdjm                                   ? 1
759e5c2ddcSdjm                                   : CBOR_BUFFER_GROWTH * metadata->allocated;
76da0d961cSdjm 
779e5c2ddcSdjm       unsigned char *new_data = _cbor_realloc_multiple(
789e5c2ddcSdjm           item->data, sizeof(struct cbor_pair), new_allocation);
79da0d961cSdjm 
80da0d961cSdjm       if (new_data == NULL) {
81da0d961cSdjm         return false;
82da0d961cSdjm       }
83da0d961cSdjm 
84da0d961cSdjm       item->data = new_data;
85da0d961cSdjm       metadata->allocated = new_allocation;
86da0d961cSdjm     }
87da0d961cSdjm     struct cbor_pair *data = cbor_map_handle(item);
88da0d961cSdjm     data[metadata->end_ptr].key = key;
89da0d961cSdjm     data[metadata->end_ptr++].value = NULL;
90da0d961cSdjm   }
91da0d961cSdjm   cbor_incref(key);
92da0d961cSdjm   return true;
93da0d961cSdjm }
94da0d961cSdjm 
_cbor_map_add_value(cbor_item_t * item,cbor_item_t * value)959e5c2ddcSdjm bool _cbor_map_add_value(cbor_item_t *item, cbor_item_t *value) {
96*4dcc46c4Sdjm   CBOR_ASSERT(cbor_isa_map(item));
97da0d961cSdjm   cbor_incref(value);
98da0d961cSdjm   cbor_map_handle(item)[
99da0d961cSdjm       /* Move one back since we are assuming _add_key (which increased the ptr)
100da0d961cSdjm        * was the previous operation on this object */
1019e5c2ddcSdjm       item->metadata.map_metadata.end_ptr - 1]
1029e5c2ddcSdjm       .value = value;
103da0d961cSdjm   return true;
104da0d961cSdjm }
105da0d961cSdjm 
cbor_map_add(cbor_item_t * item,struct cbor_pair pair)1069e5c2ddcSdjm bool cbor_map_add(cbor_item_t *item, struct cbor_pair pair) {
107*4dcc46c4Sdjm   CBOR_ASSERT(cbor_isa_map(item));
1089e5c2ddcSdjm   if (!_cbor_map_add_key(item, pair.key)) return false;
109da0d961cSdjm   return _cbor_map_add_value(item, pair.value);
110da0d961cSdjm }
111da0d961cSdjm 
cbor_map_is_definite(const cbor_item_t * item)1129e5c2ddcSdjm bool cbor_map_is_definite(const cbor_item_t *item) {
113*4dcc46c4Sdjm   CBOR_ASSERT(cbor_isa_map(item));
114da0d961cSdjm   return item->metadata.map_metadata.type == _CBOR_METADATA_DEFINITE;
115da0d961cSdjm }
116da0d961cSdjm 
cbor_map_is_indefinite(const cbor_item_t * item)1179e5c2ddcSdjm bool cbor_map_is_indefinite(const cbor_item_t *item) {
118da0d961cSdjm   return !cbor_map_is_definite(item);
119da0d961cSdjm }
120da0d961cSdjm 
cbor_map_handle(const cbor_item_t * item)1219e5c2ddcSdjm struct cbor_pair *cbor_map_handle(const cbor_item_t *item) {
122*4dcc46c4Sdjm   CBOR_ASSERT(cbor_isa_map(item));
123da0d961cSdjm   return (struct cbor_pair *)item->data;
124da0d961cSdjm }
125