110ff414cSEd Maste /*
210ff414cSEd Maste * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
310ff414cSEd Maste *
410ff414cSEd Maste * libcbor is free software; you can redistribute it and/or modify
510ff414cSEd Maste * it under the terms of the MIT license. See LICENSE for details.
610ff414cSEd Maste */
710ff414cSEd Maste
810ff414cSEd Maste #include "arrays.h"
910ff414cSEd Maste #include <string.h>
1010ff414cSEd Maste #include "internal/memory_utils.h"
1110ff414cSEd Maste
cbor_array_size(const cbor_item_t * item)1210ff414cSEd Maste size_t cbor_array_size(const cbor_item_t *item) {
13*5d3e7166SEd Maste CBOR_ASSERT(cbor_isa_array(item));
1410ff414cSEd Maste return item->metadata.array_metadata.end_ptr;
1510ff414cSEd Maste }
1610ff414cSEd Maste
cbor_array_allocated(const cbor_item_t * item)1710ff414cSEd Maste size_t cbor_array_allocated(const cbor_item_t *item) {
18*5d3e7166SEd Maste CBOR_ASSERT(cbor_isa_array(item));
1910ff414cSEd Maste return item->metadata.array_metadata.allocated;
2010ff414cSEd Maste }
2110ff414cSEd Maste
cbor_array_get(const cbor_item_t * item,size_t index)2210ff414cSEd Maste cbor_item_t *cbor_array_get(const cbor_item_t *item, size_t index) {
2310ff414cSEd Maste return cbor_incref(((cbor_item_t **)item->data)[index]);
2410ff414cSEd Maste }
2510ff414cSEd Maste
cbor_array_set(cbor_item_t * item,size_t index,cbor_item_t * value)2610ff414cSEd Maste bool cbor_array_set(cbor_item_t *item, size_t index, cbor_item_t *value) {
2710ff414cSEd Maste if (index == item->metadata.array_metadata.end_ptr) {
2810ff414cSEd Maste return cbor_array_push(item, value);
2910ff414cSEd Maste } else if (index < item->metadata.array_metadata.end_ptr) {
3010ff414cSEd Maste return cbor_array_replace(item, index, value);
3110ff414cSEd Maste } else {
3210ff414cSEd Maste return false;
3310ff414cSEd Maste }
3410ff414cSEd Maste }
3510ff414cSEd Maste
cbor_array_replace(cbor_item_t * item,size_t index,cbor_item_t * value)3610ff414cSEd Maste bool cbor_array_replace(cbor_item_t *item, size_t index, cbor_item_t *value) {
3710ff414cSEd Maste if (index >= item->metadata.array_metadata.end_ptr) return false;
3810ff414cSEd Maste /* We cannot use cbor_array_get as that would increase the refcount */
3910ff414cSEd Maste cbor_intermediate_decref(((cbor_item_t **)item->data)[index]);
4010ff414cSEd Maste ((cbor_item_t **)item->data)[index] = cbor_incref(value);
4110ff414cSEd Maste return true;
4210ff414cSEd Maste }
4310ff414cSEd Maste
cbor_array_push(cbor_item_t * array,cbor_item_t * pushee)4410ff414cSEd Maste bool cbor_array_push(cbor_item_t *array, cbor_item_t *pushee) {
45*5d3e7166SEd Maste CBOR_ASSERT(cbor_isa_array(array));
4610ff414cSEd Maste struct _cbor_array_metadata *metadata =
4710ff414cSEd Maste (struct _cbor_array_metadata *)&array->metadata;
4810ff414cSEd Maste cbor_item_t **data = (cbor_item_t **)array->data;
4910ff414cSEd Maste if (cbor_array_is_definite(array)) {
5010ff414cSEd Maste /* Do not reallocate definite arrays */
5110ff414cSEd Maste if (metadata->end_ptr >= metadata->allocated) {
5210ff414cSEd Maste return false;
5310ff414cSEd Maste }
5410ff414cSEd Maste data[metadata->end_ptr++] = pushee;
5510ff414cSEd Maste } else {
5610ff414cSEd Maste /* Exponential realloc */
5710ff414cSEd Maste if (metadata->end_ptr >= metadata->allocated) {
5810ff414cSEd Maste // Check for overflows first
5910ff414cSEd Maste if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, metadata->allocated)) {
6010ff414cSEd Maste return false;
6110ff414cSEd Maste }
6210ff414cSEd Maste
6310ff414cSEd Maste size_t new_allocation = metadata->allocated == 0
6410ff414cSEd Maste ? 1
6510ff414cSEd Maste : CBOR_BUFFER_GROWTH * metadata->allocated;
6610ff414cSEd Maste
6710ff414cSEd Maste unsigned char *new_data = _cbor_realloc_multiple(
6810ff414cSEd Maste array->data, sizeof(cbor_item_t *), new_allocation);
6910ff414cSEd Maste if (new_data == NULL) {
7010ff414cSEd Maste return false;
7110ff414cSEd Maste }
7210ff414cSEd Maste
7310ff414cSEd Maste array->data = new_data;
7410ff414cSEd Maste metadata->allocated = new_allocation;
7510ff414cSEd Maste }
7610ff414cSEd Maste ((cbor_item_t **)array->data)[metadata->end_ptr++] = pushee;
7710ff414cSEd Maste }
7810ff414cSEd Maste cbor_incref(pushee);
7910ff414cSEd Maste return true;
8010ff414cSEd Maste }
8110ff414cSEd Maste
cbor_array_is_definite(const cbor_item_t * item)8210ff414cSEd Maste bool cbor_array_is_definite(const cbor_item_t *item) {
83*5d3e7166SEd Maste CBOR_ASSERT(cbor_isa_array(item));
8410ff414cSEd Maste return item->metadata.array_metadata.type == _CBOR_METADATA_DEFINITE;
8510ff414cSEd Maste }
8610ff414cSEd Maste
cbor_array_is_indefinite(const cbor_item_t * item)8710ff414cSEd Maste bool cbor_array_is_indefinite(const cbor_item_t *item) {
88*5d3e7166SEd Maste CBOR_ASSERT(cbor_isa_array(item));
8910ff414cSEd Maste return item->metadata.array_metadata.type == _CBOR_METADATA_INDEFINITE;
9010ff414cSEd Maste }
9110ff414cSEd Maste
cbor_array_handle(const cbor_item_t * item)9210ff414cSEd Maste cbor_item_t **cbor_array_handle(const cbor_item_t *item) {
93*5d3e7166SEd Maste CBOR_ASSERT(cbor_isa_array(item));
9410ff414cSEd Maste return (cbor_item_t **)item->data;
9510ff414cSEd Maste }
9610ff414cSEd Maste
cbor_new_definite_array(size_t size)9710ff414cSEd Maste cbor_item_t *cbor_new_definite_array(size_t size) {
98*5d3e7166SEd Maste cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
9910ff414cSEd Maste _CBOR_NOTNULL(item);
10010ff414cSEd Maste cbor_item_t **data = _cbor_alloc_multiple(sizeof(cbor_item_t *), size);
10110ff414cSEd Maste _CBOR_DEPENDENT_NOTNULL(item, data);
10210ff414cSEd Maste
10310ff414cSEd Maste for (size_t i = 0; i < size; i++) {
10410ff414cSEd Maste data[i] = NULL;
10510ff414cSEd Maste }
10610ff414cSEd Maste
10710ff414cSEd Maste *item = (cbor_item_t){
10810ff414cSEd Maste .refcount = 1,
10910ff414cSEd Maste .type = CBOR_TYPE_ARRAY,
11010ff414cSEd Maste .metadata = {.array_metadata = {.type = _CBOR_METADATA_DEFINITE,
11110ff414cSEd Maste .allocated = size,
11210ff414cSEd Maste .end_ptr = 0}},
11310ff414cSEd Maste .data = (unsigned char *)data};
11410ff414cSEd Maste
11510ff414cSEd Maste return item;
11610ff414cSEd Maste }
11710ff414cSEd Maste
cbor_new_indefinite_array(void)118*5d3e7166SEd Maste cbor_item_t *cbor_new_indefinite_array(void) {
119*5d3e7166SEd Maste cbor_item_t *item = _cbor_malloc(sizeof(cbor_item_t));
12010ff414cSEd Maste _CBOR_NOTNULL(item);
12110ff414cSEd Maste
12210ff414cSEd Maste *item = (cbor_item_t){
12310ff414cSEd Maste .refcount = 1,
12410ff414cSEd Maste .type = CBOR_TYPE_ARRAY,
12510ff414cSEd Maste .metadata = {.array_metadata = {.type = _CBOR_METADATA_INDEFINITE,
12610ff414cSEd Maste .allocated = 0,
12710ff414cSEd Maste .end_ptr = 0}},
12810ff414cSEd Maste .data = NULL /* Can be safely realloc-ed */
12910ff414cSEd Maste };
13010ff414cSEd Maste return item;
13110ff414cSEd Maste }
132