source: icXML/icXML-devel/src/icxercesc/util/Transcoders/ICU/ICUTransService.cpp @ 3153

Last change on this file since 3153 was 3153, checked in by cameron, 6 years ago

Updates for build

File size: 37.2 KB
Line 
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18/*
19 * $Id: ICUTransService.cpp 901107 2010-01-20 08:45:02Z borisk $
20 */
21
22
23// ---------------------------------------------------------------------------
24//  Includes
25// ---------------------------------------------------------------------------
26#include <icxercesc/util/PlatformUtils.hpp>
27#include <xercesc/util/Janitor.hpp>
28#include <xercesc/util/TranscodingException.hpp>
29#include <icxercesc/util/XMLString.hpp>
30#include <xercesc/util/XMLUniDefs.hpp>
31#include <icxercesc/util/Transcoders/ICU/ICUTransService.hpp>
32#include <string.h>
33#include <unicode/uloc.h>
34#include <unicode/uchar.h>
35#include <unicode/ucnv.h>
36#include <unicode/ucnv_err.h>
37#include <unicode/ustring.h>
38#include <unicode/udata.h>
39#if (U_ICU_VERSION_MAJOR_NUM >= 2)
40    #include <unicode/uclean.h>
41#endif
42
43#if !defined(XML_OS390) && !defined(XML_AS400) && !defined(XML_HPUX) && !defined(XML_PTX)
44// Forward reference the symbol which points to the ICU converter data.
45#if (U_ICU_VERSION_MAJOR_NUM < 2)
46extern "C" const uint8_t U_IMPORT icudata_dat[];
47#endif
48#endif
49
50#if !defined(U16_NEXT_UNSAFE) && defined(UTF16_NEXT_CHAR_UNSAFE)
51    #define U16_NEXT_UNSAFE UTF16_NEXT_CHAR_UNSAFE
52#endif
53
54#if !defined(U16_APPEND_UNSAFE) && defined(UTF16_APPEND_CHAR_UNSAFE)
55    #define U16_APPEND_UNSAFE UTF16_APPEND_CHAR_UNSAFE
56#endif
57
58#if !defined(U_IS_BMP) && defined(UTF16_CHAR_LENGTH)
59    #define U_IS_BMP(c) (UTF16_CHAR_LENGTH(c)==1)
60#endif
61
62
63XERCES_CPP_NAMESPACE_BEGIN
64
65// ---------------------------------------------------------------------------
66//  Local, const data
67// ---------------------------------------------------------------------------
68static const XMLCh gMyServiceId[] =
69{
70    chLatin_I, chLatin_C, chLatin_U, chNull
71};
72
73static const XMLCh gS390Id[] =
74{
75    chLatin_S, chDigit_3, chDigit_9, chDigit_0, chNull
76};
77
78static const XMLCh gs390Id[] =
79{
80    chLatin_s, chDigit_3, chDigit_9, chDigit_0, chNull
81};
82
83static const XMLCh gswaplfnlId[] =
84{
85    chComma, chLatin_s, chLatin_w, chLatin_a, chLatin_p,
86    chLatin_l, chLatin_f, chLatin_n, chLatin_l, chNull
87};
88// ---------------------------------------------------------------------------
89//  Local functions
90// ---------------------------------------------------------------------------
91
92//
93//  When XMLCh and ICU's UChar are not the same size, we have to do a temp
94//  conversion of all strings. These local helper methods make that easier.
95//
96static UChar* convertToUChar( const XMLCh* const   toConvert
97                            , const XMLSize_t      srcLen = 0
98                            , MemoryManager* const manager = 0)
99{
100    const XMLSize_t actualLen = srcLen
101                                   ? srcLen : XMLString::stringLen(toConvert);
102
103    UChar* tmpBuf = (manager)
104        ? (UChar*) manager->allocate((actualLen + 1) * sizeof(UChar))
105                : new UChar[actualLen + 1];
106    const XMLCh* srcPtr = toConvert;
107    UChar* outPtr = tmpBuf;
108    while (*srcPtr)
109        *outPtr++ = UChar(*srcPtr++);
110    *outPtr = 0;
111
112    return tmpBuf;
113}
114
115
116static XMLCh* convertToXMLCh( const UChar* const toConvert,
117                            MemoryManager* const manager = 0)
118{
119    const unsigned int srcLen = u_strlen(toConvert);
120    XMLCh* retBuf = (manager)
121        ? (XMLCh*) manager->allocate((srcLen+1) * sizeof(XMLCh))
122        : new XMLCh[srcLen + 1];
123
124    XMLCh* outPtr = retBuf;
125    const UChar* srcPtr = toConvert;
126    while (*srcPtr)
127        *outPtr++ = XMLCh(*srcPtr++);
128    *outPtr = 0;
129
130    return retBuf;
131}
132
133
134
135
136// ---------------------------------------------------------------------------
137//  ICUTransService: Constructors and Destructor
138// ---------------------------------------------------------------------------
139ICUTransService::ICUTransService(MemoryManager*)
140{
141  // Starting with ICU 3.4 we don't need to call init anymore.
142  //
143#if (U_ICU_VERSION_MAJOR_NUM > 2 || (U_ICU_VERSION_MAJOR_NUM == 2 && U_ICU_VERSION_MINOR_NUM >= 6)) && \
144  (U_ICU_VERSION_MAJOR_NUM < 3 || (U_ICU_VERSION_MAJOR_NUM == 3 && U_ICU_VERSION_MINOR_NUM < 4))
145    UErrorCode errorCode=U_ZERO_ERROR;
146    u_init(&errorCode);
147    if(U_FAILURE(errorCode)) {
148        XMLPlatformUtils::panic(PanicHandler::Panic_NoTransService);
149    }
150#endif
151
152#if !defined(XML_OS390) && !defined(XML_AS400) && !defined(XML_HPUX) && !defined(XML_PTX)
153#if (U_ICU_VERSION_MAJOR_NUM < 2)
154    // Starting with ICU 2.0, ICU itself includes a static reference to the data
155    // entrypoint symbol.
156    //
157    // ICU 1.8 (and previous) did not include a static reference, but would
158    // dynamically load the data dll when it was first needed, however this dynamic
159    // loading proved unreliable in some of the odd environments that Xerces needed
160    // to run in.  Hence, the static reference.
161
162    // Pass the location of the converter data to ICU. By doing so, we are
163    // forcing the load of ICU converter data DLL, after the Xerces-C DLL is
164    // loaded. This implies that Xerces-C, now has to explicitly link with the
165    // ICU converter dll. However, the advantage is that we no longer depend
166    // on the code which does demand dynamic loading of DLL's. The demand
167    // loading is highly system dependent and was a constant source of support
168    // calls.
169    UErrorCode uerr = U_ZERO_ERROR;
170    udata_setCommonData((void *) icudata_dat, &uerr);
171#endif
172#endif
173}
174
175ICUTransService::~ICUTransService()
176{
177    /*
178     * commented out the following clean up code
179     * in case users use ICU outside of the parser
180     * if we clean up here, users' code may crash
181     *
182    #if (U_ICU_VERSION_MAJOR_NUM >= 2)
183        // release all lazily allocated data
184        u_cleanup();
185    #endif
186    */
187}
188
189
190// ---------------------------------------------------------------------------
191//  ICUTransService: The virtual transcoding service API
192// ---------------------------------------------------------------------------
193int ICUTransService::compareIString(const   XMLCh* const    comp1
194                                    , const XMLCh* const    comp2)
195{
196    size_t  i = 0;
197    size_t  j = 0;
198
199    for(;;)
200    {
201        UChar32 ch1;
202        UChar32 ch2;
203
204        U16_NEXT_UNSAFE(comp1, i, ch1);
205        U16_NEXT_UNSAFE(comp2, j, ch2);
206
207        const UChar32   folded1 =
208            u_foldCase(ch1, U_FOLD_CASE_DEFAULT);
209
210        const UChar32   folded2 =
211            u_foldCase(ch2, U_FOLD_CASE_DEFAULT);
212
213        if (folded1 !=
214            folded2)
215        {
216            return folded1 - folded2;
217        }
218        else if (ch1 == 0)
219        {
220            // If ch1 is 0, the ch2 must also be
221            // 0.  Otherwise, the previous if
222            // would have failed.
223            break;
224        }
225    }
226
227    return 0;
228}
229
230
231int ICUTransService::compareNIString(const  XMLCh* const    comp1
232                                    , const XMLCh* const    comp2
233                                    , const XMLSize_t       maxChars)
234{
235    if (maxChars > 0)
236    {
237        // Note that this function has somewhat broken semantics, as it's
238        // possible for two strings of different lengths to compare as equal
239        // in a case-insensitive manner, since one character could be
240        // represented as a surrogate pair.
241        size_t  i = 0;
242        size_t  j = 0;
243
244        for(;;)
245        {
246            UChar32 ch1;
247            UChar32 ch2;
248
249            U16_NEXT_UNSAFE(comp1, i, ch1);
250            U16_NEXT_UNSAFE(comp2, j, ch2);
251
252            const UChar32   folded1 =
253                u_foldCase(ch1, U_FOLD_CASE_DEFAULT);
254
255            const UChar32   folded2 =
256                u_foldCase(ch2, U_FOLD_CASE_DEFAULT);
257
258            if (folded1 != folded2)
259            {
260                return folded1 - folded2;
261            }
262            else if (i == maxChars)
263            {
264                // If we're at the end of both strings, return 0.
265                // Otherwise, we've run out of characters in the
266                // left string, so return -1.
267                return j == maxChars ? 0 : -1;
268            }
269            else if (j == maxChars)
270            {
271                // We've run out of characters in the right string,
272                // but not the left, so return 1.
273                return 1;
274            }
275        }
276    }
277
278    return 0;
279}
280
281
282const XMLCh* ICUTransService::getId() const
283{
284    return gMyServiceId;
285}
286
287XMLLCPTranscoder* ICUTransService::makeNewLCPTranscoder(MemoryManager* manager)
288{
289    //
290    //  Try to create a default converter. If it fails, return a null
291    //  pointer which will basically cause the system to give up because
292    //  we really can't do anything without one.
293    //
294    UErrorCode uerr = U_ZERO_ERROR;
295    UConverter* converter = ucnv_open(NULL, &uerr);
296    if (!converter)
297        return 0;
298
299    // That went ok, so create an ICU LCP transcoder wrapper and return it
300    return new (manager) ICULCPTranscoder(converter);
301}
302
303
304bool ICUTransService::supportsSrcOfs() const
305{
306    // This implementation supports source offset information
307    return true;
308}
309
310
311template <class FunctionType>
312static void doCaseConvert(XMLCh*          convertString,
313                          FunctionType    caseFunction)
314{
315    // Note the semantics of this function are broken, since it's
316    // possible that changing the case of a string could increase
317    // its length, but there's no way to handle such a situation.
318    const XMLSize_t len = XMLString::stringLen(convertString);
319
320    size_t  readPos = 0;
321    size_t  writePos = 0;
322
323    while(readPos < len)
324    {
325        UChar32     original;
326
327        // Get the next Unicode code point.
328        U16_NEXT_UNSAFE(convertString, readPos, original);
329
330        // Convert the code point
331        const UChar32   converted = caseFunction(original);
332
333        // OK, now here's where it gets ugly.
334        if (!U_IS_BMP(converted) && U_IS_BMP(original) &&
335            readPos - writePos == 1)
336        {
337            // We do not have room to convert the
338            // character without overwriting the next
339            // character, so we will just stop.
340            break;
341        }
342        else
343        {
344            U16_APPEND_UNSAFE(convertString, writePos, converted);
345        }
346    }
347
348    convertString[writePos] = 0;
349}
350
351
352
353void ICUTransService::upperCase(XMLCh* const toUpperCase)
354{
355    doCaseConvert(toUpperCase, u_toupper);
356}
357
358void ICUTransService::lowerCase(XMLCh* const toLowerCase)
359{
360    doCaseConvert(toLowerCase, u_tolower);
361}
362
363
364
365// ---------------------------------------------------------------------------
366//  ICUTransService: The protected virtual transcoding service API
367// ---------------------------------------------------------------------------
368XMLTranscoder* ICUTransService::
369makeNewXMLTranscoder(const  XMLCh* const            encodingName
370                    ,       XMLTransService::Codes& resValue
371                    , const XMLSize_t               blockSize
372                    ,       MemoryManager* const    manager)
373{
374    //
375    //  For encodings that end with "s390" we need to strip off the "s390"
376    //  from the encoding name and add ",swaplfnl" to the encoding name
377    //  that we pass into ICU on the ucnv_openU.
378    //
379    XMLCh* encodingNameToUse = (XMLCh*) encodingName;
380    XMLCh* workBuffer = 0;
381
382    if ( (XMLString::endsWith(encodingNameToUse, gs390Id)) ||
383         (XMLString::endsWith(encodingNameToUse, gS390Id)) )
384    {
385       XMLSize_t workBufferSize = (XMLString::stringLen(encodingNameToUse) + XMLString::stringLen(gswaplfnlId) - XMLString::stringLen(gS390Id) + 1);
386       workBuffer = (XMLCh*) manager->allocate(workBufferSize * sizeof(XMLCh));
387       XMLSize_t moveSize = XMLString::stringLen(encodingNameToUse) - XMLString::stringLen(gS390Id);
388       XMLString::moveChars(workBuffer, encodingNameToUse, moveSize);
389       XMLString::moveChars((workBuffer + moveSize), gswaplfnlId, XMLString::stringLen(gswaplfnlId));
390       encodingNameToUse = workBuffer;
391    }
392
393    //
394    //  If UChar and XMLCh are not the same size, then we have premassage the
395    //  encoding name into a UChar type string.
396    //
397    const UChar* actualName;
398    UChar* tmpName = 0;
399    if (sizeof(UChar) == sizeof(XMLCh))
400    {
401        actualName = (const UChar*)encodingNameToUse;
402    }
403    else
404    {
405        tmpName = convertToUChar(encodingNameToUse, 0, manager);
406        actualName = tmpName;
407    }
408
409    ArrayJanitor<UChar> janTmp(tmpName, manager);
410    ArrayJanitor<XMLCh> janTmp1(workBuffer, manager);
411
412    UErrorCode uerr = U_ZERO_ERROR;
413    UConverter* converter = ucnv_openU(actualName, &uerr);
414    if (!converter)
415    {
416        resValue = XMLTransService::UnsupportedEncoding;
417        return 0;
418    }
419
420    return new (manager) ICUTranscoder(encodingName, converter, blockSize, manager);
421}
422
423
424
425
426// ---------------------------------------------------------------------------
427//  ICUTranscoder: Constructors and Destructor
428// ---------------------------------------------------------------------------
429ICUTranscoder::ICUTranscoder(const  XMLCh* const        encodingName
430                            ,       UConverter* const   toAdopt
431                            , const XMLSize_t           blockSize
432                            , MemoryManager* const      manager) :
433
434    XMLTranscoder(encodingName, blockSize, manager)
435    , fConverter(toAdopt)
436    , fFixed(false)
437    , fSrcOffsets(0)
438{
439    // If there is a block size, then allocate our source offset array
440    if (blockSize)
441        fSrcOffsets = (XMLUInt32*) manager->allocate
442        (
443            blockSize * sizeof(XMLUInt32)
444        );//new XMLUInt32[blockSize];
445
446    // Remember if its a fixed size encoding
447    fFixed = (ucnv_getMaxCharSize(fConverter) == ucnv_getMinCharSize(fConverter));
448}
449
450ICUTranscoder::~ICUTranscoder()
451{
452    getMemoryManager()->deallocate(fSrcOffsets);//delete [] fSrcOffsets;
453
454    // If there is a converter, ask ICU to clean it up
455    if (fConverter)
456    {
457        // <TBD> Does this actually delete the structure???
458        ucnv_close(fConverter);
459        fConverter = 0;
460    }
461}
462
463
464// ---------------------------------------------------------------------------
465//  ICUTranscoder: The virtual transcoder API
466// ---------------------------------------------------------------------------
467XMLSize_t
468ICUTranscoder::transcodeFrom(const  XMLByte* const          srcData
469                            , const XMLSize_t               srcCount
470                            ,       XMLCh* const            toFill
471                            , const XMLSize_t               maxChars
472                            ,       XMLSize_t&              bytesEaten
473                            ,       unsigned char* const    charSizes)
474{
475    // Set up pointers to the start and end of the source buffer
476    const XMLByte*  startSrc = srcData;
477    const XMLByte*  endSrc = srcData + srcCount;
478
479    //
480    //  And now do the target buffer. This works differently according to
481    //  whether XMLCh and UChar are the same size or not.
482    //
483    UChar* startTarget;
484    if (sizeof(XMLCh) == sizeof(UChar))
485        startTarget = (UChar*)toFill;
486     else
487        startTarget = (UChar*) getMemoryManager()->allocate
488        (
489            maxChars * sizeof(UChar)
490        );//new UChar[maxChars];
491    UChar* orgTarget = startTarget;
492
493    //
494    //  Transcode the buffer.  Buffer overflow errors are normal, occuring
495    //  when the raw input buffer holds more characters than will fit in
496    //  the Unicode output buffer.
497    //
498    UErrorCode  err = U_ZERO_ERROR;
499    ucnv_toUnicode
500    (
501        fConverter
502        , &startTarget
503        , startTarget + maxChars
504        , (const char**)&startSrc
505        , (const char*)endSrc
506        , (fFixed ? 0 : (int32_t*)fSrcOffsets)
507        , false
508        , &err
509    );
510
511    if ((err != U_ZERO_ERROR) && (err != U_BUFFER_OVERFLOW_ERROR))
512    {
513        if (orgTarget != (UChar*)toFill)
514            getMemoryManager()->deallocate(orgTarget);//delete [] orgTarget;
515
516        if (fFixed)
517        {
518            XMLCh tmpBuf[17];
519            XMLString::binToText((unsigned int)(*startTarget), tmpBuf, 16, 16, getMemoryManager());
520            ThrowXMLwithMemMgr2
521            (
522                TranscodingException
523                , XMLExcepts::Trans_BadSrcCP
524                , tmpBuf
525                , getEncodingName()
526                , getMemoryManager()
527            );
528        }
529        else
530        {
531            ThrowXMLwithMemMgr(TranscodingException, XMLExcepts::Trans_BadSrcSeq, getMemoryManager());
532        }
533    }
534
535    // Calculate the bytes eaten and store in caller's param
536    bytesEaten = startSrc - srcData;
537
538    // And the characters decoded
539    const XMLSize_t charsDecoded = startTarget - orgTarget;
540
541    //
542    //  Translate the array of char offsets into an array of character
543    //  sizes, which is what the transcoder interface semantics requires.
544    //  If its fixed, then we can optimize it.
545    //
546    if (fFixed)
547    {
548        const unsigned char fillSize = (unsigned char)ucnv_getMaxCharSize(fConverter);
549        memset(charSizes, fillSize, maxChars);
550    }
551     else
552    {
553        //
554        //  We have to convert the series of offsets into a series of
555        //  sizes. If just one char was decoded, then its the total bytes
556        //  eaten. Otherwise, do a loop and subtract out each element from
557        //  its previous element.
558        //
559        if (charsDecoded == 1)
560        {
561            charSizes[0] = (unsigned char)bytesEaten;
562        }
563         else
564        {
565            //  ICU does not return an extra element to allow us to figure
566            //  out the last char size, so we have to compute it from the
567            //  total bytes used.
568            unsigned int index;
569            for (index = 0; index < charsDecoded - 1; index++)
570            {
571                charSizes[index] = (unsigned char)(fSrcOffsets[index + 1]
572                                                    - fSrcOffsets[index]);
573            }
574            if( charsDecoded > 0 ) {
575                charSizes[charsDecoded - 1] = (unsigned char)(bytesEaten
576                                              - fSrcOffsets[charsDecoded - 1]);
577            }
578        }
579    }
580
581    //
582    //  If XMLCh and UChar are not the same size, then we need to copy over
583    //  the temp buffer to the new one.
584    //
585    if (sizeof(UChar) != sizeof(XMLCh))
586    {
587        XMLCh* outPtr = toFill;
588        startTarget = orgTarget;
589        for (unsigned int index = 0; index < charsDecoded; index++)
590            *outPtr++ = XMLCh(*startTarget++);
591
592        // And delete the temp buffer
593        getMemoryManager()->deallocate(orgTarget);//delete [] orgTarget;
594    }
595
596    // Return the chars we put into the target buffer
597    return charsDecoded;
598}
599
600XMLSize_t
601ICUTranscoder::transcodeFrom(const  XMLByte* const          srcData
602                            , const XMLSize_t               srcCount
603                            ,       XMLCh* const            toFill
604                            , const XMLSize_t               maxChars
605                            ,       XMLSize_t&              bytesEaten)
606{
607    // Set up pointers to the start and end of the source buffer
608    const XMLByte*  startSrc = srcData;
609    const XMLByte*  endSrc = srcData + srcCount;
610
611    //
612    //  And now do the target buffer. This works differently according to
613    //  whether XMLCh and UChar are the same size or not.
614    //
615    UChar* startTarget = (UChar*)toFill;
616    UChar* orgTarget = startTarget;
617
618    //
619    //  Transcode the buffer.  Buffer overflow errors are normal, occuring
620    //  when the raw input buffer holds more characters than will fit in
621    //  the Unicode output buffer.
622    //
623    UErrorCode  err = U_ZERO_ERROR;
624    ucnv_toUnicode
625    (
626        fConverter
627        , &startTarget
628        , startTarget + maxChars
629        , (const char**)&startSrc
630        , (const char*)endSrc
631        , 0
632        , false
633        , &err
634    );
635
636    if ((err != U_ZERO_ERROR) && (err != U_BUFFER_OVERFLOW_ERROR))
637    {
638        if (orgTarget != (UChar*)toFill)
639            getMemoryManager()->deallocate(orgTarget);//delete [] orgTarget;
640
641        if (fFixed)
642        {
643            XMLCh tmpBuf[17];
644            XMLString::binToText((unsigned int)(*startTarget), tmpBuf, 16, 16, getMemoryManager());
645            ThrowXMLwithMemMgr2
646            (
647                TranscodingException
648                , XMLExcepts::Trans_BadSrcCP
649                , tmpBuf
650                , getEncodingName()
651                , getMemoryManager()
652            );
653        }
654        else
655        {
656            ThrowXMLwithMemMgr(TranscodingException, XMLExcepts::Trans_BadSrcSeq, getMemoryManager());
657        }
658    }
659
660    // Calculate the bytes eaten and store in caller's param
661    bytesEaten = startSrc - srcData;
662
663    // And the characters decoded
664    const XMLSize_t charsDecoded = startTarget - orgTarget;
665
666    // Return the chars we put into the target buffer
667    return charsDecoded;
668}
669
670
671XMLSize_t
672ICUTranscoder::transcodeTo( const   XMLCh* const    srcData
673                            , const XMLSize_t       srcCount
674                            ,       XMLByte* const  toFill
675                            , const XMLSize_t       maxBytes
676                            ,       XMLSize_t&      charsEaten
677                            , const UnRepOpts       options)
678{
679    //
680    //  Get a pointer to the buffer to transcode. If UChar and XMLCh are
681    //  the same size here, then use the original. Else, create a temp
682    //  one and put a janitor on it.
683    //
684    const UChar* srcPtr;
685    UChar* tmpBufPtr = 0;
686    if (sizeof(XMLCh) == sizeof(UChar))
687    {
688        srcPtr = (const UChar*)srcData;
689    }
690    else
691    {
692        tmpBufPtr = convertToUChar(srcData, srcCount, getMemoryManager());
693        srcPtr = tmpBufPtr;
694    }
695    ArrayJanitor<UChar> janTmpBuf(tmpBufPtr, getMemoryManager());
696
697    //
698    //  Set the appropriate callback so that it will either fail or use
699    //  the rep char. Remember the old one so we can put it back.
700    //
701    UErrorCode  err = U_ZERO_ERROR;
702    UConverterFromUCallback oldCB = NULL;
703    #if (U_ICU_VERSION_MAJOR_NUM < 2)
704    void* orgContent;
705    #else
706    const void* orgContent;
707    #endif
708    ucnv_setFromUCallBack
709    (
710        fConverter
711        , (options == UnRep_Throw) ? UCNV_FROM_U_CALLBACK_STOP
712                                   : UCNV_FROM_U_CALLBACK_SUBSTITUTE
713        , NULL
714        , &oldCB
715        , &orgContent
716        , &err
717    );
718
719    //
720    //  Ok, lets transcode as many chars as we we can in one shot. The
721    //  ICU API gives enough info not to have to do this one char by char.
722    //
723    XMLByte*        startTarget = toFill;
724    const UChar*    startSrc = srcPtr;
725    err = U_ZERO_ERROR;
726    ucnv_fromUnicode
727    (
728        fConverter
729        , (char**)&startTarget
730        , (char*)(startTarget + maxBytes)
731        , &startSrc
732        , srcPtr + srcCount
733        , 0
734        , false
735        , &err
736    );
737
738    // Rememember the status before we possibly overite the error code
739    const bool res = (err == U_ZERO_ERROR);
740
741    // Put the old handler back
742    err = U_ZERO_ERROR;
743    UConverterFromUCallback orgAction = NULL;
744
745    ucnv_setFromUCallBack(fConverter, oldCB, NULL, &orgAction, &orgContent, &err);
746
747    if (!res)
748    {
749        XMLCh tmpBuf[17];
750        XMLString::binToText((unsigned int)*startSrc, tmpBuf, 16, 16, getMemoryManager());
751        ThrowXMLwithMemMgr2
752        (
753            TranscodingException
754            , XMLExcepts::Trans_Unrepresentable
755            , tmpBuf
756            , getEncodingName()
757            , getMemoryManager()
758        );
759    }
760
761    // Fill in the chars we ate from the input
762    charsEaten = startSrc - srcPtr;
763
764    // Return the chars we stored
765    return startTarget - toFill;
766}
767
768
769bool ICUTranscoder::canTranscodeTo(const unsigned int toCheck)
770{
771    //
772    //  If the passed value is really a surrogate embedded together, then
773    //  we need to break it out into its two chars. Else just one. While
774    //  we are ate it, convert them to UChar format if required.
775    //
776    UChar           srcBuf[2];
777    unsigned int    srcCount = 1;
778    if (toCheck & 0xFFFF0000)
779    {
780        srcBuf[0] = UChar((toCheck >> 10) + 0xD800);
781        srcBuf[1] = UChar(toCheck & 0x3FF) + 0xDC00;
782        srcCount++;
783    }
784     else
785    {
786        srcBuf[0] = UChar(toCheck);
787    }
788
789    //
790    //  Set the callback so that it will fail instead of using the rep char.
791    //  Remember the old one so we can put it back.
792    //
793     UErrorCode  err = U_ZERO_ERROR;
794     UConverterFromUCallback oldCB = NULL;
795     #if (U_ICU_VERSION_MAJOR_NUM < 2)
796     void* orgContent;
797     #else
798     const void* orgContent;
799     #endif
800
801     ucnv_setFromUCallBack
802         (
803         fConverter
804         , UCNV_FROM_U_CALLBACK_STOP
805         , NULL
806         , &oldCB
807         , &orgContent
808         , &err
809         );
810
811    // Set upa temp buffer to format into. Make it more than big enough
812    char            tmpBuf[64];
813    char*           startTarget = tmpBuf;
814    const UChar*    startSrc = srcBuf;
815
816    err = U_ZERO_ERROR;
817    ucnv_fromUnicode
818    (
819        fConverter
820        , &startTarget
821        , startTarget + 64
822        , &startSrc
823        , srcBuf + srcCount
824        , 0
825        , false
826        , &err
827    );
828
829    // Save the result before we overight the error code
830    const bool res = (err == U_ZERO_ERROR);
831
832    // Put the old handler back
833    err = U_ZERO_ERROR;
834    UConverterFromUCallback orgAction = NULL;
835
836    ucnv_setFromUCallBack(fConverter, oldCB, NULL, &orgAction, &orgContent, &err);
837
838    return res;
839}
840
841
842
843// ---------------------------------------------------------------------------
844//  ICULCPTranscoder: Constructors and Destructor
845// ---------------------------------------------------------------------------
846ICULCPTranscoder::ICULCPTranscoder(UConverter* const toAdopt) :
847
848    fConverter(toAdopt)
849{
850}
851
852ICULCPTranscoder::~ICULCPTranscoder()
853{
854    // If there is a converter, ask ICU to clean it up
855    if (fConverter)
856    {
857        // <TBD> Does this actually delete the structure???
858        ucnv_close(fConverter);
859        fConverter = 0;
860    }
861}
862
863
864// ---------------------------------------------------------------------------
865//  ICULCPTranscoder: Constructors and Destructor
866// ---------------------------------------------------------------------------
867XMLSize_t ICULCPTranscoder::calcRequiredSize(const XMLCh* const srcText
868                                                , MemoryManager* const manager)
869{
870    if (!srcText)
871        return 0;
872
873    //
874    //  We do two different versions of this, according to whether XMLCh
875    //  is the same size as UChar or not.
876    //
877    UErrorCode err = U_ZERO_ERROR;
878    int32_t targetCap;
879    if (sizeof(XMLCh) == sizeof(UChar))
880    {
881        // Use a faux scope to synchronize while we do this
882        {
883            XMLMutexLock lockConverter(&fMutex);
884
885            targetCap = ucnv_fromUChars
886            (
887                fConverter
888                , 0
889                , 0
890                , (const UChar*)srcText
891                , -1
892                , &err
893            );
894        }
895    }
896    else
897    {
898        // Copy the source to a local temp
899        UChar* tmpBuf = convertToUChar(srcText, 0, manager);
900        ArrayJanitor<UChar> janTmp(tmpBuf, manager);
901
902        // Use a faux scope to synchronize while we do this
903        {
904            XMLMutexLock lockConverter(&fMutex);
905
906            targetCap = ucnv_fromUChars
907            (
908                fConverter
909                , 0
910                , 0
911                , tmpBuf
912                , -1
913                , &err
914            );
915        }
916    }
917
918    if (err != U_BUFFER_OVERFLOW_ERROR)
919        return 0;
920
921    return (XMLSize_t)targetCap;
922}
923
924XMLSize_t ICULCPTranscoder::calcRequiredSize(const char* const srcText
925                                                , MemoryManager* const /*manager*/)
926{
927    if (!srcText)
928        return 0;
929
930    int32_t targetCap;
931    UErrorCode err = U_ZERO_ERROR;
932
933    // Use a faux scope to synchronize while we do this
934    {
935        XMLMutexLock lockConverter(&fMutex);
936        targetCap = ucnv_toUChars
937        (
938            fConverter
939            , 0
940            , 0
941            , srcText
942            , (int32_t)strlen(srcText)
943            , &err
944        );
945    }
946
947    if (err != U_BUFFER_OVERFLOW_ERROR)
948        return 0;
949
950#if (U_ICU_VERSION_MAJOR_NUM < 2)
951    // Subtract one since it includes the terminator space
952    return (XMLSize_t)(targetCap - 1);
953#else
954    // Starting ICU 2.0, this is fixed and all ICU String functions have consistent NUL-termination behavior.
955    // The returned length is always the number of output UChar's, not counting an additional, terminating NUL.
956    return (XMLSize_t)(targetCap);
957#endif
958}
959
960
961char* ICULCPTranscoder::transcode(const XMLCh* const toTranscode,
962                                  MemoryManager* const manager)
963{
964    char* retBuf = 0;
965
966    // Check for a couple of special cases
967    if (!toTranscode)
968        return retBuf;
969
970    if (!*toTranscode)
971    {
972        retBuf = (char*) manager->allocate(sizeof(char));//new char[1];
973        retBuf[0] = 0;
974        return retBuf;
975    }
976
977    //
978    //  Get the length of the source string since we'll have to use it in
979    //  a couple places below.
980    //
981    const XMLSize_t srcLen = XMLString::stringLen(toTranscode);
982
983    //
984    //  If XMLCh and UChar are not the same size, then we have to make a
985    //  temp copy of the text to pass to ICU.
986    //
987    const UChar* actualSrc;
988    UChar* ncActual = 0;
989    if (sizeof(XMLCh) == sizeof(UChar))
990    {
991        actualSrc = (const UChar*)toTranscode;
992    }
993     else
994    {
995        // Allocate a non-const temp buf, but store it also in the actual
996        ncActual = convertToUChar(toTranscode, 0, manager);
997        actualSrc = ncActual;
998    }
999
1000    // Insure that the temp buffer, if any, gets cleaned up via the nc pointer
1001    ArrayJanitor<UChar> janTmp(ncActual, manager);
1002
1003    // Caculate a return buffer size not too big, but less likely to overflow
1004    int32_t targetLen = (int32_t)(srcLen * 1.25);
1005
1006    // Allocate the return buffer
1007    retBuf = (char*) manager->allocate((targetLen + 1) * sizeof(char));//new char[targetLen + 1];
1008
1009    //
1010    //  Lock now while we call the converter. Use a faux block to do the
1011    //  lock so that it unlocks immediately afterwards.
1012    //
1013    UErrorCode err = U_ZERO_ERROR;
1014    int32_t targetCap;
1015    {
1016        XMLMutexLock lockConverter(&fMutex);
1017
1018        targetCap = ucnv_fromUChars
1019        (
1020            fConverter
1021            , retBuf
1022            , targetLen + 1
1023            , actualSrc
1024            , -1
1025            , &err
1026        );
1027    }
1028
1029    // If targetLen is not enough then buffer overflow might occur
1030    if ((err == U_BUFFER_OVERFLOW_ERROR) || (err == U_STRING_NOT_TERMINATED_WARNING))
1031    {
1032        //
1033        //  Reset the error, delete the old buffer, allocate a new one,
1034        //  and try again.
1035        //
1036        err = U_ZERO_ERROR;
1037        manager->deallocate(retBuf);//delete [] retBuf;
1038        retBuf = (char*) manager->allocate((targetCap + 1) * sizeof(char));//new char[targetCap + 1];
1039
1040        // Lock again before we retry
1041        XMLMutexLock lockConverter(&fMutex);
1042        targetCap = ucnv_fromUChars
1043        (
1044            fConverter
1045            , retBuf
1046            , targetCap + 1
1047            , actualSrc
1048            , -1
1049            , &err
1050        );
1051    }
1052
1053    if (U_FAILURE(err))
1054    {
1055        manager->deallocate(retBuf);//delete [] retBuf;
1056        return 0;
1057    }
1058
1059    return retBuf;
1060}
1061
1062XMLCh* ICULCPTranscoder::transcode(const char* const toTranscode,
1063                                   MemoryManager* const manager)
1064{
1065    // Watch for a few pyscho corner cases
1066    if (!toTranscode)
1067        return 0;
1068
1069    if (!*toTranscode)
1070    {
1071        XMLCh* retVal = (XMLCh*) manager->allocate(sizeof(XMLCh));//new XMLCh[1];
1072        retVal[0] = 0;
1073        return retVal;
1074    }
1075
1076    //
1077    //  Get the length of the string to transcode. The Unicode string will
1078    //  almost always be no more chars than were in the source, so this is
1079    //  the best guess as to the storage needed.
1080    //
1081    const int32_t srcLen = (int32_t)strlen(toTranscode);
1082
1083    // We need a target buffer of UChars to fill in
1084    UChar* targetBuf = 0;
1085
1086    // Now lock while we do these calculations
1087    UErrorCode err = U_ZERO_ERROR;
1088    int32_t targetCap;
1089    {
1090        XMLMutexLock lockConverter(&fMutex);
1091
1092        //
1093        //  Here we don't know what the target length will be so use 0 and
1094        //  expect an U_BUFFER_OVERFLOW_ERROR in which case it'd get resolved
1095        //  by the correct capacity value.
1096        //
1097        targetCap = ucnv_toUChars
1098        (
1099            fConverter
1100            , 0
1101            , 0
1102            , toTranscode
1103            , srcLen
1104            , &err
1105        );
1106
1107        if (err != U_BUFFER_OVERFLOW_ERROR)
1108            return 0;
1109
1110        err = U_ZERO_ERROR;
1111        targetBuf = (UChar*) manager->allocate((targetCap+1) * sizeof(UChar));//new UChar[targetCap + 1];
1112        ucnv_toUChars
1113        (
1114            fConverter
1115            , targetBuf
1116            , targetCap + 1
1117            , toTranscode
1118            , srcLen
1119            , &err
1120        );
1121    }
1122
1123    if (U_FAILURE(err))
1124    {
1125        // Clean up if we got anything allocated
1126        manager->deallocate(targetBuf);//delete [] targetBuf;
1127        return 0;
1128    }
1129
1130    // Cap it off to make sure
1131    targetBuf[targetCap] = 0;
1132
1133    //
1134    //  If XMLCh and UChar are the same size, then we can return retVal
1135    //  as is. Else, we have to allocate another buffer and copy the data
1136    //  over to it.
1137    //
1138    XMLCh* actualRet;
1139    if (sizeof(XMLCh) == sizeof(UChar))
1140    {
1141        actualRet = (XMLCh*)targetBuf;
1142    }
1143     else
1144    {
1145        actualRet = convertToXMLCh(targetBuf, manager);
1146        manager->deallocate(targetBuf);//delete [] targetBuf;
1147    }
1148    return actualRet;
1149}
1150
1151
1152bool ICULCPTranscoder::transcode(const  char* const     toTranscode
1153                                ,       XMLCh* const    toFill
1154                                , const XMLSize_t       maxChars
1155                                , MemoryManager* const  manager)
1156{
1157    // Check for a couple of psycho corner cases
1158    if (!toTranscode || !maxChars)
1159    {
1160        toFill[0] = 0;
1161        return true;
1162    }
1163
1164    if (!*toTranscode)
1165    {
1166        toFill[0] = 0;
1167        return true;
1168    }
1169
1170    // We'll need this in a couple of places below
1171    const XMLSize_t srcLen = strlen(toTranscode);
1172
1173    //
1174    //  Set up the target buffer. If XMLCh and UChar are not the same size
1175    //  then we have to use a temp buffer and convert over.
1176    //
1177    UChar* targetBuf;
1178    if (sizeof(XMLCh) == sizeof(UChar))
1179        targetBuf = (UChar*)toFill;
1180    else
1181        targetBuf = (UChar*) manager->allocate
1182        (
1183            (maxChars + 1) * sizeof(UChar)
1184        );//new UChar[maxChars + 1];
1185
1186    //
1187    //  Use a faux block to enforce a lock on the converter, which will
1188    //  unlock immediately after its completed.
1189    //
1190    UErrorCode err = U_ZERO_ERROR;
1191    {
1192        XMLMutexLock lockConverter(&fMutex);
1193        ucnv_toUChars
1194        (
1195            fConverter
1196            , targetBuf
1197            , (int32_t)maxChars + 1
1198            , toTranscode
1199            , (int32_t)srcLen
1200            , &err
1201        );
1202    }
1203
1204    if (U_FAILURE(err))
1205    {
1206        if (targetBuf != (UChar*)toFill)
1207            manager->deallocate(targetBuf);//delete [] targetBuf;
1208        return false;
1209    }
1210
1211    // If the sizes are not the same, then copy the data over
1212    if (sizeof(XMLCh) != sizeof(UChar))
1213    {
1214        UChar* srcPtr = targetBuf;
1215        XMLCh* outPtr = toFill;
1216        while (*srcPtr)
1217            *outPtr++ = XMLCh(*srcPtr++);
1218        *outPtr = 0;
1219
1220        // And delete the temp buffer
1221        manager->deallocate(targetBuf);//delete [] targetBuf;
1222    }
1223
1224    return true;
1225}
1226
1227
1228bool ICULCPTranscoder::transcode(   const   XMLCh* const    toTranscode
1229                                    ,       char* const     toFill
1230                                    , const XMLSize_t       maxChars
1231                                    , MemoryManager* const  manager)
1232{
1233    // Watch for a few psycho corner cases
1234    if (!toTranscode || !maxChars)
1235    {
1236        toFill[0] = 0;
1237        return true;
1238    }
1239
1240    if (!*toTranscode)
1241    {
1242        toFill[0] = 0;
1243        return true;
1244    }
1245
1246    //
1247    //  If XMLCh and UChar are not the same size, then we have to make a
1248    //  temp copy of the text to pass to ICU.
1249    //
1250    const UChar* actualSrc;
1251    UChar* ncActual = 0;
1252    if (sizeof(XMLCh) == sizeof(UChar))
1253    {
1254        actualSrc = (const UChar*)toTranscode;
1255    }
1256     else
1257    {
1258        // Allocate a non-const temp buf, but store it also in the actual
1259        ncActual = convertToUChar(toTranscode, 0, manager);
1260        actualSrc = ncActual;
1261    }
1262
1263    // Insure that the temp buffer, if any, gets cleaned up via the nc pointer
1264    ArrayJanitor<UChar> janTmp(ncActual, manager);
1265
1266    //
1267    //  Use a faux block to enforce a lock on the converter while we do this.
1268    //  It will be released immediately after its done.
1269    //
1270    UErrorCode err = U_ZERO_ERROR;
1271    int32_t targetCap;
1272    {
1273        XMLMutexLock lockConverter(&fMutex);
1274        targetCap = ucnv_fromUChars
1275        (
1276            fConverter
1277            , toFill
1278            , (int32_t)maxChars
1279            , actualSrc
1280            , -1
1281            , &err
1282        );
1283    }
1284
1285    if (U_FAILURE(err))
1286        return false;
1287
1288    toFill[targetCap] = 0;
1289    return true;
1290}
1291
1292XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.