(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.90 and 1.111.6.15

version 1.90, 2004/04/08 14:45:18 version 1.111.6.15, 2005/10/14 14:09:29
Line 1 
Line 1 
 //%2003////////////////////////////////////////////////////////////////////////  //%2005////////////////////////////////////////////////////////////////////////
 // //
 // Copyright (c) 2000, 2001, 2002  BMC Software, Hewlett-Packard Development  // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
 // Company, L. P., IBM Corp., The Open Group, Tivoli Systems.  // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L. P.; // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L. P.;
 // IBM Corp.; EMC Corporation, The Open Group. // IBM Corp.; EMC Corporation, The Open Group.
   // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
   // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
   // 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 copy
 // of this software and associated documentation files (the "Software"), to // of this software and associated documentation files (the "Software"), to
Line 23 
Line 27 
 // //
 //============================================================================== //==============================================================================
 // //
 // Author: Mike Brasher (mbrasher@bmc.com)  // Author: Mike Brasher (mbrasher@austin.rr.com)
 // //
 // Modified By: Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com)  // Modified By:
   //     Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com)
   //     Josephine Eskaline Joyce, IBM (jojustin@in.ibm.com) for Bug#3297
   //     David Dillard, VERITAS Software Corp. (david.dillard@veritas.com)
   //     Mike Brasher (mike-brasher@austin.rr.com)
 // //
 //%///////////////////////////////////////////////////////////////////////////// //%/////////////////////////////////////////////////////////////////////////////
  
   #include <cassert>
 #include <cctype>  
 #include <cstring>  
 #include "String.h"  
 #include "Array.h"  
 #include "InternalException.h" #include "InternalException.h"
 #include <iostream>  
 #include <fstream>  
 #ifdef PEGASUS_USE_DEPRECATED_INTERFACES  
 #include "System.h"  // for strcasecmp  
 #endif  
   
 #include "CommonUTF.h" #include "CommonUTF.h"
   #include "MessageLoader.h"
   #include "StringRep.h"
  
 #ifdef PEGASUS_HAS_ICU #ifdef PEGASUS_HAS_ICU
 #include <unicode/unistr.h>  #include <unicode/ustring.h>
   #include <unicode/uchar.h>
 #endif #endif
  
 PEGASUS_USING_STD;  
   
 PEGASUS_NAMESPACE_BEGIN PEGASUS_NAMESPACE_BEGIN
  
 ///////////////////////////////////////////////////////////////////////////////  //==============================================================================
   //
   // Compile-time macros (undefined by default).
 // //
 // CString  //     PEGASUS_STRING_NO_THROW -- suppresses throwing of exceptions
 // //
 ///////////////////////////////////////////////////////////////////////////////  //     PEGASUS_STRING_NO_UTF8 -- don't generate slower UTF8 code.
   //
   //==============================================================================
  
 CString::CString()  //==============================================================================
     : _rep(0)  //
   // File-scope definitions:
   //
   //==============================================================================
   
   // Note: this table is much faster than the system toupper(). Please do not
   // change.
   
   const Uint8 _toUpperTable[256] =
 { {
 }      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,
   };
   
   // Note: this table is much faster than the system tulower(). Please do not
   // change.
  
 CString::CString(const CString& cstr)  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)  
     {     {
         delete [] (char*)_rep;  #ifndef PEGASUS_STRING_NO_THROW
   
       if (x > 0x0FFFFFFF)
           throw PEGASUS_STD(bad_alloc)();
   
   #endif
   
       if (x < 8)
           return 8;
   
       x--;
       x |= (x >> 1);
       x |= (x >> 2);
       x |= (x >> 4);
       x |= (x >> 8);
       x |= (x >> 16);
       x++;
   
       return x;
   }
   
   template<class P, class Q>
   static void _copy(P* p, const Q* q, size_t n)
   {
       // The following employs loop unrolling for efficiency. Please do not
       // eliminate.
   
       while (n >= 8)
       {
           p[0] = q[0];
           p[1] = q[1];
           p[2] = q[2];
           p[3] = q[3];
           p[4] = q[4];
           p[5] = q[5];
           p[6] = q[6];
           p[7] = q[7];
           p += 8;
           q += 8;
           n -= 8;
       }
   
       while (n >= 4)
       {
           p[0] = q[0];
           p[1] = q[1];
           p[2] = q[2];
           p[3] = q[3];
           p += 4;
           q += 4;
           n -= 4;
     }     }
   
       while (n--)
           *p++ = *q++;
 } }
  
 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--;
     return *this;  
 } }
  
 CString::operator const char*() const      if (n)
 { {
     return (char*)_rep;          if (*s == c)
               return (Uint16*)s;
           s++;
           n--;
 } }
  
 ///////////////////////////////////////////////////////////////////////////////      if (n && *s == c)
 //          return (Uint16*)s;
 // String  
 //  
 ///////////////////////////////////////////////////////////////////////////////  
   
 const String String::EMPTY = String();  
  
 Uint32 _strnlen(const char* str, Uint32 n)      // Not found!
 {      return 0;
     if (!str)  }
         throw NullPointer();  
  
     for (Uint32 i=0; i<n; i++)  static int _compare(const Uint16* s1, const Uint16* s2)
     {     {
         if (!*str)      while (*s1 && *s2)
         {         {
             return i;          int r = *s1++ - *s2++;
         }  
           if (r)
               return r;
     }     }
  
     return n;      if (*s2)
           return -1;
       else if (*s1)
           return 1;
   
       return 0;
 } }
  
 Uint32 _strnlen(const Char16* str, Uint32 n)  static int _compareNoUTF8(const Uint16* s1, const char* s2)
 { {
     if (!str)      Uint16 c1;
         throw NullPointer();      Uint16 c2;
  
     for (Uint32 i=0; i<n; i++)      do
     {     {
         if (!*str)          c1 = *s1++;
         {          c2 = *s2++;
             return i;  
           if (c1 == 0)
               return c1 - c2;
         }         }
       while (c1 == c2);
   
       return c1 - c2;
     }     }
  
     return n;  static int _compare(const Uint16* s1, const Uint16* s2, size_t n)
   {
       // This should only be called when s1 and s2 have the same length.
   
       while (n-- && (*s1++ - *s2++) == 0)
           ;
   
       return s1[-1] - s2[-1];
 } }
  
 inline Uint32 _StrLen(const char* str)  static inline void _copy(Uint16* s1, const Uint16* s2, size_t n)
 { {
     if (!str)      memcpy(s1, s2, n * sizeof(Uint16));
         throw NullPointer();  }
  
     return strlen(str);  void StringThrowOutOfBounds()
   {
       throw IndexOutOfBoundsException();
 } }
  
 inline Uint32 _StrLen(const Char16* str)  inline void _checkNullPointer(const void* ptr)
 { {
     if (!str)  #ifdef PEGASUS_STRING_NO_THROW
         throw NullPointer();  
  
     Uint32 n = 0;      if (!ptr)
           throw NullPointer();
  
     while (*str++)  #endif
         n++;  }
  
     return n;  static void _StringThrowBadUTF8(Uint32 index)
   {
       MessageLoaderParms parms(
           "Common.String.BAD_UTF8",
           "The byte sequence starting at index $0 "
           "is not valid UTF-8 encoding.",
           index);
       throw Exception(parms);
 } }
  
 class StringRep  static size_t _copyFromUTF8(
       Uint16* dest,
       const char* src,
       size_t n,
       size_t& utf8_error_index)
 { {
 public:      Uint16* p = dest;
     StringRep()      const Uint8* q = (const Uint8*)src;
     {}  
     StringRep(const StringRep& r)  
         : c16a(r.c16a)  
     {}  
     StringRep(const Char16* str)  
         : c16a(str, _StrLen(str) + 1)  
     {}  
  
     Array<Char16> c16a;      // Process leading 7-bit ASCII characters (to avoid UTF8 overhead later).
 };      // Use loop-unrolling.
  
 String::String()      while (n >=8 && ((q[0]|q[1]|q[2]|q[3]|q[4]|q[5]|q[6]|q[7]) & 0x80) == 0)
 { {
     _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];
           p[5] = q[5];
           p[6] = q[6];
           p[7] = q[7];
           p += 8;
           q += 8;
           n -= 8;
 } }
  
 String::String(const String& str)      while (n >=4 && ((q[0]|q[1]|q[2]|q[3]) & 0x80) == 0)
 { {
   if (str._rep != NULL)          p[0] = q[0];
           p[1] = q[1];
           p[2] = q[2];
           p[3] = q[3];
           p += 4;
           q += 4;
           n -= 4;
       }
   
       switch (n)
       {
           case 0:
               return p - dest;
           case 1:
               if (q[0] < 128)
   {   {
     _rep = new StringRep(*str._rep);                  p[0] = q[0];
                   return p + 1 - dest;
   }   }
   else              break;
           case 2:
               if (((q[0]|q[1]) & 0x80) == 0)
   {   {
     _rep = new StringRep();                  p[0] = q[0];
                   p[1] = q[1];
                   return p + 2 - dest;
   }   }
               break;
           case 3:
               if (((q[0]|q[1]|q[2]) & 0x80) == 0)
               {
                   p[0] = q[0];
                   p[1] = q[1];
                   p[2] = q[2];
                   return p + 3 - dest;
               }
               break;
 } }
  
       // Process remaining characters.
  
 String::String(const String& str, Uint32 n)      while (n)
 { {
     _rep = new StringRep;          // Optimize for 7-bit ASCII case.
     assign(str.getChar16Data(), n);  
 }  
  
 String::String(const Char16* str)          if (*q < 128)
 { {
     _rep = new StringRep(str);              *p++ = *q++;
               n--;
 } }
           else
           {
               Uint8 c = UTF_8_COUNT_TRAIL_BYTES(*q) + 1;
  
 String::String(const Char16* str, Uint32 n)              if (c > n || !isValid_U8(q, c) ||
                   UTF8toUTF16(&q, q + c, &p, p + n) != 0)
 { {
     _rep = new StringRep;                  utf8_error_index = q - (const Uint8*)src;
     assign(str, n);                  return size_t(-1);
 } }
  
 String::String(const char* str)              n -= c;
 {          }
     _rep = new StringRep;  
     assign(str);  
 } }
  
 String::String(const char* str, const char* utfFlag)      return p - dest;
   }
   
   // 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)
 { {
     _rep = new StringRep;      // The following employs loop unrolling for efficiency. Please do not
       // eliminate.
  
     if(!memcmp(utfFlag,STRING_FLAG_UTF8,sizeof(STRING_FLAG_UTF8)))      const Uint16* q = src;
       Uint8* p = (Uint8*)dest;
   
       while (n >= 4 && q[0] < 128 && q[1] < 128 && q[2] < 128 && q[3] < 128)
     {     {
         assign(str);          p[0] = q[0];
           p[1] = q[1];
           p[2] = q[2];
           p[3] = q[3];
           p += 4;
           q += 4;
           n -= 4;
     }     }
     else  
       switch (n)
       {
           case 0:
               return p - (Uint8*)dest;
           case 1:
               if (q[0] < 128)
     {     {
         assign(str);                  p[0] = q[0];
                   return p + 1 - (Uint8*)dest;
     }     }
               break;
           case 2:
               if (q[0] < 128 && q[1] < 128)
               {
                   p[0] = q[0];
                   p[1] = q[1];
                   return p + 2 - (Uint8*)dest;
 } }
               break;
 String::String(const char* str, Uint32 n)          case 3:
               if (q[0] < 128 && q[1] < 128 && q[2] < 128)
 { {
     _rep = new StringRep;                  p[0] = q[0];
     assign(str, n);                  p[1] = q[1];
                   p[2] = q[2];
                   return p + 3 - (Uint8*)dest;
               }
               break;
 } }
  
 String::~String()      // If this line was reached, there must be characters greater than 128.
   
       UTF16toUTF8(&q, q + n, &p, p + 3 * n);
   
       return p - (Uint8*)dest;
   }
   
   static inline size_t _convert(
       Uint16* p, const char* q, size_t n, size_t& utf8_error_index)
 { {
     delete _rep;  #ifdef PEGASUS_STRING_NO_UTF8
       _copy(p, q, n);
       return n;
   #else
       return _copyFromUTF8(p, q, n, utf8_error_index);
   #endif
 } }
  
 String& String::operator=(const String& str)  //==============================================================================
   //
   // class CString
   //
   //==============================================================================
   
   CString::CString(const CString& cstr) : _rep(0)
 { {
     if (&str != this)      if (cstr._rep)
     {     {
         assign(str);          size_t n = strlen(cstr._rep) + 1;
           _rep = (char*)operator new(n);
           memcpy(_rep, cstr._rep, n);
     }     }
     return *this;  
 } }
  
 String& String::assign(const String& str)  CString& CString::operator=(const CString& cstr)
 { {
     _rep->c16a = str._rep->c16a;      if (&cstr != this)
     return *this;      {
           if (_rep)
           {
               operator delete(_rep);
               _rep = 0;
 } }
  
 String& String::assign(const Char16* str)          if (cstr._rep)
 { {
     _rep->c16a.clear();              size_t n = strlen(cstr._rep) + 1;
     _rep->c16a.append(str, _StrLen(str) + 1);              _rep = (char*)operator new(n);
     return *this;              memcpy(_rep, cstr._rep, n);
           }
 } }
  
 String& String::assign(const Char16* str, Uint32 n)  
 {  
     _rep->c16a.clear();  
     Uint32 m = _strnlen(str, n);  
     _rep->c16a.append(str, m);  
     _rep->c16a.append('\0');  
     return *this;     return *this;
 } }
  
 String& String::assign(const char* str, Uint32 n)  //==============================================================================
   //
   // class StringRep
   //
   //==============================================================================
   
   StringRep StringRep::_emptyRep;
   
   inline StringRep* StringRep::alloc(size_t cap)
 { {
     char *tmpStr = new char[n+1];  #ifndef PEGASUS_STRING_NO_THROW
     memset(tmpStr,0x00,n+1);  
  
     strncpy(tmpStr,str,n);      // Any string bigger than this is seriously suspect.
     assign(tmpStr);      if (cap > 0x0FFFFFFF)
     delete tmpStr;          throw PEGASUS_STD(bad_alloc)();
  
     return *this;  #endif
   
       StringRep* rep = (StringRep*)::operator new(
           sizeof(StringRep) + cap * sizeof(Uint16));
       rep->cap = cap;
       new(&rep->refs) AtomicInt(1);
   
       return rep;
 } }
  
 void String::clear()  static inline void _reserve(StringRep*& rep, Uint32 cap)
   {
       if (cap > rep->cap || rep->refs.value() != 1)
 { {
     _rep->c16a.clear();          size_t n = _roundUpToPow2(cap);
     _rep->c16a.append('\0');          StringRep* newRep = StringRep::alloc(n);
           newRep->size = rep->size;
           _copy(newRep->data, rep->data, rep->size + 1);
           StringRep::unref(rep);
           rep = newRep;
       }
 } }
  
 void String::reserveCapacity(Uint32 capacity)  StringRep* StringRep::create(const Uint16* data, size_t size)
 { {
     _rep->c16a.reserveCapacity(capacity + 1);      StringRep* rep = StringRep::alloc(size);
       rep->size = size;
       _copy(rep->data, data, size);
       rep->data[size] = '\0';
       return rep;
 } }
  
 Uint32 String::size() const  StringRep* StringRep::copyOnWrite(StringRep* rep)
 { {
     return _rep->c16a.size() - 1;      // 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;
 } }
  
 const Char16* String::getChar16Data() const  StringRep* StringRep::create(const char* data, size_t size)
 { {
     return _rep->c16a.getData();      StringRep* rep = StringRep::alloc(size);
 }      size_t utf8_error_index;
       rep->size = _convert((Uint16*)rep->data, data, size, utf8_error_index);
  
 Char16& String::operator[](Uint32 index)  #ifndef PEGASUS_STRING_NO_THROW
       if (rep->size == size_t(-1))
 { {
     if (index > size())          StringRep::free(rep);
         throw IndexOutOfBoundsException();          _StringThrowBadUTF8(utf8_error_index);
       }
   #endif
   
       rep->data[rep->size] = '\0';
  
     return _rep->c16a[index];      return rep;
 } }
  
 const Char16 String::operator[](Uint32 index) const  Uint32 StringRep::length(const Uint16* str)
 { {
     if (index > size())      // Note: We could unroll this but it is rarely called.
         throw IndexOutOfBoundsException();  
       const Uint16* end = (Uint16*)str;
  
     return _rep->c16a[index];      while (*end++)
           ;
   
       return end - str - 1;
 } }
  
 String& String::append(const Char16& c)  //==============================================================================
   //
   // class String
   //
   //==============================================================================
   
   const String String::EMPTY;
   
   String::String(const String& str, Uint32 n)
 { {
     _rep->c16a.insert(_rep->c16a.size() - 1, c);      _checkBounds(n, str._rep->size);
     return *this;      _rep = StringRep::create(str._rep->data, n);
 } }
  
 String& String::append(const Char16* str, Uint32 n)  String::String(const Char16* str)
 { {
     Uint32 m = _strnlen(str, n);      _checkNullPointer(str);
     _rep->c16a.reserveCapacity(_rep->c16a.size() + m);      _rep = StringRep::create((Uint16*)str, StringRep::length((Uint16*)str));
     _rep->c16a.remove(_rep->c16a.size() - 1);  
     _rep->c16a.append(str, m);  
     _rep->c16a.append('\0');  
     return *this;  
 } }
  
 String& String::append(const String& str)  String::String(const Char16* str, Uint32 n)
 { {
     return append(str.getChar16Data(), str.size());      _checkNullPointer(str);
       _rep = StringRep::create((Uint16*)str, n);
 } }
  
 void String::remove(Uint32 index, Uint32 size)  String::String(const char* str)
 { {
     if (size == PEG_NOT_FOUND)      _checkNullPointer(str);
         size = this->size() - index;  
  
     if (index + size > this->size())      // Set this just in case create() throws an exception.
         throw IndexOutOfBoundsException();      _rep = &StringRep::_emptyRep;
       _rep = StringRep::create(str, strlen(str));
     if (size)  
         _rep->c16a.remove(index, size);  
 } }
  
 String String::subString(Uint32 index, Uint32 length) const  String::String(const char* str, Uint32 n)
 {  
     if (index < size())  
     {     {
         if ((length == PEG_NOT_FOUND) || (length > size() - index))      _checkNullPointer(str);
             length = size() - index;  
  
         return String(getChar16Data() + index, length);      // Set this just in case create() throws an exception.
       _rep = &StringRep::_emptyRep;
       _rep = StringRep::create(str, n);
     }     }
     else  
         return String();  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';
 } }
  
 Uint32 String::find(Char16 c) const  String::String(const String& s1, const char* s2)
 { {
     const Char16* first = getChar16Data();      _checkNullPointer(s2);
       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);
  
     for (const Char16* p = first; *p; p++)  #ifndef PEGASUS_STRING_NO_THROW
       if (tmp == size_t(-1))
     {     {
         if (*p == c)          StringRep::free(_rep);
             return  p - first;          _rep = &StringRep::_emptyRep;
           _StringThrowBadUTF8(utf8_error_index);
     }     }
   #endif
  
     return PEG_NOT_FOUND;      _rep->size = n1 + tmp;
       _rep->data[_rep->size] = '\0';
 } }
  
 Uint32 String::find(Uint32 index, Char16 c) const  String::String(const char* s1, const String& s2)
 { {
     const Char16* data = getChar16Data();      _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);
  
     for (Uint32 i = index, n = size(); i < n; i++)  #ifndef PEGASUS_STRING_NO_THROW
       if (tmp ==  size_t(-1))
     {     {
         if (data[i] == c)          StringRep::free(_rep);
             return i;          _rep = &StringRep::_emptyRep;
           _StringThrowBadUTF8(utf8_error_index);
     }     }
   #endif
  
     return PEG_NOT_FOUND;      _rep->size = n2 + tmp;
       _copy(_rep->data + n1, s2._rep->data, n2);
       _rep->data[_rep->size] = '\0';
 } }
  
 Uint32 String::find(const String& s) const  String& String::assign(const String& str)
 { {
     const Char16* pSubStr = s.getChar16Data();      if (_rep != str._rep)
     const Char16* pStr = getChar16Data();  
     Uint32 subStrLen = s.size();  
     Uint32 strLen = size();  
   
     if (subStrLen > strLen)  
     {     {
         return PEG_NOT_FOUND;          StringRep::unref(_rep);
           StringRep::ref(_rep = str._rep);
     }     }
  
     // loop to find first char match      return *this;
     Uint32 loc = 0;  
     for( ; loc <= (strLen-subStrLen); loc++)  
     {  
         if (*pStr++ == *pSubStr)  // match first char  
         {  
             // point to substr 2nd char  
             const Char16* p = pSubStr + 1;  
   
             // 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;  
 } }
  
 Uint32 String::reverseFind(Char16 c) const  String& String::assign(const Char16* str, Uint32 n)
 { {
     const Char16* first = getChar16Data();      _checkNullPointer(str);
     const Char16* last = getChar16Data() + size();  
  
     while (last != first)      if (n > _rep->cap || _rep->refs.value() != 1)
     {     {
         if (*--last == c)          StringRep::unref(_rep);
             return last - first;          _rep = StringRep::alloc(n);
     }     }
  
     return PEG_NOT_FOUND;      _rep->size = n;
 }      _copy(_rep->data, (Uint16*)str, n);
       _rep->data[n] = '\0';
  
 void String::toLower()      return *this;
 {  
     const char * noLocale = NULL;  
     String::toLower(noLocale);  
 }  
 void String::toLower(const char * strLocale)  
 {  
 #ifdef PEGASUS_HAS_ICU  
     UnicodeString UniStr((const UChar *)_rep->c16a.getData());  
     if(strLocale == NULL)  
     {  
         UniStr.toLower();  
     }     }
     else  
   String& String::assign(const char* str, Uint32 n)
     {     {
         Locale loc(strLocale);      _checkNullPointer(str);
         if(loc.isBogus())  
       if (n > _rep->cap || _rep->refs.value() != 1)
         {         {
             throw InvalidNameException(String(strLocale));          StringRep::unref(_rep);
           _rep = StringRep::alloc(n);
         }         }
         UniStr.toLower(loc);  
     }  
     UniStr.append((UChar)'\0');  
  
     assign((Char16*)UniStr.getBuffer());      size_t utf8_error_index;
 #else      _rep->size = _convert(_rep->data, str, n, utf8_error_index);
     for (Char16* p = &_rep->c16a[0]; *p; p++)  
   #ifndef PEGASUS_STRING_NO_THROW
       if (_rep->size ==  size_t(-1))
     {     {
         if (*p <= PEGASUS_MAX_PRINTABLE_CHAR)          StringRep::free(_rep);
             *p = tolower(*p);          _rep = &StringRep::_emptyRep;
           _StringThrowBadUTF8(utf8_error_index);
     }     }
 #endif #endif
   
       _rep->data[_rep->size] = 0;
   
       return *this;
 } }
  
 void String::toUpper(const char * strLocale)  void String::clear()
 { {
 #ifdef PEGASUS_HAS_ICU      if (_rep->size)
     UnicodeString UniStr((const UChar *)_rep->c16a.getData());      {
     if(strLocale == NULL)          if (_rep->refs.value() == 1)
     {     {
         UniStr.toUpper();              _rep->size = 0;
               _rep->data[0] = '\0';
     }     }
     else     else
     {     {
         Locale loc(strLocale);              StringRep::unref(_rep);
         if(loc.isBogus())              _rep = &StringRep::_emptyRep;
         {          }
             throw InvalidNameException(String(strLocale));  
         }         }
         UniStr.toUpper(loc);  
     }     }
     UniStr.append((UChar)'\0');  
  
     assign((Char16*)UniStr.getBuffer());  void String::reserveCapacity(Uint32 cap)
 #endif  {
       _reserve(_rep, cap);
 } }
  
 int String::compare(const String& s1, const String& s2, Uint32 n)  CString String::getCString() const
 { {
     const Char16* s1c16 = s1.getChar16Data();      // A UTF8 string can have three times as many characters as its UTF16
     const Char16* s2c16 = s2.getChar16Data();      // 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
       // 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 = 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
   }
  
     while (n--)  String& String::append(const Char16* str, Uint32 n)
     {     {
         int r = *s1c16++ - *s2c16++;      _checkNullPointer(str);
  
         if (r)      size_t oldSize = _rep->size;
             return r;      size_t newSize = oldSize + n;
     }      _reserve(_rep, newSize);
       _copy(_rep->data + oldSize, (Uint16*)str, n);
       _rep->size = newSize;
       _rep->data[newSize] = '\0';
  
     return 0;      return *this;
 } }
  
 int String::compare(const String& s1, const String& s2)  String& String::append(const String& str)
 { {
     const Char16* s1c16 = s1.getChar16Data();      return append((Char16*)str._rep->data, str._rep->size);
     const Char16* s2c16 = s2.getChar16Data();  }
  
     while (*s1c16 && *s2c16)  String& String::append(const char* str, Uint32 size)
     {     {
         int r = *s1c16++ - *s2c16++;      _checkNullPointer(str);
  
         if (r)      size_t oldSize = _rep->size;
             return r;      size_t cap = oldSize + size;
     }  
  
     if (*s2c16)      _reserve(_rep, cap);
         return -1;      size_t utf8_error_index;
     else if (*s1c16)      size_t tmp = _convert(
         return 1;          (Uint16*)_rep->data + oldSize, str, size, utf8_error_index);
  
     return 0;  #ifndef PEGASUS_STRING_NO_THROW
       if (tmp ==  size_t(-1))
       {
           StringRep::free(_rep);
           _rep = &StringRep::_emptyRep;
           _StringThrowBadUTF8(utf8_error_index);
 } }
   #endif
  
 int String::compareNoCase(const String& s1, const String& s2)      _rep->size += tmp;
 {      _rep->data[_rep->size] = '\0';
     const char * noLocale = NULL;  
     return String::compareNoCase(s1, s2, noLocale);      return *this;
 } }
  
 int String::compareNoCase(const String& s1, const String& s2,const char * strLocale)  void String::remove(Uint32 index, Uint32 n)
 { {
 #ifdef PEGASUS_HAS_ICU      if (n == PEG_NOT_FOUND)
     UnicodeString UniStr1((const UChar *)s1.getChar16Data(), (int32_t)s1.size());          n = _rep->size - index;
     UnicodeString UniStr2((const UChar *)s2.getChar16Data(), (int32_t)s2.size());  
     if(strLocale == NULL)      _checkBounds(index + n, _rep->size);
     {  
         UniStr1.toLower();      if (_rep->refs.value() != 1)
         UniStr2.toLower();          _rep = StringRep::copyOnWrite(_rep);
   
       assert(index + n <= _rep->size);
   
       size_t rem = _rep->size - (index + n);
       Uint16* data = _rep->data;
   
       if (rem)
           memmove(data + index, data + index + n, rem * sizeof(Uint16));
   
       _rep->size -= n;
       data[_rep->size] = '\0';
     }     }
     else  
   String String::subString(Uint32 index, Uint32 n) const
     {     {
         Locale loc(strLocale);      // Note: this implementation is very permissive but used for
         if(loc.isBogus())      // backwards compatibility.
   
       if (index < _rep->size)
         {         {
             throw InvalidNameException(String(strLocale));          if (n == PEG_NOT_FOUND || n > _rep->size - index)
               n = _rep->size - index;
   
           return String((Char16*)_rep->data + index, n);
         }         }
         UniStr1.toLower(loc);  
         UniStr2.toLower(loc);      return String();
     }     }
     // Note:  the ICU 2.6.1 documentation for UnicodeString::compare( ) is  
     // backwards!  The API actually returns +1 if this is greater than text.  
     // This is why the line below appears wrong based on the 2.6.1 docs.  
     // (ref. bugzilla 1207)  
     return (UniStr1.compare(UniStr2));  
 #else  
     const Char16* _s1 = s1.getChar16Data();  
     const Char16* _s2 = s2.getChar16Data();  
  
     while (*_s1 && *_s2)  Uint32 String::find(Char16 c) const
     {     {
         int r;      Uint16* p = (Uint16*)_find(_rep->data, _rep->size, c);
  
         if (*_s1 <= PEGASUS_MAX_PRINTABLE_CHAR &&      if (p)
             *_s2 <= PEGASUS_MAX_PRINTABLE_CHAR)          return p - _rep->data;
         {  
             r = tolower(*_s1++) - tolower(*_s2++);      return PEG_NOT_FOUND;
         }         }
         else  
   Uint32 String::find(Uint32 index, Char16 c) const
         {         {
             r = *_s1++ - *_s2++;      _checkBounds(index, _rep->size);
         }  
  
         if (r)      if (index >= _rep->size)
             return r;          return PEG_NOT_FOUND;
     }  
  
     if (*_s2)      Uint16* p = (Uint16*)_find(_rep->data + index, _rep->size - index, c);
         return -1;  
     else if (*_s1)  
         return 1;  
  
     return 0;      if (p)
 #endif          return p - _rep->data;
 }  
  
 Boolean String::equal(const String& str1, const String& str2)      return PEG_NOT_FOUND;
 {  
     return String::compare(str1, str2) == 0;  
 } }
  
 Boolean String::equalNoCase(const String& str1, const String& str2)  Uint32 StringFindAux(
       const StringRep* _rep, const Char16* s, Uint32 n)
 { {
     const char * noLocale = NULL;      _checkNullPointer(s);
     return String::equalNoCase(str1, str2, noLocale);  
 }  
  
 Boolean String::equalNoCase(const String& str1, const String& str2,const char * strLocale)      const Uint16* data = _rep->data;
 {      size_t rem = _rep->size;
 #ifdef PEGASUS_HAS_ICU  
     UnicodeString UniStr1((const UChar *)str1.getChar16Data(), (int32_t)str1.size());      while (n <= rem)
     UnicodeString UniStr2((const UChar *)str2.getChar16Data(), (int32_t)str2.size());  
     if(strLocale == NULL)  
     {  
         UniStr1.toLower();  
         UniStr2.toLower();  
     }  
     else  
     {  
         Locale loc(strLocale);  
         if(loc.isBogus())  
         {         {
             throw InvalidNameException(String(strLocale));          Uint16* p = (Uint16*)_find(data, rem, s[0]);
   
           if (!p)
               break;
   
           if (memcmp(p, s, n * sizeof(Uint16)) == 0)
               return p - _rep->data;
   
           p++;
           rem -= p - data;
           data = p;
         }         }
         UniStr1.toLower(loc);  
         UniStr2.toLower(loc);      return PEG_NOT_FOUND;
     }     }
     return (UniStr1 == UniStr2);  
 #else  
     if (str1.size() != str2.size())  
         return false;  
  
     const Char16* p = str1.getChar16Data();  Uint32 String::find(const char* s) const
     const Char16* q = str2.getChar16Data();  {
       _checkNullPointer(s);
  
     Uint32 n = str1.size();      // Note: could optimize away creation of temporary, but this is rarely
       // called.
       return find(String(s));
   }
  
     while (n--)  Uint32 String::reverseFind(Char16 c) const
     {     {
         if (*p <= PEGASUS_MAX_PRINTABLE_CHAR &&      Uint16 x = c;
             *q <= PEGASUS_MAX_PRINTABLE_CHAR)      Uint16* p = _rep->data;
       Uint16* q = _rep->data + _rep->size;
   
       while (q != p)
         {         {
             if (tolower(*p++) != tolower(*q++))          if (*--q == x)
                 return false;              return q - p;
         }  
         else if (*p++ != *q++)  
             return false;  
     }     }
  
     return true;      return PEG_NOT_FOUND;
 #endif  
 } }
  
 // UTF8 specific code:  void String::toLower()
 String& String::assign(const char* str)  
 { {
     _rep->c16a.clear();  #ifdef PEGASUS_HAS_ICU
     Uint32 n = strlen(str) + 1;  
  
     const Uint8 *strsrc = (Uint8 *)str;      if (InitializeICU::initICUSuccessful())
     Uint8 *endsrc = (Uint8 *)&str[n-1];      {
           if (_rep->refs.value() != 1)
               _rep = StringRep::copyOnWrite(_rep);
  
     Char16 *msg16 = new Char16[n];          // This will do a locale-insensitive, but context-sensitive convert.
     Uint16 *strtgt = (Uint16 *)msg16;          // Since context-sensitive casing looks at adjacent chars, this
     Uint16 *endtgt = (Uint16 *)&msg16[n];          // prevents optimizations where the us-ascii is converted before
           // calling ICU.
           // The string may shrink or expand after the convert.
  
     UTF8toUTF16(&strsrc,          //// First calculate size of resulting string. u_strToLower() returns
                 endsrc,          //// only the size when zero is passed as the destination size argument.
                 &strtgt,  
                 endtgt);  
  
     Uint32 count;          UErrorCode err = U_ZERO_ERROR;
  
     for(count = 0; ((msg16[count]) != Char16(0x00)) && (count < (n - 1)); ++count);          int32_t newSize = u_strToLower(
               NULL, 0, (UChar*)_rep->data, _rep->size, NULL, &err);
  
     _rep->c16a.append(msg16, count);          err = U_ZERO_ERROR;
  
     _rep->c16a.append('\0');          //// Reserve enough space for the result.
  
     delete [] msg16;          if ((Uint32)newSize > _rep->cap)
               _reserve(_rep, newSize);
  
     return *this;          //// Perform the conversion (overlapping buffers are allowed).
   
           u_strToLower((UChar*)_rep->data, newSize,
               (UChar*)_rep->data, _rep->size, NULL, &err);
   
           _rep->size = newSize;
           return;
 } }
 // UTF8 specific code:  
 String& String::assignUTF8(const char* str)  #endif /* PEGASUS_HAS_ICU */
   
       if (_rep->refs.value() != 1)
           _rep = StringRep::copyOnWrite(_rep);
   
       Uint16* p = _rep->data;
       size_t n = _rep->size;
   
       for (; n--; p++)
       {
           if (!(*p & 0xFF00))
               *p = _toLower(*p);
       }
   }
   
   void String::toUpper()
 { {
     _rep->c16a.clear();  #ifdef PEGASUS_HAS_ICU
     Uint32 n = strlen(str) + 1;  
  
     const Uint8 *strsrc = (Uint8 *)str;      if (InitializeICU::initICUSuccessful())
     Uint8 *endsrc = (Uint8 *)&str[n-1];      {
           if (_rep->refs.value() != 1)
               _rep = StringRep::copyOnWrite(_rep);
  
     Char16 *msg16 = new Char16[n];          // This will do a locale-insensitive, but context-sensitive convert.
     Uint16 *strtgt = (Uint16 *)msg16;          // Since context-sensitive casing looks at adjacent chars, this
     Uint16 *endtgt = (Uint16 *)&msg16[n];          // prevents optimizations where the us-ascii is converted before
           // calling ICU.
           // The string may shrink or expand after the convert.
  
     UTF8toUTF16(&strsrc,          //// First calculate size of resulting string. u_strToUpper() returns
                 endsrc,          //// only the size when zero is passed as the destination size argument.
                 &strtgt,  
                 endtgt);  
  
     Uint32 count;          UErrorCode err = U_ZERO_ERROR;
  
     for(count = 0; ((msg16[count]) != Char16(0x00)) && (count < (n - 1)); ++count);          int32_t newSize = u_strToUpper(
               NULL, 0, (UChar*)_rep->data, _rep->size, NULL, &err);
  
     _rep->c16a.append(msg16, count);          err = U_ZERO_ERROR;
  
     _rep->c16a.append('\0');          //// Reserve enough space for the result.
  
     delete [] msg16;          if ((Uint32)newSize > _rep->cap)
               _reserve(_rep, newSize);
  
     return *this;          //// Perform the conversion (overlapping buffers are allowed).
 }  
  
 CString String::getCString() const          u_strToUpper((UChar*)_rep->data, newSize,
 {              (UChar*)_rep->data, _rep->size, NULL, &err);
     Uint32 n = 3*size() + 1;  
     char* str = new char[n];  
  
     const Char16* msg16 = getChar16Data();          _rep->size = newSize;
  
     const Uint16 *strsrc = (Uint16 *)msg16;          return;
     Uint16 *endsrc = (Uint16 *)&msg16[size()+1];      }
  
     Uint8 *strtgt = (Uint8 *)str;  #endif /* PEGASUS_HAS_ICU */
     Uint8 *endtgt = (Uint8 *)&str[n];  
  
     UTF16toUTF8 (&strsrc,      if (_rep->refs.value() != 1)
                  endsrc,          _rep = StringRep::copyOnWrite(_rep);
                  &strtgt,  
                  endtgt);  
  
         char* str1 = new char[strlen(str)+1];      Uint16* p = _rep->data;
         strcpy(str1,str);      size_t n = _rep->size;
         delete [] str;  
  
     return CString(str1);      for (; n--; p++)
           *p = _toUpper(*p);
 } }
  
 CString String::getCStringUTF8() const  int String::compare(const String& s1, const String& s2, Uint32 n)
 { {
     Uint32 n = 3*size() + 1;      assert(n <= s1._rep->size);
     char* str = new char[n];      assert(n <= s2._rep->size);
  
     const Char16* msg16 = getChar16Data();      // Ignoring error in which n is greater than s1.size() or s2.size()
       return _compare(s1._rep->data, s2._rep->data, n);
   }
  
     const Uint16 *strsrc = (Uint16 *)msg16;  int String::compare(const String& s1, const String& s2)
     Uint16 *endsrc = (Uint16 *)&msg16[size()+1];  {
       return _compare(s1._rep->data, s2._rep->data);
   }
  
     Uint8 *strtgt = (Uint8 *)str;  int String::compare(const String& s1, const char* s2)
     Uint8 *endtgt = (Uint8 *)&str[n];  {
       _checkNullPointer(s2);
  
     UTF16toUTF8 (&strsrc,  #ifdef PEGASUS_STRING_NO_UTF8
                  endsrc,      return _compareNoUTF8(s1._rep->data, s2);
                  &strtgt,  #else
                  endtgt);      // ATTN: optimize this!
       return String::compare(s1, String(s2));
   #endif
   }
  
         char* str1 = new char[strlen(str)+1];  int String::compareNoCase(const String& str1, const String& str2)
         strcpy(str1,str);  {
         delete [] str;  #ifdef PEGASUS_HAS_ICU
  
     return CString(str1);      if (InitializeICU::initICUSuccessful())
       {
           return  u_strcasecmp(
               str1._rep->data, str2._rep->data, U_FOLD_CASE_DEFAULT);
 } }
  
   #endif /* PEGASUS_HAS_ICU */
  
       const Uint16* s1 = str1._rep->data;
       const Uint16* s2 = str2._rep->data;
  
 #if 0      while (*s1 && *s2)
 // ATTN-RK-P3-20020603: This code is not completely correct      {
  // Wildcard String matching function that may be useful in the future          int r = _toLower(*s1++) - _toLower(*s2++);
 // The following code was provided by Bob Blair.  
  
 /* _StringMatch Match input MatchString against a GLOB style pattern          if (r)
        Note that MatchChar is the char type so that this source              return r;
        in portable to different string types. This is an internal function      }
  
   Results: The return value is 1 if string matches pattern, and      if (*s2)
         0 otherwise.  The matching operation permits the following          return -1;
         special characters in the pattern: *?\[] (see the manual      else if (*s1)
         entry for details on what these mean).          return 1;
  
       return 0;
   }
  
   Side effects: None.  Boolean StringEqualNoCase(const String& s1, const String& s2)
  */  {
   #ifdef PEGASUS_HAS_ICU
  
 /* MatchChar defined as a separate entity because this function source used      return String::compareNoCase(s1, s2) == 0;
     elsewhere was an unsigned char *. Here we use Uint16 to  maintain 16 bit  
     size.  
 */  
 typedef Uint16 MatchChar;  
  
 inline Uint16 _ToLower(Uint16 ch)  #else /* PEGASUS_HAS_ICU */
 {  
     // ICU_TODO:  If ICU is available we should do this the correct way.      // The following employs loop unrolling for efficiency. Please do not
     return ch <= PEGASUS_MAX_PRINTABLE_CHAR ? tolower(char(ch)) : ch;      // eliminate.
 }  
  
 inline Boolean _Equal(MatchChar ch1, MatchChar ch2, int nocase)      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]))))
 { {
     // ICU_TODO:  If ICU is available we should do this the correct way.              return false;
     if (nocase)  
         return _ToLower(ch1) == _ToLower(ch2);  
     else  
         return ch1 == ch2;  
 } }
  
           n -= 8;
           p += 8;
           q += 8;
       }
  
 static const MatchChar *      while (n >= 4)
 _matchrange(const MatchChar *range, MatchChar c, int nocase)  
 { {
   const MatchChar *p = range;          if (((p[0] - q[0]) && (_toUpper(p[0]) - _toUpper(q[0]))) ||
   const MatchChar *rstart = range + 1;              ((p[1] - q[1]) && (_toUpper(p[1]) - _toUpper(q[1]))) ||
   const MatchChar *rend = 0;              ((p[2] - q[2]) && (_toUpper(p[2]) - _toUpper(q[2]))) ||
   MatchChar compchar;              ((p[3] - q[3]) && (_toUpper(p[3]) - _toUpper(q[3]))))
   
   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 false;
         (Uint16*)str.getChar16Data(), (Uint16*)pattern.getChar16Data(), 0) != 0;  
 } }
  
     /** matchNoCase Matches a String against a GLOB style pattern independent          n -= 4;
         of case.          p += 4;
         Returns true if the str parameter matches the pattern. C-Shell style          q += 4;
         glob matching is used. Ignore case in all comparisons. Case is      }
         ignored in the match.  
         @parm str String containing the string to be matched\      while (n--)
         @parm pattern GLOB style patterh to use in the match.  
         @return Boolean true if str matches patterh  
         @SeeAlso match  
     */  
 Boolean String::matchNoCase(const String& str, const String& pattern)  
 { {
     return _StringMatch(          if (((p[0] - q[0]) && (_toUpper(p[0]) - _toUpper(q[0]))))
         (Uint16*)str.getChar16Data(), (Uint16*)pattern.getChar16Data(), 1) != 0;              return false;
   
           p++;
           q++;
 } }
 #endif  
  
       return true;
  
 ///////////////////////////////////////////////////////////////////////////////  #endif /* PEGASUS_HAS_ICU */
 //  }
 // String-related functions  
 //  
 ///////////////////////////////////////////////////////////////////////////////  
  
 Boolean operator==(const String& str1, const String& str2)  Boolean String::equalNoCase(const String& s1, const char* s2)
 { {
     return String::equal(str1, str2);      _checkNullPointer(s2);
 }  
   #if defined(PEGASUS_HAS_ICU)
   
       return String::equalNoCase(s1, String(s2));
   
   #elif defined(PEGASUS_STRING_NO_UTF8)
  
 Boolean operator==(const String& str1, const char* str2)      const Uint16* p1 = (Uint16*)s1._rep->data;
       const char* p2 = s2;
       size_t n = s1._rep->size;
   
       while (n--)
 { {
     return String::equal(str1, str2);          if (!*p2)
               return false;
   
           if (_toUpper(*p1++) != _toUpperTable[int(*p2++)])
               return false;
 } }
  
 Boolean operator==(const char* str1, const String& str2)      if (*p2)
           return false;
   
       return true;
   
   #else /* PEGASUS_HAS_ICU */
   
       // ATTN: optimize this!
       return String::equalNoCase(s1, String(s2));
   
   #endif /* PEGASUS_HAS_ICU */
   }
   
   Boolean String::equal(const String& s1, const String& s2)
 { {
     return String::equal(str1, str2);      return s1._rep->size == s2._rep->size && memcmp(s1._rep->data,
           s2._rep->data, s1._rep->size * sizeof(Uint16)) == 0;
 } }
  
 Boolean operator!=(const String& str1, const String& str2)  Boolean String::equal(const String& s1, const char* s2)
   {
   #ifdef PEGASUS_STRING_NO_UTF8
   
       _checkNullPointer(s2);
   
       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;
       }
   
       return !(*p || *q);
   
   #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_OS_OS400) #if defined(PEGASUS_OS_OS400)
     CString cstr = str.getCStringUTF8();  
     const char* utf8str = cstr;  
  
       CString cstr = str.getCString();
       const char* utf8str = cstr;
     os << utf8str;     os << utf8str;
       return os;
   #else
  
 #elif defined(PEGASUS_HAS_ICU)  #if defined(PEGASUS_HAS_ICU)
         if(os == cout || os == cerr){  
       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;
         }else{          return os;
                 CString cstr = str.getCStringUTF8();  
         const char* utf8str = cstr;  
         os << utf8str;  
         }         }
  
 #else  #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 1018 
