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