home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Programming / ICU / src / icu / source / common / unistr.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-26  |  30.0 KB  |  1,254 lines

  1. /*
  2. *******************************************************************************
  3. *                                                                             *
  4. * COPYRIGHT:                                                                  *
  5. *   (C) Copyright International Business Machines Corporation, 1998-1999      *
  6. *   Licensed Material - Program-Property of IBM - All Rights Reserved.        *
  7. *   US Government Users Restricted Rights - Use, duplication, or disclosure   *
  8. *   restricted by GSA ADP Schedule Contract with IBM Corp.                    *
  9. *                                                                             *
  10. *******************************************************************************
  11. *
  12. * File unistr.cpp
  13. *
  14. * Modification History:
  15. *
  16. *   Date        Name        Description
  17. *   09/25/98    stephen     Creation.
  18. *   04/20/99    stephen     Overhauled per 4/16 code review.
  19. *   07/09/99    stephen     Renamed {hi,lo},{byte,word} to icu_X for HP/UX
  20. *******************************************************************************
  21. */
  22.  
  23. #include "unistr.h"
  24.  
  25. #include "locid.h"
  26. #include "cstring.h"
  27. #include "cmemory.h"
  28. #include "ustring.h"
  29. #include "mutex.h"
  30.  
  31. #if 0
  32. //DEBUGGING
  33. #include <iostream.h>
  34.  
  35. void
  36. print(const UnicodeString& s,
  37.       const char *name)
  38. {
  39.   UChar c;
  40.   cout << name << ":|";
  41.   for(int i = 0; i < s.length(); ++i) {
  42.     c = s[i];
  43.     if(c>= 0x007E || c < 0x0020)
  44.       cout << "[0x" << hex << s[i] << "]";
  45.     else
  46.       cout << (char) s[i];
  47.   }
  48.   cout << '|' << endl;
  49. }
  50.  
  51. void
  52. print(const UChar *s,
  53.       int32_t len,
  54.       const char *name)
  55. {
  56.   UChar c;
  57.   cout << name << ":|";
  58.   for(int i = 0; i < len; ++i) {
  59.     c = s[i];
  60.     if(c>= 0x007E || c < 0x0020)
  61.       cout << "[0x" << hex << s[i] << "]";
  62.     else
  63.       cout << (char) s[i];
  64.   }
  65.   cout << '|' << endl;
  66. }
  67. // END DEBUGGING
  68. #endif
  69.  
  70. // Local function definitions for now
  71.  
  72. // move u_arrayCompare to utypes.h ??
  73. inline int8_t
  74. u_arrayCompare(const UChar *src, int32_t srcStart,
  75.          const UChar *dst, int32_t dstStart, int32_t count)
  76. {return icu_memcmp(src+srcStart, dst+dstStart, (size_t)(count*sizeof(*src)));}
  77.  
  78. // need to copy areas that may overlap
  79. inline void
  80. us_arrayCopy(const UChar *src, int32_t srcStart,
  81.          UChar *dst, int32_t dstStart, int32_t count)
  82. {
  83.   if(count>0) {
  84.     icu_memmove(dst+dstStart, src+srcStart, (size_t)(count*sizeof(*src)));
  85.   }
  86. }
  87.  
  88. // static initialization
  89. const UChar UnicodeString::fgInvalidUChar      = 0xFFFF;
  90. const int32_t UnicodeString::kGrowSize         = 0x80;
  91. const int32_t UnicodeString::kInvalidHashCode  = 0;
  92. const int32_t UnicodeString::kEmptyHashCode    = 1;
  93. UConverter* UnicodeString::fgDefaultConverter  = 0;
  94.  
  95. //========================================
  96. // Constructors
  97. //========================================
  98. UnicodeString::UnicodeString()
  99.   : fArray(fStackBuffer),
  100.     fLength(0),
  101.     fCapacity(US_STACKBUF_SIZE),
  102.     fRefCounted(FALSE),
  103.     fHashCode(kEmptyHashCode),
  104.     fBogus(FALSE)
  105. {}
  106.  
  107. UnicodeString::UnicodeString(int32_t capacity)
  108.   : fArray(0),
  109.     fLength(0),
  110.     fCapacity(0),
  111.     fRefCounted(FALSE),
  112.     fHashCode(kEmptyHashCode),
  113.     fBogus(FALSE)
  114. {
  115.   fArray = allocate(capacity, fCapacity);
  116.   if(! fArray) {
  117.     setToBogus();
  118.     return;
  119.   }
  120.  
  121.   setRefCount(1);
  122. }
  123.  
  124. UnicodeString::UnicodeString(UChar ch)
  125.   : fArray(fStackBuffer),
  126.     fLength(0),
  127.     fCapacity(US_STACKBUF_SIZE),
  128.     fRefCounted(FALSE),
  129.     fHashCode(kEmptyHashCode),
  130.     fBogus(FALSE)
  131. {
  132.   doReplace(0, 0, &ch, 0, 1);
  133. }
  134.  
  135. UnicodeString::UnicodeString(const UChar *text)
  136.   : fArray(fStackBuffer),
  137.     fLength(0),
  138.     fCapacity(US_STACKBUF_SIZE),
  139.     fRefCounted(FALSE),
  140.     fHashCode(kEmptyHashCode),
  141.     fBogus(FALSE)
  142. {
  143.   doReplace(0, 0, text, 0, u_strlen(text));
  144. }
  145.  
  146. UnicodeString::UnicodeString( const UChar *text,
  147.                   int32_t textLength)
  148.   : fArray(fStackBuffer),
  149.     fLength(0),
  150.     fCapacity(US_STACKBUF_SIZE),
  151.     fRefCounted(FALSE),
  152.     fHashCode(kEmptyHashCode),
  153.     fBogus(FALSE)
  154. {
  155.   doReplace(0, 0, text, 0, textLength);
  156. }
  157.  
  158. UnicodeString::UnicodeString(const char *codepageData,
  159.                  const char *codepage)
  160.   : fArray(fStackBuffer),
  161.     fLength(0),
  162.     fCapacity(US_STACKBUF_SIZE),
  163.     fRefCounted(FALSE),
  164.     fHashCode(kEmptyHashCode),
  165.     fBogus(FALSE)
  166. {
  167.   if(codepageData != 0)
  168.     doCodepageCreate(codepageData, icu_strlen(codepageData), codepage);
  169. }
  170.  
  171.  
  172. UnicodeString::UnicodeString(const char *codepageData,
  173.                  int32_t dataLength,
  174.                  const char *codepage)
  175.   : fArray(fStackBuffer),
  176.     fLength(0),
  177.     fCapacity(US_STACKBUF_SIZE),
  178.     fRefCounted(FALSE),
  179.     fHashCode(kEmptyHashCode),
  180.     fBogus(FALSE)
  181. {
  182.   doCodepageCreate(codepageData, dataLength, codepage);
  183. }
  184.  
  185. //========================================
  186. // Destructor
  187. //========================================
  188. UnicodeString::~UnicodeString()
  189. {
  190.   // decrement ref count and reclaim storage, if owned
  191.   if(fRefCounted && removeRef() == 0)
  192.     delete [] fArray;
  193. }
  194.  
  195. //========================================
  196. // Assignment
  197. //========================================
  198. UnicodeString&
  199. UnicodeString::operator= (const UnicodeString& src)
  200. {
  201.   // if src is bogus, or we're bogus, or assigning to ourselves, do nothing
  202.   if(fBogus || src.isBogus() || this == &src)
  203.   return *this;
  204.  
  205.   // if src is ref counted, point ourselves at its array
  206.   if(src.fRefCounted) {
  207.  
  208.     // if we're ref counted, decrement our current ref count
  209.     if(fRefCounted && removeRef() == 0)
  210.     delete [] fArray;
  211.  
  212.     fArray      = src.fArray;
  213.     fLength     = src.fLength;
  214.     fCapacity   = src.fCapacity;
  215.     fHashCode   = src.fHashCode;
  216.     fRefCounted = TRUE;
  217.     addRef();
  218.   }
  219.   // if src isn't ref counted, just do a replace
  220.   else {
  221.     doReplace(0, fLength, src.fArray, 0, src.fLength);
  222.     fHashCode = src.fHashCode;
  223.   }
  224.  
  225.   return *this;
  226. }
  227.  
  228. //========================================
  229. // Miscellaneous operations
  230. //========================================
  231. int32_t
  232. UnicodeString::numDisplayCells( UTextOffset start,
  233.                 int32_t length,
  234.                 bool_t asian) const
  235. {
  236.   // pin indices to legal values
  237.   pinIndices(start, length);
  238.  
  239.   UChar c;
  240.   int32_t result = 0;
  241.   UTextOffset limit = start + length;
  242.  
  243.   while(start < limit) {
  244.     c = getArrayStart()[start];
  245.     switch(Unicode::getCellWidth(c)) {
  246.     case Unicode::ZERO_WIDTH:
  247.       break;;
  248.  
  249.     case Unicode::HALF_WIDTH:
  250.       result += 1;
  251.       break;
  252.  
  253.     case Unicode::FULL_WIDTH:
  254.       result += 2;
  255.       break;
  256.  
  257.     case Unicode::NEUTRAL:
  258.       result += (asian ? 2 : 1);
  259.       break;
  260.     }
  261.     ++start;
  262.   }
  263.  
  264.   return result;
  265. }
  266.  
  267. UCharReference
  268. UnicodeString::operator[] (UTextOffset pos)
  269. {
  270.   return UCharReference(this, pos);
  271. }
  272.  
  273. //========================================
  274. // Read-only implementation
  275. //========================================
  276. int8_t
  277. UnicodeString::doCompare( UTextOffset start,
  278.               int32_t length,
  279.               const UnicodeString& src,
  280.               UTextOffset srcStart,
  281.               int32_t srcLength) const
  282. {
  283.   // pin indices to legal values
  284.   pinIndices(start, length);
  285.  
  286.   // get the correct pointer
  287.   const UChar *chars = getArrayStart();
  288.  
  289.   // compare the characters
  290.   return (src.compare(srcStart, srcLength, chars, start, length) * -1);
  291. }
  292.  
  293. int8_t
  294. UnicodeString::doCompare( UTextOffset start,
  295.               int32_t length,
  296.               const UChar *srcChars,
  297.               UTextOffset srcStart,
  298.               int32_t srcLength) const
  299. {
  300.   // pin indices to legal values
  301.   pinIndices(start, length);
  302.  
  303.   // get the correct pointer
  304.   const UChar *chars = getArrayStart();
  305.  
  306.   // we're comparing different lengths
  307.   if(length != srcLength) {
  308.  
  309.     // compare the minimum # of characters
  310.     int32_t minLength     = (length < srcLength ? length : srcLength);
  311.     const UChar *minLimit = chars + minLength;
  312.     const UChar *limit    = chars + length;
  313.     int8_t result;
  314.  
  315.     // adjust for starting offsets
  316.     chars += start;
  317.     srcChars += srcStart;
  318.  
  319.     while(chars < minLimit) {
  320.       result = (*chars - *srcChars);
  321.  
  322.       if(result != 0)
  323.     return result;
  324.  
  325.       ++chars;
  326.       ++srcChars;
  327.     }
  328.  
  329.     // if we got here, the leading portions are identical
  330.     return (chars < limit ? 1 : -1);
  331.   }
  332.   // compare two identical lengths, use u_arrayCompare
  333.   else
  334.     return u_arrayCompare(chars, start, srcChars, srcStart, length);
  335. }
  336.  
  337. void
  338. UnicodeString::doExtract(UTextOffset start,
  339.              int32_t length,
  340.              UChar *dst,
  341.              UTextOffset dstStart) const
  342. {
  343.   // pin indices to legal values
  344.   pinIndices(start, length);
  345.   us_arrayCopy(getArrayStart(), start, dst, dstStart, length);
  346. }
  347.  
  348.  
  349. UTextOffset
  350. UnicodeString::doIndexOf(UChar c,
  351.              UTextOffset start,
  352.              int32_t length) const
  353. {
  354.   // pin indices
  355.   pinIndices(start, length);
  356.  
  357.   // find the first occurrence of c
  358.   const UChar *begin = getArrayStart() + start;
  359.   const UChar *limit = begin + length;
  360.  
  361.   while(begin < limit && *begin != c)
  362.     ++begin;
  363.  
  364.   return (begin == limit ? -1 : begin - getArrayStart());
  365. }
  366.  
  367. UTextOffset
  368. UnicodeString::doLastIndexOf(UChar c,
  369.                  UTextOffset start,
  370.                  int32_t length) const
  371. {
  372.   // pin indices
  373.   pinIndices(start, length);
  374.  
  375.   const UChar *begin = getArrayStart() + start + length;
  376.   const UChar *limit = begin - length;
  377.  
  378.   while(begin > limit && *begin != c)
  379.     --begin;
  380.  
  381.   return (begin == limit ? -1 : begin - getArrayStart());
  382. }
  383.  
  384.  
  385. //========================================
  386. // Write implementation
  387. //========================================
  388.  
  389. UnicodeString&
  390. UnicodeString::setCharAt(UTextOffset offset,
  391.              UChar c)
  392. {
  393.   if(offset < 0)
  394.     offset = 0;
  395.   else if(offset >= fLength)
  396.     offset = fLength - 1;
  397.  
  398.   doSetCharAt(offset, c);
  399.   fHashCode = kInvalidHashCode;
  400.   return *this;
  401. }
  402.  
  403. UnicodeString&
  404. UnicodeString::toUpper()
  405. { return toUpper(Locale::getDefault()); }
  406.  
  407. UnicodeString&
  408. UnicodeString::toLower()
  409. { return toLower(Locale::getDefault()); }
  410.  
  411. UnicodeString&
  412. UnicodeString::toUpper(const Locale& locale)
  413. {
  414.   UTextOffset start = 0;
  415.   UTextOffset limit = fLength;
  416.   UChar c;
  417.   UnicodeString lang;
  418.  
  419.   locale.getLanguage(lang);
  420.  
  421.   // The German sharp S character (U+00DF)'s uppercase equivalent is
  422.   // "SS", making it the only character that expands to two characters
  423.   // when its case is changed (we don't automatically convert "SS" to
  424.   // U+00DF going to lowercase because it can only be determined from
  425.   // knowing the language whether a particular "SS" should map to
  426.   // U+00DF or "ss").  So we make a preliminary pass through the
  427.   // string looking for sharp S characters and then go back and make
  428.   // room for the extra capital Ses if we find any.  [For performance,
  429.   // we only do this extra work if the language is actually German]
  430.   if(lang == "de") {
  431.     UChar SS [] = { 0x0053, 0x0053 };
  432.     while(start < limit) {
  433.  
  434.       c = getArrayStart()[start];
  435.  
  436.       // A sharp s needs to be replaced with two capital S's.
  437.       if(c == 0x00DF) {
  438.     doReplace(start, 1, SS, 0, 2);
  439.     start++;
  440.     limit++;
  441.       }
  442.  
  443.       // Otherwise, the case conversion can be handled by the Unicode unit.
  444.       else if(Unicode::isLowerCase(c))
  445.     doSetCharAt(start, Unicode::toUpperCase(c));
  446.  
  447.       // If no conversion is necessary, do nothing
  448.       ++start;
  449.     }
  450.   }
  451.  
  452.   // If the specfied language is Turkish, then we have to special-case
  453.   // for the Turkish dotted and dotless Is.  The regular lowercase i
  454.   // maps to the capital I with a dot (U+0130), and the lowercase i
  455.   // without the dot (U+0131) maps to the regular capital I
  456.   else if(lang == "tr") {
  457.     while(start < limit) {
  458.       c = getArrayStart()[start];
  459.  
  460.       if(c == 0x0069/*'i'*/)
  461.     doSetCharAt(start, 0x0130);
  462.       else if(c == 0x0131)
  463.     doSetCharAt(start, 0x0049/*'I'*/);
  464.       else if(Unicode::isLowerCase(c))
  465.     doSetCharAt(start, Unicode::toUpperCase(c));
  466.       ++start;
  467.     }
  468.   }
  469.  
  470.   else {
  471.     while(start < limit) {
  472.       c = getArrayStart()[start];
  473.       if(Unicode::isLowerCase(c))
  474.     doSetCharAt(start, Unicode::toUpperCase(c));
  475.       ++start;
  476.     }
  477.   }
  478.  
  479.   fHashCode = kInvalidHashCode;
  480.  
  481.   return *this;
  482. }
  483.  
  484. UnicodeString&
  485. UnicodeString::toLower(const Locale& locale)
  486. {
  487.   UTextOffset start = 0;
  488.   UTextOffset limit = fLength;
  489.   UChar c;
  490.   UnicodeString lang;
  491.  
  492.   locale.getLanguage(lang);
  493.  
  494.   // if the specfied language is Turkish, then we have to special-case
  495.   // for the Turkish dotted and dotless Is.  The capital I with a dot
  496.   // (U+0130) maps to the regular lowercase i, and the regular capital
  497.   // I maps to the lowercase i without the dot (U+0131)
  498.   if(lang == "tr") {
  499.     while(start < limit) {
  500.       c = getArrayStart()[start];
  501.       if(c == 0x0049) // 'I'
  502.     doSetCharAt(start, 0x0131);
  503.       else if(c == 0x0130)
  504.     doSetCharAt(start, 0x0069); // 'i'
  505.       else if(Unicode::isUpperCase(c) || Unicode::isTitleCase(c))
  506.     doSetCharAt(start, Unicode::toLowerCase(c));
  507.       ++start;
  508.     }
  509.   }
  510.  
  511.   // if the specfied language is Greek, then we have to special-case
  512.   // for the capital letter sigma (U+3A3), which has two lower-case
  513.   // forms.  If the character following the capital sigma is a letter,
  514.   // we use the medial form (U+3C3); otherwise, we use the final form
  515.   // (U+3C2).
  516.   else if(lang == "el") {
  517.     while(start < limit) {
  518.       c = getArrayStart()[start];
  519.       if(c == 0x3a3) {
  520.     if(start + 1 < limit && Unicode::isLetter(getArrayStart()[start + 1]))
  521.       doSetCharAt(start, 0x3C3);
  522.     else
  523.       doSetCharAt(start, 0x3C2);
  524.       }
  525.       else if(Unicode::isUpperCase(c) || Unicode::isTitleCase(c))
  526.     doSetCharAt(start, Unicode::toLowerCase(c));
  527.       ++start;
  528.     }
  529.   }
  530.  
  531.   // if the specified language is anything other than Turkish or
  532.   // Greek, we rely on the Unicode class to do all our case mapping--
  533.   // there are no other special cases
  534.   else {
  535.     while(start < limit) {
  536.       c = getArrayStart()[start];
  537.       if(Unicode::isUpperCase(c) || Unicode::isTitleCase(c))
  538.     doSetCharAt(start, Unicode::toLowerCase(c));
  539.       ++start;
  540.     }
  541.   }
  542.  
  543.   fHashCode = kInvalidHashCode;
  544.  
  545.   return *this;
  546. }
  547.  
  548. // for speed, no bounds checking is performed and the hash code isn't changed
  549. UnicodeString&
  550. UnicodeString::doSetCharAt(UTextOffset offset,
  551.                UChar c)
  552. {
  553.   // clone our array, if necessary
  554.   cloneArrayIfNeeded();
  555.  
  556.   // set the character
  557.   fArray[ (fRefCounted ? offset + 1 : offset) ] = c;
  558.   return *this;
  559. }
  560.  
  561. UnicodeString&
  562. UnicodeString::doReplace( UTextOffset start,
  563.               int32_t length,
  564.               const UnicodeString& src,
  565.               UTextOffset srcStart,
  566.               int32_t srcLength)
  567. {
  568.   // pin the indices to legal values
  569.   src.pinIndices(srcStart, srcLength);
  570.  
  571.   // get the characters from src
  572.   const UChar *chars = src.getArrayStart();
  573.  
  574.   // and replace the range in ourselves with them
  575.   doReplace(start, length, chars, srcStart, srcLength);
  576.  
  577.   return *this;
  578. }
  579.  
  580. UnicodeString&
  581. UnicodeString::doReplace(UTextOffset start,
  582.              int32_t length,
  583.              const UChar *srcChars,
  584.              UTextOffset srcStart,
  585.              int32_t srcLength)
  586. {
  587.   // if we're bogus, do nothing
  588.   if(fBogus)
  589.     return *this;
  590.  
  591.   bool_t deleteWhenDone = FALSE;
  592.   UChar *bufferToDelete = 0;
  593.  
  594.   // clone our array, if necessary
  595.   cloneArrayIfNeeded();
  596.  
  597.   // pin the indices to legal values
  598.   pinIndices(start, length);
  599.  
  600.   // calculate the size of the string after the replace
  601.   int32_t newSize = fLength - length + srcLength;
  602.  
  603.   // allocate a bigger array if needed
  604.   if( newSize > getCapacity() ) {
  605.  
  606.     // allocate at minimum the current capacity + needed space
  607.     int32_t tempLength;
  608.     UChar *temp = allocate(fCapacity + srcLength, tempLength);
  609.     if(! temp) {
  610.       setToBogus();
  611.       return *this;
  612.     }
  613.  
  614.     // if we're not currently ref counted, shift the array right by one
  615.     if(fRefCounted == FALSE)
  616.       us_arrayCopy(fArray, 0, temp, 1, fLength);
  617.     // otherwise, copy the old array into temp, including the ref count
  618.     else
  619.       us_arrayCopy(fArray, 0, temp, 0, fLength + 1);
  620.  
  621.     // delete the old array if we were ref counted
  622.     if(fRefCounted && removeRef() == 0) {
  623.       // if the srcChars array is the same as this object's array,
  624.       // don't delete it until the end of the method.  this can happen
  625.       // in code like UnicodeString s = "foo"; s += s;
  626.       if(srcChars != getArrayStart())
  627.     delete [] fArray;
  628.       else {
  629.     deleteWhenDone = TRUE;
  630.     bufferToDelete = fArray;
  631.       }
  632.     }
  633.  
  634.     // use the new array
  635.     fCapacity = tempLength;
  636.     fArray = temp;
  637.     setRefCount(1);
  638.   }
  639.  
  640.   // now do the replace
  641.  
  642.   // first copy the portion that isn't changing, leaving a hole
  643.   us_arrayCopy(getArrayStart(), start + length,
  644.           getArrayStart(), start + srcLength,
  645.           fLength - (start + length));
  646.  
  647.   // now fill in the hole with the new string
  648.   us_arrayCopy(srcChars, srcStart, getArrayStart(), start, srcLength);
  649.  
  650.   fLength = newSize;
  651.   fHashCode = kInvalidHashCode;
  652.  
  653.   if(deleteWhenDone)
  654.     delete [] bufferToDelete;
  655.  
  656.   return *this;
  657. }
  658.  
  659. UnicodeString&
  660. UnicodeString::doReverse(UTextOffset start,
  661.              int32_t length)
  662. {
  663.   // if we're bogus, do nothing
  664.   if(fBogus)
  665.     return *this;
  666.  
  667.   // clone our array, if necessary
  668.   cloneArrayIfNeeded();
  669.  
  670.   // pin the indices to legal values
  671.   pinIndices(start, length);
  672.  
  673.   UChar *left = getArrayStart() + start;
  674.   UChar *right = getArrayStart() + start + length;
  675.   UChar swap;
  676.  
  677.   while(left < --right) {
  678.     swap = *left;
  679.     *left++ = *right;
  680.     *right = swap;
  681.   }
  682.  
  683.   fHashCode = kInvalidHashCode;
  684.  
  685.   return *this;
  686. }
  687.  
  688. //========================================
  689. // Hashing
  690. //========================================
  691. int32_t
  692. UnicodeString::doHashCode()
  693. {
  694.   const UChar *key     = getArrayStart();
  695.   int32_t len         = fLength;
  696.   int32_t hash         = kInvalidHashCode;
  697.   const UChar *limit     = key + len;
  698.   int32_t inc         = (len >= 128 ? len/64 : 1);
  699.  
  700.   /*
  701.     We compute the hash by iterating sparsely over 64 (at most)
  702.     characters spaced evenly through the string.  For each character,
  703.     we multiply the previous hash value by a prime number and add the
  704.     new character in, in the manner of an additive linear congruential
  705.     random number generator, thus producing a pseudorandom
  706.     deterministic value which should be well distributed over the
  707.     output range. [LIU] */
  708.  
  709.   while(key < limit) {
  710.     hash = (hash * 37) + *key;
  711.     key += inc;
  712.   }
  713.  
  714.   if(hash == kInvalidHashCode)
  715.     hash = kEmptyHashCode;
  716.  
  717.   fHashCode = hash;
  718.   return fHashCode;
  719. }
  720.  
  721. //========================================
  722. // Bogusify?
  723. //========================================
  724. void
  725. UnicodeString::setToBogus()
  726. {
  727.   fBogus = TRUE;
  728.   if(fRefCounted) {
  729.     if(removeRef() == 0)
  730.       delete [] fArray;
  731.  
  732.     fArray = 0;
  733.     fCapacity = fLength = 0;
  734.   }
  735.  
  736.   fHashCode = kInvalidHashCode;
  737. }
  738.  
  739. //========================================
  740. // Codeset conversion
  741. //========================================
  742. int32_t
  743. UnicodeString::extract(UTextOffset start,
  744.                int32_t length,
  745.                char *dst,
  746.                const char *codepage) const
  747. {
  748.   // if we're bogus or there's nothing to convert, do nothing
  749.   if(fBogus || length == 0)
  750.     return 0;
  751.  
  752.   // pin the indices to legal values
  753.   pinIndices(start, length);
  754.  
  755.   int32_t convertedLen = 0;
  756.  
  757.   // set up the conversion parameters
  758.   int32_t sourceLen        = length;
  759.   const UChar *mySource    = getArrayStart() + start;
  760.   const UChar *mySourceEnd = mySource + length;
  761.   char *myTarget           = dst;
  762.   char *myTargetLimit;
  763.   UErrorCode status        = U_ZERO_ERROR;
  764.   int32_t arraySize        = 0x0FFFFFFF;
  765.  
  766.   // create the converter
  767.   UConverter *converter = 0;
  768.  
  769.   // if the codepage is the default, use our cache
  770.   if(codepage == 0)
  771.     converter = getDefaultConverter(status);
  772.   else
  773.     converter = ucnv_open(codepage, &status);
  774.  
  775.   // if we failed, set the appropriate flags and return
  776.   if(U_FAILURE(status)) {
  777.     // close the converter
  778.     if(codepage == 0)
  779.       releaseDefaultConverter(converter);
  780.     else
  781.       ucnv_close(converter);
  782.     return 0;
  783.   }
  784.  
  785.   myTargetLimit = myTarget + arraySize;
  786.  
  787.   if(myTargetLimit < myTarget)  /* ptr wrapped around: pin to U_MAX_PTR */
  788.     myTargetLimit = (char*)U_MAX_PTR; 
  789.  
  790.   // perform the conversion
  791.   // there is no loop here since we assume the buffer is large enough
  792.  
  793.   ucnv_fromUnicode(converter, &myTarget,  myTargetLimit,
  794.            &mySource, mySourceEnd, NULL, TRUE, &status);
  795.  
  796.   // close the converter
  797.   if(codepage == 0)
  798.     releaseDefaultConverter(converter);
  799.   else
  800.     ucnv_close(converter);
  801.  
  802.   return (myTarget - dst);
  803. }
  804.  
  805. void
  806. UnicodeString::doCodepageCreate(const char *codepageData,
  807.                 int32_t dataLength,
  808.                 const char *codepage)
  809. {
  810.   // if there's nothing to convert, do nothing
  811.   if(codepageData == 0 || dataLength == 0)
  812.     return;
  813.  
  814.   // set up the conversion parameters
  815.   int32_t sourceLen        = dataLength;
  816.   const char *mySource     = codepageData;
  817.   const char *mySourceEnd  = mySource + sourceLen;
  818.   UChar *myTarget          = getArrayStart();
  819.   UErrorCode status        = U_ZERO_ERROR;
  820.   int32_t arraySize        = getCapacity();
  821.  
  822.   // create the converter
  823.   UConverter *converter = 0;
  824.  
  825.   // if the codepage is the default, use our cache
  826.   converter = (codepage == 0
  827.            ? getDefaultConverter(status)
  828.            : ucnv_open(codepage, &status));
  829.  
  830.   // if we failed, set the appropriate flags and return
  831.   if(U_FAILURE(status)) {
  832.     // close the converter
  833.     if(codepage == 0)
  834.       releaseDefaultConverter(converter);
  835.     else
  836.       ucnv_close(converter);
  837.     setToBogus();
  838.     return;
  839.   }
  840.  
  841.   // perform the conversion
  842.   do {
  843.     // reset the error code
  844.     status = U_ZERO_ERROR;
  845.  
  846.     // perform the conversion
  847.     ucnv_toUnicode(converter, &myTarget,  myTarget + arraySize,
  848.            &mySource, mySourceEnd, NULL, TRUE, &status);
  849.  
  850.     // update the conversion parameters
  851.     fLength      = myTarget - getArrayStart();
  852.     arraySize    = getCapacity() - fLength;
  853.  
  854.     // allocate more space and copy data, if needed
  855.     if(fLength < dataLength) {
  856.       int32_t tempCapacity;
  857.       UChar *temp = allocate(fCapacity, tempCapacity);
  858.  
  859.       if(! temp) {
  860.     // close the converter
  861.     if(codepage == 0)
  862.       releaseDefaultConverter(converter);
  863.     else
  864.       ucnv_close(converter);
  865.     // set flags and return
  866.     setToBogus();
  867.     return;
  868.       }
  869.  
  870.       // if we're not currently ref counted, shift the array right by one
  871.       if(fRefCounted == FALSE)
  872.     us_arrayCopy(fArray, 0, temp, 1, fLength);
  873.       // otherwise, copy the old array into temp, including the ref count
  874.       else
  875.           us_arrayCopy(fArray, 0, temp, 0, fLength + 1);
  876.  
  877.       if(fRefCounted && removeRef() == 0)
  878.     delete [] fArray;
  879.  
  880.       fArray      = temp;
  881.       fCapacity   = tempCapacity;
  882.  
  883.       setRefCount(1);
  884.  
  885.       myTarget    = getArrayStart() + fLength;
  886.       arraySize   = getCapacity() - fLength;
  887.     }
  888.   }
  889.   while(status == U_INDEX_OUTOFBOUNDS_ERROR);
  890.  
  891.   fHashCode = kInvalidHashCode;
  892.  
  893.   // close the converter
  894.   if(codepage == 0)
  895.     releaseDefaultConverter(converter);
  896.   else
  897.     ucnv_close(converter);
  898. }
  899.  
  900. //========================================
  901. // External Buffer
  902. //========================================
  903. UnicodeString::UnicodeString(UChar *buff,
  904.                  int32_t bufLength,
  905.                  int32_t buffCapacity)
  906.   : fArray(buff),
  907.     fLength(bufLength),
  908.     fCapacity(buffCapacity),
  909.     fRefCounted(FALSE),
  910.     fHashCode(kInvalidHashCode),
  911.     fBogus(FALSE)
  912. {}
  913.  
  914. const UChar*
  915. UnicodeString::getUChars() const
  916. {
  917.   // if we're bogus, do nothing
  918.   if(fBogus)
  919.     return 0;
  920.  
  921.   // clone our array, if necessary
  922.   ((UnicodeString*)this)->cloneArrayIfNeeded();
  923.  
  924.   // no room for null, resize
  925.   if(getCapacity() <= fLength) {
  926.     // allocate at minimum the current capacity + needed space
  927.     int32_t tempLength;
  928.     UChar *temp = allocate(fCapacity + 1, tempLength);
  929.     if(! temp) {
  930.       ((UnicodeString*)this)->setToBogus();
  931.       return 0;
  932.     }
  933.  
  934.     // if we're not currently ref counted, shift the array right by one
  935.     if(fRefCounted == FALSE)
  936.       us_arrayCopy(fArray, 0, temp, 1, fLength);
  937.     // otherwise, copy the old array into temp, including the ref count
  938.     else
  939.       us_arrayCopy(fArray, 0, temp, 0, fLength + 1);
  940.  
  941.     // delete the old array
  942.     if(fRefCounted && ((UnicodeString*)this)->removeRef() == 0)
  943.       delete [] ((UnicodeString*)this)->fArray;
  944.  
  945.     // use the new array
  946.     ((UnicodeString*)this)->fCapacity = tempLength;
  947.     ((UnicodeString*)this)->fArray    = temp;
  948.     ((UnicodeString*)this)->setRefCount(1);
  949.   }
  950.  
  951.   // tack on a trailing null
  952.   fArray[(fRefCounted ? 1 : 0) + fLength] = 0;
  953.  
  954.   return getArrayStart();
  955. }
  956.  
  957. UChar*
  958. UnicodeString::orphanStorage()
  959. {
  960.   // if we're bogus, do nothing
  961.   if(fBogus)
  962.     return 0;
  963.  
  964.   // clone our array, if necessary
  965.   ((UnicodeString*)this)->cloneArrayIfNeeded();
  966.  
  967.   // if we're ref counted, get rid of the leading ref count
  968.   if(fRefCounted) {
  969.     us_arrayCopy(getArrayStart(), 0, fArray, 0, fLength);
  970.   }
  971.  
  972.   UChar *retVal = fArray;
  973.  
  974.   fArray = fStackBuffer;
  975.   fLength = 0;
  976.   fCapacity = US_STACKBUF_SIZE;
  977.   fHashCode = kEmptyHashCode;
  978.  
  979.   return retVal;
  980. }
  981.  
  982. //========================================
  983. // Miscellaneous
  984. //========================================
  985. void
  986. UnicodeString::pinIndices(UTextOffset& start,
  987.               int32_t& length) const
  988. {
  989.   // pin indices
  990.   if(length < 0 || start < 0)
  991.     start = length = 0;
  992.   else {
  993.     if(length > (fLength - start))
  994.       length = (fLength - start);
  995.   }
  996. }
  997.  
  998. void
  999. UnicodeString::cloneArrayIfNeeded()
  1000. {
  1001.   // if we're ref counted, make a copy of the buffer if necessary
  1002.   if(fRefCounted && refCount() > 1) {
  1003.     UChar *copy = new UChar [ fCapacity ];
  1004.     if( ! copy ) {
  1005.       setToBogus();
  1006.       return;
  1007.     }
  1008.  
  1009.     // copy the current shared array into our new array
  1010.     us_arrayCopy(fArray, 0, copy, 0, fLength + 1);
  1011.  
  1012.     // remove a reference from the current shared array
  1013.     // if there are no more references to the current shared array,
  1014.     // after we remove the reference, delete the array
  1015.     if(removeRef() == 0)
  1016.       delete [] fArray;
  1017.  
  1018.     // make our array point to the new copy and set the ref count to one
  1019.     fArray = copy;
  1020.     setRefCount(1);
  1021.   }
  1022. }
  1023.  
  1024. // private function for C API
  1025. U_CFUNC const UChar*
  1026. T_UnicodeString_getUChars(const UnicodeString *s)
  1027. {
  1028.   return s->getUChars();
  1029. }
  1030.  
  1031.  
  1032. //========================================
  1033. // Default converter caching
  1034. //========================================
  1035.  
  1036. UConverter*
  1037. UnicodeString::getDefaultConverter(UErrorCode &status)
  1038. {
  1039.   UConverter *converter = 0;
  1040.  
  1041.   if(fgDefaultConverter != 0) {
  1042.     Mutex lock;
  1043.  
  1044.     // need to check to make sure it wasn't taken out from under us
  1045.     if(fgDefaultConverter != 0) {
  1046.       converter = fgDefaultConverter;
  1047.       fgDefaultConverter = 0;
  1048.     }
  1049.   }
  1050.  
  1051.   // if the cache was empty, create a converter
  1052.   if(converter == 0) {
  1053.     converter = ucnv_open(0, &status);
  1054.     if(U_FAILURE(status))
  1055.       return 0;
  1056.   }
  1057.  
  1058.   return converter;
  1059. }
  1060.  
  1061. void
  1062. UnicodeString::releaseDefaultConverter(UConverter *converter)
  1063. {
  1064.   if(fgDefaultConverter == 0) {
  1065.     Mutex lock;
  1066.  
  1067.     if(fgDefaultConverter == 0) {
  1068.       fgDefaultConverter = converter;
  1069.       converter = 0;
  1070.     }
  1071.   }
  1072.  
  1073.   // it's safe to close a NULL converter
  1074.   ucnv_close(converter);
  1075. }
  1076.  
  1077. //========================================
  1078. // Streaming (to be removed)
  1079. //========================================
  1080.  
  1081. #include <iostream.h>
  1082. #include "unistrm.h"
  1083. #include "filestrm.h"
  1084.  
  1085.  
  1086. inline uint8_t
  1087. icu_hibyte(uint16_t x)
  1088. { return (uint8_t)(x >> 8); }
  1089.  
  1090. inline uint8_t
  1091. icu_lobyte(uint16_t x)
  1092. { return (uint8_t)(x & 0xff); }
  1093.  
  1094. inline uint16_t
  1095. icu_hiword(uint32_t x)
  1096. { return (uint16_t)(x >> 16); }
  1097.  
  1098. inline uint16_t
  1099. icu_loword(uint32_t x)
  1100. { return (uint16_t)(x & 0xffff); }
  1101.  
  1102. inline void
  1103. writeLong(FileStream *os,
  1104.       int32_t x)
  1105. {
  1106.   uint16_t word = icu_hiword((uint32_t)x);
  1107.   T_FileStream_putc(os, icu_hibyte(word));
  1108.   T_FileStream_putc(os, icu_lobyte(word));
  1109.   word = icu_loword((uint32_t)x);
  1110.   T_FileStream_putc(os, icu_hibyte(word));
  1111.   T_FileStream_putc(os, icu_lobyte(word));
  1112. }
  1113.  
  1114. inline int32_t
  1115. readLong(FileStream *is)
  1116. {
  1117.   int32_t x = 0;
  1118.   uint16_t byte;
  1119.  
  1120.   byte = T_FileStream_getc(is);
  1121.   x |= byte;
  1122.   byte = T_FileStream_getc(is);
  1123.   x = (x << 8) | byte;
  1124.   byte = T_FileStream_getc(is);
  1125.   x = (x << 8) | byte;
  1126.   byte = T_FileStream_getc(is);
  1127.   x = (x << 8) | byte;
  1128.  
  1129.   return x;
  1130. }
  1131.  
  1132. inline void
  1133. writeUChar(FileStream *os,
  1134.        UChar c)
  1135. {
  1136.   T_FileStream_putc(os, icu_hibyte(c));
  1137.   T_FileStream_putc(os, icu_lobyte(c));
  1138. }
  1139.  
  1140. inline UChar
  1141. readUChar(FileStream *is)
  1142. {
  1143.   UChar c = 0;
  1144.   uint16_t byte;
  1145.  
  1146.   byte = T_FileStream_getc(is);
  1147.   c |= byte;
  1148.   byte = T_FileStream_getc(is);
  1149.   c = (c << 8) | byte;
  1150.  
  1151.   return c;
  1152. }
  1153.  
  1154. void
  1155. UnicodeStringStreamer::streamOut(const UnicodeString *s,
  1156.                  FileStream *os)
  1157. {
  1158.   if(!T_FileStream_error(os))
  1159.     writeLong(os, s->fLength);
  1160.  
  1161.   const UChar *c   = s->getArrayStart();
  1162.   const UChar *end = c + s->fLength;
  1163.  
  1164.   while(c != end && ! T_FileStream_error(os))
  1165.     writeUChar(os, *c++);
  1166. }
  1167.  
  1168. void
  1169. UnicodeStringStreamer::streamIn(UnicodeString *s,
  1170.                 FileStream *is)
  1171. {
  1172.   int32_t newSize;
  1173.  
  1174.   // handle error conditions
  1175.   if(T_FileStream_error(is) || T_FileStream_eof(is)) {
  1176.     s->setToBogus();
  1177.     return;
  1178.   }
  1179.   newSize = readLong(is);
  1180.   if((newSize < 0) || T_FileStream_error(is)
  1181.      || ((newSize > 0) && T_FileStream_eof(is))) {
  1182.     s->setToBogus(); //error condition
  1183.     return;
  1184.   }
  1185.  
  1186.   // clone s's array, if needed
  1187.   s->cloneArrayIfNeeded();
  1188.  
  1189.   // if the string isn't big enough to hold the data, enlarge it
  1190.   if(s->getCapacity() < newSize) {
  1191.  
  1192.     int32_t tempLength;
  1193.     UChar *temp = s->allocate(newSize, tempLength);
  1194.     if(! temp) {
  1195.       s->setToBogus();
  1196.       return;
  1197.     }
  1198.  
  1199.     // if s is not currently ref counted, shift the array right by one
  1200.     if(s->fRefCounted == FALSE)
  1201.       us_arrayCopy(s->fArray, 0, temp, 1, s->fLength);
  1202.     // otherwise, copy the old array into temp, including the ref count
  1203.     else
  1204.       us_arrayCopy(s->fArray, 0, temp, 0, s->fLength + 1);
  1205.  
  1206.     // delete the old array if s is ref counted
  1207.     if(s->fRefCounted && s->removeRef() == 0)
  1208.       delete [] s->fArray;
  1209.  
  1210.     // use the new array
  1211.     s->fCapacity = tempLength;
  1212.     s->fArray    = temp;
  1213.     s->setRefCount(1);
  1214.   }
  1215.  
  1216.   UChar *c = s->getArrayStart();
  1217.   UChar *end = c + newSize;
  1218.  
  1219.   while(c < end && ! (T_FileStream_error(is) || T_FileStream_eof(is)))
  1220.     *c++ = readUChar(is);
  1221.  
  1222.   // couldn't read all chars
  1223.   if(c < end) {
  1224.     s->setToBogus();
  1225.     return;
  1226.   }
  1227.  
  1228.   s->fLength = newSize;
  1229. }
  1230.  
  1231. // console IO
  1232.  
  1233. ostream&
  1234. operator<<(ostream& stream,
  1235.        const UnicodeString& s)
  1236. {
  1237.   UTextOffset i;
  1238.   UChar c;
  1239.   int32_t saveFlags = stream.flags();
  1240.  
  1241.   stream << hex;
  1242.  
  1243.   for(i = 0; i < s.length(); i++) {
  1244.     c = s.charAt(i);
  1245.     if((c >= ' ' && c <= '~') || c == '\n')
  1246.       stream << (char)c;
  1247.     else
  1248.       stream << "[0x" << c << "]";
  1249.   }
  1250.   stream.flush();
  1251.   stream.setf(saveFlags & ios::basefield, ios::basefield);
  1252.   return stream;
  1253. }
  1254.