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
13cbor_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
23cbor_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
42cbor_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
53cbor_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
63void 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
81cbor_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
87size_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
93bool 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
120size_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
125unsigned char *cbor_string_handle(const cbor_item_t *item) {
126  CBOR_ASSERT(cbor_isa_string(item));
127  return item->data;
128}
129
130size_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
135bool 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
140bool cbor_string_is_indefinite(const cbor_item_t *item) {
141  return !cbor_string_is_definite(item);
142}
143