Branch data 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/memory.h>
27 : : #include <rtl/tencinfo.h>
28 : : #include <rtl/instance.hxx>
29 : : #include <tools/string.hxx>
30 : :
31 : : #include <impstrg.hxx>
32 : :
33 : : #include <tools/debug.hxx>
34 : :
35 : : DBG_NAME( UniString )
36 : :
37 : : #define STRCODE sal_Unicode
38 : : #define STRCODEU sal_Unicode
39 : : #define STRING UniString
40 : : #define STRINGDATA UniStringData
41 : : #define DBGCHECKSTRING DbgCheckUniString
42 : : #define STRING_TYPE rtl_uString
43 : : #define STRING_ACQUIRE rtl_uString_acquire
44 : : #define STRING_RELEASE rtl_uString_release
45 : : #define STRING_NEW rtl_uString_new
46 : :
47 : : #include <strimp.cxx>
48 : : #include <strucvt.cxx>
49 : : #include <strascii.cxx>
50 : :
51 : 0 : UniString::UniString(char c): mpData(ImplAllocData(1)) { mpData->maStr[0] = c; }
52 : :
53 : 192001 : UniString UniString::CreateFromInt32( sal_Int32 n, sal_Int16 nRadix )
54 : : {
55 [ + - ]: 192001 : return rtl::OUString::valueOf(n, nRadix);
56 : : }
57 : :
58 : : namespace { struct Empty : public rtl::Static< const UniString, Empty> {}; }
59 : :
60 : 44313 : const UniString& UniString::EmptyString()
61 : : {
62 : 44313 : return Empty::get();
63 : : }
64 : :
65 : 70665 : sal_Int32 UniString::ToInt32() const
66 : : {
67 : : DBG_CHKTHIS( UniString, DbgCheckUniString );
68 : :
69 : 70665 : return rtl_ustr_toInt32( mpData->maStr, 10 );
70 : : }
71 : :
72 : 0 : sal_Int64 UniString::ToInt64() const
73 : : {
74 : : DBG_CHKTHIS( UniString, DbgCheckUniString );
75 : :
76 : 0 : return rtl_ustr_toInt64( mpData->maStr, 10 );
77 : : }
78 : :
79 : 11892 : xub_StrLen STRING::SearchChar( const STRCODE* pChars, xub_StrLen nIndex ) const
80 : : {
81 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
82 : :
83 : 11892 : sal_Int32 nLen = mpData->mnLen;
84 : 11892 : const STRCODE* pStr = mpData->maStr;
85 : 11892 : pStr += nIndex;
86 [ + + ]: 83944 : while ( nIndex < nLen )
87 : : {
88 : 72102 : STRCODE c = *pStr;
89 : 72102 : const STRCODE* pCompStr = pChars;
90 [ + + ]: 413440 : while ( *pCompStr )
91 : : {
92 [ + + ]: 341388 : if ( *pCompStr == c )
93 : 50 : return nIndex;
94 : 341338 : ++pCompStr;
95 : : }
96 : : ++pStr,
97 : 72052 : ++nIndex;
98 : : }
99 : :
100 : 11892 : return STRING_NOTFOUND;
101 : : }
102 : :
103 : 405 : xub_StrLen STRING::SearchAndReplace( STRCODE c, STRCODE cRep, xub_StrLen nIndex )
104 : : {
105 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
106 : :
107 : 405 : sal_Int32 nLen = mpData->mnLen;
108 : 405 : const STRCODE* pStr = mpData->maStr;
109 : 405 : pStr += nIndex;
110 [ + + ]: 3870 : while ( nIndex < nLen )
111 : : {
112 [ + + ]: 3585 : if ( *pStr == c )
113 : : {
114 : 120 : ImplCopyData();
115 : 120 : mpData->maStr[nIndex] = cRep;
116 : 120 : return nIndex;
117 : : }
118 : : ++pStr,
119 : 3465 : ++nIndex;
120 : : }
121 : :
122 : 405 : return STRING_NOTFOUND;
123 : : }
124 : :
125 : 1587 : STRING& STRING::Insert( const STRING& rStr, xub_StrLen nPos, xub_StrLen nLen,
126 : : xub_StrLen nIndex )
127 : : {
128 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
129 : : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
130 : :
131 : : // Determine string length
132 [ - + ]: 1587 : if ( nPos > rStr.mpData->mnLen )
133 : 0 : nLen = 0;
134 : : else
135 : : {
136 : : // Correct length if necessary
137 : 1587 : sal_Int32 nMaxLen = rStr.mpData->mnLen-nPos;
138 [ - + ]: 1587 : if ( nLen > nMaxLen )
139 : 0 : nLen = static_cast< xub_StrLen >(nMaxLen);
140 : : }
141 : :
142 : : // Detect overflow
143 : 1587 : sal_Int32 nCopyLen = ImplGetCopyLen( mpData->mnLen, nLen );
144 : :
145 [ - + ]: 1587 : if ( !nCopyLen )
146 : 0 : return *this;
147 : :
148 : : // Correct index if necessary
149 [ - + ]: 1587 : if ( nIndex > mpData->mnLen )
150 : 0 : nIndex = static_cast< xub_StrLen >(mpData->mnLen);
151 : :
152 : : // Determine new length and allocate string
153 : 1587 : STRINGDATA* pNewData = ImplAllocData( mpData->mnLen+nCopyLen );
154 : :
155 : : // copy string to newdata
156 : 1587 : memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
157 : 1587 : memcpy( pNewData->maStr+nIndex, rStr.mpData->maStr+nPos, nCopyLen*sizeof( STRCODE ) );
158 : 1587 : memcpy( pNewData->maStr+nIndex+nCopyLen, mpData->maStr+nIndex,
159 : 3174 : (mpData->mnLen-nIndex)*sizeof( STRCODE ) );
160 : :
161 : : // release old data
162 : 1587 : STRING_RELEASE((STRING_TYPE *)mpData);
163 : 1587 : mpData = pNewData;
164 : :
165 : 1587 : return *this;
166 : : }
167 : :
168 : 998876 : static sal_Int32 ImplStringICompareWithoutZero( const STRCODE* pStr1, const STRCODE* pStr2,
169 : : sal_Int32 nCount )
170 : : {
171 : 998876 : sal_Int32 nRet = 0;
172 : : STRCODE c1;
173 : : STRCODE c2;
174 [ + + ]: 2108897 : do
175 : : {
176 [ + + ]: 2171161 : if ( !nCount )
177 : 62264 : break;
178 : :
179 : : // convert if char is between 'A' and 'Z'
180 : 2108897 : c1 = *pStr1;
181 : 2108897 : c2 = *pStr2;
182 [ + + ][ + + ]: 2108897 : if ( (c1 >= 65) && (c1 <= 90) )
183 : 465837 : c1 += 32;
184 [ + + ][ + + ]: 2108897 : if ( (c2 >= 65) && (c2 <= 90) )
185 : 905668 : c2 += 32;
186 : 2108897 : nRet = ((sal_Int32)((STRCODEU)c1))-((sal_Int32)((STRCODEU)c2));
187 : :
188 : : ++pStr1,
189 : : ++pStr2,
190 : 2108897 : --nCount;
191 : : }
192 : : while ( nRet == 0 );
193 : :
194 : 998876 : return nRet;
195 : : }
196 : :
197 : 0 : sal_Bool STRING::EqualsIgnoreCaseAscii( const STRING& rStr, xub_StrLen nIndex, xub_StrLen nLen ) const
198 : : {
199 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
200 : : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
201 : :
202 : : // Are there enough codes for comparing?
203 [ # # ]: 0 : if ( nIndex > mpData->mnLen )
204 : 0 : return (rStr.mpData->mnLen == 0);
205 : 0 : sal_Int32 nMaxLen = mpData->mnLen-nIndex;
206 [ # # ]: 0 : if ( nMaxLen < nLen )
207 : : {
208 [ # # ]: 0 : if ( rStr.mpData->mnLen != nMaxLen )
209 : 0 : return sal_False;
210 : 0 : nLen = static_cast< xub_StrLen >(nMaxLen);
211 : : }
212 : :
213 : 0 : return (ImplStringICompareWithoutZero( mpData->maStr+nIndex, rStr.mpData->maStr, nLen ) == 0);
214 : : }
215 : :
216 : 715365 : StringCompare STRING::CompareIgnoreCaseToAscii( const STRING& rStr,
217 : : xub_StrLen nLen ) const
218 : : {
219 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
220 : : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
221 : :
222 [ + + ]: 715365 : if ( mpData == rStr.mpData )
223 : 6969 : return COMPARE_EQUAL;
224 : :
225 : : // determine maximal length
226 [ + - ]: 708396 : if ( mpData->mnLen < nLen )
227 : 708396 : nLen = static_cast< xub_StrLen >(mpData->mnLen+1);
228 [ + + ]: 708396 : if ( rStr.mpData->mnLen < nLen )
229 : 400664 : nLen = static_cast< xub_StrLen >(rStr.mpData->mnLen+1);
230 : :
231 : 708396 : sal_Int32 nCompare = ImplStringICompareWithoutZero( mpData->maStr, rStr.mpData->maStr, nLen );
232 : :
233 [ + + ]: 708396 : if ( nCompare == 0 )
234 : 9502 : return COMPARE_EQUAL;
235 [ + + ]: 698894 : else if ( nCompare < 0 )
236 : 311933 : return COMPARE_LESS;
237 : : else
238 : 715365 : return COMPARE_GREATER;
239 : : }
240 : :
241 : 194 : STRING& STRING::Fill( xub_StrLen nCount, STRCODE cFillChar )
242 : : {
243 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
244 : :
245 [ + + ]: 194 : if ( !nCount )
246 : 26 : return *this;
247 : :
248 : : // extend string if fill length is larger
249 [ + - ]: 168 : if ( nCount > mpData->mnLen )
250 : : {
251 : : // allocate string of new length
252 : 168 : STRINGDATA* pNewData = ImplAllocData( nCount );
253 : 168 : STRING_RELEASE((STRING_TYPE *)mpData);
254 : 168 : mpData = pNewData;
255 : : }
256 : : else
257 : 0 : ImplCopyData();
258 : :
259 : 168 : STRCODE* pStr = mpData->maStr;
260 [ + + ]: 1228 : do
261 : : {
262 : 1228 : *pStr = cFillChar;
263 : : ++pStr,
264 : 1228 : --nCount;
265 : : }
266 : : while ( nCount );
267 : :
268 : 194 : return *this;
269 : : }
270 : :
271 : 16620 : STRING& STRING::Expand( xub_StrLen nCount, STRCODE cExpandChar )
272 : : {
273 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
274 : :
275 : : // return if string doesn't need expanding
276 : 16620 : sal_Int32 nLen = mpData->mnLen;
277 [ - + ]: 16620 : if ( nCount <= nLen )
278 : 0 : return *this;
279 : :
280 : : // allocate string of new size
281 : 16620 : STRINGDATA* pNewData = ImplAllocData( nCount );
282 : :
283 : : // copy from old string
284 : 16620 : memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
285 : :
286 : : // and expand using the given character
287 : 16620 : STRCODE* pStr = pNewData->maStr;
288 : 16620 : pStr += nLen;
289 [ + + ]: 65857 : for (sal_Int32 i = nCount - nLen; i > 0; --i) {
290 : 49237 : *pStr++ = cExpandChar;
291 : : }
292 : :
293 : : // free old string
294 : 16620 : STRING_RELEASE((STRING_TYPE *)mpData);
295 : 16620 : mpData = pNewData;
296 : :
297 : 16620 : return *this;
298 : : }
299 : :
300 : 3208 : STRCODE* STRING::GetBufferAccess()
301 : : {
302 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
303 : :
304 : : // Copy data if necessary
305 [ + + ]: 3208 : if ( mpData->mnLen )
306 : 3188 : ImplCopyData();
307 : :
308 : : // return pointer to string data
309 : 3208 : return mpData->maStr;
310 : : }
311 : :
312 : 935 : void STRING::ReleaseBufferAccess( xub_StrLen nLen )
313 : : {
314 : : // String not consinstent, thus no functionality test
315 : : DBG_CHKTHIS( STRING, NULL );
316 : : DBG_ASSERT( mpData->mnRefCount == 1, "String::ReleaseCharStr() called for String with RefCount" );
317 : :
318 [ + - ]: 935 : if ( nLen > mpData->mnLen )
319 : 935 : nLen = ImplStringLen( mpData->maStr );
320 : : OSL_ASSERT(nLen <= mpData->mnLen);
321 [ - + ]: 935 : if ( !nLen )
322 : : {
323 : 0 : STRING_NEW((STRING_TYPE **)&mpData);
324 : : }
325 : : // shorten buffer is difference > 8 chars
326 [ - + ]: 935 : else if ( mpData->mnLen - nLen > 8 )
327 : : {
328 : 0 : STRINGDATA* pNewData = ImplAllocData( nLen );
329 : 0 : memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
330 : 0 : STRING_RELEASE((STRING_TYPE *)mpData);
331 : 0 : mpData = pNewData;
332 : : }
333 : : else
334 : 935 : mpData->mnLen = nLen;
335 : 935 : }
336 : :
337 : 0 : STRCODE* STRING::AllocBuffer( xub_StrLen nLen )
338 : : {
339 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
340 : :
341 : 0 : STRING_RELEASE((STRING_TYPE *)mpData);
342 [ # # ]: 0 : if ( nLen )
343 : 0 : mpData = ImplAllocData( nLen );
344 : : else
345 : : {
346 : 0 : mpData = NULL;
347 : 0 : STRING_NEW((STRING_TYPE **)&mpData);
348 : : }
349 : :
350 : 0 : return mpData->maStr;
351 : : }
352 : :
353 : 0 : STRING::STRING( STRCODE c )
354 : : {
355 : : DBG_CTOR( STRING, DBGCHECKSTRING );
356 : : DBG_ASSERT( c, "String::String() - c is 0" );
357 : :
358 : : // Initalize maintenance data
359 : 0 : mpData = ImplAllocData( 1 );
360 : 0 : mpData->maStr[0] = c;
361 : 0 : }
362 : :
363 : 53638 : STRING& STRING::Insert( STRCODE c, xub_StrLen nIndex )
364 : : {
365 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
366 : :
367 : : // Don't insert 0 char or string size is maximum
368 [ + - ][ - + ]: 53638 : if ( !c || (mpData->mnLen == STRING_MAXLEN) )
369 : 0 : return *this;
370 : :
371 : : // Adjust string index
372 [ + + ]: 53638 : if ( nIndex > mpData->mnLen )
373 : 3802 : nIndex = static_cast< xub_StrLen >(mpData->mnLen);
374 : :
375 : : // allocate string of new size
376 : 53638 : STRINGDATA* pNewData = ImplAllocData( mpData->mnLen+1 );
377 : :
378 : : // copy string
379 : 53638 : memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
380 : 53638 : pNewData->maStr[nIndex] = c;
381 : 53638 : memcpy( pNewData->maStr+nIndex+1, mpData->maStr+nIndex,
382 : 107276 : (mpData->mnLen-nIndex)*sizeof( STRCODE ) );
383 : :
384 : : // free old data
385 : 53638 : STRING_RELEASE((STRING_TYPE *)mpData);
386 : 53638 : mpData = pNewData;
387 : :
388 : 53638 : return *this;
389 : : }
390 : :
391 : 14616 : STRING& STRING::ToUpperAscii()
392 : : {
393 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
394 : :
395 : 14616 : sal_Int32 nIndex = 0;
396 : 14616 : sal_Int32 nLen = mpData->mnLen;
397 : 14616 : STRCODE* pStr = mpData->maStr;
398 [ + + ]: 37625 : while ( nIndex < nLen )
399 : : {
400 : : // convert char if between 'a' and 'z'
401 [ + + ][ + - ]: 23009 : if ( (*pStr >= 97) && (*pStr <= 122) )
402 : : {
403 : : // allocate string of new size
404 : 1967 : pStr = ImplCopyStringData( pStr );
405 : 1967 : *pStr -= 32;
406 : : }
407 : :
408 : : ++pStr,
409 : 23009 : ++nIndex;
410 : : }
411 : :
412 : 14616 : return *this;
413 : : }
414 : :
415 : 4460447 : StringCompare STRING::CompareTo( const STRING& rStr, xub_StrLen nLen ) const
416 : : {
417 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
418 : : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
419 : :
420 [ + + ]: 4460447 : if ( mpData == rStr.mpData )
421 : 22297 : return COMPARE_EQUAL;
422 : :
423 : : // determine maximal length
424 [ + + ]: 4438150 : if ( mpData->mnLen < nLen )
425 : 4385047 : nLen = static_cast< xub_StrLen >(mpData->mnLen+1);
426 [ + + ]: 4438150 : if ( rStr.mpData->mnLen < nLen )
427 : 2408123 : nLen = static_cast< xub_StrLen >(rStr.mpData->mnLen+1);
428 : :
429 : 4438150 : sal_Int32 nCompare = ImplStringCompareWithoutZero( mpData->maStr, rStr.mpData->maStr, nLen );
430 : :
431 [ + + ]: 4438150 : if ( nCompare == 0 )
432 : 744451 : return COMPARE_EQUAL;
433 [ + + ]: 3693699 : else if ( nCompare < 0 )
434 : 2210206 : return COMPARE_LESS;
435 : : else
436 : 4460447 : return COMPARE_GREATER;
437 : : }
438 : :
439 : 26215418 : sal_Bool STRING::Equals( const STRING& rStr ) const
440 : : {
441 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
442 : : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
443 : :
444 [ + + ]: 26215418 : if ( mpData == rStr.mpData )
445 : 6915214 : return sal_True;
446 : :
447 [ + + ]: 19300204 : if ( mpData->mnLen != rStr.mpData->mnLen )
448 : 16121410 : return sal_False;
449 : :
450 : 26215418 : return (ImplStringCompareWithoutZero( mpData->maStr, rStr.mpData->maStr, mpData->mnLen ) == 0);
451 : : }
452 : :
453 : 563044 : sal_Bool STRING::EqualsIgnoreCaseAscii( const STRING& rStr ) const
454 : : {
455 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
456 : : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
457 : :
458 [ + + ]: 563044 : if ( mpData == rStr.mpData )
459 : 12732 : return sal_True;
460 : :
461 [ + + ]: 550312 : if ( mpData->mnLen != rStr.mpData->mnLen )
462 : 259832 : return sal_False;
463 : :
464 : : // compare string while ignoring case
465 : 563044 : return (ImplStringICompareWithoutZero( mpData->maStr, rStr.mpData->maStr, mpData->mnLen ) == 0);
466 : : }
467 : :
468 : 23663 : sal_Bool STRING::Equals( const STRING& rStr, xub_StrLen nIndex, xub_StrLen nLen ) const
469 : : {
470 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
471 : : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
472 : :
473 : : // Are there enough codes for comparing?
474 [ - + ]: 23663 : if ( nIndex > mpData->mnLen )
475 : 0 : return (rStr.mpData->mnLen == 0);
476 : 23663 : sal_Int32 nMaxLen = mpData->mnLen-nIndex;
477 [ - + ]: 23663 : if ( nMaxLen < nLen )
478 : : {
479 [ # # ]: 0 : if ( rStr.mpData->mnLen != nMaxLen )
480 : 0 : return sal_False;
481 : 0 : nLen = static_cast< xub_StrLen >(nMaxLen);
482 : : }
483 : :
484 : 23663 : return (ImplStringCompareWithoutZero( mpData->maStr+nIndex, rStr.mpData->maStr, nLen ) == 0);
485 : : }
486 : :
487 : 0 : sal_Bool STRING::Equals( const STRCODE* pCharStr, xub_StrLen nIndex, xub_StrLen nLen ) const
488 : : {
489 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
490 : :
491 : : // Are there enough codes for comparing?
492 [ # # ]: 0 : if ( nIndex > mpData->mnLen )
493 : 0 : return (*pCharStr == 0);
494 : :
495 : 0 : return (ImplStringCompare( mpData->maStr+nIndex, pCharStr, nLen ) == 0);
496 : : }
497 : :
498 : 72204 : xub_StrLen STRING::Match( const STRING& rStr ) const
499 : : {
500 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
501 : : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
502 : :
503 : : // return if string is empty
504 [ + + ]: 72204 : if ( !mpData->mnLen )
505 : 1662 : return STRING_MATCH;
506 : :
507 : : // Search the string for unmatching chars
508 : 70542 : const STRCODE* pStr1 = mpData->maStr;
509 : 70542 : const STRCODE* pStr2 = rStr.mpData->maStr;
510 : 70542 : xub_StrLen i = 0;
511 [ + - ]: 97278 : while ( i < mpData->mnLen )
512 : : {
513 : : // Abort on the first unmatching char
514 [ + + ]: 97278 : if ( *pStr1 != *pStr2 )
515 : 70542 : return i;
516 : : ++pStr1,
517 : : ++pStr2,
518 : 26736 : ++i;
519 : : }
520 : :
521 : 72204 : return STRING_MATCH;
522 : : }
523 : :
524 : 811 : xub_StrLen STRING::SearchBackward( STRCODE c, xub_StrLen nIndex ) const
525 : : {
526 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
527 : :
528 [ + - ]: 811 : if ( nIndex > mpData->mnLen )
529 : 811 : nIndex = (xub_StrLen)mpData->mnLen;
530 : :
531 : 811 : const STRCODE* pStr = mpData->maStr;
532 : 811 : pStr += nIndex;
533 : :
534 [ + + ]: 26923 : while ( nIndex )
535 : : {
536 : 26631 : nIndex--;
537 : 26631 : pStr--;
538 [ + + ]: 26631 : if ( *pStr == c )
539 : 519 : return nIndex;
540 : : }
541 : :
542 : 811 : return STRING_NOTFOUND;
543 : : }
544 : :
545 : 9410 : void STRING::SearchAndReplaceAll( const STRING& rStr, const STRING& rRepStr )
546 : : {
547 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
548 : : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
549 : : DBG_CHKOBJ( &rRepStr, STRING, DBGCHECKSTRING );
550 : :
551 : 9410 : xub_StrLen nSPos = Search( rStr, 0 );
552 [ - + ]: 9410 : while ( nSPos != STRING_NOTFOUND )
553 : : {
554 : 0 : Replace( nSPos, rStr.Len(), rRepStr );
555 : 0 : nSPos = nSPos + rRepStr.Len();
556 : 0 : nSPos = Search( rStr, nSPos );
557 : : }
558 : 9410 : }
559 : :
560 : 16 : void STRING::SetToken( xub_StrLen nToken, STRCODE cTok, const STRING& rStr,
561 : : xub_StrLen nIndex )
562 : : {
563 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
564 : : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
565 : :
566 : 16 : const STRCODE* pStr = mpData->maStr;
567 : 16 : xub_StrLen nLen = (xub_StrLen)mpData->mnLen;
568 : 16 : xub_StrLen nTok = 0;
569 : 16 : xub_StrLen nFirstChar = nIndex;
570 : 16 : xub_StrLen i = nFirstChar;
571 : :
572 : : // Determine token position and length
573 : 16 : pStr += i;
574 [ + + ]: 60 : while ( i < nLen )
575 : : {
576 : : // Increase token count if match
577 [ + + ]: 52 : if ( *pStr == cTok )
578 : : {
579 : 28 : ++nTok;
580 : :
581 [ + + ]: 28 : if ( nTok == nToken )
582 : 12 : nFirstChar = i+1;
583 : : else
584 : : {
585 [ + + ]: 16 : if ( nTok > nToken )
586 : 8 : break;
587 : : }
588 : : }
589 : :
590 : : ++pStr,
591 : 44 : ++i;
592 : : }
593 : :
594 [ + - ]: 16 : if ( nTok >= nToken )
595 : 16 : Replace( nFirstChar, i-nFirstChar, rStr );
596 : 16 : }
597 : :
598 : 67725 : STRING STRING::GetToken( xub_StrLen nToken, STRCODE cTok, xub_StrLen& rIndex ) const
599 : : {
600 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
601 : :
602 : 67725 : const STRCODE* pStr = mpData->maStr;
603 : 67725 : xub_StrLen nLen = (xub_StrLen)mpData->mnLen;
604 : 67725 : xub_StrLen nTok = 0;
605 : 67725 : xub_StrLen nFirstChar = rIndex;
606 : 67725 : xub_StrLen i = nFirstChar;
607 : :
608 : : // Determine token position and length
609 : 67725 : pStr += i;
610 [ + + ]: 1070912 : while ( i < nLen )
611 : : {
612 : : // Increase token count if match
613 [ + + ]: 1037830 : if ( *pStr == cTok )
614 : : {
615 : 80782 : ++nTok;
616 : :
617 [ + + ]: 80782 : if ( nTok == nToken )
618 : 29416 : nFirstChar = i+1;
619 : : else
620 : : {
621 [ + + ]: 51366 : if ( nTok > nToken )
622 : 34643 : break;
623 : : }
624 : : }
625 : :
626 : : ++pStr,
627 : 1003187 : ++i;
628 : : }
629 : :
630 [ + + ]: 67725 : if ( nTok >= nToken )
631 : : {
632 [ + + ]: 61365 : if ( i < nLen )
633 : 34643 : rIndex = i+1;
634 : : else
635 : 26722 : rIndex = STRING_NOTFOUND;
636 : 61365 : return Copy( nFirstChar, i-nFirstChar );
637 : : }
638 : : else
639 : : {
640 : 6360 : rIndex = STRING_NOTFOUND;
641 : 67725 : return STRING();
642 : : }
643 : : }
644 : :
645 : 11798 : STRING& STRING::Append( const STRCODE* pCharStr, xub_StrLen nCharLen )
646 : : {
647 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
648 : : DBG_ASSERT( pCharStr, "String::Append() - pCharStr is NULL" );
649 : :
650 [ - + ]: 11798 : if ( nCharLen == STRING_LEN )
651 : 0 : nCharLen = ImplStringLen( pCharStr );
652 : :
653 : : #ifdef DBG_UTIL
654 : : if ( DbgIsAssert() )
655 : : {
656 : : for ( xub_StrLen i = 0; i < nCharLen; i++ )
657 : : {
658 : : if ( !pCharStr[i] )
659 : : {
660 : : OSL_FAIL( "String::Append() : nLen is wrong" );
661 : : }
662 : : }
663 : : }
664 : : #endif
665 : :
666 : : // Catch overflow
667 : 11798 : sal_Int32 nLen = mpData->mnLen;
668 : 11798 : sal_Int32 nCopyLen = ImplGetCopyLen( nLen, nCharLen );
669 : :
670 [ + + ]: 11798 : if ( nCopyLen )
671 : : {
672 : : // allocate string of new size
673 : 11008 : STRINGDATA* pNewData = ImplAllocData( nLen+nCopyLen );
674 : :
675 : : // copy string
676 : 11008 : memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
677 : 11008 : memcpy( pNewData->maStr+nLen, pCharStr, nCopyLen*sizeof( STRCODE ) );
678 : :
679 : : // free old string
680 : 11008 : STRING_RELEASE((STRING_TYPE *)mpData);
681 : 11008 : mpData = pNewData;
682 : : }
683 : :
684 : 11798 : return *this;
685 : : }
686 : :
687 : 4409848 : STRING& STRING::Append( STRCODE c )
688 : : {
689 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
690 : :
691 : : // don't append null characters and keep string length < maxlen
692 : 4409848 : sal_Int32 nLen = mpData->mnLen;
693 [ + - ][ + - ]: 4409848 : if ( c && (nLen < STRING_MAXLEN) )
694 : : {
695 : : // allocate string of new size
696 : 4409848 : STRINGDATA* pNewData = ImplAllocData( nLen+1 );
697 : :
698 : : // copy string
699 : 4409848 : memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
700 : 4409848 : pNewData->maStr[nLen] = c;
701 : :
702 : : // free old string
703 : 4409848 : STRING_RELEASE((STRING_TYPE *)mpData);
704 : 4409848 : mpData = pNewData;
705 : : }
706 : :
707 : 4409848 : return *this;
708 : : }
709 : :
710 : 13965 : STRING& STRING::Assign( const STRCODE* pCharStr, xub_StrLen nLen )
711 : : {
712 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
713 : : DBG_ASSERT( pCharStr, "String::Assign() - pCharStr is NULL" );
714 : :
715 [ - + ]: 13965 : if ( nLen == STRING_LEN )
716 : 0 : nLen = ImplStringLen( pCharStr );
717 : :
718 : : #ifdef DBG_UTIL
719 : : if ( DbgIsAssert() )
720 : : {
721 : : for ( xub_StrLen i = 0; i < nLen; i++ )
722 : : {
723 : : if ( !pCharStr[i] )
724 : : {
725 : : OSL_FAIL( "String::Assign() : nLen is wrong" );
726 : : }
727 : : }
728 : : }
729 : : #endif
730 : :
731 [ - + ]: 13965 : if ( !nLen )
732 : : {
733 : 0 : STRING_NEW((STRING_TYPE **)&mpData);
734 : : }
735 : : else
736 : : {
737 : : // copy without allocation if string length is identical
738 [ + + ][ + - ]: 13965 : if ( (nLen == mpData->mnLen) && (mpData->mnRefCount == 1) )
739 : 8823 : memcpy( mpData->maStr, pCharStr, nLen*sizeof( STRCODE ) );
740 : : else
741 : : {
742 : : // free old string
743 : 5142 : STRING_RELEASE((STRING_TYPE *)mpData);
744 : :
745 : : // allocate string of new size and copy
746 : 5142 : mpData = ImplAllocData( nLen );
747 : 5142 : memcpy( mpData->maStr, pCharStr, nLen*sizeof( STRCODE ) );
748 : : }
749 : : }
750 : :
751 : 13965 : return *this;
752 : : }
753 : :
754 : 5967 : STRING& STRING::Assign( STRCODE c )
755 : : {
756 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
757 : : DBG_ASSERT( c, "String::Assign() - c is 0" );
758 : :
759 : : // initialize maintenance data
760 : 5967 : STRING_RELEASE((STRING_TYPE *)mpData);
761 : 5967 : mpData = ImplAllocData( 1 );
762 : 5967 : mpData->maStr[0] = c;
763 : 5967 : return *this;
764 : : }
765 : :
766 : 20592 : xub_StrLen STRING::SearchAndReplace( const STRING& rStr, const STRING& rRepStr,
767 : : xub_StrLen nIndex )
768 : : {
769 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
770 : : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
771 : : DBG_CHKOBJ( &rRepStr, STRING, DBGCHECKSTRING );
772 : :
773 : 20592 : xub_StrLen nSPos = Search( rStr, nIndex );
774 [ + + ]: 20592 : if ( nSPos != STRING_NOTFOUND )
775 : 19992 : Replace( nSPos, rStr.Len(), rRepStr );
776 : :
777 : 20592 : return nSPos;
778 : : }
779 : :
780 : 792 : static sal_Int32 ImplStringICompare( const STRCODE* pStr1, const STRCODE* pStr2 )
781 : : {
782 : : sal_Int32 nRet;
783 : : STRCODE c1;
784 : : STRCODE c2;
785 [ + + ]: 504 : do
786 : : {
787 : : // Convert char if between 'A' and 'Z'
788 : 792 : c1 = *pStr1;
789 : 792 : c2 = *pStr2;
790 [ + + ][ + - ]: 792 : if ( (c1 >= 65) && (c1 <= 90) )
791 : 360 : c1 += 32;
792 [ + + ][ + - ]: 792 : if ( (c2 >= 65) && (c2 <= 90) )
793 : 360 : c2 += 32;
794 : 792 : nRet = ((sal_Int32)((STRCODEU)c1))-((sal_Int32)((STRCODEU)c2));
795 [ + + ]: 792 : if ( nRet != 0 )
796 : 288 : break;
797 : :
798 : : ++pStr1,
799 : 504 : ++pStr2;
800 : : }
801 : : while ( c2 );
802 : :
803 : 360 : return nRet;
804 : : }
805 : :
806 : 360 : sal_Bool STRING::EqualsIgnoreCaseAscii( const STRCODE* pCharStr ) const
807 : : {
808 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
809 : :
810 : 360 : return (ImplStringICompare( mpData->maStr, pCharStr ) == 0);
811 : : }
812 : :
813 : 146853 : STRING& STRING::Assign( const STRCODE* pCharStr )
814 : : {
815 : : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
816 : : DBG_ASSERT( pCharStr, "String::Assign() - pCharStr is NULL" );
817 : :
818 : 146853 : xub_StrLen nLen = ImplStringLen( pCharStr );
819 : :
820 [ + + ]: 146853 : if ( !nLen )
821 : : {
822 : 68651 : STRING_NEW((STRING_TYPE **)&mpData);
823 : : }
824 : : else
825 : : {
826 : : // copy without allocation if string length is identical
827 [ + + ][ + + ]: 78202 : if ( (nLen == mpData->mnLen) && (mpData->mnRefCount == 1) )
828 : 84 : memcpy( mpData->maStr, pCharStr, nLen*sizeof( STRCODE ) );
829 : : else
830 : : {
831 : : // free old string
832 : 78118 : STRING_RELEASE((STRING_TYPE *)mpData);
833 : :
834 : : // allocate string of new size and copy
835 : 78118 : mpData = ImplAllocData( nLen );
836 : 78118 : memcpy( mpData->maStr, pCharStr, nLen*sizeof( STRCODE ) );
837 : : }
838 : : }
839 : :
840 : 146853 : return *this;
841 : : }
842 : :
843 : 12288560 : xub_StrLen ImplStringLen( const sal_Char* pStr )
844 : : {
845 : 12288560 : const sal_Char* pTempStr = pStr;
846 [ + + ]: 83923088 : while( *pTempStr )
847 : 71634528 : ++pTempStr;
848 : 12288560 : return (xub_StrLen)(pTempStr-pStr);
849 : : }
850 : :
851 : 170168 : xub_StrLen ImplStringLen( const sal_Unicode* pStr )
852 : : {
853 : 170168 : const sal_Unicode* pTempStr = pStr;
854 [ + + ]: 1636395 : while( *pTempStr )
855 : 1466227 : ++pTempStr;
856 : 170168 : return (xub_StrLen)(pTempStr-pStr);
857 : : }
858 : :
859 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|