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 "bytestrings.h"
9 #include <string.h>
10 #include "internal/memory_utils.h"
11
cbor_bytestring_length(const cbor_item_t * item)12 size_t cbor_bytestring_length(const cbor_item_t *item) {
13 assert(cbor_isa_bytestring(item));
14 return item->metadata.bytestring_metadata.length;
15 }
16
cbor_bytestring_handle(const cbor_item_t * item)17 unsigned char *cbor_bytestring_handle(const cbor_item_t *item) {
18 assert(cbor_isa_bytestring(item));
19 return item->data;
20 }
21
cbor_bytestring_is_definite(const cbor_item_t * item)22 bool cbor_bytestring_is_definite(const cbor_item_t *item) {
23 assert(cbor_isa_bytestring(item));
24 return item->metadata.bytestring_metadata.type == _CBOR_METADATA_DEFINITE;
25 }
26
cbor_bytestring_is_indefinite(const cbor_item_t * item)27 bool cbor_bytestring_is_indefinite(const cbor_item_t *item) {
28 return !cbor_bytestring_is_definite(item);
29 }
30
cbor_new_definite_bytestring()31 cbor_item_t *cbor_new_definite_bytestring() {
32 cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
33 _CBOR_NOTNULL(item);
34 *item = (cbor_item_t){
35 .refcount = 1,
36 .type = CBOR_TYPE_BYTESTRING,
37 .metadata = {.bytestring_metadata = {_CBOR_METADATA_DEFINITE, 0}}};
38 return item;
39 }
40
cbor_new_indefinite_bytestring()41 cbor_item_t *cbor_new_indefinite_bytestring() {
42 cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t));
43 _CBOR_NOTNULL(item);
44 *item = (cbor_item_t){
45 .refcount = 1,
46 .type = CBOR_TYPE_BYTESTRING,
47 .metadata = {.bytestring_metadata = {.type = _CBOR_METADATA_INDEFINITE,
48 .length = 0}},
49 .data = _CBOR_MALLOC(sizeof(struct cbor_indefinite_string_data))};
50 _CBOR_DEPENDENT_NOTNULL(item, item->data);
51 *((struct cbor_indefinite_string_data *)item->data) =
52 (struct cbor_indefinite_string_data){
53 .chunk_count = 0,
54 .chunk_capacity = 0,
55 .chunks = NULL,
56 };
57 return item;
58 }
59
cbor_build_bytestring(cbor_data handle,size_t length)60 cbor_item_t *cbor_build_bytestring(cbor_data handle, size_t length) {
61 cbor_item_t *item = cbor_new_definite_bytestring();
62 _CBOR_NOTNULL(item);
63 void *content = _CBOR_MALLOC(length);
64 _CBOR_DEPENDENT_NOTNULL(item, content);
65 memcpy(content, handle, length);
66 cbor_bytestring_set_handle(item, content, length);
67 return item;
68 }
69
cbor_bytestring_set_handle(cbor_item_t * item,cbor_mutable_data CBOR_RESTRICT_POINTER data,size_t length)70 void cbor_bytestring_set_handle(cbor_item_t *item,
71 cbor_mutable_data CBOR_RESTRICT_POINTER data,
72 size_t length) {
73 assert(cbor_isa_bytestring(item));
74 assert(cbor_bytestring_is_definite(item));
75 item->data = data;
76 item->metadata.bytestring_metadata.length = length;
77 }
78
cbor_bytestring_chunks_handle(const cbor_item_t * item)79 cbor_item_t **cbor_bytestring_chunks_handle(const cbor_item_t *item) {
80 assert(cbor_isa_bytestring(item));
81 assert(cbor_bytestring_is_indefinite(item));
82 return ((struct cbor_indefinite_string_data *)item->data)->chunks;
83 }
84
cbor_bytestring_chunk_count(const cbor_item_t * item)85 size_t cbor_bytestring_chunk_count(const cbor_item_t *item) {
86 assert(cbor_isa_bytestring(item));
87 assert(cbor_bytestring_is_indefinite(item));
88 return ((struct cbor_indefinite_string_data *)item->data)->chunk_count;
89 }
90
cbor_bytestring_add_chunk(cbor_item_t * item,cbor_item_t * chunk)91 bool cbor_bytestring_add_chunk(cbor_item_t *item, cbor_item_t *chunk) {
92 assert(cbor_isa_bytestring(item));
93 assert(cbor_bytestring_is_indefinite(item));
94 struct cbor_indefinite_string_data *data =
95 (struct cbor_indefinite_string_data *)item->data;
96 if (data->chunk_count == data->chunk_capacity) {
97 // TODO: Add a test for this
98 if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, data->chunk_capacity)) {
99 return false;
100 }
101
102 size_t new_chunk_capacity =
103 data->chunk_capacity == 0 ? 1
104 : CBOR_BUFFER_GROWTH * (data->chunk_capacity);
105
106 cbor_item_t **new_chunks_data = _cbor_realloc_multiple(
107 data->chunks, sizeof(cbor_item_t *), new_chunk_capacity);
108
109 if (new_chunks_data == NULL) {
110 return false;
111 }
112 data->chunk_capacity = new_chunk_capacity;
113 data->chunks = new_chunks_data;
114 }
115 data->chunks[data->chunk_count++] = cbor_incref(chunk);
116 return true;
117 }
118