1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
25 #include <osl/interlck.h>
26 #include <rtl/alloc.h>
27 #include <osl/diagnose.h>
28 #include <rtl/tencinfo.h>
31 #include <rtl/character.hxx>
32 #include <rtl/string.h>
36 /* ======================================================================= */
38 /* static data to be referenced by all empty strings
39 * the refCount is predefined to 1 and must never become 0 !
41 static rtl_String
const aImplEmpty_rtl_String
=
43 SAL_STRING_STATIC_FLAG
|1,
44 /* sal_Int32 refCount; */
45 0, /* sal_Int32 length; */
46 { 0 } /* sal_Char buffer[1]; */
49 /* ======================================================================= */
50 /* These macros are for the "poor-man templates" included from
51 * the strtmpl.cxx just below, used to share code between here and
55 #define IMPL_RTL_IS_USTRING 0
57 #define IMPL_RTL_STRCODE sal_Char
58 #define IMPL_RTL_USTRCODE( c ) (static_cast<unsigned char>(c))
59 #define IMPL_RTL_STRNAME( n ) rtl_str_ ## n
61 #define IMPL_RTL_STRINGNAME( n ) rtl_string_ ## n
62 #define IMPL_RTL_STRINGDATA rtl_String
63 #define IMPL_RTL_EMPTYSTRING aImplEmpty_rtl_String
66 #define RTL_LOG_STRING_BITS 8
69 /* ======================================================================= */
71 /* Include String/UString template code */
73 #include "strtmpl.cxx"
75 #undef IMPL_RTL_EMPTYSTRING
76 #undef IMPL_RTL_IS_USTRING
77 #undef IMPL_RTL_STRCODE
78 #undef IMPL_RTL_STRINGDATA
79 #undef IMPL_RTL_STRINGNAME
80 #undef IMPL_RTL_STRNAME
81 #undef IMPL_RTL_USTRCODE
82 #undef RTL_LOG_STRING_BITS
84 sal_Int32 SAL_CALL
rtl_str_valueOfFloat(sal_Char
* pStr
, float f
)
88 rtl_String
* pResult
= nullptr;
90 rtl_math_doubleToString(
91 &pResult
, nullptr, 0, f
, rtl_math_StringFormat_G
,
92 RTL_STR_MAX_VALUEOFFLOAT
- RTL_CONSTASCII_LENGTH("-x.E-xxx"), '.', nullptr, 0,
94 nLen
= pResult
->length
;
95 OSL_ASSERT(nLen
< RTL_STR_MAX_VALUEOFFLOAT
);
96 memcpy(pStr
, pResult
->buffer
, (nLen
+ 1) * sizeof(sal_Char
));
97 rtl_string_release(pResult
);
101 sal_Int32 SAL_CALL
rtl_str_valueOfDouble(sal_Char
* pStr
, double d
)
105 rtl_String
* pResult
= nullptr;
107 rtl_math_doubleToString(
108 &pResult
, nullptr, 0, d
, rtl_math_StringFormat_G
,
109 RTL_STR_MAX_VALUEOFDOUBLE
- RTL_CONSTASCII_LENGTH("-x.E-xxx"), '.', nullptr,
111 nLen
= pResult
->length
;
112 OSL_ASSERT(nLen
< RTL_STR_MAX_VALUEOFDOUBLE
);
113 memcpy(pStr
, pResult
->buffer
, (nLen
+ 1) * sizeof(sal_Char
));
114 rtl_string_release(pResult
);
118 float SAL_CALL
rtl_str_toFloat(sal_Char
const * pStr
) SAL_THROW_EXTERN_C()
121 return static_cast<float>(rtl_math_stringToDouble(pStr
, pStr
+ rtl_str_getLength(pStr
),
122 '.', 0, nullptr, nullptr));
125 double SAL_CALL
rtl_str_toDouble(sal_Char
const * pStr
) SAL_THROW_EXTERN_C()
128 return rtl_math_stringToDouble(pStr
, pStr
+ rtl_str_getLength(pStr
), '.', 0,
132 /* ======================================================================= */
134 static int rtl_ImplGetFastUTF8ByteLen( const sal_Unicode
* pStr
, sal_Int32 nLen
)
138 sal_uInt32 nUCS4Char
;
139 const sal_Unicode
* pEndStr
;
143 while ( pStr
< pEndStr
)
149 else if ( c
< 0x800 )
153 if ( !rtl::isHighSurrogate(c
) )
159 if ( pStr
+1 < pEndStr
)
162 if ( rtl::isLowSurrogate(c
) )
164 nUCS4Char
= rtl::combineSurrogates(nUCS4Char
, c
);
169 if ( nUCS4Char
< 0x10000 )
171 else if ( nUCS4Char
< 0x200000 )
173 else if ( nUCS4Char
< 0x4000000 )
186 /* ----------------------------------------------------------------------- */
188 static bool rtl_impl_convertUStringToString(rtl_String
** pTarget
,
189 sal_Unicode
const * pSource
,
191 rtl_TextEncoding nEncoding
,
195 assert(pTarget
!= nullptr);
196 assert(pSource
!= nullptr || nLength
== 0);
197 assert(nLength
>= 0);
198 OSL_ASSERT(nLength
== 0 || rtl_isOctetTextEncoding(nEncoding
));
201 rtl_string_new( pTarget
);
205 rtl_UnicodeToTextConverter hConverter
;
210 sal_Size nNotConvertedChars
;
211 sal_Size nMaxCharLen
;
213 /* Optimization for UTF-8 - we try to calculate the exact length */
214 /* For all other encoding we try a good estimation */
215 if ( nEncoding
== RTL_TEXTENCODING_UTF8
)
217 nNewLen
= rtl_ImplGetFastUTF8ByteLen( pSource
, nLength
);
218 /* Includes the string only ASCII, then we could copy
220 if ( nNewLen
== static_cast<sal_Size
>(nLength
) )
224 rtl_string_release( *pTarget
);
225 *pTarget
= rtl_string_ImplAlloc( nLength
);
226 OSL_ASSERT(*pTarget
!= nullptr);
227 pBuffer
= (*pTarget
)->buffer
;
230 /* Check ASCII range */
231 OSL_ENSURE( *pSource
<= 127,
232 "rtl_uString2String() - UTF8 test is encoding is wrong" );
234 *pBuffer
= static_cast<sal_Char
>(static_cast<unsigned char>(*pSource
));
247 rtl_TextEncodingInfo aTextEncInfo
;
248 aTextEncInfo
.StructSize
= sizeof( aTextEncInfo
);
249 if ( !rtl_getTextEncodingInfo( nEncoding
, &aTextEncInfo
) )
251 aTextEncInfo
.AverageCharSize
= 1;
252 aTextEncInfo
.MaximumCharSize
= 8;
255 nNewLen
= nLength
* static_cast<sal_Size
>(aTextEncInfo
.AverageCharSize
);
256 nMaxCharLen
= aTextEncInfo
.MaximumCharSize
;
259 nFlags
|= RTL_UNICODETOTEXT_FLAGS_FLUSH
;
260 hConverter
= rtl_createUnicodeToTextConverter( nEncoding
);
264 pTemp
= rtl_string_ImplAlloc( nNewLen
);
265 OSL_ASSERT(pTemp
!= nullptr);
266 nDestBytes
= rtl_convertUnicodeToText( hConverter
, nullptr,
268 pTemp
->buffer
, nNewLen
,
270 &nInfo
, &nSrcChars
);
271 if (bCheckErrors
&& (nInfo
& RTL_UNICODETOTEXT_INFO_ERROR
) != 0)
273 rtl_freeString(pTemp
);
274 rtl_destroyUnicodeToTextConverter(hConverter
);
278 if ((nInfo
& RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL
) == 0)
281 /* Buffer not big enough, try again with enough space */
282 rtl_freeString( pTemp
);
284 /* Try with the max. count of characters with
285 additional overhead for replacing functionality */
286 nNotConvertedChars
= nLength
-nSrcChars
;
287 nNewLen
= nDestBytes
+(nNotConvertedChars
*nMaxCharLen
)+nNotConvertedChars
+4;
290 /* Set the buffer to the correct size or is there to
291 much overhead, reallocate to the correct size */
292 if ( nNewLen
> nDestBytes
+8 )
294 rtl_String
* pTemp2
= rtl_string_ImplAlloc( nDestBytes
);
295 OSL_ASSERT(pTemp2
!= nullptr);
296 rtl_str_ImplCopy( pTemp2
->buffer
, pTemp
->buffer
, nDestBytes
);
297 rtl_freeString( pTemp
);
302 pTemp
->length
= nDestBytes
;
303 pTemp
->buffer
[nDestBytes
] = 0;
306 rtl_destroyUnicodeToTextConverter( hConverter
);
308 rtl_string_release( *pTarget
);
311 /* Results the conversion in an empty buffer -
312 create an empty string */
313 if ( pTemp
&& !nDestBytes
)
314 rtl_string_new( pTarget
);
319 void SAL_CALL
rtl_uString2String( rtl_String
** ppThis
,
320 const sal_Unicode
* pUStr
,
322 rtl_TextEncoding eTextEncoding
,
323 sal_uInt32 nCvtFlags
)
326 rtl_impl_convertUStringToString(ppThis
, pUStr
, nULen
, eTextEncoding
,
330 sal_Bool SAL_CALL
rtl_convertUStringToString(rtl_String
** pTarget
,
331 sal_Unicode
const * pSource
,
333 rtl_TextEncoding nEncoding
,
337 return rtl_impl_convertUStringToString(pTarget
, pSource
, nLength
, nEncoding
,
341 void rtl_string_newReplaceFirst(
342 rtl_String
** newStr
, rtl_String
* str
, char const * from
,
343 sal_Int32 fromLength
, char const * to
, sal_Int32 toLength
,
344 sal_Int32
* index
) SAL_THROW_EXTERN_C()
346 assert(str
!= nullptr);
347 assert(index
!= nullptr);
348 assert(*index
>= 0 && *index
<= str
->length
);
349 assert(fromLength
>= 0);
350 assert(toLength
>= 0);
351 sal_Int32 i
= rtl_str_indexOfStr_WithLength(
352 str
->buffer
+ *index
, str
->length
- *index
, from
, fromLength
);
354 rtl_string_assign(newStr
, str
);
356 assert(i
<= str
->length
- *index
);
358 assert(fromLength
<= str
->length
);
359 if (str
->length
- fromLength
> SAL_MAX_INT32
- toLength
) {
362 sal_Int32 n
= str
->length
- fromLength
+ toLength
;
363 rtl_string_acquire(str
); // in case *newStr == str
364 rtl_string_new_WithLength(newStr
, n
);
366 (*newStr
)->length
= n
;
367 assert(i
>= 0 && i
< str
->length
);
368 memcpy((*newStr
)->buffer
, str
->buffer
, i
);
369 memcpy((*newStr
)->buffer
+ i
, to
, toLength
);
371 (*newStr
)->buffer
+ i
+ toLength
, str
->buffer
+ i
+ fromLength
,
372 str
->length
- i
- fromLength
);
374 rtl_string_release(str
);
379 void rtl_string_newReplaceAll(
380 rtl_String
** newStr
, rtl_String
* str
, char const * from
,
381 sal_Int32 fromLength
, char const * to
, sal_Int32 toLength
)
384 rtl_string_assign(newStr
, str
);
385 for (sal_Int32 i
= 0;; i
+= toLength
) {
386 rtl_string_newReplaceFirst(
387 newStr
, *newStr
, from
, fromLength
, to
, toLength
, &i
);
394 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */