Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <AK/ByteBuffer.h>
8#include <AK/DeprecatedFlyString.h>
9#include <AK/DeprecatedString.h>
10#include <AK/Format.h>
11#include <AK/Function.h>
12#include <AK/StdLibExtras.h>
13#include <AK/StringView.h>
14#include <AK/Utf8View.h>
15#include <AK/Vector.h>
16
17namespace AK {
18
19bool DeprecatedString::operator==(DeprecatedFlyString const& fly_string) const
20{
21 return m_impl == fly_string.impl() || view() == fly_string.view();
22}
23
24bool DeprecatedString::operator==(DeprecatedString const& other) const
25{
26 return m_impl == other.impl() || view() == other.view();
27}
28
29bool DeprecatedString::operator==(StringView other) const
30{
31 return view() == other;
32}
33
34bool DeprecatedString::operator<(DeprecatedString const& other) const
35{
36 return view() < other.view();
37}
38
39bool DeprecatedString::operator>(DeprecatedString const& other) const
40{
41 return view() > other.view();
42}
43
44bool DeprecatedString::copy_characters_to_buffer(char* buffer, size_t buffer_size) const
45{
46 // We must fit at least the NUL-terminator.
47 VERIFY(buffer_size > 0);
48
49 size_t characters_to_copy = min(length(), buffer_size - 1);
50 __builtin_memcpy(buffer, characters(), characters_to_copy);
51 buffer[characters_to_copy] = 0;
52
53 return characters_to_copy == length();
54}
55
56DeprecatedString DeprecatedString::isolated_copy() const
57{
58 if (!m_impl)
59 return {};
60 if (!m_impl->length())
61 return empty();
62 char* buffer;
63 auto impl = StringImpl::create_uninitialized(length(), buffer);
64 memcpy(buffer, m_impl->characters(), m_impl->length());
65 return DeprecatedString(move(*impl));
66}
67
68DeprecatedString DeprecatedString::substring(size_t start, size_t length) const
69{
70 if (!length)
71 return DeprecatedString::empty();
72 VERIFY(m_impl);
73 VERIFY(!Checked<size_t>::addition_would_overflow(start, length));
74 VERIFY(start + length <= m_impl->length());
75 return { characters() + start, length };
76}
77
78DeprecatedString DeprecatedString::substring(size_t start) const
79{
80 VERIFY(m_impl);
81 VERIFY(start <= length());
82 return { characters() + start, length() - start };
83}
84
85StringView DeprecatedString::substring_view(size_t start, size_t length) const
86{
87 VERIFY(m_impl);
88 VERIFY(!Checked<size_t>::addition_would_overflow(start, length));
89 VERIFY(start + length <= m_impl->length());
90 return { characters() + start, length };
91}
92
93StringView DeprecatedString::substring_view(size_t start) const
94{
95 VERIFY(m_impl);
96 VERIFY(start <= length());
97 return { characters() + start, length() - start };
98}
99
100Vector<DeprecatedString> DeprecatedString::split(char separator, SplitBehavior split_behavior) const
101{
102 return split_limit(separator, 0, split_behavior);
103}
104
105Vector<DeprecatedString> DeprecatedString::split_limit(char separator, size_t limit, SplitBehavior split_behavior) const
106{
107 if (is_empty())
108 return {};
109
110 Vector<DeprecatedString> v;
111 size_t substart = 0;
112 bool keep_empty = has_flag(split_behavior, SplitBehavior::KeepEmpty);
113 bool keep_separator = has_flag(split_behavior, SplitBehavior::KeepTrailingSeparator);
114 for (size_t i = 0; i < length() && (v.size() + 1) != limit; ++i) {
115 char ch = characters()[i];
116 if (ch == separator) {
117 size_t sublen = i - substart;
118 if (sublen != 0 || keep_empty)
119 v.append(substring(substart, keep_separator ? sublen + 1 : sublen));
120 substart = i + 1;
121 }
122 }
123 size_t taillen = length() - substart;
124 if (taillen != 0 || keep_empty)
125 v.append(substring(substart, taillen));
126 return v;
127}
128
129Vector<StringView> DeprecatedString::split_view(Function<bool(char)> separator, SplitBehavior split_behavior) const
130{
131 if (is_empty())
132 return {};
133
134 Vector<StringView> v;
135 size_t substart = 0;
136 bool keep_empty = has_flag(split_behavior, SplitBehavior::KeepEmpty);
137 bool keep_separator = has_flag(split_behavior, SplitBehavior::KeepTrailingSeparator);
138 for (size_t i = 0; i < length(); ++i) {
139 char ch = characters()[i];
140 if (separator(ch)) {
141 size_t sublen = i - substart;
142 if (sublen != 0 || keep_empty)
143 v.append(substring_view(substart, keep_separator ? sublen + 1 : sublen));
144 substart = i + 1;
145 }
146 }
147 size_t taillen = length() - substart;
148 if (taillen != 0 || keep_empty)
149 v.append(substring_view(substart, taillen));
150 return v;
151}
152
153Vector<StringView> DeprecatedString::split_view(char const separator, SplitBehavior split_behavior) const
154{
155 return split_view([separator](char ch) { return ch == separator; }, split_behavior);
156}
157
158ByteBuffer DeprecatedString::to_byte_buffer() const
159{
160 if (!m_impl)
161 return {};
162 // FIXME: Handle OOM failure.
163 return ByteBuffer::copy(bytes()).release_value_but_fixme_should_propagate_errors();
164}
165
166template<typename T>
167Optional<T> DeprecatedString::to_int(TrimWhitespace trim_whitespace) const
168{
169 return StringUtils::convert_to_int<T>(view(), trim_whitespace);
170}
171
172template Optional<i8> DeprecatedString::to_int(TrimWhitespace) const;
173template Optional<i16> DeprecatedString::to_int(TrimWhitespace) const;
174template Optional<i32> DeprecatedString::to_int(TrimWhitespace) const;
175template Optional<long> DeprecatedString::to_int(TrimWhitespace) const;
176template Optional<long long> DeprecatedString::to_int(TrimWhitespace) const;
177
178template<typename T>
179Optional<T> DeprecatedString::to_uint(TrimWhitespace trim_whitespace) const
180{
181 return StringUtils::convert_to_uint<T>(view(), trim_whitespace);
182}
183
184template Optional<u8> DeprecatedString::to_uint(TrimWhitespace) const;
185template Optional<u16> DeprecatedString::to_uint(TrimWhitespace) const;
186template Optional<u32> DeprecatedString::to_uint(TrimWhitespace) const;
187template Optional<unsigned long> DeprecatedString::to_uint(TrimWhitespace) const;
188template Optional<unsigned long long> DeprecatedString::to_uint(TrimWhitespace) const;
189
190#ifndef KERNEL
191Optional<double> DeprecatedString::to_double(TrimWhitespace trim_whitespace) const
192{
193 return StringUtils::convert_to_floating_point<double>(*this, trim_whitespace);
194}
195
196Optional<float> DeprecatedString::to_float(TrimWhitespace trim_whitespace) const
197{
198 return StringUtils::convert_to_floating_point<float>(*this, trim_whitespace);
199}
200#endif
201
202bool DeprecatedString::starts_with(StringView str, CaseSensitivity case_sensitivity) const
203{
204 return StringUtils::starts_with(*this, str, case_sensitivity);
205}
206
207bool DeprecatedString::starts_with(char ch) const
208{
209 if (is_empty())
210 return false;
211 return characters()[0] == ch;
212}
213
214bool DeprecatedString::ends_with(StringView str, CaseSensitivity case_sensitivity) const
215{
216 return StringUtils::ends_with(*this, str, case_sensitivity);
217}
218
219bool DeprecatedString::ends_with(char ch) const
220{
221 if (is_empty())
222 return false;
223 return characters()[length() - 1] == ch;
224}
225
226DeprecatedString DeprecatedString::repeated(char ch, size_t count)
227{
228 if (!count)
229 return empty();
230 char* buffer;
231 auto impl = StringImpl::create_uninitialized(count, buffer);
232 memset(buffer, ch, count);
233 return *impl;
234}
235
236DeprecatedString DeprecatedString::repeated(StringView string, size_t count)
237{
238 if (!count || string.is_empty())
239 return empty();
240 char* buffer;
241 auto impl = StringImpl::create_uninitialized(count * string.length(), buffer);
242 for (size_t i = 0; i < count; i++)
243 __builtin_memcpy(buffer + i * string.length(), string.characters_without_null_termination(), string.length());
244 return *impl;
245}
246
247DeprecatedString DeprecatedString::bijective_base_from(size_t value, unsigned base, StringView map)
248{
249 value++;
250 if (map.is_null())
251 map = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"sv;
252
253 VERIFY(base >= 2 && base <= map.length());
254
255 // The '8 bits per byte' assumption may need to go?
256 Array<char, round_up_to_power_of_two(sizeof(size_t) * 8 + 1, 2)> buffer;
257 size_t i = 0;
258 do {
259 auto remainder = value % base;
260 auto new_value = value / base;
261 if (remainder == 0) {
262 new_value--;
263 remainder = map.length();
264 }
265
266 buffer[i++] = map[remainder - 1];
267 value = new_value;
268 } while (value > 0);
269
270 for (size_t j = 0; j < i / 2; ++j)
271 swap(buffer[j], buffer[i - j - 1]);
272
273 return DeprecatedString { ReadonlyBytes(buffer.data(), i) };
274}
275
276DeprecatedString DeprecatedString::roman_number_from(size_t value)
277{
278 if (value > 3999)
279 return DeprecatedString::number(value);
280
281 StringBuilder builder;
282
283 while (value > 0) {
284 if (value >= 1000) {
285 builder.append('M');
286 value -= 1000;
287 } else if (value >= 900) {
288 builder.append("CM"sv);
289 value -= 900;
290 } else if (value >= 500) {
291 builder.append('D');
292 value -= 500;
293 } else if (value >= 400) {
294 builder.append("CD"sv);
295 value -= 400;
296 } else if (value >= 100) {
297 builder.append('C');
298 value -= 100;
299 } else if (value >= 90) {
300 builder.append("XC"sv);
301 value -= 90;
302 } else if (value >= 50) {
303 builder.append('L');
304 value -= 50;
305 } else if (value >= 40) {
306 builder.append("XL"sv);
307 value -= 40;
308 } else if (value >= 10) {
309 builder.append('X');
310 value -= 10;
311 } else if (value == 9) {
312 builder.append("IX"sv);
313 value -= 9;
314 } else if (value >= 5 && value <= 8) {
315 builder.append('V');
316 value -= 5;
317 } else if (value == 4) {
318 builder.append("IV"sv);
319 value -= 4;
320 } else if (value <= 3) {
321 builder.append('I');
322 value -= 1;
323 }
324 }
325
326 return builder.to_deprecated_string();
327}
328
329bool DeprecatedString::matches(StringView mask, Vector<MaskSpan>& mask_spans, CaseSensitivity case_sensitivity) const
330{
331 return StringUtils::matches(*this, mask, case_sensitivity, &mask_spans);
332}
333
334bool DeprecatedString::matches(StringView mask, CaseSensitivity case_sensitivity) const
335{
336 return StringUtils::matches(*this, mask, case_sensitivity);
337}
338
339bool DeprecatedString::contains(StringView needle, CaseSensitivity case_sensitivity) const
340{
341 return StringUtils::contains(*this, needle, case_sensitivity);
342}
343
344bool DeprecatedString::contains(char needle, CaseSensitivity case_sensitivity) const
345{
346 return StringUtils::contains(*this, StringView(&needle, 1), case_sensitivity);
347}
348
349bool DeprecatedString::equals_ignoring_ascii_case(StringView other) const
350{
351 return StringUtils::equals_ignoring_ascii_case(view(), other);
352}
353
354DeprecatedString DeprecatedString::reverse() const
355{
356 StringBuilder reversed_string(length());
357 for (size_t i = length(); i-- > 0;) {
358 reversed_string.append(characters()[i]);
359 }
360 return reversed_string.to_deprecated_string();
361}
362
363DeprecatedString escape_html_entities(StringView html)
364{
365 StringBuilder builder;
366 for (size_t i = 0; i < html.length(); ++i) {
367 if (html[i] == '<')
368 builder.append("<"sv);
369 else if (html[i] == '>')
370 builder.append(">"sv);
371 else if (html[i] == '&')
372 builder.append("&"sv);
373 else if (html[i] == '"')
374 builder.append("""sv);
375 else
376 builder.append(html[i]);
377 }
378 return builder.to_deprecated_string();
379}
380
381DeprecatedString::DeprecatedString(DeprecatedFlyString const& string)
382 : m_impl(string.impl())
383{
384}
385
386DeprecatedString DeprecatedString::to_lowercase() const
387{
388 if (!m_impl)
389 return {};
390 return m_impl->to_lowercase();
391}
392
393DeprecatedString DeprecatedString::to_uppercase() const
394{
395 if (!m_impl)
396 return {};
397 return m_impl->to_uppercase();
398}
399
400DeprecatedString DeprecatedString::to_snakecase() const
401{
402 return StringUtils::to_snakecase(*this);
403}
404
405DeprecatedString DeprecatedString::to_titlecase() const
406{
407 return StringUtils::to_titlecase(*this);
408}
409
410DeprecatedString DeprecatedString::invert_case() const
411{
412 return StringUtils::invert_case(*this);
413}
414
415bool DeprecatedString::operator==(char const* cstring) const
416{
417 return view() == cstring;
418}
419
420DeprecatedString DeprecatedString::vformatted(StringView fmtstr, TypeErasedFormatParams& params)
421{
422 StringBuilder builder;
423 MUST(vformat(builder, fmtstr, params));
424 return builder.to_deprecated_string();
425}
426
427Vector<size_t> DeprecatedString::find_all(StringView needle) const
428{
429 return StringUtils::find_all(*this, needle);
430}
431
432DeprecatedStringCodePointIterator DeprecatedString::code_points() const
433{
434 return DeprecatedStringCodePointIterator(*this);
435}
436
437ErrorOr<DeprecatedString> DeprecatedString::from_utf8(ReadonlyBytes bytes)
438{
439 if (!Utf8View(bytes).validate())
440 return Error::from_string_literal("DeprecatedString::from_utf8: Input was not valid UTF-8");
441 return DeprecatedString { StringImpl::create(bytes) };
442}
443
444}