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