Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / sal / rtl / ustring.cxx
blobdafccb4d7d2838abeaa65172b9b439b4d3e2c8ff
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <cassert>
23 #include <cstdlib>
24 #include <limits>
25 #include <stdexcept>
26 #include <string>
28 #include <osl/diagnose.h>
29 #include <osl/interlck.h>
30 #include <rtl/alloc.h>
31 #include <osl/mutex.h>
32 #include <rtl/tencinfo.h>
34 #include <string.h>
35 #include <sal/alloca.h>
36 #include <sal/log.hxx>
38 #include "hash.hxx"
39 #include "strimp.hxx"
40 #include <rtl/character.hxx>
41 #include <rtl/ustring.h>
43 #include <rtl/math.h>
45 /* ======================================================================= */
47 /* static data to be referenced by all empty strings
48 * the refCount is predefined to 1 and must never become 0 !
50 static rtl_uString const aImplEmpty_rtl_uString =
52 sal_Int32(SAL_STRING_INTERN_FLAG|SAL_STRING_STATIC_FLAG|1), /*sal_Int32 refCount; */
53 0, /*sal_Int32 length; */
54 { 0 } /*sal_Unicode buffer[1];*/
57 /* ======================================================================= */
58 /* These macros are for the "poor-man templates" included from
59 * the strtmpl.cxx just below, used to share code between here and
60 * string.cxx
63 #define IMPL_RTL_IS_USTRING 1
65 #define IMPL_RTL_STRCODE sal_Unicode
66 #define IMPL_RTL_USTRCODE( c ) (c)
67 #define IMPL_RTL_STRNAME( n ) rtl_ustr_ ## n
69 #define IMPL_RTL_STRINGNAME( n ) rtl_uString_ ## n
70 #define IMPL_RTL_STRINGDATA rtl_uString
71 #define IMPL_RTL_EMPTYSTRING aImplEmpty_rtl_uString
73 static void internRelease (rtl_uString *pThis);
75 #if USE_SDT_PROBES
76 #define RTL_LOG_STRING_BITS 16
77 #endif
79 /* ======================================================================= */
81 /* Include String/UString template code */
83 #include "strtmpl.cxx"
85 #undef IMPL_RTL_EMPTYSTRING
86 #undef IMPL_RTL_IS_USTRING
87 #undef IMPL_RTL_STRCODE
88 #undef IMPL_RTL_STRINGDATA
89 #undef IMPL_RTL_STRINGNAME
90 #undef IMPL_RTL_STRNAME
91 #undef IMPL_RTL_USTRCODE
92 #undef RTL_LOG_STRING_BITS
94 sal_Int32 rtl_ustr_indexOfAscii_WithLength(
95 sal_Unicode const * str, sal_Int32 len,
96 char const * subStr, sal_Int32 subLen) SAL_THROW_EXTERN_C()
98 assert(len >= 0);
99 assert(subLen >= 0);
100 if (subLen > 0 && subLen <= len)
102 sal_Unicode const* end = str + len;
103 sal_Unicode const* cursor = str;
105 while(cursor < end)
107 cursor = std::char_traits<sal_Unicode>::find(cursor, end - cursor, *subStr);
108 if(!cursor || (end - cursor < subLen))
110 /* no enough left to actually have a match */
111 break;
113 /* now it is worth trying a full match */
114 if (rtl_ustr_asciil_reverseEquals_WithLength(cursor, subStr, subLen))
116 return cursor - str;
118 cursor += 1;
121 return -1;
124 sal_Int32 rtl_ustr_lastIndexOfAscii_WithLength(
125 sal_Unicode const * str, sal_Int32 len,
126 char const * subStr, sal_Int32 subLen) SAL_THROW_EXTERN_C()
128 assert(len >= 0);
129 assert(subLen >= 0);
130 if (subLen > 0 && subLen <= len) {
131 sal_Int32 i;
132 for (i = len - subLen; i >= 0; --i) {
133 if (rtl_ustr_asciil_reverseEquals_WithLength(
134 str + i, subStr, subLen))
136 return i;
140 return -1;
143 sal_Int32 SAL_CALL rtl_ustr_valueOfFloat(sal_Unicode * pStr, float f)
144 SAL_THROW_EXTERN_C()
146 assert(pStr);
147 rtl_uString * pResult = nullptr;
148 sal_Int32 nLen;
149 rtl_math_doubleToUString(
150 &pResult, nullptr, 0, f, rtl_math_StringFormat_G,
151 RTL_USTR_MAX_VALUEOFFLOAT - RTL_CONSTASCII_LENGTH("-x.E-xxx"), '.', nullptr,
152 0, true);
153 nLen = pResult->length;
154 OSL_ASSERT(nLen < RTL_USTR_MAX_VALUEOFFLOAT);
155 memcpy(pStr, pResult->buffer, (nLen + 1) * sizeof(sal_Unicode));
156 rtl_uString_release(pResult);
157 return nLen;
160 sal_Int32 SAL_CALL rtl_ustr_valueOfDouble(sal_Unicode * pStr, double d)
161 SAL_THROW_EXTERN_C()
163 assert(pStr);
164 rtl_uString * pResult = nullptr;
165 sal_Int32 nLen;
166 rtl_math_doubleToUString(
167 &pResult, nullptr, 0, d, rtl_math_StringFormat_G,
168 RTL_USTR_MAX_VALUEOFDOUBLE - RTL_CONSTASCII_LENGTH("-x.E-xxx"), '.', nullptr,
169 0, true);
170 nLen = pResult->length;
171 OSL_ASSERT(nLen < RTL_USTR_MAX_VALUEOFDOUBLE);
172 memcpy(pStr, pResult->buffer, (nLen + 1) * sizeof(sal_Unicode));
173 rtl_uString_release(pResult);
174 return nLen;
177 namespace {
179 // Avoid -fsanitize=undefined warning e.g. "runtime error: value 1e+99 is
180 // outside the range of representable values of type 'float'":
181 float doubleToFloat(double x) {
182 return
183 x < -std::numeric_limits<float>::max()
184 ? -std::numeric_limits<float>::infinity()
185 : x > std::numeric_limits<float>::max()
186 ? std::numeric_limits<float>::infinity()
187 : static_cast<float>(x);
192 float SAL_CALL rtl_ustr_toFloat(sal_Unicode const * pStr) SAL_THROW_EXTERN_C()
194 assert(pStr);
195 return doubleToFloat(rtl_math_uStringToDouble(pStr,
196 pStr + rtl_ustr_getLength(pStr),
197 '.', 0, nullptr, nullptr));
200 double SAL_CALL rtl_ustr_toDouble(sal_Unicode const * pStr) SAL_THROW_EXTERN_C()
202 assert(pStr);
203 return rtl_math_uStringToDouble(pStr, pStr + rtl_ustr_getLength(pStr), '.',
204 0, nullptr, nullptr);
207 /* ======================================================================= */
209 sal_Int32 SAL_CALL rtl_ustr_ascii_compare( const sal_Unicode* pStr1,
210 const sal_Char* pStr2 )
211 SAL_THROW_EXTERN_C()
213 assert(pStr1);
214 assert(pStr2);
215 sal_Int32 nRet;
216 while ( ((nRet = static_cast<sal_Int32>(*pStr1)-
217 static_cast<sal_Int32>(static_cast<unsigned char>(*pStr2))) == 0) &&
218 *pStr2 )
220 /* Check ASCII range */
221 SAL_WARN_IF( (static_cast<unsigned char>(*pStr2)) > 127, "rtl.string",
222 "rtl_ustr_ascii_compare - Found char > 127" );
223 pStr1++;
224 pStr2++;
227 return nRet;
230 /* ----------------------------------------------------------------------- */
232 sal_Int32 SAL_CALL rtl_ustr_ascii_compare_WithLength( const sal_Unicode* pStr1,
233 sal_Int32 nStr1Len,
234 const sal_Char* pStr2 )
235 SAL_THROW_EXTERN_C()
237 assert(pStr1);
238 assert(nStr1Len >= 0);
239 assert(pStr2);
240 sal_Int32 nRet = 0;
241 while( ((nRet = (nStr1Len ? static_cast<sal_Int32>(*pStr1) : 0)-
242 static_cast<sal_Int32>(static_cast<unsigned char>(*pStr2))) == 0) &&
243 nStr1Len && *pStr2 )
245 /* Check ASCII range */
246 SAL_WARN_IF( (static_cast<unsigned char>(*pStr2)) > 127, "rtl.string",
247 "rtl_ustr_ascii_compare_WithLength - Found char > 127" );
248 pStr1++;
249 pStr2++;
250 nStr1Len--;
253 return nRet;
256 /* ----------------------------------------------------------------------- */
258 sal_Int32 SAL_CALL rtl_ustr_ascii_shortenedCompare_WithLength( const sal_Unicode* pStr1,
259 sal_Int32 nStr1Len,
260 const sal_Char* pStr2,
261 sal_Int32 nShortenedLength )
262 SAL_THROW_EXTERN_C()
264 assert(nStr1Len >= 0);
265 assert(nShortenedLength >= 0);
266 const sal_Unicode* pStr1End = pStr1 + nStr1Len;
267 sal_Int32 nRet;
268 while ( (nShortenedLength > 0) &&
269 (pStr1 < pStr1End) && *pStr2 )
271 /* Check ASCII range */
272 SAL_WARN_IF( (static_cast<unsigned char>(*pStr2)) > 127, "rtl.string",
273 "rtl_ustr_ascii_shortenedCompare_WithLength - Found char > 127" );
275 nRet = static_cast<sal_Int32>(*pStr1)-
276 static_cast<sal_Int32>(static_cast<unsigned char>(*pStr2));
277 if ( nRet != 0 )
278 return nRet;
280 nShortenedLength--;
281 pStr1++;
282 pStr2++;
285 if ( nShortenedLength <= 0 )
286 return 0;
288 if ( *pStr2 )
290 OSL_ENSURE( pStr1 == pStr1End, "pStr1 == pStr1End failed" );
291 // first is a substring of the second string => less (negative value)
292 nRet = -1;
294 else
296 // greater or equal
297 nRet = pStr1End - pStr1;
300 return nRet;
303 /* ----------------------------------------------------------------------- */
305 sal_Int32 SAL_CALL rtl_ustr_asciil_reverseCompare_WithLength( const sal_Unicode* pStr1,
306 sal_Int32 nStr1Len,
307 const sal_Char* pStr2,
308 sal_Int32 nStr2Len )
309 SAL_THROW_EXTERN_C()
311 assert(nStr1Len >= 0 && nStr2Len >= 0);
312 const sal_Unicode* pStr1Run = pStr1+nStr1Len;
313 const sal_Char* pStr2Run = pStr2+nStr2Len;
314 sal_Int32 nRet;
315 while ( (pStr1 < pStr1Run) && (pStr2 < pStr2Run) )
317 /* Check ASCII range */
318 SAL_WARN_IF( (static_cast<unsigned char>(*pStr2)) > 127, "rtl.string",
319 "rtl_ustr_asciil_reverseCompare_WithLength - Found char > 127" );
320 pStr1Run--;
321 pStr2Run--;
322 nRet = static_cast<sal_Int32>(*pStr1Run)- static_cast<sal_Int32>(*pStr2Run);
323 if ( nRet )
324 return nRet;
327 return nStr1Len - nStr2Len;
330 /* ----------------------------------------------------------------------- */
332 sal_Bool SAL_CALL rtl_ustr_asciil_reverseEquals_WithLength( const sal_Unicode* pStr1,
333 const sal_Char* pStr2,
334 sal_Int32 nStrLen )
335 SAL_THROW_EXTERN_C()
337 assert(nStrLen >= 0);
338 const sal_Unicode* pStr1Run = pStr1+nStrLen;
339 const sal_Char* pStr2Run = pStr2+nStrLen;
340 while ( pStr1 < pStr1Run )
342 /* Check ASCII range */
343 SAL_WARN_IF( (static_cast<unsigned char>(*pStr2)) > 127, "rtl.string",
344 "rtl_ustr_asciil_reverseEquals_WithLength - Found char > 127" );
345 pStr1Run--;
346 pStr2Run--;
347 if( *pStr1Run != static_cast<sal_Unicode>(*pStr2Run) )
348 return false;
351 return true;
354 /* ----------------------------------------------------------------------- */
356 sal_Int32 SAL_CALL rtl_ustr_ascii_compareIgnoreAsciiCase( const sal_Unicode* pStr1,
357 const sal_Char* pStr2 )
358 SAL_THROW_EXTERN_C()
360 assert(pStr1);
361 assert(pStr2);
362 sal_Int32 nRet;
363 sal_Int32 c1;
364 sal_Int32 c2;
367 /* Check ASCII range */
368 SAL_WARN_IF( (static_cast<unsigned char>(*pStr2)) > 127, "rtl.string",
369 "rtl_ustr_ascii_compareIgnoreAsciiCase - Found char > 127" );
370 /* If character between 'A' and 'Z', then convert it to lowercase */
371 c1 = static_cast<sal_Int32>(*pStr1);
372 c2 = static_cast<sal_Int32>(static_cast<unsigned char>(*pStr2));
373 if ( (c1 >= 65) && (c1 <= 90) )
374 c1 += 32;
375 if ( (c2 >= 65) && (c2 <= 90) )
376 c2 += 32;
377 nRet = c1-c2;
378 if ( nRet != 0 )
379 return nRet;
381 pStr1++;
382 pStr2++;
384 while ( c2 );
386 return 0;
389 /* ----------------------------------------------------------------------- */
391 sal_Int32 SAL_CALL rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( const sal_Unicode* pStr1,
392 sal_Int32 nStr1Len,
393 const sal_Char* pStr2 )
394 SAL_THROW_EXTERN_C()
396 assert(nStr1Len >= 0);
397 assert(pStr2);
398 sal_Int32 nRet;
399 sal_Int32 c1;
400 sal_Int32 c2;
403 /* Check ASCII range */
404 SAL_WARN_IF( (static_cast<unsigned char>(*pStr2)) > 127, "rtl.string",
405 "rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength - Found char > 127" );
406 if ( !nStr1Len )
407 return *pStr2 == '\0' ? 0 : -1;
409 /* If character between 'A' and 'Z', then convert it to lowercase */
410 c1 = static_cast<sal_Int32>(*pStr1);
411 c2 = static_cast<sal_Int32>(static_cast<unsigned char>(*pStr2));
412 if ( (c1 >= 65) && (c1 <= 90) )
413 c1 += 32;
414 if ( (c2 >= 65) && (c2 <= 90) )
415 c2 += 32;
416 nRet = c1-c2;
417 if ( nRet != 0 )
418 return nRet;
420 pStr1++;
421 pStr2++;
422 nStr1Len--;
424 while( c2 );
426 return 0;
429 sal_Int32 rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths(
430 sal_Unicode const * first, sal_Int32 firstLen,
431 char const * second, sal_Int32 secondLen) SAL_THROW_EXTERN_C()
433 assert(firstLen >= 0 && secondLen >= 0);
434 sal_Int32 i;
435 sal_Int32 len = std::min(firstLen, secondLen);
436 for (i = 0; i < len; ++i) {
437 /* Check ASCII range */
438 SAL_WARN_IF( (static_cast<unsigned char>(*second)) > 127, "rtl.string",
439 "rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths - Found char > 127" );
440 sal_Int32 c1 = *first++;
441 sal_Int32 c2 = static_cast<unsigned char>(*second++);
442 sal_Int32 d;
443 if (c1 >= 65 && c1 <= 90) {
444 c1 += 32;
446 if (c2 >= 65 && c2 <= 90) {
447 c2 += 32;
449 d = c1 - c2;
450 if (d != 0) {
451 return d;
454 return firstLen - secondLen;
457 /* ----------------------------------------------------------------------- */
459 sal_Int32 SAL_CALL rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( const sal_Unicode* pStr1,
460 sal_Int32 nStr1Len,
461 const sal_Char* pStr2,
462 sal_Int32 nShortenedLength )
463 SAL_THROW_EXTERN_C()
465 assert(nStr1Len >= 0);
466 assert(nShortenedLength >= 0);
467 const sal_Unicode* pStr1End = pStr1 + nStr1Len;
468 sal_Int32 nRet;
469 sal_Int32 c1;
470 sal_Int32 c2;
471 while ( (nShortenedLength > 0) &&
472 (pStr1 < pStr1End) && *pStr2 )
474 /* Check ASCII range */
475 SAL_WARN_IF( (static_cast<unsigned char>(*pStr2)) > 127, "rtl.string",
476 "rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength - Found char > 127" );
478 /* If character between 'A' and 'Z', then convert it to lowercase */
479 c1 = static_cast<sal_Int32>(*pStr1);
480 c2 = static_cast<sal_Int32>(static_cast<unsigned char>(*pStr2));
481 if ( (c1 >= 65) && (c1 <= 90) )
482 c1 += 32;
483 if ( (c2 >= 65) && (c2 <= 90) )
484 c2 += 32;
485 nRet = c1-c2;
486 if ( nRet != 0 )
487 return nRet;
489 nShortenedLength--;
490 pStr1++;
491 pStr2++;
494 if ( nShortenedLength <= 0 )
495 return 0;
497 if ( *pStr2 )
499 OSL_ENSURE( pStr1 == pStr1End, "pStr1 == pStr1End failed" );
500 // first is a substring of the second string => less (negative value)
501 nRet = -1;
503 else
505 // greater or equal
506 nRet = pStr1End - pStr1;
509 return nRet;
512 /* ----------------------------------------------------------------------- */
514 void SAL_CALL rtl_uString_newFromAscii( rtl_uString** ppThis,
515 const sal_Char* pCharStr )
516 SAL_THROW_EXTERN_C()
518 assert(ppThis);
519 sal_Int32 nLen;
521 if ( pCharStr )
523 const sal_Char* pTempStr = pCharStr;
524 while( *pTempStr )
525 pTempStr++;
526 nLen = pTempStr-pCharStr;
528 else
529 nLen = 0;
531 if ( !nLen )
533 rtl_uString_new( ppThis );
534 return;
537 if ( *ppThis )
538 rtl_uString_release( *ppThis );
540 *ppThis = rtl_uString_ImplAlloc( nLen );
541 OSL_ASSERT(*ppThis != nullptr);
542 if ( *ppThis )
544 sal_Unicode* pBuffer = (*ppThis)->buffer;
547 assert(static_cast<unsigned char>(*pCharStr) < 0x80); // ASCII range
548 *pBuffer = *pCharStr;
549 pBuffer++;
550 pCharStr++;
552 while ( *pCharStr );
554 RTL_LOG_STRING_NEW( *ppThis );
558 void SAL_CALL rtl_uString_newFromCodePoints(
559 rtl_uString ** newString, sal_uInt32 const * codePoints,
560 sal_Int32 codePointCount) SAL_THROW_EXTERN_C()
562 sal_Int32 n;
563 sal_Int32 i;
564 sal_Unicode * p;
565 assert(newString != nullptr);
566 assert((codePoints != nullptr || codePointCount == 0) && codePointCount >= 0);
567 if (codePointCount == 0) {
568 rtl_uString_new(newString);
569 return;
571 if (*newString != nullptr) {
572 rtl_uString_release(*newString);
574 n = codePointCount;
575 for (i = 0; i < codePointCount; ++i) {
576 OSL_ASSERT(rtl::isUnicodeCodePoint(codePoints[i]));
577 if (codePoints[i] >= 0x10000) {
578 ++n;
581 /* Builds on the assumption that sal_Int32 uses 32 bit two's complement
582 representation with wrap around (the necessary number of UTF-16 code
583 units will be no larger than 2 * SAL_MAX_INT32, represented as
584 sal_Int32 -2): */
585 if (n < 0) {
586 // coverity[dead_error_begin] - assumes wrap around
587 *newString = nullptr;
588 return;
590 *newString = rtl_uString_ImplAlloc(n);
591 if (*newString == nullptr) {
592 return;
594 p = (*newString)->buffer;
595 for (i = 0; i < codePointCount; ++i) {
596 p += rtl::splitSurrogates(codePoints[i], p);
598 RTL_LOG_STRING_NEW( *newString );
601 void rtl_uString_newConcatAsciiL(
602 rtl_uString ** newString, rtl_uString * left, char const * right,
603 sal_Int32 rightLength)
605 assert(newString != nullptr);
606 assert(left != nullptr);
607 assert(right != nullptr);
608 assert(rightLength >= 0);
609 if (left->length > std::numeric_limits<sal_Int32>::max() - rightLength) {
610 #if !defined(__COVERITY__)
611 throw std::length_error("rtl_uString_newConcatAsciiL");
612 #else
613 //coverity doesn't report std::bad_alloc as an unhandled exception when
614 //potentially thrown from destructors but does report std::length_error
615 throw std::bad_alloc();
616 #endif
618 sal_Int32 n = left->length + rightLength;
619 rtl_uString_assign(newString, left);
620 rtl_uString_ensureCapacity(newString, n);
621 sal_Unicode * p = (*newString)->buffer + (*newString)->length;
622 for (sal_Int32 i = 0; i != rightLength; ++i) {
623 p[i] = static_cast<unsigned char>(right[i]);
625 (*newString)->buffer[n] = 0;
626 (*newString)->length = n;
629 void rtl_uString_newConcatUtf16L(
630 rtl_uString ** newString, rtl_uString * left, sal_Unicode const * right,
631 sal_Int32 rightLength)
633 assert(newString != nullptr);
634 assert(left != nullptr);
635 assert(right != nullptr);
636 assert(rightLength >= 0);
637 if (left->length > std::numeric_limits<sal_Int32>::max() - rightLength) {
638 #if !defined(__COVERITY__)
639 throw std::length_error("rtl_uString_newConcatUtf16L");
640 #else
641 //coverity doesn't report std::bad_alloc as an unhandled exception when
642 //potentially thrown from destructors but does report std::length_error
643 throw std::bad_alloc();
644 #endif
646 sal_Int32 n = left->length + rightLength;
647 rtl_uString_assign(newString, left);
648 rtl_uString_ensureCapacity(newString, n);
649 memcpy(
650 (*newString)->buffer + (*newString)->length, right,
651 rightLength * sizeof (sal_Unicode));
652 (*newString)->buffer[n] = 0;
653 (*newString)->length = n;
656 /* ======================================================================= */
658 static int rtl_ImplGetFastUTF8UnicodeLen( const sal_Char* pStr, sal_Int32 nLen, bool * ascii )
660 int n;
661 const sal_Char* pEndStr;
663 *ascii = true;
664 n = 0;
665 pEndStr = pStr+nLen;
666 while ( pStr < pEndStr )
668 unsigned char c = static_cast<unsigned char>(*pStr);
670 if ( !(c & 0x80) )
671 pStr++;
672 else
674 if ( (c & 0xE0) == 0xC0 )
675 pStr += 2;
676 else if ( (c & 0xF0) == 0xE0 )
677 pStr += 3;
678 else if ( (c & 0xF8) == 0xF0 )
679 pStr += 4;
680 else if ( (c & 0xFC) == 0xF8 )
681 pStr += 5;
682 else if ( (c & 0xFE) == 0xFC )
683 pStr += 6;
684 else
685 pStr++;
686 *ascii = false;
689 n++;
692 return n;
695 /* ----------------------------------------------------------------------- */
697 static void rtl_string2UString_status( rtl_uString** ppThis,
698 const sal_Char* pStr,
699 sal_Int32 nLen,
700 rtl_TextEncoding eTextEncoding,
701 sal_uInt32 nCvtFlags,
702 sal_uInt32 *pInfo )
704 OSL_ENSURE(nLen == 0 || rtl_isOctetTextEncoding(eTextEncoding),
705 "rtl_string2UString_status() - Wrong TextEncoding" );
707 if ( !nLen )
709 rtl_uString_new( ppThis );
710 if (pInfo != nullptr) {
711 *pInfo = 0;
714 else
716 if ( *ppThis )
717 rtl_uString_release( *ppThis );
719 /* Optimization for US-ASCII */
720 if ( eTextEncoding == RTL_TEXTENCODING_ASCII_US )
722 sal_Unicode* pBuffer;
723 *ppThis = rtl_uString_ImplAlloc( nLen );
724 if (*ppThis == nullptr) {
725 if (pInfo != nullptr) {
726 *pInfo = RTL_TEXTTOUNICODE_INFO_ERROR |
727 RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL;
729 return;
731 pBuffer = (*ppThis)->buffer;
732 sal_Int32 nLenCopy(nLen);
733 const sal_Char *pStrCopy(pStr);
736 /* Check ASCII range */
737 if (static_cast<unsigned char>(*pStrCopy) > 127)
739 rtl_uString_release(*ppThis);
740 goto retry; // cancel loop - try again with the converter
743 *pBuffer = *pStrCopy;
744 pBuffer++;
745 pStrCopy++;
746 nLenCopy--;
748 while (nLenCopy);
749 if (pInfo != nullptr) {
750 *pInfo = 0;
752 RTL_LOG_STRING_NEW( *ppThis );
753 return;
755 retry:
757 rtl_uString* pTemp;
758 rtl_uString* pTemp2 = nullptr;
759 rtl_TextToUnicodeConverter hConverter;
760 sal_uInt32 nInfo;
761 sal_Size nSrcBytes;
762 sal_Size nDestChars;
763 sal_Size nNewLen;
765 /* Optimization for UTF-8 - we try to calculate the exact length */
766 /* For all other encoding we try the maximum - and reallocate
767 the buffer if needed */
768 if ( eTextEncoding == RTL_TEXTENCODING_UTF8 )
770 bool ascii;
771 nNewLen = rtl_ImplGetFastUTF8UnicodeLen( pStr, nLen, &ascii );
772 /* Includes the string only ASCII, then we could copy
773 the buffer faster */
774 if ( ascii )
776 sal_Unicode* pBuffer;
777 *ppThis = rtl_uString_ImplAlloc( nLen );
778 if (*ppThis == nullptr)
780 if (pInfo != nullptr) {
781 *pInfo = RTL_TEXTTOUNICODE_INFO_ERROR |
782 RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL;
784 return;
786 pBuffer = (*ppThis)->buffer;
789 assert((static_cast<unsigned char>(*pStr)) <= 127);
790 *pBuffer = *pStr;
791 pBuffer++;
792 pStr++;
793 nLen--;
795 while ( nLen );
796 if (pInfo != nullptr) {
797 *pInfo = 0;
799 RTL_LOG_STRING_NEW( *ppThis );
800 return;
803 else
804 nNewLen = nLen;
806 nCvtFlags |= RTL_TEXTTOUNICODE_FLAGS_FLUSH;
807 hConverter = rtl_createTextToUnicodeConverter( eTextEncoding );
809 pTemp = rtl_uString_ImplAlloc( nNewLen );
810 if (pTemp == nullptr) {
811 if (pInfo != nullptr) {
812 *pInfo = RTL_TEXTTOUNICODE_INFO_ERROR |
813 RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL;
815 return;
817 nDestChars = rtl_convertTextToUnicode( hConverter, nullptr,
818 pStr, nLen,
819 pTemp->buffer, nNewLen,
820 nCvtFlags,
821 &nInfo, &nSrcBytes );
823 /* Buffer not big enough, try again with enough space */
824 /* Shouldn't be the case, but if we get textencoding which
825 could results in more unicode characters we have this
826 code here. Could be the case for apple encodings */
827 while ( nInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL )
829 rtl_freeString( pTemp );
830 nNewLen += 8;
831 pTemp = rtl_uString_ImplAlloc( nNewLen );
832 if (pTemp == nullptr) {
833 if (pInfo != nullptr) {
834 *pInfo = RTL_TEXTTOUNICODE_INFO_ERROR |
835 RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL;
837 return;
839 nDestChars = rtl_convertTextToUnicode( hConverter, nullptr,
840 pStr, nLen,
841 pTemp->buffer, nNewLen,
842 nCvtFlags,
843 &nInfo, &nSrcBytes );
846 if (pInfo)
847 *pInfo = nInfo;
849 /* Set the buffer to the correct size or if there is too
850 much overhead, reallocate to the correct size */
851 if ( nNewLen > nDestChars+8 )
853 pTemp2 = rtl_uString_ImplAlloc( nDestChars );
855 if (pTemp2 != nullptr)
857 rtl_str_ImplCopy(pTemp2->buffer, pTemp->buffer, nDestChars);
858 rtl_freeString(pTemp);
859 pTemp = pTemp2;
861 else
863 pTemp->length = nDestChars;
864 pTemp->buffer[nDestChars] = 0;
867 rtl_destroyTextToUnicodeConverter( hConverter );
868 *ppThis = pTemp;
870 /* Results the conversion in an empty buffer -
871 create an empty string */
872 if ( pTemp && !nDestChars )
873 rtl_uString_new( ppThis );
876 RTL_LOG_STRING_NEW( *ppThis );
879 void SAL_CALL rtl_string2UString( rtl_uString** ppThis,
880 const sal_Char* pStr,
881 sal_Int32 nLen,
882 rtl_TextEncoding eTextEncoding,
883 sal_uInt32 nCvtFlags ) SAL_THROW_EXTERN_C()
885 assert(ppThis);
886 assert(nLen >= 0);
887 rtl_string2UString_status( ppThis, pStr, nLen, eTextEncoding,
888 nCvtFlags, nullptr );
891 /* ----------------------------------------------------------------------- */
893 enum StrLifecycle {
894 CANNOT_RETURN,
895 CAN_RETURN = 1
898 static oslMutex
899 getInternMutex()
901 static oslMutex pPoolGuard = osl_createMutex();
903 return pPoolGuard;
906 /* returns true if we found a dup in the pool */
907 static void rtl_ustring_intern_internal( rtl_uString ** newStr,
908 rtl_uString * str,
909 StrLifecycle can_return )
911 oslMutex pPoolMutex;
913 pPoolMutex = getInternMutex();
915 osl_acquireMutex( pPoolMutex );
917 *newStr = rtl_str_hash_intern (str, can_return);
919 osl_releaseMutex( pPoolMutex );
921 RTL_LOG_STRING_INTERN_NEW(*newStr, str);
923 if( can_return && *newStr != str )
924 { /* we dupped, then found a match */
925 rtl_freeString( str );
929 void SAL_CALL rtl_uString_intern( rtl_uString ** newStr,
930 rtl_uString * str) SAL_THROW_EXTERN_C()
932 assert(newStr);
933 assert(str);
934 if (SAL_STRING_IS_INTERN(str))
936 IMPL_RTL_ACQUIRE( str );
937 *newStr = str;
939 else
941 rtl_uString *pOrg = *newStr;
942 *newStr = nullptr;
943 rtl_ustring_intern_internal( newStr, str, CANNOT_RETURN );
944 if (pOrg)
945 rtl_uString_release (pOrg);
949 static int rtl_canGuessUOutputLength( int len, rtl_TextEncoding eTextEncoding )
951 // FIXME: Maybe we should use a bit flag in the higher bits of the
952 // eTextEncoding value itself to determine the encoding type. But if we
953 // do, be sure to mask the value in certain places that expect the values
954 // to be numbered serially from 0 and up. One such place is
955 // Impl_getTextEncodingData().
957 switch ( eTextEncoding )
959 // 1 to 1 (with no zero elements)
960 case RTL_TEXTENCODING_IBM_437:
961 case RTL_TEXTENCODING_IBM_850:
962 case RTL_TEXTENCODING_IBM_860:
963 case RTL_TEXTENCODING_IBM_861:
964 case RTL_TEXTENCODING_IBM_863:
965 case RTL_TEXTENCODING_IBM_865:
966 return len;
967 break;
969 return 0;
972 void SAL_CALL rtl_uString_internConvert( rtl_uString ** newStr,
973 const sal_Char * str,
974 sal_Int32 len,
975 rtl_TextEncoding eTextEncoding,
976 sal_uInt32 convertFlags,
977 sal_uInt32 * pInfo )
978 SAL_THROW_EXTERN_C()
980 assert(newStr);
981 assert(len >= 0);
982 rtl_uString *scratch;
984 if (*newStr)
986 rtl_uString_release (*newStr);
987 *newStr = nullptr;
990 if ( len < 256 )
991 { // try various optimisations
992 sal_Int32 ulen;
993 if ( eTextEncoding == RTL_TEXTENCODING_ASCII_US )
995 int i;
996 rtl_uString *pScratch;
997 pScratch = static_cast< rtl_uString * >(
998 alloca(sizeof (rtl_uString) + len * sizeof (sal_Unicode)));
999 for (i = 0; i < len; i++)
1001 /* Check ASCII range */
1002 SAL_WARN_IF( (static_cast<unsigned char>(str[i])) > 127, "rtl.string",
1003 "rtl_ustring_internConvert() - Found char > 127 and RTL_TEXTENCODING_ASCII_US is specified" );
1004 pScratch->buffer[i] = str[i];
1006 pScratch->length = len;
1007 rtl_ustring_intern_internal( newStr, pScratch, CANNOT_RETURN );
1008 return;
1010 if ( (ulen = rtl_canGuessUOutputLength(len, eTextEncoding)) != 0 )
1012 rtl_uString *pScratch;
1013 rtl_TextToUnicodeConverter hConverter;
1014 sal_Size nSrcBytes;
1015 sal_uInt32 nInfo;
1017 pScratch = static_cast< rtl_uString * >(
1018 alloca(
1019 sizeof (rtl_uString) + ulen * sizeof (sal_Unicode)));
1021 hConverter = rtl_createTextToUnicodeConverter( eTextEncoding );
1022 rtl_convertTextToUnicode(
1023 hConverter, nullptr, str, len, pScratch->buffer, ulen, convertFlags, &nInfo, &nSrcBytes );
1024 rtl_destroyTextToUnicodeConverter( hConverter );
1026 if (pInfo)
1027 *pInfo = nInfo;
1029 pScratch->length = ulen;
1030 rtl_ustring_intern_internal( newStr, pScratch, CANNOT_RETURN );
1031 return;
1034 /* FIXME: we want a nice UTF-8 / alloca shortcut here */
1037 scratch = nullptr;
1038 rtl_string2UString_status( &scratch, str, len, eTextEncoding, convertFlags,
1039 pInfo );
1040 if (!scratch) {
1041 return;
1043 rtl_ustring_intern_internal( newStr, scratch, CAN_RETURN );
1046 static void
1047 internRelease (rtl_uString *pThis)
1049 oslMutex pPoolMutex;
1051 rtl_uString *pFree = nullptr;
1052 if ( SAL_STRING_REFCOUNT(
1053 osl_atomic_decrement( &(pThis->refCount) ) ) == 0)
1055 RTL_LOG_STRING_INTERN_DELETE(pThis);
1056 pPoolMutex = getInternMutex();
1057 osl_acquireMutex( pPoolMutex );
1059 rtl_str_hash_remove (pThis);
1061 /* May have been separately acquired */
1062 if ( SAL_STRING_REFCOUNT(
1063 osl_atomic_increment( &(pThis->refCount) ) ) == 1 )
1065 /* we got the last ref */
1066 pFree = pThis;
1068 else /* very unusual */
1070 internRelease (pThis);
1073 osl_releaseMutex( pPoolMutex );
1075 if (pFree)
1076 rtl_freeString (pFree);
1079 sal_uInt32 SAL_CALL rtl_uString_iterateCodePoints(
1080 rtl_uString const * string, sal_Int32 * indexUtf16,
1081 sal_Int32 incrementCodePoints)
1083 sal_Int32 n;
1084 sal_Unicode cu;
1085 sal_uInt32 cp;
1086 assert(string != nullptr && indexUtf16 != nullptr);
1087 n = *indexUtf16;
1088 assert(n >= 0 && n <= string->length);
1089 while (incrementCodePoints < 0) {
1090 assert(n > 0);
1091 cu = string->buffer[--n];
1092 if (rtl::isLowSurrogate(cu) && n != 0 &&
1093 rtl::isHighSurrogate(string->buffer[n - 1]))
1095 --n;
1097 ++incrementCodePoints;
1099 assert(n >= 0 && n < string->length);
1100 cu = string->buffer[n];
1101 if (rtl::isHighSurrogate(cu) && string->length - n >= 2 &&
1102 rtl::isLowSurrogate(string->buffer[n + 1]))
1104 cp = rtl::combineSurrogates(cu, string->buffer[n + 1]);
1105 } else {
1106 cp = cu;
1108 while (incrementCodePoints > 0) {
1109 assert(n < string->length);
1110 cu = string->buffer[n++];
1111 if (rtl::isHighSurrogate(cu) && n != string->length &&
1112 rtl::isLowSurrogate(string->buffer[n]))
1114 ++n;
1116 --incrementCodePoints;
1118 assert(n >= 0 && n <= string->length);
1119 *indexUtf16 = n;
1120 return cp;
1123 sal_Bool rtl_convertStringToUString(
1124 rtl_uString ** target, char const * source, sal_Int32 length,
1125 rtl_TextEncoding encoding, sal_uInt32 flags) SAL_THROW_EXTERN_C()
1127 assert(target);
1128 assert(length >= 0);
1129 sal_uInt32 info;
1130 rtl_string2UString_status(target, source, length, encoding, flags, &info);
1131 return (info & RTL_TEXTTOUNICODE_INFO_ERROR) == 0;
1134 void rtl_uString_newReplaceFirst(
1135 rtl_uString ** newStr, rtl_uString * str, rtl_uString const * from,
1136 rtl_uString const * to, sal_Int32 * index) SAL_THROW_EXTERN_C()
1138 assert(str != nullptr);
1139 assert(index != nullptr);
1140 assert(*index >= 0 && *index <= str->length);
1141 assert(from != nullptr);
1142 assert(to != nullptr);
1143 sal_Int32 i = rtl_ustr_indexOfStr_WithLength(
1144 str->buffer + *index, str->length - *index, from->buffer, from->length);
1145 if (i == -1) {
1146 rtl_uString_assign(newStr, str);
1147 } else {
1148 assert(i <= str->length - *index);
1149 i += *index;
1150 assert(from->length <= str->length);
1151 if (str->length - from->length > SAL_MAX_INT32 - to->length) {
1152 std::abort();
1154 sal_Int32 n = str->length - from->length + to->length;
1155 rtl_uString_acquire(str); // in case *newStr == str
1156 rtl_uString_new_WithLength(newStr, n);
1157 if (n != 0) {
1158 (*newStr)->length = n;
1159 assert(i >= 0 && i < str->length);
1160 memcpy(
1161 (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
1162 memcpy(
1163 (*newStr)->buffer + i, to->buffer,
1164 to->length * sizeof (sal_Unicode));
1165 memcpy(
1166 (*newStr)->buffer + i + to->length,
1167 str->buffer + i + from->length,
1168 (str->length - i - from->length) * sizeof (sal_Unicode));
1170 rtl_uString_release(str);
1172 *index = i;
1175 void rtl_uString_newReplaceFirstAsciiL(
1176 rtl_uString ** newStr, rtl_uString * str, char const * from,
1177 sal_Int32 fromLength, rtl_uString const * to, sal_Int32 * index)
1178 SAL_THROW_EXTERN_C()
1180 assert(str != nullptr);
1181 assert(index != nullptr);
1182 assert(*index >= 0 && *index <= str->length);
1183 assert(fromLength >= 0);
1184 assert(to != nullptr);
1185 sal_Int32 i = rtl_ustr_indexOfAscii_WithLength(
1186 str->buffer + *index, str->length - *index, from, fromLength);
1187 if (i == -1) {
1188 rtl_uString_assign(newStr, str);
1189 } else {
1190 assert(i <= str->length - *index);
1191 i += *index;
1192 assert(fromLength <= str->length);
1193 if (str->length - fromLength > SAL_MAX_INT32 - to->length) {
1194 std::abort();
1196 sal_Int32 n = str->length - fromLength + to->length;
1197 rtl_uString_acquire(str); // in case *newStr == str
1198 rtl_uString_new_WithLength(newStr, n);
1199 if (n != 0) {
1200 (*newStr)->length = n;
1201 assert(i >= 0 && i < str->length);
1202 memcpy(
1203 (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
1204 memcpy(
1205 (*newStr)->buffer + i, to->buffer,
1206 to->length * sizeof (sal_Unicode));
1207 memcpy(
1208 (*newStr)->buffer + i + to->length,
1209 str->buffer + i + fromLength,
1210 (str->length - i - fromLength) * sizeof (sal_Unicode));
1212 rtl_uString_release(str);
1214 *index = i;
1217 void rtl_uString_newReplaceFirstToAsciiL(
1218 rtl_uString ** newStr, rtl_uString * str, rtl_uString const * from,
1219 char const * to, sal_Int32 toLength, sal_Int32 * index)
1220 SAL_THROW_EXTERN_C()
1222 assert(str != nullptr);
1223 assert(index != nullptr);
1224 assert(*index >= 0 && *index <= str->length);
1225 assert(from != nullptr);
1226 assert(toLength >= 0);
1227 sal_Int32 i = rtl_ustr_indexOfStr_WithLength(
1228 str->buffer + *index, str->length - *index, from->buffer, from->length);
1229 if (i == -1) {
1230 rtl_uString_assign(newStr, str);
1231 } else {
1232 assert(i <= str->length - *index);
1233 i += *index;
1234 assert(from->length <= str->length);
1235 if (str->length - from->length > SAL_MAX_INT32 - toLength) {
1236 std::abort();
1238 sal_Int32 n = str->length - from->length + toLength;
1239 rtl_uString_acquire(str); // in case *newStr == str
1240 rtl_uString_new_WithLength(newStr, n);
1241 if (n != 0) {
1242 (*newStr)->length = n;
1243 assert(i >= 0 && i < str->length);
1244 memcpy(
1245 (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
1246 for (sal_Int32 j = 0; j != toLength; ++j) {
1247 assert(static_cast< unsigned char >(to[j]) <= 0x7F);
1248 (*newStr)->buffer[i + j] = to[j];
1250 memcpy(
1251 (*newStr)->buffer + i + toLength,
1252 str->buffer + i + from->length,
1253 (str->length - i - from->length) * sizeof (sal_Unicode));
1255 rtl_uString_release(str);
1257 *index = i;
1260 void rtl_uString_newReplaceFirstAsciiLAsciiL(
1261 rtl_uString ** newStr, rtl_uString * str, char const * from,
1262 sal_Int32 fromLength, char const * to, sal_Int32 toLength,
1263 sal_Int32 * index) SAL_THROW_EXTERN_C()
1265 assert(str != nullptr);
1266 assert(index != nullptr);
1267 assert(*index >= 0 && *index <= str->length);
1268 assert(fromLength >= 0);
1269 assert(to != nullptr);
1270 assert(toLength >= 0);
1271 sal_Int32 i = rtl_ustr_indexOfAscii_WithLength(
1272 str->buffer + *index, str->length - *index, from, fromLength);
1273 if (i == -1) {
1274 rtl_uString_assign(newStr, str);
1275 } else {
1276 assert(i <= str->length - *index);
1277 i += *index;
1278 assert(fromLength <= str->length);
1279 if (str->length - fromLength > SAL_MAX_INT32 - toLength) {
1280 std::abort();
1282 sal_Int32 n = str->length - fromLength + toLength;
1283 rtl_uString_acquire(str); // in case *newStr == str
1284 rtl_uString_new_WithLength(newStr, n);
1285 if (n != 0) {
1286 (*newStr)->length = n;
1287 assert(i >= 0 && i < str->length);
1288 memcpy(
1289 (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
1290 for (sal_Int32 j = 0; j != toLength; ++j) {
1291 assert(static_cast< unsigned char >(to[j]) <= 0x7F);
1292 (*newStr)->buffer[i + j] = to[j];
1294 memcpy(
1295 (*newStr)->buffer + i + toLength,
1296 str->buffer + i + fromLength,
1297 (str->length - i - fromLength) * sizeof (sal_Unicode));
1299 rtl_uString_release(str);
1301 *index = i;
1304 void rtl_uString_newReplaceFirstAsciiLUtf16L(
1305 rtl_uString ** newStr, rtl_uString * str, char const * from,
1306 sal_Int32 fromLength, sal_Unicode const * to, sal_Int32 toLength,
1307 sal_Int32 * index) SAL_THROW_EXTERN_C()
1309 assert(str != nullptr);
1310 assert(index != nullptr);
1311 assert(*index >= 0 && *index <= str->length);
1312 assert(fromLength >= 0);
1313 assert(to != nullptr);
1314 assert(toLength >= 0);
1315 sal_Int32 i = rtl_ustr_indexOfAscii_WithLength(
1316 str->buffer + *index, str->length - *index, from, fromLength);
1317 if (i == -1) {
1318 rtl_uString_assign(newStr, str);
1319 } else {
1320 assert(i <= str->length - *index);
1321 i += *index;
1322 assert(fromLength <= str->length);
1323 if (str->length - fromLength > SAL_MAX_INT32 - toLength) {
1324 rtl_uString_release(*newStr);
1325 *newStr = nullptr;
1326 } else {
1327 sal_Int32 n = str->length - fromLength + toLength;
1328 rtl_uString_acquire(str); // in case *newStr == str
1329 rtl_uString_new_WithLength(newStr, n);
1330 if (n != 0 && /*TODO:*/ *newStr != nullptr) {
1331 (*newStr)->length = n;
1332 assert(i >= 0 && i < str->length);
1333 memcpy(
1334 (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
1335 memcpy(
1336 (*newStr)->buffer + i, to, toLength * sizeof (sal_Unicode));
1337 memcpy(
1338 (*newStr)->buffer + i + toLength,
1339 str->buffer + i + fromLength,
1340 (str->length - i - fromLength) * sizeof (sal_Unicode));
1342 rtl_uString_release(str);
1345 *index = i;
1348 void rtl_uString_newReplaceFirstUtf16LAsciiL(
1349 rtl_uString ** newStr, rtl_uString * str, sal_Unicode const * from,
1350 sal_Int32 fromLength, char const * to, sal_Int32 toLength,
1351 sal_Int32 * index) SAL_THROW_EXTERN_C()
1353 assert(str != nullptr);
1354 assert(index != nullptr);
1355 assert(*index >= 0 && *index <= str->length);
1356 assert(fromLength >= 0);
1357 assert(to != nullptr);
1358 assert(toLength >= 0);
1359 sal_Int32 i = rtl_ustr_indexOfStr_WithLength(
1360 str->buffer + *index, str->length - *index, from, fromLength);
1361 if (i == -1) {
1362 rtl_uString_assign(newStr, str);
1363 } else {
1364 assert(i <= str->length - *index);
1365 i += *index;
1366 assert(fromLength <= str->length);
1367 if (str->length - fromLength > SAL_MAX_INT32 - toLength) {
1368 rtl_uString_release(*newStr);
1369 *newStr = nullptr;
1370 } else {
1371 sal_Int32 n = str->length - fromLength + toLength;
1372 rtl_uString_acquire(str); // in case *newStr == str
1373 rtl_uString_new_WithLength(newStr, n);
1374 if (n != 0 && /*TODO:*/ *newStr != nullptr) {
1375 (*newStr)->length = n;
1376 assert(i >= 0 && i < str->length);
1377 memcpy(
1378 (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
1379 for (sal_Int32 j = 0; j != toLength; ++j) {
1380 assert(static_cast< unsigned char >(to[j]) <= 0x7F);
1381 (*newStr)->buffer[i + j] = to[j];
1383 memcpy(
1384 (*newStr)->buffer + i + toLength,
1385 str->buffer + i + fromLength,
1386 (str->length - i - fromLength) * sizeof (sal_Unicode));
1388 rtl_uString_release(str);
1391 *index = i;
1394 void rtl_uString_newReplaceFirstUtf16LUtf16L(
1395 rtl_uString ** newStr, rtl_uString * str, sal_Unicode const * from,
1396 sal_Int32 fromLength, sal_Unicode const * to, sal_Int32 toLength,
1397 sal_Int32 * index) SAL_THROW_EXTERN_C()
1399 assert(str != nullptr);
1400 assert(index != nullptr);
1401 assert(*index >= 0 && *index <= str->length);
1402 assert(fromLength >= 0);
1403 assert(to != nullptr);
1404 assert(toLength >= 0);
1405 sal_Int32 i = rtl_ustr_indexOfStr_WithLength(
1406 str->buffer + *index, str->length - *index, from, fromLength);
1407 if (i == -1) {
1408 rtl_uString_assign(newStr, str);
1409 } else {
1410 assert(i <= str->length - *index);
1411 i += *index;
1412 assert(fromLength <= str->length);
1413 if (str->length - fromLength > SAL_MAX_INT32 - toLength) {
1414 rtl_uString_release(*newStr);
1415 *newStr = nullptr;
1416 } else {
1417 sal_Int32 n = str->length - fromLength + toLength;
1418 rtl_uString_acquire(str); // in case *newStr == str
1419 rtl_uString_new_WithLength(newStr, n);
1420 if (n != 0 && /*TODO:*/ *newStr != nullptr) {
1421 (*newStr)->length = n;
1422 assert(i >= 0 && i < str->length);
1423 memcpy(
1424 (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
1425 memcpy(
1426 (*newStr)->buffer + i, to, toLength * sizeof (sal_Unicode));
1427 memcpy(
1428 (*newStr)->buffer + i + toLength,
1429 str->buffer + i + fromLength,
1430 (str->length - i - fromLength) * sizeof (sal_Unicode));
1432 rtl_uString_release(str);
1435 *index = i;
1438 void rtl_uString_newReplaceAll(
1439 rtl_uString ** newStr, rtl_uString * str, rtl_uString const * from,
1440 rtl_uString const * to) SAL_THROW_EXTERN_C()
1442 rtl_uString_newReplaceAllFromIndex( newStr, str, from, to, 0 );
1445 void rtl_uString_newReplaceAllFromIndex(
1446 rtl_uString ** newStr, rtl_uString * str, rtl_uString const * from,
1447 rtl_uString const * to, sal_Int32 fromIndex) SAL_THROW_EXTERN_C()
1449 assert(to != nullptr);
1450 assert(fromIndex >= 0 && fromIndex <= str->length);
1451 rtl_uString_assign(newStr, str);
1452 for (sal_Int32 i = fromIndex;; i += to->length) {
1453 rtl_uString_newReplaceFirst(newStr, *newStr, from, to, &i);
1454 if (i == -1) {
1455 break;
1460 void rtl_uString_newReplaceAllAsciiL(
1461 rtl_uString ** newStr, rtl_uString * str, char const * from,
1462 sal_Int32 fromLength, rtl_uString const * to) SAL_THROW_EXTERN_C()
1464 assert(to != nullptr);
1465 rtl_uString_assign(newStr, str);
1466 for (sal_Int32 i = 0;; i += to->length) {
1467 rtl_uString_newReplaceFirstAsciiL(
1468 newStr, *newStr, from, fromLength, to, &i);
1469 if (i == -1) {
1470 break;
1475 void rtl_uString_newReplaceAllToAsciiL(
1476 rtl_uString ** newStr, rtl_uString * str, rtl_uString const * from,
1477 char const * to, sal_Int32 toLength) SAL_THROW_EXTERN_C()
1479 assert(from != nullptr);
1480 rtl_uString_assign(newStr, str);
1481 for (sal_Int32 i = 0;; i += toLength) {
1482 rtl_uString_newReplaceFirstToAsciiL(
1483 newStr, *newStr, from, to, toLength, &i);
1484 if (i == -1) {
1485 break;
1490 void rtl_uString_newReplaceAllAsciiLAsciiL(
1491 rtl_uString ** newStr, rtl_uString * str, char const * from,
1492 sal_Int32 fromLength, char const * to, sal_Int32 toLength)
1493 SAL_THROW_EXTERN_C()
1495 assert(toLength >= 0);
1496 rtl_uString_assign(newStr, str);
1497 for (sal_Int32 i = 0;; i += toLength) {
1498 rtl_uString_newReplaceFirstAsciiLAsciiL(
1499 newStr, *newStr, from, fromLength, to, toLength, &i);
1500 if (i == -1) {
1501 break;
1506 void rtl_uString_newReplaceAllAsciiLUtf16L(
1507 rtl_uString ** newStr, rtl_uString * str, char const * from,
1508 sal_Int32 fromLength, sal_Unicode const * to, sal_Int32 toLength)
1509 SAL_THROW_EXTERN_C()
1511 assert(toLength >= 0);
1512 rtl_uString_assign(newStr, str);
1513 for (sal_Int32 i = 0;; i += toLength) {
1514 rtl_uString_newReplaceFirstAsciiLUtf16L(
1515 newStr, *newStr, from, fromLength, to, toLength, &i);
1516 if (i == -1 || *newStr == nullptr) {
1517 break;
1522 void rtl_uString_newReplaceAllUtf16LAsciiL(
1523 rtl_uString ** newStr, rtl_uString * str, sal_Unicode const * from,
1524 sal_Int32 fromLength, char const * to, sal_Int32 toLength)
1525 SAL_THROW_EXTERN_C()
1527 assert(toLength >= 0);
1528 rtl_uString_assign(newStr, str);
1529 for (sal_Int32 i = 0;; i += toLength) {
1530 rtl_uString_newReplaceFirstUtf16LAsciiL(
1531 newStr, *newStr, from, fromLength, to, toLength, &i);
1532 if (i == -1 || *newStr == nullptr) {
1533 break;
1538 void rtl_uString_newReplaceAllUtf16LUtf16L(
1539 rtl_uString ** newStr, rtl_uString * str, sal_Unicode const * from,
1540 sal_Int32 fromLength, sal_Unicode const * to, sal_Int32 toLength)
1541 SAL_THROW_EXTERN_C()
1543 assert(toLength >= 0);
1544 rtl_uString_assign(newStr, str);
1545 for (sal_Int32 i = 0;; i += toLength) {
1546 rtl_uString_newReplaceFirstUtf16LUtf16L(
1547 newStr, *newStr, from, fromLength, to, toLength, &i);
1548 if (i == -1 || *newStr == nullptr) {
1549 break;
1554 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */