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