xref: /trunk/main/sal/rtl/source/ustring.c (revision ee5121da92cb9fa76cc1dba8422013fb0ffc4842)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
24 #pragma warning(disable:4738) // storing 32-bit float result in memory, possible loss of performance
25 #endif
26 
27 #include <rtl/memory.h>
28 #include <osl/diagnose.h>
29 #include <osl/interlck.h>
30 #include <rtl/alloc.h>
31 #include <osl/mutex.h>
32 #include <osl/doublecheckedlocking.h>
33 #include <rtl/tencinfo.h>
34 
35 #include <string.h>
36 #include <sal/alloca.h>
37 
38 #include "hash.h"
39 #include "strimp.h"
40 #include "surrogates.h"
41 #include <rtl/ustring.h>
42 
43 #include "rtl/math.h"
44 #include "rtl/tencinfo.h"
45 
46 /* ======================================================================= */
47 
48 /* static data to be referenced by all empty strings
49  * the refCount is predefined to 1 and must never become 0 !
50  */
51 static rtl_uString const aImplEmpty_rtl_uString =
52 {
53     (sal_Int32) (SAL_STRING_INTERN_FLAG|SAL_STRING_STATIC_FLAG|1), /*sal_Int32    refCount; */
54     0,                                               /*sal_Int32    length;   */
55     { 0 }                                            /*sal_Unicode  buffer[1];*/
56 };
57 
58 /* ======================================================================= */
59 
60 #define IMPL_RTL_STRCODE            sal_Unicode
61 #define IMPL_RTL_USTRCODE( c )      (c)
62 #define IMPL_RTL_STRNAME( n )       rtl_ustr_ ## n
63 
64 #define IMPL_RTL_STRINGNAME( n )    rtl_uString_ ## n
65 #define IMPL_RTL_STRINGDATA         rtl_uString
66 #define IMPL_RTL_EMPTYSTRING        aImplEmpty_rtl_uString
67 #define IMPL_RTL_INTERN
68 static void internRelease (rtl_uString *pThis);
69 
70 /* ======================================================================= */
71 
72 /* Include String/UString template code */
73 
74 #include "strtmpl.c"
75 
rtl_ustr_indexOfAscii_WithLength(sal_Unicode const * str,sal_Int32 len,char const * subStr,sal_Int32 subLen)76 sal_Int32 rtl_ustr_indexOfAscii_WithLength(
77     sal_Unicode const * str, sal_Int32 len,
78     char const * subStr, sal_Int32 subLen)
79 {
80     if (subLen > 0 && subLen <= len) {
81         sal_Int32 i;
82         for (i = 0; i <= len - subLen; ++i) {
83             if (rtl_ustr_asciil_reverseEquals_WithLength(
84                     str + i, subStr, subLen))
85             {
86                 return i;
87             }
88         }
89     }
90     return -1;
91 }
92 
rtl_ustr_lastIndexOfAscii_WithLength(sal_Unicode const * str,sal_Int32 len,char const * subStr,sal_Int32 subLen)93 sal_Int32 rtl_ustr_lastIndexOfAscii_WithLength(
94     sal_Unicode const * str, sal_Int32 len,
95     char const * subStr, sal_Int32 subLen)
96 {
97     if (subLen > 0 && subLen <= len) {
98         sal_Int32 i;
99         for (i = len - subLen; i >= 0; --i) {
100             if (rtl_ustr_asciil_reverseEquals_WithLength(
101                     str + i, subStr, subLen))
102             {
103                 return i;
104             }
105         }
106     }
107     return -1;
108 }
109 
rtl_ustr_valueOfFloat(sal_Unicode * pStr,float f)110 sal_Int32 SAL_CALL rtl_ustr_valueOfFloat(sal_Unicode * pStr, float f)
111 {
112     rtl_uString * pResult = NULL;
113     sal_Int32 nLen;
114     rtl_math_doubleToUString(
115         &pResult, 0, 0, f, rtl_math_StringFormat_G,
116         RTL_USTR_MAX_VALUEOFFLOAT - RTL_CONSTASCII_LENGTH("-x.E-xxx"), '.', 0,
117         0, sal_True);
118     nLen = pResult->length;
119     OSL_ASSERT(nLen < RTL_USTR_MAX_VALUEOFFLOAT);
120     rtl_copyMemory(pStr, pResult->buffer, (nLen + 1) * sizeof(sal_Unicode));
121     rtl_uString_release(pResult);
122     return nLen;
123 }
124 
rtl_ustr_valueOfDouble(sal_Unicode * pStr,double d)125 sal_Int32 SAL_CALL rtl_ustr_valueOfDouble(sal_Unicode * pStr, double d)
126 {
127     rtl_uString * pResult = NULL;
128     sal_Int32 nLen;
129     rtl_math_doubleToUString(
130         &pResult, 0, 0, d, rtl_math_StringFormat_G,
131         RTL_USTR_MAX_VALUEOFDOUBLE - RTL_CONSTASCII_LENGTH("-x.E-xxx"), '.', 0,
132         0, sal_True);
133     nLen = pResult->length;
134     OSL_ASSERT(nLen < RTL_USTR_MAX_VALUEOFDOUBLE);
135     rtl_copyMemory(pStr, pResult->buffer, (nLen + 1) * sizeof(sal_Unicode));
136     rtl_uString_release(pResult);
137     return nLen;
138 }
139 
rtl_ustr_toFloat(sal_Unicode const * pStr)140 float SAL_CALL rtl_ustr_toFloat(sal_Unicode const * pStr)
141 {
142     return (float) rtl_math_uStringToDouble(pStr,
143                                             pStr + rtl_ustr_getLength(pStr),
144                                             '.', 0, 0, 0);
145 }
146 
rtl_ustr_toDouble(sal_Unicode const * pStr)147 double SAL_CALL rtl_ustr_toDouble(sal_Unicode const * pStr)
148 {
149     return rtl_math_uStringToDouble(pStr, pStr + rtl_ustr_getLength(pStr), '.',
150                                     0, 0, 0);
151 }
152 
153 /* ======================================================================= */
154 /* NULL-pointer guards for the mixed UTF-16 / ASCII comparison helpers.    */
155 /*                                                                         */
156 /* These follow the same policy as strtmpl.c (which is #included above and */
157 /* already defines the sal_Unicode empty string aImplGuardEmptyStr): the   */
158 /* public functions document a non-NULL, null-terminated contract; a NULL  */
159 /* argument is diagnosed in non-product builds via OSL_PRECOND and treated */
160 /* as the empty string otherwise, so NULL is never dereferenced.  The      */
161 /* guards are at function entry, outside the per-character loops.          */
162 /* ======================================================================= */
163 
164 #if OSL_DEBUG_LEVEL > 0
165 
166 static const sal_Char aImplGuardEmptyAscii = 0;
167 
168 /* Null-terminated ASCII argument: treat NULL as the empty string. */
169 #define IMPL_RTL_ASCII_NULL_AS_EMPTY( pAscii )                              \
170     do {                                                                    \
171         OSL_PRECOND( (pAscii) != NULL,                                      \
172             "rtl_ustr_ascii_*: NULL ASCII pointer passed; contract "        \
173             "requires a non-NULL, null-terminated string" );                \
174         if ( !(pAscii) )                                                    \
175             (pAscii) = &aImplGuardEmptyAscii;                               \
176     } while (0)
177 
178 /* Null-terminated UTF-16 argument: treat NULL as the empty string. */
179 #define IMPL_RTL_UNI_NULL_AS_EMPTY( pUni )                                  \
180     do {                                                                    \
181         OSL_PRECOND( (pUni) != NULL,                                        \
182             "rtl_ustr_ascii_*: NULL string pointer passed; contract "       \
183             "requires a non-NULL, null-terminated string" );                \
184         if ( !(pUni) )                                                      \
185             (pUni) = &aImplGuardEmptyStr;                                   \
186     } while (0)
187 
188 /* Length-bounded UTF-16 argument: a NULL pointer is an empty (length 0)    */
189 /* string.  Clamp the length to 0 so the pointer is never dereferenced and  */
190 /* substitute a valid buffer to avoid NULL pointer arithmetic (pStr + len). */
191 #define IMPL_RTL_UNI_NULL_AS_EMPTY_LEN( pUni, nLen )                        \
192     do {                                                                    \
193         OSL_PRECOND( (pUni) != NULL,                                        \
194             "rtl_ustr_ascii_*: NULL string pointer passed; contract "       \
195             "requires a valid buffer of the given length" );                \
196         if ( !(pUni) )                                                      \
197         {                                                                   \
198             (pUni) = &aImplGuardEmptyStr;                                   \
199             (nLen) = 0;                                                     \
200         }                                                                   \
201     } while (0)
202 
203 #else /* product build: guards compile away, callers must honour contract */
204 
205 #define IMPL_RTL_ASCII_NULL_AS_EMPTY( pAscii )        ((void)0)
206 #define IMPL_RTL_UNI_NULL_AS_EMPTY( pUni )            ((void)0)
207 #define IMPL_RTL_UNI_NULL_AS_EMPTY_LEN( pUni, nLen )  ((void)0)
208 
209 #endif
210 
rtl_ustr_ascii_compare(const sal_Unicode * pStr1,const sal_Char * pStr2)211 sal_Int32 SAL_CALL rtl_ustr_ascii_compare( const sal_Unicode* pStr1,
212                                            const sal_Char* pStr2 )
213 {
214     sal_Int32 nRet;
215     IMPL_RTL_UNI_NULL_AS_EMPTY( pStr1 );
216     IMPL_RTL_ASCII_NULL_AS_EMPTY( pStr2 );
217     while ( ((nRet = ((sal_Int32)(*pStr1))-
218                      ((sal_Int32)((unsigned char)(*pStr2)))) == 0) &&
219             *pStr2 )
220     {
221         pStr1++;
222         pStr2++;
223     }
224 
225     return nRet;
226 }
227 
228 /* ----------------------------------------------------------------------- */
229 
rtl_ustr_ascii_compare_WithLength(const sal_Unicode * pStr1,sal_Int32 nStr1Len,const sal_Char * pStr2)230 sal_Int32 SAL_CALL rtl_ustr_ascii_compare_WithLength( const sal_Unicode* pStr1,
231                                                       sal_Int32 nStr1Len,
232                                                       const sal_Char* pStr2 )
233 {
234     sal_Int32 nRet = 0;
235     IMPL_RTL_UNI_NULL_AS_EMPTY_LEN( pStr1, nStr1Len );
236     IMPL_RTL_ASCII_NULL_AS_EMPTY( pStr2 );
237     while( ((nRet = (nStr1Len ? (sal_Int32)(*pStr1) : 0)-
238                     ((sal_Int32)((unsigned char)(*pStr2)))) == 0) &&
239            nStr1Len && *pStr2 )
240     {
241         pStr1++;
242         pStr2++;
243         nStr1Len--;
244     }
245 
246     return nRet;
247 }
248 
249 /* ----------------------------------------------------------------------- */
250 
rtl_ustr_ascii_shortenedCompare_WithLength(const sal_Unicode * pStr1,sal_Int32 nStr1Len,const sal_Char * pStr2,sal_Int32 nShortenedLength)251 sal_Int32 SAL_CALL rtl_ustr_ascii_shortenedCompare_WithLength( const sal_Unicode* pStr1,
252                                                                sal_Int32 nStr1Len,
253                                                                const sal_Char* pStr2,
254                                                                sal_Int32 nShortenedLength )
255 {
256     const sal_Unicode*  pStr1End;
257     sal_Int32           nRet;
258     IMPL_RTL_UNI_NULL_AS_EMPTY_LEN( pStr1, nStr1Len );
259     IMPL_RTL_ASCII_NULL_AS_EMPTY( pStr2 );
260     pStr1End = pStr1 + nStr1Len;
261     while ( (nShortenedLength > 0) &&
262             (pStr1 < pStr1End) && *pStr2 )
263     {
264         /* Check ASCII range */
265         OSL_ENSURE( (*pStr2 & 0x80) == 0, "Found ASCII char > 127");
266 
267         nRet = ((sal_Int32)*pStr1)-
268                ((sal_Int32)(unsigned char)*pStr2);
269         if ( nRet != 0 )
270             return nRet;
271 
272         nShortenedLength--;
273         pStr1++;
274         pStr2++;
275     }
276 
277     if ( nShortenedLength <= 0 )
278         return 0;
279 
280     if ( *pStr2 )
281     {
282         OSL_ENSURE( pStr1 == pStr1End, "pStr1 == pStr1End failed" );
283         // first is a substring of the second string => less (negative value)
284         nRet = -1;
285     }
286     else
287     {
288         // greater or equal
289         nRet = pStr1End - pStr1;
290     }
291 
292     return nRet;
293 }
294 
295 /* ----------------------------------------------------------------------- */
296 
rtl_ustr_asciil_reverseCompare_WithLength(const sal_Unicode * pStr1,sal_Int32 nStr1Len,const sal_Char * pStr2,sal_Int32 nStr2Len)297 sal_Int32 SAL_CALL rtl_ustr_asciil_reverseCompare_WithLength( const sal_Unicode* pStr1,
298                                                               sal_Int32 nStr1Len,
299                                                               const sal_Char* pStr2,
300                                                               sal_Int32 nStr2Len )
301 {
302     const sal_Unicode*  pStr1Run = pStr1+nStr1Len;
303     const sal_Char*     pStr2Run = pStr2+nStr2Len;
304     sal_Int32           nRet;
305     while ( (pStr1 < pStr1Run) && (pStr2 < pStr2Run) )
306     {
307         pStr1Run--;
308         pStr2Run--;
309         nRet = ((sal_Int32)*pStr1Run)-((sal_Int32)*pStr2Run);
310         if ( nRet )
311             return nRet;
312     }
313 
314     return nStr1Len - nStr2Len;
315 }
316 
317 /* ----------------------------------------------------------------------- */
318 
rtl_ustr_asciil_reverseEquals_WithLength(const sal_Unicode * pStr1,const sal_Char * pStr2,sal_Int32 nStrLen)319 sal_Bool SAL_CALL rtl_ustr_asciil_reverseEquals_WithLength( const sal_Unicode* pStr1,
320                                                               const sal_Char* pStr2,
321                                                               sal_Int32 nStrLen )
322 {
323     const sal_Unicode*  pStr1Run = pStr1+nStrLen;
324     const sal_Char*     pStr2Run = pStr2+nStrLen;
325     while ( pStr1 < pStr1Run )
326     {
327         pStr1Run--;
328         pStr2Run--;
329         if( *pStr1Run != (sal_Unicode)*pStr2Run )
330             return sal_False;
331     }
332 
333     return sal_True;
334 }
335 
336 /* ----------------------------------------------------------------------- */
337 
rtl_ustr_ascii_compareIgnoreAsciiCase(const sal_Unicode * pStr1,const sal_Char * pStr2)338 sal_Int32 SAL_CALL rtl_ustr_ascii_compareIgnoreAsciiCase( const sal_Unicode* pStr1,
339                                                           const sal_Char* pStr2 )
340 {
341     sal_Int32   nRet;
342     sal_Int32   c1;
343     sal_Int32   c2;
344     IMPL_RTL_UNI_NULL_AS_EMPTY( pStr1 );
345     IMPL_RTL_ASCII_NULL_AS_EMPTY( pStr2 );
346     do
347     {
348         /* If character between 'A' and 'Z', than convert it to lowercase */
349         c1 = (sal_Int32)*pStr1;
350         c2 = (sal_Int32)((unsigned char)*pStr2);
351         if ( (c1 >= 65) && (c1 <= 90) )
352             c1 += 32;
353         if ( (c2 >= 65) && (c2 <= 90) )
354             c2 += 32;
355         nRet = c1-c2;
356         if ( nRet != 0 )
357             return nRet;
358 
359         pStr1++;
360         pStr2++;
361     }
362     while ( c2 );
363 
364     return 0;
365 }
366 
367 /* ----------------------------------------------------------------------- */
368 
rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength(const sal_Unicode * pStr1,sal_Int32 nStr1Len,const sal_Char * pStr2)369 sal_Int32 SAL_CALL rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( const sal_Unicode* pStr1,
370                                                                      sal_Int32 nStr1Len,
371                                                                      const sal_Char* pStr2 )
372 {
373     sal_Int32   nRet;
374     sal_Int32   c1;
375     sal_Int32   c2;
376     IMPL_RTL_UNI_NULL_AS_EMPTY_LEN( pStr1, nStr1Len );
377     IMPL_RTL_ASCII_NULL_AS_EMPTY( pStr2 );
378     do
379     {
380         if ( !nStr1Len )
381             return *pStr2 == '\0' ? 0 : -1;
382 
383         /* If character between 'A' and 'Z', than convert it to lowercase */
384         c1 = (sal_Int32)*pStr1;
385         c2 = (sal_Int32)((unsigned char)*pStr2);
386         if ( (c1 >= 65) && (c1 <= 90) )
387             c1 += 32;
388         if ( (c2 >= 65) && (c2 <= 90) )
389             c2 += 32;
390         nRet = c1-c2;
391         if ( nRet != 0 )
392             return nRet;
393 
394         pStr1++;
395         pStr2++;
396         nStr1Len--;
397     }
398     while( c2 );
399 
400     return 0;
401 }
402 
rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths(sal_Unicode const * first,sal_Int32 firstLen,char const * second,sal_Int32 secondLen)403 sal_Int32 rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths(
404     sal_Unicode const * first, sal_Int32 firstLen,
405     char const * second, sal_Int32 secondLen)
406 {
407     sal_Int32 i;
408     sal_Int32 len = firstLen < secondLen ? firstLen : secondLen;
409     for (i = 0; i < len; ++i) {
410         sal_Int32 c1 = *first++;
411         sal_Int32 c2 = (unsigned char) *second++;
412         sal_Int32 d;
413         if (c1 >= 65 && c1 <= 90) {
414             c1 += 32;
415         }
416         if (c2 >= 65 && c2 <= 90) {
417             c2 += 32;
418         }
419         d = c1 - c2;
420         if (d != 0) {
421             return d;
422         }
423     }
424     return firstLen - secondLen;
425 }
426 
427 /* ----------------------------------------------------------------------- */
428 
rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength(const sal_Unicode * pStr1,sal_Int32 nStr1Len,const sal_Char * pStr2,sal_Int32 nShortenedLength)429 sal_Int32 SAL_CALL rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( const sal_Unicode* pStr1,
430                                                                               sal_Int32 nStr1Len,
431                                                                               const sal_Char* pStr2,
432                                                                               sal_Int32 nShortenedLength )
433 {
434     const sal_Unicode*  pStr1End;
435     sal_Int32           nRet;
436     sal_Int32           c1;
437     sal_Int32           c2;
438     IMPL_RTL_UNI_NULL_AS_EMPTY_LEN( pStr1, nStr1Len );
439     IMPL_RTL_ASCII_NULL_AS_EMPTY( pStr2 );
440     pStr1End = pStr1 + nStr1Len;
441     while ( (nShortenedLength > 0) &&
442             (pStr1 < pStr1End) && *pStr2 )
443     {
444         /* Check ASCII range */
445         OSL_ENSURE( (*pStr2 & 0x80) == 0, "Found ASCII char > 127");
446 
447         /* If character between 'A' and 'Z', than convert it to lowercase */
448         c1 = (sal_Int32)*pStr1;
449         c2 = (sal_Int32)((unsigned char)*pStr2);
450         if ( (c1 >= 65) && (c1 <= 90) )
451             c1 += 32;
452         if ( (c2 >= 65) && (c2 <= 90) )
453             c2 += 32;
454         nRet = c1-c2;
455         if ( nRet != 0 )
456             return nRet;
457 
458         nShortenedLength--;
459         pStr1++;
460         pStr2++;
461     }
462 
463     if ( nShortenedLength <= 0 )
464         return 0;
465 
466     if ( *pStr2 )
467     {
468         OSL_ENSURE( pStr1 == pStr1End, "pStr1 == pStr1End failed" );
469         // first is a substring of the second string => less (negative value)
470         nRet = -1;
471     }
472     else
473     {
474         // greater or equal
475         nRet = pStr1End - pStr1;
476     }
477 
478     return nRet;
479 }
480 
481 /* ----------------------------------------------------------------------- */
482 
rtl_uString_newFromAscii(rtl_uString ** ppThis,const sal_Char * pCharStr)483 void SAL_CALL rtl_uString_newFromAscii( rtl_uString** ppThis,
484                                         const sal_Char* pCharStr )
485 {
486     sal_Int32 nLen;
487 
488     if ( pCharStr )
489     {
490         const sal_Char* pTempStr = pCharStr;
491         while( *pTempStr )
492             pTempStr++;
493         nLen = pTempStr-pCharStr;
494     }
495     else
496         nLen = 0;
497 
498     if ( !nLen )
499     {
500         IMPL_RTL_STRINGNAME( new )( ppThis );
501         return;
502     }
503 
504     if ( *ppThis )
505         IMPL_RTL_STRINGNAME( release )( *ppThis );
506 
507     *ppThis = IMPL_RTL_STRINGNAME( ImplAlloc )( nLen );
508     OSL_ASSERT(*ppThis != NULL);
509     if ( (*ppThis) )
510     {
511         IMPL_RTL_STRCODE* pBuffer = (*ppThis)->buffer;
512         do
513         {
514             /* Check ASCII range */
515             OSL_ENSURE( ((unsigned char)*pCharStr) <= 127,
516                         "rtl_uString_newFromAscii() - Found ASCII char > 127" );
517 
518             *pBuffer = *pCharStr;
519             pBuffer++;
520             pCharStr++;
521         }
522         while ( *pCharStr );
523     }
524 }
525 
rtl_uString_newFromCodePoints(rtl_uString ** newString,sal_uInt32 const * codePoints,sal_Int32 codePointCount)526 void SAL_CALL rtl_uString_newFromCodePoints(
527     rtl_uString ** newString, sal_uInt32 const * codePoints,
528     sal_Int32 codePointCount)
529 {
530     sal_Int32 n;
531     sal_Int32 i;
532     sal_Unicode * p;
533     OSL_ASSERT(
534         newString != NULL &&
535         (codePoints != NULL || codePointCount == 0) &&
536         codePointCount >= 0);
537     if (codePointCount == 0) {
538         rtl_uString_new(newString);
539         return;
540     }
541     if (*newString != NULL) {
542         rtl_uString_release(*newString);
543     }
544     n = codePointCount;
545     for (i = 0; i < codePointCount; ++i) {
546         OSL_ASSERT(codePoints[i] <= 0x10FFFF);
547         if (codePoints[i] >= 0x10000) {
548             ++n;
549         }
550     }
551     /* Builds on the assumption that sal_Int32 uses 32 bit two's complement
552        representation with wrap around (the necessary number of UTF-16 code
553        units will be no larger than 2 * SAL_MAX_INT32, represented as
554        sal_Int32 -2): */
555     if (n < 0) {
556         *newString = NULL;
557         return;
558     }
559     *newString = rtl_uString_ImplAlloc(n);
560     if (*newString == NULL) {
561         return;
562     }
563     p = (*newString)->buffer;
564     for (i = 0; i < codePointCount; ++i) {
565         sal_uInt32 c = codePoints[i];
566         if (c < 0x10000) {
567             *p++ = (sal_Unicode) c;
568         } else {
569             c -= 0x10000;
570             *p++ = (sal_Unicode) ((c >> 10) | SAL_RTL_FIRST_HIGH_SURROGATE);
571             *p++ = (sal_Unicode) ((c & 0x3FF) | SAL_RTL_FIRST_LOW_SURROGATE);
572         }
573     }
574 }
575 
576 /* ======================================================================= */
577 
rtl_ImplGetFastUTF8UnicodeLen(const sal_Char * pStr,sal_Int32 nLen)578 static int rtl_ImplGetFastUTF8UnicodeLen( const sal_Char* pStr, sal_Int32 nLen )
579 {
580     int             n;
581     sal_uChar       c;
582     const sal_Char* pEndStr;
583 
584     n = 0;
585     pEndStr  = pStr+nLen;
586     while ( pStr < pEndStr )
587     {
588         c = (sal_uChar)*pStr;
589 
590         if ( !(c & 0x80) )
591             pStr++;
592         else if ( (c & 0xE0) == 0xC0 )
593             pStr += 2;
594         else if ( (c & 0xF0) == 0xE0 )
595             pStr += 3;
596         else if ( (c & 0xF8) == 0xF0 )
597             pStr += 4;
598         else if ( (c & 0xFC) == 0xF8 )
599             pStr += 5;
600         else if ( (c & 0xFE) == 0xFC )
601             pStr += 6;
602         else
603             pStr++;
604 
605         n++;
606     }
607 
608     return n;
609 }
610 
611 /* ----------------------------------------------------------------------- */
612 
rtl_string2UString_status(rtl_uString ** ppThis,const sal_Char * pStr,sal_Int32 nLen,rtl_TextEncoding eTextEncoding,sal_uInt32 nCvtFlags,sal_uInt32 * pInfo)613 static void rtl_string2UString_status( rtl_uString** ppThis,
614                                        const sal_Char* pStr,
615                                        sal_Int32 nLen,
616                                        rtl_TextEncoding eTextEncoding,
617                                        sal_uInt32 nCvtFlags,
618                                        sal_uInt32 *pInfo )
619 {
620     OSL_ENSURE(rtl_isOctetTextEncoding(eTextEncoding),
621                "rtl_string2UString_status() - Wrong TextEncoding" );
622 
623     if ( !nLen )
624     {
625         rtl_uString_new( ppThis );
626         if (pInfo != NULL) {
627             *pInfo = 0;
628         }
629     }
630     else
631     {
632         if ( *ppThis )
633             IMPL_RTL_STRINGNAME( release )( *ppThis );
634 
635         /* Optimization for US-ASCII */
636         if ( eTextEncoding == RTL_TEXTENCODING_ASCII_US )
637         {
638             IMPL_RTL_STRCODE* pBuffer;
639             *ppThis = IMPL_RTL_STRINGNAME( ImplAlloc )( nLen );
640             if (*ppThis == NULL) {
641                 if (pInfo != NULL) {
642                     *pInfo = RTL_TEXTTOUNICODE_INFO_ERROR |
643                         RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL;
644                 }
645                 return;
646             }
647             pBuffer = (*ppThis)->buffer;
648             do
649             {
650                 /* Check ASCII range */
651                 OSL_ENSURE( ((unsigned char)*pStr) <= 127,
652                             "rtl_string2UString_status() - Found char > 127 and RTL_TEXTENCODING_ASCII_US is specified" );
653 
654                 *pBuffer = *pStr;
655                 pBuffer++;
656                 pStr++;
657                 nLen--;
658             }
659             while ( nLen );
660             if (pInfo != NULL) {
661                 *pInfo = 0;
662             }
663         }
664         else
665         {
666             rtl_uString*                pTemp;
667             rtl_uString*                pTemp2 = NULL;
668             rtl_TextToUnicodeConverter  hConverter;
669             sal_uInt32                  nInfo;
670             sal_Size                    nSrcBytes;
671             sal_Size                    nDestChars;
672             sal_Size                    nNewLen;
673 
674             /* Optimization for UTF-8 - we try to calculate the exact length */
675             /* For all other encoding we try the maximum - and reallocate
676                the buffer if needed */
677             if ( eTextEncoding == RTL_TEXTENCODING_UTF8 )
678             {
679                 nNewLen = rtl_ImplGetFastUTF8UnicodeLen( pStr, nLen );
680                 /* Includes the string only ASCII, then we could copy
681                    the buffer faster */
682                 if ( nNewLen == (sal_Size)nLen )
683                 {
684                     IMPL_RTL_STRCODE* pBuffer;
685                     *ppThis = IMPL_RTL_STRINGNAME( ImplAlloc )( nLen );
686                     if (*ppThis == NULL)
687                     {
688                         if (pInfo != NULL) {
689                             *pInfo = RTL_TEXTTOUNICODE_INFO_ERROR |
690                                 RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL;
691                         }
692                         return;
693                     }
694                     pBuffer = (*ppThis)->buffer;
695                     do
696                     {
697                         /* Check ASCII range */
698                         OSL_ENSURE( ((unsigned char)*pStr) <= 127,
699                                     "rtl_string2UString_status() - UTF8 test encoding is wrong" );
700 
701                         *pBuffer = *pStr;
702                         pBuffer++;
703                         pStr++;
704                         nLen--;
705                     }
706                     while ( nLen );
707                     if (pInfo != NULL) {
708                         *pInfo = 0;
709                     }
710                     return;
711                 }
712             }
713             else
714                 nNewLen = nLen;
715 
716             nCvtFlags |= RTL_TEXTTOUNICODE_FLAGS_FLUSH;
717             hConverter = rtl_createTextToUnicodeConverter( eTextEncoding );
718 
719             pTemp = IMPL_RTL_STRINGNAME( ImplAlloc )( nNewLen );
720             if (pTemp == NULL) {
721                 if (pInfo != NULL) {
722                     *pInfo = RTL_TEXTTOUNICODE_INFO_ERROR |
723                         RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL;
724                 }
725                 return;
726             }
727             nDestChars = rtl_convertTextToUnicode( hConverter, 0,
728                                                    pStr, nLen,
729                                                    pTemp->buffer, nNewLen,
730                                                    nCvtFlags,
731                                                    &nInfo, &nSrcBytes );
732 
733             /* Buffer not big enough, try again with enough space */
734             /* Shouldn't be the case, but if we get textencoding which
735                could results in more unicode characters we have this
736                code here. Could be the case for apple encodings */
737             while ( nInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL )
738             {
739                 rtl_freeMemory( pTemp );
740                 nNewLen += 8;
741                 pTemp = IMPL_RTL_STRINGNAME( ImplAlloc )( nNewLen );
742                 if (pTemp == NULL) {
743                     if (pInfo != NULL) {
744                         *pInfo = RTL_TEXTTOUNICODE_INFO_ERROR |
745                             RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL;
746                     }
747                     return;
748                 }
749                 nDestChars = rtl_convertTextToUnicode( hConverter, 0,
750                                                        pStr, nLen,
751                                                        pTemp->buffer, nNewLen,
752                                                        nCvtFlags,
753                                                        &nInfo, &nSrcBytes );
754             }
755 
756             if (pInfo)
757                 *pInfo = nInfo;
758 
759             /* Set the buffer to the correct size or if there is too
760                much overhead, reallocate to the correct size */
761             if ( nNewLen > nDestChars+8 )
762             {
763                 pTemp2 = IMPL_RTL_STRINGNAME( ImplAlloc )( nDestChars );
764             }
765             if (pTemp2 != NULL)
766             {
767                 rtl_str_ImplCopy(pTemp2->buffer, pTemp->buffer, nDestChars);
768                 rtl_freeMemory(pTemp);
769                 pTemp = pTemp2;
770             }
771             else
772             {
773                 pTemp->length = nDestChars;
774                 pTemp->buffer[nDestChars] = 0;
775             }
776 
777             rtl_destroyTextToUnicodeConverter( hConverter );
778             *ppThis = pTemp;
779 
780             /* Results the conversion in an empty buffer -
781                create an empty string */
782             if ( pTemp && !nDestChars )
783                 rtl_uString_new( ppThis );
784         }
785     }
786 }
787 
rtl_string2UString(rtl_uString ** ppThis,const sal_Char * pStr,sal_Int32 nLen,rtl_TextEncoding eTextEncoding,sal_uInt32 nCvtFlags)788 void SAL_CALL rtl_string2UString( rtl_uString** ppThis,
789                                   const sal_Char* pStr,
790                                   sal_Int32 nLen,
791                                   rtl_TextEncoding eTextEncoding,
792                                   sal_uInt32 nCvtFlags )
793 {
794     rtl_string2UString_status( ppThis, pStr, nLen, eTextEncoding,
795                                nCvtFlags, NULL );
796 }
797 
798 /* ----------------------------------------------------------------------- */
799 
800 typedef enum {
801     CANNOT_RETURN,
802     CAN_RETURN = 1
803 } StrLifecycle;
804 
805 static oslMutex
getInternMutex()806 getInternMutex()
807 {
808     static oslMutex pPoolGuard = NULL;
809     if( !pPoolGuard )
810     {
811         oslMutex pGlobalGuard;
812         pGlobalGuard = *osl_getGlobalMutex();
813         osl_acquireMutex( pGlobalGuard );
814         if( !pPoolGuard )
815         {
816             oslMutex p = osl_createMutex();
817             OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
818             pPoolGuard = p;
819         }
820         osl_releaseMutex( pGlobalGuard );
821     }
822     else
823     {
824         OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
825     }
826 
827     return pPoolGuard;
828 }
829 
830 /* returns true if we found a dup in the pool */
rtl_ustring_intern_internal(rtl_uString ** newStr,rtl_uString * str,StrLifecycle can_return)831 static void rtl_ustring_intern_internal( rtl_uString ** newStr,
832                                          rtl_uString  * str,
833                                          StrLifecycle   can_return )
834 {
835     oslMutex pPoolMutex;
836 
837     pPoolMutex = getInternMutex();
838 
839     osl_acquireMutex( pPoolMutex );
840 
841     *newStr = rtl_str_hash_intern (str, can_return);
842 
843     osl_releaseMutex( pPoolMutex );
844 
845     if( can_return && *newStr != str )
846     { /* we dupped, then found a match */
847         rtl_freeMemory( str );
848     }
849 }
850 
rtl_uString_intern(rtl_uString ** newStr,rtl_uString * str)851 void SAL_CALL rtl_uString_intern( rtl_uString ** newStr,
852                                   rtl_uString  * str)
853 {
854     if (SAL_STRING_IS_INTERN(str))
855     {
856         IMPL_RTL_AQUIRE( str );
857         *newStr = str;
858     }
859     else
860     {
861         rtl_uString *pOrg = *newStr;
862         *newStr = NULL;
863         rtl_ustring_intern_internal( newStr, str, CANNOT_RETURN );
864         if (pOrg)
865             rtl_uString_release (pOrg);
866     }
867 }
868 
rtl_uString_internConvert(rtl_uString ** newStr,const sal_Char * str,sal_Int32 len,rtl_TextEncoding eTextEncoding,sal_uInt32 convertFlags,sal_uInt32 * pInfo)869 void SAL_CALL rtl_uString_internConvert( rtl_uString   ** newStr,
870                                          const sal_Char * str,
871                                          sal_Int32        len,
872                                          rtl_TextEncoding eTextEncoding,
873                                          sal_uInt32       convertFlags,
874                                          sal_uInt32     * pInfo )
875 {
876     rtl_uString *scratch;
877 
878     if (*newStr)
879     {
880         rtl_uString_release (*newStr);
881         *newStr = NULL;
882     }
883 
884     if ( len < 256 )
885     { // try various optimisations
886         if ( len < 0 )
887             len = strlen( str );
888         if ( eTextEncoding == RTL_TEXTENCODING_ASCII_US )
889         {
890             int i;
891             rtl_uString *pScratch;
892             pScratch = alloca( sizeof( rtl_uString )
893                                + len * sizeof (IMPL_RTL_STRCODE ) );
894             for (i = 0; i < len; i++)
895             {
896                 /* Check ASCII range */
897                 OSL_ENSURE( ((unsigned char)str[i]) <= 127,
898                             "rtl_ustring_internConvert() - Found char > 127 and RTL_TEXTENCODING_ASCII_US is specified" );
899                 pScratch->buffer[i] = str[i];
900             }
901             pScratch->length = len;
902             rtl_ustring_intern_internal( newStr, pScratch, CANNOT_RETURN );
903             return;
904         }
905         /* FIXME: we want a nice UTF-8 / alloca shortcut here */
906     }
907 
908     scratch = NULL;
909     rtl_string2UString_status( &scratch, str, len, eTextEncoding, convertFlags,
910                                pInfo );
911     if (!scratch) {
912         return;
913     }
914     rtl_ustring_intern_internal( newStr, scratch, CAN_RETURN );
915 }
916 
917 static void
internRelease(rtl_uString * pThis)918 internRelease (rtl_uString *pThis)
919 {
920     oslMutex pPoolMutex;
921 
922     rtl_uString *pFree = NULL;
923     if ( SAL_STRING_REFCOUNT(
924              osl_decrementInterlockedCount( &(pThis->refCount) ) ) == 0)
925     {
926         pPoolMutex = getInternMutex();
927         osl_acquireMutex( pPoolMutex );
928 
929         rtl_str_hash_remove (pThis);
930 
931         /* May have been separately acquired */
932         if ( SAL_STRING_REFCOUNT(
933                  osl_incrementInterlockedCount( &(pThis->refCount) ) ) == 1 )
934         {
935             /* we got the last ref */
936             pFree = pThis;
937         }
938         else /* very unusual */
939         {
940             internRelease (pThis);
941         }
942 
943         osl_releaseMutex( pPoolMutex );
944     }
945     if (pFree)
946         rtl_freeMemory (pFree);
947 }
948 
rtl_uString_iterateCodePoints(rtl_uString const * string,sal_Int32 * indexUtf16,sal_Int32 incrementCodePoints)949 sal_uInt32 SAL_CALL rtl_uString_iterateCodePoints(
950     rtl_uString const * string, sal_Int32 * indexUtf16,
951     sal_Int32 incrementCodePoints)
952 {
953     sal_Int32 n;
954     sal_Unicode cu;
955     sal_uInt32 cp;
956     OSL_ASSERT(string != NULL && indexUtf16 != NULL);
957     n = *indexUtf16;
958     OSL_ASSERT(n >= 0 && n <= string->length);
959     while (incrementCodePoints < 0) {
960         OSL_ASSERT(n > 0);
961         cu = string->buffer[--n];
962         if (SAL_RTL_IS_LOW_SURROGATE(cu) && n != 0 &&
963             SAL_RTL_IS_HIGH_SURROGATE(string->buffer[n - 1]))
964         {
965             --n;
966         }
967         ++incrementCodePoints;
968     }
969     OSL_ASSERT(n >= 0 && n < string->length);
970     cu = string->buffer[n];
971     if (SAL_RTL_IS_HIGH_SURROGATE(cu) && string->length - n >= 2 &&
972         SAL_RTL_IS_LOW_SURROGATE(string->buffer[n + 1]))
973     {
974         cp = SAL_RTL_COMBINE_SURROGATES(cu, string->buffer[n + 1]);
975     } else {
976         cp = cu;
977     }
978     while (incrementCodePoints > 0) {
979         OSL_ASSERT(n < string->length);
980         cu = string->buffer[n++];
981         if (SAL_RTL_IS_HIGH_SURROGATE(cu) && n != string->length &&
982             SAL_RTL_IS_LOW_SURROGATE(string->buffer[n]))
983         {
984             ++n;
985         }
986         --incrementCodePoints;
987     }
988     OSL_ASSERT(n >= 0 && n <= string->length);
989     *indexUtf16 = n;
990     return cp;
991 }
992 
rtl_convertStringToUString(rtl_uString ** target,char const * source,sal_Int32 length,rtl_TextEncoding encoding,sal_uInt32 flags)993 sal_Bool rtl_convertStringToUString(
994     rtl_uString ** target, char const * source, sal_Int32 length,
995     rtl_TextEncoding encoding, sal_uInt32 flags) SAL_THROW_EXTERN_C()
996 {
997     sal_uInt32 info;
998     rtl_string2UString_status(target, source, length, encoding, flags, &info);
999     return (sal_Bool) ((info & RTL_TEXTTOUNICODE_INFO_ERROR) == 0);
1000 }
1001