nss: upgrade to release 3.73
[LibreOffice.git] / sal / rtl / ustring.cxx
blobf84e3e1bd2d47c7e4ca6f9aa75f654bc7e341d23
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 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 char* pStr2 )
211 SAL_THROW_EXTERN_C()
213 assert(pStr1);
214 assert(pStr2);
215 sal_Int32 nRet;
216 for (;;)
218 nRet = static_cast<sal_Int32>(*pStr1)-
219 static_cast<sal_Int32>(static_cast<unsigned char>(*pStr2));
220 if (!(nRet == 0 && *pStr2 ))
221 break;
222 /* Check ASCII range */
223 SAL_WARN_IF( (static_cast<unsigned char>(*pStr2)) > 127, "rtl.string",
224 "rtl_ustr_ascii_compare - Found char > 127" );
225 pStr1++;
226 pStr2++;
229 return nRet;
232 /* ----------------------------------------------------------------------- */
234 sal_Int32 SAL_CALL rtl_ustr_ascii_compare_WithLength( const sal_Unicode* pStr1,
235 sal_Int32 nStr1Len,
236 const char* pStr2 )
237 SAL_THROW_EXTERN_C()
239 assert(pStr1);
240 assert(nStr1Len >= 0);
241 assert(pStr2);
242 sal_Int32 nRet = 0;
243 for (;;)
245 nRet = (nStr1Len ? static_cast<sal_Int32>(*pStr1) : 0) -
246 static_cast<sal_Int32>(static_cast<unsigned char>(*pStr2));
247 if (!(nRet == 0 && nStr1Len && *pStr2 ))
248 break;
249 /* Check ASCII range */
250 SAL_WARN_IF( (static_cast<unsigned char>(*pStr2)) > 127, "rtl.string",
251 "rtl_ustr_ascii_compare_WithLength - Found char > 127" );
252 pStr1++;
253 pStr2++;
254 nStr1Len--;
257 return nRet;
260 /* ----------------------------------------------------------------------- */
262 sal_Int32 SAL_CALL rtl_ustr_ascii_shortenedCompare_WithLength( const sal_Unicode* pStr1,
263 sal_Int32 nStr1Len,
264 const char* pStr2,
265 sal_Int32 nShortenedLength )
266 SAL_THROW_EXTERN_C()
268 assert(nStr1Len >= 0);
269 assert(nShortenedLength >= 0);
270 const sal_Unicode* pStr1End = pStr1 + nStr1Len;
271 sal_Int32 nRet;
272 while ( (nShortenedLength > 0) &&
273 (pStr1 < pStr1End) && *pStr2 )
275 /* Check ASCII range */
276 SAL_WARN_IF( (static_cast<unsigned char>(*pStr2)) > 127, "rtl.string",
277 "rtl_ustr_ascii_shortenedCompare_WithLength - Found char > 127" );
279 nRet = static_cast<sal_Int32>(*pStr1)-
280 static_cast<sal_Int32>(static_cast<unsigned char>(*pStr2));
281 if ( nRet != 0 )
282 return nRet;
284 nShortenedLength--;
285 pStr1++;
286 pStr2++;
289 if ( nShortenedLength <= 0 )
290 return 0;
292 if ( *pStr2 )
294 OSL_ENSURE( pStr1 == pStr1End, "pStr1 == pStr1End failed" );
295 // first is a substring of the second string => less (negative value)
296 nRet = -1;
298 else
300 // greater or equal
301 nRet = pStr1End - pStr1;
304 return nRet;
307 /* ----------------------------------------------------------------------- */
309 sal_Int32 SAL_CALL rtl_ustr_asciil_reverseCompare_WithLength( const sal_Unicode* pStr1,
310 sal_Int32 nStr1Len,
311 const char* pStr2,
312 sal_Int32 nStr2Len )
313 SAL_THROW_EXTERN_C()
315 assert(nStr1Len >= 0 && nStr2Len >= 0);
316 const sal_Unicode* pStr1Run = pStr1+nStr1Len;
317 const char* pStr2Run = pStr2+nStr2Len;
318 sal_Int32 nRet;
319 while ( (pStr1 < pStr1Run) && (pStr2 < pStr2Run) )
321 /* Check ASCII range */
322 SAL_WARN_IF( (static_cast<unsigned char>(*pStr2)) > 127, "rtl.string",
323 "rtl_ustr_asciil_reverseCompare_WithLength - Found char > 127" );
324 pStr1Run--;
325 pStr2Run--;
326 nRet = static_cast<sal_Int32>(*pStr1Run)- static_cast<sal_Int32>(*pStr2Run);
327 if ( nRet )
328 return nRet;
331 return nStr1Len - nStr2Len;
334 /* ----------------------------------------------------------------------- */
336 sal_Bool SAL_CALL rtl_ustr_asciil_reverseEquals_WithLength( const sal_Unicode* pStr1,
337 const char* pStr2,
338 sal_Int32 nStrLen )
339 SAL_THROW_EXTERN_C()
341 assert(nStrLen >= 0);
342 const sal_Unicode* pStr1Run = pStr1+nStrLen;
343 const char* pStr2Run = pStr2+nStrLen;
344 while ( pStr1 < pStr1Run )
346 /* Check ASCII range */
347 SAL_WARN_IF( (static_cast<unsigned char>(*pStr2)) > 127, "rtl.string",
348 "rtl_ustr_asciil_reverseEquals_WithLength - Found char > 127" );
349 pStr1Run--;
350 pStr2Run--;
351 if( *pStr1Run != static_cast<sal_Unicode>(*pStr2Run) )
352 return false;
355 return true;
358 /* ----------------------------------------------------------------------- */
360 sal_Int32 SAL_CALL rtl_ustr_ascii_compareIgnoreAsciiCase( const sal_Unicode* pStr1,
361 const char* pStr2 )
362 SAL_THROW_EXTERN_C()
364 assert(pStr1);
365 assert(pStr2);
366 sal_Int32 nRet;
367 sal_Int32 c1;
368 sal_Int32 c2;
371 /* Check ASCII range */
372 SAL_WARN_IF( (static_cast<unsigned char>(*pStr2)) > 127, "rtl.string",
373 "rtl_ustr_ascii_compareIgnoreAsciiCase - Found char > 127" );
374 /* If character between 'A' and 'Z', then convert it to lowercase */
375 c1 = static_cast<sal_Int32>(*pStr1);
376 c2 = static_cast<sal_Int32>(static_cast<unsigned char>(*pStr2));
377 if ( (c1 >= 65) && (c1 <= 90) )
378 c1 += 32;
379 if ( (c2 >= 65) && (c2 <= 90) )
380 c2 += 32;
381 nRet = c1-c2;
382 if ( nRet != 0 )
383 return nRet;
385 pStr1++;
386 pStr2++;
388 while ( c2 );
390 return 0;
393 /* ----------------------------------------------------------------------- */
395 sal_Int32 SAL_CALL rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( const sal_Unicode* pStr1,
396 sal_Int32 nStr1Len,
397 const char* pStr2 )
398 SAL_THROW_EXTERN_C()
400 assert(nStr1Len >= 0);
401 assert(pStr2);
402 sal_Int32 nRet;
403 sal_Int32 c1;
404 sal_Int32 c2;
407 /* Check ASCII range */
408 SAL_WARN_IF( (static_cast<unsigned char>(*pStr2)) > 127, "rtl.string",
409 "rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength - Found char > 127" );
410 if ( !nStr1Len )
411 return *pStr2 == '\0' ? 0 : -1;
413 /* If character between 'A' and 'Z', then convert it to lowercase */
414 c1 = static_cast<sal_Int32>(*pStr1);
415 c2 = static_cast<sal_Int32>(static_cast<unsigned char>(*pStr2));
416 if ( (c1 >= 65) && (c1 <= 90) )
417 c1 += 32;
418 if ( (c2 >= 65) && (c2 <= 90) )
419 c2 += 32;
420 nRet = c1-c2;
421 if ( nRet != 0 )
422 return nRet;
424 pStr1++;
425 pStr2++;
426 nStr1Len--;
428 while( c2 );
430 return 0;
433 sal_Int32 rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths(
434 sal_Unicode const * first, sal_Int32 firstLen,
435 char const * second, sal_Int32 secondLen) SAL_THROW_EXTERN_C()
437 assert(firstLen >= 0 && secondLen >= 0);
438 sal_Int32 i;
439 sal_Int32 len = std::min(firstLen, secondLen);
440 for (i = 0; i < len; ++i) {
441 /* Check ASCII range */
442 SAL_WARN_IF( (static_cast<unsigned char>(*second)) > 127, "rtl.string",
443 "rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths - Found char > 127" );
444 sal_Int32 c1 = *first++;
445 sal_Int32 c2 = static_cast<unsigned char>(*second++);
446 sal_Int32 d;
447 if (c1 >= 65 && c1 <= 90) {
448 c1 += 32;
450 if (c2 >= 65 && c2 <= 90) {
451 c2 += 32;
453 d = c1 - c2;
454 if (d != 0) {
455 return d;
458 return firstLen - secondLen;
461 /* ----------------------------------------------------------------------- */
463 sal_Int32 SAL_CALL rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( const sal_Unicode* pStr1,
464 sal_Int32 nStr1Len,
465 const char* pStr2,
466 sal_Int32 nShortenedLength )
467 SAL_THROW_EXTERN_C()
469 assert(nStr1Len >= 0);
470 assert(nShortenedLength >= 0);
471 const sal_Unicode* pStr1End = pStr1 + nStr1Len;
472 sal_Int32 nRet;
473 sal_Int32 c1;
474 sal_Int32 c2;
475 while ( (nShortenedLength > 0) &&
476 (pStr1 < pStr1End) && *pStr2 )
478 /* Check ASCII range */
479 SAL_WARN_IF( (static_cast<unsigned char>(*pStr2)) > 127, "rtl.string",
480 "rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength - Found char > 127" );
482 /* If character between 'A' and 'Z', then convert it to lowercase */
483 c1 = static_cast<sal_Int32>(*pStr1);
484 c2 = static_cast<sal_Int32>(static_cast<unsigned char>(*pStr2));
485 if ( (c1 >= 65) && (c1 <= 90) )
486 c1 += 32;
487 if ( (c2 >= 65) && (c2 <= 90) )
488 c2 += 32;
489 nRet = c1-c2;
490 if ( nRet != 0 )
491 return nRet;
493 nShortenedLength--;
494 pStr1++;
495 pStr2++;
498 if ( nShortenedLength <= 0 )
499 return 0;
501 if ( *pStr2 )
503 OSL_ENSURE( pStr1 == pStr1End, "pStr1 == pStr1End failed" );
504 // first is a substring of the second string => less (negative value)
505 nRet = -1;
507 else
509 // greater or equal
510 nRet = pStr1End - pStr1;
513 return nRet;
516 /* ----------------------------------------------------------------------- */
518 void SAL_CALL rtl_uString_newFromAscii( rtl_uString** ppThis,
519 const char* pCharStr )
520 SAL_THROW_EXTERN_C()
522 assert(ppThis);
523 sal_Int32 nLen;
525 if ( pCharStr )
527 const char* pTempStr = pCharStr;
528 while( *pTempStr )
529 pTempStr++;
530 nLen = pTempStr-pCharStr;
532 else
533 nLen = 0;
535 if ( !nLen )
537 rtl_uString_new( ppThis );
538 return;
541 if ( *ppThis )
542 rtl_uString_release( *ppThis );
544 *ppThis = rtl_uString_ImplAlloc( nLen );
545 OSL_ASSERT(*ppThis != nullptr);
546 if ( !(*ppThis) )
547 return;
549 sal_Unicode* pBuffer = (*ppThis)->buffer;
552 assert(static_cast<unsigned char>(*pCharStr) < 0x80); // ASCII range
553 *pBuffer = *pCharStr;
554 pBuffer++;
555 pCharStr++;
557 while ( *pCharStr );
559 RTL_LOG_STRING_NEW( *ppThis );
562 void SAL_CALL rtl_uString_newFromCodePoints(
563 rtl_uString ** newString, sal_uInt32 const * codePoints,
564 sal_Int32 codePointCount) SAL_THROW_EXTERN_C()
566 sal_Int32 n;
567 sal_Int32 i;
568 sal_Unicode * p;
569 assert(newString != nullptr);
570 assert((codePoints != nullptr || codePointCount == 0) && codePointCount >= 0);
571 if (codePointCount == 0) {
572 rtl_uString_new(newString);
573 return;
575 if (*newString != nullptr) {
576 rtl_uString_release(*newString);
578 n = codePointCount;
579 for (i = 0; i < codePointCount; ++i) {
580 OSL_ASSERT(rtl::isUnicodeCodePoint(codePoints[i]));
581 if (codePoints[i] >= 0x10000) {
582 ++n;
585 /* Builds on the assumption that sal_Int32 uses 32 bit two's complement
586 representation with wrap around (the necessary number of UTF-16 code
587 units will be no larger than 2 * SAL_MAX_INT32, represented as
588 sal_Int32 -2): */
589 if (n < 0) {
590 // coverity[dead_error_begin] - assumes wrap around
591 *newString = nullptr;
592 return;
594 *newString = rtl_uString_ImplAlloc(n);
595 if (*newString == nullptr) {
596 return;
598 p = (*newString)->buffer;
599 for (i = 0; i < codePointCount; ++i) {
600 p += rtl::splitSurrogates(codePoints[i], p);
602 RTL_LOG_STRING_NEW( *newString );
605 void rtl_uString_newConcatAsciiL(
606 rtl_uString ** newString, rtl_uString * left, char const * right,
607 sal_Int32 rightLength)
609 assert(newString != nullptr);
610 assert(left != nullptr);
611 assert(right != nullptr);
612 assert(rightLength >= 0);
613 if (left->length > std::numeric_limits<sal_Int32>::max() - rightLength) {
614 #if !defined(__COVERITY__)
615 throw std::length_error("rtl_uString_newConcatAsciiL");
616 #else
617 //coverity doesn't report std::bad_alloc as an unhandled exception when
618 //potentially thrown from destructors but does report std::length_error
619 throw std::bad_alloc();
620 #endif
622 sal_Int32 n = left->length + rightLength;
623 rtl_uString_assign(newString, left);
624 rtl_uString_ensureCapacity(newString, n);
625 sal_Unicode * p = (*newString)->buffer + (*newString)->length;
626 for (sal_Int32 i = 0; i != rightLength; ++i) {
627 p[i] = static_cast<unsigned char>(right[i]);
629 (*newString)->buffer[n] = 0;
630 (*newString)->length = n;
633 void rtl_uString_newConcatUtf16L(
634 rtl_uString ** newString, rtl_uString * left, sal_Unicode const * right,
635 sal_Int32 rightLength)
637 assert(newString != nullptr);
638 assert(left != nullptr);
639 assert(right != nullptr || rightLength == 0);
640 assert(rightLength >= 0);
641 if (left->length > std::numeric_limits<sal_Int32>::max() - rightLength) {
642 #if !defined(__COVERITY__)
643 throw std::length_error("rtl_uString_newConcatUtf16L");
644 #else
645 //coverity doesn't report std::bad_alloc as an unhandled exception when
646 //potentially thrown from destructors but does report std::length_error
647 throw std::bad_alloc();
648 #endif
650 sal_Int32 n = left->length + rightLength;
651 rtl_uString_assign(newString, left);
652 rtl_uString_ensureCapacity(newString, n);
653 if (rightLength != 0) {
654 memcpy(
655 (*newString)->buffer + (*newString)->length, right,
656 rightLength * sizeof (sal_Unicode));
658 (*newString)->buffer[n] = 0;
659 (*newString)->length = n;
662 /* ======================================================================= */
664 static int rtl_ImplGetFastUTF8UnicodeLen( const char* pStr, sal_Int32 nLen, bool * ascii )
666 int n;
667 const char* pEndStr;
669 *ascii = true;
670 n = 0;
671 pEndStr = pStr+nLen;
672 while ( pStr < pEndStr )
674 unsigned char c = static_cast<unsigned char>(*pStr);
676 if ( !(c & 0x80) )
677 pStr++;
678 else
680 if ( (c & 0xE0) == 0xC0 )
681 pStr += 2;
682 else if ( (c & 0xF0) == 0xE0 )
683 pStr += 3;
684 else if ( (c & 0xF8) == 0xF0 )
685 pStr += 4;
686 else if ( (c & 0xFC) == 0xF8 )
687 pStr += 5;
688 else if ( (c & 0xFE) == 0xFC )
689 pStr += 6;
690 else
691 pStr++;
692 *ascii = false;
695 n++;
698 return n;
701 /* ----------------------------------------------------------------------- */
703 static void rtl_string2UString_status( rtl_uString** ppThis,
704 const char* pStr,
705 sal_Int32 nLen,
706 rtl_TextEncoding eTextEncoding,
707 sal_uInt32 nCvtFlags,
708 sal_uInt32 *pInfo )
710 OSL_ENSURE(nLen == 0 || rtl_isOctetTextEncoding(eTextEncoding),
711 "rtl_string2UString_status() - Wrong TextEncoding" );
713 if ( !nLen )
715 rtl_uString_new( ppThis );
716 if (pInfo != nullptr) {
717 *pInfo = 0;
720 else
722 if ( *ppThis )
723 rtl_uString_release( *ppThis );
725 /* Optimization for US-ASCII */
726 if ( eTextEncoding == RTL_TEXTENCODING_ASCII_US )
728 sal_Unicode* pBuffer;
729 *ppThis = rtl_uString_ImplAlloc( nLen );
730 if (*ppThis == nullptr) {
731 if (pInfo != nullptr) {
732 *pInfo = RTL_TEXTTOUNICODE_INFO_ERROR |
733 RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL;
735 return;
737 pBuffer = (*ppThis)->buffer;
738 sal_Int32 nLenCopy(nLen);
739 const char *pStrCopy(pStr);
742 /* Check ASCII range */
743 if (static_cast<unsigned char>(*pStrCopy) > 127)
745 rtl_uString_release(*ppThis);
746 goto retry; // cancel loop - try again with the converter
749 *pBuffer = *pStrCopy;
750 pBuffer++;
751 pStrCopy++;
752 nLenCopy--;
754 while (nLenCopy);
755 if (pInfo != nullptr) {
756 *pInfo = 0;
758 RTL_LOG_STRING_NEW( *ppThis );
759 return;
761 retry:
763 rtl_uString* pTemp;
764 rtl_uString* pTemp2 = nullptr;
765 rtl_TextToUnicodeConverter hConverter;
766 sal_uInt32 nInfo;
767 sal_Size nSrcBytes;
768 sal_Size nDestChars;
769 sal_Size nNewLen;
771 /* Optimization for UTF-8 - we try to calculate the exact length */
772 /* For all other encoding we try the maximum - and reallocate
773 the buffer if needed */
774 if ( eTextEncoding == RTL_TEXTENCODING_UTF8 )
776 bool ascii;
777 nNewLen = rtl_ImplGetFastUTF8UnicodeLen( pStr, nLen, &ascii );
778 /* Includes the string only ASCII, then we could copy
779 the buffer faster */
780 if ( ascii )
782 sal_Unicode* pBuffer;
783 *ppThis = rtl_uString_ImplAlloc( nLen );
784 if (*ppThis == nullptr)
786 if (pInfo != nullptr) {
787 *pInfo = RTL_TEXTTOUNICODE_INFO_ERROR |
788 RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL;
790 return;
792 pBuffer = (*ppThis)->buffer;
795 assert((static_cast<unsigned char>(*pStr)) <= 127);
796 *pBuffer = *pStr;
797 pBuffer++;
798 pStr++;
799 nLen--;
801 while ( nLen );
802 if (pInfo != nullptr) {
803 *pInfo = 0;
805 RTL_LOG_STRING_NEW( *ppThis );
806 return;
809 else
810 nNewLen = nLen;
812 nCvtFlags |= RTL_TEXTTOUNICODE_FLAGS_FLUSH;
813 hConverter = rtl_createTextToUnicodeConverter( eTextEncoding );
815 pTemp = rtl_uString_ImplAlloc( nNewLen );
816 if (pTemp == nullptr) {
817 if (pInfo != nullptr) {
818 *pInfo = RTL_TEXTTOUNICODE_INFO_ERROR |
819 RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL;
821 return;
823 nDestChars = rtl_convertTextToUnicode( hConverter, nullptr,
824 pStr, nLen,
825 pTemp->buffer, nNewLen,
826 nCvtFlags,
827 &nInfo, &nSrcBytes );
829 /* Buffer not big enough, try again with enough space */
830 /* Shouldn't be the case, but if we get textencoding which
831 could results in more unicode characters we have this
832 code here. Could be the case for apple encodings */
833 while ( nInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL )
835 rtl_freeString( pTemp );
836 nNewLen += 8;
837 pTemp = rtl_uString_ImplAlloc( nNewLen );
838 if (pTemp == nullptr) {
839 if (pInfo != nullptr) {
840 *pInfo = RTL_TEXTTOUNICODE_INFO_ERROR |
841 RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL;
843 return;
845 nDestChars = rtl_convertTextToUnicode( hConverter, nullptr,
846 pStr, nLen,
847 pTemp->buffer, nNewLen,
848 nCvtFlags,
849 &nInfo, &nSrcBytes );
852 if (pInfo)
853 *pInfo = nInfo;
855 /* Set the buffer to the correct size or if there is too
856 much overhead, reallocate to the correct size */
857 if ( nNewLen > nDestChars+8 )
859 pTemp2 = rtl_uString_ImplAlloc( nDestChars );
861 if (pTemp2 != nullptr)
863 rtl_str_ImplCopy(pTemp2->buffer, pTemp->buffer, nDestChars);
864 rtl_freeString(pTemp);
865 pTemp = pTemp2;
867 else
869 pTemp->length = nDestChars;
870 pTemp->buffer[nDestChars] = 0;
873 rtl_destroyTextToUnicodeConverter( hConverter );
874 *ppThis = pTemp;
876 /* Results the conversion in an empty buffer -
877 create an empty string */
878 if ( pTemp && !nDestChars )
879 rtl_uString_new( ppThis );
882 RTL_LOG_STRING_NEW( *ppThis );
885 void SAL_CALL rtl_string2UString( rtl_uString** ppThis,
886 const char* pStr,
887 sal_Int32 nLen,
888 rtl_TextEncoding eTextEncoding,
889 sal_uInt32 nCvtFlags ) SAL_THROW_EXTERN_C()
891 assert(ppThis);
892 assert(nLen >= 0);
893 rtl_string2UString_status( ppThis, pStr, nLen, eTextEncoding,
894 nCvtFlags, nullptr );
897 /* ----------------------------------------------------------------------- */
899 namespace {
901 enum StrLifecycle {
902 CANNOT_RETURN,
903 CAN_RETURN = 1
908 static oslMutex
909 getInternMutex()
911 static oslMutex pPoolGuard = osl_createMutex();
913 return pPoolGuard;
916 /* returns true if we found a dup in the pool */
917 static void rtl_ustring_intern_internal( rtl_uString ** newStr,
918 rtl_uString * str,
919 StrLifecycle can_return )
921 oslMutex pPoolMutex;
923 pPoolMutex = getInternMutex();
925 osl_acquireMutex( pPoolMutex );
927 *newStr = rtl_str_hash_intern (str, can_return);
929 osl_releaseMutex( pPoolMutex );
931 RTL_LOG_STRING_INTERN_NEW(*newStr, str);
933 if( can_return && *newStr != str )
934 { /* we dupped, then found a match */
935 rtl_freeString( str );
939 void SAL_CALL rtl_uString_intern( rtl_uString ** newStr,
940 rtl_uString * str) SAL_THROW_EXTERN_C()
942 assert(newStr);
943 assert(str);
944 if (SAL_STRING_IS_INTERN(str))
946 IMPL_RTL_ACQUIRE( str );
947 *newStr = str;
949 else
951 rtl_uString *pOrg = *newStr;
952 *newStr = nullptr;
953 rtl_ustring_intern_internal( newStr, str, CANNOT_RETURN );
954 if (pOrg)
955 rtl_uString_release (pOrg);
959 static int rtl_canGuessUOutputLength( int len, rtl_TextEncoding eTextEncoding )
961 // FIXME: Maybe we should use a bit flag in the higher bits of the
962 // eTextEncoding value itself to determine the encoding type. But if we
963 // do, be sure to mask the value in certain places that expect the values
964 // to be numbered serially from 0 and up. One such place is
965 // Impl_getTextEncodingData().
967 switch ( eTextEncoding )
969 // 1 to 1 (with no zero elements)
970 case RTL_TEXTENCODING_IBM_437:
971 case RTL_TEXTENCODING_IBM_850:
972 case RTL_TEXTENCODING_IBM_860:
973 case RTL_TEXTENCODING_IBM_861:
974 case RTL_TEXTENCODING_IBM_863:
975 case RTL_TEXTENCODING_IBM_865:
976 return len;
977 break;
979 return 0;
982 void SAL_CALL rtl_uString_internConvert( rtl_uString ** newStr,
983 const char * str,
984 sal_Int32 len,
985 rtl_TextEncoding eTextEncoding,
986 sal_uInt32 convertFlags,
987 sal_uInt32 * pInfo )
988 SAL_THROW_EXTERN_C()
990 assert(newStr);
991 assert(len >= 0);
992 rtl_uString *scratch;
994 if (*newStr)
996 rtl_uString_release (*newStr);
997 *newStr = nullptr;
1000 if ( len < 256 )
1001 { // try various optimisations
1002 sal_Int32 ulen;
1003 if ( eTextEncoding == RTL_TEXTENCODING_ASCII_US )
1005 int i;
1006 rtl_uString *pScratch;
1007 pScratch = static_cast< rtl_uString * >(
1008 alloca(sizeof (rtl_uString) + len * sizeof (sal_Unicode)));
1009 for (i = 0; i < len; i++)
1011 /* Check ASCII range */
1012 SAL_WARN_IF( (static_cast<unsigned char>(str[i])) > 127, "rtl.string",
1013 "rtl_ustring_internConvert() - Found char > 127 and RTL_TEXTENCODING_ASCII_US is specified" );
1014 pScratch->buffer[i] = str[i];
1016 pScratch->length = len;
1017 rtl_ustring_intern_internal( newStr, pScratch, CANNOT_RETURN );
1018 return;
1020 if ( (ulen = rtl_canGuessUOutputLength(len, eTextEncoding)) != 0 )
1022 rtl_uString *pScratch;
1023 rtl_TextToUnicodeConverter hConverter;
1024 sal_Size nSrcBytes;
1025 sal_uInt32 nInfo;
1027 pScratch = static_cast< rtl_uString * >(
1028 alloca(
1029 sizeof (rtl_uString) + ulen * sizeof (sal_Unicode)));
1031 hConverter = rtl_createTextToUnicodeConverter( eTextEncoding );
1032 rtl_convertTextToUnicode(
1033 hConverter, nullptr, str, len, pScratch->buffer, ulen, convertFlags, &nInfo, &nSrcBytes );
1034 rtl_destroyTextToUnicodeConverter( hConverter );
1036 if (pInfo)
1037 *pInfo = nInfo;
1039 pScratch->length = ulen;
1040 rtl_ustring_intern_internal( newStr, pScratch, CANNOT_RETURN );
1041 return;
1044 /* FIXME: we want a nice UTF-8 / alloca shortcut here */
1047 scratch = nullptr;
1048 rtl_string2UString_status( &scratch, str, len, eTextEncoding, convertFlags,
1049 pInfo );
1050 if (!scratch) {
1051 return;
1053 rtl_ustring_intern_internal( newStr, scratch, CAN_RETURN );
1056 static void
1057 internRelease (rtl_uString *pThis)
1059 rtl_uString *pFree = nullptr;
1060 if ( SAL_STRING_REFCOUNT(
1061 osl_atomic_decrement( &(pThis->refCount) ) ) == 0)
1063 RTL_LOG_STRING_INTERN_DELETE(pThis);
1064 oslMutex pPoolMutex = getInternMutex();
1065 osl_acquireMutex( pPoolMutex );
1067 rtl_str_hash_remove (pThis);
1069 /* May have been separately acquired */
1070 if ( SAL_STRING_REFCOUNT(
1071 osl_atomic_increment( &(pThis->refCount) ) ) == 1 )
1073 /* we got the last ref */
1074 pFree = pThis;
1076 else /* very unusual */
1078 internRelease (pThis);
1081 osl_releaseMutex( pPoolMutex );
1083 if (pFree)
1084 rtl_freeString (pFree);
1087 sal_uInt32 SAL_CALL rtl_uString_iterateCodePoints(
1088 rtl_uString const * string, sal_Int32 * indexUtf16,
1089 sal_Int32 incrementCodePoints)
1091 sal_Int32 n;
1092 sal_Unicode cu;
1093 sal_uInt32 cp;
1094 assert(string != nullptr && indexUtf16 != nullptr);
1095 n = *indexUtf16;
1096 assert(n >= 0 && n <= string->length);
1097 while (incrementCodePoints < 0) {
1098 assert(n > 0);
1099 cu = string->buffer[--n];
1100 if (rtl::isLowSurrogate(cu) && n != 0 &&
1101 rtl::isHighSurrogate(string->buffer[n - 1]))
1103 --n;
1105 ++incrementCodePoints;
1107 assert(n >= 0 && n < string->length);
1108 cu = string->buffer[n];
1109 if (rtl::isHighSurrogate(cu) && string->length - n >= 2 &&
1110 rtl::isLowSurrogate(string->buffer[n + 1]))
1112 cp = rtl::combineSurrogates(cu, string->buffer[n + 1]);
1113 } else {
1114 cp = cu;
1116 while (incrementCodePoints > 0) {
1117 assert(n < string->length);
1118 cu = string->buffer[n++];
1119 if (rtl::isHighSurrogate(cu) && n != string->length &&
1120 rtl::isLowSurrogate(string->buffer[n]))
1122 ++n;
1124 --incrementCodePoints;
1126 assert(n >= 0 && n <= string->length);
1127 *indexUtf16 = n;
1128 return cp;
1131 sal_Bool rtl_convertStringToUString(
1132 rtl_uString ** target, char const * source, sal_Int32 length,
1133 rtl_TextEncoding encoding, sal_uInt32 flags) SAL_THROW_EXTERN_C()
1135 assert(target);
1136 assert(length >= 0);
1137 sal_uInt32 info;
1138 rtl_string2UString_status(target, source, length, encoding, flags, &info);
1139 return (info & RTL_TEXTTOUNICODE_INFO_ERROR) == 0;
1142 void rtl_uString_newReplaceFirst(
1143 rtl_uString ** newStr, rtl_uString * str, rtl_uString const * from,
1144 rtl_uString const * to, sal_Int32 * index) SAL_THROW_EXTERN_C()
1146 assert(str != nullptr);
1147 assert(index != nullptr);
1148 assert(*index >= 0 && *index <= str->length);
1149 assert(from != nullptr);
1150 assert(to != nullptr);
1151 sal_Int32 i = rtl_ustr_indexOfStr_WithLength(
1152 str->buffer + *index, str->length - *index, from->buffer, from->length);
1153 if (i == -1) {
1154 rtl_uString_assign(newStr, str);
1155 } else {
1156 assert(i <= str->length - *index);
1157 i += *index;
1158 assert(from->length <= str->length);
1159 if (str->length - from->length > SAL_MAX_INT32 - to->length) {
1160 std::abort();
1162 sal_Int32 n = str->length - from->length + to->length;
1163 rtl_uString_acquire(str); // in case *newStr == str
1164 rtl_uString_new_WithLength(newStr, n);
1165 if (n != 0) {
1166 (*newStr)->length = n;
1167 assert(i >= 0 && i < str->length);
1168 memcpy(
1169 (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
1170 memcpy(
1171 (*newStr)->buffer + i, to->buffer,
1172 to->length * sizeof (sal_Unicode));
1173 memcpy(
1174 (*newStr)->buffer + i + to->length,
1175 str->buffer + i + from->length,
1176 (str->length - i - from->length) * sizeof (sal_Unicode));
1178 rtl_uString_release(str);
1180 *index = i;
1183 void rtl_uString_newReplaceFirstAsciiL(
1184 rtl_uString ** newStr, rtl_uString * str, char const * from,
1185 sal_Int32 fromLength, rtl_uString const * to, sal_Int32 * index)
1186 SAL_THROW_EXTERN_C()
1188 assert(str != nullptr);
1189 assert(index != nullptr);
1190 assert(*index >= 0 && *index <= str->length);
1191 assert(fromLength >= 0);
1192 assert(to != nullptr);
1193 sal_Int32 i = rtl_ustr_indexOfAscii_WithLength(
1194 str->buffer + *index, str->length - *index, from, fromLength);
1195 if (i == -1) {
1196 rtl_uString_assign(newStr, str);
1197 } else {
1198 assert(i <= str->length - *index);
1199 i += *index;
1200 assert(fromLength <= str->length);
1201 if (str->length - fromLength > SAL_MAX_INT32 - to->length) {
1202 std::abort();
1204 sal_Int32 n = str->length - fromLength + to->length;
1205 rtl_uString_acquire(str); // in case *newStr == str
1206 rtl_uString_new_WithLength(newStr, n);
1207 if (n != 0) {
1208 (*newStr)->length = n;
1209 assert(i >= 0 && i < str->length);
1210 memcpy(
1211 (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
1212 memcpy(
1213 (*newStr)->buffer + i, to->buffer,
1214 to->length * sizeof (sal_Unicode));
1215 memcpy(
1216 (*newStr)->buffer + i + to->length,
1217 str->buffer + i + fromLength,
1218 (str->length - i - fromLength) * sizeof (sal_Unicode));
1220 rtl_uString_release(str);
1222 *index = i;
1225 void rtl_uString_newReplaceFirstToAsciiL(
1226 rtl_uString ** newStr, rtl_uString * str, rtl_uString const * from,
1227 char const * to, sal_Int32 toLength, sal_Int32 * index)
1228 SAL_THROW_EXTERN_C()
1230 assert(str != nullptr);
1231 assert(index != nullptr);
1232 assert(*index >= 0 && *index <= str->length);
1233 assert(from != nullptr);
1234 assert(toLength >= 0);
1235 sal_Int32 i = rtl_ustr_indexOfStr_WithLength(
1236 str->buffer + *index, str->length - *index, from->buffer, from->length);
1237 if (i == -1) {
1238 rtl_uString_assign(newStr, str);
1239 } else {
1240 assert(i <= str->length - *index);
1241 i += *index;
1242 assert(from->length <= str->length);
1243 if (str->length - from->length > SAL_MAX_INT32 - toLength) {
1244 std::abort();
1246 sal_Int32 n = str->length - from->length + toLength;
1247 rtl_uString_acquire(str); // in case *newStr == str
1248 rtl_uString_new_WithLength(newStr, n);
1249 if (n != 0) {
1250 (*newStr)->length = n;
1251 assert(i >= 0 && i < str->length);
1252 memcpy(
1253 (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
1254 for (sal_Int32 j = 0; j != toLength; ++j) {
1255 assert(static_cast< unsigned char >(to[j]) <= 0x7F);
1256 (*newStr)->buffer[i + j] = to[j];
1258 memcpy(
1259 (*newStr)->buffer + i + toLength,
1260 str->buffer + i + from->length,
1261 (str->length - i - from->length) * sizeof (sal_Unicode));
1263 rtl_uString_release(str);
1265 *index = i;
1268 void rtl_uString_newReplaceFirstAsciiLAsciiL(
1269 rtl_uString ** newStr, rtl_uString * str, char const * from,
1270 sal_Int32 fromLength, char const * to, sal_Int32 toLength,
1271 sal_Int32 * index) SAL_THROW_EXTERN_C()
1273 assert(str != nullptr);
1274 assert(index != nullptr);
1275 assert(*index >= 0 && *index <= str->length);
1276 assert(fromLength >= 0);
1277 assert(to != nullptr);
1278 assert(toLength >= 0);
1279 sal_Int32 i = rtl_ustr_indexOfAscii_WithLength(
1280 str->buffer + *index, str->length - *index, from, fromLength);
1281 if (i == -1) {
1282 rtl_uString_assign(newStr, str);
1283 } else {
1284 assert(i <= str->length - *index);
1285 i += *index;
1286 assert(fromLength <= str->length);
1287 if (str->length - fromLength > SAL_MAX_INT32 - toLength) {
1288 std::abort();
1290 sal_Int32 n = str->length - fromLength + toLength;
1291 rtl_uString_acquire(str); // in case *newStr == str
1292 rtl_uString_new_WithLength(newStr, n);
1293 if (n != 0) {
1294 (*newStr)->length = n;
1295 assert(i >= 0 && i < str->length);
1296 memcpy(
1297 (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
1298 for (sal_Int32 j = 0; j != toLength; ++j) {
1299 assert(static_cast< unsigned char >(to[j]) <= 0x7F);
1300 (*newStr)->buffer[i + j] = to[j];
1302 memcpy(
1303 (*newStr)->buffer + i + toLength,
1304 str->buffer + i + fromLength,
1305 (str->length - i - fromLength) * sizeof (sal_Unicode));
1307 rtl_uString_release(str);
1309 *index = i;
1312 void rtl_uString_newReplaceFirstAsciiLUtf16L(
1313 rtl_uString ** newStr, rtl_uString * str, char const * from,
1314 sal_Int32 fromLength, sal_Unicode const * to, sal_Int32 toLength,
1315 sal_Int32 * index) SAL_THROW_EXTERN_C()
1317 assert(str != nullptr);
1318 assert(index != nullptr);
1319 assert(*index >= 0 && *index <= str->length);
1320 assert(fromLength >= 0);
1321 assert(to != nullptr || toLength == 0);
1322 assert(toLength >= 0);
1323 sal_Int32 i = rtl_ustr_indexOfAscii_WithLength(
1324 str->buffer + *index, str->length - *index, from, fromLength);
1325 if (i == -1) {
1326 rtl_uString_assign(newStr, str);
1327 } else {
1328 assert(i <= str->length - *index);
1329 i += *index;
1330 assert(fromLength <= str->length);
1331 if (str->length - fromLength > SAL_MAX_INT32 - toLength) {
1332 rtl_uString_release(*newStr);
1333 *newStr = nullptr;
1334 } else {
1335 sal_Int32 n = str->length - fromLength + toLength;
1336 rtl_uString_acquire(str); // in case *newStr == str
1337 rtl_uString_new_WithLength(newStr, n);
1338 if (n != 0 && /*TODO:*/ *newStr != nullptr) {
1339 (*newStr)->length = n;
1340 assert(i >= 0 && i < str->length);
1341 memcpy(
1342 (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
1343 if (toLength != 0) {
1344 memcpy(
1345 (*newStr)->buffer + i, to, toLength * sizeof (sal_Unicode));
1347 memcpy(
1348 (*newStr)->buffer + i + toLength,
1349 str->buffer + i + fromLength,
1350 (str->length - i - fromLength) * sizeof (sal_Unicode));
1352 rtl_uString_release(str);
1355 *index = i;
1358 void rtl_uString_newReplaceFirstUtf16LAsciiL(
1359 rtl_uString ** newStr, rtl_uString * str, sal_Unicode const * from,
1360 sal_Int32 fromLength, char const * to, sal_Int32 toLength,
1361 sal_Int32 * index) SAL_THROW_EXTERN_C()
1363 assert(str != nullptr);
1364 assert(index != nullptr);
1365 assert(*index >= 0 && *index <= str->length);
1366 assert(fromLength >= 0);
1367 assert(to != nullptr);
1368 assert(toLength >= 0);
1369 sal_Int32 i = rtl_ustr_indexOfStr_WithLength(
1370 str->buffer + *index, str->length - *index, from, fromLength);
1371 if (i == -1) {
1372 rtl_uString_assign(newStr, str);
1373 } else {
1374 assert(i <= str->length - *index);
1375 i += *index;
1376 assert(fromLength <= str->length);
1377 if (str->length - fromLength > SAL_MAX_INT32 - toLength) {
1378 rtl_uString_release(*newStr);
1379 *newStr = nullptr;
1380 } else {
1381 sal_Int32 n = str->length - fromLength + toLength;
1382 rtl_uString_acquire(str); // in case *newStr == str
1383 rtl_uString_new_WithLength(newStr, n);
1384 if (n != 0 && /*TODO:*/ *newStr != nullptr) {
1385 (*newStr)->length = n;
1386 assert(i >= 0 && i < str->length);
1387 memcpy(
1388 (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
1389 for (sal_Int32 j = 0; j != toLength; ++j) {
1390 assert(static_cast< unsigned char >(to[j]) <= 0x7F);
1391 (*newStr)->buffer[i + j] = to[j];
1393 memcpy(
1394 (*newStr)->buffer + i + toLength,
1395 str->buffer + i + fromLength,
1396 (str->length - i - fromLength) * sizeof (sal_Unicode));
1398 rtl_uString_release(str);
1401 *index = i;
1404 void rtl_uString_newReplaceFirstUtf16LUtf16L(
1405 rtl_uString ** newStr, rtl_uString * str, sal_Unicode const * from,
1406 sal_Int32 fromLength, sal_Unicode const * to, sal_Int32 toLength,
1407 sal_Int32 * index) SAL_THROW_EXTERN_C()
1409 assert(str != nullptr);
1410 assert(index != nullptr);
1411 assert(*index >= 0 && *index <= str->length);
1412 assert(from != nullptr || fromLength == 0);
1413 assert(fromLength >= 0);
1414 assert(to != nullptr || toLength == 0);
1415 assert(toLength >= 0);
1416 sal_Int32 i = rtl_ustr_indexOfStr_WithLength(
1417 str->buffer + *index, str->length - *index, from, fromLength);
1418 if (i == -1) {
1419 rtl_uString_assign(newStr, str);
1420 } else {
1421 assert(i <= str->length - *index);
1422 i += *index;
1423 assert(fromLength <= str->length);
1424 if (str->length - fromLength > SAL_MAX_INT32 - toLength) {
1425 rtl_uString_release(*newStr);
1426 *newStr = nullptr;
1427 } else {
1428 sal_Int32 n = str->length - fromLength + toLength;
1429 rtl_uString_acquire(str); // in case *newStr == str
1430 rtl_uString_new_WithLength(newStr, n);
1431 if (n != 0 && /*TODO:*/ *newStr != nullptr) {
1432 (*newStr)->length = n;
1433 assert(i >= 0 && i < str->length);
1434 memcpy(
1435 (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
1436 if (toLength != 0) {
1437 memcpy(
1438 (*newStr)->buffer + i, to, toLength * sizeof (sal_Unicode));
1440 memcpy(
1441 (*newStr)->buffer + i + toLength,
1442 str->buffer + i + fromLength,
1443 (str->length - i - fromLength) * sizeof (sal_Unicode));
1445 rtl_uString_release(str);
1448 *index = i;
1451 void rtl_uString_newReplaceAll(
1452 rtl_uString ** newStr, rtl_uString * str, rtl_uString const * from,
1453 rtl_uString const * to) SAL_THROW_EXTERN_C()
1455 rtl_uString_newReplaceAllFromIndex( newStr, str, from, to, 0 );
1458 void rtl_uString_newReplaceAllFromIndex(
1459 rtl_uString ** newStr, rtl_uString * str, rtl_uString const * from,
1460 rtl_uString const * to, sal_Int32 fromIndex) SAL_THROW_EXTERN_C()
1462 assert(to != nullptr);
1463 assert(fromIndex >= 0 && fromIndex <= str->length);
1464 rtl_uString_assign(newStr, str);
1465 for (sal_Int32 i = fromIndex;; i += to->length) {
1466 rtl_uString_newReplaceFirst(newStr, *newStr, from, to, &i);
1467 if (i == -1) {
1468 break;
1473 void rtl_uString_newReplaceAllAsciiL(
1474 rtl_uString ** newStr, rtl_uString * str, char const * from,
1475 sal_Int32 fromLength, rtl_uString const * to) SAL_THROW_EXTERN_C()
1477 assert(to != nullptr);
1478 rtl_uString_assign(newStr, str);
1479 for (sal_Int32 i = 0;; i += to->length) {
1480 rtl_uString_newReplaceFirstAsciiL(
1481 newStr, *newStr, from, fromLength, to, &i);
1482 if (i == -1) {
1483 break;
1488 void rtl_uString_newReplaceAllToAsciiL(
1489 rtl_uString ** newStr, rtl_uString * str, rtl_uString const * from,
1490 char const * to, sal_Int32 toLength) SAL_THROW_EXTERN_C()
1492 assert(from != nullptr);
1493 rtl_uString_assign(newStr, str);
1494 for (sal_Int32 i = 0;; i += toLength) {
1495 rtl_uString_newReplaceFirstToAsciiL(
1496 newStr, *newStr, from, to, toLength, &i);
1497 if (i == -1) {
1498 break;
1503 void rtl_uString_newReplaceAllAsciiLAsciiL(
1504 rtl_uString ** newStr, rtl_uString * str, char const * from,
1505 sal_Int32 fromLength, char const * to, sal_Int32 toLength)
1506 SAL_THROW_EXTERN_C()
1508 assert(toLength >= 0);
1509 rtl_uString_assign(newStr, str);
1510 for (sal_Int32 i = 0;; i += toLength) {
1511 rtl_uString_newReplaceFirstAsciiLAsciiL(
1512 newStr, *newStr, from, fromLength, to, toLength, &i);
1513 if (i == -1) {
1514 break;
1519 void rtl_uString_newReplaceAllAsciiLUtf16L(
1520 rtl_uString ** newStr, rtl_uString * str, char const * from,
1521 sal_Int32 fromLength, sal_Unicode const * to, sal_Int32 toLength)
1522 SAL_THROW_EXTERN_C()
1524 assert(toLength >= 0);
1525 rtl_uString_assign(newStr, str);
1526 for (sal_Int32 i = 0;; i += toLength) {
1527 rtl_uString_newReplaceFirstAsciiLUtf16L(
1528 newStr, *newStr, from, fromLength, to, toLength, &i);
1529 if (i == -1 || *newStr == nullptr) {
1530 break;
1535 void rtl_uString_newReplaceAllUtf16LAsciiL(
1536 rtl_uString ** newStr, rtl_uString * str, sal_Unicode const * from,
1537 sal_Int32 fromLength, char const * to, sal_Int32 toLength)
1538 SAL_THROW_EXTERN_C()
1540 assert(toLength >= 0);
1541 rtl_uString_assign(newStr, str);
1542 for (sal_Int32 i = 0;; i += toLength) {
1543 rtl_uString_newReplaceFirstUtf16LAsciiL(
1544 newStr, *newStr, from, fromLength, to, toLength, &i);
1545 if (i == -1 || *newStr == nullptr) {
1546 break;
1551 void rtl_uString_newReplaceAllUtf16LUtf16L(
1552 rtl_uString ** newStr, rtl_uString * str, sal_Unicode const * from,
1553 sal_Int32 fromLength, sal_Unicode const * to, sal_Int32 toLength)
1554 SAL_THROW_EXTERN_C()
1556 rtl_uString_newReplaceAllFromIndexUtf16LUtf16L(newStr, str, from, fromLength, to, toLength, 0);
1559 void rtl_uString_newReplaceAllFromIndexUtf16LUtf16L(
1560 rtl_uString ** newStr, rtl_uString * str, sal_Unicode const * from,
1561 sal_Int32 fromLength, sal_Unicode const * to, sal_Int32 toLength, sal_Int32 fromIndex)
1562 SAL_THROW_EXTERN_C()
1564 assert(toLength >= 0);
1565 assert(fromIndex >= 0 && fromIndex <= str->length);
1566 rtl_uString_assign(newStr, str);
1567 for (sal_Int32 i = fromIndex;; i += toLength) {
1568 rtl_uString_newReplaceFirstUtf16LUtf16L(
1569 newStr, *newStr, from, fromLength, to, toLength, &i);
1570 if (i == -1 || *newStr == nullptr) {
1571 break;
1576 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */