1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef COMMON_INTERFACES_OBJECTS_STRING_BASE_STRING_INL2_H
17 #define COMMON_INTERFACES_OBJECTS_STRING_BASE_STRING_INL2_H
18
19 #include "securec.h"
20
21 #include "common_components/base/config.h"
22 #include "common_interfaces/base/mem.h"
23 #include "common_interfaces/objects/string/base_string_declare.h"
24 #include "common_interfaces/objects/string/line_string.h"
25 #include "common_interfaces/objects/string/sliced_string.h"
26 #include "common_interfaces/objects/string/tree_string.h"
27 #include "common_interfaces/objects/utils/utf_utils.h"
28
29 namespace common {
30 template <typename Allocator, objects_traits::enable_if_is_allocate<Allocator, BaseObject *>>
CreateFromUtf8(Allocator && allocator,const uint8_t * utf8Data,uint32_t utf8Len,bool canBeCompress)31 BaseString *BaseString::CreateFromUtf8(Allocator &&allocator, const uint8_t *utf8Data, uint32_t utf8Len,
32 bool canBeCompress)
33 {
34 BaseString *string = nullptr;
35 if (canBeCompress) {
36 string = CreateLineString(allocator, utf8Len, true);
37 DCHECK_CC(string != nullptr);
38 std::copy(utf8Data, utf8Data + utf8Len, string->GetDataUtf8Writable());
39 } else {
40 ASSERT(UtfUtils::Utf8ToUtf16Size(utf8Data, utf8Len) <= utf8Len);
41 string = CreateLineString(allocator, utf8Len, false);
42 ASSERT(string != nullptr);
43 auto utf16Len = UtfUtils::ConvertRegionUtf8ToUtf16(utf8Data, string->GetDataUtf16Writable(),
44 utf8Len, utf8Len);
45 #if !defined(NDEBUG)
46 auto calculatedLen = UtfUtils::Utf8ToUtf16Size(utf8Data, utf8Len);
47 ASSERT_PRINT(utf16Len == calculatedLen,
48 "Bad utf8 to utf16 conversion!, utf16 length: " << utf16Len
49 << ", calculated length: " << calculatedLen);
50 #endif
51 reinterpret_cast<LineString *>(string)->LineString::Trim(utf16Len);
52 }
53
54 ASSERT_PRINT(canBeCompress == CanBeCompressed(string), "Bad input canBeCompress!");
55 return string;
56 }
57
58 template <typename Allocator, objects_traits::enable_if_is_allocate<Allocator, BaseObject *>>
CreateFromUtf8CompressedSubString(Allocator && allocator,const ReadOnlyHandle<BaseString> string,uint32_t offset,uint32_t utf8Len)59 BaseString *BaseString::CreateFromUtf8CompressedSubString(Allocator &&allocator,
60 const ReadOnlyHandle<BaseString> string,
61 uint32_t offset, uint32_t utf8Len)
62 {
63 BaseString *subString = CreateLineString(allocator, utf8Len, true);
64 DCHECK_CC(subString != nullptr);
65
66 auto *utf8Data = string->GetDataUtf8() + offset;
67 std::copy(utf8Data, utf8Data + utf8Len, subString->GetDataUtf8Writable());
68 ASSERT_PRINT(CanBeCompressed(subString), "String cannot be compressed!");
69 return subString;
70 }
71
72 template <typename Allocator, objects_traits::enable_if_is_allocate<Allocator, BaseObject *>>
CreateFromUtf16(Allocator && allocator,const uint16_t * utf16Data,uint32_t utf16Len,bool canBeCompress)73 BaseString *BaseString::CreateFromUtf16(Allocator &&allocator, const uint16_t *utf16Data, uint32_t utf16Len,
74 bool canBeCompress)
75 {
76 auto string = CreateLineString(allocator, utf16Len, canBeCompress);
77 DCHECK_CC(string != nullptr);
78
79 if (canBeCompress) {
80 CopyChars(string->GetDataUtf8Writable(), utf16Data, utf16Len);
81 } else {
82 uint32_t len = utf16Len * (sizeof(uint16_t) / sizeof(uint8_t));
83 if (memcpy_s(string->GetDataUtf16Writable(), len, utf16Data, len) != EOK) {
84 UNREACHABLE();
85 }
86 }
87
88 ASSERT_PRINT(canBeCompress == CanBeCompressed(string), "Bad input canBeCompress!");
89 return string;
90 }
91
92 template <typename Allocator, objects_traits::enable_if_is_allocate<Allocator, BaseObject *>>
CreateLineString(Allocator && allocator,size_t length,bool compressed)93 LineString *BaseString::CreateLineString(Allocator &&allocator, size_t length, bool compressed)
94 {
95 size_t size = compressed ? LineString::ComputeSizeUtf8(length) : LineString::ComputeSizeUtf16(length);
96 BaseObject *obj = std::invoke(allocator, size, CommonType::LINE_STRING);
97 LineString *string = LineString::Cast(obj);
98 string->InitLengthAndFlags(length, compressed);
99 string->SetMixHashcode(0);
100 return string;
101 }
102
103 template <typename Allocator, typename WriteBarrier,
104 objects_traits::enable_if_is_allocate<Allocator, BaseObject *>,
105 objects_traits::enable_if_is_write_barrier<WriteBarrier>>
CreateSlicedString(Allocator && allocate,WriteBarrier && writeBarrier,ReadOnlyHandle<BaseString> parent)106 SlicedString *BaseString::CreateSlicedString(Allocator &&allocate, WriteBarrier &&writeBarrier,
107 ReadOnlyHandle<BaseString> parent)
108 {
109 SlicedString *slicedString = SlicedString::Cast(
110 std::invoke(allocate, SlicedString::SIZE, CommonType::SLICED_STRING));
111 slicedString->SetMixHashcode(0);
112 slicedString->SetParent(std::forward<WriteBarrier>(writeBarrier), parent.GetBaseObject());
113 return slicedString;
114 }
115
116
117 template <typename Allocator, typename WriteBarrier,
118 objects_traits::enable_if_is_allocate<Allocator, BaseObject *>,
119 objects_traits::enable_if_is_write_barrier<WriteBarrier>>
CreateTreeString(Allocator && allocator,WriteBarrier && writeBarrier,ReadOnlyHandle<BaseString> left,ReadOnlyHandle<BaseString> right,uint32_t length,bool compressed)120 TreeString *BaseString::CreateTreeString(Allocator &&allocator, WriteBarrier &&writeBarrier,
121 ReadOnlyHandle<BaseString> left, ReadOnlyHandle<BaseString> right,
122 uint32_t length, bool compressed)
123 {
124 auto string = TreeString::Cast(
125 std::invoke(allocator, TreeString::SIZE, CommonType::TREE_STRING));
126 string->InitLengthAndFlags(length, compressed);
127 string->SetMixHashcode(0);
128 string->SetFirst(writeBarrier, left.GetBaseObject());
129 string->SetSecond(writeBarrier, right.GetBaseObject());
130 return string;
131 }
132
133 template <typename ReadBarrier>
GetUtf8Length(ReadBarrier && readBarrier,bool modify,bool isGetBufferSize)134 size_t BaseString::GetUtf8Length(ReadBarrier &&readBarrier, bool modify, bool isGetBufferSize) const
135 {
136 if (!IsUtf16()) {
137 return GetLength() + 1; // add place for zero in the end
138 }
139 std::vector<uint16_t> tmpBuf;
140 const uint16_t *data = GetUtf16DataFlat(std::forward<ReadBarrier>(readBarrier), this, tmpBuf);
141 return UtfUtils::Utf16ToUtf8Size(data, GetLength(), modify, isGetBufferSize);
142 }
143
144 template <typename ReadBarrier, typename Vec,
145 std::enable_if_t<objects_traits::is_std_vector_of_v<std::decay_t<Vec>, uint16_t>, int>>
GetUtf16DataFlat(ReadBarrier && readBarrier,const BaseString * src,Vec & buf)146 const uint16_t *BaseString::GetUtf16DataFlat(ReadBarrier &&readBarrier, const BaseString *src, Vec &buf)
147 {
148 DCHECK_CC(src->IsUtf16());
149 uint32_t length = src->GetLength();
150 BaseString *string = const_cast<BaseString *>(src);
151 if (string->IsTreeString()) {
152 if (string->IsFlat(std::forward<ReadBarrier>(readBarrier))) {
153 string = BaseString::Cast(
154 TreeString::Cast(string)->GetFirst<BaseObject *>(std::forward<ReadBarrier>(readBarrier)));
155 } else {
156 buf.reserve(length);
157 WriteToFlat(std::forward<ReadBarrier>(readBarrier), string, buf.data(), length);
158 return buf.data();
159 }
160 } else if (string->IsSlicedString()) {
161 SlicedString *str = SlicedString::Cast(string);
162 return BaseString::Cast(str->GetParent<BaseObject *>(std::forward<ReadBarrier>(readBarrier)))->GetDataUtf16() +
163 str->GetStartIndex();
164 }
165 return string->GetDataUtf16();
166 }
167
GetStringType()168 inline CommonType BaseString::GetStringType() const
169 {
170 CommonType type = GetBaseClass()->GetObjectType();
171 ASSERT_PRINT(type >= CommonType::STRING_FIRST && type <= CommonType::STRING_LAST,
172 "Invalid CommonType: " + std::to_string(static_cast<uint8_t>(type)));
173 return type;
174 }
175
176 template <bool verify, typename ReadBarrier>
At(ReadBarrier && readBarrier,int32_t index)177 uint16_t BaseString::At(ReadBarrier &&readBarrier, int32_t index) const
178 {
179 int32_t length = static_cast<int32_t>(GetLength());
180 if constexpr (verify) {
181 if ((index < 0) || (index >= length)) {
182 return 0;
183 }
184 }
185 switch (GetStringType()) {
186 case CommonType::LINE_STRING:
187 return LineString::ConstCast(this)->Get<verify>(index);
188 case CommonType::SLICED_STRING:
189 return SlicedString::ConstCast(this)->Get<verify>(std::forward<ReadBarrier>(readBarrier), index);
190 case CommonType::TREE_STRING:
191 return TreeString::ConstCast(this)->Get<verify>(std::forward<ReadBarrier>(readBarrier), index);
192 default:
193 UNREACHABLE();
194 }
195 }
196
GetData()197 inline uint16_t *BaseString::GetData() const
198 {
199 ASSERT_PRINT(IsLineString(), "BaseString: Read data from not LineString");
200 return LineString::ConstCast(this)->GetData();
201 }
202
GetData()203 inline uint16_t *LineString::GetData() const
204 {
205 return reinterpret_cast<uint16_t *>(ToUintPtr(this) + DATA_OFFSET);
206 }
207
GetDataUtf8()208 inline const uint8_t *BaseString::GetDataUtf8() const
209 {
210 ASSERT_PRINT(IsUtf8(), "BaseString: Read data as utf8 for utf16 string");
211 return reinterpret_cast<uint8_t *>(GetData());
212 }
213
GetDataUtf16()214 inline const uint16_t *BaseString::GetDataUtf16() const
215 {
216 ASSERT_PRINT(IsUtf16(), "BaseString: Read data as utf16 for utf8 string");
217 return GetData();
218 }
219
GetDataUtf8Writable()220 inline uint8_t *BaseString::GetDataUtf8Writable()
221 {
222 ASSERT_PRINT(IsUtf8(), "BaseString: Read data as utf8 for utf16 string");
223 return reinterpret_cast<uint8_t *>(GetData());
224 }
225
GetDataUtf16Writable()226 inline uint16_t *BaseString::GetDataUtf16Writable()
227 {
228 ASSERT_PRINT(IsUtf16(), "BaseString: Read data as utf16 for utf8 string");
229 return GetData();
230 }
231
232
WriteData(uint32_t index,uint16_t src)233 inline void BaseString::WriteData(uint32_t index, uint16_t src)
234 {
235 DCHECK_CC(index < GetLength());
236 DCHECK_CC(IsLineString());
237 LineString::Cast(this)->Set(index, src);
238 }
239
240
241 template <typename ReadBarrier>
IsFlat(ReadBarrier && readBarrier)242 bool BaseString::IsFlat(ReadBarrier &&readBarrier) const
243 {
244 if (!this->IsTreeString()) {
245 return true;
246 }
247 return TreeString::ConstCast(this)->IsFlat(std::forward<ReadBarrier>(readBarrier));
248 }
249
250 template <typename Char, typename ReadBarrier>
251 // CC-OFFNXT(huge_depth, huge_method, G.FUN.01-CPP) solid logic
WriteToFlat(ReadBarrier && readBarrier,BaseString * src,Char * buf,uint32_t maxLength)252 void BaseString::WriteToFlat(ReadBarrier &&readBarrier, BaseString *src, Char *buf, uint32_t maxLength)
253 {
254 // DISALLOW_GARBAGE_COLLECTION;
255 uint32_t length = src->GetLength();
256 if (length == 0) {
257 return;
258 }
259 while (true) {
260 DCHECK_CC(length <= maxLength && length > 0);
261 DCHECK_CC(length <= src->GetLength());
262 switch (src->GetStringType()) {
263 case CommonType::LINE_STRING: {
264 if (src->IsUtf8()) {
265 CopyChars(buf, src->GetDataUtf8(), length);
266 } else {
267 CopyChars(buf, src->GetDataUtf16(), length);
268 }
269 return;
270 }
271 case CommonType::TREE_STRING: {
272 TreeString *treeSrc = TreeString::Cast(src);
273 BaseString *first = BaseString::Cast(
274 treeSrc->GetFirst<BaseObject *>(std::forward<ReadBarrier>(readBarrier)));
275 BaseString *second = BaseString::Cast(
276 treeSrc->GetSecond<BaseObject *>(std::forward<ReadBarrier>(readBarrier)));
277 uint32_t firstLength = first->GetLength();
278 uint32_t secondLength = second->GetLength();
279 // NOLINTNEXTLINE(C_RULE_ID_FUNCTION_NESTING_LEVEL)
280 if (secondLength >= firstLength) {
281 // second string is longer. So recurse over first.
282 WriteToFlat(std::forward<ReadBarrier>(readBarrier), first, buf, maxLength);
283 // CC-OFFNXT(G.FUN.01-CPP) solid logic
284 if (first == second) {
285 CopyChars(buf + firstLength, buf, firstLength);
286 return;
287 }
288 buf += firstLength;
289 maxLength -= firstLength;
290 src = second;
291 length -= firstLength;
292 } else {
293 // first string is longer. So recurse over second.
294 // if src{first:A,second:B} is half flat to {first:A+B,second:empty} by another thread
295 // but the other thread didn't end, and this thread get {first:A+B,second:B}
296 // it may cause write buffer overflower in line 424, buf + firstLength is overflower.
297 // so use 'length > firstLength' instead of 'secondLength > 0'
298 // CC-OFFNXT(G.FUN.01-CPP) solid logic
299 if (length > firstLength) {
300 if (secondLength == 1) {
301 buf[firstLength] = static_cast<Char>(second->At<false>(
302 std::forward<ReadBarrier>(readBarrier), 0));
303 } else if ((second->IsLineString()) && second->IsUtf8()) {
304 CopyChars(buf + firstLength, second->GetDataUtf8(), secondLength);
305 } else {
306 WriteToFlat(std::forward<ReadBarrier>(readBarrier), second, buf + firstLength,
307 maxLength - firstLength);
308 }
309 length -= secondLength;
310 }
311 maxLength = firstLength;
312 src = first;
313 }
314 continue;
315 }
316 case CommonType::SLICED_STRING: {
317 BaseString *parent = BaseString::Cast(
318 SlicedString::Cast(src)->GetParent<BaseObject *>(std::forward<ReadBarrier>(readBarrier)));
319 if (src->IsUtf8()) {
320 CopyChars(buf, parent->GetDataUtf8() + SlicedString::Cast(src)->GetStartIndex(), length);
321 } else {
322 CopyChars(buf, parent->GetDataUtf16() + SlicedString::Cast(src)->GetStartIndex(), length);
323 }
324 return;
325 }
326 default:
327 UNREACHABLE();
328 }
329 }
330 }
331
332
333 template <typename Char, typename ReadBarrier>
WriteToFlatWithPos(ReadBarrier && readBarrier,BaseString * src,Char * buf,uint32_t length,uint32_t pos)334 void BaseString::WriteToFlatWithPos(ReadBarrier &&readBarrier, BaseString *src, Char *buf, uint32_t length,
335 uint32_t pos)
336 {
337 // DISALLOW_GARBAGE_COLLECTION;
338 [[ maybe_unused ]] uint32_t maxLength = src->GetLength();
339 if (length == 0) {
340 return;
341 }
342 while (true) {
343 DCHECK_CC(length + pos <= maxLength && length > 0);
344 DCHECK_CC(length <= src->GetLength());
345 DCHECK_CC(pos >= 0);
346 switch (src->GetStringType()) {
347 case CommonType::LINE_STRING: {
348 if (src->IsUtf8()) {
349 CopyChars(buf, src->GetDataUtf8() + pos, length);
350 } else {
351 CopyChars(buf, src->GetDataUtf16() + pos, length);
352 }
353 return;
354 }
355 case CommonType::TREE_STRING: {
356 TreeString *treeSrc = TreeString::Cast(src);
357 BaseString *first = BaseString::Cast(
358 treeSrc->GetFirst<BaseObject *>(std::forward<ReadBarrier>(readBarrier)));
359 DCHECK_CC(first->IsLineString());
360 src = first;
361 continue;
362 }
363 case CommonType::SLICED_STRING: {
364 BaseString *parent = BaseString::Cast(
365 SlicedString::Cast(src)->GetParent<BaseObject *>(std::forward<ReadBarrier>(readBarrier)));
366 if (src->IsUtf8()) {
367 CopyChars(buf, parent->GetDataUtf8() + SlicedString::Cast(src)->GetStartIndex() + pos, length);
368 } else {
369 CopyChars(buf, parent->GetDataUtf16() + SlicedString::Cast(src)->GetStartIndex() + pos, length);
370 }
371 return;
372 }
373 default:
374 UNREACHABLE();
375 }
376 }
377 }
378
379 // It allows user to copy into buffer even if maxLength < length
380 template <typename ReadBarrier>
WriteUtf8(ReadBarrier && readBarrier,uint8_t * buf,size_t maxLength,bool isWriteBuffer)381 size_t BaseString::WriteUtf8(ReadBarrier &&readBarrier, uint8_t *buf, size_t maxLength, bool isWriteBuffer) const
382 {
383 if (maxLength == 0) {
384 return 1; // maxLength was -1 at napi
385 }
386 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
387 buf[maxLength - 1] = '\0';
388 return CopyDataRegionUtf8(std::forward<ReadBarrier>(readBarrier), buf, 0, GetLength(), maxLength, true,
389 isWriteBuffer) + 1;
390 }
391
392 // It allows user to copy into buffer even if maxLength < length
393 template <typename ReadBarrier>
WriteUtf16(ReadBarrier && readBarrier,uint16_t * buf,uint32_t targetLength,uint32_t bufLength)394 size_t BaseString::WriteUtf16(ReadBarrier &&readBarrier, uint16_t *buf, uint32_t targetLength,
395 uint32_t bufLength) const
396 {
397 if (bufLength == 0) {
398 return 0;
399 }
400 // Returns a number representing a valid backrest length.
401 return CopyDataToUtf16(std::forward<ReadBarrier>(readBarrier), buf, targetLength, bufLength);
402 }
403
404
405 template <typename ReadBarrier>
WriteOneByte(ReadBarrier && readBarrier,uint8_t * buf,size_t maxLength)406 size_t BaseString::WriteOneByte(ReadBarrier &&readBarrier, uint8_t *buf, size_t maxLength) const
407 {
408 if (maxLength == 0) {
409 return 0;
410 }
411 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
412 buf[maxLength - 1] = '\0';
413 uint32_t length = GetLength();
414 if (!IsUtf16()) {
415 std::vector<uint8_t> tmpBuf;
416 const uint8_t *data = GetUtf8DataFlat(std::forward<ReadBarrier>(readBarrier), this, tmpBuf);
417 if (length > maxLength) {
418 length = maxLength;
419 }
420 if (memcpy_s(buf, maxLength, data, length) != EOK) {
421 UNREACHABLE();
422 }
423 return length;
424 }
425
426 std::vector<uint16_t> tmpBuf;
427 const uint16_t *data = GetUtf16DataFlat(std::forward<ReadBarrier>(readBarrier), this, tmpBuf);
428 if (length > maxLength) {
429 return UtfUtils::ConvertRegionUtf16ToLatin1(data, buf, maxLength, maxLength);
430 }
431 return UtfUtils::ConvertRegionUtf16ToLatin1(data, buf, length, maxLength);
432 }
433
434
435 template <typename ReadBarrier>
CopyDataUtf16(ReadBarrier && readBarrier,uint16_t * buf,uint32_t maxLength)436 uint32_t BaseString::CopyDataUtf16(ReadBarrier &&readBarrier, uint16_t *buf, uint32_t maxLength) const
437 {
438 uint32_t length = GetLength();
439 if (length > maxLength) {
440 return 0;
441 }
442 if (IsUtf16()) {
443 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
444 std::vector<uint16_t> tmpBuf;
445 const uint16_t *data = GetUtf16DataFlat(std::forward<ReadBarrier>(readBarrier), this, tmpBuf);
446 if (memcpy_s(buf, maxLength * sizeof(uint16_t), data, length * sizeof(uint16_t)) != EOK) {
447 UNREACHABLE();
448 }
449 return length;
450 }
451 std::vector<uint8_t> tmpBuf;
452 const uint8_t *data = GetUtf8DataFlat(std::forward<ReadBarrier>(readBarrier), this, tmpBuf);
453 return UtfUtils::ConvertRegionUtf8ToUtf16(data, buf, length, maxLength);
454 }
455
456
457 template <typename ReadBarrier, typename Vec,
458 std::enable_if_t<objects_traits::is_std_vector_of_v<std::decay_t<Vec>, uint8_t>, int>>
ToUtf8Span(ReadBarrier && readBarrier,Vec & buf,bool modify,bool cesu8)459 Span<const uint8_t> BaseString::ToUtf8Span(ReadBarrier &&readBarrier, Vec &buf, bool modify, bool cesu8)
460 {
461 Span<const uint8_t> str;
462 uint32_t strLen = GetLength();
463 if (UNLIKELY(IsUtf16())) {
464 using U16Vec = objects_traits::vector_with_same_alloc_t<Vec, uint16_t>;
465 U16Vec tmpBuf;
466 const uint16_t *data = BaseString::GetUtf16DataFlat(std::forward<ReadBarrier>(readBarrier), this, tmpBuf);
467 DCHECK_CC(UtfUtils::Utf16ToUtf8Size(data, strLen, modify, false, cesu8) > 0);
468 size_t len = UtfUtils::Utf16ToUtf8Size(data, strLen, modify, false, cesu8) - 1;
469 buf.reserve(len);
470 len = UtfUtils::ConvertRegionUtf16ToUtf8(data, buf.data(), strLen, len, 0, modify, false, cesu8);
471 str = Span<const uint8_t>(buf.data(), len);
472 } else {
473 const uint8_t *data = BaseString::GetUtf8DataFlat(std::forward<ReadBarrier>(readBarrier), this, buf);
474 str = Span<const uint8_t>(data, strLen);
475 }
476 return str;
477 }
478
479
480 template <typename ReadBarrier, typename Vec,
481 std::enable_if_t<objects_traits::is_std_vector_of_v<std::decay_t<Vec>, uint8_t>, int>>
DebuggerToUtf8Span(ReadBarrier && readBarrier,Vec & buf,bool modify)482 Span<const uint8_t> BaseString::DebuggerToUtf8Span(ReadBarrier &&readBarrier, Vec &buf, bool modify)
483 {
484 Span<const uint8_t> str;
485 uint32_t strLen = GetLength();
486 if (UNLIKELY(IsUtf16())) {
487 using U16Vec = objects_traits::vector_with_same_alloc_t<Vec, uint16_t>;
488 U16Vec tmpBuf;
489 const uint16_t *data = BaseString::GetUtf16DataFlat(std::forward<ReadBarrier>(readBarrier), this, tmpBuf);
490 size_t len = UtfUtils::Utf16ToUtf8Size(data, strLen, modify) - 1;
491 buf.reserve(len);
492 len = UtfUtils::DebuggerConvertRegionUtf16ToUtf8(data, buf.data(), strLen, len, 0, modify);
493 str = Span<const uint8_t>(buf.data(), len);
494 } else {
495 const uint8_t *data = BaseString::GetUtf8DataFlat(std::forward<ReadBarrier>(readBarrier), this, buf);
496 str = Span<const uint8_t>(data, strLen);
497 }
498 return str;
499 }
500
501 // single char copy for loop
502 template <typename DstType, typename SrcType>
CopyChars(DstType * dst,SrcType * src,uint32_t count)503 void BaseString::CopyChars(DstType *dst, SrcType *src, uint32_t count)
504 {
505 Span<SrcType> srcSp(src, count);
506 Span<DstType> dstSp(dst, count);
507 for (uint32_t i = 0; i < count; i++) {
508 dstSp[i] = srcSp[i];
509 }
510 }
511
512 template <typename ReadBarrier, typename Vec,
513 std::enable_if_t<objects_traits::is_std_vector_of_v<std::decay_t<Vec>, uint8_t>, int>>
GetUtf8DataFlat(ReadBarrier && readBarrier,const BaseString * src,Vec & buf)514 const uint8_t *BaseString::GetUtf8DataFlat(ReadBarrier &&readBarrier, const BaseString *src, Vec &buf)
515 {
516 DCHECK_CC(src->IsUtf8());
517 uint32_t length = src->GetLength();
518 BaseString *string = const_cast<BaseString *>(src);
519 if (string->IsTreeString()) {
520 if (string->IsFlat(std::forward<ReadBarrier>(readBarrier))) {
521 string = BaseString::Cast(
522 TreeString::Cast(string)->GetFirst<BaseObject *>(std::forward<ReadBarrier>(readBarrier)));
523 } else {
524 buf.reserve(length);
525 WriteToFlat(std::forward<ReadBarrier>(readBarrier), string, buf.data(), length);
526 return buf.data();
527 }
528 } else if (string->IsSlicedString()) {
529 SlicedString *str = SlicedString::Cast(string);
530 return BaseString::Cast(str->GetParent<BaseObject *>(std::forward<ReadBarrier>(readBarrier)))->GetDataUtf8() +
531 str->GetStartIndex();
532 }
533 return string->GetDataUtf8();
534 }
535
536
537 template <typename ReadBarrier>
CopyDataRegionUtf8(ReadBarrier && readBarrier,uint8_t * buf,size_t start,size_t length,size_t maxLength,bool modify,bool isWriteBuffer)538 size_t BaseString::CopyDataRegionUtf8(ReadBarrier &&readBarrier, uint8_t *buf, size_t start, size_t length,
539 size_t maxLength, bool modify, bool isWriteBuffer) const
540 {
541 uint32_t len = GetLength();
542 if (start + length > len) {
543 return 0;
544 }
545 constexpr size_t TWO_TIMES = 2;
546 if (!IsUtf16()) {
547 if (length > (std::numeric_limits<size_t>::max() / TWO_TIMES - 1)) {
548 // 2: half
549 UNREACHABLE();
550 }
551 std::vector<uint8_t> tmpBuf;
552 const uint8_t *data = GetUtf8DataFlat(std::forward<ReadBarrier>(readBarrier), this, tmpBuf) + start;
553 // Only copy maxLength number of chars into buffer if length > maxLength
554 auto dataLen = std::min(length, maxLength);
555 std::copy(data, data + dataLen, buf);
556 return dataLen;
557 }
558 std::vector<uint16_t> tmpBuf;
559 const uint16_t *data = GetUtf16DataFlat(std::forward<ReadBarrier>(readBarrier), this, tmpBuf);
560 if (length > maxLength) {
561 return UtfUtils::ConvertRegionUtf16ToUtf8(data, buf, maxLength, maxLength, start,
562 modify, isWriteBuffer);
563 }
564 return UtfUtils::ConvertRegionUtf16ToUtf8(data, buf, length, maxLength, start,
565 modify, isWriteBuffer);
566 }
567
568 template <typename ReadBarrier>
CopyDataToUtf16(ReadBarrier && readBarrier,uint16_t * buf,uint32_t length,uint32_t bufLength)569 size_t BaseString::CopyDataToUtf16(ReadBarrier &&readBarrier, uint16_t *buf, uint32_t length,
570 uint32_t bufLength) const
571 {
572 if (IsUtf16()) {
573 std::vector<uint16_t> tmpBuf;
574 const uint16_t *data = BaseString::GetUtf16DataFlat(std::forward<ReadBarrier>(readBarrier), this, tmpBuf);
575 if (length > bufLength) {
576 if (memcpy_s(buf, bufLength * sizeof(uint16_t), data, bufLength * sizeof(uint16_t)) != EOK) {
577 UNREACHABLE();
578 }
579 return bufLength;
580 }
581 if (memcpy_s(buf, bufLength * sizeof(uint16_t), data, length * sizeof(uint16_t)) != EOK) {
582 UNREACHABLE();
583 }
584 return length;
585 }
586 std::vector<uint8_t> tmpBuf;
587 const uint8_t *data = BaseString::GetUtf8DataFlat(std::forward<ReadBarrier>(readBarrier), this, tmpBuf);
588 if (length > bufLength) {
589 return UtfUtils::ConvertRegionUtf8ToUtf16(data, buf, bufLength, bufLength);
590 }
591 return UtfUtils::ConvertRegionUtf8ToUtf16(data, buf, length, bufLength);
592 }
593 } // namespace common
594
595 #endif //COMMON_INTERFACES_OBJECTS_STRING_BASE_STRING_INL2_H