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