source: icXML/icXML-devel/src/xercesc/util/Transcoders/MacOSUnicodeConverter/MacOSUnicodeConverter.cpp @ 2722

Last change on this file since 2722 was 2722, checked in by cameron, 7 years ago

Original Xerces files with import mods for icxercesc

File size: 30.9 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: MacOSUnicodeConverter.cpp 695759 2008-09-16 08:04:55Z borisk $
20 */
21 
22 
23// ---------------------------------------------------------------------------
24//  Includes
25// ---------------------------------------------------------------------------
26#include <xercesc/util/XercesDefs.hpp>
27
28#include <algorithm>
29#include <cstddef>
30#include <cstring>
31
32#if defined(__APPLE__)
33    //  Framework includes
34    #include <CoreServices/CoreServices.h>
35#else
36    //  Classic includes otherwise
37    #include <MacErrors.h>
38    #include <Script.h>
39    #include <TextUtils.h>
40    #include <TextEncodingConverter.h>
41    #include <TextCommon.h>
42    #include <CodeFragments.h>
43    #include <UnicodeConverter.h>
44    #include <UnicodeUtilities.h>
45    #include <CFCharacterSet.h>
46    #include <CFString.h>
47#endif
48
49#include <xercesc/util/Transcoders/MacOSUnicodeConverter/MacOSUnicodeConverter.hpp>
50#include <xercesc/util/XMLUniDefs.hpp>
51#include <xercesc/util/XMLUni.hpp>
52#include <icxercesc/util/XMLString.hpp>
53#include <xercesc/util/TranscodingException.hpp>
54#include <icxercesc/util/PlatformUtils.hpp>
55#include <xercesc/util/Janitor.hpp>
56
57XERCES_CPP_NAMESPACE_BEGIN
58
59// ---------------------------------------------------------------------------
60//      Typedefs
61// ---------------------------------------------------------------------------
62
63//      TempBufs are used for cases where we need a temporary buffer while processing.
64const std::size_t kTempBufCount = 512;
65typedef char    TempCharBuf[kTempBufCount];
66typedef UniChar TempUniBuf[kTempBufCount];
67typedef XMLCh   TempXMLBuf[kTempBufCount];
68
69
70// ---------------------------------------------------------------------------
71//  Local, const data
72// ---------------------------------------------------------------------------
73const XMLCh MacOSUnicodeConverter::fgMyServiceId[] =
74{
75    chLatin_M, chLatin_a, chLatin_c, chLatin_O, chLatin_S, chNull
76};
77
78
79const XMLCh MacOSUnicodeConverter::fgMacLCPEncodingName[] =
80{
81        chLatin_M, chLatin_a, chLatin_c, chLatin_O, chLatin_S, chLatin_L
82    ,   chLatin_C, chLatin_P, chLatin_E, chLatin_n, chLatin_c, chLatin_o
83    ,   chLatin_d, chLatin_i, chLatin_n, chLatin_g, chNull
84};
85
86
87
88// ---------------------------------------------------------------------------
89//  MacOSUnicodeConverter: Constructors and Destructor
90// ---------------------------------------------------------------------------
91MacOSUnicodeConverter::MacOSUnicodeConverter(MemoryManager* manager)
92  : fCollator(NULL)
93{
94        //      Test for presense of unicode collation functions
95        fHasUnicodeCollation = (UCCompareText != NULL);
96   
97    //  Create a unicode collator for doing string comparisons
98    if (fHasUnicodeCollation)
99    {
100                //  Configure collation options
101        UCCollateOptions collateOptions =
102                                                                kUCCollateComposeInsensitiveMask
103                                                                | kUCCollateWidthInsensitiveMask
104                                                                | kUCCollateCaseInsensitiveMask
105                                                                | kUCCollatePunctuationSignificantMask
106                                                                ;
107                                               
108        OSStatus status = UCCreateCollator(NULL, 0, collateOptions, &fCollator);
109    }
110}
111
112
113MacOSUnicodeConverter::~MacOSUnicodeConverter()
114{
115    //  Dispose our collator
116    if (fCollator != NULL)
117        UCDisposeCollator(&fCollator);
118}
119
120
121// ---------------------------------------------------------------------------
122//  MacOSUnicodeConverter: The virtual transcoding service API
123// ---------------------------------------------------------------------------
124int MacOSUnicodeConverter::compareIString(  const XMLCh* const    comp1
125                                          , const XMLCh* const    comp2)
126{
127        //      If unicode collation routines are available, use them.
128        //      This should be the case on Mac OS 8.6 and later,
129        //      with Carbon 1.0.2 or later, and under Mac OS X.
130        //
131        //      Otherwise, but only for Metrowerks, since only Metrowerks
132        //      has a c library with a valid set of wchar routines,
133        //      fall back to the standard library.
134
135        if (fHasUnicodeCollation && fCollator != NULL)
136        {
137                std::size_t cnt1 = XMLString::stringLen(comp1);
138                std::size_t cnt2 = XMLString::stringLen(comp2);
139               
140        Boolean equivalent = false;
141        SInt32 order = 0;
142        OSStatus status = UCCompareText(
143                                fCollator,
144                                reinterpret_cast<const UniChar*>(comp1),
145                                cnt1,
146                                reinterpret_cast<const UniChar*>(comp2),
147                                cnt2,
148                                &equivalent,
149                                &order
150                                );
151                                                                       
152        return ((status != noErr) || equivalent) ? 0 : order;
153        }
154        else
155        {
156                //      For some reason there is no platform utils available
157                //      where we expect it. Bail.
158                XMLPlatformUtils::panic(PanicHandler::Panic_NoTransService);
159                return 0;
160        }
161}
162
163
164int MacOSUnicodeConverter::compareNIString( const XMLCh* const  comp1
165                                        , const XMLCh* const    comp2
166                                        , const XMLSize_t       maxChars)
167{
168        //      If unicode collation routines are available, use them.
169        //      This should be the case on Mac OS 8.6 and later,
170        //      with Carbon 1.0.2 or later, and under Mac OS X.
171        //
172        //      Otherwise, but only for Metrowerks, since only Metrowerks
173        //      has a c library with a valid set of wchar routines,
174        //      fall back to the standard library.
175
176        if (fHasUnicodeCollation && fCollator != NULL)
177        {
178                std::size_t cnt1 = XMLString::stringLen(comp1);
179                std::size_t cnt2 = XMLString::stringLen(comp2);
180               
181                //      Restrict view of source characters to first {maxChars}
182                if (cnt1 > maxChars)
183                        cnt1 = maxChars;
184                       
185                if (cnt2 > maxChars)
186                        cnt2 = maxChars;
187               
188        Boolean equivalent = false;
189        SInt32 order = 0;
190        OSStatus status = UCCompareText(
191                                fCollator,     
192                                reinterpret_cast<const UniChar*>(comp1),
193                                cnt1,
194                                reinterpret_cast<const UniChar*>(comp2),
195                                cnt2,
196                                &equivalent,
197                                &order
198                                );
199                               
200        return ((status != noErr) || equivalent) ? 0 : order;
201        }
202        else
203        {
204                //      For some reason there is no platform utils available
205                //      where we expect it. Bail.
206                XMLPlatformUtils::panic(PanicHandler::Panic_NoTransService);
207                return 0;
208        }
209}
210
211
212const XMLCh* MacOSUnicodeConverter::getId() const
213{
214    return fgMyServiceId;
215}
216
217TextEncoding
218MacOSUnicodeConverter::discoverLCPEncoding()
219{
220        TextEncoding encoding = 0;
221       
222    //  Ask the OS for the best text encoding for this application
223    //  We would call GetApplicationTextEncoding(), but it's available only in
224    //  Carbon (not CarbonCore), and we try to link with frameworks only in CoreServices.
225    //      encoding = GetApplicationTextEncoding();
226   
227        //      Get TextEncoding for the current Mac System Script, falling back to Mac Roman
228        if (noErr != UpgradeScriptInfoToTextEncoding(
229                                        smSystemScript, kTextLanguageDontCare, kTextRegionDontCare,
230                                        NULL, &encoding))
231                encoding = CreateTextEncoding(kTextEncodingMacRoman,
232                                                                        kTextEncodingDefaultVariant,
233                                                                        kTextEncodingDefaultFormat);
234
235        //  Traditionally, the Mac transcoder has used the current system script
236        //  as the LCP text encoding.
237        //
238        //  As of Xerces 2.6, this continues to be the case if XML_MACOS_LCP_TRADITIONAL
239        //  is defined.
240        //
241        //  Otherwise, but only for Mac OS X,  utf-8 will be used instead.
242        //  Since posix paths are utf-8 encoding on OS X, and the OS X
243        //  terminal uses utf-8 by default, this seems to make the most sense.
244        #if !defined(XML_MACOS_LCP_TRADITIONAL)
245        if (true /*gMacOSXOrBetter*/)
246        {
247                //  Manufacture a text encoding for UTF8
248                encoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
249                                                                        kTextEncodingDefaultVariant,
250                                                                        kUnicodeUTF8Format);
251        }
252        #endif
253       
254        return encoding;
255}
256
257
258XMLLCPTranscoder* MacOSUnicodeConverter::makeNewLCPTranscoder(MemoryManager* manager)
259{
260        XMLLCPTranscoder* result = NULL;
261        OSStatus status = noErr;
262       
263        //  Discover the text encoding to use for the LCP
264        TextEncoding lcpTextEncoding = discoverLCPEncoding();
265
266    //  We implement the LCP transcoder in terms of the XMLTranscoder.
267        //  Create an XMLTranscoder for this encoding
268        XMLTransService::Codes resValue;
269    XMLTranscoder* xmlTrans = makeNewXMLTranscoder(fgMacLCPEncodingName,
270                                resValue, kTempBufCount,
271                                                                lcpTextEncoding, manager);
272   
273    if (xmlTrans)
274    {
275        //  Pass the XMLTranscoder over to the LPC transcoder
276        if (resValue == XMLTransService::Ok)
277            result = new (manager) MacOSLCPTranscoder(xmlTrans, manager);
278        else
279            delete xmlTrans;
280    }
281       
282    return result;
283}
284
285
286bool MacOSUnicodeConverter::supportsSrcOfs() const
287{
288        // For now, we don't support source offsets
289    return false;
290}
291
292
293void MacOSUnicodeConverter::upperCase(XMLCh* const toUpperCase)
294{
295#if TARGET_API_MAC_CARBON
296
297   // If we're targeting carbon, use the CFString conversion to uppercase
298   int len = XMLString::stringLen(toUpperCase);
299   CFMutableStringRef cfString = CFStringCreateMutableWithExternalCharactersNoCopy(
300        kCFAllocatorDefault,
301        (UniChar*)toUpperCase,
302        len,            // length
303        len,            // capacity
304        kCFAllocatorNull);
305   CFStringUppercase(cfString, NULL);
306   CFRelease(cfString);
307
308#elif (__GNUC__ >= 3 && _GLIBCPP_USE_WCHAR_T)
309
310        // Use this if there's a reasonable c library available.
311        // Metrowerks does this reasonably
312        wchar_t c;
313        for (XMLCh* p = (XMLCh*)toUpperCase; ((c = *p) != 0); )
314                *p++ = std::towupper(c);
315
316#else
317        #error Sorry, no support for upperCase
318#endif
319}
320
321
322void MacOSUnicodeConverter::lowerCase(XMLCh* const toLowerCase)
323{
324#if TARGET_API_MAC_CARBON
325
326   // If we're targeting carbon, use the CFString conversion to uppercase
327   int len = XMLString::stringLen(toLowerCase);
328   CFMutableStringRef cfString = CFStringCreateMutableWithExternalCharactersNoCopy(
329        kCFAllocatorDefault,
330        (UniChar*)toLowerCase,
331        len,            // length
332        len,            // capacity
333        kCFAllocatorNull);
334   CFStringLowercase(cfString, NULL);
335   CFRelease(cfString);
336
337#elif (__GNUC__ >= 3 && _GLIBCPP_USE_WCHAR_T)
338
339        // Use this if there's a reasonable c library available.
340        // Metrowerks does this reasonably
341        wchar_t c;
342        for (XMLCh* p = (XMLCh*)toLowerCase; ((c = *p) != 0); )
343                *p++ = std::towlower(c);
344
345#else
346        #error Sorry, no support for lowerCase
347#endif
348}
349
350
351void
352MacOSUnicodeConverter::ConvertWideToNarrow(const XMLCh* wide, char* narrow, std::size_t maxChars)
353{
354        while (maxChars-- > 0)
355                if ((*narrow++ = *wide++) == 0)
356                        break;
357}
358
359
360void
361MacOSUnicodeConverter::CopyCStringToPascal(const char* c, Str255 pas)
362{
363        int len = strlen(c);
364        if (len > sizeof(pas)-1)
365                len = sizeof(pas)-1;
366        memmove(&pas[1], c, len);
367        pas[0] = len;
368}
369
370
371// ---------------------------------------------------------------------------
372//  MacOSTransService: The protected virtual transcoding service API
373// ---------------------------------------------------------------------------
374XMLTranscoder*
375MacOSUnicodeConverter::makeNewXMLTranscoder(const   XMLCh* const                encodingName
376                                        ,       XMLTransService::Codes& resValue
377                                        , const XMLSize_t               blockSize
378                                        ,       MemoryManager* const    manager)
379{
380        XMLTranscoder* result = NULL;
381        resValue = XMLTransService::Ok;
382       
383        TextToUnicodeInfo textToUnicodeInfo = NULL;
384        UnicodeToTextInfo unicodeToTextInfo = NULL;
385
386        //      Map the encoding to a Mac OS Encoding value
387        Str255 pasEncodingName;
388        char cEncodingName[256];
389        ConvertWideToNarrow(encodingName, cEncodingName, sizeof(cEncodingName));
390        CopyCStringToPascal(cEncodingName, pasEncodingName);
391       
392        TextEncoding textEncoding = 0;
393        OSStatus status = TECGetTextEncodingFromInternetName (
394                                                        &textEncoding,
395                                                        pasEncodingName);
396                           
397    //  Make a transcoder for that encoding
398        if (status == noErr)
399                result = makeNewXMLTranscoder(encodingName, resValue, blockSize, textEncoding, manager);
400        else
401                resValue = XMLTransService::UnsupportedEncoding;
402       
403        return result;
404}
405
406
407XMLTranscoder*
408MacOSUnicodeConverter::makeNewXMLTranscoder(const   XMLCh* const                encodingName
409                                        ,       XMLTransService::Codes& resValue
410                                        , const XMLSize_t               blockSize
411                                                                                ,               TextEncoding            textEncoding
412                                        ,       MemoryManager* const    manager)
413{
414    XMLTranscoder* result = NULL;
415        resValue = XMLTransService::Ok;
416    OSStatus status = noErr;
417   
418    TECObjectRef textToUnicode = NULL;
419    TECObjectRef unicodeToText = NULL;
420   
421    //  We convert to and from utf16
422    TextEncoding utf16Encoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
423                                        kTextEncodingDefaultVariant,
424                                        kUnicode16BitFormat);
425
426    //  Create a TEC from our encoding to utf16
427    if (status == noErr)
428        status = TECCreateConverter(&textToUnicode, textEncoding, utf16Encoding);
429
430    //  Create a TEC from utf16 to our encoding
431    if (status == noErr)
432        status = TECCreateConverter(&unicodeToText, utf16Encoding, textEncoding);
433
434        if (status != noErr)
435        {
436        //  Clean up on error
437                if (textToUnicode != NULL)
438            TECDisposeConverter(textToUnicode);
439                       
440                if (unicodeToText != NULL)
441            TECDisposeConverter(unicodeToText);
442
443                resValue = XMLTransService::UnsupportedEncoding;
444        }
445        else
446    {
447        //  Create our transcoder, passing in the converters
448                result = new (manager) MacOSTranscoder(encodingName, textToUnicode, unicodeToText, blockSize, manager);
449    }
450       
451    return result;
452}
453
454
455// ---------------------------------------------------------------------------
456//  IsMacOSUnicodeConverterSupported
457// ---------------------------------------------------------------------------
458bool
459MacOSUnicodeConverter::IsMacOSUnicodeConverterSupported(void)
460{
461    return UpgradeScriptInfoToTextEncoding != (void*)NULL
462        && CreateTextToUnicodeInfoByEncoding != (void*)NULL
463        ;
464}
465
466
467// ---------------------------------------------------------------------------
468//  MacOSTranscoder: Constructors and Destructor
469// ---------------------------------------------------------------------------
470MacOSTranscoder::MacOSTranscoder(const  XMLCh* const    encodingName
471                                                                , TECObjectRef          textToUnicode
472                                                                , TECObjectRef          unicodeToText
473                                , const XMLSize_t       blockSize
474                                , MemoryManager* const  manager) :
475    XMLTranscoder(encodingName, blockSize, manager),
476    mTextToUnicode(textToUnicode),
477    mUnicodeToText(unicodeToText)
478{
479}
480
481
482MacOSTranscoder::~MacOSTranscoder()
483{
484        //      Dispose our text encoding converters
485        TECDisposeConverter(mTextToUnicode);
486        TECDisposeConverter(mUnicodeToText);
487}
488
489
490// ---------------------------------------------------------------------------
491//  MacOSTranscoder: The virtual transcoder API
492// ---------------------------------------------------------------------------
493
494XMLSize_t
495MacOSTranscoder::transcodeFrom(  const  XMLByte* const          srcData
496                                , const XMLSize_t               srcCount
497                                ,       XMLCh* const            toFill
498                                , const XMLSize_t               maxChars
499                                ,       XMLSize_t&              bytesEaten
500                                ,       unsigned char* const    charSizes)
501{
502        //  Reset the tec state (since we don't know that we're part of a
503        //  larger run of text).
504        TECClearConverterContextInfo(mTextToUnicode);
505       
506    //  Do the conversion
507    ByteCount bytesConsumed = 0;
508    ByteCount bytesProduced = 0;
509    OSStatus status = TECConvertText(mTextToUnicode,
510                (ConstTextPtr) srcData,
511                srcCount,                   // inputBufferLength
512                &bytesConsumed,                         // actualInputLength
513                (TextPtr) toFill,           // outputBuffer
514                maxChars * sizeof(XMLCh),       // outputBufferLength
515                &bytesProduced);                        // actualOutputLength
516
517    //  Ignorable error codes
518    if(    status == kTECUsedFallbacksStatus
519        || status == kTECOutputBufferFullStatus
520        || status == kTECPartialCharErr
521                )
522        status = noErr;
523       
524    if (status != noErr)
525        ThrowXML(TranscodingException, XMLExcepts::Trans_BadSrcSeq);
526       
527        std::size_t charsProduced = bytesProduced / sizeof(XMLCh);
528       
529    bytesEaten = bytesConsumed;
530    return charsProduced;
531}
532
533
534XMLSize_t
535MacOSTranscoder::transcodeTo(const  XMLCh* const    srcData
536                            , const XMLSize_t       srcCount
537                            ,       XMLByte* const  toFill
538                            , const XMLSize_t       maxBytes
539                            ,       XMLSize_t&      charsEaten
540                            , const UnRepOpts       options)
541{
542        //  Reset the tec state (since we don't know that we're part of a
543        //  larger run of text).
544        TECClearConverterContextInfo(mUnicodeToText);
545       
546    //  Do the conversion
547    ByteCount bytesConsumed = 0;
548    ByteCount bytesProduced = 0;
549    OSStatus status = TECConvertText(mUnicodeToText,
550                (ConstTextPtr) srcData,
551                srcCount * sizeof(XMLCh),   // inputBufferLength
552                &bytesConsumed,                         // actualInputLength
553                (TextPtr) toFill,           // outputBuffer
554                maxBytes,                   // outputBufferLength
555                &bytesProduced);                        // actualOutputLength
556
557    //  Ignorable error codes
558    if(    status == kTECUsedFallbacksStatus
559        || status == kTECOutputBufferFullStatus
560        || status == kTECPartialCharErr
561                )
562        status = noErr;
563       
564    std::size_t charsConsumed = bytesConsumed / sizeof(XMLCh);
565   
566    //  Deal with errors
567    if (status != noErr)
568    {
569        if (status == kTECUnmappableElementErr && options == UnRep_Throw)
570        {
571                XMLCh tmpBuf[17];
572            XMLString::binToText(srcData[charsConsumed], tmpBuf, 16, 16);
573            ThrowXML2
574            (
575                TranscodingException
576                , XMLExcepts::Trans_Unrepresentable
577                , tmpBuf
578                , getEncodingName()
579            );
580        }
581    }
582       
583    charsEaten = charsConsumed;
584    return bytesProduced;
585}
586
587
588bool
589MacOSTranscoder::canTranscodeTo(const unsigned int toCheck)
590{
591        //
592    //  If the passed value is really a surrogate embedded together, then
593    //  we need to break it out into its two chars. Else just one.
594    //
595    unsigned int    srcCnt = 0;
596    UniChar         srcBuf[2];
597
598    if (toCheck & 0xFFFF0000)
599    {
600        srcBuf[srcCnt++] = XMLCh(toCheck >> 10)   + 0xD800;
601        srcBuf[srcCnt++] = XMLCh(toCheck & 0x3FF) + 0xDC00;
602    }
603    else
604    {
605        srcBuf[srcCnt++] = XMLCh(toCheck);
606    }
607
608        //  Clear the converter state: we're in a new run of text
609        TECClearConverterContextInfo(mUnicodeToText);
610
611    //
612    //  Use a local temp buffer that would hold any sane multi-byte char
613    //  sequence and try to transcode this guy into it.
614    //
615    char tmpBuf[64];
616
617    ByteCount bytesConsumed = 0;
618    ByteCount bytesProduced = 0;
619    OSStatus status = TECConvertText(mUnicodeToText,
620                (ConstTextPtr) srcBuf,
621                srcCnt * sizeof(XMLCh),     // inputBufferLength
622                &bytesConsumed,                         // actualInputLength
623                (TextPtr) tmpBuf,           // outputBuffer
624                sizeof(tmpBuf),             // outputBufferLength
625                &bytesProduced);                        // actualOutputLength
626
627    std::size_t charsConsumed = bytesConsumed / sizeof(XMLCh);
628       
629        //      Return true if we transcoded the character(s)
630        //      successfully
631        return status == noErr && charsConsumed == srcCnt;
632}
633
634
635// ---------------------------------------------------------------------------
636//  MacOSLCPTranscoder: Constructors and Destructor
637// ---------------------------------------------------------------------------
638MacOSLCPTranscoder::MacOSLCPTranscoder(XMLTranscoder* const transcoder, MemoryManager* const manager)
639 : mTranscoder(transcoder),
640   mManager(manager),
641   mMutex (manager)
642{
643}
644
645
646MacOSLCPTranscoder::~MacOSLCPTranscoder()
647{
648        //      Dispose the XMLTranscoder we're using
649    delete mTranscoder;
650}
651
652
653// ---------------------------------------------------------------------------
654//  MacOSLCPTranscoder: Implementation of the virtual transcoder interface
655// ---------------------------------------------------------------------------
656
657// ---------------------------------------------------------------------------
658//      In order to implement calcRequiredSize we have to go ahead and do the
659//      conversion, which seems quite painful. The Mac Unicode converter has
660//      no way of saying "don't actually do the conversion." So we end up
661//      converting twice. It would be nice if the calling code could do some
662//      extra buffering to avoid this result.
663// ---------------------------------------------------------------------------
664XMLSize_t MacOSLCPTranscoder::calcRequiredSize(const char* const srcText
665                                     , MemoryManager* const manager)
666{
667        if (!srcText)
668                return 0;
669               
670        //  Lock our mutex to gain exclusive access to the transcoder
671        //  since the lcp transcoders are used globally.
672        XMLMutexLock lock(&mMutex);
673
674        std::size_t totalCharsProduced = 0;
675
676        const char* src = srcText;
677        XMLSize_t srcCnt = std::strlen(src);
678   
679    //  Iterate over the characters, converting into a temporary buffer which we'll discard.
680    //  All this to get the size required.
681        while (srcCnt > 0)
682    {
683        TempXMLBuf tmpBuf;
684        XMLSize_t bytesConsumed = 0;
685                XMLSize_t charsProduced = mTranscoder->transcodeFrom((XMLByte*)src, srcCnt,
686                                                                                                                tmpBuf, kTempBufCount,
687                                                                                                                bytesConsumed,
688                                                                                                                NULL);
689               
690        src     += bytesConsumed;
691        srcCnt  -= bytesConsumed;
692
693        totalCharsProduced += charsProduced;
694       
695        //  Bail out if nothing more was produced
696        if (charsProduced == 0)
697            break;
698    }
699
700        //      Return number of XMLCh characters required (not counting terminating NULL!)
701        return totalCharsProduced;
702}
703
704
705// ---------------------------------------------------------------------------
706//      In order to implement calcRequiredSize we have to go ahead and do the
707//      conversion, which seems quite painful. The Mac Unicode converter has
708//      no way of saying "don't actually do the conversion." So we end up
709//      converting twice. It would be nice if the calling code could do some
710//      extra buffering to avoid this result.
711// ---------------------------------------------------------------------------
712XMLSize_t MacOSLCPTranscoder::calcRequiredSize(const XMLCh* const srcText
713                                     , MemoryManager* const manager)
714{
715        if (!srcText)
716                return 0;
717
718        //  Lock our mutex to gain exclusive access to the transcoder
719        //  since the lcp transcoders are used globally.
720        XMLMutexLock lock(&mMutex);
721        std::size_t     totalBytesProduced = 0;
722
723        const XMLCh*    src     = srcText;
724        XMLSize_t    srcCnt  = XMLString::stringLen(src);
725   
726    //  Iterate over the characters, converting into a temporary buffer which we'll discard.
727    //  All this to get the size required.
728    while (srcCnt > 0)
729    {
730        TempCharBuf tmpBuf;
731        XMLSize_t charsConsumed = 0;
732                XMLSize_t bytesProduced = mTranscoder->transcodeTo(src, srcCnt,
733                                            (XMLByte*)tmpBuf, kTempBufCount,
734                                            charsConsumed,
735                                            XMLTranscoder::UnRep_RepChar);
736       
737        src     += charsConsumed;
738        srcCnt  -= charsConsumed;
739
740        totalBytesProduced += bytesProduced;
741       
742        //  Bail out if nothing more was produced
743        if (bytesProduced == 0)
744            break;
745    }
746
747        //      Return number of characters required (not counting terminating NULL!)
748        return totalBytesProduced;
749}
750
751
752char*
753MacOSLCPTranscoder::transcode(const XMLCh* const srcText,
754                              MemoryManager* const manager)
755{
756        if (!srcText)
757                return NULL;
758
759        //  Lock our mutex to gain exclusive access to the transcoder
760        //  since the lcp transcoders are used globally.
761        XMLMutexLock lock(&mMutex);
762
763        ArrayJanitor<char> result(0);
764        const XMLCh* src                = srcText;
765        XMLSize_t srcCnt                = XMLString::stringLen(src);
766        std::size_t resultCnt   = 0;
767
768    //  Iterate over the characters, buffering into a local temporary
769    //  buffer, which we dump into an allocated (and reallocated, as necessary)
770    //  string for return.
771    while (srcCnt > 0)
772    {
773                //  Transcode some characters
774        TempCharBuf tmpBuf;
775        XMLSize_t charsConsumed = 0;
776        XMLSize_t bytesProduced = mTranscoder->transcodeTo(src, srcCnt,
777                                            (XMLByte*)tmpBuf, kTempBufCount,
778                                            charsConsumed,
779                                            XMLTranscoder::UnRep_RepChar);
780        src     += charsConsumed;
781        srcCnt  -= charsConsumed;
782
783                //      Move the data to result buffer, reallocating as needed
784                if (bytesProduced > 0)
785                {
786                        //      Allocate space for result
787                        std::size_t newCnt = resultCnt + bytesProduced;
788                        ArrayJanitor<char> newResult
789            (
790                (char*) manager->allocate((newCnt + 1) * sizeof(char)) //new char[newCnt + 1]
791                , manager
792            );
793                        if (newResult.get() != NULL)
794                        {
795                                //      Incorporate previous result
796                                if (result.get() != NULL)
797                                        std::memcpy(newResult.get(), result.get(), resultCnt);
798                                result.reset(newResult.release());
799
800                                //      Copy in new data
801                                std::memcpy(result.get() + resultCnt, tmpBuf, bytesProduced);
802                                resultCnt = newCnt;
803                               
804                //  Terminate the result
805                                result[resultCnt] = '\0';                                       
806                        }
807                }
808        else
809            break;
810    }
811
812    if (!result.get())
813        {
814                //      No error, and no result: we probably processed a zero length
815                //      input, in which case we want a valid zero length output.
816                result.reset
817        (
818            (char*) manager->allocate(sizeof(char))//new char[1]
819            , manager
820        );
821                result[0] = '\0';
822        }
823
824        return result.release();
825}
826
827
828XMLCh*
829MacOSLCPTranscoder::transcode(const char* const srcText,
830                              MemoryManager* const manager)
831{
832        if (!srcText)
833                return NULL;
834
835        //  Lock our mutex to gain exclusive access to the transcoder
836        //  since the lcp transcoders are used globally.
837        XMLMutexLock lock(&mMutex);
838
839        ArrayJanitor<XMLCh> result(0);
840        const char* src                 = srcText;
841        std::size_t srcCnt              = std::strlen(src);
842        std::size_t resultCnt   = 0;
843
844    //  Iterate over the characters, buffering into a local temporary
845    //  buffer, which we dump into an allocated (and reallocated, as necessary)
846    //  string for return.
847    while (srcCnt > 0)
848    {
849        //  Transcode some characters
850                TempXMLBuf tmpBuf;
851        XMLSize_t bytesConsumed = 0;
852                XMLSize_t charsProduced = mTranscoder->transcodeFrom((XMLByte*)src, srcCnt,
853                                                                                                tmpBuf, kTempBufCount,
854                                                                                                bytesConsumed,
855                                                                                                NULL);
856        src     += bytesConsumed;
857        srcCnt  -= bytesConsumed;
858
859                //      Move the data to result buffer, reallocating as needed
860                if (charsProduced > 0)
861                {
862                        //      Allocate space for result
863                        std::size_t newCnt = resultCnt + charsProduced;
864                        ArrayJanitor<XMLCh> newResult
865            (
866                (XMLCh*) manager->allocate((newCnt + 1) * sizeof(XMLCh)) //new XMLCh[newCnt + 1]
867                , manager
868            );
869                        if (newResult.get() != NULL)
870                        {
871                                //      Incorporate previous result
872                                if (result.get() != NULL)
873                                        std::memcpy(newResult.get(), result.get(), resultCnt * sizeof(XMLCh));
874                                result.reset(newResult.release());
875
876                                //      Copy in new data
877                                std::memcpy(result.get() + resultCnt, tmpBuf, charsProduced * sizeof(XMLCh));
878                                resultCnt = newCnt;
879                               
880                                result[resultCnt] = 0;                 
881                        }
882                }
883        else
884            break;
885    }
886
887    if (!result.get())
888        {
889                //      No error, and no result: we probably processed a zero length
890                //      input, in which case we want a valid zero length output.
891                result.reset
892        (
893            (XMLCh*) manager->allocate(sizeof(XMLCh))//new XMLCh[1]
894            , manager
895        );
896                result[0] = '\0';
897        }
898       
899        return result.release();
900}
901
902
903bool
904MacOSLCPTranscoder::transcode(           const   char* const    toTranscode
905                                    ,       XMLCh* const    toFill
906                                    , const XMLSize_t       maxChars
907                                    , MemoryManager* const  manager)
908{
909    // toFill must contain space for maxChars XMLCh characters + 1 (for terminating NULL).
910
911    // Check for a couple of psycho corner cases
912    if (!toTranscode || !maxChars || !*toTranscode)
913    {
914        toFill[0] = 0;
915        return true;
916    }
917
918        //  Lock our mutex to gain exclusive access to the transcoder
919        //  since the lcp transcoders are used globally.
920        XMLMutexLock lock(&mMutex);
921
922    //  Call the transcoder to do the work
923    XMLSize_t srcLen = std::strlen(toTranscode);
924    XMLSize_t bytesConsumed = 0;
925    XMLSize_t charsProduced = mTranscoder->transcodeFrom((XMLByte*)toTranscode, srcLen,
926                                            toFill, maxChars,
927                                                                                        bytesConsumed,
928                                                                                        NULL);
929
930    //  Zero terminate the output string
931    toFill[charsProduced] = L'\0';
932   
933    //  Return true if we consumed all of the characters
934    return (bytesConsumed == srcLen);
935}
936
937
938bool
939MacOSLCPTranscoder::transcode(          const   XMLCh* const    toTranscode
940                                    ,       char* const     toFill
941                                    , const XMLSize_t       maxChars
942                                    , MemoryManager* const  manager)
943{
944    //  toFill must contain space for maxChars bytes + 1 (for terminating NULL).
945
946    // Check for a couple of psycho corner cases
947    if (!toTranscode || !maxChars || !*toTranscode)
948    {
949        toFill[0] = 0;
950        return true;
951    }
952
953        //  Lock our mutex to gain exclusive access to the transcoder
954        //  since the lcp transcoders are used globally.
955        XMLMutexLock lock(&mMutex);
956
957    //  Call the transcoder to do the work
958    XMLSize_t srcLen = XMLString::stringLen(toTranscode);
959    XMLSize_t charsConsumed = 0;
960    XMLSize_t bytesProduced = mTranscoder->transcodeTo(toTranscode, srcLen,
961                                            (XMLByte*)toFill, maxChars,
962                                            charsConsumed,
963                                            XMLTranscoder::UnRep_RepChar);
964
965    //  Zero terminate the output string
966    toFill[bytesProduced] = '\0';
967   
968    //  Return true if we consumed all of the characters
969    return (charsConsumed == srcLen);
970}
971
972
973XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.