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 42291 : UniString UniString::CreateFromInt32( sal_Int32 n, sal_Int16 nRadix )
53 : {
54 42291 : return rtl::OUString::valueOf(n, nRadix);
55 : }
56 :
57 : namespace { struct Empty : public rtl::Static< const UniString, Empty> {}; }
58 :
59 376 : const UniString& UniString::EmptyString()
60 : {
61 376 : return Empty::get();
62 : }
63 :
64 6686 : sal_Int32 UniString::ToInt32() const
65 : {
66 : DBG_CHKTHIS( UniString, DbgCheckUniString );
67 :
68 6686 : 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 469 : xub_StrLen STRING::SearchChar( const STRCODE* pChars, xub_StrLen nIndex ) const
79 : {
80 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
81 :
82 469 : sal_Int32 nLen = mpData->mnLen;
83 469 : const STRCODE* pStr = mpData->maStr;
84 469 : pStr += nIndex;
85 5662 : while ( nIndex < nLen )
86 : {
87 4762 : STRCODE c = *pStr;
88 4762 : const STRCODE* pCompStr = pChars;
89 23598 : while ( *pCompStr )
90 : {
91 14112 : if ( *pCompStr == c )
92 38 : return nIndex;
93 14074 : ++pCompStr;
94 : }
95 : ++pStr,
96 4724 : ++nIndex;
97 : }
98 :
99 431 : 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 522 : 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 522 : if ( nPos > rStr.mpData->mnLen )
132 0 : nLen = 0;
133 : else
134 : {
135 : // Correct length if necessary
136 522 : sal_Int32 nMaxLen = rStr.mpData->mnLen-nPos;
137 522 : if ( nLen > nMaxLen )
138 0 : nLen = static_cast< xub_StrLen >(nMaxLen);
139 : }
140 :
141 : // Detect overflow
142 522 : sal_Int32 nCopyLen = ImplGetCopyLen( mpData->mnLen, nLen );
143 :
144 522 : if ( !nCopyLen )
145 0 : return *this;
146 :
147 : // Correct index if necessary
148 522 : if ( nIndex > mpData->mnLen )
149 0 : nIndex = static_cast< xub_StrLen >(mpData->mnLen);
150 :
151 : // Determine new length and allocate string
152 522 : STRINGDATA* pNewData = ImplAllocData( mpData->mnLen+nCopyLen );
153 :
154 : // copy string to newdata
155 522 : memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
156 522 : memcpy( pNewData->maStr+nIndex, rStr.mpData->maStr+nPos, nCopyLen*sizeof( STRCODE ) );
157 522 : memcpy( pNewData->maStr+nIndex+nCopyLen, mpData->maStr+nIndex,
158 1044 : (mpData->mnLen-nIndex)*sizeof( STRCODE ) );
159 :
160 : // release old data
161 522 : STRING_RELEASE((STRING_TYPE *)mpData);
162 522 : mpData = pNewData;
163 :
164 522 : return *this;
165 : }
166 :
167 326235 : static sal_Int32 ImplStringICompareWithoutZero( const STRCODE* pStr1, const STRCODE* pStr2,
168 : sal_Int32 nCount )
169 : {
170 326235 : sal_Int32 nRet = 0;
171 : STRCODE c1;
172 : STRCODE c2;
173 617916 : do
174 : {
175 625930 : if ( !nCount )
176 8014 : break;
177 :
178 : // convert if char is between 'A' and 'Z'
179 617916 : c1 = *pStr1;
180 617916 : c2 = *pStr2;
181 617916 : if ( (c1 >= 65) && (c1 <= 90) )
182 138362 : c1 += 32;
183 617916 : if ( (c2 >= 65) && (c2 <= 90) )
184 305306 : c2 += 32;
185 617916 : nRet = ((sal_Int32)((STRCODEU)c1))-((sal_Int32)((STRCODEU)c2));
186 :
187 : ++pStr1,
188 : ++pStr2,
189 617916 : --nCount;
190 : }
191 : while ( nRet == 0 );
192 :
193 326235 : return nRet;
194 : }
195 :
196 64 : 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 64 : if ( nIndex > mpData->mnLen )
203 0 : return (rStr.mpData->mnLen == 0);
204 64 : sal_Int32 nMaxLen = mpData->mnLen-nIndex;
205 64 : 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 64 : return (ImplStringICompareWithoutZero( mpData->maStr+nIndex, rStr.mpData->maStr, nLen ) == 0);
213 : }
214 :
215 224000 : 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 224000 : if ( mpData == rStr.mpData )
222 2489 : return COMPARE_EQUAL;
223 :
224 : // determine maximal length
225 221511 : if ( mpData->mnLen < nLen )
226 221511 : nLen = static_cast< xub_StrLen >(mpData->mnLen+1);
227 221511 : if ( rStr.mpData->mnLen < nLen )
228 131636 : nLen = static_cast< xub_StrLen >(rStr.mpData->mnLen+1);
229 :
230 221511 : sal_Int32 nCompare = ImplStringICompareWithoutZero( mpData->maStr, rStr.mpData->maStr, nLen );
231 :
232 221511 : if ( nCompare == 0 )
233 3068 : return COMPARE_EQUAL;
234 218443 : else if ( nCompare < 0 )
235 98931 : return COMPARE_LESS;
236 : else
237 119512 : return COMPARE_GREATER;
238 : }
239 :
240 0 : STRING& STRING::Fill( xub_StrLen nCount, STRCODE cFillChar )
241 : {
242 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
243 :
244 0 : if ( !nCount )
245 0 : return *this;
246 :
247 : // extend string if fill length is larger
248 0 : if ( nCount > mpData->mnLen )
249 : {
250 : // allocate string of new length
251 0 : STRINGDATA* pNewData = ImplAllocData( nCount );
252 0 : STRING_RELEASE((STRING_TYPE *)mpData);
253 0 : mpData = pNewData;
254 : }
255 : else
256 0 : ImplCopyData();
257 :
258 0 : STRCODE* pStr = mpData->maStr;
259 0 : do
260 : {
261 0 : *pStr = cFillChar;
262 : ++pStr,
263 0 : --nCount;
264 : }
265 : while ( nCount );
266 :
267 0 : return *this;
268 : }
269 :
270 910 : STRCODE* STRING::GetBufferAccess()
271 : {
272 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
273 :
274 : // Copy data if necessary
275 910 : if ( mpData->mnLen )
276 910 : ImplCopyData();
277 :
278 : // return pointer to string data
279 910 : return mpData->maStr;
280 : }
281 :
282 430 : void STRING::ReleaseBufferAccess( xub_StrLen nLen )
283 : {
284 : // String not consinstent, thus no functionality test
285 : DBG_CHKTHIS( STRING, NULL );
286 : DBG_ASSERT( mpData->mnRefCount == 1, "String::ReleaseCharStr() called for String with RefCount" );
287 :
288 430 : if ( nLen > mpData->mnLen )
289 430 : nLen = ImplStringLen( mpData->maStr );
290 : OSL_ASSERT(nLen <= mpData->mnLen);
291 430 : if ( !nLen )
292 : {
293 0 : STRING_NEW((STRING_TYPE **)&mpData);
294 : }
295 : // shorten buffer is difference > 8 chars
296 430 : else if ( mpData->mnLen - nLen > 8 )
297 : {
298 0 : STRINGDATA* pNewData = ImplAllocData( nLen );
299 0 : memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
300 0 : STRING_RELEASE((STRING_TYPE *)mpData);
301 0 : mpData = pNewData;
302 : }
303 : else
304 430 : mpData->mnLen = nLen;
305 430 : }
306 :
307 0 : STRCODE* STRING::AllocBuffer( xub_StrLen nLen )
308 : {
309 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
310 :
311 0 : STRING_RELEASE((STRING_TYPE *)mpData);
312 0 : if ( nLen )
313 0 : mpData = ImplAllocData( nLen );
314 : else
315 : {
316 0 : mpData = NULL;
317 0 : STRING_NEW((STRING_TYPE **)&mpData);
318 : }
319 :
320 0 : return mpData->maStr;
321 : }
322 :
323 2475 : STRING& STRING::Insert( STRCODE c, xub_StrLen nIndex )
324 : {
325 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
326 :
327 : // Don't insert 0 char or string size is maximum
328 2475 : if ( !c || (mpData->mnLen == STRING_MAXLEN) )
329 0 : return *this;
330 :
331 : // Adjust string index
332 2475 : if ( nIndex > mpData->mnLen )
333 231 : nIndex = static_cast< xub_StrLen >(mpData->mnLen);
334 :
335 : // allocate string of new size
336 2475 : STRINGDATA* pNewData = ImplAllocData( mpData->mnLen+1 );
337 :
338 : // copy string
339 2475 : memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
340 2475 : pNewData->maStr[nIndex] = c;
341 2475 : memcpy( pNewData->maStr+nIndex+1, mpData->maStr+nIndex,
342 4950 : (mpData->mnLen-nIndex)*sizeof( STRCODE ) );
343 :
344 : // free old data
345 2475 : STRING_RELEASE((STRING_TYPE *)mpData);
346 2475 : mpData = pNewData;
347 :
348 2475 : return *this;
349 : }
350 :
351 2838 : STRING& STRING::ToUpperAscii()
352 : {
353 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
354 :
355 2838 : sal_Int32 nIndex = 0;
356 2838 : sal_Int32 nLen = mpData->mnLen;
357 2838 : STRCODE* pStr = mpData->maStr;
358 10834 : while ( nIndex < nLen )
359 : {
360 : // convert char if between 'a' and 'z'
361 5158 : if ( (*pStr >= 97) && (*pStr <= 122) )
362 : {
363 : // allocate string of new size
364 504 : pStr = ImplCopyStringData( pStr );
365 504 : *pStr -= 32;
366 : }
367 :
368 : ++pStr,
369 5158 : ++nIndex;
370 : }
371 :
372 2838 : return *this;
373 : }
374 :
375 375856 : StringCompare STRING::CompareTo( const STRING& rStr, xub_StrLen nLen ) const
376 : {
377 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
378 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
379 :
380 375856 : if ( mpData == rStr.mpData )
381 6412 : return COMPARE_EQUAL;
382 :
383 : // determine maximal length
384 369444 : if ( mpData->mnLen < nLen )
385 344512 : nLen = static_cast< xub_StrLen >(mpData->mnLen+1);
386 369444 : if ( rStr.mpData->mnLen < nLen )
387 192430 : nLen = static_cast< xub_StrLen >(rStr.mpData->mnLen+1);
388 :
389 369444 : sal_Int32 nCompare = ImplStringCompareWithoutZero( mpData->maStr, rStr.mpData->maStr, nLen );
390 :
391 369444 : if ( nCompare == 0 )
392 45414 : return COMPARE_EQUAL;
393 324030 : else if ( nCompare < 0 )
394 225880 : return COMPARE_LESS;
395 : else
396 98150 : return COMPARE_GREATER;
397 : }
398 :
399 7455427 : sal_Bool STRING::Equals( const STRING& rStr ) const
400 : {
401 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
402 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
403 :
404 7455427 : if ( mpData == rStr.mpData )
405 1709223 : return sal_True;
406 :
407 5746204 : if ( mpData->mnLen != rStr.mpData->mnLen )
408 5038510 : return sal_False;
409 :
410 707694 : return (ImplStringCompareWithoutZero( mpData->maStr, rStr.mpData->maStr, mpData->mnLen ) == 0);
411 : }
412 :
413 111710 : sal_Bool STRING::EqualsIgnoreCaseAscii( const STRING& rStr ) const
414 : {
415 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
416 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
417 :
418 111710 : if ( mpData == rStr.mpData )
419 0 : return sal_True;
420 :
421 111710 : if ( mpData->mnLen != rStr.mpData->mnLen )
422 7050 : return sal_False;
423 :
424 : // compare string while ignoring case
425 104660 : return (ImplStringICompareWithoutZero( mpData->maStr, rStr.mpData->maStr, mpData->mnLen ) == 0);
426 : }
427 :
428 11916 : sal_Bool STRING::Equals( const STRING& rStr, xub_StrLen nIndex, xub_StrLen nLen ) const
429 : {
430 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
431 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
432 :
433 : // Are there enough codes for comparing?
434 11916 : if ( nIndex > mpData->mnLen )
435 0 : return (rStr.mpData->mnLen == 0);
436 11916 : sal_Int32 nMaxLen = mpData->mnLen-nIndex;
437 11916 : if ( nMaxLen < nLen )
438 : {
439 0 : if ( rStr.mpData->mnLen != nMaxLen )
440 0 : return sal_False;
441 0 : nLen = static_cast< xub_StrLen >(nMaxLen);
442 : }
443 :
444 11916 : return (ImplStringCompareWithoutZero( mpData->maStr+nIndex, rStr.mpData->maStr, nLen ) == 0);
445 : }
446 :
447 0 : sal_Bool STRING::Equals( const STRCODE* pCharStr, xub_StrLen nIndex, xub_StrLen nLen ) const
448 : {
449 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
450 :
451 : // Are there enough codes for comparing?
452 0 : if ( nIndex > mpData->mnLen )
453 0 : return (*pCharStr == 0);
454 :
455 0 : return (ImplStringCompare( mpData->maStr+nIndex, pCharStr, nLen ) == 0);
456 : }
457 :
458 28074 : xub_StrLen STRING::Match( const STRING& rStr ) const
459 : {
460 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
461 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
462 :
463 : // return if string is empty
464 28074 : if ( !mpData->mnLen )
465 48 : return STRING_MATCH;
466 :
467 : // Search the string for unmatching chars
468 28026 : const STRCODE* pStr1 = mpData->maStr;
469 28026 : const STRCODE* pStr2 = rStr.mpData->maStr;
470 28026 : xub_StrLen i = 0;
471 59896 : while ( i < mpData->mnLen )
472 : {
473 : // Abort on the first unmatching char
474 31870 : if ( *pStr1 != *pStr2 )
475 28026 : return i;
476 : ++pStr1,
477 : ++pStr2,
478 3844 : ++i;
479 : }
480 :
481 0 : return STRING_MATCH;
482 : }
483 :
484 54 : xub_StrLen STRING::SearchBackward( STRCODE c, xub_StrLen nIndex ) const
485 : {
486 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
487 :
488 54 : if ( nIndex > mpData->mnLen )
489 54 : nIndex = (xub_StrLen)mpData->mnLen;
490 :
491 54 : const STRCODE* pStr = mpData->maStr;
492 54 : pStr += nIndex;
493 :
494 607 : while ( nIndex )
495 : {
496 553 : nIndex--;
497 553 : pStr--;
498 553 : if ( *pStr == c )
499 54 : return nIndex;
500 : }
501 :
502 0 : return STRING_NOTFOUND;
503 : }
504 :
505 4068 : void STRING::SearchAndReplaceAll( const STRING& rStr, const STRING& rRepStr )
506 : {
507 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
508 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
509 : DBG_CHKOBJ( &rRepStr, STRING, DBGCHECKSTRING );
510 :
511 4068 : xub_StrLen nSPos = Search( rStr, 0 );
512 8136 : while ( nSPos != STRING_NOTFOUND )
513 : {
514 0 : Replace( nSPos, rStr.Len(), rRepStr );
515 0 : nSPos = nSPos + rRepStr.Len();
516 0 : nSPos = Search( rStr, nSPos );
517 : }
518 4068 : }
519 :
520 0 : void STRING::SetToken( xub_StrLen nToken, STRCODE cTok, const STRING& rStr,
521 : xub_StrLen nIndex )
522 : {
523 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
524 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
525 :
526 0 : const STRCODE* pStr = mpData->maStr;
527 0 : xub_StrLen nLen = (xub_StrLen)mpData->mnLen;
528 0 : xub_StrLen nTok = 0;
529 0 : xub_StrLen nFirstChar = nIndex;
530 0 : xub_StrLen i = nFirstChar;
531 :
532 : // Determine token position and length
533 0 : pStr += i;
534 0 : while ( i < nLen )
535 : {
536 : // Increase token count if match
537 0 : if ( *pStr == cTok )
538 : {
539 0 : ++nTok;
540 :
541 0 : if ( nTok == nToken )
542 0 : nFirstChar = i+1;
543 : else
544 : {
545 0 : if ( nTok > nToken )
546 0 : break;
547 : }
548 : }
549 :
550 : ++pStr,
551 0 : ++i;
552 : }
553 :
554 0 : if ( nTok >= nToken )
555 0 : Replace( nFirstChar, i-nFirstChar, rStr );
556 0 : }
557 :
558 7800 : STRING STRING::GetToken( xub_StrLen nToken, STRCODE cTok, xub_StrLen& rIndex ) const
559 : {
560 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
561 :
562 7800 : const STRCODE* pStr = mpData->maStr;
563 7800 : xub_StrLen nLen = (xub_StrLen)mpData->mnLen;
564 7800 : xub_StrLen nTok = 0;
565 7800 : xub_StrLen nFirstChar = rIndex;
566 7800 : xub_StrLen i = nFirstChar;
567 :
568 : // Determine token position and length
569 7800 : pStr += i;
570 111920 : while ( i < nLen )
571 : {
572 : // Increase token count if match
573 98666 : if ( *pStr == cTok )
574 : {
575 6594 : ++nTok;
576 :
577 6594 : if ( nTok == nToken )
578 2162 : nFirstChar = i+1;
579 : else
580 : {
581 4432 : if ( nTok > nToken )
582 2346 : break;
583 : }
584 : }
585 :
586 : ++pStr,
587 96320 : ++i;
588 : }
589 :
590 7800 : if ( nTok >= nToken )
591 : {
592 5894 : if ( i < nLen )
593 2346 : rIndex = i+1;
594 : else
595 3548 : rIndex = STRING_NOTFOUND;
596 5894 : return Copy( nFirstChar, i-nFirstChar );
597 : }
598 : else
599 : {
600 1906 : rIndex = STRING_NOTFOUND;
601 1906 : return STRING();
602 : }
603 : }
604 :
605 5350 : STRING& STRING::Append( const STRCODE* pCharStr, xub_StrLen nCharLen )
606 : {
607 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
608 : DBG_ASSERT( pCharStr, "String::Append() - pCharStr is NULL" );
609 :
610 5350 : if ( nCharLen == STRING_LEN )
611 0 : nCharLen = ImplStringLen( pCharStr );
612 :
613 : #ifdef DBG_UTIL
614 : if ( DbgIsAssert() )
615 : {
616 : for ( xub_StrLen i = 0; i < nCharLen; i++ )
617 : {
618 : if ( !pCharStr[i] )
619 : {
620 : OSL_FAIL( "String::Append() : nLen is wrong" );
621 : }
622 : }
623 : }
624 : #endif
625 :
626 : // Catch overflow
627 5350 : sal_Int32 nLen = mpData->mnLen;
628 5350 : sal_Int32 nCopyLen = ImplGetCopyLen( nLen, nCharLen );
629 :
630 5350 : if ( nCopyLen )
631 : {
632 : // allocate string of new size
633 5034 : STRINGDATA* pNewData = ImplAllocData( nLen+nCopyLen );
634 :
635 : // copy string
636 5034 : memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
637 5034 : memcpy( pNewData->maStr+nLen, pCharStr, nCopyLen*sizeof( STRCODE ) );
638 :
639 : // free old string
640 5034 : STRING_RELEASE((STRING_TYPE *)mpData);
641 5034 : mpData = pNewData;
642 : }
643 :
644 5350 : return *this;
645 : }
646 :
647 52806 : STRING& STRING::Append( STRCODE c )
648 : {
649 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
650 :
651 : // don't append null characters and keep string length < maxlen
652 52806 : sal_Int32 nLen = mpData->mnLen;
653 52806 : if ( c && (nLen < STRING_MAXLEN) )
654 : {
655 : // allocate string of new size
656 52806 : STRINGDATA* pNewData = ImplAllocData( nLen+1 );
657 :
658 : // copy string
659 52806 : memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
660 52806 : pNewData->maStr[nLen] = c;
661 :
662 : // free old string
663 52806 : STRING_RELEASE((STRING_TYPE *)mpData);
664 52806 : mpData = pNewData;
665 : }
666 :
667 52806 : return *this;
668 : }
669 :
670 196 : STRING& STRING::Assign( STRCODE c )
671 : {
672 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
673 : DBG_ASSERT( c, "String::Assign() - c is 0" );
674 :
675 : // initialize maintenance data
676 196 : STRING_RELEASE((STRING_TYPE *)mpData);
677 196 : mpData = ImplAllocData( 1 );
678 196 : mpData->maStr[0] = c;
679 196 : return *this;
680 : }
681 :
682 2696 : xub_StrLen STRING::SearchAndReplace( const STRING& rStr, const STRING& rRepStr,
683 : xub_StrLen nIndex )
684 : {
685 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
686 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
687 : DBG_CHKOBJ( &rRepStr, STRING, DBGCHECKSTRING );
688 :
689 2696 : xub_StrLen nSPos = Search( rStr, nIndex );
690 2696 : if ( nSPos != STRING_NOTFOUND )
691 2670 : Replace( nSPos, rStr.Len(), rRepStr );
692 :
693 2696 : return nSPos;
694 : }
695 :
696 22 : static sal_Int32 ImplStringICompare( const STRCODE* pStr1, const STRCODE* pStr2 )
697 : {
698 : sal_Int32 nRet;
699 : STRCODE c1;
700 : STRCODE c2;
701 14 : do
702 : {
703 : // Convert char if between 'A' and 'Z'
704 22 : c1 = *pStr1;
705 22 : c2 = *pStr2;
706 22 : if ( (c1 >= 65) && (c1 <= 90) )
707 10 : c1 += 32;
708 22 : if ( (c2 >= 65) && (c2 <= 90) )
709 10 : c2 += 32;
710 22 : nRet = ((sal_Int32)((STRCODEU)c1))-((sal_Int32)((STRCODEU)c2));
711 22 : if ( nRet != 0 )
712 8 : break;
713 :
714 : ++pStr1,
715 14 : ++pStr2;
716 : }
717 : while ( c2 );
718 :
719 10 : return nRet;
720 : }
721 :
722 10 : sal_Bool STRING::EqualsIgnoreCaseAscii( const STRCODE* pCharStr ) const
723 : {
724 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
725 :
726 10 : return (ImplStringICompare( mpData->maStr, pCharStr ) == 0);
727 : }
728 :
729 16790 : STRING& STRING::Assign( const STRCODE* pCharStr )
730 : {
731 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
732 : DBG_ASSERT( pCharStr, "String::Assign() - pCharStr is NULL" );
733 :
734 16790 : xub_StrLen nLen = ImplStringLen( pCharStr );
735 :
736 16790 : if ( !nLen )
737 : {
738 6422 : STRING_NEW((STRING_TYPE **)&mpData);
739 : }
740 : else
741 : {
742 : // copy without allocation if string length is identical
743 10368 : if ( (nLen == mpData->mnLen) && (mpData->mnRefCount == 1) )
744 2 : memcpy( mpData->maStr, pCharStr, nLen*sizeof( STRCODE ) );
745 : else
746 : {
747 : // free old string
748 10366 : STRING_RELEASE((STRING_TYPE *)mpData);
749 :
750 : // allocate string of new size and copy
751 10366 : mpData = ImplAllocData( nLen );
752 10366 : memcpy( mpData->maStr, pCharStr, nLen*sizeof( STRCODE ) );
753 : }
754 : }
755 :
756 16790 : return *this;
757 : }
758 :
759 2042238 : xub_StrLen ImplStringLen( const sal_Char* pStr )
760 : {
761 2042238 : const sal_Char* pTempStr = pStr;
762 17881926 : while( *pTempStr )
763 13797450 : ++pTempStr;
764 2042238 : return (xub_StrLen)(pTempStr-pStr);
765 : }
766 :
767 29316 : xub_StrLen ImplStringLen( const sal_Unicode* pStr )
768 : {
769 29316 : const sal_Unicode* pTempStr = pStr;
770 312876 : while( *pTempStr )
771 254244 : ++pTempStr;
772 29316 : return (xub_StrLen)(pTempStr-pStr);
773 : }
774 :
775 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|