Line 1328 
                 os << buffer;                 os << buffer;
                 }                 }
         }         }
 #endif // End of PEGASUS_HAS_ICU #else leg.  
  
     return os;     return os;
   #endif // PEGASUS_OS_OS400
 } }
  
 String operator+(const String& str1, const String& str2)  void StringAppendCharAux(StringRep*& _rep)
 { {
     return String(str1).append(str2);      StringRep* tmp;
 }  
  
 Boolean operator<(const String& str1, const String& str2)      if (_rep->cap)
 { {
     return String::compare(str1, str2) < 0;          tmp = StringRep::alloc(2 * _rep->cap);
           tmp->size = _rep->size;
           _copy(tmp->data, _rep->data, _rep->size);
 } }
       else
 Boolean operator<=(const String& str1, const String& str2)  
 { {
     return String::compare(str1, str2) <= 0;          tmp = StringRep::alloc(8);
           tmp->size = 0;
       }
   
       StringRep::unref(_rep);
       _rep = tmp;
 } }
  
 Boolean operator>(const String& str1, const String& str2)  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[] =
 { {
     return String::compare(str1, str2) > 0;                  0,1,2,...255
               };
   
               inline Uint16 _toUpper(Uint16 x)
               {
                   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;
 } }
  
 #ifdef PEGASUS_USE_DEPRECATED_INTERFACES      8.  Implemented "concatenating constructors" to eliminate temporaries
 int CompareNoCase(const char* s1, const char* s2)          created by operator+(). This scheme employs the "return-value
           optimization" described by Stan Lippman.
   
               inline String operator+(const String& s1, const String& s2)
 { {
     return System::strcasecmp(s1, s2);                  return String(s1, s2, 0);
 } }
 #endif  
  
 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.
   
   ================================================================================
   
   TO-DO:
   
       (+) [DONE] Use PEGASUS_USE_EXPERIMENTAL_INTERFACES
   
       (+) [DONE] Submit BUG-2754 (Windows buffer limit).
   
       (+) [DONE] Eliminate char versions of find() and append().
   
       (+) [DONE] Remove PEGASUS_MAX_PRINTABLE_CHARACTER from Config.h
   
       (+) [DONE] Change _next_pow_2() to _roundUpToPow2().
   
       (+) [DONE] Change '99' to '2' in StringRep constructor (comment as well).
   
       (+) [DONE] Comment StringRep allocation layout.
   
       (+) [DONE] Conceal private inline functions.
   
       (+) [DONE] Shorten inclusion of StringInline.h in String.h.
   
       (+) [DONE] Change USE_INTERNAL_INLINE TO DISABLE_INTERNAL_INLINE or get
           rid of altogether.
   
       (+) [DONE] useCamelNotationOnAllFunctionNames.
   
       (+) [DONE] Check for overlow condition in StringRep::alloc().
   
       (+) [DONE] Remove tabs (used vim ":set expandtab" and ":retab").
   
       (+) [DONE] Fix throw-related memory leak.
   
       (+) [DONE] Look at PEP223 for coding security guidelines.
   
       (+) [DONE] Use old AtomicInt for now (split new AtomicInt into another
           bug.
   
       (+) [DONE] Removed appendASCII() and the ASCII form of the constructor.
   
       -----------
   
       (+) DOC++ String.h
   
   ================================================================================
   */


Legend:
Removed from v.1.90  
changed lines
  Added in v.1.111.6.15

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2