xref: /freebsd/contrib/libcbor/src/cbor/strings.c (revision a3cefe7f2b4df0f70ff92d4570ce18e517af43ec)
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