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