Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <string.h>
21 :
22 : #include "boost/static_assert.hpp"
23 :
24 : #include <osl/interlck.h>
25 : #include <rtl/alloc.h>
26 : #include <rtl/tencinfo.h>
27 : #include <rtl/instance.hxx>
28 : #include <tools/string.hxx>
29 :
30 : #include <impstrg.hxx>
31 :
32 : #include <tools/debug.hxx>
33 :
34 : DBG_NAME( UniString )
35 :
36 : #define STRCODE sal_Unicode
37 : #define STRCODEU sal_Unicode
38 : #define STRING UniString
39 : #define STRINGDATA UniStringData
40 : #define DBGCHECKSTRING DbgCheckUniString
41 : #define STRING_TYPE rtl_uString
42 : #define STRING_ACQUIRE rtl_uString_acquire
43 : #define STRING_RELEASE rtl_uString_release
44 : #define STRING_NEW rtl_uString_new
45 :
46 : #include <strimp.cxx>
47 : #include <strucvt.cxx>
48 : #include <strascii.cxx>
49 :
50 0 : UniString::UniString(char c): mpData(ImplAllocData(1)) { mpData->maStr[0] = c; }
51 :
52 19323 : UniString UniString::CreateFromInt32( sal_Int32 n, sal_Int16 nRadix )
53 : {
54 19323 : return rtl::OUString::valueOf(n, nRadix);
55 : }
56 :
57 : namespace { struct Empty : public rtl::Static< const UniString, Empty> {}; }
58 :
59 126 : const UniString& UniString::EmptyString()
60 : {
61 126 : return Empty::get();
62 : }
63 :
64 3752 : sal_Int32 UniString::ToInt32() const
65 : {
66 : DBG_CHKTHIS( UniString, DbgCheckUniString );
67 :
68 3752 : return rtl_ustr_toInt32( mpData->maStr, 10 );
69 : }
70 :
71 0 : sal_Int64 UniString::ToInt64() const
72 : {
73 : DBG_CHKTHIS( UniString, DbgCheckUniString );
74 :
75 0 : return rtl_ustr_toInt64( mpData->maStr, 10 );
76 : }
77 :
78 221 : xub_StrLen STRING::SearchChar( const STRCODE* pChars, xub_StrLen nIndex ) const
79 : {
80 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
81 :
82 221 : sal_Int32 nLen = mpData->mnLen;
83 221 : const STRCODE* pStr = mpData->maStr;
84 221 : pStr += nIndex;
85 2710 : while ( nIndex < nLen )
86 : {
87 2286 : STRCODE c = *pStr;
88 2286 : const STRCODE* pCompStr = pChars;
89 11327 : while ( *pCompStr )
90 : {
91 6773 : if ( *pCompStr == c )
92 18 : return nIndex;
93 6755 : ++pCompStr;
94 : }
95 : ++pStr,
96 2268 : ++nIndex;
97 : }
98 :
99 203 : return STRING_NOTFOUND;
100 : }
101 :
102 0 : xub_StrLen STRING::SearchAndReplace( STRCODE c, STRCODE cRep, xub_StrLen nIndex )
103 : {
104 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
105 :
106 0 : sal_Int32 nLen = mpData->mnLen;
107 0 : const STRCODE* pStr = mpData->maStr;
108 0 : pStr += nIndex;
109 0 : while ( nIndex < nLen )
110 : {
111 0 : if ( *pStr == c )
112 : {
113 0 : ImplCopyData();
114 0 : mpData->maStr[nIndex] = cRep;
115 0 : return nIndex;
116 : }
117 : ++pStr,
118 0 : ++nIndex;
119 : }
120 :
121 0 : return STRING_NOTFOUND;
122 : }
123 :
124 261 : STRING& STRING::Insert( const STRING& rStr, xub_StrLen nPos, xub_StrLen nLen,
125 : xub_StrLen nIndex )
126 : {
127 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
128 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
129 :
130 : // Determine string length
131 261 : if ( nPos > rStr.mpData->mnLen )
132 0 : nLen = 0;
133 : else
134 : {
135 : // Correct length if necessary
136 261 : sal_Int32 nMaxLen = rStr.mpData->mnLen-nPos;
137 261 : if ( nLen > nMaxLen )
138 0 : nLen = static_cast< xub_StrLen >(nMaxLen);
139 : }
140 :
141 : // Detect overflow
142 261 : sal_Int32 nCopyLen = ImplGetCopyLen( mpData->mnLen, nLen );
143 :
144 261 : if ( !nCopyLen )
145 0 : return *this;
146 :
147 : // Correct index if necessary
148 261 : if ( nIndex > mpData->mnLen )
149 0 : nIndex = static_cast< xub_StrLen >(mpData->mnLen);
150 :
151 : // Determine new length and allocate string
152 261 : STRINGDATA* pNewData = ImplAllocData( mpData->mnLen+nCopyLen );
153 :
154 : // copy string to newdata
155 261 : memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
156 261 : memcpy( pNewData->maStr+nIndex, rStr.mpData->maStr+nPos, nCopyLen*sizeof( STRCODE ) );
157 261 : memcpy( pNewData->maStr+nIndex+nCopyLen, mpData->maStr+nIndex,
158 522 : (mpData->mnLen-nIndex)*sizeof( STRCODE ) );
159 :
160 : // release old data
161 261 : STRING_RELEASE((STRING_TYPE *)mpData);
162 261 : mpData = pNewData;
163 :
164 261 : return *this;
165 : }
166 :
167 143181 : static sal_Int32 ImplStringICompareWithoutZero( const STRCODE* pStr1, const STRCODE* pStr2,
168 : sal_Int32 nCount )
169 : {
170 143181 : sal_Int32 nRet = 0;
171 : STRCODE c1;
172 : STRCODE c2;
173 276368 : do
174 : {
175 280339 : if ( !nCount )
176 3971 : break;
177 :
178 : // convert if char is between 'A' and 'Z'
179 276368 : c1 = *pStr1;
180 276368 : c2 = *pStr2;
181 276368 : if ( (c1 >= 65) && (c1 <= 90) )
182 58708 : c1 += 32;
183 276368 : if ( (c2 >= 65) && (c2 <= 90) )
184 137941 : c2 += 32;
185 276368 : nRet = ((sal_Int32)((STRCODEU)c1))-((sal_Int32)((STRCODEU)c2));
186 :
187 : ++pStr1,
188 : ++pStr2,
189 276368 : --nCount;
190 : }
191 : while ( nRet == 0 );
192 :
193 143181 : return nRet;
194 : }
195 :
196 32 : sal_Bool STRING::EqualsIgnoreCaseAscii( const STRING& rStr, xub_StrLen nIndex, xub_StrLen nLen ) const
197 : {
198 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
199 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
200 :
201 : // Are there enough codes for comparing?
202 32 : if ( nIndex > mpData->mnLen )
203 0 : return (rStr.mpData->mnLen == 0);
204 32 : sal_Int32 nMaxLen = mpData->mnLen-nIndex;
205 32 : if ( nMaxLen < nLen )
206 : {
207 0 : if ( rStr.mpData->mnLen != nMaxLen )
208 0 : return sal_False;
209 0 : nLen = static_cast< xub_StrLen >(nMaxLen);
210 : }
211 :
212 32 : return (ImplStringICompareWithoutZero( mpData->maStr+nIndex, rStr.mpData->maStr, nLen ) == 0);
213 : }
214 :
215 92227 : StringCompare STRING::CompareIgnoreCaseToAscii( const STRING& rStr,
216 : xub_StrLen nLen ) const
217 : {
218 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
219 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
220 :
221 92227 : if ( mpData == rStr.mpData )
222 1152 : return COMPARE_EQUAL;
223 :
224 : // determine maximal length
225 91075 : if ( mpData->mnLen < nLen )
226 91075 : nLen = static_cast< xub_StrLen >(mpData->mnLen+1);
227 91075 : if ( rStr.mpData->mnLen < nLen )
228 54894 : nLen = static_cast< xub_StrLen >(rStr.mpData->mnLen+1);
229 :
230 91075 : sal_Int32 nCompare = ImplStringICompareWithoutZero( mpData->maStr, rStr.mpData->maStr, nLen );
231 :
232 91075 : if ( nCompare == 0 )
233 1528 : return COMPARE_EQUAL;
234 89547 : else if ( nCompare < 0 )
235 40367 : return COMPARE_LESS;
236 : else
237 49180 : return COMPARE_GREATER;
238 : }
239 :
240 339 : STRCODE* STRING::GetBufferAccess()
241 : {
242 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
243 :
244 : // Copy data if necessary
245 339 : if ( mpData->mnLen )
246 339 : ImplCopyData();
247 :
248 : // return pointer to string data
249 339 : return mpData->maStr;
250 : }
251 :
252 163 : void STRING::ReleaseBufferAccess( xub_StrLen nLen )
253 : {
254 : // String not consinstent, thus no functionality test
255 : DBG_CHKTHIS( STRING, NULL );
256 : DBG_ASSERT( mpData->mnRefCount == 1, "String::ReleaseCharStr() called for String with RefCount" );
257 :
258 163 : if ( nLen > mpData->mnLen )
259 163 : nLen = ImplStringLen( mpData->maStr );
260 : OSL_ASSERT(nLen <= mpData->mnLen);
261 163 : if ( !nLen )
262 : {
263 0 : STRING_NEW((STRING_TYPE **)&mpData);
264 : }
265 : // shorten buffer is difference > 8 chars
266 163 : else if ( mpData->mnLen - nLen > 8 )
267 : {
268 0 : STRINGDATA* pNewData = ImplAllocData( nLen );
269 0 : memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
270 0 : STRING_RELEASE((STRING_TYPE *)mpData);
271 0 : mpData = pNewData;
272 : }
273 : else
274 163 : mpData->mnLen = nLen;
275 163 : }
276 :
277 0 : STRCODE* STRING::AllocBuffer( xub_StrLen nLen )
278 : {
279 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
280 :
281 0 : STRING_RELEASE((STRING_TYPE *)mpData);
282 0 : if ( nLen )
283 0 : mpData = ImplAllocData( nLen );
284 : else
285 : {
286 0 : mpData = NULL;
287 0 : STRING_NEW((STRING_TYPE **)&mpData);
288 : }
289 :
290 0 : return mpData->maStr;
291 : }
292 :
293 1113 : STRING& STRING::Insert( STRCODE c, xub_StrLen nIndex )
294 : {
295 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
296 :
297 : // Don't insert 0 char or string size is maximum
298 1113 : if ( !c || (mpData->mnLen == STRING_MAXLEN) )
299 0 : return *this;
300 :
301 : // Adjust string index
302 1113 : if ( nIndex > mpData->mnLen )
303 71 : nIndex = static_cast< xub_StrLen >(mpData->mnLen);
304 :
305 : // allocate string of new size
306 1113 : STRINGDATA* pNewData = ImplAllocData( mpData->mnLen+1 );
307 :
308 : // copy string
309 1113 : memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
310 1113 : pNewData->maStr[nIndex] = c;
311 1113 : memcpy( pNewData->maStr+nIndex+1, mpData->maStr+nIndex,
312 2226 : (mpData->mnLen-nIndex)*sizeof( STRCODE ) );
313 :
314 : // free old data
315 1113 : STRING_RELEASE((STRING_TYPE *)mpData);
316 1113 : mpData = pNewData;
317 :
318 1113 : return *this;
319 : }
320 :
321 22 : STRING& STRING::ToUpperAscii()
322 : {
323 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
324 :
325 22 : sal_Int32 nIndex = 0;
326 22 : sal_Int32 nLen = mpData->mnLen;
327 22 : STRCODE* pStr = mpData->maStr;
328 102 : while ( nIndex < nLen )
329 : {
330 : // convert char if between 'a' and 'z'
331 58 : if ( (*pStr >= 97) && (*pStr <= 122) )
332 : {
333 : // allocate string of new size
334 58 : pStr = ImplCopyStringData( pStr );
335 58 : *pStr -= 32;
336 : }
337 :
338 : ++pStr,
339 58 : ++nIndex;
340 : }
341 :
342 22 : return *this;
343 : }
344 :
345 173936 : StringCompare STRING::CompareTo( const STRING& rStr, xub_StrLen nLen ) const
346 : {
347 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
348 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
349 :
350 173936 : if ( mpData == rStr.mpData )
351 2940 : return COMPARE_EQUAL;
352 :
353 : // determine maximal length
354 170996 : if ( mpData->mnLen < nLen )
355 158840 : nLen = static_cast< xub_StrLen >(mpData->mnLen+1);
356 170996 : if ( rStr.mpData->mnLen < nLen )
357 89081 : nLen = static_cast< xub_StrLen >(rStr.mpData->mnLen+1);
358 :
359 170996 : sal_Int32 nCompare = ImplStringCompareWithoutZero( mpData->maStr, rStr.mpData->maStr, nLen );
360 :
361 170996 : if ( nCompare == 0 )
362 21714 : return COMPARE_EQUAL;
363 149282 : else if ( nCompare < 0 )
364 103191 : return COMPARE_LESS;
365 : else
366 46091 : return COMPARE_GREATER;
367 : }
368 :
369 3406779 : sal_Bool STRING::Equals( const STRING& rStr ) const
370 : {
371 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
372 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
373 :
374 3406779 : if ( mpData == rStr.mpData )
375 814179 : return sal_True;
376 :
377 2592600 : if ( mpData->mnLen != rStr.mpData->mnLen )
378 2203247 : return sal_False;
379 :
380 389353 : return (ImplStringCompareWithoutZero( mpData->maStr, rStr.mpData->maStr, mpData->mnLen ) == 0);
381 : }
382 :
383 54907 : sal_Bool STRING::EqualsIgnoreCaseAscii( const STRING& rStr ) const
384 : {
385 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
386 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
387 :
388 54907 : if ( mpData == rStr.mpData )
389 0 : return sal_True;
390 :
391 54907 : if ( mpData->mnLen != rStr.mpData->mnLen )
392 2833 : return sal_False;
393 :
394 : // compare string while ignoring case
395 52074 : return (ImplStringICompareWithoutZero( mpData->maStr, rStr.mpData->maStr, mpData->mnLen ) == 0);
396 : }
397 :
398 2173 : sal_Bool STRING::Equals( const STRING& rStr, xub_StrLen nIndex, xub_StrLen nLen ) const
399 : {
400 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
401 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
402 :
403 : // Are there enough codes for comparing?
404 2173 : if ( nIndex > mpData->mnLen )
405 0 : return (rStr.mpData->mnLen == 0);
406 2173 : sal_Int32 nMaxLen = mpData->mnLen-nIndex;
407 2173 : if ( nMaxLen < nLen )
408 : {
409 0 : if ( rStr.mpData->mnLen != nMaxLen )
410 0 : return sal_False;
411 0 : nLen = static_cast< xub_StrLen >(nMaxLen);
412 : }
413 :
414 2173 : return (ImplStringCompareWithoutZero( mpData->maStr+nIndex, rStr.mpData->maStr, nLen ) == 0);
415 : }
416 :
417 0 : sal_Bool STRING::Equals( const STRCODE* pCharStr, xub_StrLen nIndex, xub_StrLen nLen ) const
418 : {
419 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
420 :
421 : // Are there enough codes for comparing?
422 0 : if ( nIndex > mpData->mnLen )
423 0 : return (*pCharStr == 0);
424 :
425 0 : return (ImplStringCompare( mpData->maStr+nIndex, pCharStr, nLen ) == 0);
426 : }
427 :
428 13895 : xub_StrLen STRING::Match( const STRING& rStr ) const
429 : {
430 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
431 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
432 :
433 : // return if string is empty
434 13895 : if ( !mpData->mnLen )
435 24 : return STRING_MATCH;
436 :
437 : // Search the string for unmatching chars
438 13871 : const STRCODE* pStr1 = mpData->maStr;
439 13871 : const STRCODE* pStr2 = rStr.mpData->maStr;
440 13871 : xub_StrLen i = 0;
441 29561 : while ( i < mpData->mnLen )
442 : {
443 : // Abort on the first unmatching char
444 15690 : if ( *pStr1 != *pStr2 )
445 13871 : return i;
446 : ++pStr1,
447 : ++pStr2,
448 1819 : ++i;
449 : }
450 :
451 0 : return STRING_MATCH;
452 : }
453 :
454 21 : xub_StrLen STRING::SearchBackward( STRCODE c, xub_StrLen nIndex ) const
455 : {
456 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
457 :
458 21 : if ( nIndex > mpData->mnLen )
459 21 : nIndex = (xub_StrLen)mpData->mnLen;
460 :
461 21 : const STRCODE* pStr = mpData->maStr;
462 21 : pStr += nIndex;
463 :
464 245 : while ( nIndex )
465 : {
466 224 : nIndex--;
467 224 : pStr--;
468 224 : if ( *pStr == c )
469 21 : return nIndex;
470 : }
471 :
472 0 : return STRING_NOTFOUND;
473 : }
474 :
475 1958 : void STRING::SearchAndReplaceAll( const STRING& rStr, const STRING& rRepStr )
476 : {
477 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
478 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
479 : DBG_CHKOBJ( &rRepStr, STRING, DBGCHECKSTRING );
480 :
481 1958 : xub_StrLen nSPos = Search( rStr, 0 );
482 3916 : while ( nSPos != STRING_NOTFOUND )
483 : {
484 0 : Replace( nSPos, rStr.Len(), rRepStr );
485 0 : nSPos = nSPos + rRepStr.Len();
486 0 : nSPos = Search( rStr, nSPos );
487 : }
488 1958 : }
489 :
490 0 : void STRING::SetToken( xub_StrLen nToken, STRCODE cTok, const STRING& rStr,
491 : xub_StrLen nIndex )
492 : {
493 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
494 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
495 :
496 0 : const STRCODE* pStr = mpData->maStr;
497 0 : xub_StrLen nLen = (xub_StrLen)mpData->mnLen;
498 0 : xub_StrLen nTok = 0;
499 0 : xub_StrLen nFirstChar = nIndex;
500 0 : xub_StrLen i = nFirstChar;
501 :
502 : // Determine token position and length
503 0 : pStr += i;
504 0 : while ( i < nLen )
505 : {
506 : // Increase token count if match
507 0 : if ( *pStr == cTok )
508 : {
509 0 : ++nTok;
510 :
511 0 : if ( nTok == nToken )
512 0 : nFirstChar = i+1;
513 : else
514 : {
515 0 : if ( nTok > nToken )
516 0 : break;
517 : }
518 : }
519 :
520 : ++pStr,
521 0 : ++i;
522 : }
523 :
524 0 : if ( nTok >= nToken )
525 0 : Replace( nFirstChar, i-nFirstChar, rStr );
526 0 : }
527 :
528 3708 : STRING STRING::GetToken( xub_StrLen nToken, STRCODE cTok, xub_StrLen& rIndex ) const
529 : {
530 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
531 :
532 3708 : const STRCODE* pStr = mpData->maStr;
533 3708 : xub_StrLen nLen = (xub_StrLen)mpData->mnLen;
534 3708 : xub_StrLen nTok = 0;
535 3708 : xub_StrLen nFirstChar = rIndex;
536 3708 : xub_StrLen i = nFirstChar;
537 :
538 : // Determine token position and length
539 3708 : pStr += i;
540 52046 : while ( i < nLen )
541 : {
542 : // Increase token count if match
543 45842 : if ( *pStr == cTok )
544 : {
545 3770 : ++nTok;
546 :
547 3770 : if ( nTok == nToken )
548 1422 : nFirstChar = i+1;
549 : else
550 : {
551 2348 : if ( nTok > nToken )
552 1212 : break;
553 : }
554 : }
555 :
556 : ++pStr,
557 44630 : ++i;
558 : }
559 :
560 3708 : if ( nTok >= nToken )
561 : {
562 2954 : if ( i < nLen )
563 1212 : rIndex = i+1;
564 : else
565 1742 : rIndex = STRING_NOTFOUND;
566 2954 : return Copy( nFirstChar, i-nFirstChar );
567 : }
568 : else
569 : {
570 754 : rIndex = STRING_NOTFOUND;
571 754 : return STRING();
572 : }
573 : }
574 :
575 2489 : STRING& STRING::Append( const STRCODE* pCharStr, xub_StrLen nCharLen )
576 : {
577 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
578 : DBG_ASSERT( pCharStr, "String::Append() - pCharStr is NULL" );
579 :
580 2489 : if ( nCharLen == STRING_LEN )
581 0 : nCharLen = ImplStringLen( pCharStr );
582 :
583 : #ifdef DBG_UTIL
584 : if ( DbgIsAssert() )
585 : {
586 : for ( xub_StrLen i = 0; i < nCharLen; i++ )
587 : {
588 : if ( !pCharStr[i] )
589 : {
590 : OSL_FAIL( "String::Append() : nLen is wrong" );
591 : }
592 : }
593 : }
594 : #endif
595 :
596 : // Catch overflow
597 2489 : sal_Int32 nLen = mpData->mnLen;
598 2489 : sal_Int32 nCopyLen = ImplGetCopyLen( nLen, nCharLen );
599 :
600 2489 : if ( nCopyLen )
601 : {
602 : // allocate string of new size
603 2331 : STRINGDATA* pNewData = ImplAllocData( nLen+nCopyLen );
604 :
605 : // copy string
606 2331 : memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
607 2331 : memcpy( pNewData->maStr+nLen, pCharStr, nCopyLen*sizeof( STRCODE ) );
608 :
609 : // free old string
610 2331 : STRING_RELEASE((STRING_TYPE *)mpData);
611 2331 : mpData = pNewData;
612 : }
613 :
614 2489 : return *this;
615 : }
616 :
617 23732 : STRING& STRING::Append( STRCODE c )
618 : {
619 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
620 :
621 : // don't append null characters and keep string length < maxlen
622 23732 : sal_Int32 nLen = mpData->mnLen;
623 23732 : if ( c && (nLen < STRING_MAXLEN) )
624 : {
625 : // allocate string of new size
626 23732 : STRINGDATA* pNewData = ImplAllocData( nLen+1 );
627 :
628 : // copy string
629 23732 : memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
630 23732 : pNewData->maStr[nLen] = c;
631 :
632 : // free old string
633 23732 : STRING_RELEASE((STRING_TYPE *)mpData);
634 23732 : mpData = pNewData;
635 : }
636 :
637 23732 : return *this;
638 : }
639 :
640 74 : STRING& STRING::Assign( STRCODE c )
641 : {
642 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
643 : DBG_ASSERT( c, "String::Assign() - c is 0" );
644 :
645 : // initialize maintenance data
646 74 : STRING_RELEASE((STRING_TYPE *)mpData);
647 74 : mpData = ImplAllocData( 1 );
648 74 : mpData->maStr[0] = c;
649 74 : return *this;
650 : }
651 :
652 1069 : xub_StrLen STRING::SearchAndReplace( const STRING& rStr, const STRING& rRepStr,
653 : xub_StrLen nIndex )
654 : {
655 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
656 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
657 : DBG_CHKOBJ( &rRepStr, STRING, DBGCHECKSTRING );
658 :
659 1069 : xub_StrLen nSPos = Search( rStr, nIndex );
660 1069 : if ( nSPos != STRING_NOTFOUND )
661 1058 : Replace( nSPos, rStr.Len(), rRepStr );
662 :
663 1069 : return nSPos;
664 : }
665 :
666 0 : static sal_Int32 ImplStringICompare( const STRCODE* pStr1, const STRCODE* pStr2 )
667 : {
668 : sal_Int32 nRet;
669 : STRCODE c1;
670 : STRCODE c2;
671 0 : do
672 : {
673 : // Convert char if between 'A' and 'Z'
674 0 : c1 = *pStr1;
675 0 : c2 = *pStr2;
676 0 : if ( (c1 >= 65) && (c1 <= 90) )
677 0 : c1 += 32;
678 0 : if ( (c2 >= 65) && (c2 <= 90) )
679 0 : c2 += 32;
680 0 : nRet = ((sal_Int32)((STRCODEU)c1))-((sal_Int32)((STRCODEU)c2));
681 0 : if ( nRet != 0 )
682 0 : break;
683 :
684 : ++pStr1,
685 0 : ++pStr2;
686 : }
687 : while ( c2 );
688 :
689 0 : return nRet;
690 : }
691 :
692 0 : sal_Bool STRING::EqualsIgnoreCaseAscii( const STRCODE* pCharStr ) const
693 : {
694 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
695 :
696 0 : return (ImplStringICompare( mpData->maStr, pCharStr ) == 0);
697 : }
698 :
699 8159 : STRING& STRING::Assign( const STRCODE* pCharStr )
700 : {
701 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
702 : DBG_ASSERT( pCharStr, "String::Assign() - pCharStr is NULL" );
703 :
704 8159 : xub_StrLen nLen = ImplStringLen( pCharStr );
705 :
706 8159 : if ( !nLen )
707 : {
708 3114 : STRING_NEW((STRING_TYPE **)&mpData);
709 : }
710 : else
711 : {
712 : // copy without allocation if string length is identical
713 5045 : if ( (nLen == mpData->mnLen) && (mpData->mnRefCount == 1) )
714 0 : memcpy( mpData->maStr, pCharStr, nLen*sizeof( STRCODE ) );
715 : else
716 : {
717 : // free old string
718 5045 : STRING_RELEASE((STRING_TYPE *)mpData);
719 :
720 : // allocate string of new size and copy
721 5045 : mpData = ImplAllocData( nLen );
722 5045 : memcpy( mpData->maStr, pCharStr, nLen*sizeof( STRCODE ) );
723 : }
724 : }
725 :
726 8159 : return *this;
727 : }
728 :
729 984825 : xub_StrLen ImplStringLen( const sal_Char* pStr )
730 : {
731 984825 : const sal_Char* pTempStr = pStr;
732 8618473 : while( *pTempStr )
733 6648823 : ++pTempStr;
734 984825 : return (xub_StrLen)(pTempStr-pStr);
735 : }
736 :
737 14071 : xub_StrLen ImplStringLen( const sal_Unicode* pStr )
738 : {
739 14071 : const sal_Unicode* pTempStr = pStr;
740 149664 : while( *pTempStr )
741 121522 : ++pTempStr;
742 14071 : return (xub_StrLen)(pTempStr-pStr);
743 : }
744 :
745 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|