1 | /* |
2 | * Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"). |
5 | * You may not use this file except in compliance with the License. |
6 | * A copy of the License is located at |
7 | * |
8 | * http://aws.amazon.com/apache2.0 |
9 | * |
10 | * or in the "license" file accompanying this file. This file is distributed |
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either |
12 | * express or implied. See the License for the specific language governing |
13 | * permissions and limitations under the License. |
14 | */ |
15 | #include <aws/common/string.h> |
16 | |
17 | struct aws_string *aws_string_new_from_c_str(struct aws_allocator *allocator, const char *c_str) { |
18 | AWS_PRECONDITION(allocator && c_str); |
19 | return aws_string_new_from_array(allocator, (const uint8_t *)c_str, strlen(c_str)); |
20 | } |
21 | |
22 | struct aws_string *aws_string_new_from_array(struct aws_allocator *allocator, const uint8_t *bytes, size_t len) { |
23 | AWS_PRECONDITION(allocator); |
24 | AWS_PRECONDITION(AWS_MEM_IS_READABLE(bytes, len)); |
25 | size_t malloc_size; |
26 | if (aws_add_size_checked(sizeof(struct aws_string) + 1, len, &malloc_size)) { |
27 | return NULL; |
28 | } |
29 | struct aws_string *str = aws_mem_acquire(allocator, malloc_size); |
30 | if (!str) { |
31 | return NULL; |
32 | } |
33 | |
34 | /* Fields are declared const, so we need to copy them in like this */ |
35 | *(struct aws_allocator **)(&str->allocator) = allocator; |
36 | *(size_t *)(&str->len) = len; |
37 | memcpy((void *)str->bytes, bytes, len); |
38 | *(uint8_t *)&str->bytes[len] = '\0'; |
39 | AWS_RETURN_WITH_POSTCONDITION(str, aws_string_is_valid(str)); |
40 | } |
41 | |
42 | struct aws_string *aws_string_new_from_string(struct aws_allocator *allocator, const struct aws_string *str) { |
43 | AWS_PRECONDITION(allocator && aws_string_is_valid(str)); |
44 | return aws_string_new_from_array(allocator, str->bytes, str->len); |
45 | } |
46 | |
47 | void aws_string_destroy(struct aws_string *str) { |
48 | AWS_PRECONDITION(!str || aws_string_is_valid(str)); |
49 | if (str && str->allocator) { |
50 | aws_mem_release(str->allocator, str); |
51 | } |
52 | } |
53 | |
54 | void aws_string_destroy_secure(struct aws_string *str) { |
55 | AWS_PRECONDITION(!str || aws_string_is_valid(str)); |
56 | if (str) { |
57 | aws_secure_zero((void *)aws_string_bytes(str), str->len); |
58 | if (str->allocator) { |
59 | aws_mem_release(str->allocator, str); |
60 | } |
61 | } |
62 | } |
63 | |
64 | int aws_string_compare(const struct aws_string *a, const struct aws_string *b) { |
65 | AWS_PRECONDITION(!a || aws_string_is_valid(a)); |
66 | AWS_PRECONDITION(!b || aws_string_is_valid(b)); |
67 | if (a == b) { |
68 | return 0; /* strings identical */ |
69 | } |
70 | if (a == NULL) { |
71 | return -1; |
72 | } |
73 | if (b == NULL) { |
74 | return 1; |
75 | } |
76 | |
77 | size_t len_a = a->len; |
78 | size_t len_b = b->len; |
79 | size_t min_len = len_a < len_b ? len_a : len_b; |
80 | |
81 | int ret = memcmp(aws_string_bytes(a), aws_string_bytes(b), min_len); |
82 | AWS_POSTCONDITION(aws_string_is_valid(a)); |
83 | AWS_POSTCONDITION(aws_string_is_valid(b)); |
84 | if (ret) { |
85 | return ret; /* overlapping characters differ */ |
86 | } |
87 | if (len_a == len_b) { |
88 | return 0; /* strings identical */ |
89 | } |
90 | if (len_a > len_b) { |
91 | return 1; /* string b is first n characters of string a */ |
92 | } |
93 | return -1; /* string a is first n characters of string b */ |
94 | } |
95 | |
96 | int aws_array_list_comparator_string(const void *a, const void *b) { |
97 | if (a == b) { |
98 | return 0; /* strings identical */ |
99 | } |
100 | if (a == NULL) { |
101 | return -1; |
102 | } |
103 | if (b == NULL) { |
104 | return 1; |
105 | } |
106 | const struct aws_string *str_a = *(const struct aws_string **)a; |
107 | const struct aws_string *str_b = *(const struct aws_string **)b; |
108 | return aws_string_compare(str_a, str_b); |
109 | } |
110 | |
111 | /** |
112 | * Returns true if bytes of string are the same, false otherwise. |
113 | */ |
114 | bool aws_string_eq(const struct aws_string *a, const struct aws_string *b) { |
115 | AWS_PRECONDITION(!a || aws_string_is_valid(a)); |
116 | AWS_PRECONDITION(!b || aws_string_is_valid(b)); |
117 | if (a == b) { |
118 | return true; |
119 | } |
120 | if (a == NULL || b == NULL) { |
121 | return false; |
122 | } |
123 | return aws_array_eq(a->bytes, a->len, b->bytes, b->len); |
124 | } |
125 | |
126 | /** |
127 | * Returns true if bytes of string are equivalent, using a case-insensitive comparison. |
128 | */ |
129 | bool aws_string_eq_ignore_case(const struct aws_string *a, const struct aws_string *b) { |
130 | AWS_PRECONDITION(!a || aws_string_is_valid(a)); |
131 | AWS_PRECONDITION(!b || aws_string_is_valid(b)); |
132 | if (a == b) { |
133 | return true; |
134 | } |
135 | if (a == NULL || b == NULL) { |
136 | return false; |
137 | } |
138 | return aws_array_eq_ignore_case(a->bytes, a->len, b->bytes, b->len); |
139 | } |
140 | |
141 | /** |
142 | * Returns true if bytes of string and cursor are the same, false otherwise. |
143 | */ |
144 | bool aws_string_eq_byte_cursor(const struct aws_string *str, const struct aws_byte_cursor *cur) { |
145 | AWS_PRECONDITION(!str || aws_string_is_valid(str)); |
146 | AWS_PRECONDITION(!cur || aws_byte_cursor_is_valid(cur)); |
147 | if (str == NULL && cur == NULL) { |
148 | return true; |
149 | } |
150 | if (str == NULL || cur == NULL) { |
151 | return false; |
152 | } |
153 | return aws_array_eq(str->bytes, str->len, cur->ptr, cur->len); |
154 | } |
155 | |
156 | /** |
157 | * Returns true if bytes of string and cursor are equivalent, using a case-insensitive comparison. |
158 | */ |
159 | |
160 | bool aws_string_eq_byte_cursor_ignore_case(const struct aws_string *str, const struct aws_byte_cursor *cur) { |
161 | AWS_PRECONDITION(!str || aws_string_is_valid(str)); |
162 | AWS_PRECONDITION(!cur || aws_byte_cursor_is_valid(cur)); |
163 | if (str == NULL && cur == NULL) { |
164 | return true; |
165 | } |
166 | if (str == NULL || cur == NULL) { |
167 | return false; |
168 | } |
169 | return aws_array_eq_ignore_case(str->bytes, str->len, cur->ptr, cur->len); |
170 | } |
171 | |
172 | /** |
173 | * Returns true if bytes of string and buffer are the same, false otherwise. |
174 | */ |
175 | bool aws_string_eq_byte_buf(const struct aws_string *str, const struct aws_byte_buf *buf) { |
176 | AWS_PRECONDITION(!str || aws_string_is_valid(str)); |
177 | AWS_PRECONDITION(!buf || aws_byte_buf_is_valid(buf)); |
178 | if (str == NULL && buf == NULL) { |
179 | return true; |
180 | } |
181 | if (str == NULL || buf == NULL) { |
182 | return false; |
183 | } |
184 | return aws_array_eq(str->bytes, str->len, buf->buffer, buf->len); |
185 | } |
186 | |
187 | /** |
188 | * Returns true if bytes of string and buffer are equivalent, using a case-insensitive comparison. |
189 | */ |
190 | |
191 | bool aws_string_eq_byte_buf_ignore_case(const struct aws_string *str, const struct aws_byte_buf *buf) { |
192 | AWS_PRECONDITION(!str || aws_string_is_valid(str)); |
193 | AWS_PRECONDITION(!buf || aws_byte_buf_is_valid(buf)); |
194 | if (str == NULL && buf == NULL) { |
195 | return true; |
196 | } |
197 | if (str == NULL || buf == NULL) { |
198 | return false; |
199 | } |
200 | return aws_array_eq_ignore_case(str->bytes, str->len, buf->buffer, buf->len); |
201 | } |
202 | |
203 | bool aws_string_eq_c_str(const struct aws_string *str, const char *c_str) { |
204 | AWS_PRECONDITION(!str || aws_string_is_valid(str)); |
205 | if (str == NULL && c_str == NULL) { |
206 | return true; |
207 | } |
208 | if (str == NULL || c_str == NULL) { |
209 | return false; |
210 | } |
211 | return aws_array_eq_c_str(str->bytes, str->len, c_str); |
212 | } |
213 | |
214 | /** |
215 | * Returns true if bytes of strings are equivalent, using a case-insensitive comparison. |
216 | */ |
217 | bool aws_string_eq_c_str_ignore_case(const struct aws_string *str, const char *c_str) { |
218 | AWS_PRECONDITION(!str || aws_string_is_valid(str)); |
219 | if (str == NULL && c_str == NULL) { |
220 | return true; |
221 | } |
222 | if (str == NULL || c_str == NULL) { |
223 | return false; |
224 | } |
225 | return aws_array_eq_c_str_ignore_case(str->bytes, str->len, c_str); |
226 | } |
227 | |
228 | bool aws_byte_buf_write_from_whole_string( |
229 | struct aws_byte_buf *AWS_RESTRICT buf, |
230 | const struct aws_string *AWS_RESTRICT src) { |
231 | AWS_PRECONDITION(!buf || aws_byte_buf_is_valid(buf)); |
232 | AWS_PRECONDITION(!src || aws_string_is_valid(src)); |
233 | if (buf == NULL || src == NULL) { |
234 | return false; |
235 | } |
236 | return aws_byte_buf_write(buf, aws_string_bytes(src), src->len); |
237 | } |
238 | |
239 | /** |
240 | * Creates an aws_byte_cursor from an existing string. |
241 | */ |
242 | struct aws_byte_cursor aws_byte_cursor_from_string(const struct aws_string *src) { |
243 | AWS_PRECONDITION(aws_string_is_valid(src)); |
244 | return aws_byte_cursor_from_array(aws_string_bytes(src), src->len); |
245 | } |
246 | |
247 | struct aws_string *aws_string_clone_or_reuse(struct aws_allocator *allocator, const struct aws_string *str) { |
248 | AWS_PRECONDITION(allocator); |
249 | AWS_PRECONDITION(aws_string_is_valid(str)); |
250 | |
251 | if (str->allocator == NULL) { |
252 | /* Since the string cannot be deallocated, we assume that it will remain valid for the lifetime of the |
253 | * application */ |
254 | AWS_POSTCONDITION(aws_string_is_valid(str)); |
255 | return (struct aws_string *)str; |
256 | } |
257 | |
258 | AWS_POSTCONDITION(aws_string_is_valid(str)); |
259 | return aws_string_new_from_string(allocator, str); |
260 | } |
261 | |
262 | int aws_secure_strlen(const char *str, size_t max_read_len, size_t *str_len) { |
263 | AWS_ERROR_PRECONDITION(str && str_len, AWS_ERROR_INVALID_ARGUMENT); |
264 | |
265 | /* why not strnlen? It doesn't work everywhere as it wasn't standardized til C11, and is considered |
266 | * a GNU extension. This should be faster anyways. This should work for ascii and utf8. |
267 | * Any other character sets in use deserve what they get. */ |
268 | char *null_char_ptr = memchr(str, '\0', max_read_len); |
269 | |
270 | if (null_char_ptr) { |
271 | *str_len = null_char_ptr - str; |
272 | return AWS_OP_SUCCESS; |
273 | } |
274 | |
275 | return aws_raise_error(AWS_ERROR_C_STRING_BUFFER_NOT_NULL_TERMINATED); |
276 | } |
277 | |