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
cbor_new_definite_string(void)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
cbor_new_indefinite_string(void)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
cbor_build_string(const char * val)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
cbor_build_stringn(const char * val,size_t length)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
cbor_string_set_handle(cbor_item_t * item,cbor_mutable_data CBOR_RESTRICT_POINTER data,size_t length)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
cbor_string_chunks_handle(const cbor_item_t * item)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
cbor_string_chunk_count(const cbor_item_t * item)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
cbor_string_add_chunk(cbor_item_t * item,cbor_item_t * chunk)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
cbor_string_length(const cbor_item_t * item)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
cbor_string_handle(const cbor_item_t * item)127 unsigned char* cbor_string_handle(const cbor_item_t* item) {
128 CBOR_ASSERT(cbor_isa_string(item));
129 return item->data;
130 }
131
cbor_string_codepoint_count(const cbor_item_t * item)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
cbor_string_is_definite(const cbor_item_t * item)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
cbor_string_is_indefinite(const cbor_item_t * item)142 bool cbor_string_is_indefinite(const cbor_item_t* item) {
143 return !cbor_string_is_definite(item);
144 }
145