ICUTransService.cpp
上传用户:huihehuasu
上传日期:2007-01-10
资源大小:6948k
文件大小:31k
源码类别:

xml/soap/webservice

开发平台:

C/C++

  1. /*
  2.  * The Apache Software License, Version 1.1
  3.  *
  4.  * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
  5.  * reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  *
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  *
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in
  16.  *    the documentation and/or other materials provided with the
  17.  *    distribution.
  18.  *
  19.  * 3. The end-user documentation included with the redistribution,
  20.  *    if any, must include the following acknowledgment:
  21.  *       "This product includes software developed by the
  22.  *        Apache Software Foundation (http://www.apache.org/)."
  23.  *    Alternately, this acknowledgment may appear in the software itself,
  24.  *    if and wherever such third-party acknowledgments normally appear.
  25.  *
  26.  * 4. The names "Xerces" and "Apache Software Foundation" must
  27.  *    not be used to endorse or promote products derived from this
  28.  *    software without prior written permission. For written
  29.  *    permission, please contact apache@apache.org.
  30.  *
  31.  * 5. Products derived from this software may not be called "Apache",
  32.  *    nor may "Apache" appear in their name, without prior written
  33.  *    permission of the Apache Software Foundation.
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38.  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42.  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44.  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45.  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46.  * SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Software Foundation, and was
  51.  * originally based on software copyright (c) 1999, International
  52.  * Business Machines, Inc., http://www.ibm.com .  For more information
  53.  * on the Apache Software Foundation, please see
  54.  * <http://www.apache.org/>.
  55.  */
  56. /*
  57.  * $Id: ICUTransService.cpp,v 1.30 2001/11/26 18:09:31 tng Exp $
  58.  */
  59. // ---------------------------------------------------------------------------
  60. //  Includes
  61. // ---------------------------------------------------------------------------
  62. #include <util/Janitor.hpp>
  63. #include <util/TranscodingException.hpp>
  64. #include <util/XMLString.hpp>
  65. #include <util/XMLUniDefs.hpp>
  66. #include "ICUTransService.hpp"
  67. #include <string.h>
  68. #include <unicode/uloc.h>
  69. #include <unicode/unicode.h>
  70. #include <unicode/ucnv.h>
  71. #include <unicode/ucnv_err.h>
  72. #include <unicode/ustring.h>
  73. #include <unicode/udata.h>
  74. #if !defined(XML_OS390) && !defined(XML_AS400) && !defined(XML_HPUX) && !defined(XML_PTX)
  75. // Forward reference the symbol which points to the ICU converter data.
  76. #if (U_ICU_VERSION_MAJOR_NUM < 2)
  77. extern "C" const uint8_t U_IMPORT icudata_dat[];
  78. #endif
  79. #endif
  80. // ---------------------------------------------------------------------------
  81. //  Local, const data
  82. // ---------------------------------------------------------------------------
  83. static const XMLCh gMyServiceId[] =
  84. {
  85.     chLatin_I, chLatin_C, chLatin_U, chNull
  86. };
  87. // ---------------------------------------------------------------------------
  88. //  Local functions
  89. // ---------------------------------------------------------------------------
  90. //
  91. //  When XMLCh and ICU's UChar are not the same size, we have to do a temp
  92. //  conversion of all strings. These local helper methods make that easier.
  93. //
  94. static UChar* convertToUChar(   const   XMLCh* const    toConvert
  95.                                 , const unsigned int    srcLen = 0)
  96. {
  97.     const unsigned int actualLen = srcLen
  98.                                    ? srcLen : XMLString::stringLen(toConvert);
  99.     UChar* tmpBuf = new UChar[actualLen + 1];
  100.     const XMLCh* srcPtr = toConvert;
  101.     UChar* outPtr = tmpBuf;
  102.     while (*srcPtr)
  103.         *outPtr++ = UChar(*srcPtr++);
  104.     *outPtr = 0;
  105.     return tmpBuf;
  106. }
  107. static XMLCh* convertToXMLCh(const UChar* const toConvert)
  108. {
  109.     const unsigned int srcLen = u_strlen(toConvert);
  110.     XMLCh* retBuf = new XMLCh[srcLen + 1];
  111.     XMLCh* outPtr = retBuf;
  112.     const UChar* srcPtr = toConvert;
  113.     while (*srcPtr)
  114.         *outPtr++ = XMLCh(*srcPtr++);
  115.     *outPtr = 0;
  116.     return retBuf;
  117. }
  118. // ---------------------------------------------------------------------------
  119. //  ICUTransService: Constructors and Destructor
  120. // ---------------------------------------------------------------------------
  121. ICUTransService::ICUTransService()
  122. {
  123. #if !defined(XML_OS390) && !defined(XML_AS400) && !defined(XML_HPUX) && !defined(XML_PTX)
  124. #if (U_ICU_VERSION_MAJOR_NUM < 2)
  125.     // Starting with ICU 2.0, ICU itself includes a static reference to the data
  126.     // entrypoint symbol.
  127.     //
  128.     // ICU 1.8 (and previous) did not include a static reference, but would
  129.     // dynamically load the data dll when it was first needed, however this dynamic
  130.     // loading proved unreliable in some of the odd environments that Xerces needed
  131.     // to run in.  Hence, the static reference.
  132.     // Pass the location of the converter data to ICU. By doing so, we are
  133.     // forcing the load of ICU converter data DLL, after the Xerces-C DLL is
  134.     // loaded. This implies that Xerces-C, now has to explicitly link with the
  135.     // ICU converter dll. However, the advantage is that we no longer depend
  136.     // on the code which does demand dynamic loading of DLL's. The demand
  137.     // loading is highly system dependent and was a constant source of support
  138.     // calls.
  139.     UErrorCode uerr = U_ZERO_ERROR;
  140.     udata_setCommonData((void *) icudata_dat, &uerr);
  141. #endif
  142. #endif
  143. }
  144. ICUTransService::~ICUTransService()
  145. {
  146. }
  147. // ---------------------------------------------------------------------------
  148. //  ICUTransService: The virtual transcoding service API
  149. // ---------------------------------------------------------------------------
  150. int ICUTransService::compareIString(const   XMLCh* const    comp1
  151.                                     , const XMLCh* const    comp2)
  152. {
  153.     const XMLCh* psz1 = comp1;
  154.     const XMLCh* psz2 = comp2;
  155.     unsigned int curCount = 0;
  156.     while (true)
  157.     {
  158.         //
  159.         //  If an inequality, then return the difference. Note that the XMLCh
  160.         //  might be bigger physically than UChar, but it won't hold anything
  161.         //  larger than 0xFFFF, so our cast here will work for both possible
  162.         //  sizes of XMLCh.
  163.         //
  164.         if (Unicode::toUpperCase(UChar(*psz1)) != Unicode::toUpperCase(UChar(*psz2)))
  165.             return int(*psz1) - int(*psz2);
  166.         // If either has ended, then they both ended, so equal
  167.         if (!*psz1 || !*psz2)
  168.             break;
  169.         // Move upwards for the next round
  170.         psz1++;
  171.         psz2++;
  172.     }
  173.     return 0;
  174. }
  175. int ICUTransService::compareNIString(const  XMLCh* const    comp1
  176.                                     , const XMLCh* const    comp2
  177.                                     , const unsigned int    maxChars)
  178. {
  179.     const XMLCh* psz1 = comp1;
  180.     const XMLCh* psz2 = comp2;
  181.     unsigned int curCount = 0;
  182.     while (true)
  183.     {
  184.         //
  185.         //  If an inequality, then return the difference. Note that the XMLCh
  186.         //  might be bigger physically than UChar, but it won't hold anything
  187.         //  larger than 0xFFFF, so our cast here will work for both possible
  188.         //  sizes of XMLCh.
  189.         //
  190.         if (Unicode::toUpperCase(UChar(*psz1)) != Unicode::toUpperCase(UChar(*psz2)))
  191.             return int(*psz1) - int(*psz2);
  192.         // If either ended, then both ended, so equal
  193.         if (!*psz1 || !*psz2)
  194.             break;
  195.         // Move upwards to next chars
  196.         psz1++;
  197.         psz2++;
  198.         //
  199.         //  Bump the count of chars done. If it equals the count then we
  200.         //  are equal for the requested count, so break out and return
  201.         //  equal.
  202.         //
  203.         curCount++;
  204.         if (maxChars == curCount)
  205.             break;
  206.     }
  207.     return 0;
  208. }
  209. const XMLCh* ICUTransService::getId() const
  210. {
  211.     return gMyServiceId;
  212. }
  213. bool ICUTransService::isSpace(const XMLCh toCheck) const
  214. {
  215.     //
  216.     //  <TBD>
  217.     //  For now, we short circuit some of the control chars because ICU
  218.     //  is not correctly reporting them as space. Later, when they change
  219.     //  this, we can get rid of this special case.
  220.     //
  221.     if ((toCheck == 0x09)
  222.     ||  (toCheck == 0x0A)
  223.     ||  (toCheck == 0x0D))
  224.     {
  225.         return true;
  226.     }
  227.     return (Unicode::isSpaceChar(UChar(toCheck)) != 0);
  228. }
  229. XMLLCPTranscoder* ICUTransService::makeNewLCPTranscoder()
  230. {
  231.     //
  232.     //  Try to create a default converter. If it fails, return a null
  233.     //  pointer which will basically cause the system to give up because
  234.     //  we really can't do anything without one.
  235.     //
  236.     UErrorCode uerr = U_ZERO_ERROR;
  237.     UConverter* converter = ucnv_open(NULL, &uerr);
  238.     if (!converter)
  239.         return 0;
  240.     // That went ok, so create an ICU LCP transcoder wrapper and return it
  241.     return new ICULCPTranscoder(converter);
  242. }
  243. bool ICUTransService::supportsSrcOfs() const
  244. {
  245.     // This implementation supports source offset information
  246.     return true;
  247. }
  248. void ICUTransService::upperCase(XMLCh* const toUpperCase) const
  249. {
  250.     XMLCh* outPtr = toUpperCase;
  251.     while (*outPtr)
  252.     {
  253.         *outPtr = XMLCh(Unicode::toUpperCase(UChar(*outPtr)));
  254.         outPtr++;
  255.     }
  256. }
  257. // ---------------------------------------------------------------------------
  258. //  ICUTransService: The protected virtual transcoding service API
  259. // ---------------------------------------------------------------------------
  260. XMLTranscoder* ICUTransService::
  261. makeNewXMLTranscoder(const  XMLCh* const            encodingName
  262.                     ,       XMLTransService::Codes& resValue
  263.                     , const unsigned int            blockSize)
  264. {
  265.     //
  266.     //  If UChar and XMLCh are not the same size, then we have premassage the
  267.     //  encoding name into a UChar type string.
  268.     //
  269.     const UChar* actualName;
  270.     UChar* tmpName = 0;
  271.     if (sizeof(UChar) == sizeof(XMLCh))
  272.     {
  273.         actualName = (const UChar*)encodingName;
  274.     }
  275.      else
  276.     {
  277.         tmpName = convertToUChar(encodingName);
  278.         actualName = tmpName;
  279.     }
  280.     ArrayJanitor<UChar> janTmp(tmpName);
  281.     UErrorCode uerr = U_ZERO_ERROR;
  282.     UConverter* converter = ucnv_openU(actualName, &uerr);
  283.     if (!converter)
  284.     {
  285.         resValue = XMLTransService::UnsupportedEncoding;
  286.         return 0;
  287.     }
  288.     return new ICUTranscoder(encodingName, converter, blockSize);
  289. }
  290. // ---------------------------------------------------------------------------
  291. //  ICUTranscoder: Constructors and Destructor
  292. // ---------------------------------------------------------------------------
  293. ICUTranscoder::ICUTranscoder(const  XMLCh* const        encodingName
  294.                             ,       UConverter* const   toAdopt
  295.                             , const unsigned int        blockSize) :
  296.     XMLTranscoder(encodingName, blockSize)
  297.     , fConverter(toAdopt)
  298.     , fFixed(false)
  299.     , fSrcOffsets(0)
  300. {
  301.     // If there is a block size, then allocate our source offset array
  302.     if (blockSize)
  303.         fSrcOffsets = new XMLUInt32[blockSize];
  304.     // Remember if its a fixed size encoding
  305.     fFixed = (ucnv_getMaxCharSize(fConverter) == ucnv_getMinCharSize(fConverter));
  306. }
  307. ICUTranscoder::~ICUTranscoder()
  308. {
  309.     delete [] fSrcOffsets;
  310.     // If there is a converter, ask ICU to clean it up
  311.     if (fConverter)
  312.     {
  313.         // <TBD> Does this actually delete the structure???
  314.         ucnv_close(fConverter);
  315.         fConverter = 0;
  316.     }
  317. }
  318. // ---------------------------------------------------------------------------
  319. //  ICUTranscoder: The virtual transcoder API
  320. // ---------------------------------------------------------------------------
  321. unsigned int
  322. ICUTranscoder::transcodeFrom(const  XMLByte* const          srcData
  323.                             , const unsigned int            srcCount
  324.                             ,       XMLCh* const            toFill
  325.                             , const unsigned int            maxChars
  326.                             ,       unsigned int&           bytesEaten
  327.                             ,       unsigned char* const    charSizes)
  328. {
  329.     // If debugging, insure the block size is legal
  330.     #if defined(XERCES_DEBUG)
  331.     checkBlockSize(maxChars);
  332.     #endif
  333.     // Set up pointers to the start and end of the source buffer
  334.     const XMLByte*  startSrc = srcData;
  335.     const XMLByte*  endSrc = srcData + srcCount;
  336.     //
  337.     //  And now do the target buffer. This works differently according to
  338.     //  whether XMLCh and UChar are the same size or not.
  339.     //
  340.     UChar* startTarget;
  341.     if (sizeof(XMLCh) == sizeof(UChar))
  342.         startTarget = (UChar*)toFill;
  343.      else
  344.         startTarget = new UChar[maxChars];
  345.     UChar* orgTarget = startTarget;
  346.     //
  347.     //  Transoode the buffer.  Buffer overflow errors are normal, occuring
  348.     //  when the raw input buffer holds more characters than will fit in
  349.     //  the Unicode output buffer.
  350.     //
  351.     UErrorCode  err = U_ZERO_ERROR;
  352.     ucnv_toUnicode
  353.     (
  354.         fConverter
  355.         , &startTarget
  356.         , startTarget + maxChars
  357.         , (const char**)&startSrc
  358.         , (const char*)endSrc
  359.         , (fFixed ? 0 : (int32_t*)fSrcOffsets)
  360.         , false
  361.         , &err
  362.     );
  363.     if ((err != U_ZERO_ERROR) && (err != U_BUFFER_OVERFLOW_ERROR))
  364.     {
  365.         if (orgTarget != (UChar*)toFill)
  366.             delete [] orgTarget;
  367.         if (fFixed)
  368.         {
  369.             XMLCh tmpBuf[16];
  370.             XMLString::binToText((unsigned int)(*startTarget), tmpBuf, 16, 16);
  371.             ThrowXML2
  372.             (
  373.                 TranscodingException
  374.                 , XMLExcepts::Trans_BadSrcCP
  375.                 , tmpBuf
  376.                 , getEncodingName()
  377.             );
  378.         }
  379.          else
  380.         {
  381.             ThrowXML(TranscodingException, XMLExcepts::Trans_BadSrcSeq);
  382.         }
  383.     }
  384.     // Calculate the bytes eaten and store in caller's param
  385.     bytesEaten = startSrc - srcData;
  386.     // And the characters decoded
  387.     const unsigned int charsDecoded = startTarget - orgTarget;
  388.     //
  389.     //  Translate the array of char offsets into an array of character
  390.     //  sizes, which is what the transcoder interface semantics requires.
  391.     //  If its fixed, then we can optimize it.
  392.     //
  393.     if (fFixed)
  394.     {
  395.         const unsigned char fillSize = (unsigned char)ucnv_getMaxCharSize(fConverter);;
  396.         memset(charSizes, fillSize, maxChars);
  397.     }
  398.      else
  399.     {
  400.         //
  401.         //  We have to convert the series of offsets into a series of
  402.         //  sizes. If just one char was decoded, then its the total bytes
  403.         //  eaten. Otherwise, do a loop and subtract out each element from
  404.         //  its previous element.
  405.         //
  406.         if (charsDecoded == 1)
  407.         {
  408.             charSizes[0] = (unsigned char)bytesEaten;
  409.         }
  410.          else
  411.         {
  412.             //  ICU does not return an extra element to allow us to figure
  413.             //  out the last char size, so we have to compute it from the
  414.             //  total bytes used.
  415.             unsigned int index;
  416.             for (index = 0; index < charsDecoded - 1; index++)
  417.             {
  418.                 charSizes[index] = (unsigned char)(fSrcOffsets[index + 1]
  419.                                                     - fSrcOffsets[index]);
  420.             }
  421.             if( charsDecoded > 0 ) {
  422.                 charSizes[charsDecoded - 1] = (unsigned char)(bytesEaten
  423.                                               - fSrcOffsets[charsDecoded - 1]);
  424.             }
  425.         }
  426.     }
  427.     //
  428.     //  If XMLCh and UChar are not the same size, then we need to copy over
  429.     //  the temp buffer to the new one.
  430.     //
  431.     if (sizeof(UChar) != sizeof(XMLCh))
  432.     {
  433.         XMLCh* outPtr = toFill;
  434.         startTarget = orgTarget;
  435.         for (unsigned int index = 0; index < charsDecoded; index++)
  436.             *outPtr++ = XMLCh(*startTarget++);
  437.         // And delete the temp buffer
  438.         delete [] orgTarget;
  439.     }
  440.     // Return the chars we put into the target buffer
  441.     return charsDecoded;
  442. }
  443. unsigned int
  444. ICUTranscoder::transcodeTo( const   XMLCh* const    srcData
  445.                             , const unsigned int    srcCount
  446.                             ,       XMLByte* const  toFill
  447.                             , const unsigned int    maxBytes
  448.                             ,       unsigned int&   charsEaten
  449.                             , const UnRepOpts       options)
  450. {
  451.     //
  452.     //  Get a pointer to the buffer to transcode. If UChar and XMLCh are
  453.     //  the same size here, then use the original. Else, create a temp
  454.     //  one and put a janitor on it.
  455.     //
  456.     const UChar* srcPtr;
  457.     UChar* tmpBufPtr = 0;
  458.     if (sizeof(XMLCh) == sizeof(UChar))
  459.     {
  460.         srcPtr = (const UChar*)srcData;
  461.     }
  462.      else
  463.     {
  464.         tmpBufPtr = convertToUChar(srcData, srcCount);
  465.         srcPtr = tmpBufPtr;
  466.     }
  467.     ArrayJanitor<UChar> janTmpBuf(tmpBufPtr);
  468.     //
  469.     //  Set the appropriate callback so that it will either fail or use
  470.     //  the rep char. Remember the old one so we can put it back.
  471.     //
  472.     UErrorCode  err = U_ZERO_ERROR;
  473.     UConverterFromUCallback oldCB = NULL;
  474.     #if (U_ICU_VERSION_MAJOR_NUM < 2)
  475.     void* orgContent;
  476.     #else
  477.     const void* orgContent;
  478.     #endif
  479.     ucnv_setFromUCallBack
  480.     (
  481.         fConverter
  482.         , (options == UnRep_Throw) ? UCNV_FROM_U_CALLBACK_STOP
  483.                                    : UCNV_FROM_U_CALLBACK_SUBSTITUTE
  484.         , NULL
  485.         , &oldCB
  486.         , &orgContent
  487.         , &err
  488.     );
  489.     //
  490.     //  Ok, lets transcode as many chars as we we can in one shot. The
  491.     //  ICU API gives enough info not to have to do this one char by char.
  492.     //
  493.     XMLByte*        startTarget = toFill;
  494.     const UChar*    startSrc = srcPtr;
  495.     err = U_ZERO_ERROR;
  496.     ucnv_fromUnicode
  497.     (
  498.         fConverter
  499.         , (char**)&startTarget
  500.         , (char*)(startTarget + maxBytes)
  501.         , &startSrc
  502.         , srcPtr + srcCount
  503.         , 0
  504.         , false
  505.         , &err
  506.     );
  507.     // Rememember the status before we possibly overite the error code
  508.     const bool res = (err == U_ZERO_ERROR);
  509.     // Put the old handler back
  510.     err = U_ZERO_ERROR;
  511.     UConverterFromUCallback orgAction = NULL;
  512.     ucnv_setFromUCallBack(fConverter, oldCB, NULL, &orgAction, &orgContent, &err);
  513.     if (!res)
  514.     {
  515.         XMLCh tmpBuf[16];
  516.         XMLString::binToText((unsigned int)*startSrc, tmpBuf, 16, 16);
  517.         ThrowXML2
  518.         (
  519.             TranscodingException
  520.             , XMLExcepts::Trans_Unrepresentable
  521.             , tmpBuf
  522.             , getEncodingName()
  523.         );
  524.     }
  525.     // Fill in the chars we ate from the input
  526.     charsEaten = startSrc - srcPtr;
  527.     // Return the chars we stored
  528.     return startTarget - toFill;
  529. }
  530. bool ICUTranscoder::canTranscodeTo(const unsigned int toCheck) const
  531. {
  532.     //
  533.     //  If the passed value is really a surrogate embedded together, then
  534.     //  we need to break it out into its two chars. Else just one. While
  535.     //  we are ate it, convert them to UChar format if required.
  536.     //
  537.     UChar           srcBuf[2];
  538.     unsigned int    srcCount = 1;
  539.     if (toCheck & 0xFFFF0000)
  540.     {
  541.         srcBuf[0] = UChar((toCheck >> 10) + 0xD800);
  542.         srcBuf[1] = UChar(toCheck & 0x3FF) + 0xDC00;
  543.         srcCount++;
  544.     }
  545.      else
  546.     {
  547.         srcBuf[0] = UChar(toCheck);
  548.     }
  549.     //
  550.     //  Set the callback so that it will fail instead of using the rep char.
  551.     //  Remember the old one so we can put it back.
  552.     //
  553.      UErrorCode  err = U_ZERO_ERROR;
  554.      UConverterFromUCallback oldCB = NULL;
  555.      #if (U_ICU_VERSION_MAJOR_NUM < 2)
  556.      void* orgContent;
  557.      #else
  558.      const void* orgContent;
  559.      #endif
  560.      ucnv_setFromUCallBack
  561.          (
  562.          fConverter
  563.          , UCNV_FROM_U_CALLBACK_STOP
  564.          , NULL
  565.          , &oldCB
  566.          , &orgContent
  567.          , &err
  568.          );
  569.     // Set upa temp buffer to format into. Make it more than big enough
  570.     char            tmpBuf[64];
  571.     char*           startTarget = tmpBuf;
  572.     const UChar*    startSrc = srcBuf;
  573.     err = U_ZERO_ERROR;
  574.     ucnv_fromUnicode
  575.     (
  576.         fConverter
  577.         , &startTarget
  578.         , startTarget + 64
  579.         , &startSrc
  580.         , srcBuf + srcCount
  581.         , 0
  582.         , false
  583.         , &err
  584.     );
  585.     // Save the result before we overight the error code
  586.     const bool res = (err == U_ZERO_ERROR);
  587.     // Put the old handler back
  588.     err = U_ZERO_ERROR;
  589.     UConverterFromUCallback orgAction = NULL;
  590.     ucnv_setFromUCallBack(fConverter, oldCB, NULL, &orgAction, &orgContent, &err);
  591.     return res;
  592. }
  593. // ---------------------------------------------------------------------------
  594. //  ICULCPTranscoder: Constructors and Destructor
  595. // ---------------------------------------------------------------------------
  596. ICULCPTranscoder::ICULCPTranscoder(UConverter* const toAdopt) :
  597.     fConverter(toAdopt)
  598. {
  599. }
  600. ICULCPTranscoder::~ICULCPTranscoder()
  601. {
  602.     // If there is a converter, ask ICU to clean it up
  603.     if (fConverter)
  604.     {
  605.         // <TBD> Does this actually delete the structure???
  606.         ucnv_close(fConverter);
  607.         fConverter = 0;
  608.     }
  609. }
  610. // ---------------------------------------------------------------------------
  611. //  ICULCPTranscoder: Constructors and Destructor
  612. // ---------------------------------------------------------------------------
  613. unsigned int ICULCPTranscoder::calcRequiredSize(const XMLCh* const srcText)
  614. {
  615.     if (!srcText)
  616.         return 0;
  617.     //
  618.     //  We do two different versions of this, according to whether XMLCh
  619.     //  is the same size as UChar or not.
  620.     //
  621.     UErrorCode err = U_ZERO_ERROR;
  622.     int32_t targetCap;
  623.     if (sizeof(XMLCh) == sizeof(UChar))
  624.     {
  625.         // Use a faux scope to synchronize while we do this
  626.         {
  627.             XMLMutexLock lockConverter(&fMutex);
  628.             targetCap = ucnv_fromUChars
  629.             (
  630.                 fConverter
  631.                 , 0
  632.                 , 0
  633.                 , (const UChar*)srcText
  634.                 , -1
  635.                 , &err
  636.             );
  637.         }
  638.     }
  639.      else
  640.     {
  641.         // Copy the source to a local temp
  642.         UChar* tmpBuf = convertToUChar(srcText);
  643.         ArrayJanitor<UChar> janTmp(tmpBuf);
  644.         // Use a faux scope to synchronize while we do this
  645.         {
  646.             XMLMutexLock lockConverter(&fMutex);
  647.             targetCap = ucnv_fromUChars
  648.             (
  649.                 fConverter
  650.                 , 0
  651.                 , 0
  652.                 , tmpBuf
  653.                 , -1
  654.                 , &err
  655.             );
  656.         }
  657.     }
  658.     if (err != U_BUFFER_OVERFLOW_ERROR)
  659.         return 0;
  660.     return (unsigned int)targetCap;
  661. }
  662. unsigned int ICULCPTranscoder::calcRequiredSize(const char* const srcText)
  663. {
  664.     if (!srcText)
  665.         return 0;
  666.     int32_t targetCap;
  667.     UErrorCode err = U_ZERO_ERROR;
  668.     // Use a faux scope to synchronize while we do this
  669.     {
  670.         XMLMutexLock lockConverter(&fMutex);
  671.         targetCap = ucnv_toUChars
  672.         (
  673.             fConverter
  674.             , 0
  675.             , 0
  676.             , srcText
  677.             , strlen(srcText)
  678.             , &err
  679.         );
  680.     }
  681.     if (err != U_BUFFER_OVERFLOW_ERROR)
  682.         return 0;
  683. #if (U_ICU_VERSION_MAJOR_NUM < 2)
  684.     // Subtract one since it includes the terminator space
  685.     return (unsigned int)(targetCap - 1);
  686. #else
  687.     // Starting ICU 2.0, this is fixed and all ICU String functions have consistent NUL-termination behavior.
  688.     // The returned length is always the number of output UChar's, not counting an additional, terminating NUL.
  689.     return (unsigned int)(targetCap);
  690. #endif
  691. }
  692. char* ICULCPTranscoder::transcode(const XMLCh* const toTranscode)
  693. {
  694.     char* retBuf = 0;
  695.     // Check for a couple of special cases
  696.     if (!toTranscode)
  697.         return retBuf;
  698.     if (!*toTranscode)
  699.     {
  700.         retBuf = new char[1];
  701.         retBuf[0] = 0;
  702.         return retBuf;
  703.     }
  704.     //
  705.     //  Get the length of the source string since we'll have to use it in
  706.     //  a couple places below.
  707.     //
  708.     const unsigned int srcLen = XMLString::stringLen(toTranscode);
  709.     //
  710.     //  If XMLCh and UChar are not the same size, then we have to make a
  711.     //  temp copy of the text to pass to ICU.
  712.     //
  713.     const UChar* actualSrc;
  714.     UChar* ncActual = 0;
  715.     if (sizeof(XMLCh) == sizeof(UChar))
  716.     {
  717.         actualSrc = (const UChar*)toTranscode;
  718.     }
  719.      else
  720.     {
  721.         // Allocate a non-const temp buf, but store it also in the actual
  722.         ncActual = convertToUChar(toTranscode);
  723.         actualSrc = ncActual;
  724.     }
  725.     // Insure that the temp buffer, if any, gets cleaned up via the nc pointer
  726.     ArrayJanitor<UChar> janTmp(ncActual);
  727.     // Caculate a return buffer size not too big, but less likely to overflow
  728.     int32_t targetLen = (int32_t)(srcLen * 1.25);
  729.     // Allocate the return buffer
  730.     retBuf = new char[targetLen + 1];
  731.     //
  732.     //  Lock now while we call the converter. Use a faux block to do the
  733.     //  lock so that it unlocks immediately afterwards.
  734.     //
  735.     UErrorCode err = U_ZERO_ERROR;
  736.     int32_t targetCap;
  737.     {
  738.         XMLMutexLock lockConverter(&fMutex);
  739.         targetCap = ucnv_fromUChars
  740.         (
  741.             fConverter
  742.             , retBuf
  743.             , targetLen + 1
  744.             , actualSrc
  745.             , -1
  746.             , &err
  747.         );
  748.     }
  749.     // If targetLen is not enough then buffer overflow might occur
  750.     if (err == U_BUFFER_OVERFLOW_ERROR)
  751.     {
  752.         //
  753.         //  Reset the error, delete the old buffer, allocate a new one,
  754.         //  and try again.
  755.         //
  756.         err = U_ZERO_ERROR;
  757.         delete [] retBuf;
  758.         retBuf = new char[targetCap + 1];
  759.         // Lock again before we retry
  760.         XMLMutexLock lockConverter(&fMutex);
  761.         targetCap = ucnv_fromUChars
  762.         (
  763.             fConverter
  764.             , retBuf
  765.             , targetCap
  766.             , actualSrc
  767.             , -1
  768.             , &err
  769.         );
  770.     }
  771.     if (U_FAILURE(err))
  772.     {
  773.         delete [] retBuf;
  774.         return 0;
  775.     }
  776.     // Cap it off and return
  777.     retBuf[targetCap] = 0;
  778.     return retBuf;
  779. }
  780. XMLCh* ICULCPTranscoder::transcode(const char* const toTranscode)
  781. {
  782.     // Watch for a few pyscho corner cases
  783.     if (!toTranscode)
  784.         return 0;
  785.     if (!*toTranscode)
  786.     {
  787.         XMLCh* retVal = new XMLCh[1];
  788.         retVal[0] = 0;
  789.         return retVal;
  790.     }
  791.     //
  792.     //  Get the length of the string to transcode. The Unicode string will
  793.     //  almost always be no more chars than were in the source, so this is
  794.     //  the best guess as to the storage needed.
  795.     //
  796.     const int32_t srcLen = (int32_t)strlen(toTranscode);
  797.     // We need a target buffer of UChars to fill in
  798.     UChar* targetBuf = 0;
  799.     // Now lock while we do these calculations
  800.     UErrorCode err = U_ZERO_ERROR;
  801.     int32_t targetCap;
  802.     {
  803.         XMLMutexLock lockConverter(&fMutex);
  804.         //
  805.         //  Here we don't know what the target length will be so use 0 and
  806.         //  expect an U_BUFFER_OVERFLOW_ERROR in which case it'd get resolved
  807.         //  by the correct capacity value.
  808.         //
  809.         targetCap = ucnv_toUChars
  810.         (
  811.             fConverter
  812.             , 0
  813.             , 0
  814.             , toTranscode
  815.             , srcLen
  816.             , &err
  817.         );
  818.         if (err != U_BUFFER_OVERFLOW_ERROR)
  819.             return 0;
  820.         err = U_ZERO_ERROR;
  821.         targetBuf = new UChar[targetCap + 1];
  822.         ucnv_toUChars
  823.         (
  824.             fConverter
  825.             , targetBuf
  826.             , targetCap
  827.             , toTranscode
  828.             , srcLen
  829.             , &err
  830.         );
  831.     }
  832.     if (U_FAILURE(err))
  833.     {
  834.         // Clean up if we got anything allocated
  835.         delete [] targetBuf;
  836.         return 0;
  837.     }
  838.     // Cap it off to make sure
  839.     targetBuf[targetCap] = 0;
  840.     //
  841.     //  If XMLCh and UChar are the same size, then we can return retVal
  842.     //  as is. Else, we have to allocate another buffer and copy the data
  843.     //  over to it.
  844.     //
  845.     XMLCh* actualRet;
  846.     if (sizeof(XMLCh) == sizeof(UChar))
  847.     {
  848.         actualRet = (XMLCh*)targetBuf;
  849.     }
  850.      else
  851.     {
  852.         actualRet = convertToXMLCh(targetBuf);
  853.         delete [] targetBuf;
  854.     }
  855.     return actualRet;
  856. }
  857. bool ICULCPTranscoder::transcode(const  char* const     toTranscode
  858.                                 ,       XMLCh* const    toFill
  859.                                 , const unsigned int    maxChars)
  860. {
  861.     // Check for a couple of psycho corner cases
  862.     if (!toTranscode || !maxChars)
  863.     {
  864.         toFill[0] = 0;
  865.         return true;
  866.     }
  867.     if (!*toTranscode)
  868.     {
  869.         toFill[0] = 0;
  870.         return true;
  871.     }
  872.     // We'll need this in a couple of places below
  873.     const unsigned int srcLen = strlen(toTranscode);
  874.     //
  875.     //  Set up the target buffer. If XMLCh and UChar are not the same size
  876.     //  then we have to use a temp buffer and convert over.
  877.     //
  878.     UChar* targetBuf;
  879.     if (sizeof(XMLCh) == sizeof(UChar))
  880.         targetBuf = (UChar*)toFill;
  881.     else
  882.         targetBuf = new UChar[maxChars + 1];
  883.     //
  884.     //  Use a faux block to enforce a lock on the converter, which will
  885.     //  unlock immediately after its completed.
  886.     //
  887.     UErrorCode err = U_ZERO_ERROR;
  888.     {
  889.         XMLMutexLock lockConverter(&fMutex);
  890.         ucnv_toUChars
  891.         (
  892.             fConverter
  893.             , targetBuf
  894.             , maxChars + 1
  895.             , toTranscode
  896.             , srcLen
  897.             , &err
  898.         );
  899.     }
  900.     if (U_FAILURE(err))
  901.     {
  902.         if (targetBuf != (UChar*)toFill)
  903.             delete [] targetBuf;
  904.         return false;
  905.     }
  906.     // If the sizes are not the same, then copy the data over
  907.     if (sizeof(XMLCh) != sizeof(UChar))
  908.     {
  909.         UChar* srcPtr = targetBuf;
  910.         XMLCh* outPtr = toFill;
  911.         while (*srcPtr)
  912.             *outPtr++ = XMLCh(*srcPtr++);
  913.         *outPtr = 0;
  914.         // And delete the temp buffer
  915.         delete [] targetBuf;
  916.     }
  917.     return true;
  918. }
  919. bool ICULCPTranscoder::transcode(   const   XMLCh* const    toTranscode
  920.                                     ,       char* const     toFill
  921.                                     , const unsigned int    maxChars)
  922. {
  923.     // Watch for a few psycho corner cases
  924.     if (!toTranscode || !maxChars)
  925.     {
  926.         toFill[0] = 0;
  927.         return true;
  928.     }
  929.     if (!*toTranscode)
  930.     {
  931.         toFill[0] = 0;
  932.         return true;
  933.     }
  934.     //
  935.     //  If XMLCh and UChar are not the same size, then we have to make a
  936.     //  temp copy of the text to pass to ICU.
  937.     //
  938.     const UChar* actualSrc;
  939.     UChar* ncActual = 0;
  940.     if (sizeof(XMLCh) == sizeof(UChar))
  941.     {
  942.         actualSrc = (const UChar*)toTranscode;
  943.     }
  944.      else
  945.     {
  946.         // Allocate a non-const temp buf, but store it also in the actual
  947.         ncActual = convertToUChar(toTranscode);
  948.         actualSrc = ncActual;
  949.     }
  950.     // Insure that the temp buffer, if any, gets cleaned up via the nc pointer
  951.     ArrayJanitor<UChar> janTmp(ncActual);
  952.     //
  953.     //  Use a faux block to enforce a lock on the converter while we do this.
  954.     //  It will be released immediately after its done.
  955.     //
  956.     UErrorCode err = U_ZERO_ERROR;
  957.     int32_t targetCap;
  958.     {
  959.         XMLMutexLock lockConverter(&fMutex);
  960.         targetCap = ucnv_fromUChars
  961.         (
  962.             fConverter
  963.             , toFill
  964.             , maxChars
  965.             , actualSrc
  966.             , -1
  967.             , &err
  968.         );
  969.     }
  970.     if (U_FAILURE(err))
  971.         return false;
  972.     toFill[targetCap] = 0;
  973.     return true;
  974. }