1/*
2 * Copyright (c) 2014-2019 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 "cbor/common.h"
9#include "arrays.h"
10#include "bytestrings.h"
11#include "data.h"
12#include "floats_ctrls.h"
13#include "ints.h"
14#include "maps.h"
15#include "strings.h"
16#include "tags.h"
17
18bool cbor_isa_uint(const cbor_item_t *item) {
19  return item->type == CBOR_TYPE_UINT;
20}
21
22bool cbor_isa_negint(const cbor_item_t *item) {
23  return item->type == CBOR_TYPE_NEGINT;
24}
25
26bool cbor_isa_bytestring(const cbor_item_t *item) {
27  return item->type == CBOR_TYPE_BYTESTRING;
28}
29
30bool cbor_isa_string(const cbor_item_t *item) {
31  return item->type == CBOR_TYPE_STRING;
32}
33
34bool cbor_isa_array(const cbor_item_t *item) {
35  return item->type == CBOR_TYPE_ARRAY;
36}
37
38bool cbor_isa_map(const cbor_item_t *item) {
39  return item->type == CBOR_TYPE_MAP;
40}
41
42bool cbor_isa_tag(const cbor_item_t *item) {
43  return item->type == CBOR_TYPE_TAG;
44}
45
46bool cbor_isa_float_ctrl(const cbor_item_t *item) {
47  return item->type == CBOR_TYPE_FLOAT_CTRL;
48}
49
50cbor_type cbor_typeof(const cbor_item_t *item) { return item->type; }
51
52bool cbor_is_int(const cbor_item_t *item) {
53  return cbor_isa_uint(item) || cbor_isa_negint(item);
54}
55
56bool cbor_is_bool(const cbor_item_t *item) {
57  return cbor_isa_float_ctrl(item) &&
58         (cbor_ctrl_value(item) == CBOR_CTRL_FALSE ||
59          cbor_ctrl_value(item) == CBOR_CTRL_TRUE);
60}
61
62bool cbor_is_null(const cbor_item_t *item) {
63  return cbor_isa_float_ctrl(item) && cbor_ctrl_value(item) == CBOR_CTRL_NULL;
64}
65
66bool cbor_is_undef(const cbor_item_t *item) {
67  return cbor_isa_float_ctrl(item) && cbor_ctrl_value(item) == CBOR_CTRL_UNDEF;
68}
69
70bool cbor_is_float(const cbor_item_t *item) {
71  return cbor_isa_float_ctrl(item) && !cbor_float_ctrl_is_ctrl(item);
72}
73
74cbor_item_t *cbor_incref(cbor_item_t *item) {
75  item->refcount++;
76  return item;
77}
78
79void cbor_decref(cbor_item_t **item_ref) {
80  cbor_item_t *item = *item_ref;
81  assert(item->refcount > 0);
82  if (--item->refcount == 0) {
83    switch (item->type) {
84      case CBOR_TYPE_UINT:
85        /* Fallthrough */
86      case CBOR_TYPE_NEGINT:
87        /* Combined allocation, freeing the item suffices */
88        { break; }
89      case CBOR_TYPE_BYTESTRING: {
90        if (cbor_bytestring_is_definite(item)) {
91          _CBOR_FREE(item->data);
92        } else {
93          /* We need to decref all chunks */
94          cbor_item_t **handle = cbor_bytestring_chunks_handle(item);
95          for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++)
96            cbor_decref(&handle[i]);
97          _CBOR_FREE(
98              ((struct cbor_indefinite_string_data *)item->data)->chunks);
99          _CBOR_FREE(item->data);
100        }
101        break;
102      }
103      case CBOR_TYPE_STRING: {
104        if (cbor_string_is_definite(item)) {
105          _CBOR_FREE(item->data);
106        } else {
107          /* We need to decref all chunks */
108          cbor_item_t **handle = cbor_string_chunks_handle(item);
109          for (size_t i = 0; i < cbor_string_chunk_count(item); i++)
110            cbor_decref(&handle[i]);
111          _CBOR_FREE(
112              ((struct cbor_indefinite_string_data *)item->data)->chunks);
113          _CBOR_FREE(item->data);
114        }
115        break;
116      }
117      case CBOR_TYPE_ARRAY: {
118        /* Get all items and decref them */
119        cbor_item_t **handle = cbor_array_handle(item);
120        size_t size = cbor_array_size(item);
121        for (size_t i = 0; i < size; i++)
122          if (handle[i] != NULL) cbor_decref(&handle[i]);
123        _CBOR_FREE(item->data);
124        break;
125      }
126      case CBOR_TYPE_MAP: {
127        struct cbor_pair *handle = cbor_map_handle(item);
128        for (size_t i = 0; i < item->metadata.map_metadata.end_ptr;
129             i++, handle++) {
130          cbor_decref(&handle->key);
131          if (handle->value != NULL) cbor_decref(&handle->value);
132        }
133        _CBOR_FREE(item->data);
134        break;
135      };
136      case CBOR_TYPE_TAG: {
137        if (item->metadata.tag_metadata.tagged_item != NULL)
138          cbor_decref(&item->metadata.tag_metadata.tagged_item);
139        _CBOR_FREE(item->data);
140        break;
141      }
142      case CBOR_TYPE_FLOAT_CTRL: {
143        /* Floats have combined allocation */
144        break;
145      }
146    }
147    _CBOR_FREE(item);
148    // TODO
149    *item_ref = NULL;
150  }
151}
152
153void cbor_intermediate_decref(cbor_item_t *item) { cbor_decref(&item); }
154
155size_t cbor_refcount(const cbor_item_t *item) { return item->refcount; }
156
157cbor_item_t *cbor_move(cbor_item_t *item) {
158  item->refcount--;
159  return item;
160}
161