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 "strings.h" 9 #include <string.h> 10 #include "internal/memory_utils.h" 11 12 cbor_item_t *cbor_new_definite_string() { 13 cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t)); 14 _CBOR_NOTNULL(item); 15 *item = (cbor_item_t){ 16 .refcount = 1, 17 .type = CBOR_TYPE_STRING, 18 .metadata = {.string_metadata = {_CBOR_METADATA_DEFINITE, 0}}}; 19 return item; 20 } 21 22 cbor_item_t *cbor_new_indefinite_string() { 23 cbor_item_t *item = _CBOR_MALLOC(sizeof(cbor_item_t)); 24 _CBOR_NOTNULL(item); 25 *item = (cbor_item_t){ 26 .refcount = 1, 27 .type = CBOR_TYPE_STRING, 28 .metadata = {.string_metadata = {.type = _CBOR_METADATA_INDEFINITE, 29 .length = 0}}, 30 .data = _CBOR_MALLOC(sizeof(struct cbor_indefinite_string_data))}; 31 _CBOR_DEPENDENT_NOTNULL(item, item->data); 32 *((struct cbor_indefinite_string_data *)item->data) = 33 (struct cbor_indefinite_string_data){ 34 .chunk_count = 0, 35 .chunk_capacity = 0, 36 .chunks = NULL, 37 }; 38 return item; 39 } 40 41 cbor_item_t *cbor_build_string(const char *val) { 42 cbor_item_t *item = cbor_new_definite_string(); 43 _CBOR_NOTNULL(item); 44 size_t len = strlen(val); 45 unsigned char *handle = _CBOR_MALLOC(len); 46 _CBOR_DEPENDENT_NOTNULL(item, handle); 47 memcpy(handle, val, len); 48 cbor_string_set_handle(item, handle, len); 49 return item; 50 } 51 52 cbor_item_t *cbor_build_stringn(const char *val, size_t length) { 53 cbor_item_t *item = cbor_new_definite_string(); 54 _CBOR_NOTNULL(item); 55 unsigned char *handle = _CBOR_MALLOC(length); 56 _CBOR_DEPENDENT_NOTNULL(item, handle); 57 memcpy(handle, val, length); 58 cbor_string_set_handle(item, handle, length); 59 return item; 60 } 61 62 void cbor_string_set_handle(cbor_item_t *item, 63 cbor_mutable_data CBOR_RESTRICT_POINTER data, 64 size_t length) { 65 assert(cbor_isa_string(item)); 66 assert(cbor_string_is_definite(item)); 67 item->data = data; 68 item->metadata.string_metadata.length = length; 69 } 70 71 cbor_item_t **cbor_string_chunks_handle(const cbor_item_t *item) { 72 assert(cbor_isa_string(item)); 73 assert(cbor_string_is_indefinite(item)); 74 return ((struct cbor_indefinite_string_data *)item->data)->chunks; 75 } 76 77 size_t cbor_string_chunk_count(const cbor_item_t *item) { 78 assert(cbor_isa_string(item)); 79 assert(cbor_string_is_indefinite(item)); 80 return ((struct cbor_indefinite_string_data *)item->data)->chunk_count; 81 } 82 83 bool cbor_string_add_chunk(cbor_item_t *item, cbor_item_t *chunk) { 84 assert(cbor_isa_string(item)); 85 assert(cbor_string_is_indefinite(item)); 86 struct cbor_indefinite_string_data *data = 87 (struct cbor_indefinite_string_data *)item->data; 88 if (data->chunk_count == data->chunk_capacity) { 89 // TODO: Add a test for this 90 if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, data->chunk_capacity)) { 91 return false; 92 } 93 94 size_t new_chunk_capacity = 95 data->chunk_capacity == 0 ? 1 96 : CBOR_BUFFER_GROWTH * (data->chunk_capacity); 97 cbor_item_t **new_chunks_data = _cbor_realloc_multiple( 98 data->chunks, sizeof(cbor_item_t *), new_chunk_capacity); 99 100 if (new_chunks_data == NULL) { 101 return false; 102 } 103 104 data->chunk_capacity = new_chunk_capacity; 105 data->chunks = new_chunks_data; 106 } 107 data->chunks[data->chunk_count++] = cbor_incref(chunk); 108 return true; 109 } 110 111 size_t cbor_string_length(const cbor_item_t *item) { 112 assert(cbor_isa_string(item)); 113 return item->metadata.string_metadata.length; 114 } 115 116 unsigned char *cbor_string_handle(const cbor_item_t *item) { 117 assert(cbor_isa_string(item)); 118 return item->data; 119 } 120 121 size_t cbor_string_codepoint_count(const cbor_item_t *item) { 122 assert(cbor_isa_string(item)); 123 return item->metadata.string_metadata.codepoint_count; 124 } 125 126 bool cbor_string_is_definite(const cbor_item_t *item) { 127 assert(cbor_isa_string(item)); 128 return item->metadata.string_metadata.type == _CBOR_METADATA_DEFINITE; 129 } 130 131 bool cbor_string_is_indefinite(const cbor_item_t *item) { 132 return !cbor_string_is_definite(item); 133 } 134