bump product version to 4.1.6.2
[LibreOffice.git] / tools / source / string / tustring.cxx
blobac4bb4ac51810ff7da585ec1f63d31d2a3097f2f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <string.h>
22 #include "boost/static_assert.hpp"
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>
30 #include <impstrg.hxx>
32 #include <tools/debug.hxx>
34 DBG_NAME( UniString )
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
45 #if defined DBG_UTIL
46 #define DBGCHECKSTRING DbgCheckUniString
47 #endif
49 #include <strimp.cxx>
50 #include <strucvt.cxx>
51 #include <strascii.cxx>
53 UniString::UniString(char c): mpData(ImplAllocData(1)) { mpData->maStr[0] = c; }
55 namespace { struct Empty : public rtl::Static< const UniString, Empty> {}; }
57 const UniString& UniString::EmptyString()
59 return Empty::get();
62 sal_Int32 UniString::ToInt32() const
64 DBG_CHKTHIS( UniString, DbgCheckUniString );
66 return rtl_ustr_toInt32( mpData->maStr, 10 );
69 sal_Int64 UniString::ToInt64() const
71 DBG_CHKTHIS( UniString, DbgCheckUniString );
73 return rtl_ustr_toInt64( mpData->maStr, 10 );
76 xub_StrLen STRING::SearchChar( const STRCODE* pChars, xub_StrLen nIndex ) const
78 DBG_CHKTHIS( STRING, DBGCHECKSTRING );
80 sal_Int32 nLen = mpData->mnLen;
81 const STRCODE* pStr = mpData->maStr;
82 pStr += nIndex;
83 while ( nIndex < nLen )
85 STRCODE c = *pStr;
86 const STRCODE* pCompStr = pChars;
87 while ( *pCompStr )
89 if ( *pCompStr == c )
90 return nIndex;
91 ++pCompStr;
93 ++pStr,
94 ++nIndex;
97 return STRING_NOTFOUND;
100 xub_StrLen STRING::SearchAndReplace( STRCODE c, STRCODE cRep, xub_StrLen nIndex )
102 DBG_CHKTHIS( STRING, DBGCHECKSTRING );
104 sal_Int32 nLen = mpData->mnLen;
105 const STRCODE* pStr = mpData->maStr;
106 pStr += nIndex;
107 while ( nIndex < nLen )
109 if ( *pStr == c )
111 ImplCopyData();
112 mpData->maStr[nIndex] = cRep;
113 return nIndex;
115 ++pStr,
116 ++nIndex;
119 return STRING_NOTFOUND;
122 STRING& STRING::Insert( const STRING& rStr, xub_StrLen nPos, xub_StrLen nLen,
123 xub_StrLen nIndex )
125 DBG_CHKTHIS( STRING, DBGCHECKSTRING );
126 DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
128 // Determine string length
129 if ( nPos > rStr.mpData->mnLen )
130 nLen = 0;
131 else
133 // Correct length if necessary
134 sal_Int32 nMaxLen = rStr.mpData->mnLen-nPos;
135 if ( nLen > nMaxLen )
136 nLen = static_cast< xub_StrLen >(nMaxLen);
139 // Detect overflow
140 sal_Int32 nCopyLen = ImplGetCopyLen( mpData->mnLen, nLen );
142 if ( !nCopyLen )
143 return *this;
145 // Correct index if necessary
146 if ( nIndex > mpData->mnLen )
147 nIndex = static_cast< xub_StrLen >(mpData->mnLen);
149 // Determine new length and allocate string
150 STRINGDATA* pNewData = ImplAllocData( mpData->mnLen+nCopyLen );
152 // copy string to newdata
153 memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
154 memcpy( pNewData->maStr+nIndex, rStr.mpData->maStr+nPos, nCopyLen*sizeof( STRCODE ) );
155 memcpy( pNewData->maStr+nIndex+nCopyLen, mpData->maStr+nIndex,
156 (mpData->mnLen-nIndex)*sizeof( STRCODE ) );
158 // release old data
159 STRING_RELEASE((STRING_TYPE *)mpData);
160 mpData = pNewData;
162 return *this;
165 static sal_Int32 ImplStringICompareWithoutZero( const STRCODE* pStr1, const STRCODE* pStr2,
166 sal_Int32 nCount )
168 sal_Int32 nRet = 0;
169 STRCODE c1;
170 STRCODE c2;
173 if ( !nCount )
174 break;
176 // convert if char is between 'A' and 'Z'
177 c1 = *pStr1;
178 c2 = *pStr2;
179 if ( (c1 >= 65) && (c1 <= 90) )
180 c1 += 32;
181 if ( (c2 >= 65) && (c2 <= 90) )
182 c2 += 32;
183 nRet = ((sal_Int32)((STRCODEU)c1))-((sal_Int32)((STRCODEU)c2));
185 ++pStr1,
186 ++pStr2,
187 --nCount;
189 while ( nRet == 0 );
191 return nRet;
194 sal_Bool STRING::EqualsIgnoreCaseAscii( const STRING& rStr, xub_StrLen nIndex, xub_StrLen nLen ) const
196 DBG_CHKTHIS( STRING, DBGCHECKSTRING );
197 DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
199 // Are there enough codes for comparing?
200 if ( nIndex > mpData->mnLen )
201 return (rStr.mpData->mnLen == 0);
202 sal_Int32 nMaxLen = mpData->mnLen-nIndex;
203 if ( nMaxLen < nLen )
205 if ( rStr.mpData->mnLen != nMaxLen )
206 return sal_False;
207 nLen = static_cast< xub_StrLen >(nMaxLen);
210 return (ImplStringICompareWithoutZero( mpData->maStr+nIndex, rStr.mpData->maStr, nLen ) == 0);
213 StringCompare STRING::CompareIgnoreCaseToAscii( const STRING& rStr,
214 xub_StrLen nLen ) const
216 DBG_CHKTHIS( STRING, DBGCHECKSTRING );
217 DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
219 if ( mpData == rStr.mpData )
220 return COMPARE_EQUAL;
222 // determine maximal length
223 if ( mpData->mnLen < nLen )
224 nLen = static_cast< xub_StrLen >(mpData->mnLen+1);
225 if ( rStr.mpData->mnLen < nLen )
226 nLen = static_cast< xub_StrLen >(rStr.mpData->mnLen+1);
228 sal_Int32 nCompare = ImplStringICompareWithoutZero( mpData->maStr, rStr.mpData->maStr, nLen );
230 if ( nCompare == 0 )
231 return COMPARE_EQUAL;
232 else if ( nCompare < 0 )
233 return COMPARE_LESS;
234 else
235 return COMPARE_GREATER;
238 STRCODE* STRING::GetBufferAccess()
240 DBG_CHKTHIS( STRING, DBGCHECKSTRING );
242 // Copy data if necessary
243 if ( mpData->mnLen )
244 ImplCopyData();
246 // return pointer to string data
247 return mpData->maStr;
250 void STRING::ReleaseBufferAccess( xub_StrLen nLen )
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" );
256 if ( nLen > mpData->mnLen )
257 nLen = ImplStringLen( mpData->maStr );
258 OSL_ASSERT(nLen <= mpData->mnLen);
259 if ( !nLen )
261 STRING_NEW((STRING_TYPE **)&mpData);
263 // shorten buffer is difference > 8 chars
264 else if ( mpData->mnLen - nLen > 8 )
266 STRINGDATA* pNewData = ImplAllocData( nLen );
267 memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
268 STRING_RELEASE((STRING_TYPE *)mpData);
269 mpData = pNewData;
271 else
272 mpData->mnLen = nLen;
275 STRCODE* STRING::AllocBuffer( xub_StrLen nLen )
277 DBG_CHKTHIS( STRING, DBGCHECKSTRING );
279 STRING_RELEASE((STRING_TYPE *)mpData);
280 if ( nLen )
281 mpData = ImplAllocData( nLen );
282 else
284 mpData = NULL;
285 STRING_NEW((STRING_TYPE **)&mpData);
288 return mpData->maStr;
291 STRING& STRING::Insert( STRCODE c, xub_StrLen nIndex )
293 DBG_CHKTHIS( STRING, DBGCHECKSTRING );
295 // Don't insert 0 char or string size is maximum
296 if ( !c || (mpData->mnLen == STRING_MAXLEN) )
297 return *this;
299 // Adjust string index
300 if ( nIndex > mpData->mnLen )
301 nIndex = static_cast< xub_StrLen >(mpData->mnLen);
303 // allocate string of new size
304 STRINGDATA* pNewData = ImplAllocData( mpData->mnLen+1 );
306 // copy string
307 memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
308 pNewData->maStr[nIndex] = c;
309 memcpy( pNewData->maStr+nIndex+1, mpData->maStr+nIndex,
310 (mpData->mnLen-nIndex)*sizeof( STRCODE ) );
312 // free old data
313 STRING_RELEASE((STRING_TYPE *)mpData);
314 mpData = pNewData;
316 return *this;
319 STRING& STRING::ToUpperAscii()
321 DBG_CHKTHIS( STRING, DBGCHECKSTRING );
323 sal_Int32 nIndex = 0;
324 sal_Int32 nLen = mpData->mnLen;
325 STRCODE* pStr = mpData->maStr;
326 while ( nIndex < nLen )
328 // convert char if between 'a' and 'z'
329 if ( (*pStr >= 97) && (*pStr <= 122) )
331 // allocate string of new size
332 pStr = ImplCopyStringData( pStr );
333 *pStr -= 32;
336 ++pStr,
337 ++nIndex;
340 return *this;
343 StringCompare STRING::CompareTo( const STRING& rStr, xub_StrLen nLen ) const
345 DBG_CHKTHIS( STRING, DBGCHECKSTRING );
346 DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
348 if ( mpData == rStr.mpData )
349 return COMPARE_EQUAL;
351 // determine maximal length
352 if ( mpData->mnLen < nLen )
353 nLen = static_cast< xub_StrLen >(mpData->mnLen+1);
354 if ( rStr.mpData->mnLen < nLen )
355 nLen = static_cast< xub_StrLen >(rStr.mpData->mnLen+1);
357 sal_Int32 nCompare = ImplStringCompareWithoutZero( mpData->maStr, rStr.mpData->maStr, nLen );
359 if ( nCompare == 0 )
360 return COMPARE_EQUAL;
361 else if ( nCompare < 0 )
362 return COMPARE_LESS;
363 else
364 return COMPARE_GREATER;
367 sal_Bool STRING::Equals( const STRING& rStr ) const
369 DBG_CHKTHIS( STRING, DBGCHECKSTRING );
370 DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
372 if ( mpData == rStr.mpData )
373 return sal_True;
375 if ( mpData->mnLen != rStr.mpData->mnLen )
376 return sal_False;
378 return (ImplStringCompareWithoutZero( mpData->maStr, rStr.mpData->maStr, mpData->mnLen ) == 0);
381 sal_Bool STRING::EqualsIgnoreCaseAscii( const STRING& rStr ) const
383 DBG_CHKTHIS( STRING, DBGCHECKSTRING );
384 DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
386 if ( mpData == rStr.mpData )
387 return sal_True;
389 if ( mpData->mnLen != rStr.mpData->mnLen )
390 return sal_False;
392 // compare string while ignoring case
393 return (ImplStringICompareWithoutZero( mpData->maStr, rStr.mpData->maStr, mpData->mnLen ) == 0);
396 sal_Bool STRING::Equals( const STRING& rStr, xub_StrLen nIndex, xub_StrLen nLen ) const
398 DBG_CHKTHIS( STRING, DBGCHECKSTRING );
399 DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
401 // Are there enough codes for comparing?
402 if ( nIndex > mpData->mnLen )
403 return (rStr.mpData->mnLen == 0);
404 sal_Int32 nMaxLen = mpData->mnLen-nIndex;
405 if ( nMaxLen < nLen )
407 if ( rStr.mpData->mnLen != nMaxLen )
408 return sal_False;
409 nLen = static_cast< xub_StrLen >(nMaxLen);
412 return (ImplStringCompareWithoutZero( mpData->maStr+nIndex, rStr.mpData->maStr, nLen ) == 0);
415 sal_Bool STRING::Equals( const STRCODE* pCharStr, xub_StrLen nIndex, xub_StrLen nLen ) const
417 DBG_CHKTHIS( STRING, DBGCHECKSTRING );
419 // Are there enough codes for comparing?
420 if ( nIndex > mpData->mnLen )
421 return (*pCharStr == 0);
423 return (ImplStringCompare( mpData->maStr+nIndex, pCharStr, nLen ) == 0);
426 xub_StrLen STRING::Match( const STRING& rStr ) const
428 DBG_CHKTHIS( STRING, DBGCHECKSTRING );
429 DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
431 // return if string is empty
432 if ( !mpData->mnLen )
433 return STRING_MATCH;
435 // Search the string for unmatching chars
436 const STRCODE* pStr1 = mpData->maStr;
437 const STRCODE* pStr2 = rStr.mpData->maStr;
438 xub_StrLen i = 0;
439 while ( i < mpData->mnLen )
441 // Abort on the first unmatching char
442 if ( *pStr1 != *pStr2 )
443 return i;
444 ++pStr1,
445 ++pStr2,
446 ++i;
449 return STRING_MATCH;
452 xub_StrLen STRING::SearchBackward( STRCODE c, xub_StrLen nIndex ) const
454 DBG_CHKTHIS( STRING, DBGCHECKSTRING );
456 if ( nIndex > mpData->mnLen )
457 nIndex = (xub_StrLen)mpData->mnLen;
459 const STRCODE* pStr = mpData->maStr;
460 pStr += nIndex;
462 while ( nIndex )
464 nIndex--;
465 pStr--;
466 if ( *pStr == c )
467 return nIndex;
470 return STRING_NOTFOUND;
473 void STRING::SearchAndReplaceAll( const STRING& rStr, const STRING& rRepStr )
475 DBG_CHKTHIS( STRING, DBGCHECKSTRING );
476 DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
477 DBG_CHKOBJ( &rRepStr, STRING, DBGCHECKSTRING );
479 xub_StrLen nSPos = Search( rStr, 0 );
480 while ( nSPos != STRING_NOTFOUND )
482 Replace( nSPos, rStr.Len(), rRepStr );
483 nSPos = nSPos + rRepStr.Len();
484 nSPos = Search( rStr, nSPos );
488 void STRING::SetToken( xub_StrLen nToken, STRCODE cTok, const STRING& rStr,
489 xub_StrLen nIndex )
491 DBG_CHKTHIS( STRING, DBGCHECKSTRING );
492 DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
494 const STRCODE* pStr = mpData->maStr;
495 xub_StrLen nLen = (xub_StrLen)mpData->mnLen;
496 xub_StrLen nTok = 0;
497 xub_StrLen nFirstChar = nIndex;
498 xub_StrLen i = nFirstChar;
500 // Determine token position and length
501 pStr += i;
502 while ( i < nLen )
504 // Increase token count if match
505 if ( *pStr == cTok )
507 ++nTok;
509 if ( nTok == nToken )
510 nFirstChar = i+1;
511 else
513 if ( nTok > nToken )
514 break;
518 ++pStr,
519 ++i;
522 if ( nTok >= nToken )
523 Replace( nFirstChar, i-nFirstChar, rStr );
526 STRING STRING::GetToken( xub_StrLen nToken, STRCODE cTok, sal_Int32& rIndex ) const
528 DBG_CHKTHIS( STRING, DBGCHECKSTRING );
530 const STRCODE* pStr = mpData->maStr;
531 xub_StrLen nLen = (xub_StrLen)mpData->mnLen;
532 xub_StrLen nTok = 0;
533 sal_Int32 nFirstChar = rIndex;
534 xub_StrLen i = nFirstChar;
536 // Determine token position and length
537 pStr += i;
538 while ( i < nLen )
540 // Increase token count if match
541 if ( *pStr == cTok )
543 ++nTok;
545 if ( nTok == nToken )
546 nFirstChar = i+1;
547 else
549 if ( nTok > nToken )
550 break;
554 ++pStr,
555 ++i;
558 if ( nTok >= nToken )
560 if ( i < nLen )
561 rIndex = i+1;
562 else
563 rIndex = -1;
564 return Copy( nFirstChar, i-nFirstChar );
566 else
568 rIndex = -1;
569 return STRING();
573 STRING& STRING::Append( const STRCODE* pCharStr, xub_StrLen nCharLen )
575 DBG_CHKTHIS( STRING, DBGCHECKSTRING );
576 DBG_ASSERT( pCharStr, "String::Append() - pCharStr is NULL" );
578 if ( nCharLen == STRING_LEN )
579 nCharLen = ImplStringLen( pCharStr );
581 #ifdef DBG_UTIL
582 if ( DbgIsAssert() )
584 for ( xub_StrLen i = 0; i < nCharLen; i++ )
586 if ( !pCharStr[i] )
588 OSL_FAIL( "String::Append() : nLen is wrong" );
592 #endif
594 // Catch overflow
595 sal_Int32 nLen = mpData->mnLen;
596 sal_Int32 nCopyLen = ImplGetCopyLen( nLen, nCharLen );
598 if ( nCopyLen )
600 // allocate string of new size
601 STRINGDATA* pNewData = ImplAllocData( nLen+nCopyLen );
603 // copy string
604 memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
605 memcpy( pNewData->maStr+nLen, pCharStr, nCopyLen*sizeof( STRCODE ) );
607 // free old string
608 STRING_RELEASE((STRING_TYPE *)mpData);
609 mpData = pNewData;
612 return *this;
615 STRING& STRING::Append( STRCODE c )
617 DBG_CHKTHIS( STRING, DBGCHECKSTRING );
619 // don't append null characters and keep string length < maxlen
620 sal_Int32 nLen = mpData->mnLen;
621 if ( c && (nLen < STRING_MAXLEN) )
623 // allocate string of new size
624 STRINGDATA* pNewData = ImplAllocData( nLen+1 );
626 // copy string
627 memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
628 pNewData->maStr[nLen] = c;
630 // free old string
631 STRING_RELEASE((STRING_TYPE *)mpData);
632 mpData = pNewData;
635 return *this;
638 STRING& STRING::Assign( STRCODE c )
640 DBG_CHKTHIS( STRING, DBGCHECKSTRING );
641 DBG_ASSERT( c, "String::Assign() - c is 0" );
643 // initialize maintenance data
644 STRING_RELEASE((STRING_TYPE *)mpData);
645 mpData = ImplAllocData( 1 );
646 mpData->maStr[0] = c;
647 return *this;
650 xub_StrLen STRING::SearchAndReplace( const STRING& rStr, const STRING& rRepStr,
651 xub_StrLen nIndex )
653 DBG_CHKTHIS( STRING, DBGCHECKSTRING );
654 DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
655 DBG_CHKOBJ( &rRepStr, STRING, DBGCHECKSTRING );
657 xub_StrLen nSPos = Search( rStr, nIndex );
658 if ( nSPos != STRING_NOTFOUND )
659 Replace( nSPos, rStr.Len(), rRepStr );
661 return nSPos;
664 static sal_Int32 ImplStringICompare( const STRCODE* pStr1, const STRCODE* pStr2 )
666 sal_Int32 nRet;
667 STRCODE c1;
668 STRCODE c2;
671 // Convert char if between 'A' and 'Z'
672 c1 = *pStr1;
673 c2 = *pStr2;
674 if ( (c1 >= 65) && (c1 <= 90) )
675 c1 += 32;
676 if ( (c2 >= 65) && (c2 <= 90) )
677 c2 += 32;
678 nRet = ((sal_Int32)((STRCODEU)c1))-((sal_Int32)((STRCODEU)c2));
679 if ( nRet != 0 )
680 break;
682 ++pStr1,
683 ++pStr2;
685 while ( c2 );
687 return nRet;
690 sal_Bool STRING::EqualsIgnoreCaseAscii( const STRCODE* pCharStr ) const
692 DBG_CHKTHIS( STRING, DBGCHECKSTRING );
694 return (ImplStringICompare( mpData->maStr, pCharStr ) == 0);
697 STRING& STRING::Assign( const STRCODE* pCharStr )
699 DBG_CHKTHIS( STRING, DBGCHECKSTRING );
700 DBG_ASSERT( pCharStr, "String::Assign() - pCharStr is NULL" );
702 xub_StrLen nLen = ImplStringLen( pCharStr );
704 if ( !nLen )
706 STRING_NEW((STRING_TYPE **)&mpData);
708 else
710 // copy without allocation if string length is identical
711 if ( (nLen == mpData->mnLen) && (mpData->mnRefCount == 1) )
712 memcpy( mpData->maStr, pCharStr, nLen*sizeof( STRCODE ) );
713 else
715 // free old string
716 STRING_RELEASE((STRING_TYPE *)mpData);
718 // allocate string of new size and copy
719 mpData = ImplAllocData( nLen );
720 memcpy( mpData->maStr, pCharStr, nLen*sizeof( STRCODE ) );
724 return *this;
727 xub_StrLen ImplStringLen( const sal_Char* pStr )
729 const sal_Char* pTempStr = pStr;
730 while( *pTempStr )
731 ++pTempStr;
732 return (xub_StrLen)(pTempStr-pStr);
735 xub_StrLen ImplStringLen( const sal_Unicode* pStr )
737 const sal_Unicode* pTempStr = pStr;
738 while( *pTempStr )
739 ++pTempStr;
740 return (xub_StrLen)(pTempStr-pStr);
743 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */