1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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>
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
46 #define DBGCHECKSTRING DbgCheckUniString
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()
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
;
83 while ( nIndex
< nLen
)
86 const STRCODE
* pCompStr
= pChars
;
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
;
107 while ( nIndex
< nLen
)
112 mpData
->maStr
[nIndex
] = cRep
;
119 return STRING_NOTFOUND
;
122 STRING
& STRING::Insert( const STRING
& rStr
, xub_StrLen nPos
, xub_StrLen nLen
,
125 DBG_CHKTHIS( STRING
, DBGCHECKSTRING
);
126 DBG_CHKOBJ( &rStr
, STRING
, DBGCHECKSTRING
);
128 // Determine string length
129 if ( nPos
> rStr
.mpData
->mnLen
)
133 // Correct length if necessary
134 sal_Int32 nMaxLen
= rStr
.mpData
->mnLen
-nPos
;
135 if ( nLen
> nMaxLen
)
136 nLen
= static_cast< xub_StrLen
>(nMaxLen
);
140 sal_Int32 nCopyLen
= ImplGetCopyLen( mpData
->mnLen
, nLen
);
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
) );
159 STRING_RELEASE((STRING_TYPE
*)mpData
);
165 static sal_Int32
ImplStringICompareWithoutZero( const STRCODE
* pStr1
, const STRCODE
* pStr2
,
176 // convert if char is between 'A' and 'Z'
179 if ( (c1
>= 65) && (c1
<= 90) )
181 if ( (c2
>= 65) && (c2
<= 90) )
183 nRet
= ((sal_Int32
)((STRCODEU
)c1
))-((sal_Int32
)((STRCODEU
)c2
));
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
)
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
);
231 return COMPARE_EQUAL
;
232 else if ( nCompare
< 0 )
235 return COMPARE_GREATER
;
238 STRCODE
* STRING::GetBufferAccess()
240 DBG_CHKTHIS( STRING
, DBGCHECKSTRING
);
242 // Copy data if necessary
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
);
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
);
272 mpData
->mnLen
= nLen
;
275 STRCODE
* STRING::AllocBuffer( xub_StrLen nLen
)
277 DBG_CHKTHIS( STRING
, DBGCHECKSTRING
);
279 STRING_RELEASE((STRING_TYPE
*)mpData
);
281 mpData
= ImplAllocData( nLen
);
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
) )
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 );
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
) );
313 STRING_RELEASE((STRING_TYPE
*)mpData
);
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
);
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
);
360 return COMPARE_EQUAL
;
361 else if ( nCompare
< 0 )
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
)
375 if ( mpData
->mnLen
!= rStr
.mpData
->mnLen
)
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
)
389 if ( mpData
->mnLen
!= rStr
.mpData
->mnLen
)
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
)
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
)
435 // Search the string for unmatching chars
436 const STRCODE
* pStr1
= mpData
->maStr
;
437 const STRCODE
* pStr2
= rStr
.mpData
->maStr
;
439 while ( i
< mpData
->mnLen
)
441 // Abort on the first unmatching char
442 if ( *pStr1
!= *pStr2
)
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
;
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
,
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
;
497 xub_StrLen nFirstChar
= nIndex
;
498 xub_StrLen i
= nFirstChar
;
500 // Determine token position and length
504 // Increase token count if match
509 if ( nTok
== nToken
)
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
;
533 sal_Int32 nFirstChar
= rIndex
;
534 xub_StrLen i
= nFirstChar
;
536 // Determine token position and length
540 // Increase token count if match
545 if ( nTok
== nToken
)
558 if ( nTok
>= nToken
)
564 return Copy( nFirstChar
, i
-nFirstChar
);
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
);
584 for ( xub_StrLen i
= 0; i
< nCharLen
; i
++ )
588 OSL_FAIL( "String::Append() : nLen is wrong" );
595 sal_Int32 nLen
= mpData
->mnLen
;
596 sal_Int32 nCopyLen
= ImplGetCopyLen( nLen
, nCharLen
);
600 // allocate string of new size
601 STRINGDATA
* pNewData
= ImplAllocData( nLen
+nCopyLen
);
604 memcpy( pNewData
->maStr
, mpData
->maStr
, nLen
*sizeof( STRCODE
) );
605 memcpy( pNewData
->maStr
+nLen
, pCharStr
, nCopyLen
*sizeof( STRCODE
) );
608 STRING_RELEASE((STRING_TYPE
*)mpData
);
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 );
627 memcpy( pNewData
->maStr
, mpData
->maStr
, nLen
*sizeof( STRCODE
) );
628 pNewData
->maStr
[nLen
] = c
;
631 STRING_RELEASE((STRING_TYPE
*)mpData
);
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
;
650 xub_StrLen
STRING::SearchAndReplace( const STRING
& rStr
, const STRING
& rRepStr
,
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
);
664 static sal_Int32
ImplStringICompare( const STRCODE
* pStr1
, const STRCODE
* pStr2
)
671 // Convert char if between 'A' and 'Z'
674 if ( (c1
>= 65) && (c1
<= 90) )
676 if ( (c2
>= 65) && (c2
<= 90) )
678 nRet
= ((sal_Int32
)((STRCODEU
)c1
))-((sal_Int32
)((STRCODEU
)c2
));
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
);
706 STRING_NEW((STRING_TYPE
**)&mpData
);
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
) );
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
) );
727 xub_StrLen
ImplStringLen( const sal_Char
* pStr
)
729 const sal_Char
* pTempStr
= pStr
;
732 return (xub_StrLen
)(pTempStr
-pStr
);
735 xub_StrLen
ImplStringLen( const sal_Unicode
* pStr
)
737 const sal_Unicode
* pTempStr
= pStr
;
740 return (xub_StrLen
)(pTempStr
-pStr
);
743 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */