xref: /freebsd/contrib/libcbor/src/cbor/bytestrings.c (revision 29fc4075e69fd27de0cded313ac6000165d99f8b)
1 /*
2  * Copyright (c) 2014-2020 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 
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 
17 unsigned char *cbor_bytestring_handle(const cbor_item_t *item) {
18   assert(cbor_isa_bytestring(item));
19   return item->data;
20 }
21 
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 
27 bool cbor_bytestring_is_indefinite(const cbor_item_t *item) {
28   return !cbor_bytestring_is_definite(item);
29 }
30 
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 
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 
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 
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 
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 
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 
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