(file) Return to String.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

Diff for /pegasus/src/Pegasus/Common/String.cpp between version 1.109 and 1.141

version 1.109, 2005/05/18 20:34:36 version 1.141, 2014/07/17 19:55:40
Line 1 
Line 1 
 //%2005////////////////////////////////////////////////////////////////////////  //%LICENSE////////////////////////////////////////////////////////////////
 // //
 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development  // Licensed to The Open Group (TOG) under one or more contributor license
 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.  // agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;  // this work for additional information regarding copyright ownership.
 // IBM Corp.; EMC Corporation, The Open Group.  // Each contributor licenses this file to you under the OpenPegasus Open
 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;  // Source License; you may not use this file except in compliance with the
 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.  // License.
 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;  
 // EMC Corporation; VERITAS Software Corporation; The Open Group.  
 // //
 // Permission is hereby granted, free of charge, to any person obtaining a copy  // Permission is hereby granted, free of charge, to any person obtaining a
 // of this software and associated documentation files (the "Software"), to  // copy of this software and associated documentation files (the "Software"),
 // deal in the Software without restriction, including without limitation the  // to deal in the Software without restriction, including without limitation
 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or  // the rights to use, copy, modify, merge, publish, distribute, sublicense,
 // sell copies of the Software, and to permit persons to whom the Software is  // and/or sell copies of the Software, and to permit persons to whom the
 // furnished to do so, subject to the following conditions:  // Software is furnished to do so, subject to the following conditions:
 // //
 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN  // The above copyright notice and this permission notice shall be included
 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED  // in all copies or substantial portions of the Software.
 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT  
 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR  
 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT  
 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN  
 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION  
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  
 // //
 //==============================================================================  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 //  // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 // Author: Mike Brasher (mbrasher@bmc.com)  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
   // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
   // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
   // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 // //
 // Modified By: Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com)  //////////////////////////////////////////////////////////////////////////
 //              Josephine Eskaline Joyce, IBM (jojustin@in.ibm.com) for Bug#3297  
 // //
 //%///////////////////////////////////////////////////////////////////////////// //%/////////////////////////////////////////////////////////////////////////////
  
   #include <Pegasus/Common/PegasusAssert.h>
 #include <cctype>  
 #include <cstring> #include <cstring>
 #include "String.h"  
 #include "Array.h"  
 #include "AutoPtr.h"  
 #include "InternalException.h" #include "InternalException.h"
 #include <iostream>  #include "MessageLoader.h"
 #include <fstream>  #include "StringRep.h"
 #include <Pegasus/Common/CommonUTF.h>  #include <Pegasus/Common/Pegasus_inl.h>
   #include <cstdarg>
 #include "CommonUTF.h"  
  
 #ifdef PEGASUS_HAS_ICU #ifdef PEGASUS_HAS_ICU
   # include <unicode/ures.h>
 #include <unicode/ustring.h> #include <unicode/ustring.h>
 #include <unicode/uchar.h> #include <unicode/uchar.h>
 #endif #endif
  
 PEGASUS_USING_STD;  
   
 PEGASUS_NAMESPACE_BEGIN PEGASUS_NAMESPACE_BEGIN
  
 ///////////////////////////////////////////////////////////////////////////////  //==============================================================================
   //
   // Compile-time macros (undefined by default).
   //
   //     PEGASUS_STRING_NO_UTF8 -- don't generate slower UTF8 code.
   //
   //==============================================================================
   
   //==============================================================================
 // //
 // CString  // File-scope definitions:
 // //
 ///////////////////////////////////////////////////////////////////////////////  //==============================================================================
   
   // Note: this table is much faster than the system toupper(). Please do not
   // change.
  
 CString::CString()  const Uint8 _toUpperTable[256] =
     : _rep(0)  
 { {
 }      0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
       0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
       0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
       0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
       0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
       0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
       0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
       0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
       0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
       0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
       0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
       0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
       0x60,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
       0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
       0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
       0x58,0x59,0x5A,0x7B,0x7C,0x7D,0x7E,0x7F,
       0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
       0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
       0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
       0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
       0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
       0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
       0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,
       0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
       0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
       0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
       0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,
       0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
       0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,
       0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
       0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,
       0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,
   };
  
 CString::CString(const CString& cstr)  // Note: this table is much faster than the system tolower(). Please do not
   // change.
   
   const Uint8 _toLowerTable[256] =
 { {
     _rep = 0;      0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
       0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
       0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
       0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
       0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
       0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
       0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
       0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
       0x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
       0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
       0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
       0x78,0x79,0x7A,0x5B,0x5C,0x5D,0x5E,0x5F,
       0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
       0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
       0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
       0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
       0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
       0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
       0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
       0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
       0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
       0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
       0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,
       0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
       0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
       0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
       0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,
       0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
       0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,
       0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
       0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,
       0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,
   };
  
     if (cstr._rep)  // Converts 16-bit characters to upper case. This routine is faster than the
   // system toupper(). Please do not change.
   inline Uint16 _toUpper(Uint16 x)
     {     {
         _rep = (void*)new char[strlen((char*)cstr._rep)+1];      return (x & 0xFF00) ? x : _toUpperTable[x];
         strcpy((char*)_rep, (char*)cstr._rep);  
     }  
 } }
  
 CString::CString(char* cstr)  // Converts 16-bit characters to lower case. This routine is faster than the
     : _rep(cstr)  // system toupper(). Please do not change.
   inline Uint16 _toLower(Uint16 x)
 { {
       return (x & 0xFF00) ? x : _toLowerTable[x];
 } }
  
 CString::~CString()  // Rounds x up to the nearest power of two (or just returns 8 if x < 8).
   static Uint32 _roundUpToPow2(Uint32 x)
 { {
     if (_rep)      // Check for potential overflow in x
     {      PEGASUS_CHECK_CAPACITY_OVERFLOW(x);
         delete [] (char*)_rep;  
     }      if (x < 8)
           return 8;
   
       x--;
       x |= (x >> 1);
       x |= (x >> 2);
       x |= (x >> 4);
       x |= (x >> 8);
       x |= (x >> 16);
       x++;
   
       return x;
 } }
  
 CString& CString::operator=(const CString& cstr)  static Uint16* _find(const Uint16* s, size_t n, Uint16 c)
 {  
     if (&cstr != this)  
     {     {
         if (_rep)      // The following employs loop unrolling for efficiency. Please do not
       // eliminate.
   
       while (n >= 4)
         {         {
             delete [] (char*)_rep;          if (s[0] == c)
             _rep = 0;              return (Uint16*)s;
           if (s[1] == c)
               return (Uint16*)&s[1];
           if (s[2] == c)
               return (Uint16*)&s[2];
           if (s[3] == c)
               return (Uint16*)&s[3];
   
           n -= 4;
           s += 4;
         }         }
         if (cstr._rep)  
       if (n)
         {         {
             _rep = (char*)new char[strlen((char*)cstr._rep)+1];          if (*s == c)
             strcpy((char*)_rep, (char*)cstr._rep);              return (Uint16*)s;
           s++;
           n--;
         }         }
   
       if (n)
       {
           if (*s == c)
               return (Uint16*)s;
           s++;
           n--;
     }     }
     return *this;  
       if (n && *s == c)
           return (Uint16*)s;
   
       // Not found!
       return 0;
 } }
  
 CString::operator const char*() const  static int _compare(const Uint16* s1, const Uint16* s2)
   {
       while (*s1 && *s2)
 { {
     return (char*)_rep;          int r = *s1++ - *s2++;
   
           if (r)
               return r;
 } }
  
 ///////////////////////////////////////////////////////////////////////////////      if (*s2)
 //          return -1;
 // String      else if (*s1)
 //          return 1;
 ///////////////////////////////////////////////////////////////////////////////  
  
 const String String::EMPTY = String();      return 0;
   }
  
 inline Uint32 _StrLen(const Char16* str)  #ifdef PEGASUS_STRING_NO_UTF8
   static int _compareNoUTF8(const Uint16* s1, const char* s2)
 { {
     if (!str)      Uint16 c1;
         throw NullPointer();      Uint16 c2;
  
     Uint32 n = 0;      do
       {
           c1 = *s1++;
           c2 = *s2++;
  
     while (*str++)          if (c1 == 0)
         n++;              return c1 - c2;
       }
       while (c1 == c2);
  
     return n;      return c1 - c2;
 } }
   #endif
  
 //  static inline void _copy(Uint16* s1, const Uint16* s2, size_t n)
 // Converts a utf-8 char buffer to utf-16 and appends the utf-16 to the Array.  
 // n is the length of the input char *, if stopAtTerm is 0  
 // A terminator character is appended to the end.  
 // Note that each input char is converted individually, which gives  
 // the fastest performance.  
 //  
 void _convertAndAppend(const char* str, Array<Char16>& c16a, Uint32 n, Uint8 stopAtTerm)  
 { {
     Uint32 i = 0;      memcpy(s1, s2, n * sizeof(Uint16));
     while ((stopAtTerm && *str) || (!stopAtTerm && i < n))  }
   
   void StringThrowOutOfBounds()
     {     {
         if (*(Uint8*)str <= 0x7f)      throw IndexOutOfBoundsException();
   }
   
   inline void _checkNullPointer(const void* ptr)
         {         {
             // Current byte sequence is in the us-ascii range.      if (!ptr)
             c16a.append(Uint8(*str++));          throw NullPointer();
         }         }
         else  
   #define BADUTF8_MAX_CLEAR_CHAR 40
   #define BADUTF8_MAX_CHAR_TO_HEX 10
   
   static void _formatBadUTF8Chars(
       char* buffer,
       Uint32 index,
       const char* q,
       size_t n )
         {         {
             //  
             // Current byte sequence is not in the us-ascii range.  
             //  
  
             // Check if the byte sequence is valid utf-8, and if so,      char tmp[20];
             // call the converter to utf-16      const char* start;
             Uint16 tgt[3];  
             tgt[1] = 0;      size_t clearChar =
             Uint8 c = UTF_8_COUNT_TRAIL_BYTES(*str);          (( index < BADUTF8_MAX_CLEAR_CHAR ) ? index : BADUTF8_MAX_CLEAR_CHAR );
             if ( (!stopAtTerm && i + c >= n) ||      size_t charToHex =
                  (!isValid_U8((const Uint8 *)str, c+1)) )          ((n-index-1) < BADUTF8_MAX_CHAR_TO_HEX ?
             {              (n-index-1) : BADUTF8_MAX_CHAR_TO_HEX );
                 // Note about error conditions.  
                 // It is possible that the last utf-8 char before the      if (index < BADUTF8_MAX_CLEAR_CHAR)
                 // end of input string extends past the end of the input string.  
                 // This is caught in both cases -  
                 // If counting up to n, then the test above catches it.  
                 // If converting until terminator found, then a terminator  
                 // in the middle of a multi-byte utf-8 char is invalid.  
                 MessageLoaderParms parms("Common.String.BAD_UTF8",  
                   "The byte sequence starting at index $0 is not valid UTF-8 encoding.",  
                   i);  
                 throw Exception(parms);  
             }  
             else  
             {             {
                 //  str is incremented by this call to the start of the next char          start = q;
                 Uint16 * tgtBuf = tgt;      } else
                 UTF8toUTF16((const Uint8 **)&str, (Uint8 *)&str[c+1], &tgtBuf,  &tgtBuf[2]);  
                 c16a.append(tgt[0]);  
                 if (tgt[1])  
                 {                 {
                     // Its a utf-16 surrogate pair (uses 2 Char16's)          start = &(q[ index - BADUTF8_MAX_CLEAR_CHAR]);
                     c16a.append(tgt[1]);  
                 }                 }
  
                 // bump by the trailing byte count      // Intialize the buffer with the first character as '\0' to be able to use
                 i += c;      // strnchat() and strcat()
       buffer[0] = 0;
       // Start the buffer with the valid UTF8 chars
       strncat(buffer,start,clearChar);
       for (size_t i = clearChar, j = 0; j <= charToHex; i++,j++ )
       {
           tmp[0] = 0;
           sprintf(&(tmp[0])," 0x%02X",(Uint8)start[i]);
           strncat(buffer,&(tmp[0]),5);
             }             }
   
         }         }
  
         i++;  static void _StringThrowBadUTF8(Uint32 index, const char* q, size_t n)
     }  // end while  {
       char buffer[1024];
   
       _formatBadUTF8Chars(&(buffer[0]),index,q,n);
  
     c16a.append('\0');      MessageLoaderParms parms(
           "Common.String.BAD_UTF8_LONG",
           "The byte sequence starting at index $0 "
           "is not valid UTF-8 encoding: $1",
           index,buffer);
   
       throw Exception(parms);
 } }
  
 class StringRep  // Note: dest must be at least three times src (plus an extra byte for
   // terminator).
   static inline size_t _copyToUTF8(char* dest, const Uint16* src, size_t n)
 { {
 public:      // The following employs loop unrolling for efficiency. Please do not
     StringRep()      // eliminate.
     {}  
     StringRep(const StringRep& r)  
         : c16a(r.c16a)  
     {}  
     StringRep(const Char16* str)  
         : c16a(str, _StrLen(str) + 1)  
     {}  
  
     Array<Char16> c16a;      const Uint16* q = src;
 };      Uint8* p = (Uint8*)dest;
  
 String::String()      while (n >= 4 && q[0] < 128 && q[1] < 128 && q[2] < 128 && q[3] < 128)
 { {
     _rep = new StringRep;          p[0] = q[0];
     _rep->c16a.append('\0');          p[1] = q[1];
           p[2] = q[2];
           p[3] = q[3];
           p += 4;
           q += 4;
           n -= 4;
 } }
  
 String::String(const String& str)      switch (n)
 { {
   if (str._rep != NULL)          case 0:
               return p - (Uint8*)dest;
           case 1:
               if (q[0] < 128)
   {   {
     _rep = new StringRep(*str._rep);                  p[0] = q[0];
                   return p + 1 - (Uint8*)dest;
   }   }
   else              break;
           case 2:
               if (q[0] < 128 && q[1] < 128)
               {
                   p[0] = q[0];
                   p[1] = q[1];
                   return p + 2 - (Uint8*)dest;
               }
               break;
           case 3:
               if (q[0] < 128 && q[1] < 128 && q[2] < 128)
   {   {
     _rep = new StringRep();                  p[0] = q[0];
                   p[1] = q[1];
                   p[2] = q[2];
                   return p + 3 - (Uint8*)dest;
   }   }
               break;
 } }
  
       // If this line was reached, there must be characters greater than 128.
  
 String::String(const String& str, Uint32 n)      UTF16toUTF8(&q, q + n, &p, p + 3 * n);
   
       return p - (Uint8*)dest;
   }
   
   //==============================================================================
   //
   // class CString
   //
   //==============================================================================
   
   CString::CString(const CString& cstr) : _rep(0)
 { {
     _rep = new StringRep;      if (cstr._rep)
     assign(str.getChar16Data(), n);      {
           size_t n = strlen(cstr._rep) + 1;
           _rep = (char*)operator new(n);
           memcpy(_rep, cstr._rep, n);
       }
 } }
  
 String::String(const Char16* str)  CString& CString::operator=(const CString& cstr)
 { {
     if ( str == 0 )      if (&cstr != this)
     {     {
         throw NullPointer();          if (_rep)
           {
               operator delete(_rep);
               _rep = 0;
     }     }
  
     _rep = new StringRep(str);          if (cstr._rep)
           {
               size_t n = strlen(cstr._rep) + 1;
               _rep = (char*)operator new(n);
               memcpy(_rep, cstr._rep, n);
           }
 } }
  
 String::String(const Char16* str, Uint32 n)      return *this;
   }
   
   //==============================================================================
   //
   // class StringRep
   //
   //==============================================================================
   
   StringRep StringRep::_emptyRep;
   
   inline StringRep* StringRep::alloc(size_t cap)
 { {
     if ( str == 0 )      // Check for potential overflow in cap
       PEGASUS_CHECK_CAPACITY_OVERFLOW(cap);
   
       StringRep* rep = (StringRep*)::operator new(
           sizeof(StringRep) + cap * sizeof(Uint16));
       rep->cap = cap;
       new(&rep->refs) AtomicInt(1);
   
       return rep;
   }
   
   static inline void _reserve(StringRep*& rep, Uint32 cap)
     {     {
         throw NullPointer();      if (cap > rep->cap || rep->refs.get() != 1)
       {
           size_t n = _roundUpToPow2(cap);
           StringRep* newRep = StringRep::alloc(n);
           newRep->size = rep->size;
           _copy(newRep->data, rep->data, rep->size + 1);
           StringRep::unref(rep);
           rep = newRep;
       }
     }     }
  
     _rep = new StringRep;  StringRep* StringRep::create(const Uint16* data, size_t size)
     assign(str, n);  {
       StringRep* rep = StringRep::alloc(size);
       rep->size = size;
       _copy(rep->data, data, size);
       rep->data[size] = '\0';
       return rep;
 } }
  
 String::String(const char* str)  StringRep* StringRep::copyOnWrite(StringRep* rep)
 { {
     if ( str == 0 )      // Return a new copy of rep. Release rep.
   
       StringRep* newRep = StringRep::alloc(rep->size);
       newRep->size = rep->size;
       _copy(newRep->data, rep->data, rep->size);
       newRep->data[newRep->size] = '\0';
       StringRep::unref(rep);
       return newRep;
   }
   
   StringRep* StringRep::create(const char* data, size_t size)
     {     {
         throw NullPointer();      StringRep* rep = StringRep::alloc(size);
       size_t utf8_error_index;
       rep->size = _convert((Uint16*)rep->data, data, size, utf8_error_index);
   
       if (rep->size == size_t(-1))
       {
           StringRep::free(rep);
           _StringThrowBadUTF8((Uint32)utf8_error_index, data,size);
     }     }
  
     _rep = new StringRep;      rep->data[rep->size] = '\0';
     AutoPtr<StringRep> tempRep(_rep);  
     // An exception can be thrown, so use a temp AutoPtr.      return rep;
     _convertAndAppend(str, _rep->c16a, 0, 1);  
     tempRep.release();  
 } }
  
 String::String(const char* str, Uint32 n)  Uint32 StringRep::length(const Uint16* str)
 { {
     if ( str == 0 )      // Note: We could unroll this but it is rarely called.
   
       const Uint16* end = (Uint16*)str;
   
       while (*end++)
           ;
   
       return (Uint32)(end - str - 1);
   }
   
   //==============================================================================
   //
   // class String
   //
   //==============================================================================
   
   const String String::EMPTY;
   
   String::String(const String& str, Uint32 n)
     {     {
         throw NullPointer();      _checkBounds(n, str._rep->size);
       _rep = StringRep::create(str._rep->data, n);
     }     }
  
     _rep = new StringRep;  String::String(const Char16* str)
     AutoPtr<StringRep> tempRep(_rep);  {
     // An exception can be thrown, so use a temp AutoPtr.      _checkNullPointer(str);
     _convertAndAppend(str, _rep->c16a, n, 0);      _rep = StringRep::create((Uint16*)str, StringRep::length((Uint16*)str));
     tempRep.release();  
 } }
  
 String::~String()  String::String(const Char16* str, Uint32 n)
 { {
     delete _rep;      _checkNullPointer(str);
       _rep = StringRep::create((Uint16*)str, n);
 } }
  
 String& String::operator=(const String& str)  String::String(const char* str)
 { {
     if (&str != this)      _checkNullPointer(str);
   
       // Set this just in case create() throws an exception.
       _rep = &StringRep::_emptyRep;
       _rep = StringRep::create(str, strlen(str));
   }
   
   String::String(const char* str, Uint32 n)
     {     {
         assign(str);      _checkNullPointer(str);
   
       // Set this just in case create() throws an exception.
       _rep = &StringRep::_emptyRep;
       _rep = StringRep::create(str, n);
     }     }
     return *this;  
   String::String(const String& s1, const String& s2)
   {
       size_t n1 = s1._rep->size;
       size_t n2 = s2._rep->size;
       size_t n = n1 + n2;
       _rep = StringRep::alloc(n);
       _copy(_rep->data, s1._rep->data, n1);
       _copy(_rep->data + n1, s2._rep->data, n2);
       _rep->size = n;
       _rep->data[n] = '\0';
 } }
  
 String& String::assign(const String& str)  String::String(const String& s1, const char* s2)
 { {
     _rep->c16a = str._rep->c16a;      _checkNullPointer(s2);
     return *this;      size_t n1 = s1._rep->size;
       size_t n2 = strlen(s2);
       _rep = StringRep::alloc(n1 + n2);
       _copy(_rep->data, s1._rep->data, n1);
       size_t utf8_error_index;
       size_t tmp = _convert((Uint16*)_rep->data + n1, s2, n2, utf8_error_index);
   
       if (tmp == size_t(-1))
       {
           StringRep::free(_rep);
           _rep = &StringRep::_emptyRep;
           _StringThrowBadUTF8((Uint32)utf8_error_index,s2,n2);
       }
   
       _rep->size = n1 + tmp;
       _rep->data[_rep->size] = '\0';
 } }
  
 String& String::assign(const Char16* str)  String::String(const char* s1, const String& s2)
 { {
     if ( str == 0 )      _checkNullPointer(s1);
       size_t n1 = strlen(s1);
       size_t n2 = s2._rep->size;
       _rep = StringRep::alloc(n1 + n2);
       size_t utf8_error_index;
       size_t tmp = _convert((Uint16*)_rep->data, s1, n1, utf8_error_index);
   
       if (tmp ==  size_t(-1))
     {     {
         throw NullPointer();          StringRep::free(_rep);
           _rep = &StringRep::_emptyRep;
           _StringThrowBadUTF8((Uint32)utf8_error_index,s1,n1);
     }     }
  
     _rep->c16a.clear();      _rep->size = n2 + tmp;
     _rep->c16a.append(str, _StrLen(str) + 1);      _copy(_rep->data + n1, s2._rep->data, n2);
     return *this;      _rep->data[_rep->size] = '\0';
 } }
  
 String& String::assign(const Char16* str, Uint32 n)  String& String::assign(const String& str)
 { {
     if ( str == 0 )      if (_rep != str._rep)
     {     {
         throw NullPointer();          StringRep::unref(_rep);
           StringRep::ref(_rep = str._rep);
     }     }
  
     _rep->c16a.clear();  
     _rep->c16a.append(str, n);  
     _rep->c16a.append('\0');  
     return *this;     return *this;
 } }
  
 String& String::assign(const char* str)  String& String::assign(const Char16* str, Uint32 n)
 { {
     if ( str == 0 )      _checkNullPointer(str);
   
       if (n > _rep->cap || _rep->refs.get() != 1)
     {     {
         throw NullPointer();          StringRep::unref(_rep);
           _rep = StringRep::alloc(n);
     }     }
  
     _rep->c16a.clear();      _rep->size = n;
     _convertAndAppend(str, _rep->c16a, 0, 1);      _copy(_rep->data, (Uint16*)str, n);
       _rep->data[n] = '\0';
   
     return *this;     return *this;
 } }
  
 String& String::assign(const char* str, Uint32 n) String& String::assign(const char* str, Uint32 n)
 { {
     if ( str == 0 )      _checkNullPointer(str);
   
       if (n > _rep->cap || _rep->refs.get() != 1)
     {     {
         throw NullPointer();          StringRep::unref(_rep);
           _rep = StringRep::alloc(n);
     }     }
  
     _rep->c16a.clear();      size_t utf8_error_index;
     _convertAndAppend(str, _rep->c16a, n, 0);      _rep->size = _convert(_rep->data, str, n, utf8_error_index);
   
       if (_rep->size ==  size_t(-1))
       {
           StringRep::free(_rep);
           _rep = &StringRep::_emptyRep;
           _StringThrowBadUTF8((Uint32)utf8_error_index,str,n);
       }
   
       _rep->data[_rep->size] = 0;
   
     return *this;     return *this;
 } }
  
 void String::clear() void String::clear()
 { {
     _rep->c16a.clear();      if (_rep->size)
     _rep->c16a.append('\0');      {
 }          if (_rep->refs.get() == 1)
   
 void String::reserveCapacity(Uint32 capacity)  
 { {
     _rep->c16a.reserveCapacity(capacity + 1);              _rep->size = 0;
               _rep->data[0] = '\0';
 } }
           else
 Uint32 String::size() const  
 { {
 //#if defined (PEGASUS_OS_VMS)              StringRep::unref(_rep);
   //              _rep = &StringRep::_emptyRep;
   // This prevents returning a minus number.          }
   //      }
   // Seems as though the first time through  
   //  the XML parser something doesn't get  
   //  initialized and there is no check for  
   //  a negative number in the parser!  
   //  
 //  Uint32 foo;  
 //  foo = _rep->c16a.size();  
 //  if (foo == 0)  
 //  {  
 //    return 0;  
 //  }  
 //  else  
 //  {  
 //    return (foo -1);  
 //  }  
 //#else  
     return _rep->c16a.size() - 1;  
 //#endif  
 } }
  
 const Char16* String::getChar16Data() const  void String::reserveCapacity(Uint32 cap)
 { {
     return _rep->c16a.getData();      _reserve(_rep, cap);
 } }
  
 Char16& String::operator[](Uint32 index)  CString String::getCString() const
 { {
     if (index > size())      // A UTF8 string can have three times as many characters as its UTF16
         throw IndexOutOfBoundsException();      // counterpart, so we allocate extra memory for the worst case. In the
       // best case, we may need only one third of the memory allocated. But
     return _rep->c16a[index];      // downsizing the string afterwards is expensive and unecessary since
       // CString objects are usually short-lived (disappearing after only a few
       // instructions). CString objects are typically created on the stack as
       // means to obtain a char* pointer.
   
   #ifdef PEGASUS_STRING_NO_UTF8
       char* str = (char*)operator new(_rep->size + 1);
       _copy(str, _rep->data, _rep->size);
       str[_rep->size] = '\0';
       return CString(str);
   #else
       Uint32 n = (Uint32)(3 * _rep->size);
       char* str = (char*)operator new(n + 1);
       size_t size = _copyToUTF8(str, _rep->data, _rep->size);
       str[size] = '\0';
       return CString(str);
   #endif
 } }
  
 const Char16 String::operator[](Uint32 index) const  String& String::append(const Char16* str, Uint32 n)
 { {
     if (index > size())      _checkNullPointer(str);
         throw IndexOutOfBoundsException();  
       size_t oldSize = _rep->size;
       size_t newSize = oldSize + n;
       _reserve(_rep, (Uint32)newSize);
       _copy(_rep->data + oldSize, (Uint16*)str, n);
       _rep->size = newSize;
       _rep->data[newSize] = '\0';
  
     return _rep->c16a[index];      return *this;
 } }
  
 String& String::append(const Char16& c)  String& String::append(const String& str)
 { {
     _rep->c16a.insert(_rep->c16a.size() - 1, c);      return append((Char16*)(&(str._rep->data[0])), (Uint32)str._rep->size);
     return *this;  
 } }
  
 String& String::append(const Char16* str, Uint32 n)  String& String::append(const char* str, Uint32 size)
 { {
      if (str == 0)      _checkNullPointer(str);
   
       size_t oldSize = _rep->size;
       size_t cap = oldSize + size;
   
       _reserve(_rep, (Uint32)cap);
       size_t utf8_error_index;
       size_t tmp = _convert(
           (Uint16*)_rep->data + oldSize, str, size, utf8_error_index);
   
       if (tmp ==  size_t(-1))
      {      {
          throw NullPointer();          StringRep::free(_rep);
           _rep = &StringRep::_emptyRep;
           _StringThrowBadUTF8((Uint32)utf8_error_index,str,size);
      }      }
  
     _rep->c16a.reserveCapacity(_rep->c16a.size() + n);      _rep->size += tmp;
     _rep->c16a.remove(_rep->c16a.size() - 1);      _rep->data[_rep->size] = '\0';
     _rep->c16a.append(str, n);  
     _rep->c16a.append('\0');  
     return *this;     return *this;
 } }
  
 String& String::append(const String& str)  void String::remove(Uint32 index, Uint32 n)
 { {
     return append(str.getChar16Data(), str.size());      if (n == PEG_NOT_FOUND)
 }          n = (Uint32)(_rep->size - index);
  
 void String::remove(Uint32 index, Uint32 size)      _checkBounds(index + n, _rep->size);
 {  
     if (size == PEG_NOT_FOUND)  
         size = this->size() - index;  
  
     if (index + size > this->size())      if (_rep->refs.get() != 1)
         throw IndexOutOfBoundsException();          _rep = StringRep::copyOnWrite(_rep);
   
       PEGASUS_ASSERT(index + n <= _rep->size);
  
     if (size)      size_t rem = _rep->size - (index + n);
         _rep->c16a.remove(index, size);      Uint16* data = _rep->data;
   
       if (rem)
           memmove(data + index, data + index + n, rem * sizeof(Uint16));
   
       _rep->size -= n;
       data[_rep->size] = '\0';
 } }
  
 String String::subString(Uint32 index, Uint32 length) const  String String::subString(Uint32 index, Uint32 n) const
 { {
     if (index < size())      // Note: this implementation is very permissive but used for
       // backwards compatibility.
   
       if (index < _rep->size)
     {     {
         if ((length == PEG_NOT_FOUND) || (length > size() - index))          if (n == PEG_NOT_FOUND || n > _rep->size - index)
             length = size() - index;              n = (Uint32)(_rep->size - index);
  
         return String(getChar16Data() + index, length);          return String((Char16*)(_rep->data + index), n);
     }     }
  
     return String();     return String();
Line 469 
Line 784 
  
 Uint32 String::find(Char16 c) const Uint32 String::find(Char16 c) const
 { {
     const Char16* first = getChar16Data();      Uint16* p = (Uint16*)_find(_rep->data, _rep->size, c);
  
     for (const Char16* p = first; *p; p++)      if (p)
     {          return static_cast<Uint32>(p - _rep->data);
         if (*p == c)  
             return  p - first;  
     }  
  
     return PEG_NOT_FOUND;     return PEG_NOT_FOUND;
 } }
  
 Uint32 String::find(Uint32 index, Char16 c) const Uint32 String::find(Uint32 index, Char16 c) const
 { {
     const Char16* data = getChar16Data();      _checkBounds(index, _rep->size);
  
     for (Uint32 i = index, n = size(); i < n; i++)      if (index >= _rep->size)
     {          return PEG_NOT_FOUND;
         if (data[i] == c)  
             return i;      Uint16* p = (Uint16*)_find(_rep->data + index, _rep->size - index, c);
     }  
       if (p)
           return static_cast<Uint32>(p - _rep->data);
  
     return PEG_NOT_FOUND;     return PEG_NOT_FOUND;
 } }
  
 Uint32 String::find(const String& s) const  Uint32 StringFindAux(
       const StringRep* _rep, const Char16* s, Uint32 n)
 { {
     const Char16* pSubStr = s.getChar16Data();      _checkNullPointer(s);
     const Char16* pStr = getChar16Data();  
     Uint32 subStrLen = s.size();      const Uint16* data = _rep->data;
     Uint32 strLen = size();      size_t rem = _rep->size;
  
     if (subStrLen > strLen)      while (n <= rem)
     {     {
         return PEG_NOT_FOUND;          Uint16* p = (Uint16*)_find(data, rem, s[0]);
     }  
  
     // loop to find first char match          if (!p)
     Uint32 loc = 0;              break;
     for( ; loc <= (strLen-subStrLen); loc++)  
     {          if (memcmp(p, s, n * sizeof(Uint16)) == 0)
         if (*pStr++ == *pSubStr)  // match first char              return static_cast<Uint32>(p - _rep->data);
         {  
             // point to substr 2nd char          p++;
             const Char16* p = pSubStr + 1;          rem -= p - data;
           data = p;
             // Test remaining chars for equal  
             Uint32 i = 1;  
             for (; i < subStrLen; i++)  
                 if (*pStr++ != *p++ )  
                     {pStr-=i; break;} // break from loop  
             if (i == subStrLen)  
                 return loc;  
         }  
     }     }
   
     return PEG_NOT_FOUND;     return PEG_NOT_FOUND;
 } }
  
   Uint32 String::find(const char* s) const
   {
       _checkNullPointer(s);
   
       // Note: could optimize away creation of temporary, but this is rarely
       // called.
       return find(String(s));
   }
   
 Uint32 String::reverseFind(Char16 c) const Uint32 String::reverseFind(Char16 c) const
 { {
     const Char16* first = getChar16Data();      Uint16 x = c;
     const Char16* last = getChar16Data() + size();      Uint16* p = _rep->data;
       Uint16* q = _rep->data + _rep->size;
  
     while (last != first)      while (q != p)
     {     {
         if (*--last == c)          if (*--q == x)
             return last - first;              return static_cast<Uint32>(q - p);
     }     }
  
     return PEG_NOT_FOUND;     return PEG_NOT_FOUND;
Line 543 
Line 860 
 void String::toLower() void String::toLower()
 { {
 #ifdef PEGASUS_HAS_ICU #ifdef PEGASUS_HAS_ICU
   
     if (InitializeICU::initICUSuccessful())     if (InitializeICU::initICUSuccessful())
     {     {
           if (_rep->refs.get() != 1)
               _rep = StringRep::copyOnWrite(_rep);
   
         // This will do a locale-insensitive, but context-sensitive convert.         // This will do a locale-insensitive, but context-sensitive convert.
         // Context-sensitive prevents any optimizations that try to          // Since context-sensitive casing looks at adjacent chars, this
         // convert just the ascii before calling ICU.          // prevents optimizations where the us-ascii is converted before
           // calling ICU.
         // The string may shrink or expand after the convert.         // The string may shrink or expand after the convert.
  
         int32_t sz = size();          //// First calculate size of resulting string. u_strToLower() returns
         UChar* destbuf = new UChar[sz + 1];          //// only the size when zero is passed as the destination size argument.
         const UChar* srcbuf = (const UChar *)getChar16Data();  
         UErrorCode err = U_ZERO_ERROR;         UErrorCode err = U_ZERO_ERROR;
  
         int32_t needed = u_strToLower(destbuf, sz + 1 , srcbuf, sz, NULL, &err);          int32_t newSize = u_strToLower(
         if (err == U_BUFFER_OVERFLOW_ERROR)              NULL, 0, (UChar*)_rep->data, _rep->size, NULL, &err);
         {  
           delete [] destbuf;  
           destbuf = new UChar[needed + 1];  
           err = U_ZERO_ERROR;           err = U_ZERO_ERROR;
           u_strToLower(destbuf, needed + 1 , srcbuf, sz, NULL, &err);  
         }  
         if (U_FAILURE(err))  
         {  
             delete [] destbuf;  
             throw Exception(u_errorName(err));  
         }  
  
         if (needed == sz)          //// Reserve enough space for the result.
         {  
             Char16* from = (Char16*)destbuf;          if ((Uint32)newSize > _rep->cap)
             for (Char16* to = &_rep->c16a[0]; *to; to++, from++)              _reserve(_rep, newSize);
             {  
               *to = *from;          //// Perform the conversion (overlapping buffers are allowed).
             }  
         }  
         else  
         {  
             assign((Char16 *)destbuf, needed);  
         }  
  
         delete [] destbuf;          u_strToLower((UChar*)_rep->data, newSize,
               (UChar*)_rep->data, _rep->size, NULL, &err);
   
           _rep->size = newSize;
           return;
     }     }
     else  
 #endif  #endif /* PEGASUS_HAS_ICU */
     {  
         for (Char16* p = &_rep->c16a[0]; *p; p++)      if (_rep->refs.get() != 1)
           _rep = StringRep::copyOnWrite(_rep);
   
       Uint16* p = _rep->data;
       size_t n = _rep->size;
   
       for (; n--; p++)
         {         {
             if (*p <= PEGASUS_MAX_PRINTABLE_CHAR)          if (!(*p & 0xFF00))
                 *p = tolower(*p);              *p = _toLower(*p);
         }  
     }     }
 } }
  
 void String::toUpper() void String::toUpper()
 { {
 #ifdef PEGASUS_HAS_ICU #ifdef PEGASUS_HAS_ICU
   
     if (InitializeICU::initICUSuccessful())     if (InitializeICU::initICUSuccessful())
     {     {
           if (_rep->refs.get() != 1)
               _rep = StringRep::copyOnWrite(_rep);
   
         // This will do a locale-insensitive, but context-sensitive convert.         // This will do a locale-insensitive, but context-sensitive convert.
         // Context-sensitive prevents any optimizations that try to          // Since context-sensitive casing looks at adjacent chars, this
         // convert just the ascii before calling ICU.          // prevents optimizations where the us-ascii is converted before
           // calling ICU.
         // The string may shrink or expand after the convert.         // The string may shrink or expand after the convert.
  
         int32_t sz = size();          //// First calculate size of resulting string. u_strToUpper() returns
         UChar* destbuf = new UChar[sz + 1];          //// only the size when zero is passed as the destination size argument.
         const UChar* srcbuf = (const UChar *)getChar16Data();  
         UErrorCode err = U_ZERO_ERROR;         UErrorCode err = U_ZERO_ERROR;
  
         int32_t needed = u_strToUpper(destbuf, sz + 1 , srcbuf, sz, NULL, &err);          int32_t newSize = u_strToUpper(
         if (err == U_BUFFER_OVERFLOW_ERROR)              NULL, 0, (UChar*)_rep->data, _rep->size, NULL, &err);
         {  
           delete [] destbuf;  
           destbuf = new UChar[needed + 1];  
           err = U_ZERO_ERROR;           err = U_ZERO_ERROR;
           u_strToUpper(destbuf, needed + 1 , srcbuf, sz, NULL, &err);  
         }  
         if (U_FAILURE(err))  
         {  
             delete [] destbuf;  
             throw Exception(u_errorName(err));  
         }  
  
         if (needed == sz)          //// Reserve enough space for the result.
         {  
             Char16* from = (Char16*)destbuf;  
             for (Char16* to = &_rep->c16a[0]; *to; to++, from++)  
             {  
               *to = *from;  
             }  
         }  
         else  
         {  
             assign((Char16 *)destbuf, needed);  
         }  
  
         delete [] destbuf;          if ((Uint32)newSize > _rep->cap)
     }              _reserve(_rep, newSize);
     else  
 #endif          //// Perform the conversion (overlapping buffers are allowed).
     {  
         for (Char16* p = &_rep->c16a[0]; *p; p++)          u_strToUpper((UChar*)_rep->data, newSize,
         {              (UChar*)_rep->data, _rep->size, NULL, &err);
             if (*p <= PEGASUS_MAX_PRINTABLE_CHAR)  
                 *p = toupper(*p);          _rep->size = newSize;
         }  
           return;
     }     }
   
   #endif /* PEGASUS_HAS_ICU */
   
       if (_rep->refs.get() != 1)
           _rep = StringRep::copyOnWrite(_rep);
   
       Uint16* p = _rep->data;
       size_t n = _rep->size;
   
       for (; n--; p++)
           *p = _toUpper(*p);
 } }
  
 int String::compare(const String& s1, const String& s2, Uint32 n) int String::compare(const String& s1, const String& s2, Uint32 n)
 { {
     const Char16* s1c16 = s1.getChar16Data();      const Uint16* p1 = s1._rep->data;
     const Char16* s2c16 = s2.getChar16Data();      const Uint16* p2 = s2._rep->data;
  
     while (n--)     while (n--)
     {     {
         int r = *s1c16++ - *s2c16++;          int r = *p1++ - *p2++;
   
         if (r)         if (r)
           {
             return r;             return r;
     }     }
           else if (!p1[-1])
           {
               // We must have encountered a null terminator in both s1 and s2
               return 0;
           }
       }
     return 0;     return 0;
 } }
  
 int String::compare(const String& s1, const String& s2) int String::compare(const String& s1, const String& s2)
 { {
     const Char16* s1c16 = s1.getChar16Data();      return _compare(s1._rep->data, s2._rep->data);
     const Char16* s2c16 = s2.getChar16Data();  
   
     while (*s1c16 && *s2c16)  
     {  
         int r = *s1c16++ - *s2c16++;  
   
         if (r)  
             return r;  
     }     }
  
     if (*s2c16)  int String::compare(const String& s1, const char* s2)
         return -1;  {
     else if (*s1c16)      _checkNullPointer(s2);
         return 1;  
  
     return 0;  #ifdef PEGASUS_STRING_NO_UTF8
       return _compareNoUTF8(s1._rep->data, s2);
   #else
       // ATTN: optimize this!
       return String::compare(s1, String(s2));
   #endif
 } }
  
 int String::compareNoCase(const String& s1, const String& s2)  int String::compareNoCase(const String& str1, const String& str2)
 { {
 #ifdef PEGASUS_HAS_ICU #ifdef PEGASUS_HAS_ICU
   
     if (InitializeICU::initICUSuccessful())     if (InitializeICU::initICUSuccessful())
     {     {
         return  u_strcasecmp((const UChar*)s1.getChar16Data(),          return  u_strcasecmp(
                              (const UChar*)s2.getChar16Data(),              (const UChar*)str1._rep->data,
                              U_FOLD_CASE_DEFAULT);              (const UChar*)str2._rep->data,
               U_FOLD_CASE_DEFAULT
               );
     }     }
 #endif  
     const Char16* _s1 = s1.getChar16Data();  
     const Char16* _s2 = s2.getChar16Data();  
  
     while (*_s1 && *_s2)  #endif /* PEGASUS_HAS_ICU */
     {  
         int r;  
  
         if (*_s1 <= PEGASUS_MAX_PRINTABLE_CHAR &&      const Uint16* s1 = str1._rep->data;
             *_s2 <= PEGASUS_MAX_PRINTABLE_CHAR)      const Uint16* s2 = str2._rep->data;
         {  
             r = tolower(*_s1++) - tolower(*_s2++);      while (*s1 && *s2)
         }  
         else  
         {         {
             r = *_s1++ - *_s2++;          int r = _toLower(*s1++) - _toLower(*s2++);
         }  
  
         if (r)         if (r)
             return r;             return r;
     }     }
  
     if (*_s2)      if (*s2)
         return -1;         return -1;
     else if (*_s1)      else if (*s1)
         return 1;         return 1;
  
     return 0;     return 0;
 } }
  
 Boolean String::equal(const String& str1, const String& str2)  Boolean StringEqualNoCase(const String& s1, const String& s2)
 { {
     return String::compare(str1, str2) == 0;  #ifdef PEGASUS_HAS_ICU
 }  
       return String::compareNoCase(s1, s2) == 0;
  
 Boolean String::equalNoCase(const String& str1, const String& str2)  #else /* PEGASUS_HAS_ICU */
   
       // The following employs loop unrolling for efficiency. Please do not
       // eliminate.
   
       Uint16* p = (Uint16*)s1.getChar16Data();
       Uint16* q = (Uint16*)s2.getChar16Data();
       Uint32 n = s2.size();
   
       while (n >= 8)
       {
           if (((p[0] - q[0]) && (_toUpper(p[0]) - _toUpper(q[0]))) ||
               ((p[1] - q[1]) && (_toUpper(p[1]) - _toUpper(q[1]))) ||
               ((p[2] - q[2]) && (_toUpper(p[2]) - _toUpper(q[2]))) ||
               ((p[3] - q[3]) && (_toUpper(p[3]) - _toUpper(q[3]))) ||
               ((p[4] - q[4]) && (_toUpper(p[4]) - _toUpper(q[4]))) ||
               ((p[5] - q[5]) && (_toUpper(p[5]) - _toUpper(q[5]))) ||
               ((p[6] - q[6]) && (_toUpper(p[6]) - _toUpper(q[6]))) ||
               ((p[7] - q[7]) && (_toUpper(p[7]) - _toUpper(q[7]))))
 { {
 #ifdef PEGASUS_HAS_ICU  
     return  compareNoCase(str1, str2) == 0;  
 #else  
     if (str1.size() != str2.size())  
         return false;         return false;
           }
  
     const Char16* p = str1.getChar16Data();          n -= 8;
     const Char16* q = str2.getChar16Data();          p += 8;
           q += 8;
     Uint32 n = str1.size();      }
  
     while (n--)      while (n >= 4)
     {     {
         if (*p <= PEGASUS_MAX_PRINTABLE_CHAR &&          if (((p[0] - q[0]) && (_toUpper(p[0]) - _toUpper(q[0]))) ||
             *q <= PEGASUS_MAX_PRINTABLE_CHAR)              ((p[1] - q[1]) && (_toUpper(p[1]) - _toUpper(q[1]))) ||
               ((p[2] - q[2]) && (_toUpper(p[2]) - _toUpper(q[2]))) ||
               ((p[3] - q[3]) && (_toUpper(p[3]) - _toUpper(q[3]))))
         {         {
             if (tolower(*p++) != tolower(*q++))  
                 return false;                 return false;
         }         }
         else if (*p++ != *q++)  
           n -= 4;
           p += 4;
           q += 4;
       }
   
       while (n--)
       {
           if (((p[0] - q[0]) && (_toUpper(p[0]) - _toUpper(q[0]))))
             return false;             return false;
   
           p++;
           q++;
     }     }
  
     return true;     return true;
 #endif  
 }  
  
   #endif /* PEGASUS_HAS_ICU */
   }
  
 CString String::getCString() const  Boolean String::equalNoCase(const String& s1, const char* s2)
 { {
     Uint32 n = 3*size() + 1;      _checkNullPointer(s2);
     char* str = new char[n];  
  
     const Char16* msg16 = getChar16Data();  #if defined(PEGASUS_HAS_ICU)
  
     const Uint16 *strsrc = (Uint16 *)msg16;      return String::equalNoCase(s1, String(s2));
     Uint16 *endsrc = (Uint16 *)&msg16[size()+1];  
  
     Uint8 *strtgt = (Uint8 *)str;  #elif defined(PEGASUS_STRING_NO_UTF8)
     Uint8 *endtgt = (Uint8 *)&str[n];  
  
     UTF16toUTF8 (&strsrc,      const Uint16* p1 = (Uint16*)s1._rep->data;
                  endsrc,      const char* p2 = s2;
                  &strtgt,      size_t n = s1._rep->size;
                  endtgt);  
  
         char* str1 = new char[strlen(str)+1];      while (n--)
         strcpy(str1,str);      {
         delete [] str;          if (!*p2)
               return false;
  
     return CString(str1);          if (_toUpper(*p1++) != _toUpperTable[int(*p2++)])
               return false;
 } }
  
 #if 0      if (*p2)
 // ATTN-RK-P3-20020603: This code is not completely correct          return false;
  // Wildcard String matching function that may be useful in the future  
 // The following code was provided by Bob Blair.  
   
 /* _StringMatch Match input MatchString against a GLOB style pattern  
        Note that MatchChar is the char type so that this source  
        in portable to different string types. This is an internal function  
  
   Results: The return value is 1 if string matches pattern, and      return true;
         0 otherwise.  The matching operation permits the following  
         special characters in the pattern: *?\[] (see the manual  
         entry for details on what these mean).  
  
   #else /* PEGASUS_HAS_ICU */
  
   Side effects: None.      // ATTN: optimize this!
  */      return String::equalNoCase(s1, String(s2));
  
 /* MatchChar defined as a separate entity because this function source used  #endif /* PEGASUS_HAS_ICU */
     elsewhere was an unsigned char *. Here we use Uint16 to  maintain 16 bit  }
     size.  
 */  
 typedef Uint16 MatchChar;  
  
 inline Uint16 _ToLower(Uint16 ch)  Boolean String::equal(const String& s1, const String& s2)
 { {
     // ICU_TODO:  If ICU is available we should do this the correct way.      return (s1._rep == s2._rep) ||
     return ch <= PEGASUS_MAX_PRINTABLE_CHAR ? tolower(char(ch)) : ch;          ((s1._rep->size == s2._rep->size) &&
            memcmp(s1._rep->data,
                   s2._rep->data,
                   s1._rep->size * sizeof(Uint16)) == 0);
 } }
  
 inline Boolean _Equal(MatchChar ch1, MatchChar ch2, int nocase)  void String::appendPrintf(const char* format, ...)
 {  {
     // ICU_TODO:  If ICU is available we should do this the correct way.      va_list ap;
     if (nocase)      va_start(ap, format);
         return _ToLower(ch1) == _ToLower(ch2);  
       // Format into allocated memory
     return ch1 == ch2;      ////char* rtnCharPtr = _charVPrintf(format, ap);
 }  
       // Iniitial allocation size.  This is a guess assuming that
       // most printfs are one or two lines long
 static const MatchChar *      int allocSize = 256;
 _matchrange(const MatchChar *range, MatchChar c, int nocase)      int rtnSize;
 {      char *p;
   const MatchChar *p = range;  
   const MatchChar *rstart = range + 1;      // initial allocate for output
   const MatchChar *rend = 0;      if ((p = (char*)malloc(allocSize)) == NULL)
   MatchChar compchar;  
   
   for (rend = rstart; *rend && *rend != ']'; rend++);  
   if (*rend == ']') {  // if there is an end to this pattern  
     for (compchar = *rstart; rstart != rend; rstart++) {  
       if (_Equal(*rstart, c, nocase))  
         return ++rend;  
       if (*rstart == '-') {  
         rstart++;  
         if (c >= compchar && c <= *rstart)  
           return ++rend;  
       }  
     }  
   }  
   return (const MatchChar *)0;  
 }  
   
 static int  
 _StringMatch(  
     const MatchChar *testString,  
     const MatchChar *pattern,  
     int nocase )                /* Ignore case if this is true */  
 {  
   const MatchChar *pat = pattern;  
   const MatchChar *str = testString;  
   unsigned int done = 0;  
   unsigned int res = 0;  // the result: 1 == match  
   
   while (!done) { // main loop walks through pattern and test string  
     //cerr << "Comparing <" << *pat << "> and <" << *str << ">" << endl;  
     if (!*pat) {                                         //end of pattern  
       done = 1;                                          // we're done  
       if (!*str)                                         //end of test, too?  
         res = 1;                                         // then we matched  
     } else {                                             //Not end of pattern  
       if (!*str) {                                       // but end of test  
         done = 1;                                        // We're done  
         if (*pat == '*')                                 // If pattern openends  
           res = 1;                                       //  then we matched  
       } else {                                           //Not end of test  
         if (*pat == '*') {                               //Ambiguuity found  
           if (!*++pat) {                                 //and it ends pattern  
             done = 1;                                    //  then we're done  
             res = 1;                                     //  and match  
           } else {                                       //if it doesn't end  
             while (!done) {                              //  until we're done  
               if (_StringMatch(str, pat, nocase)) {      //  we recurse  
                 done = 1;                                //if it recurses true  
                 res = 1;                                 //  we done and match  
               } else {                                   //it recurses false  
                 if (!*str)                               // see if test is done  
                   done = 1;                              //  yes: we done  
                 else                                     // not done:  
                   str++;                                 //   keep testing  
               } // end test on recursive call  
             } // end looping on recursive calls  
           } // end logic when pattern is ambiguous  
         } else {                                         //pattern not ambiguus  
           if (*pat == '?') {                             //pattern is 'any'  
             pat++, str++;                                //  so move along  
           } else if (*pat == '[') {                      //see if it's a range  
             pat = _matchrange(pat, *str, nocase);         // and is a match  
             if (!pat) {                                  //It is not a match  
               done = 1;                                  //  we're done  
               res = 0;                                   //  no match  
             } else {                                     //Range matches  
               str++, pat++;                              //  keep going  
             }  
           } else {               // only case left is individual characters  
             if (!_Equal(*pat++, *str++, nocase))         // if they don't match  
               done = 1;                                  //   bail.  
           }  
         }  // end ("pattern is not ambiguous (*)" logic  
       } // end logic when pattern and string still have data  
     } // end logic when pattern still has data  
   } // end main loop  
   return res;  
 }  
   
   
     /** match matches a string against a GLOB style pattern.  
         Return trues if the String parameter matches the pattern. C-Shell style  
         glob matching is used.  
         @param str String to be matched against the pattern  
         @param pattern Pattern to use in the match  
         @return Boolean true if str matches pattern  
         The pattern definition is as follows:  
         <pre>  
         *             Matches any number of any characters  
         ?             Match exactly one character  
         [chars]       Match any character in chars  
         [chara-charb] Match any character in the range between chara and charb  
         </pre>  
         The literal characters *, ?, [, ] can be included in a string by  
         escaping them with backslash "\".  Ranges of characters can be concatenated.  
         <pre>  
         examples:  
         Boolean result = String::match("This is a test", "*is*");  
         Boolean works =  String::match("abcdef123", "*[0-9]");  
         </pre>  
     */  
 Boolean String::match(const String& str, const String& pattern)  
 { {
     return _StringMatch(          return;
         (Uint16*)str.getChar16Data(), (Uint16*)pattern.getChar16Data(), 0) != 0;  
 } }
  
     /** matchNoCase Matches a String against a GLOB style pattern independent      // repeat formatting  with increased realloc until it works.
         of case.      do
         Returns true if the str parameter matches the pattern. C-Shell style  
         glob matching is used. Ignore case in all comparisons. Case is  
         ignored in the match.  
         @parm str String containing the string to be matched\  
         @parm pattern GLOB style patterh to use in the match.  
         @return Boolean true if str matches patterh  
         @see match  
     */  
 Boolean String::matchNoCase(const String& str, const String& pattern)  
 { {
     return _StringMatch(          rtnSize = vsnprintf(p, allocSize, format, ap);
         (Uint16*)str.getChar16Data(), (Uint16*)pattern.getChar16Data(), 1) != 0;  
           // return if successful; i.e. if not negative and
           // returns less than allocated size.
           if (rtnSize > -1 && rtnSize < allocSize)
           {
               break;
 } }
 #endif  
  
           // increment alloc size. Positive return is
           // expected size and negative is error.
           allocSize = (rtnSize > -1)? (rtnSize + 1) : allocSize * 2;
  
 ///////////////////////////////////////////////////////////////////////////////      } while((p = (char*)peg_inln_realloc(p, allocSize)) != NULL);
 //  
 // String-related functions  
 //  
 ///////////////////////////////////////////////////////////////////////////////  
  
 Boolean operator==(const String& str1, const String& str2)      // get here only with error in malloc.
 {  
     return String::equal(str1, str2);      va_end(ap);
   
       // Free allocated memory append printf output to current string
       append(p, rtnSize);
       free(p);
 } }
  
 Boolean operator==(const String& str1, const char* str2)  Boolean String::equal(const String& s1, const char* s2)
 { {
     return String::equal(str1, str2);  #ifdef PEGASUS_STRING_NO_UTF8
 }  
       _checkNullPointer(s2);
  
 Boolean operator==(const char* str1, const String& str2)      const Uint16* p = (Uint16*)s1._rep->data;
       const char* q = s2;
   
       while (*p && *q)
 { {
     return String::equal(str1, str2);          if (*p++ != Uint16(*q++))
               return false;
 } }
  
 Boolean operator!=(const String& str1, const String& str2)      return !(*p || *q);
 {  
     return !String::equal(str1, str2);  #else /* PEGASUS_STRING_NO_UTF8 */
   
       return String::equal(s1, String(s2));
   
   #endif /* PEGASUS_STRING_NO_UTF8 */
 } }
  
 PEGASUS_STD(ostream)& operator<<(PEGASUS_STD(ostream)& os, const String& str) PEGASUS_STD(ostream)& operator<<(PEGASUS_STD(ostream)& os, const String& str)
 { {
   #if defined(PEGASUS_HAS_ICU)
  
 #if defined(PEGASUS_OS_OS400)  
     CString cstr = str.getCString();  
     const char* utf8str = cstr;  
   
     os << utf8str;  
   
 #elif defined(PEGASUS_HAS_ICU)  
     if (InitializeICU::initICUSuccessful())     if (InitializeICU::initICUSuccessful())
     {     {
         char *buf = NULL;         char *buf = NULL;
         const int size = str.size() * 6;         const int size = str.size() * 6;
         UnicodeString UniStr((const UChar *)str.getChar16Data(), (int32_t)str.size());          UnicodeString UniStr(
               (const UChar *)str.getChar16Data(), (int32_t)str.size());
         Uint32 bufsize = UniStr.extract(0,size,buf);         Uint32 bufsize = UniStr.extract(0,size,buf);
   
         buf = new char[bufsize+1];         buf = new char[bufsize+1];
         UniStr.extract(0,bufsize,buf);         UniStr.extract(0,bufsize,buf);
         os << buf;         os << buf;
         os.flush();         os.flush();
         delete [] buf;         delete [] buf;
           return os;
     }     }
     else  
 #endif // End of PEGASUS_HAS_ICU #else leg.  #endif  // PEGASUS_HAS_ICU
     {  
         for (Uint32 i = 0, n = str.size(); i < n; i++)         for (Uint32 i = 0, n = str.size(); i < n; i++)
         {         {
                 Uint16 code = str[i];                 Uint16 code = str[i];
  
                 if (code > 0 && code <= PEGASUS_MAX_PRINTABLE_CHAR)          if (code > 0 && !(code & 0xFF00))
                 {  
                  os << char(code);                  os << char(code);
                 }  
                 else                 else
                 {                 {
                 // Print in hex format:                 // Print in hex format:
Line 1025 
Line 1249 
                 os << buffer;                 os << buffer;
                 }                 }
         }         }
     }  
  
     return os;     return os;
 } }
  
 String operator+(const String& str1, const String& str2)  void StringAppendCharAux(StringRep*& _rep)
   {
       StringRep* tmp;
   
       if (_rep->cap)
       {
           tmp = StringRep::alloc(2 * _rep->cap);
           tmp->size = _rep->size;
           _copy(tmp->data, _rep->data, _rep->size);
       }
       else
 { {
     return String(str1).append(str2);          tmp = StringRep::alloc(8);
           tmp->size = 0;
       }
   
       StringRep::unref(_rep);
       _rep = tmp;
 } }
  
 Boolean operator<(const String& str1, const String& str2)  void AssignASCII(String& s, const char* str, Uint32 n)
 { {
     return String::compare(str1, str2) < 0;      class StringLayout
       {
       public:
           StringRep* rep;
       };
   
       StringLayout* that = reinterpret_cast<StringLayout*>(&s);
   
       _checkNullPointer(str);
   
       if (n > that->rep->cap || that->rep->refs.get() != 1)
       {
           StringRep::unref(that->rep);
           that->rep = StringRep::alloc(n);
 } }
  
 Boolean operator<=(const String& str1, const String& str2)      _copy(that->rep->data, str, n);
       that->rep->size = n;
       that->rep->data[that->rep->size] = 0;
   }
   
   PEGASUS_NAMESPACE_END
   
   /*
   ================================================================================
   
   String optimizations:
   
       1.  Added mechanism allowing certain functions to be inlined only when
           used by internal Pegasus modules. External modules (i.e., providers)
           link to a non-inline version, which allows for binary compatibility.
   
       2.  Implemented copy-on-write with atomic increment/decrement. This
           yieled a 10% improvement for the 'gc' benchmark and a 11% improvment
           for the 'ni1000' benchmark.
   
       3.  Employed loop unrolling in several places. For example, see:
   
               static Uint16* _find(const Uint16* s, size_t n, Uint16 c);
   
       4.  Used the "empty-rep" optimization (described in whitepaper from the
           GCC Developers Summit). This reduced default construction to a simple
           pointer assignment.
   
               inline String::String() : _rep(&_emptyRep) { }
   
       5.  Implemented Uint16 versions of toupper() and tolower() using tables.
           For example:
   
               static const char _upper[] =
               {
                   0,1,2,...255
               };
   
               inline Uint16 _toUpper(Uint16 x)
 { {
     return String::compare(str1, str2) <= 0;                  return (x & 0xFF00) ? x : _upper[x];
 } }
  
 Boolean operator>(const String& str1, const String& str2)          This outperforms the system implementation by avoiding an anding
           operation.
   
       6.  Implemented char* version of the following member functions to
           eliminate unecessary creation of anonymous string objects
           (temporaries).
   
               String(const String& s1, const char* s2);
               String(const char* s1, const String& s2);
               String& String::operator=(const char* str);
               Uint32 String::find(const char* s) const;
               bool String::equal(const String& s1, const char* s2);
               static int String::compare(const String& s1, const char* s2);
               String& String::append(const char* str);
               String& String::append(const char* str, Uint32 size);
               static bool String::equalNoCase(const String& s1, const char* s2);
               String& operator=(const char* str)
               String& String::assign(const char* str)
               String& String::append(const char* str)
               Boolean operator==(const String& s1, const char* s2)
               Boolean operator==(const char* s1, const String& s2)
               Boolean operator!=(const String& s1, const char* s2)
               Boolean operator!=(const char* s1, const String& s2)
               Boolean operator<(const String& s1, const char* s2)
               Boolean operator<(const char* s1, const String& s2)
               Boolean operator>(const String& s1, const char* s2)
               Boolean operator>(const char* s1, const String& s2)
               Boolean operator<=(const String& s1, const char* s2)
               Boolean operator<=(const char* s1, const String& s2)
               Boolean operator>=(const String& s1, const char* s2)
               Boolean operator>=(const char* s1, const String& s2)
               String operator+(const String& s1, const char* s2)
               String operator+(const char* s1, const String& s2)
   
       7.  Optimized _roundUpToPow2(), used in rounding the capacity to the next
           power of two (algorithm from the book "Hacker's Delight").
   
               static Uint32 _roundUpToPow2(Uint32 x)
 { {
     return String::compare(str1, str2) > 0;                  if (x < 8)
                       return 8;
   
                   x--;
                   x |= (x >> 1);
                   x |= (x >> 2);
                   x |= (x >> 4);
                   x |= (x >> 8);
                   x |= (x >> 16);
                   x++;
   
                   return x;
 } }
  
 Boolean operator>=(const String& str1, const String& str2)      8.  Implemented "concatenating constructors" to eliminate temporaries
           created by operator+(). This scheme employs the "return-value
           optimization" described by Stan Lippman.
   
               inline String operator+(const String& s1, const String& s2)
 { {
     return String::compare(str1, str2) >= 0;                  return String(s1, s2, 0);
 } }
  
 PEGASUS_NAMESPACE_END      9.  Experimented to find the optimial initial size for a short string.
           Eight seems to offer the best tradeoff between space and time.
   
       10. Inlined all members of the Char16 class.
   
       11. Used Uint16 internally in the String class. This showed no improvememnt
           since Char16 was already fully inlined and was essentially reduced to
           Uint16 in any case.
   
       12. Implemented conditional logic (#if) allowing error checking logic to
           be excluded to better performance. Examples include bounds checking
           and null-pointer checking.
   
       13. Used memcpy() and memcmp() where possible. These are implemented using
           the rep family of intructions under Intel and are much faster.
   
       14. Used loop unrolling, jump-tables, and short-circuiting to reduce UTF8
           copy routine overhead.
   
       15. Added ASCII7 form of the constructor and assign().
   
               String s("hello world", String::ASCII7);
   
               s.assignASCII7("hello world");
   
           This avoids slower UTF8 processing when not needed.
   
   ================================================================================
   */


Legend:
Removed from v.1.109  
changed lines
  Added in v.1.141

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2