xref: /trunk/main/tools/source/string/strimp.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // no include "precompiled_tools.hxx" because this is included in other cxx files.
29 
30 // =======================================================================
31 
32 static sal_Int32 ImplStringCompare( const STRCODE* pStr1, const STRCODE* pStr2 )
33 {
34     sal_Int32 nRet;
35     while ( ((nRet = ((sal_Int32)((STRCODEU)*pStr1))-((sal_Int32)((STRCODEU)*pStr2))) == 0) &&
36             *pStr2 )
37     {
38         ++pStr1,
39         ++pStr2;
40     }
41 
42     return nRet;
43 }
44 
45 // -----------------------------------------------------------------------
46 
47 static sal_Int32 ImplStringCompare( const STRCODE* pStr1, const STRCODE* pStr2,
48                                     xub_StrLen nCount )
49 {
50     sal_Int32 nRet = 0;
51     while ( nCount &&
52             ((nRet = ((sal_Int32)((STRCODEU)*pStr1))-((sal_Int32)((STRCODEU)*pStr2))) == 0) &&
53             *pStr2 )
54     {
55         ++pStr1,
56         ++pStr2,
57         --nCount;
58     }
59 
60     return nRet;
61 }
62 
63 // -----------------------------------------------------------------------
64 
65 static sal_Int32 ImplStringCompareWithoutZero( const STRCODE* pStr1, const STRCODE* pStr2,
66                                                sal_Int32 nCount )
67 {
68     sal_Int32 nRet = 0;
69     while ( nCount &&
70             ((nRet = ((sal_Int32)((STRCODEU)*pStr1))-((sal_Int32)((STRCODEU)*pStr2))) == 0) )
71     {
72         ++pStr1,
73         ++pStr2,
74         --nCount;
75     }
76 
77     return nRet;
78 }
79 
80 // -----------------------------------------------------------------------
81 
82 static sal_Int32 ImplStringICompare( const STRCODE* pStr1, const STRCODE* pStr2 )
83 {
84     sal_Int32   nRet;
85     STRCODE     c1;
86     STRCODE     c2;
87     do
88     {
89         // Ist das Zeichen zwischen 'A' und 'Z' dann umwandeln
90         c1 = *pStr1;
91         c2 = *pStr2;
92         if ( (c1 >= 65) && (c1 <= 90) )
93             c1 += 32;
94         if ( (c2 >= 65) && (c2 <= 90) )
95             c2 += 32;
96         nRet = ((sal_Int32)((STRCODEU)c1))-((sal_Int32)((STRCODEU)c2));
97         if ( nRet != 0 )
98             break;
99 
100         ++pStr1,
101         ++pStr2;
102     }
103     while ( c2 );
104 
105     return nRet;
106 }
107 
108 // -----------------------------------------------------------------------
109 
110 static sal_Int32 ImplStringICompare( const STRCODE* pStr1, const STRCODE* pStr2,
111                                      xub_StrLen nCount )
112 {
113     sal_Int32   nRet = 0;
114     STRCODE     c1;
115     STRCODE     c2;
116     do
117     {
118         if ( !nCount )
119             break;
120 
121         // Ist das Zeichen zwischen 'A' und 'Z' dann umwandeln
122         c1 = *pStr1;
123         c2 = *pStr2;
124         if ( (c1 >= 65) && (c1 <= 90) )
125             c1 += 32;
126         if ( (c2 >= 65) && (c2 <= 90) )
127             c2 += 32;
128         nRet = ((sal_Int32)((STRCODEU)c1))-((sal_Int32)((STRCODEU)c2));
129         if ( nRet != 0 )
130             break;
131 
132         ++pStr1,
133         ++pStr2,
134         --nCount;
135     }
136     while ( c2 );
137 
138     return nRet;
139 }
140 
141 // -----------------------------------------------------------------------
142 
143 static sal_Int32 ImplStringICompareWithoutZero( const STRCODE* pStr1, const STRCODE* pStr2,
144                                                 sal_Int32 nCount )
145 {
146     sal_Int32   nRet = 0;
147     STRCODE     c1;
148     STRCODE     c2;
149     do
150     {
151         if ( !nCount )
152             break;
153 
154         // Ist das Zeichen zwischen 'A' und 'Z' dann umwandeln
155         c1 = *pStr1;
156         c2 = *pStr2;
157         if ( (c1 >= 65) && (c1 <= 90) )
158             c1 += 32;
159         if ( (c2 >= 65) && (c2 <= 90) )
160             c2 += 32;
161         nRet = ((sal_Int32)((STRCODEU)c1))-((sal_Int32)((STRCODEU)c2));
162 
163         ++pStr1,
164         ++pStr2,
165         --nCount;
166     }
167     while ( nRet == 0 );
168 
169     return nRet;
170 }
171 
172 // =======================================================================
173 
174 #ifdef DBG_UTIL
175 const char* DBGCHECKSTRING( const void* pString )
176 {
177     STRING* p = (STRING*)pString;
178 
179     if ( p->GetBuffer()[p->Len()] != 0 )
180         return "String damaged: aStr[nLen] != 0";
181 
182     return NULL;
183 }
184 #endif
185 
186 // =======================================================================
187 
188 static STRINGDATA* ImplAllocData( sal_Int32 nLen )
189 {
190     // Dann kopiere die Daten
191     STRINGDATA* pData   = (STRINGDATA*)rtl_allocateMemory( sizeof(STRINGDATA)+(nLen*sizeof( STRCODE )) );
192     pData->mnRefCount   = 1;
193     pData->mnLen        = nLen;
194     pData->maStr[nLen]  = 0;
195     return pData;
196 }
197 
198 // -----------------------------------------------------------------------
199 
200 static STRINGDATA* _ImplCopyData( STRINGDATA* pData )
201 {
202     unsigned int    nSize       = sizeof(STRINGDATA)+(pData->mnLen*sizeof( STRCODE ));
203     STRINGDATA*     pNewData    = (STRINGDATA*)rtl_allocateMemory( nSize );
204     memcpy( pNewData, pData, nSize );
205     pNewData->mnRefCount = 1;
206     STRING_RELEASE((STRING_TYPE *)pData);
207     return pNewData;
208 }
209 
210 // -----------------------------------------------------------------------
211 
212 inline void STRING::ImplCopyData()
213 {
214     DBG_ASSERT( (mpData->mnRefCount != 0), "String::ImplCopyData() - RefCount == 0" );
215 
216     // ist es ein referenzierter String, dann die Daten abkoppeln
217     if ( mpData->mnRefCount != 1 )
218         mpData = _ImplCopyData( mpData );
219 }
220 
221 // -----------------------------------------------------------------------
222 
223 inline STRCODE* STRING::ImplCopyStringData( STRCODE* pStr )
224 {
225     // Ist der Referenzzaehler groesser 0
226     if ( mpData->mnRefCount != 1 ) {
227         DBG_ASSERT( (pStr >= mpData->maStr) &&
228                     ((pStr-mpData->maStr) < mpData->mnLen),
229                     "ImplCopyStringData - pStr from other String-Instanz" );
230         unsigned int nIndex = (unsigned int)(pStr-mpData->maStr);
231         mpData = _ImplCopyData( mpData );
232         pStr = mpData->maStr + nIndex;
233     }
234     return pStr;
235 }
236 
237 // -----------------------------------------------------------------------
238 
239 inline sal_Int32 ImplGetCopyLen( sal_Int32 nStrLen, sal_Int32 nCopyLen )
240 {
241     OSL_ASSERT(nStrLen <= STRING_MAXLEN && nCopyLen <= STRING_MAXLEN);
242     if ( nCopyLen > STRING_MAXLEN-nStrLen )
243         nCopyLen = STRING_MAXLEN-nStrLen;
244     return nCopyLen;
245 }
246 
247 // =======================================================================
248 
249 STRING::STRING()
250     : mpData(NULL)
251 {
252     DBG_CTOR( STRING, DBGCHECKSTRING );
253 
254     STRING_NEW((STRING_TYPE **)&mpData);
255 }
256 
257 // -----------------------------------------------------------------------
258 
259 STRING::STRING( const STRING& rStr )
260 {
261     DBG_CTOR( STRING, DBGCHECKSTRING );
262     DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
263 
264     // Pointer auf die Daten des uebergebenen Strings setzen und
265     // Referenzzaehler erhoehen
266     STRING_ACQUIRE((STRING_TYPE *)rStr.mpData);
267     mpData = rStr.mpData;
268 }
269 
270 // -----------------------------------------------------------------------
271 
272 STRING::STRING( const STRING& rStr, xub_StrLen nPos, xub_StrLen nLen )
273 : mpData( NULL )
274 {
275     DBG_CTOR( STRING, DBGCHECKSTRING );
276     DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
277 
278     // Stringlaenge ermitteln
279     if ( nPos > rStr.mpData->mnLen )
280         nLen = 0;
281     else
282     {
283         // Laenge korrigieren, wenn noetig
284         sal_Int32 nMaxLen = rStr.mpData->mnLen-nPos;
285         if ( nLen > nMaxLen )
286             nLen = static_cast< xub_StrLen >(nMaxLen);
287     }
288 
289     // Ist es kein leerer String
290     if ( nLen )
291     {
292         // Reicht ein einfaches erhoehen des Referenzcounters
293         if ( (nPos == 0) && (nLen == rStr.mpData->mnLen) )
294         {
295             STRING_ACQUIRE((STRING_TYPE *)rStr.mpData);
296             mpData = rStr.mpData;
297         }
298         else
299         {
300             // Verwaltungsdaten anlegen und String kopieren
301             mpData = ImplAllocData( nLen );
302             memcpy( mpData->maStr, rStr.mpData->maStr+nPos, nLen*sizeof( STRCODE ) );
303         }
304     }
305     else
306     {
307         STRING_NEW((STRING_TYPE **)&mpData);
308     }
309 }
310 
311 // -----------------------------------------------------------------------
312 
313 STRING::STRING( const STRCODE* pCharStr )
314     : mpData(NULL)
315 {
316     DBG_CTOR( STRING, DBGCHECKSTRING );
317 
318     // Stringlaenge ermitteln
319     // Bei diesem Ctor darf NULL uebergeben werden
320     xub_StrLen nLen;
321     if ( pCharStr )
322         nLen = ImplStringLen( pCharStr );
323     else
324         nLen = 0;
325 
326     // Ist es kein leerer String
327     if ( nLen )
328     {
329         // Verwaltungsdaten anlegen und String kopieren
330         mpData = ImplAllocData( nLen );
331         memcpy( mpData->maStr, pCharStr, nLen*sizeof( STRCODE ) );
332     }
333     else
334     {
335         STRING_NEW((STRING_TYPE **)&mpData);
336     }
337 }
338 
339 // -----------------------------------------------------------------------
340 
341 STRING::STRING( const STRCODE* pCharStr, xub_StrLen nLen )
342 : mpData(NULL)
343 {
344     DBG_CTOR( STRING, DBGCHECKSTRING );
345     DBG_ASSERT( pCharStr, "String::String() - pCharStr is NULL" );
346 
347     if ( nLen == STRING_LEN )
348         nLen = ImplStringLen( pCharStr );
349 
350 #ifdef DBG_UTIL
351     if ( DbgIsAssert() )
352     {
353         for ( xub_StrLen i = 0; i < nLen; i++ )
354         {
355             if ( !pCharStr[i] )
356             {
357                 DBG_ERROR( "String::String() : nLen is wrong" );
358             }
359         }
360     }
361 #endif
362 
363     // Ist es kein leerer String
364     if ( nLen )
365     {
366         // Verwaltungsdaten anlegen und String kopieren
367         mpData = ImplAllocData( nLen );
368         memcpy( mpData->maStr, pCharStr, nLen*sizeof( STRCODE ) );
369     }
370     else
371     {
372         STRING_NEW((STRING_TYPE **)&mpData);
373     }
374 }
375 
376 // -----------------------------------------------------------------------
377 
378 STRING::STRING( STRCODE c )
379 {
380     DBG_CTOR( STRING, DBGCHECKSTRING );
381     DBG_ASSERT( c, "String::String() - c is 0" );
382 
383     // Verwaltungsdaten anlegen und initialisieren
384     mpData = ImplAllocData( 1 );
385     mpData->maStr[0] = c;
386 }
387 
388 // -----------------------------------------------------------------------
389 
390 STRING::~STRING()
391 {
392     DBG_DTOR( STRING, DBGCHECKSTRING );
393 
394     // Daten loeschen
395     STRING_RELEASE((STRING_TYPE *)mpData);
396 }
397 
398 // -----------------------------------------------------------------------
399 
400 STRING& STRING::Assign( const STRING& rStr )
401 {
402     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
403     DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
404 
405     STRING_ACQUIRE((STRING_TYPE *)rStr.mpData);
406     STRING_RELEASE((STRING_TYPE *)mpData);
407     mpData = rStr.mpData;
408     return *this;
409 }
410 
411 // -----------------------------------------------------------------------
412 
413 STRING& STRING::Assign( const STRCODE* pCharStr )
414 {
415     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
416     DBG_ASSERT( pCharStr, "String::Assign() - pCharStr is NULL" );
417 
418     // Stringlaenge ermitteln
419     xub_StrLen nLen = ImplStringLen( pCharStr );
420 
421     if ( !nLen )
422     {
423         STRING_NEW((STRING_TYPE **)&mpData);
424     }
425     else
426     {
427         // Wenn String genauso lang ist, wie der String, dann direkt kopieren
428         if ( (nLen == mpData->mnLen) && (mpData->mnRefCount == 1) )
429             memcpy( mpData->maStr, pCharStr, nLen*sizeof( STRCODE ) );
430         else
431         {
432             // Alte Daten loeschen
433             STRING_RELEASE((STRING_TYPE *)mpData);
434 
435             // Daten initialisieren und String kopieren
436             mpData = ImplAllocData( nLen );
437             memcpy( mpData->maStr, pCharStr, nLen*sizeof( STRCODE ) );
438         }
439     }
440 
441     return *this;
442 }
443 
444 // -----------------------------------------------------------------------
445 
446 STRING& STRING::Assign( const STRCODE* pCharStr, xub_StrLen nLen )
447 {
448     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
449     DBG_ASSERT( pCharStr, "String::Assign() - pCharStr is NULL" );
450 
451     if ( nLen == STRING_LEN )
452         nLen = ImplStringLen( pCharStr );
453 
454 #ifdef DBG_UTIL
455     if ( DbgIsAssert() )
456     {
457         for ( xub_StrLen i = 0; i < nLen; i++ )
458         {
459             if ( !pCharStr[i] )
460             {
461                 DBG_ERROR( "String::Assign() : nLen is wrong" );
462             }
463         }
464     }
465 #endif
466 
467     if ( !nLen )
468     {
469         STRING_NEW((STRING_TYPE **)&mpData);
470     }
471     else
472     {
473         // Wenn String genauso lang ist, wie der String, dann direkt kopieren
474         if ( (nLen == mpData->mnLen) && (mpData->mnRefCount == 1) )
475             memcpy( mpData->maStr, pCharStr, nLen*sizeof( STRCODE ) );
476         else
477         {
478             // Alte Daten loeschen
479             STRING_RELEASE((STRING_TYPE *)mpData);
480 
481             // Daten initialisieren und String kopieren
482             mpData = ImplAllocData( nLen );
483             memcpy( mpData->maStr, pCharStr, nLen*sizeof( STRCODE ) );
484         }
485     }
486 
487     return *this;
488 }
489 
490 // -----------------------------------------------------------------------
491 
492 STRING& STRING::Assign( STRCODE c )
493 {
494     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
495     DBG_ASSERT( c, "String::Assign() - c is 0" );
496 
497     // Verwaltungsdaten anlegen und initialisieren
498     STRING_RELEASE((STRING_TYPE *)mpData);
499     mpData = ImplAllocData( 1 );
500     mpData->maStr[0] = c;
501     return *this;
502 }
503 
504 // -----------------------------------------------------------------------
505 
506 STRING& STRING::Append( const STRING& rStr )
507 {
508     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
509     DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
510 
511     // Wenn String leer, dann reicht eine Zuweisung
512     sal_Int32 nLen = mpData->mnLen;
513     if ( !nLen )
514     {
515         STRING_ACQUIRE((STRING_TYPE *)rStr.mpData);
516         STRING_RELEASE((STRING_TYPE *)mpData);
517         mpData = rStr.mpData;
518     }
519     else
520     {
521         // Ueberlauf abfangen
522         sal_Int32 nCopyLen = ImplGetCopyLen( nLen, rStr.mpData->mnLen );
523 
524         // Ist der uebergebene String kein Leerstring
525         if ( nCopyLen )
526         {
527             // Neue Datenstruktur und neuen String erzeugen
528             STRINGDATA* pNewData = ImplAllocData( nLen+nCopyLen );
529 
530             // String kopieren
531             memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
532             memcpy( pNewData->maStr+nLen, rStr.mpData->maStr, nCopyLen*sizeof( STRCODE ) );
533 
534             // Alte Daten loeschen und Neue zuweisen
535             STRING_RELEASE((STRING_TYPE *)mpData);
536             mpData = pNewData;
537         }
538     }
539 
540     return *this;
541 }
542 
543 // -----------------------------------------------------------------------
544 
545 STRING& STRING::Append( const STRCODE* pCharStr )
546 {
547     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
548     DBG_ASSERT( pCharStr, "String::Append() - pCharStr is NULL" );
549 
550     // Stringlaenge ermitteln
551     sal_Int32 nLen = mpData->mnLen;
552     sal_Int32 nCopyLen = ImplStringLen( pCharStr );
553 
554     // Ueberlauf abfangen
555     nCopyLen = ImplGetCopyLen( nLen, nCopyLen );
556 
557     // Ist es kein leerer String
558     if ( nCopyLen )
559     {
560         // Neue Datenstruktur und neuen String erzeugen
561         STRINGDATA* pNewData = ImplAllocData( nLen+nCopyLen );
562 
563         // String kopieren
564         memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
565         memcpy( pNewData->maStr+nLen, pCharStr, nCopyLen*sizeof( STRCODE ) );
566 
567         // Alte Daten loeschen und Neue zuweisen
568         STRING_RELEASE((STRING_TYPE *)mpData);
569         mpData = pNewData;
570     }
571 
572     return *this;
573 }
574 
575 // -----------------------------------------------------------------------
576 
577 STRING& STRING::Append( const STRCODE* pCharStr, xub_StrLen nCharLen )
578 {
579     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
580     DBG_ASSERT( pCharStr, "String::Append() - pCharStr is NULL" );
581 
582     if ( nCharLen == STRING_LEN )
583         nCharLen = ImplStringLen( pCharStr );
584 
585 #ifdef DBG_UTIL
586     if ( DbgIsAssert() )
587     {
588         for ( xub_StrLen i = 0; i < nCharLen; i++ )
589         {
590             if ( !pCharStr[i] )
591             {
592                 DBG_ERROR( "String::Append() : nLen is wrong" );
593             }
594         }
595     }
596 #endif
597 
598     // Ueberlauf abfangen
599     sal_Int32 nLen = mpData->mnLen;
600     sal_Int32 nCopyLen = ImplGetCopyLen( nLen, nCharLen );
601 
602     // Ist es kein leerer String
603     if ( nCopyLen )
604     {
605         // Neue Datenstruktur und neuen String erzeugen
606         STRINGDATA* pNewData = ImplAllocData( nLen+nCopyLen );
607 
608         // String kopieren
609         memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
610         memcpy( pNewData->maStr+nLen, pCharStr, nCopyLen*sizeof( STRCODE ) );
611 
612         // Alte Daten loeschen und Neue zuweisen
613         STRING_RELEASE((STRING_TYPE *)mpData);
614         mpData = pNewData;
615     }
616 
617     return *this;
618 }
619 
620 // -----------------------------------------------------------------------
621 
622 STRING& STRING::Append( STRCODE c )
623 {
624     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
625 
626     // kein 0-Character und maximale Stringlaenge nicht ueberschreiten
627     sal_Int32 nLen = mpData->mnLen;
628     if ( c && (nLen < STRING_MAXLEN) )
629     {
630         // Neue Datenstruktur und neuen String erzeugen
631         STRINGDATA* pNewData = ImplAllocData( nLen+1 );
632 
633         // String kopieren
634         memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
635         pNewData->maStr[nLen] = c;
636 
637         // Alte Daten loeschen und Neue zuweisen
638         STRING_RELEASE((STRING_TYPE *)mpData);
639         mpData = pNewData;
640     }
641 
642     return *this;
643 }
644 
645 // -----------------------------------------------------------------------
646 
647 void STRING::SetChar( xub_StrLen nIndex, STRCODE c )
648 {
649     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
650     DBG_ASSERT( nIndex < mpData->mnLen, "String::SetChar() - nIndex > String.Len()" );
651 
652     // Daten kopieren, wenn noetig und Character zuweisen
653     ImplCopyData();
654     mpData->maStr[nIndex] = c;
655 }
656 
657 // -----------------------------------------------------------------------
658 
659 STRING& STRING::Insert( const STRING& rStr, xub_StrLen nIndex )
660 {
661     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
662     DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
663 
664     // Ueberlauf abfangen
665     sal_Int32 nCopyLen = ImplGetCopyLen( mpData->mnLen, rStr.mpData->mnLen );
666 
667     // Ist der einzufuegende String ein Leerstring
668     if ( !nCopyLen )
669         return *this;
670 
671     // Index groesser als Laenge
672     if ( nIndex > mpData->mnLen )
673         nIndex = static_cast< xub_StrLen >(mpData->mnLen);
674 
675     // Neue Laenge ermitteln und neuen String anlegen
676     STRINGDATA* pNewData = ImplAllocData( mpData->mnLen+nCopyLen );
677 
678     // String kopieren
679     memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
680     memcpy( pNewData->maStr+nIndex, rStr.mpData->maStr, nCopyLen*sizeof( STRCODE ) );
681     memcpy( pNewData->maStr+nIndex+nCopyLen, mpData->maStr+nIndex,
682             (mpData->mnLen-nIndex)*sizeof( STRCODE ) );
683 
684     // Alte Daten loeschen und Neue zuweisen
685     STRING_RELEASE((STRING_TYPE *)mpData);
686     mpData = pNewData;
687 
688     return *this;
689 }
690 
691 // -----------------------------------------------------------------------
692 
693 STRING& STRING::Insert( const STRING& rStr, xub_StrLen nPos, xub_StrLen nLen,
694                         xub_StrLen nIndex )
695 {
696     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
697     DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
698 
699     // Stringlaenge ermitteln
700     if ( nPos > rStr.mpData->mnLen )
701         nLen = 0;
702     else
703     {
704         // Laenge korrigieren, wenn noetig
705         sal_Int32 nMaxLen = rStr.mpData->mnLen-nPos;
706         if ( nLen > nMaxLen )
707             nLen = static_cast< xub_StrLen >(nMaxLen);
708     }
709 
710     // Ueberlauf abfangen
711     sal_Int32 nCopyLen = ImplGetCopyLen( mpData->mnLen, nLen );
712 
713     // Ist der einzufuegende String ein Leerstring
714     if ( !nCopyLen )
715         return *this;
716 
717     // Index groesser als Laenge
718     if ( nIndex > mpData->mnLen )
719         nIndex = static_cast< xub_StrLen >(mpData->mnLen);
720 
721     // Neue Laenge ermitteln und neuen String anlegen
722     STRINGDATA* pNewData = ImplAllocData( mpData->mnLen+nCopyLen );
723 
724     // String kopieren
725     memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
726     memcpy( pNewData->maStr+nIndex, rStr.mpData->maStr+nPos, nCopyLen*sizeof( STRCODE ) );
727     memcpy( pNewData->maStr+nIndex+nCopyLen, mpData->maStr+nIndex,
728             (mpData->mnLen-nIndex)*sizeof( STRCODE ) );
729 
730     // Alte Daten loeschen und Neue zuweisen
731     STRING_RELEASE((STRING_TYPE *)mpData);
732     mpData = pNewData;
733 
734     return *this;
735 }
736 
737 // -----------------------------------------------------------------------
738 
739 STRING& STRING::Insert( const STRCODE* pCharStr, xub_StrLen nIndex )
740 {
741     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
742     DBG_ASSERT( pCharStr, "String::Insert() - pCharStr is NULL" );
743 
744     // Stringlaenge ermitteln
745     sal_Int32 nCopyLen = ImplStringLen( pCharStr );
746 
747     // Ueberlauf abfangen
748     nCopyLen = ImplGetCopyLen( mpData->mnLen, nCopyLen );
749 
750     // Ist der einzufuegende String ein Leerstring
751     if ( !nCopyLen )
752         return *this;
753 
754     // Index groesser als Laenge
755     if ( nIndex > mpData->mnLen )
756         nIndex = static_cast< xub_StrLen >(mpData->mnLen);
757 
758     // Neue Laenge ermitteln und neuen String anlegen
759     STRINGDATA* pNewData = ImplAllocData( mpData->mnLen+nCopyLen );
760 
761     // String kopieren
762     memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
763     memcpy( pNewData->maStr+nIndex, pCharStr, nCopyLen*sizeof( STRCODE ) );
764     memcpy( pNewData->maStr+nIndex+nCopyLen, mpData->maStr+nIndex,
765             (mpData->mnLen-nIndex)*sizeof( STRCODE ) );
766 
767     // Alte Daten loeschen und Neue zuweisen
768     STRING_RELEASE((STRING_TYPE *)mpData);
769     mpData = pNewData;
770 
771     return *this;
772 }
773 
774 // -----------------------------------------------------------------------
775 
776 STRING& STRING::Insert( STRCODE c, xub_StrLen nIndex )
777 {
778     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
779 
780     // Ist es kein 0-Character
781     if ( !c || (mpData->mnLen == STRING_MAXLEN) )
782         return *this;
783 
784     // Index groesser als Laenge
785     if ( nIndex > mpData->mnLen )
786         nIndex = static_cast< xub_StrLen >(mpData->mnLen);
787 
788     // Neue Laenge ermitteln und neuen String anlegen
789     STRINGDATA* pNewData = ImplAllocData( mpData->mnLen+1 );
790 
791     // String kopieren
792     memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
793     pNewData->maStr[nIndex] = c;
794     memcpy( pNewData->maStr+nIndex+1, mpData->maStr+nIndex,
795             (mpData->mnLen-nIndex)*sizeof( STRCODE ) );
796 
797     // Alte Daten loeschen und Neue zuweisen
798     STRING_RELEASE((STRING_TYPE *)mpData);
799     mpData = pNewData;
800 
801     return *this;
802 }
803 
804 // -----------------------------------------------------------------------
805 
806 STRING& STRING::Replace( xub_StrLen nIndex, xub_StrLen nCount, const STRING& rStr )
807 {
808     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
809     DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
810 
811     // Wenn Index groessergleich Laenge ist, dann ist es ein Append
812     if ( nIndex >= mpData->mnLen )
813     {
814         Append( rStr );
815         return *this;
816     }
817 
818     // Ist es eine Zuweisung
819     if ( (nIndex == 0) && (nCount >= mpData->mnLen) )
820     {
821         Assign( rStr );
822         return *this;
823     }
824 
825     // Reicht ein Erase
826     sal_Int32 nStrLen = rStr.mpData->mnLen;
827     if ( !nStrLen )
828         return Erase( nIndex, nCount );
829 
830     // nCount darf nicht ueber das Stringende hinnausgehen
831     if ( nCount > mpData->mnLen - nIndex )
832         nCount = static_cast< xub_StrLen >(mpData->mnLen-nIndex);
833 
834     // Reicht ein Insert
835     if ( !nCount )
836         return Insert( rStr, nIndex );
837 
838     // Reicht eine zeichenweise Zuweisung
839     if ( nCount == nStrLen )
840     {
841         ImplCopyData();
842         memcpy( mpData->maStr+nIndex, rStr.mpData->maStr, nCount*sizeof( STRCODE ) );
843         return *this;
844     }
845 
846     // Ueberlauf abfangen
847     nStrLen = ImplGetCopyLen( mpData->mnLen-nCount, nStrLen );
848 
849     // Neue Daten anlegen
850     STRINGDATA* pNewData = ImplAllocData( mpData->mnLen-nCount+nStrLen );
851 
852     // String kopieren
853     memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
854     memcpy( pNewData->maStr+nIndex, rStr.mpData->maStr, nStrLen*sizeof( STRCODE ) );
855     memcpy( pNewData->maStr+nIndex+nStrLen, mpData->maStr+nIndex+nCount,
856             (mpData->mnLen-nIndex-nCount+1)*sizeof( STRCODE ) );
857 
858     // Alte Daten loeschen und Neue zuweisen
859     STRING_RELEASE((STRING_TYPE *)mpData);
860     mpData = pNewData;
861 
862     return *this;
863 }
864 
865 // -----------------------------------------------------------------------
866 
867 STRING& STRING::Erase( xub_StrLen nIndex, xub_StrLen nCount )
868 {
869     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
870 
871     // Ist der Index ausserhalb des Strings oder ist nCount == 0
872     if ( (nIndex >= mpData->mnLen) || !nCount )
873         return *this;
874 
875     // nCount darf nicht ueber das Stringende hinnausgehen
876     if ( nCount > mpData->mnLen - nIndex )
877         nCount = static_cast< xub_StrLen >(mpData->mnLen-nIndex);
878 
879     // Ist das Ergebnis kein Leerstring
880     if ( mpData->mnLen - nCount )
881     {
882         // Neue Daten anlegen
883         STRINGDATA* pNewData = ImplAllocData( mpData->mnLen-nCount );
884 
885         // String kopieren
886         memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
887         memcpy( pNewData->maStr+nIndex, mpData->maStr+nIndex+nCount,
888                 (mpData->mnLen-nIndex-nCount+1)*sizeof( STRCODE ) );
889 
890         // Alte Daten loeschen und Neue zuweisen
891         STRING_RELEASE((STRING_TYPE *)mpData);
892         mpData = pNewData;
893     }
894     else
895     {
896         STRING_NEW((STRING_TYPE **)&mpData);
897     }
898 
899     return *this;
900 }
901 
902 // -----------------------------------------------------------------------
903 
904 STRING& STRING::Fill( xub_StrLen nCount, STRCODE cFillChar )
905 {
906     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
907 
908     if ( !nCount )
909         return *this;
910 
911     // Ist nCount groesser wie der jetzige String, dann verlaengern
912     if ( nCount > mpData->mnLen )
913     {
914         // dann neuen String mit der neuen Laenge anlegen
915         STRINGDATA* pNewData = ImplAllocData( nCount );
916         STRING_RELEASE((STRING_TYPE *)mpData);
917         mpData = pNewData;
918     }
919     else
920         ImplCopyData();
921 
922     STRCODE* pStr = mpData->maStr;
923     do
924     {
925         *pStr = cFillChar;
926         ++pStr,
927         --nCount;
928     }
929     while ( nCount );
930 
931     return *this;
932 }
933 
934 // -----------------------------------------------------------------------
935 
936 STRING& STRING::Expand( xub_StrLen nCount, STRCODE cExpandChar )
937 {
938     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
939 
940     // Muss der String erweitert werden
941     sal_Int32 nLen = mpData->mnLen;
942     if ( nCount <= nLen )
943         return *this;
944 
945     // Neuen String anlegen
946     STRINGDATA* pNewData = ImplAllocData( nCount );
947 
948     // Alten String kopieren
949     memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
950 
951     // und initialisieren
952     STRCODE* pStr = pNewData->maStr;
953     pStr += nLen;
954     for (sal_Int32 i = nCount - nLen; i > 0; --i) {
955         *pStr++ = cExpandChar;
956     }
957 
958     // Alte Daten loeschen und Neue zuweisen
959     STRING_RELEASE((STRING_TYPE *)mpData);
960     mpData = pNewData;
961 
962     return *this;
963 }
964 
965 // -----------------------------------------------------------------------
966 
967 STRING& STRING::EraseLeadingChars( STRCODE c )
968 {
969     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
970 
971     if ( mpData->maStr[0] != c )
972         return *this;
973 
974     xub_StrLen nStart = 0;
975     while ( mpData->maStr[nStart] == c )
976         ++nStart;
977 
978     return Erase( 0, nStart );
979 }
980 
981 // -----------------------------------------------------------------------
982 
983 STRING& STRING::EraseTrailingChars( STRCODE c )
984 {
985     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
986 
987     sal_Int32 nEnd = mpData->mnLen;
988     while ( nEnd && (mpData->maStr[nEnd-1] == c) )
989         nEnd--;
990 
991     if ( nEnd != mpData->mnLen )
992         Erase( static_cast< xub_StrLen >(nEnd) );
993 
994     return *this;
995 }
996 
997 // -----------------------------------------------------------------------
998 
999 STRING& STRING::EraseLeadingAndTrailingChars( STRCODE c )
1000 {
1001     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1002 
1003     xub_StrLen nStart = 0;
1004     while ( mpData->maStr[nStart] == c )
1005         ++nStart;
1006     if ( nStart )
1007         Erase( 0, nStart );
1008 
1009     sal_Int32 nEnd = mpData->mnLen;
1010     while ( nEnd && (mpData->maStr[nEnd-1] == c) )
1011         nEnd--;
1012     if ( nEnd != mpData->mnLen )
1013         Erase( static_cast< xub_StrLen >(nEnd) );
1014 
1015     return *this;
1016 }
1017 
1018 // -----------------------------------------------------------------------
1019 
1020 STRING& STRING::EraseAllChars( STRCODE c )
1021 {
1022     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1023 
1024     sal_Int32 nCount = 0;
1025     for (sal_Int32 i = 0; i < mpData->mnLen; ++i) {
1026         if ( mpData->maStr[i] == c )
1027             ++nCount;
1028     }
1029 
1030     if ( nCount )
1031     {
1032         if ( nCount == mpData->mnLen )
1033         {
1034             STRING_NEW((STRING_TYPE **)&mpData);
1035         }
1036         else
1037         {
1038             // Neuen String anlegen
1039             STRINGDATA* pNewData = ImplAllocData( mpData->mnLen-nCount );
1040 
1041             // Alten String kopieren und initialisieren
1042             nCount = 0;
1043             for( xub_StrLen j = 0; j < mpData->mnLen; ++j )
1044             {
1045                 if ( mpData->maStr[j] != c )
1046                 {
1047                     pNewData->maStr[nCount] = mpData->maStr[j];
1048                     ++nCount;
1049                 }
1050             }
1051 
1052             // Alte Daten loeschen und Neue zuweisen
1053             STRING_RELEASE((STRING_TYPE *)mpData);
1054             mpData = pNewData;
1055         }
1056     }
1057 
1058     return *this;
1059 }
1060 
1061 // -----------------------------------------------------------------------
1062 
1063 STRING& STRING::Reverse()
1064 {
1065     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1066 
1067     if ( !mpData->mnLen )
1068         return *this;
1069 
1070     // Daten kopieren, wenn noetig
1071     ImplCopyData();
1072 
1073     // Reverse
1074     sal_Int32 nCount = mpData->mnLen / 2;
1075     for ( sal_Int32 i = 0; i < nCount; ++i )
1076     {
1077         STRCODE cTemp = mpData->maStr[i];
1078         mpData->maStr[i] = mpData->maStr[mpData->mnLen-i-1];
1079         mpData->maStr[mpData->mnLen-i-1] = cTemp;
1080     }
1081 
1082     return *this;
1083 }
1084 
1085 // -----------------------------------------------------------------------
1086 
1087 STRING& STRING::ToLowerAscii()
1088 {
1089     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1090 
1091     sal_Int32 nIndex = 0;
1092     sal_Int32 nLen = mpData->mnLen;
1093     STRCODE*    pStr = mpData->maStr;
1094     while ( nIndex < nLen )
1095     {
1096         // Ist das Zeichen zwischen 'A' und 'Z' dann umwandeln
1097         if ( (*pStr >= 65) && (*pStr <= 90) )
1098         {
1099             // Daten kopieren, wenn noetig
1100             pStr = ImplCopyStringData( pStr );
1101             *pStr += 32;
1102         }
1103 
1104         ++pStr,
1105         ++nIndex;
1106     }
1107 
1108     return *this;
1109 }
1110 
1111 // -----------------------------------------------------------------------
1112 
1113 STRING& STRING::ToUpperAscii()
1114 {
1115     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1116 
1117     sal_Int32 nIndex = 0;
1118     sal_Int32 nLen = mpData->mnLen;
1119     STRCODE*    pStr = mpData->maStr;
1120     while ( nIndex < nLen )
1121     {
1122         // Ist das Zeichen zwischen 'a' und 'z' dann umwandeln
1123         if ( (*pStr >= 97) && (*pStr <= 122) )
1124         {
1125             // Daten kopieren, wenn noetig
1126             pStr = ImplCopyStringData( pStr );
1127             *pStr -= 32;
1128         }
1129 
1130         ++pStr,
1131         ++nIndex;
1132     }
1133 
1134     return *this;
1135 }
1136 
1137 // -----------------------------------------------------------------------
1138 
1139 STRING& STRING::ConvertLineEnd( LineEnd eLineEnd )
1140 {
1141     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1142 
1143     // Zeilenumbrueche ermitteln und neue Laenge berechnen
1144     sal_Bool            bConvert    = sal_False;            // Muss konvertiert werden
1145     const STRCODE*  pStr        = mpData->maStr;    // damit es schneller geht
1146     xub_StrLen      nLineEndLen = (eLineEnd == LINEEND_CRLF) ? 2 : 1;
1147     xub_StrLen      nLen        = 0;                // Ziel-Laenge
1148     xub_StrLen      i           = 0;                // Source-Zaehler
1149 
1150     while ( i < mpData->mnLen )
1151     {
1152         // Bei \r oder \n gibt es neuen Zeilenumbruch
1153         if ( (pStr[i] == _CR) || (pStr[i] == _LF) )
1154         {
1155             nLen = nLen + nLineEndLen;
1156 
1157             // Wenn schon gesetzt, dann brauchen wir keine aufwendige Abfrage
1158             if ( !bConvert )
1159             {
1160                 // Muessen wir Konvertieren
1161                 if ( ((eLineEnd != LINEEND_LF) && (pStr[i] == _LF)) ||
1162                      ((eLineEnd == LINEEND_CRLF) && (pStr[i+1] != _LF)) ||
1163                      ((eLineEnd == LINEEND_LF) &&
1164                       ((pStr[i] == _CR) || (pStr[i+1] == _CR))) ||
1165                      ((eLineEnd == LINEEND_CR) &&
1166                       ((pStr[i] == _LF) || (pStr[i+1] == _LF))) )
1167                     bConvert = sal_True;
1168             }
1169 
1170             // \r\n oder \n\r, dann Zeichen ueberspringen
1171             if ( ((pStr[i+1] == _CR) || (pStr[i+1] == _LF)) &&
1172                  (pStr[i] != pStr[i+1]) )
1173                 ++i;
1174         }
1175         else
1176             ++nLen;
1177         ++i;
1178 
1179         // Wenn String zu lang, dann konvertieren wir nicht
1180         if ( nLen >= STRING_MAXLEN )
1181             return *this;
1182     }
1183 
1184     // Zeilenumbrueche konvertieren
1185     if ( bConvert )
1186     {
1187         // Neuen String anlegen
1188         STRINGDATA* pNewData = ImplAllocData( nLen );
1189         xub_StrLen  j = 0;
1190         i = 0;
1191         while ( i < mpData->mnLen )
1192         {
1193             // Bei \r oder \n gibt es neuen Zeilenumbruch
1194             if ( (pStr[i] == _CR) || (pStr[i] == _LF) )
1195             {
1196                 if ( eLineEnd == LINEEND_CRLF )
1197                 {
1198                     pNewData->maStr[j]   = _CR;
1199                     pNewData->maStr[j+1] = _LF;
1200                     j += 2;
1201                 }
1202                 else
1203                 {
1204                     if ( eLineEnd == LINEEND_CR )
1205                         pNewData->maStr[j] = _CR;
1206                     else
1207                         pNewData->maStr[j] = _LF;
1208                     ++j;
1209                 }
1210 
1211                 if ( ((pStr[i+1] == _CR) || (pStr[i+1] == _LF)) &&
1212                      (pStr[i] != pStr[i+1]) )
1213                     ++i;
1214             }
1215             else
1216             {
1217                 pNewData->maStr[j] = mpData->maStr[i];
1218                 ++j;
1219             }
1220 
1221             ++i;
1222         }
1223 
1224         // Alte Daten loeschen und Neue zuweisen
1225         STRING_RELEASE((STRING_TYPE *)mpData);
1226         mpData = pNewData;
1227     }
1228 
1229     return *this;
1230 }
1231 
1232 // -----------------------------------------------------------------------
1233 
1234 StringCompare STRING::CompareTo( const STRING& rStr, xub_StrLen nLen ) const
1235 {
1236     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1237     DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
1238 
1239     // Auf Gleichheit der Pointer testen
1240     if ( mpData == rStr.mpData )
1241         return COMPARE_EQUAL;
1242 
1243     // Maximale Laenge ermitteln
1244     if ( mpData->mnLen < nLen )
1245         nLen = static_cast< xub_StrLen >(mpData->mnLen+1);
1246     if ( rStr.mpData->mnLen < nLen )
1247         nLen = static_cast< xub_StrLen >(rStr.mpData->mnLen+1);
1248 
1249     // String vergleichen
1250     sal_Int32 nCompare = ImplStringCompareWithoutZero( mpData->maStr, rStr.mpData->maStr, nLen );
1251 
1252     // Rueckgabewert anpassen
1253     if ( nCompare == 0 )
1254         return COMPARE_EQUAL;
1255     else if ( nCompare < 0 )
1256         return COMPARE_LESS;
1257     else
1258         return COMPARE_GREATER;
1259 }
1260 
1261 // -----------------------------------------------------------------------
1262 
1263 StringCompare STRING::CompareTo( const STRCODE* pCharStr, xub_StrLen nLen ) const
1264 {
1265     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1266 
1267     // String vergleichen
1268     sal_Int32 nCompare = ImplStringCompare( mpData->maStr, pCharStr, nLen );
1269 
1270     // Rueckgabewert anpassen
1271     if ( nCompare == 0 )
1272         return COMPARE_EQUAL;
1273     else if ( nCompare < 0 )
1274         return COMPARE_LESS;
1275     else
1276         return COMPARE_GREATER;
1277 }
1278 
1279 // -----------------------------------------------------------------------
1280 
1281 StringCompare STRING::CompareIgnoreCaseToAscii( const STRING& rStr,
1282                                                 xub_StrLen nLen ) const
1283 {
1284     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1285     DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
1286 
1287     // Auf Gleichheit der Pointer testen
1288     if ( mpData == rStr.mpData )
1289         return COMPARE_EQUAL;
1290 
1291     // Maximale Laenge ermitteln
1292     if ( mpData->mnLen < nLen )
1293         nLen = static_cast< xub_StrLen >(mpData->mnLen+1);
1294     if ( rStr.mpData->mnLen < nLen )
1295         nLen = static_cast< xub_StrLen >(rStr.mpData->mnLen+1);
1296 
1297     // String vergleichen
1298     sal_Int32 nCompare = ImplStringICompareWithoutZero( mpData->maStr, rStr.mpData->maStr, nLen );
1299 
1300     // Rueckgabewert anpassen
1301     if ( nCompare == 0 )
1302         return COMPARE_EQUAL;
1303     else if ( nCompare < 0 )
1304         return COMPARE_LESS;
1305     else
1306         return COMPARE_GREATER;
1307 }
1308 
1309 // -----------------------------------------------------------------------
1310 
1311 StringCompare STRING::CompareIgnoreCaseToAscii( const STRCODE* pCharStr,
1312                                                 xub_StrLen nLen ) const
1313 {
1314     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1315 
1316     // String vergleichen
1317     sal_Int32 nCompare = ImplStringICompare( mpData->maStr, pCharStr, nLen );
1318 
1319     // Rueckgabewert anpassen
1320     if ( nCompare == 0 )
1321         return COMPARE_EQUAL;
1322     else if ( nCompare < 0 )
1323         return COMPARE_LESS;
1324     else
1325         return COMPARE_GREATER;
1326 }
1327 
1328 // -----------------------------------------------------------------------
1329 
1330 sal_Bool STRING::Equals( const STRING& rStr ) const
1331 {
1332     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1333     DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
1334 
1335     // Sind die Daten gleich
1336     if ( mpData == rStr.mpData )
1337         return sal_True;
1338 
1339     // Gleiche Laenge
1340     if ( mpData->mnLen != rStr.mpData->mnLen )
1341         return sal_False;
1342 
1343     // String vergleichen
1344     return (ImplStringCompareWithoutZero( mpData->maStr, rStr.mpData->maStr, mpData->mnLen ) == 0);
1345 }
1346 
1347 // -----------------------------------------------------------------------
1348 
1349 sal_Bool STRING::Equals( const STRCODE* pCharStr ) const
1350 {
1351     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1352 
1353     return (ImplStringCompare( mpData->maStr, pCharStr ) == 0);
1354 }
1355 
1356 // -----------------------------------------------------------------------
1357 
1358 sal_Bool STRING::EqualsIgnoreCaseAscii( const STRING& rStr ) const
1359 {
1360     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1361     DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
1362 
1363     // Sind die Daten gleich
1364     if ( mpData == rStr.mpData )
1365         return sal_True;
1366 
1367     // Gleiche Laenge
1368     if ( mpData->mnLen != rStr.mpData->mnLen )
1369         return sal_False;
1370 
1371     // String vergleichen
1372     return (ImplStringICompareWithoutZero( mpData->maStr, rStr.mpData->maStr, mpData->mnLen ) == 0);
1373 }
1374 
1375 // -----------------------------------------------------------------------
1376 
1377 sal_Bool STRING::EqualsIgnoreCaseAscii( const STRCODE* pCharStr ) const
1378 {
1379     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1380 
1381     return (ImplStringICompare( mpData->maStr, pCharStr ) == 0);
1382 }
1383 
1384 // -----------------------------------------------------------------------
1385 
1386 sal_Bool STRING::Equals( const STRING& rStr, xub_StrLen nIndex, xub_StrLen nLen ) const
1387 {
1388     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1389     DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
1390 
1391     // Are there enough codes for comparing?
1392     if ( nIndex > mpData->mnLen )
1393         return (rStr.mpData->mnLen == 0);
1394     sal_Int32 nMaxLen = mpData->mnLen-nIndex;
1395     if ( nMaxLen < nLen )
1396     {
1397         if ( rStr.mpData->mnLen != nMaxLen )
1398             return sal_False;
1399         nLen = static_cast< xub_StrLen >(nMaxLen);
1400     }
1401 
1402     // String vergleichen
1403     return (ImplStringCompareWithoutZero( mpData->maStr+nIndex, rStr.mpData->maStr, nLen ) == 0);
1404 }
1405 
1406 // -----------------------------------------------------------------------
1407 
1408 sal_Bool STRING::Equals( const STRCODE* pCharStr, xub_StrLen nIndex, xub_StrLen nLen ) const
1409 {
1410     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1411 
1412     // Are there enough codes for comparing?
1413     if ( nIndex > mpData->mnLen )
1414         return (*pCharStr == 0);
1415 
1416     return (ImplStringCompare( mpData->maStr+nIndex, pCharStr, nLen ) == 0);
1417 }
1418 
1419 // -----------------------------------------------------------------------
1420 
1421 sal_Bool STRING::EqualsIgnoreCaseAscii( const STRING& rStr, xub_StrLen nIndex, xub_StrLen nLen ) const
1422 {
1423     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1424     DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
1425 
1426     // Are there enough codes for comparing?
1427     if ( nIndex > mpData->mnLen )
1428         return (rStr.mpData->mnLen == 0);
1429     sal_Int32 nMaxLen = mpData->mnLen-nIndex;
1430     if ( nMaxLen < nLen )
1431     {
1432         if ( rStr.mpData->mnLen != nMaxLen )
1433             return sal_False;
1434         nLen = static_cast< xub_StrLen >(nMaxLen);
1435     }
1436 
1437     // String vergleichen
1438     return (ImplStringICompareWithoutZero( mpData->maStr+nIndex, rStr.mpData->maStr, nLen ) == 0);
1439 }
1440 
1441 // -----------------------------------------------------------------------
1442 
1443 sal_Bool STRING::EqualsIgnoreCaseAscii( const STRCODE* pCharStr, xub_StrLen nIndex, xub_StrLen nLen ) const
1444 {
1445     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1446 
1447     // Are there enough codes for comparing?
1448     if ( nIndex > mpData->mnLen )
1449         return (*pCharStr == 0);
1450 
1451     return (ImplStringICompare( mpData->maStr+nIndex, pCharStr, nLen ) == 0);
1452 }
1453 
1454 // -----------------------------------------------------------------------
1455 
1456 xub_StrLen STRING::Match( const STRING& rStr ) const
1457 {
1458     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1459     DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
1460 
1461     // Ist dieser String leer
1462     if ( !mpData->mnLen )
1463         return STRING_MATCH;
1464 
1465     // Suche bis Stringende nach dem ersten nicht uebereinstimmenden Zeichen
1466     const STRCODE*  pStr1 = mpData->maStr;
1467     const STRCODE*  pStr2 = rStr.mpData->maStr;
1468     xub_StrLen      i = 0;
1469     while ( i < mpData->mnLen )
1470     {
1471         // Stimmt das Zeichen nicht ueberein, dann abbrechen
1472         if ( *pStr1 != *pStr2 )
1473             return i;
1474         ++pStr1,
1475         ++pStr2,
1476         ++i;
1477     }
1478 
1479     return STRING_MATCH;
1480 }
1481 
1482 // -----------------------------------------------------------------------
1483 
1484 xub_StrLen STRING::Match( const STRCODE* pCharStr ) const
1485 {
1486     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1487 
1488     // Ist dieser String leer
1489     if ( !mpData->mnLen )
1490         return STRING_MATCH;
1491 
1492     // Suche bis Stringende nach dem ersten nicht uebereinstimmenden Zeichen
1493     const STRCODE*  pStr = mpData->maStr;
1494     xub_StrLen      i = 0;
1495     while ( i < mpData->mnLen )
1496     {
1497         // Stimmt das Zeichen nicht ueberein, dann abbrechen
1498         if ( *pStr != *pCharStr )
1499             return i;
1500         ++pStr,
1501         ++pCharStr,
1502         ++i;
1503     }
1504 
1505     return STRING_MATCH;
1506 }
1507 
1508 // -----------------------------------------------------------------------
1509 
1510 xub_StrLen STRING::Search( STRCODE c, xub_StrLen nIndex ) const
1511 {
1512     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1513 
1514     sal_Int32       nLen = mpData->mnLen;
1515     const STRCODE*  pStr = mpData->maStr;
1516     pStr += nIndex;
1517     while ( nIndex < nLen )
1518     {
1519         if ( *pStr == c )
1520             return nIndex;
1521         ++pStr,
1522         ++nIndex;
1523     }
1524 
1525     return STRING_NOTFOUND;
1526 }
1527 
1528 // -----------------------------------------------------------------------
1529 
1530 xub_StrLen STRING::Search( const STRING& rStr, xub_StrLen nIndex ) const
1531 {
1532     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1533     DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
1534 
1535     sal_Int32 nLen = mpData->mnLen;
1536     sal_Int32 nStrLen = rStr.mpData->mnLen;
1537 
1538     // Falls die Laenge des uebergebenen Strings 0 ist oder der Index
1539     // hinter dem String liegt, dann wurde der String nicht gefunden
1540     if ( !nStrLen || (nIndex >= nLen) )
1541         return STRING_NOTFOUND;
1542 
1543     const STRCODE* pStr1 = mpData->maStr;
1544     pStr1 += nIndex;
1545 
1546     if ( nStrLen == 1 )
1547     {
1548         STRCODE cSearch = rStr.mpData->maStr[0];
1549         while ( nIndex < nLen )
1550         {
1551             if ( *pStr1 == cSearch )
1552                 return nIndex;
1553             ++pStr1,
1554             ++nIndex;
1555         }
1556     }
1557     else
1558     {
1559         const STRCODE* pStr2 = rStr.mpData->maStr;
1560 
1561         // Nur innerhalb des Strings suchen
1562         while ( nLen - nIndex >= nStrLen )
1563         {
1564             // Stimmt der String ueberein
1565             if ( ImplStringCompareWithoutZero( pStr1, pStr2, nStrLen ) == 0 )
1566                 return nIndex;
1567             ++pStr1,
1568             ++nIndex;
1569         }
1570     }
1571 
1572     return STRING_NOTFOUND;
1573 }
1574 
1575 // -----------------------------------------------------------------------
1576 
1577 xub_StrLen STRING::Search( const STRCODE* pCharStr, xub_StrLen nIndex ) const
1578 {
1579     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1580 
1581     sal_Int32 nLen = mpData->mnLen;
1582     xub_StrLen nStrLen  = ImplStringLen( pCharStr );
1583 
1584     // Falls die Laenge des uebergebenen Strings 0 ist oder der Index
1585     // hinter dem String liegt, dann wurde der String nicht gefunden
1586     if ( !nStrLen || (nIndex >= nLen) )
1587         return STRING_NOTFOUND;
1588 
1589     const STRCODE* pStr = mpData->maStr;
1590     pStr += nIndex;
1591 
1592     if ( nStrLen == 1 )
1593     {
1594         STRCODE cSearch = *pCharStr;
1595         while ( nIndex < nLen )
1596         {
1597             if ( *pStr == cSearch )
1598                 return nIndex;
1599             ++pStr,
1600             ++nIndex;
1601         }
1602     }
1603     else
1604     {
1605         // Nur innerhalb des Strings suchen
1606         while ( nLen - nIndex >= nStrLen )
1607         {
1608             // Stimmt der String ueberein
1609             if ( ImplStringCompareWithoutZero( pStr, pCharStr, nStrLen ) == 0 )
1610                 return nIndex;
1611             ++pStr,
1612             ++nIndex;
1613         }
1614     }
1615 
1616     return STRING_NOTFOUND;
1617 }
1618 
1619 // -----------------------------------------------------------------------
1620 
1621 xub_StrLen STRING::SearchBackward( STRCODE c, xub_StrLen nIndex ) const
1622 {
1623     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1624 
1625     if ( nIndex > mpData->mnLen )
1626         nIndex = (xub_StrLen)mpData->mnLen;
1627 
1628     const STRCODE* pStr = mpData->maStr;
1629     pStr += nIndex;
1630 
1631     while ( nIndex )
1632     {
1633         nIndex--;
1634         pStr--;
1635         if ( *pStr == c )
1636             return nIndex;
1637     }
1638 
1639     return STRING_NOTFOUND;
1640 }
1641 
1642 // -----------------------------------------------------------------------
1643 
1644 xub_StrLen STRING::SearchChar( const STRCODE* pChars, xub_StrLen nIndex ) const
1645 {
1646     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1647 
1648     sal_Int32       nLen = mpData->mnLen;
1649     const STRCODE*  pStr = mpData->maStr;
1650     pStr += nIndex;
1651     while ( nIndex < nLen )
1652     {
1653         STRCODE         c = *pStr;
1654         const STRCODE*  pCompStr = pChars;
1655         while ( *pCompStr )
1656         {
1657             if ( *pCompStr == c )
1658                 return nIndex;
1659             ++pCompStr;
1660         }
1661         ++pStr,
1662         ++nIndex;
1663     }
1664 
1665     return STRING_NOTFOUND;
1666 }
1667 
1668 // -----------------------------------------------------------------------
1669 
1670 xub_StrLen STRING::SearchCharBackward( const STRCODE* pChars, xub_StrLen nIndex ) const
1671 {
1672     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1673 
1674     if ( nIndex > mpData->mnLen )
1675         nIndex = (xub_StrLen)mpData->mnLen;
1676 
1677     const STRCODE* pStr = mpData->maStr;
1678     pStr += nIndex;
1679 
1680     while ( nIndex )
1681     {
1682         nIndex--;
1683         pStr--;
1684 
1685         STRCODE         c =*pStr;
1686         const STRCODE*  pCompStr = pChars;
1687         while ( *pCompStr )
1688         {
1689             if ( *pCompStr == c )
1690                 return nIndex;
1691             ++pCompStr;
1692         }
1693     }
1694 
1695     return STRING_NOTFOUND;
1696 }
1697 
1698 // -----------------------------------------------------------------------
1699 
1700 xub_StrLen STRING::SearchAndReplace( STRCODE c, STRCODE cRep, xub_StrLen nIndex )
1701 {
1702     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1703 
1704     sal_Int32       nLen = mpData->mnLen;
1705     const STRCODE*  pStr = mpData->maStr;
1706     pStr += nIndex;
1707     while ( nIndex < nLen )
1708     {
1709         if ( *pStr == c )
1710         {
1711             ImplCopyData();
1712             mpData->maStr[nIndex] = cRep;
1713             return nIndex;
1714         }
1715         ++pStr,
1716         ++nIndex;
1717     }
1718 
1719     return STRING_NOTFOUND;
1720 }
1721 
1722 // -----------------------------------------------------------------------
1723 
1724 xub_StrLen STRING::SearchAndReplace( const STRING& rStr, const STRING& rRepStr,
1725                                      xub_StrLen nIndex )
1726 {
1727     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1728     DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
1729     DBG_CHKOBJ( &rRepStr, STRING, DBGCHECKSTRING );
1730 
1731     xub_StrLen nSPos = Search( rStr, nIndex );
1732     if ( nSPos != STRING_NOTFOUND )
1733         Replace( nSPos, rStr.Len(), rRepStr );
1734 
1735     return nSPos;
1736 }
1737 
1738 // -----------------------------------------------------------------------
1739 
1740 xub_StrLen STRING::SearchAndReplace( const STRCODE* pCharStr, const STRING& rRepStr,
1741                                      xub_StrLen nIndex )
1742 {
1743     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1744     DBG_CHKOBJ( &rRepStr, STRING, DBGCHECKSTRING );
1745 
1746     xub_StrLen nSPos = Search( pCharStr, nIndex );
1747     if ( nSPos != STRING_NOTFOUND )
1748         Replace( nSPos, ImplStringLen( pCharStr ), rRepStr );
1749 
1750     return nSPos;
1751 }
1752 
1753 // -----------------------------------------------------------------------
1754 
1755 void STRING::SearchAndReplaceAll( STRCODE c, STRCODE cRep )
1756 {
1757     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1758 
1759     sal_Int32       nLen    = mpData->mnLen;
1760     const STRCODE*  pStr    = mpData->maStr;
1761     sal_Int32       nIndex  = 0;
1762     while ( nIndex < nLen )
1763     {
1764         if ( *pStr == c )
1765         {
1766             ImplCopyData();
1767             mpData->maStr[nIndex] = cRep;
1768         }
1769         ++pStr,
1770         ++nIndex;
1771     }
1772 }
1773 
1774 // -----------------------------------------------------------------------
1775 
1776 void STRING::SearchAndReplaceAll( const STRCODE* pCharStr, const STRING& rRepStr )
1777 {
1778     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1779     DBG_CHKOBJ( &rRepStr, STRING, DBGCHECKSTRING );
1780 
1781     xub_StrLen nCharLen = ImplStringLen( pCharStr );
1782     xub_StrLen nSPos = Search( pCharStr, 0 );
1783     while ( nSPos != STRING_NOTFOUND )
1784     {
1785         Replace( nSPos, nCharLen, rRepStr );
1786         nSPos = nSPos + rRepStr.Len();
1787         nSPos = Search( pCharStr, nSPos );
1788     }
1789 }
1790 
1791 // -----------------------------------------------------------------------
1792 
1793 void STRING::SearchAndReplaceAll( const STRING& rStr, const STRING& rRepStr )
1794 {
1795     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1796     DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
1797     DBG_CHKOBJ( &rRepStr, STRING, DBGCHECKSTRING );
1798 
1799     xub_StrLen nSPos = Search( rStr, 0 );
1800     while ( nSPos != STRING_NOTFOUND )
1801     {
1802         Replace( nSPos, rStr.Len(), rRepStr );
1803         nSPos = nSPos + rRepStr.Len();
1804         nSPos = Search( rStr, nSPos );
1805     }
1806 }
1807 
1808 // -----------------------------------------------------------------------
1809 
1810 xub_StrLen STRING::GetTokenCount( STRCODE cTok ) const
1811 {
1812     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1813 
1814     // Leerer String: TokenCount per Definition 0
1815     if ( !mpData->mnLen )
1816         return 0;
1817 
1818     xub_StrLen      nTokCount       = 1;
1819     sal_Int32       nLen            = mpData->mnLen;
1820     const STRCODE*  pStr            = mpData->maStr;
1821     sal_Int32       nIndex          = 0;
1822     while ( nIndex < nLen )
1823     {
1824         // Stimmt das Tokenzeichen ueberein, dann erhoehe TokCount
1825         if ( *pStr == cTok )
1826             ++nTokCount;
1827         ++pStr,
1828         ++nIndex;
1829     }
1830 
1831     return nTokCount;
1832 }
1833 
1834 // -----------------------------------------------------------------------
1835 
1836 void STRING::SetToken( xub_StrLen nToken, STRCODE cTok, const STRING& rStr,
1837                        xub_StrLen nIndex )
1838 {
1839     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1840     DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
1841 
1842     const STRCODE*  pStr            = mpData->maStr;
1843     xub_StrLen      nLen            = (xub_StrLen)mpData->mnLen;
1844     xub_StrLen      nTok            = 0;
1845     xub_StrLen      nFirstChar      = nIndex;
1846     xub_StrLen      i               = nFirstChar;
1847 
1848     // Bestimme die Token-Position und Laenge
1849     pStr += i;
1850     while ( i < nLen )
1851     {
1852         // Stimmt das Tokenzeichen ueberein, dann erhoehe TokCount
1853         if ( *pStr == cTok )
1854         {
1855             ++nTok;
1856 
1857             if ( nTok == nToken )
1858                 nFirstChar = i+1;
1859             else
1860             {
1861                 if ( nTok > nToken )
1862                     break;
1863             }
1864         }
1865 
1866         ++pStr,
1867         ++i;
1868     }
1869 
1870     if ( nTok >= nToken )
1871         Replace( nFirstChar, i-nFirstChar, rStr );
1872 }
1873 
1874 // -----------------------------------------------------------------------
1875 
1876 STRING STRING::GetToken( xub_StrLen nToken, STRCODE cTok, xub_StrLen& rIndex ) const
1877 {
1878     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1879 
1880     const STRCODE*  pStr            = mpData->maStr;
1881     xub_StrLen      nLen            = (xub_StrLen)mpData->mnLen;
1882     xub_StrLen      nTok            = 0;
1883     xub_StrLen      nFirstChar      = rIndex;
1884     xub_StrLen      i               = nFirstChar;
1885 
1886     // Bestimme die Token-Position und Laenge
1887     pStr += i;
1888     while ( i < nLen )
1889     {
1890         // Stimmt das Tokenzeichen ueberein, dann erhoehe TokCount
1891         if ( *pStr == cTok )
1892         {
1893             ++nTok;
1894 
1895             if ( nTok == nToken )
1896                 nFirstChar = i+1;
1897             else
1898             {
1899                 if ( nTok > nToken )
1900                     break;
1901             }
1902         }
1903 
1904         ++pStr,
1905         ++i;
1906     }
1907 
1908     if ( nTok >= nToken )
1909     {
1910         if ( i < nLen )
1911             rIndex = i+1;
1912         else
1913             rIndex = STRING_NOTFOUND;
1914         return Copy( nFirstChar, i-nFirstChar );
1915     }
1916     else
1917     {
1918         rIndex = STRING_NOTFOUND;
1919         return STRING();
1920     }
1921 }
1922 
1923 // -----------------------------------------------------------------------
1924 
1925 xub_StrLen STRING::GetQuotedTokenCount( const STRING& rQuotedPairs, STRCODE cTok ) const
1926 {
1927     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1928     DBG_CHKOBJ( &rQuotedPairs, STRING, DBGCHECKSTRING );
1929     DBG_ASSERT( !(rQuotedPairs.Len()%2), "String::GetQuotedTokenCount() - QuotedString%2 != 0" );
1930     DBG_ASSERT( rQuotedPairs.Search(cTok) == STRING_NOTFOUND, "String::GetQuotedTokenCount() - cTok in QuotedString" );
1931 
1932     // Leerer String: TokenCount per Definition 0
1933     if ( !mpData->mnLen )
1934         return 0;
1935 
1936     xub_StrLen      nTokCount       = 1;
1937     sal_Int32       nLen            = mpData->mnLen;
1938     xub_StrLen      nQuotedLen      = rQuotedPairs.Len();
1939     STRCODE         cQuotedEndChar  = 0;
1940     const STRCODE*  pQuotedStr      = rQuotedPairs.mpData->maStr;
1941     const STRCODE*  pStr            = mpData->maStr;
1942     sal_Int32       nIndex          = 0;
1943     while ( nIndex < nLen )
1944     {
1945         STRCODE c = *pStr;
1946         if ( cQuotedEndChar )
1947         {
1948             // Ende des Quotes erreicht ?
1949             if ( c == cQuotedEndChar )
1950                 cQuotedEndChar = 0;
1951         }
1952         else
1953         {
1954             // Ist das Zeichen ein Quote-Anfang-Zeichen ?
1955             xub_StrLen nQuoteIndex = 0;
1956             while ( nQuoteIndex < nQuotedLen )
1957             {
1958                 if ( pQuotedStr[nQuoteIndex] == c )
1959                 {
1960                     cQuotedEndChar = pQuotedStr[nQuoteIndex+1];
1961                     break;
1962                 }
1963                 else
1964                     nQuoteIndex += 2;
1965             }
1966 
1967             // Stimmt das Tokenzeichen ueberein, dann erhoehe TokCount
1968             if ( c == cTok )
1969                 ++nTokCount;
1970         }
1971 
1972         ++pStr,
1973         ++nIndex;
1974     }
1975 
1976     return nTokCount;
1977 }
1978 
1979 // -----------------------------------------------------------------------
1980 
1981 STRING STRING::GetQuotedToken( xub_StrLen nToken, const STRING& rQuotedPairs,
1982                                STRCODE cTok, xub_StrLen& rIndex ) const
1983 {
1984     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
1985     DBG_CHKOBJ( &rQuotedPairs, STRING, DBGCHECKSTRING );
1986     DBG_ASSERT( !(rQuotedPairs.Len()%2), "String::GetQuotedToken() - QuotedString%2 != 0" );
1987     DBG_ASSERT( rQuotedPairs.Search(cTok) == STRING_NOTFOUND, "String::GetQuotedToken() - cTok in QuotedString" );
1988 
1989     const STRCODE*  pStr            = mpData->maStr;
1990     const STRCODE*  pQuotedStr      = rQuotedPairs.mpData->maStr;
1991     STRCODE         cQuotedEndChar  = 0;
1992     xub_StrLen      nQuotedLen      = rQuotedPairs.Len();
1993     xub_StrLen      nLen            = (xub_StrLen)mpData->mnLen;
1994     xub_StrLen      nTok            = 0;
1995     xub_StrLen      nFirstChar      = rIndex;
1996     xub_StrLen      i               = nFirstChar;
1997 
1998     // Bestimme die Token-Position und Laenge
1999     pStr += i;
2000     while ( i < nLen )
2001     {
2002         STRCODE c = *pStr;
2003         if ( cQuotedEndChar )
2004         {
2005             // Ende des Quotes erreicht ?
2006             if ( c == cQuotedEndChar )
2007                 cQuotedEndChar = 0;
2008         }
2009         else
2010         {
2011             // Ist das Zeichen ein Quote-Anfang-Zeichen ?
2012             xub_StrLen nQuoteIndex = 0;
2013             while ( nQuoteIndex < nQuotedLen )
2014             {
2015                 if ( pQuotedStr[nQuoteIndex] == c )
2016                 {
2017                     cQuotedEndChar = pQuotedStr[nQuoteIndex+1];
2018                     break;
2019                 }
2020                 else
2021                     nQuoteIndex += 2;
2022             }
2023 
2024             // Stimmt das Tokenzeichen ueberein, dann erhoehe TokCount
2025             if ( c == cTok )
2026             {
2027                 ++nTok;
2028 
2029                 if ( nTok == nToken )
2030                     nFirstChar = i+1;
2031                 else
2032                 {
2033                     if ( nTok > nToken )
2034                         break;
2035                 }
2036             }
2037         }
2038 
2039         ++pStr,
2040         ++i;
2041     }
2042 
2043     if ( nTok >= nToken )
2044     {
2045         if ( i < nLen )
2046             rIndex = i+1;
2047         else
2048             rIndex = STRING_NOTFOUND;
2049         return Copy( nFirstChar, i-nFirstChar );
2050     }
2051     else
2052     {
2053         rIndex = STRING_NOTFOUND;
2054         return STRING();
2055     }
2056 }
2057 
2058 // -----------------------------------------------------------------------
2059 
2060 STRCODE* STRING::GetBufferAccess()
2061 {
2062     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
2063 
2064     // Daten kopieren, wenn noetig
2065     if ( mpData->mnLen )
2066         ImplCopyData();
2067 
2068     // Pointer auf den String zurueckgeben
2069     return mpData->maStr;
2070 }
2071 
2072 // -----------------------------------------------------------------------
2073 
2074 void STRING::ReleaseBufferAccess( xub_StrLen nLen )
2075 {
2076     // Hier ohne Funktionstest, da String nicht konsistent
2077     DBG_CHKTHIS( STRING, NULL );
2078     DBG_ASSERT( mpData->mnRefCount == 1, "String::ReleaseCharStr() called for String with RefCount" );
2079 
2080     if ( nLen > mpData->mnLen )
2081         nLen = ImplStringLen( mpData->maStr );
2082     OSL_ASSERT(nLen <= mpData->mnLen);
2083     if ( !nLen )
2084     {
2085         STRING_NEW((STRING_TYPE **)&mpData);
2086     }
2087     // Bei mehr als 8 Zeichen unterschied, kuerzen wir den Buffer
2088     else if ( mpData->mnLen - nLen > 8 )
2089     {
2090         STRINGDATA* pNewData = ImplAllocData( nLen );
2091         memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
2092         STRING_RELEASE((STRING_TYPE *)mpData);
2093         mpData = pNewData;
2094     }
2095     else
2096         mpData->mnLen = nLen;
2097 }
2098 
2099 // -----------------------------------------------------------------------
2100 
2101 STRCODE* STRING::AllocBuffer( xub_StrLen nLen )
2102 {
2103     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
2104 
2105     STRING_RELEASE((STRING_TYPE *)mpData);
2106     if ( nLen )
2107         mpData = ImplAllocData( nLen );
2108     else
2109     {
2110         mpData = NULL;
2111         STRING_NEW((STRING_TYPE **)&mpData);
2112     }
2113 
2114     return mpData->maStr;
2115 }
2116