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