GME  13
XMLFormatter.cpp
Go to the documentation of this file.
00001 /*
00002  * Licensed to the Apache Software Foundation (ASF) under one or more
00003  * contributor license agreements.  See the NOTICE file distributed with
00004  * this work for additional information regarding copyright ownership.
00005  * The ASF licenses this file to You under the Apache License, Version 2.0
00006  * (the "License"); you may not use this file except in compliance with
00007  * the License.  You may obtain a copy of the License at
00008  *
00009  *      http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00023 // ---------------------------------------------------------------------------
00024 //  Includes
00025 // ---------------------------------------------------------------------------
00026 #include <xercesc/util/PlatformUtils.hpp>
00027 #include <xercesc/util/XMLUniDefs.hpp>
00028 #include <xercesc/util/XMLString.hpp>
00029 #include <xercesc/util/TransService.hpp>
00030 #include <xercesc/util/TranscodingException.hpp>
00031 #include <xercesc/util/XMLExceptMsgs.hpp>
00032 #include <xercesc/framework/XMLFormatter.hpp>
00033 #include <xercesc/util/Janitor.hpp>
00034 #include <xercesc/util/XMLChar.hpp>
00035 
00036 #include <string.h>
00037 
00038 XERCES_CPP_NAMESPACE_BEGIN
00039 
00040 // ---------------------------------------------------------------------------
00041 //  Local data
00042 //
00043 //  gXXXRef
00044 //      These are hard coded versions of the char refs we put out for the
00045 //      standard char refs.
00046 //
00047 //  gEscapeChars
00048 //      For each style of escape, we have a list of the chars that must
00049 //      be escaped for that style. The first null hit in each list indicates
00050 //      no more valid entries in that list. The first entry is a dummy for
00051 //      the NoEscapes style.
00052 // ---------------------------------------------------------------------------
00053 static const XMLCh  gAmpRef[] =
00054 {
00055     chAmpersand, chLatin_a, chLatin_m, chLatin_p, chSemiColon, chNull
00056 };
00057 
00058 static const XMLCh  gAposRef[] =
00059 {
00060     chAmpersand, chLatin_a, chLatin_p, chLatin_o, chLatin_s, chSemiColon, chNull
00061 };
00062 
00063 static const XMLCh  gGTRef[] =
00064 {
00065     chAmpersand, chLatin_g, chLatin_t, chSemiColon, chNull
00066 };
00067 
00068 static const XMLCh  gLTRef[] =
00069 {
00070     chAmpersand, chLatin_l, chLatin_t, chSemiColon, chNull
00071 };
00072 
00073 static const XMLCh  gQuoteRef[] =
00074 {
00075     chAmpersand, chLatin_q, chLatin_u, chLatin_o, chLatin_t, chSemiColon, chNull
00076 };
00077 
00078 static const unsigned int kEscapeCount = 7;
00079 static const XMLCh gEscapeChars[XMLFormatter::EscapeFlags_Count][kEscapeCount] =
00080 {
00081         { chNull      , chNull       , chNull        , chNull       , chNull        , chNull    , chNull }
00082     ,   { chAmpersand , chCloseAngle , chDoubleQuote , chOpenAngle  , chSingleQuote , chNull    , chNull }
00083     ,   { chAmpersand , chOpenAngle  , chDoubleQuote , chLF         , chCR          , chHTab    , chNull }
00084     ,   { chAmpersand , chOpenAngle  , chCloseAngle  , chNull       , chNull        , chNull    , chNull }
00085 };
00086 
00087 // ---------------------------------------------------------------------------
00088 //  Local methods
00089 // ---------------------------------------------------------------------------
00090 bool XMLFormatter::inEscapeList(const XMLFormatter::EscapeFlags escStyle
00091                               , const XMLCh                     toCheck)
00092 {
00093     const XMLCh* escList = gEscapeChars[escStyle];
00094     while (*escList)
00095     {
00096         if (*escList++ == toCheck)
00097             return true;
00098     }
00099 
00100     /***
00101      *  XML1.1
00102      *
00103      *  Finally, there is considerable demand to define a standard representation of
00104      *  arbitrary Unicode characters in XML documents. Therefore, XML 1.1 allows the
00105      *  use of character references to the control characters #x1 through #x1F,
00106      *  most of which are forbidden in XML 1.0. For reasons of robustness, however,
00107      *  these characters still cannot be used directly in documents.
00108      *  In order to improve the robustness of character encoding detection, the
00109      *  additional control characters #x7F through #x9F, which were freely allowed in
00110      *  XML 1.0 documents, now must also appear only as character references.
00111      *  (Whitespace characters are of course exempt.) The minor sacrifice of backward
00112      *  compatibility is considered not significant.
00113      *  Due to potential problems with APIs, #x0 is still forbidden both directly and
00114      *  as a character reference.
00115      *
00116     ***/
00117     if (fIsXML11)
00118     {
00119         // for XML11
00120         if ( XMLChar1_1::isControlChar(toCheck, 0) &&
00121             !XMLChar1_1::isWhitespace(toCheck, 0)   )
00122         {
00123             return true;
00124         }
00125         else
00126         {
00127             return false;
00128         }
00129     }
00130     else
00131     {
00132         return false;
00133     }
00134 
00135 }
00136 
00137 
00138 // ---------------------------------------------------------------------------
00139 //  XMLFormatter: Constructors and Destructor
00140 // ---------------------------------------------------------------------------
00141 XMLFormatter::XMLFormatter( const   char* const             outEncoding
00142                             , const char* const             docVersion
00143                             ,       XMLFormatTarget* const  target
00144                             , const EscapeFlags             escapeFlags
00145                             , const UnRepFlags              unrepFlags
00146                             ,       MemoryManager* const    manager)
00147     : fEscapeFlags(escapeFlags)
00148     , fOutEncoding(0)
00149     , fTarget(target)
00150     , fUnRepFlags(unrepFlags)
00151     , fXCoder(0)
00152     , fAposRef(0)
00153     , fAposLen(0)
00154     , fAmpRef(0)
00155     , fAmpLen(0)
00156     , fGTRef(0)
00157     , fGTLen(0)
00158     , fLTRef(0)
00159     , fLTLen(0)
00160     , fQuoteRef(0)
00161     , fQuoteLen(0)
00162     , fIsXML11(false)
00163     , fMemoryManager(manager)
00164 {
00165     // Transcode the encoding string
00166     fOutEncoding = XMLString::transcode(outEncoding, fMemoryManager);
00167 
00168     // Try to create a transcoder for this encoding
00169     XMLTransService::Codes resCode;
00170     fXCoder = XMLPlatformUtils::fgTransService->makeNewTranscoderFor
00171     (
00172         fOutEncoding
00173         , resCode
00174         , kTmpBufSize
00175         , fMemoryManager
00176     );
00177 
00178     if (!fXCoder)
00179     {
00180         fMemoryManager->deallocate(fOutEncoding); //delete [] fOutEncoding;
00181         ThrowXMLwithMemMgr1
00182         (
00183             TranscodingException
00184             , XMLExcepts::Trans_CantCreateCvtrFor
00185             , outEncoding
00186             , fMemoryManager
00187         );
00188     }
00189 
00190     XMLCh* const tmpDocVer = XMLString::transcode(docVersion, fMemoryManager);
00191     ArrayJanitor<XMLCh> jname(tmpDocVer, fMemoryManager);
00192     fIsXML11 = XMLString::equals(tmpDocVer, XMLUni::fgVersion1_1);
00193 }
00194 
00195 
00196 XMLFormatter::XMLFormatter( const   XMLCh* const            outEncoding
00197                             , const XMLCh* const            docVersion
00198                             ,       XMLFormatTarget* const  target
00199                             , const EscapeFlags             escapeFlags
00200                             , const UnRepFlags              unrepFlags
00201                             ,       MemoryManager* const    manager)
00202     : fEscapeFlags(escapeFlags)
00203     , fOutEncoding(0)
00204     , fTarget(target)
00205     , fUnRepFlags(unrepFlags)
00206     , fXCoder(0)
00207     , fAposRef(0)
00208     , fAposLen(0)
00209     , fAmpRef(0)
00210     , fAmpLen(0)
00211     , fGTRef(0)
00212     , fGTLen(0)
00213     , fLTRef(0)
00214     , fLTLen(0)
00215     , fQuoteRef(0)
00216     , fQuoteLen(0)
00217     , fIsXML11(false)
00218     , fMemoryManager(manager)
00219 {
00220     // Try to create a transcoder for this encoding
00221     XMLTransService::Codes resCode;
00222     fXCoder = XMLPlatformUtils::fgTransService->makeNewTranscoderFor
00223     (
00224         outEncoding
00225         , resCode
00226         , kTmpBufSize
00227         , fMemoryManager
00228     );
00229 
00230     if (!fXCoder)
00231     {
00232         ThrowXMLwithMemMgr1
00233         (
00234             TranscodingException
00235             , XMLExcepts::Trans_CantCreateCvtrFor
00236             , outEncoding
00237             , fMemoryManager
00238         );
00239     }
00240 
00241     // Copy the encoding string
00242     fOutEncoding = XMLString::replicate(outEncoding, fMemoryManager);
00243 
00244 
00245     fIsXML11 = XMLString::equals(docVersion, XMLUni::fgVersion1_1);
00246 }
00247 
00248 XMLFormatter::XMLFormatter( const   char* const             outEncoding
00249                             ,       XMLFormatTarget* const  target
00250                             , const EscapeFlags             escapeFlags
00251                             , const UnRepFlags              unrepFlags
00252                             ,       MemoryManager* const    manager)
00253     : fEscapeFlags(escapeFlags)
00254     , fOutEncoding(0)
00255     , fTarget(target)
00256     , fUnRepFlags(unrepFlags)
00257     , fXCoder(0)
00258     , fAposRef(0)
00259     , fAposLen(0)
00260     , fAmpRef(0)
00261     , fAmpLen(0)
00262     , fGTRef(0)
00263     , fGTLen(0)
00264     , fLTRef(0)
00265     , fLTLen(0)
00266     , fQuoteRef(0)
00267     , fQuoteLen(0)
00268     , fIsXML11(false)
00269     , fMemoryManager(manager)
00270 {
00271     // this constructor uses "1.0" for the docVersion
00272 
00273     // Transcode the encoding string
00274     fOutEncoding = XMLString::transcode(outEncoding, fMemoryManager);
00275 
00276     // Try to create a transcoder for this encoding
00277     XMLTransService::Codes resCode;
00278     fXCoder = XMLPlatformUtils::fgTransService->makeNewTranscoderFor
00279     (
00280         fOutEncoding
00281         , resCode
00282         , kTmpBufSize
00283         , fMemoryManager
00284     );
00285 
00286     if (!fXCoder)
00287     {
00288         fMemoryManager->deallocate(fOutEncoding); //delete [] fOutEncoding;
00289         ThrowXMLwithMemMgr1
00290         (
00291             TranscodingException
00292             , XMLExcepts::Trans_CantCreateCvtrFor
00293             , outEncoding
00294             , fMemoryManager
00295         );
00296     }
00297 
00298     //XMLCh* const tmpDocVer = XMLString::transcode("1.0", fMemoryManager);
00299     //ArrayJanitor<XMLCh> jname(tmpDocVer, fMemoryManager);
00300     //fIsXML11 = XMLString::equals(tmpDocVer, XMLUni::fgVersion1_1);
00301     fIsXML11 = false;  // docVersion 1.0 is not 1.1!
00302 }
00303 
00304 
00305 XMLFormatter::XMLFormatter( const   XMLCh* const            outEncoding
00306                             ,       XMLFormatTarget* const  target
00307                             , const EscapeFlags             escapeFlags
00308                             , const UnRepFlags              unrepFlags
00309                             ,       MemoryManager* const    manager)
00310     : fEscapeFlags(escapeFlags)
00311     , fOutEncoding(0)
00312     , fTarget(target)
00313     , fUnRepFlags(unrepFlags)
00314     , fXCoder(0)
00315     , fAposRef(0)
00316     , fAposLen(0)
00317     , fAmpRef(0)
00318     , fAmpLen(0)
00319     , fGTRef(0)
00320     , fGTLen(0)
00321     , fLTRef(0)
00322     , fLTLen(0)
00323     , fQuoteRef(0)
00324     , fQuoteLen(0)
00325     , fIsXML11(false)
00326     , fMemoryManager(manager)
00327 {
00328     // this constructor uses XMLUni::fgVersion1_0 for the docVersion
00329 
00330     // Try to create a transcoder for this encoding
00331     XMLTransService::Codes resCode;
00332     fXCoder = XMLPlatformUtils::fgTransService->makeNewTranscoderFor
00333     (
00334         outEncoding
00335         , resCode
00336         , kTmpBufSize
00337         , fMemoryManager
00338     );
00339 
00340     if (!fXCoder)
00341     {
00342         ThrowXMLwithMemMgr1
00343         (
00344             TranscodingException
00345             , XMLExcepts::Trans_CantCreateCvtrFor
00346             , outEncoding
00347             , fMemoryManager
00348         );
00349     }
00350 
00351     // Copy the encoding string
00352     fOutEncoding = XMLString::replicate(outEncoding, fMemoryManager);
00353 
00354     //fIsXML11 = XMLString::equals(docVersion, XMLUni::fgVersion1_1);
00355     fIsXML11 = false;  // docVersion 1.0 is not 1.1!
00356 }
00357 
00358 XMLFormatter::~XMLFormatter()
00359 {
00360     fMemoryManager->deallocate(fAposRef); //delete [] fAposRef;
00361     fMemoryManager->deallocate(fAmpRef); //delete [] fAmpRef;
00362     fMemoryManager->deallocate(fGTRef); //delete [] fGTRef;
00363     fMemoryManager->deallocate(fLTRef); //delete [] fLTRef;
00364     fMemoryManager->deallocate(fQuoteRef); //delete [] fQuoteRef;
00365     fMemoryManager->deallocate(fOutEncoding); //delete [] fOutEncoding;
00366     delete fXCoder;
00367 
00368     // We DO NOT own the target object!
00369 }
00370 
00371 
00372 // ---------------------------------------------------------------------------
00373 //  XMLFormatter: Formatting methods
00374 // ---------------------------------------------------------------------------
00375 void
00376 XMLFormatter::formatBuf(const   XMLCh* const    toFormat
00377                         , const XMLSize_t       count
00378                         , const EscapeFlags     escapeFlags
00379                         , const UnRepFlags      unrepFlags)
00380 {
00381     //
00382     //  Figure out the actual escape flag value. If the parameter is not
00383     //  the default, then take it. Else take the current default.
00384     //
00385     const EscapeFlags actualEsc = (escapeFlags == DefaultEscape)
00386                                 ? fEscapeFlags : escapeFlags;
00387 
00388     // And do the same for the unrep flags
00389     const UnRepFlags  actualUnRep = (unrepFlags == DefaultUnRep)
00390                                     ? fUnRepFlags : unrepFlags;
00391 
00392     //
00393     //  If the actual unrep action is that they want to provide char refs
00394     //  for unrepresentable chars, then this one is a much more difficult
00395     //  one to do cleanly, and we handle it separately.
00396     //
00397     if (actualUnRep == UnRep_CharRef)
00398     {
00399         specialFormat(toFormat, count, actualEsc);
00400         return;
00401     }
00402 
00403     //
00404     //  If we don't have any escape flags set, then we can do the most
00405     //  efficient loop, else we have to do it the hard way.
00406     //
00407     const XMLCh*    srcPtr = toFormat;
00408     const XMLCh*    endPtr = toFormat + count;
00409     if (actualEsc == NoEscapes)
00410     {
00411         //
00412         //  Just do a whole buffer at a time into the temp buffer, cap
00413         //  it off, and send it to the target.
00414         //
00415         if (srcPtr < endPtr)
00416            srcPtr += handleUnEscapedChars(srcPtr, endPtr - srcPtr, actualUnRep);
00417     }
00418      else
00419     {
00420         //
00421         //  Escape chars that require it according tot he scale flags
00422         //  we were given. For the others, try to accumulate them and
00423         //  format them in as big as bulk as we can.
00424         //
00425         while (srcPtr < endPtr)
00426         {
00427             //
00428             //  Run a temp pointer up until we hit a character that we have
00429             //  to escape. Then we can convert all the chars between our
00430             //  current source pointer and here all at once.
00431             //
00432             const XMLCh* tmpPtr = srcPtr;
00433             while ((tmpPtr < endPtr) && !inEscapeList(actualEsc, *tmpPtr))
00434                 tmpPtr++;
00435 
00436             //
00437             //  If we got any chars, then lets convert them and write them
00438             //  out.
00439             //
00440             if (tmpPtr > srcPtr)
00441                srcPtr += handleUnEscapedChars(srcPtr, tmpPtr - srcPtr,
00442                                               actualUnRep);
00443 
00444              else if (tmpPtr < endPtr)
00445             {
00446                 //
00447                 //  Ok, so we've hit a char that must be escaped. So do
00448                 //  this one specially.
00449                 //
00450                 const XMLByte * theChars;
00451                 switch (*srcPtr) {
00452                     case chAmpersand :
00453                         theChars = getCharRef(fAmpLen, fAmpRef, gAmpRef);
00454                         fTarget->writeChars(theChars, fAmpLen, this);
00455                         break;
00456 
00457                     case chSingleQuote :
00458                         theChars = getCharRef(fAposLen, fAposRef, gAposRef);
00459                         fTarget->writeChars(theChars, fAposLen, this);
00460                         break;
00461 
00462                     case chDoubleQuote :
00463                         theChars = getCharRef(fQuoteLen, fQuoteRef, gQuoteRef);
00464                         fTarget->writeChars(theChars, fQuoteLen, this);
00465                         break;
00466 
00467                     case chCloseAngle :
00468                         theChars = getCharRef(fGTLen, fGTRef, gGTRef);
00469                         fTarget->writeChars(theChars, fGTLen, this);
00470                         break;
00471 
00472                     case chOpenAngle :
00473                         theChars = getCharRef(fLTLen, fLTRef, gLTRef);
00474                         fTarget->writeChars(theChars, fLTLen, this);
00475                         break;
00476 
00477                     default:
00478                         // control characters
00479                         writeCharRef(*srcPtr);
00480                         break;
00481                 }
00482                 srcPtr++;
00483             }
00484         }
00485     }
00486 }
00487 
00488 
00489 XMLSize_t
00490 XMLFormatter::handleUnEscapedChars(const XMLCh *                  srcPtr,
00491                                    const XMLSize_t                oCount,
00492                                    const UnRepFlags               actualUnRep)
00493 {
00494    //
00495    //  Use that to figure out what I should pass to the transcoder. If we
00496    //  are doing character references or failing for unrepresentable chars,
00497    //  then we just throw, since we should never get a call for something
00498    //  we cannot represent. Else, we tell it to just use the replacement
00499    //  char.
00500    //
00501    const XMLTranscoder::UnRepOpts unRepOpts = (actualUnRep == UnRep_Replace)
00502                                              ? XMLTranscoder::UnRep_RepChar
00503                                              : XMLTranscoder::UnRep_Throw;
00504 
00505    XMLSize_t charsEaten;
00506    XMLSize_t count = oCount;
00507 
00508    while (count) {
00509      const XMLSize_t srcChars = (count > XMLSize_t (kTmpBufSize))
00510        ? XMLSize_t (kTmpBufSize) : count;
00511 
00512       const XMLSize_t outBytes
00513          = fXCoder->transcodeTo(srcPtr, srcChars,
00514                                 fTmpBuf, kTmpBufSize,
00515                                 charsEaten, unRepOpts);
00516 
00517       if (outBytes) {
00518          fTmpBuf[outBytes]     = 0; fTmpBuf[outBytes + 1] = 0;
00519          fTmpBuf[outBytes + 2] = 0; fTmpBuf[outBytes + 3] = 0;
00520          fTarget->writeChars(fTmpBuf, outBytes, this);
00521       }
00522 
00523       srcPtr += charsEaten;
00524       count  -= charsEaten;
00525    }
00526 
00527    return oCount; // This should be an assertion that count == 0.
00528 }
00529 
00530 
00531 XMLFormatter& XMLFormatter::operator<<(const XMLCh* const toFormat)
00532 {
00533     const XMLSize_t len = XMLString::stringLen(toFormat);
00534     formatBuf(toFormat, len);
00535     return *this;
00536 }
00537 
00538 XMLFormatter& XMLFormatter::operator<<(const XMLCh toFormat)
00539 {
00540     // Make a temp string format that
00541     XMLCh szTmp[2];
00542     szTmp[0] = toFormat;
00543     szTmp[1] = 0;
00544 
00545     formatBuf(szTmp, 1);
00546     return *this;
00547 }
00548 
00554 void XMLFormatter::writeBOM(const XMLByte* const toFormat
00555                           , const XMLSize_t      count)
00556 {
00557     fTarget->writeChars(toFormat, count, this);
00558 }
00559 
00560 // ---------------------------------------------------------------------------
00561 //  XMLFormatter: Private helper methods
00562 // ---------------------------------------------------------------------------
00563 void XMLFormatter::writeCharRef(const XMLCh &toWrite)
00564 {
00565     XMLCh tmpBuf[32];
00566     tmpBuf[0] = chAmpersand;
00567     tmpBuf[1] = chPound;
00568     tmpBuf[2] = chLatin_x;
00569 
00570     // Build a char ref for the current char
00571     XMLString::binToText(toWrite, &tmpBuf[3], 8, 16, fMemoryManager);
00572     const XMLSize_t bufLen = XMLString::stringLen(tmpBuf);
00573     tmpBuf[bufLen] = chSemiColon;
00574     tmpBuf[bufLen+1] = chNull;
00575 
00576     // write it out
00577     formatBuf(tmpBuf
00578             , bufLen + 1
00579             , XMLFormatter::NoEscapes
00580             , XMLFormatter::UnRep_Fail);
00581 
00582 }
00583 
00584 void XMLFormatter::writeCharRef(XMLSize_t toWrite)
00585 {
00586     XMLCh tmpBuf[64];
00587     tmpBuf[0] = chAmpersand;
00588     tmpBuf[1] = chPound;
00589     tmpBuf[2] = chLatin_x;
00590 
00591     // Build a char ref for the current char
00592     XMLString::sizeToText(toWrite, &tmpBuf[3], 32, 16, fMemoryManager);
00593     const XMLSize_t bufLen = XMLString::stringLen(tmpBuf);
00594     tmpBuf[bufLen] = chSemiColon;
00595     tmpBuf[bufLen+1] = chNull;
00596 
00597     // write it out
00598     formatBuf(tmpBuf
00599             , bufLen + 1
00600             , XMLFormatter::NoEscapes
00601             , XMLFormatter::UnRep_Fail);
00602 
00603 }
00604 
00605 
00606 const XMLByte* XMLFormatter::getCharRef(XMLSize_t     &count,
00607                                         XMLByte*      &ref,
00608                                         const XMLCh *  stdRef)
00609 {
00610    if (!ref) {
00611 
00612        XMLSize_t charsEaten;
00613        const XMLSize_t outBytes =
00614            fXCoder->transcodeTo(stdRef, XMLString::stringLen(stdRef),
00615                                 fTmpBuf, kTmpBufSize, charsEaten,
00616                                 XMLTranscoder::UnRep_Throw);
00617 
00618        fTmpBuf[outBytes] = 0;
00619        fTmpBuf[outBytes + 1] = 0;
00620        fTmpBuf[outBytes + 2] = 0;
00621        fTmpBuf[outBytes + 3] = 0;
00622 
00623        ref = (XMLByte*) fMemoryManager->allocate
00624        (
00625            (outBytes + 4) * sizeof(XMLByte)
00626        );//new XMLByte[outBytes + 4];
00627        memcpy(ref, fTmpBuf, outBytes + 4);
00628        count = outBytes;
00629    }
00630 
00631    return ref;
00632 }
00633 
00634 void XMLFormatter::specialFormat(const  XMLCh* const    toFormat
00635                                 , const XMLSize_t       count
00636                                 , const EscapeFlags     escapeFlags)
00637 {
00638     //
00639     //  We have to check each character and see if it could be represented.
00640     //  As long as it can, we just keep up with where we started and how
00641     //  many chars we've checked. When we hit an unrepresentable one, we
00642     //  stop, transcode everything we've collected, then start handling
00643     //  the unrepresentables via char refs. We repeat this until we get all
00644     //  the chars done.
00645     //
00646     const XMLCh*    srcPtr = toFormat;
00647     const XMLCh*    endPtr = toFormat + count;
00648 
00649     while (srcPtr < endPtr)
00650     {
00651         const XMLCh* tmpPtr = srcPtr;
00652         while (tmpPtr < endPtr)
00653         {
00654             if (fXCoder->canTranscodeTo(*tmpPtr))
00655                 tmpPtr++;
00656             else
00657                 break;
00658         }
00659 
00660         if (tmpPtr > srcPtr)
00661         {
00662             // We got at least some chars that can be done normally
00663             formatBuf
00664             (
00665                 srcPtr
00666                 , tmpPtr - srcPtr
00667                 , escapeFlags
00668                 , XMLFormatter::UnRep_Fail
00669             );
00670 
00671             // Update the source pointer to our new spot
00672             srcPtr = tmpPtr;
00673         }
00674          else
00675         {
00676 
00677             //  We hit something unrepresentable. So continue forward doing
00678             //  char refs until we hit something representable again or the
00679             //  end of input.
00680             //
00681             while (srcPtr < endPtr)
00682             {
00683                 if ((*srcPtr & 0xFC00) == 0xD800) {
00684                     // we have encountered a surrogate, need to recombine before printing out
00685                     // use writeCharRef that takes XMLSize_t to get values larger than
00686                     // hex 0xFFFF printed.
00687                     tmpPtr = srcPtr;
00688                     tmpPtr++; // point at low surrogate
00689                     writeCharRef((XMLSize_t) (0x10000+((*srcPtr-0xD800)<<10)+*tmpPtr-0xDC00));
00690                     srcPtr++; // advance to low surrogate (will advance again below)
00691                 }
00692                 else {
00693                     writeCharRef(*srcPtr);
00694                 }
00695 
00696                 // Move up the source pointer and break out if needed
00697                 srcPtr++;
00698                 if (fXCoder->canTranscodeTo(*srcPtr))
00699                     break;
00700             }
00701         }
00702     }
00703 }
00704 
00705 XERCES_CPP_NAMESPACE_END