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 0 : static sal_Int32 ImplStringCompare( const STRCODE* pStr1, const STRCODE* pStr2,
21 : xub_StrLen nCount )
22 : {
23 0 : sal_Int32 nRet = 0;
24 0 : while ( nCount &&
25 : ((nRet = ((sal_Int32)((STRCODEU)*pStr1))-((sal_Int32)((STRCODEU)*pStr2))) == 0) &&
26 : *pStr2 )
27 : {
28 : ++pStr1,
29 : ++pStr2,
30 0 : --nCount;
31 : }
32 :
33 0 : return nRet;
34 : }
35 :
36 603591 : static sal_Int32 ImplStringCompareWithoutZero( const STRCODE* pStr1, const STRCODE* pStr2,
37 : sal_Int32 nCount )
38 : {
39 603591 : sal_Int32 nRet = 0;
40 5000887 : while ( nCount &&
41 : ((nRet = ((sal_Int32)((STRCODEU)*pStr1))-((sal_Int32)((STRCODEU)*pStr2))) == 0) )
42 : {
43 : ++pStr1,
44 : ++pStr2,
45 3793705 : --nCount;
46 : }
47 :
48 603591 : return nRet;
49 : }
50 :
51 : #ifdef DBG_UTIL
52 : const char* DBGCHECKSTRING( const void* pString )
53 : {
54 : STRING* p = (STRING*)pString;
55 :
56 : if ( p->GetBuffer()[p->Len()] != 0 )
57 : return "String damaged: aStr[nLen] != 0";
58 :
59 : return NULL;
60 : }
61 : #endif
62 :
63 362569 : static STRINGDATA* ImplAllocData( sal_Int32 nLen )
64 : {
65 362569 : STRINGDATA* pData = (STRINGDATA*)rtl_allocateMemory( sizeof(STRINGDATA)+(nLen*sizeof( STRCODE )) );
66 362569 : pData->mnRefCount = 1;
67 362569 : pData->mnLen = nLen;
68 362569 : pData->maStr[nLen] = 0;
69 362569 : return pData;
70 : }
71 :
72 198993 : static STRINGDATA* _ImplCopyData( STRINGDATA* pData )
73 : {
74 198993 : unsigned int nSize = sizeof(STRINGDATA)+(pData->mnLen*sizeof( STRCODE ));
75 198993 : STRINGDATA* pNewData = (STRINGDATA*)rtl_allocateMemory( nSize );
76 198993 : memcpy( pNewData, pData, nSize );
77 198993 : pNewData->mnRefCount = 1;
78 198993 : STRING_RELEASE((STRING_TYPE *)pData);
79 198993 : return pNewData;
80 : }
81 :
82 400492 : inline void STRING::ImplCopyData()
83 : {
84 : DBG_ASSERT( (mpData->mnRefCount != 0), "String::ImplCopyData() - RefCount == 0" );
85 :
86 : // Dereference data if this string is referenced
87 400492 : if ( mpData->mnRefCount != 1 )
88 148910 : mpData = _ImplCopyData( mpData );
89 400492 : }
90 :
91 170488 : inline STRCODE* STRING::ImplCopyStringData( STRCODE* pStr )
92 : {
93 170488 : if ( mpData->mnRefCount != 1 ) {
94 : DBG_ASSERT( (pStr >= mpData->maStr) &&
95 : ((pStr-mpData->maStr) < mpData->mnLen),
96 : "ImplCopyStringData - pStr from other String-Instanz" );
97 50083 : unsigned int nIndex = (unsigned int)(pStr-mpData->maStr);
98 50083 : mpData = _ImplCopyData( mpData );
99 50083 : pStr = mpData->maStr + nIndex;
100 : }
101 170488 : return pStr;
102 : }
103 :
104 115747 : inline sal_Int32 ImplGetCopyLen( sal_Int32 nStrLen, sal_Int32 nCopyLen )
105 : {
106 : OSL_ASSERT(nStrLen <= STRING_MAXLEN && nCopyLen <= STRING_MAXLEN);
107 115747 : if ( nCopyLen > STRING_MAXLEN-nStrLen )
108 0 : nCopyLen = STRING_MAXLEN-nStrLen;
109 115747 : return nCopyLen;
110 : }
111 :
112 1386291 : STRING::STRING()
113 1386291 : : mpData(NULL)
114 : {
115 : DBG_CTOR( STRING, DBGCHECKSTRING );
116 :
117 1386291 : STRING_NEW((STRING_TYPE **)&mpData);
118 1386291 : }
119 :
120 3073128 : STRING::STRING( const STRING& rStr )
121 : {
122 : DBG_CTOR( STRING, DBGCHECKSTRING );
123 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
124 :
125 : // Set pointer to argument string and increase reference counter
126 3073128 : STRING_ACQUIRE((STRING_TYPE *)rStr.mpData);
127 3073128 : mpData = rStr.mpData;
128 3073128 : }
129 :
130 128724 : STRING::STRING( const STRING& rStr, xub_StrLen nPos, xub_StrLen nLen )
131 128724 : : mpData( NULL )
132 : {
133 : DBG_CTOR( STRING, DBGCHECKSTRING );
134 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
135 :
136 128724 : if ( nPos > rStr.mpData->mnLen )
137 4 : nLen = 0;
138 : else
139 : {
140 : // correct length if necessary
141 128720 : sal_Int32 nMaxLen = rStr.mpData->mnLen-nPos;
142 128720 : if ( nLen > nMaxLen )
143 5363 : nLen = static_cast< xub_StrLen >(nMaxLen);
144 : }
145 :
146 128724 : if ( nLen )
147 : {
148 : // Increase reference counter if it suffices
149 122093 : if ( (nPos == 0) && (nLen == rStr.mpData->mnLen) )
150 : {
151 79354 : STRING_ACQUIRE((STRING_TYPE *)rStr.mpData);
152 79354 : mpData = rStr.mpData;
153 : }
154 : else
155 : {
156 : // otherwise, copy string
157 42739 : mpData = ImplAllocData( nLen );
158 42739 : memcpy( mpData->maStr, rStr.mpData->maStr+nPos, nLen*sizeof( STRCODE ) );
159 : }
160 : }
161 : else
162 : {
163 6631 : STRING_NEW((STRING_TYPE **)&mpData);
164 : }
165 128724 : }
166 :
167 6566664 : STRING::~STRING()
168 : {
169 : DBG_DTOR( STRING, DBGCHECKSTRING );
170 :
171 : // free string data
172 6566664 : STRING_RELEASE((STRING_TYPE *)mpData);
173 6566664 : }
174 :
175 1407454 : STRING& STRING::Assign( const STRING& rStr )
176 : {
177 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
178 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
179 :
180 1407454 : STRING_ACQUIRE((STRING_TYPE *)rStr.mpData);
181 1407454 : STRING_RELEASE((STRING_TYPE *)mpData);
182 1407454 : mpData = rStr.mpData;
183 1407454 : return *this;
184 : }
185 :
186 60479 : STRING& STRING::Append( const STRING& rStr )
187 : {
188 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
189 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
190 :
191 : // Assignment is sufficient if string is empty
192 60479 : sal_Int32 nLen = mpData->mnLen;
193 60479 : if ( !nLen )
194 : {
195 20018 : STRING_ACQUIRE((STRING_TYPE *)rStr.mpData);
196 20018 : STRING_RELEASE((STRING_TYPE *)mpData);
197 20018 : mpData = rStr.mpData;
198 : }
199 : else
200 : {
201 : // Detect overflow
202 40461 : sal_Int32 nCopyLen = ImplGetCopyLen( nLen, rStr.mpData->mnLen );
203 :
204 40461 : if ( nCopyLen )
205 : {
206 : // allocate string of new size
207 37811 : STRINGDATA* pNewData = ImplAllocData( nLen+nCopyLen );
208 :
209 : // copy string
210 37811 : memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
211 37811 : memcpy( pNewData->maStr+nLen, rStr.mpData->maStr, nCopyLen*sizeof( STRCODE ) );
212 :
213 : // free old string
214 37811 : STRING_RELEASE((STRING_TYPE *)mpData);
215 37811 : mpData = pNewData;
216 : }
217 : }
218 :
219 60479 : return *this;
220 : }
221 :
222 5749 : STRING& STRING::Append( const STRCODE* pCharStr )
223 : {
224 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
225 : DBG_ASSERT( pCharStr, "String::Append() - pCharStr is NULL" );
226 :
227 : // determine string length
228 5749 : sal_Int32 nLen = mpData->mnLen;
229 5749 : sal_Int32 nCopyLen = ImplStringLen( pCharStr );
230 :
231 : // detect overflow
232 5749 : nCopyLen = ImplGetCopyLen( nLen, nCopyLen );
233 :
234 5749 : if ( nCopyLen )
235 : {
236 : // allocate string of new size
237 5745 : STRINGDATA* pNewData = ImplAllocData( nLen+nCopyLen );
238 :
239 : // copy string
240 5745 : memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
241 5745 : memcpy( pNewData->maStr+nLen, pCharStr, nCopyLen*sizeof( STRCODE ) );
242 :
243 : // free old string
244 5745 : STRING_RELEASE((STRING_TYPE *)mpData);
245 5745 : mpData = pNewData;
246 : }
247 :
248 5749 : return *this;
249 : }
250 :
251 400129 : void STRING::SetChar( xub_StrLen nIndex, STRCODE c )
252 : {
253 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
254 : DBG_ASSERT( nIndex < mpData->mnLen, "String::SetChar() - nIndex > String.Len()" );
255 :
256 : // copy data if necessary
257 400129 : ImplCopyData();
258 400129 : mpData->maStr[nIndex] = c;
259 400129 : }
260 :
261 66175 : STRING& STRING::Insert( const STRING& rStr, xub_StrLen nIndex )
262 : {
263 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
264 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
265 :
266 : // detect overflow
267 66175 : sal_Int32 nCopyLen = ImplGetCopyLen( mpData->mnLen, rStr.mpData->mnLen );
268 :
269 66175 : if ( !nCopyLen )
270 4405 : return *this;
271 :
272 : // adjust index if necessary
273 61770 : if ( nIndex > mpData->mnLen )
274 63 : nIndex = static_cast< xub_StrLen >(mpData->mnLen);
275 :
276 : // allocate string of new size
277 61770 : STRINGDATA* pNewData = ImplAllocData( mpData->mnLen+nCopyLen );
278 :
279 : // copy string
280 61770 : memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
281 61770 : memcpy( pNewData->maStr+nIndex, rStr.mpData->maStr, nCopyLen*sizeof( STRCODE ) );
282 61770 : memcpy( pNewData->maStr+nIndex+nCopyLen, mpData->maStr+nIndex,
283 123540 : (mpData->mnLen-nIndex)*sizeof( STRCODE ) );
284 :
285 : // free old string
286 61770 : STRING_RELEASE((STRING_TYPE *)mpData);
287 61770 : mpData = pNewData;
288 :
289 61770 : return *this;
290 : }
291 :
292 1461 : STRING& STRING::Replace( xub_StrLen nIndex, xub_StrLen nCount, const STRING& rStr )
293 : {
294 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
295 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
296 :
297 : // Append if index > current length
298 1461 : if ( nIndex >= mpData->mnLen )
299 : {
300 0 : Append( rStr );
301 0 : return *this;
302 : }
303 :
304 : // assign if index = 0 and length >= stringlen
305 1461 : if ( (nIndex == 0) && (nCount >= mpData->mnLen) )
306 : {
307 46 : Assign( rStr );
308 46 : return *this;
309 : }
310 :
311 : // Use erase if replacestring is empty
312 1415 : sal_Int32 nStrLen = rStr.mpData->mnLen;
313 1415 : if ( !nStrLen )
314 1069 : return Erase( nIndex, nCount );
315 :
316 : // Adjust nCount if it's larger than the string
317 346 : if ( nCount > mpData->mnLen - nIndex )
318 0 : nCount = static_cast< xub_StrLen >(mpData->mnLen-nIndex);
319 :
320 346 : if ( !nCount )
321 0 : return Insert( rStr, nIndex );
322 :
323 : // Use character-based assignment if length is equal
324 346 : if ( nCount == nStrLen )
325 : {
326 21 : ImplCopyData();
327 21 : memcpy( mpData->maStr+nIndex, rStr.mpData->maStr, nCount*sizeof( STRCODE ) );
328 21 : return *this;
329 : }
330 :
331 : // detect overflow
332 325 : nStrLen = ImplGetCopyLen( mpData->mnLen-nCount, nStrLen );
333 :
334 : // allocate string of new size
335 325 : STRINGDATA* pNewData = ImplAllocData( mpData->mnLen-nCount+nStrLen );
336 :
337 : // copy string
338 325 : memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
339 325 : memcpy( pNewData->maStr+nIndex, rStr.mpData->maStr, nStrLen*sizeof( STRCODE ) );
340 325 : memcpy( pNewData->maStr+nIndex+nStrLen, mpData->maStr+nIndex+nCount,
341 650 : (mpData->mnLen-nIndex-nCount+1)*sizeof( STRCODE ) );
342 :
343 : // free old string
344 325 : STRING_RELEASE((STRING_TYPE *)mpData);
345 325 : mpData = pNewData;
346 :
347 325 : return *this;
348 : }
349 :
350 238593 : STRING& STRING::Erase( xub_StrLen nIndex, xub_StrLen nCount )
351 : {
352 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
353 :
354 : // Return if index outside string or count = 0
355 238593 : if ( (nIndex >= mpData->mnLen) || !nCount )
356 62819 : return *this;
357 :
358 : // Adjust nCount if it's larger than the string
359 175774 : if ( nCount > mpData->mnLen - nIndex )
360 7338 : nCount = static_cast< xub_StrLen >(mpData->mnLen-nIndex);
361 :
362 175774 : if ( mpData->mnLen - nCount )
363 : {
364 : // allocate string of new size
365 171002 : STRINGDATA* pNewData = ImplAllocData( mpData->mnLen-nCount );
366 :
367 : // copy string
368 171002 : memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
369 171002 : memcpy( pNewData->maStr+nIndex, mpData->maStr+nIndex+nCount,
370 342004 : (mpData->mnLen-nIndex-nCount+1)*sizeof( STRCODE ) );
371 :
372 : // free old string
373 171002 : STRING_RELEASE((STRING_TYPE *)mpData);
374 171002 : mpData = pNewData;
375 : }
376 : else
377 : {
378 4772 : STRING_NEW((STRING_TYPE **)&mpData);
379 : }
380 :
381 175774 : return *this;
382 : }
383 :
384 66202 : STRING& STRING::ToLowerAscii()
385 : {
386 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
387 :
388 66202 : sal_Int32 nIndex = 0;
389 66202 : sal_Int32 nLen = mpData->mnLen;
390 66202 : STRCODE* pStr = mpData->maStr;
391 972859 : while ( nIndex < nLen )
392 : {
393 : // Convert if char is between 'A' and 'Z'
394 840455 : if ( (*pStr >= 65) && (*pStr <= 90) )
395 : {
396 : // allocate string of new size
397 170430 : pStr = ImplCopyStringData( pStr );
398 170430 : *pStr += 32;
399 : }
400 :
401 : ++pStr,
402 840455 : ++nIndex;
403 : }
404 :
405 66202 : return *this;
406 : }
407 :
408 404276 : xub_StrLen STRING::Search( STRCODE c, xub_StrLen nIndex ) const
409 : {
410 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
411 :
412 404276 : sal_Int32 nLen = mpData->mnLen;
413 404276 : const STRCODE* pStr = mpData->maStr;
414 404276 : pStr += nIndex;
415 4634275 : while ( nIndex < nLen )
416 : {
417 3828646 : if ( *pStr == c )
418 2923 : return nIndex;
419 : ++pStr,
420 3825723 : ++nIndex;
421 : }
422 :
423 401353 : return STRING_NOTFOUND;
424 : }
425 :
426 5238 : xub_StrLen STRING::Search( const STRING& rStr, xub_StrLen nIndex ) const
427 : {
428 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
429 : DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
430 :
431 5238 : sal_Int32 nLen = mpData->mnLen;
432 5238 : sal_Int32 nStrLen = rStr.mpData->mnLen;
433 :
434 : // rStr was not found if its length is zero
435 : // or index is larger than searched string
436 5238 : if ( !nStrLen || (nIndex >= nLen) )
437 11 : return STRING_NOTFOUND;
438 :
439 5227 : const STRCODE* pStr1 = mpData->maStr;
440 5227 : pStr1 += nIndex;
441 :
442 5227 : if ( nStrLen == 1 )
443 : {
444 568 : STRCODE cSearch = rStr.mpData->maStr[0];
445 2381 : while ( nIndex < nLen )
446 : {
447 1245 : if ( *pStr1 == cSearch )
448 0 : return nIndex;
449 : ++pStr1,
450 1245 : ++nIndex;
451 : }
452 : }
453 : else
454 : {
455 4659 : const STRCODE* pStr2 = rStr.mpData->maStr;
456 :
457 : // search only within string
458 47610 : while ( nLen - nIndex >= nStrLen )
459 : {
460 : // increase match if found
461 41069 : if ( ImplStringCompareWithoutZero( pStr1, pStr2, nStrLen ) == 0 )
462 2777 : return nIndex;
463 : ++pStr1,
464 38292 : ++nIndex;
465 : }
466 : }
467 :
468 2450 : return STRING_NOTFOUND;
469 : }
470 :
471 0 : xub_StrLen STRING::Search( const STRCODE* pCharStr, xub_StrLen nIndex ) const
472 : {
473 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
474 :
475 0 : sal_Int32 nLen = mpData->mnLen;
476 0 : xub_StrLen nStrLen = ImplStringLen( pCharStr );
477 :
478 : // rStr was not found if its length is zero
479 : // or index is larger than searched string
480 0 : if ( !nStrLen || (nIndex >= nLen) )
481 0 : return STRING_NOTFOUND;
482 :
483 0 : const STRCODE* pStr = mpData->maStr;
484 0 : pStr += nIndex;
485 :
486 0 : if ( nStrLen == 1 )
487 : {
488 0 : STRCODE cSearch = *pCharStr;
489 0 : while ( nIndex < nLen )
490 : {
491 0 : if ( *pStr == cSearch )
492 0 : return nIndex;
493 : ++pStr,
494 0 : ++nIndex;
495 : }
496 : }
497 : else
498 : {
499 : // search only within string
500 0 : while ( nLen - nIndex >= nStrLen )
501 : {
502 : // increase match if found
503 0 : if ( ImplStringCompareWithoutZero( pStr, pCharStr, nStrLen ) == 0 )
504 0 : return nIndex;
505 : ++pStr,
506 0 : ++nIndex;
507 : }
508 : }
509 :
510 0 : return STRING_NOTFOUND;
511 : }
512 :
513 227 : void STRING::SearchAndReplaceAll( STRCODE c, STRCODE cRep )
514 : {
515 : DBG_CHKTHIS( STRING, DBGCHECKSTRING );
516 :
517 227 : sal_Int32 nLen = mpData->mnLen;
518 227 : const STRCODE* pStr = mpData->maStr;
519 227 : sal_Int32 nIndex = 0;
520 3999 : while ( nIndex < nLen )
521 : {
522 3545 : if ( *pStr == c )
523 : {
524 3 : ImplCopyData();
525 3 : mpData->maStr[nIndex] = cRep;
526 : }
527 : ++pStr,
528 3545 : ++nIndex;
529 : }
530 227 : }
531 :
532 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|