Home | History | Annotate | Line # | Download | only in cbor
      1 /*
      2  * Copyright (c) 2014-2019 Pavel Kalvoda <me (at) 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 "maps.h"
      9 #include "internal/memory_utils.h"
     10 
     11 size_t cbor_map_size(const cbor_item_t *item) {
     12   assert(cbor_isa_map(item));
     13   return item->metadata.map_metadata.end_ptr;
     14 }
     15 
     16 size_t cbor_map_allocated(const cbor_item_t *item) {
     17   assert(cbor_isa_map(item));
     18   return item->metadata.map_metadata.allocated;
     19 }
     20 
     21 cbor_item_t *cbor_new_definite_map(size_t size) {
     22   cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
     23   _CBOR_NOTNULL(item);
     24 
     25   *item = (cbor_item_t){
     26       .refcount = 1,
     27       .type = CBOR_TYPE_MAP,
     28       .metadata = {.map_metadata = {.allocated = size,
     29                                     .type = _CBOR_METADATA_DEFINITE,
     30                                     .end_ptr = 0}},
     31       .data = _cbor_alloc_multiple(sizeof(struct cbor_pair), size)};
     32   _CBOR_DEPENDENT_NOTNULL(item, item->data);
     33 
     34   return item;
     35 }
     36 
     37 cbor_item_t *cbor_new_indefinite_map() {
     38   cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
     39   _CBOR_NOTNULL(item);
     40 
     41   *item = (cbor_item_t){
     42       .refcount = 1,
     43       .type = CBOR_TYPE_MAP,
     44       .metadata = {.map_metadata = {.allocated = 0,
     45                                     .type = _CBOR_METADATA_INDEFINITE,
     46                                     .end_ptr = 0}},
     47       .data = NULL};
     48 
     49   return item;
     50 }
     51 
     52 bool _cbor_map_add_key(cbor_item_t *item, cbor_item_t *key) {
     53   assert(cbor_isa_map(item));
     54   struct _cbor_map_metadata *metadata =
     55       (struct _cbor_map_metadata *)&item->metadata;
     56   if (cbor_map_is_definite(item)) {
     57     struct cbor_pair *data = cbor_map_handle(item);
     58     if (metadata->end_ptr >= metadata->allocated) {
     59       /* Don't realloc definite preallocated map */
     60       return false;
     61     }
     62 
     63     data[metadata->end_ptr].key = key;
     64     data[metadata->end_ptr++].value = NULL;
     65   } else {
     66     if (metadata->end_ptr >= metadata->allocated) {
     67       /* Exponential realloc */
     68       // Check for overflows first
     69       // TODO: Explicitly test this
     70       if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, metadata->allocated)) {
     71         return false;
     72       }
     73 
     74       size_t new_allocation = metadata->allocated == 0
     75                                   ? 1
     76                                   : CBOR_BUFFER_GROWTH * metadata->allocated;
     77 
     78       unsigned char *new_data = _cbor_realloc_multiple(
     79           item->data, sizeof(struct cbor_pair), new_allocation);
     80 
     81       if (new_data == NULL) {
     82         return false;
     83       }
     84 
     85       item->data = new_data;
     86       metadata->allocated = new_allocation;
     87     }
     88     struct cbor_pair *data = cbor_map_handle(item);
     89     data[metadata->end_ptr].key = key;
     90     data[metadata->end_ptr++].value = NULL;
     91   }
     92   cbor_incref(key);
     93   return true;
     94 }
     95 
     96 bool _cbor_map_add_value(cbor_item_t *item, cbor_item_t *value) {
     97   assert(cbor_isa_map(item));
     98   cbor_incref(value);
     99   cbor_map_handle(item)[
    100       /* Move one back since we are assuming _add_key (which increased the ptr)
    101        * was the previous operation on this object */
    102       item->metadata.map_metadata.end_ptr - 1]
    103       .value = value;
    104   return true;
    105 }
    106 
    107 bool cbor_map_add(cbor_item_t *item, struct cbor_pair pair) {
    108   assert(cbor_isa_map(item));
    109   if (!_cbor_map_add_key(item, pair.key)) return false;
    110   return _cbor_map_add_value(item, pair.value);
    111 }
    112 
    113 bool cbor_map_is_definite(const cbor_item_t *item) {
    114   assert(cbor_isa_map(item));
    115   return item->metadata.map_metadata.type == _CBOR_METADATA_DEFINITE;
    116 }
    117 
    118 bool cbor_map_is_indefinite(const cbor_item_t *item) {
    119   return !cbor_map_is_definite(item);
    120 }
    121 
    122 struct cbor_pair *cbor_map_handle(const cbor_item_t *item) {
    123   assert(cbor_isa_map(item));
    124   return (struct cbor_pair *)item->data;
    125 }
    126