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

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

Original Xerces files with import mods for icxercesc

File size: 32.0 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: Win32TransService.cpp 676954 2008-07-15 16:29:19Z dbertoni $
20 */
21
22
23// ---------------------------------------------------------------------------
24//  Includes
25// ---------------------------------------------------------------------------
26#if HAVE_CONFIG_H
27#       include <config.h>
28#endif
29
30#include <icxercesc/util/PlatformUtils.hpp>
31#include <xercesc/util/TranscodingException.hpp>
32#include <xercesc/util/XMLException.hpp>
33#include <icxercesc/util/XMLString.hpp>
34#include <xercesc/util/XMLUniDefs.hpp>
35#include <xercesc/util/XMLUni.hpp>
36#include <icxercesc/util/RefHashTableOf.hpp>
37#include "Win32TransService.hpp"
38
39XERCES_CPP_NAMESPACE_BEGIN
40
41
42// ---------------------------------------------------------------------------
43//  Local, const data
44// ---------------------------------------------------------------------------
45static const XMLCh gMyServiceId[] =
46{
47    chLatin_W, chLatin_i, chLatin_n, chDigit_3, chDigit_2, chNull
48};
49
50
51#if !HAVE_WCSUPR
52void _wcsupr(LPWSTR str)
53{
54    int nLen=XMLString::stringLen(str);
55    ::LCMapStringW( GetThreadLocale(), LCMAP_UPPERCASE, str, nLen, str, nLen);
56}
57#endif
58
59#if !HAVE_WCSLWR
60void _wcslwr(LPWSTR str)
61{
62    int nLen=XMLString::stringLen(str);
63    ::LCMapStringW( GetThreadLocale(), LCMAP_LOWERCASE, str, nLen, str, nLen);
64}
65#endif
66
67#if !HAVE_WCSNICMP
68int _wcsnicmp(LPCWSTR comp1, LPCWSTR comp2, unsigned int nLen)
69{
70    unsigned int len = XMLString::stringLen( comp1);
71    unsigned int otherLen = XMLString::stringLen( comp2);
72    unsigned int countChar = 0;
73    unsigned int maxChars;
74    int          theResult = 0;
75
76    // Determine at what string index the comparison stops.
77    len = ( len > nLen ) ? nLen : len;
78    otherLen = ( otherLen > nLen ) ? nLen : otherLen;
79    maxChars = ( len > otherLen ) ? otherLen : len;
80
81    // Handle situation when one argument or the other is NULL
82    // by returning +/- string length of non-NULL argument (inferred
83    // from XMLString::CompareNString).
84
85    // Obs. Definition of stringLen(XMLCh*) implies NULL ptr and ptr
86    // to Empty String are equivalent.  It handles NULL args, BTW.
87
88    if ( !comp1 )
89    {
90        // Negative because null ptr (c1) less than string (c2).
91        return ( 0 - otherLen );
92    }
93
94    if ( !comp2 )
95    {
96        // Positive because string (c1) still greater than null ptr (c2).
97        return len;
98    }
99
100    // Copy const parameter strings (plus terminating nul) into locals.
101    XMLCh* firstBuf = (XMLCh*) XMLPlatformUtils::fgMemoryManager->allocate( (++len) * sizeof(XMLCh) );//new XMLCh[ ++len];
102    XMLCh* secondBuf = (XMLCh*) XMLPlatformUtils::fgMemoryManager->allocate( (++otherLen) * sizeof(XMLCh) );//new XMLCh[ ++otherLen];
103    memcpy( firstBuf, comp1, len * sizeof(XMLCh));
104    memcpy( secondBuf, comp2, otherLen * sizeof(XMLCh));
105
106    // Then uppercase both strings, losing their case info.
107    ::LCMapStringW( GetThreadLocale(), LCMAP_UPPERCASE, (LPWSTR)firstBuf, len, (LPWSTR)firstBuf, len);
108    ::LCMapStringW( GetThreadLocale(), LCMAP_UPPERCASE, (LPWSTR)secondBuf, otherLen, (LPWSTR)secondBuf, otherLen);
109
110    // Strings are equal until proven otherwise.
111    while ( ( countChar < maxChars ) && ( !theResult ) )
112    {
113        theResult = (int)(firstBuf[countChar]) - (int)(secondBuf[countChar]);
114        ++countChar;
115    }
116
117    XMLPlatformUtils::fgMemoryManager->deallocate(firstBuf);//delete [] firstBuf;
118    XMLPlatformUtils::fgMemoryManager->deallocate(secondBuf);//delete [] secondBuf;
119
120    return theResult;
121}
122#endif
123
124#if !HAVE_WCSICMP
125int _wcsicmp(LPCWSTR comp1, LPCWSTR comp2)
126{
127    unsigned int len = XMLString::stringLen( comp1);
128    unsigned int otherLen = XMLString::stringLen( comp2);
129    // Must compare terminating NUL to return difference if one string is shorter than the other.
130    unsigned int maxChars = ( len > otherLen ) ? otherLen : len;
131    return _wcsnicmp(comp1, comp2, maxChars+1);
132}
133#endif
134
135// it's a local function (instead of a static function) so that we are not
136// forced to include <windows.h> in the header
137bool isAlias(const   HKEY            encodingKey
138             ,       char* const     aliasBuf = 0
139             , const unsigned int    nameBufSz = 0)
140{
141    unsigned long theType;
142    unsigned long theSize = nameBufSz;
143    return (::RegQueryValueExA
144    (
145        encodingKey
146        , "AliasForCharset"
147        , 0
148        , &theType
149        , (unsigned char*)aliasBuf
150        , &theSize
151    ) == ERROR_SUCCESS);
152}
153
154// ---------------------------------------------------------------------------
155//  This is the simple CPMapEntry class. It just contains an encoding name
156//  and a code page for that encoding.
157// ---------------------------------------------------------------------------
158class CPMapEntry : public XMemory
159{
160public :
161    // -----------------------------------------------------------------------
162    //  Constructors and Destructor
163    // -----------------------------------------------------------------------
164    CPMapEntry
165    (
166        const   XMLCh* const    encodingName
167        , const unsigned int    ieId
168        , MemoryManager*        manager
169    );
170
171    CPMapEntry
172    (
173        const   char* const     encodingName
174        , const unsigned int    ieId
175        , MemoryManager*        manager
176    );
177
178    ~CPMapEntry();
179
180
181    // -----------------------------------------------------------------------
182    //  Getter methods
183    // -----------------------------------------------------------------------
184    const XMLCh* getEncodingName() const;
185    const XMLCh* getKey() const;
186    unsigned int getIEEncoding() const;
187
188
189private :
190    // -----------------------------------------------------------------------
191    //  Unimplemented constructors and operators
192    // -----------------------------------------------------------------------
193    CPMapEntry();
194    CPMapEntry(const CPMapEntry&);
195    CPMapEntry& operator=(const CPMapEntry&);
196
197
198    // -----------------------------------------------------------------------
199    //  Private data members
200    //
201    //  fEncodingName
202    //      This is the encoding name for the code page that this instance
203    //      represents.
204    //
205    //  fIEId
206    //      This is the code page id.
207    // -----------------------------------------------------------------------
208    XMLCh*          fEncodingName;
209    unsigned int    fIEId;
210    MemoryManager*  fManager;
211};
212
213// ---------------------------------------------------------------------------
214//  CPMapEntry: Constructors and Destructor
215// ---------------------------------------------------------------------------
216CPMapEntry::CPMapEntry( const   char* const     encodingName
217                        , const unsigned int    ieId
218                        , MemoryManager*        manager) :
219    fEncodingName(0)
220    , fIEId(ieId)
221    , fManager(manager)
222{
223    // Transcode the name to Unicode and store that copy
224    int targetLen=::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, encodingName, -1, NULL, 0);
225    if(targetLen!=0)
226    {
227        fEncodingName = (XMLCh*) fManager->allocate
228        (
229            (targetLen + 1) * sizeof(XMLCh)
230        );//new XMLCh[targetLen + 1];
231        ::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, encodingName, -1, (LPWSTR)fEncodingName, targetLen);
232        fEncodingName[targetLen] = 0;
233
234        //
235        //  Upper case it because we are using a hash table and need to be
236        //  sure that we find all case combinations.
237        //
238        _wcsupr(fEncodingName);
239  }
240}
241
242CPMapEntry::CPMapEntry( const   XMLCh* const    encodingName
243                        , const unsigned int    ieId
244                        , MemoryManager*        manager) :
245
246    fEncodingName(0)
247    , fIEId(ieId)
248    , fManager(manager)
249{
250    fEncodingName = XMLString::replicate(encodingName, fManager);
251
252    //
253    //  Upper case it because we are using a hash table and need to be
254    //  sure that we find all case combinations.
255    //
256    _wcsupr(fEncodingName);
257}
258
259CPMapEntry::~CPMapEntry()
260{
261    fManager->deallocate(fEncodingName);//delete [] fEncodingName;
262}
263
264
265// ---------------------------------------------------------------------------
266//  CPMapEntry: Getter methods
267// ---------------------------------------------------------------------------
268const XMLCh* CPMapEntry::getEncodingName() const
269{
270    return fEncodingName;
271}
272
273unsigned int CPMapEntry::getIEEncoding() const
274{
275    return fIEId;
276}
277
278
279static bool onXPOrLater = false;
280
281
282//---------------------------------------------------------------------------
283//
284//  class Win32TransService Implementation ...
285//
286//---------------------------------------------------------------------------
287
288
289// ---------------------------------------------------------------------------
290//  Win32TransService: Constructors and Destructor
291// ---------------------------------------------------------------------------
292Win32TransService::Win32TransService(MemoryManager* manager) :
293    fCPMap(NULL)
294    , fManager(manager)
295{
296    // Figure out if we are on XP or later and save that flag for later use.
297    // We need this because of certain code page conversion calls.
298    OSVERSIONINFO   OSVer;
299    OSVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
300    ::GetVersionEx(&OSVer);
301
302    if ((OSVer.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
303        ((OSVer.dwMajorVersion == 5) && (OSVer.dwMinorVersion > 0)))
304    {
305        onXPOrLater = true;
306    }
307
308    fCPMap = new RefHashTableOf<CPMapEntry>(109);
309
310    //
311    //  Open up the registry key that contains the info we want. Note that,
312    //  if this key does not exist, then we just return. It will just mean
313    //  that we don't have any support except for intrinsic encodings supported
314    //  by the parser itself (and the LCP support of course.
315    //
316    HKEY charsetKey;
317    if (::RegOpenKeyExA
318    (
319        HKEY_CLASSES_ROOT
320        , "MIME\\Database\\Charset"
321        , 0
322        , KEY_READ
323        , &charsetKey))
324    {
325        return;
326    }
327
328    //
329    //  Read in the registry keys that hold the code page ids. Skip for now
330    //  those entries which indicate that they are aliases for some other
331    //  encodings. We'll come back and do a second round for those and look
332    //  up the original name and get the code page id.
333    //
334    //  Note that we have to use A versions here so that this will run on
335    //  98, and transcode the strings to Unicode.
336    //
337    const unsigned int nameBufSz = 1024;
338    char nameBuf[nameBufSz + 1];
339    unsigned int subIndex;
340    unsigned long theSize;
341    for (subIndex = 0;;++subIndex)
342    {
343        // Get the name of the next key
344        theSize = nameBufSz;
345        if (::RegEnumKeyExA
346        (
347            charsetKey
348            , subIndex
349            , nameBuf
350            , &theSize
351            , 0, 0, 0, 0) == ERROR_NO_MORE_ITEMS)
352        {
353            break;
354        }
355
356        // Open this subkey
357        HKEY encodingKey;
358        if (::RegOpenKeyExA
359        (
360            charsetKey
361            , nameBuf
362            , 0
363            , KEY_READ
364            , &encodingKey))
365        {
366            continue;
367        }
368
369        //
370        //  Lts see if its an alias. If so, then ignore it in this first
371        //  loop. Else, we'll add a new entry for this one.
372        //
373        if (!isAlias(encodingKey))
374        {
375            //
376            //  Lets get the two values out of this key that we are
377            //  interested in. There should be a code page entry and an
378            //  IE entry.
379            //
380            //  The Codepage entry is the default code page for a computer using that charset
381            //  while the InternetEncoding holds the code page that represents that charset
382            //
383            unsigned long theType;
384            unsigned int CPId;
385            unsigned int IEId;
386
387            theSize = sizeof(unsigned int);
388            if (::RegQueryValueExA
389            (
390                encodingKey
391                , "Codepage"
392                , 0
393                , &theType
394                , (unsigned char*)&CPId
395                , &theSize) != ERROR_SUCCESS)
396            {
397                ::RegCloseKey(encodingKey);
398                continue;
399            }
400
401            //
402            //  If this is not a valid Id, and it might not be because its
403            //  not loaded on this system, then don't take it.
404            //
405            if (::IsValidCodePage(CPId))
406            {
407                theSize = sizeof(unsigned int);
408                if (::RegQueryValueExA
409                (
410                    encodingKey
411                    , "InternetEncoding"
412                    , 0
413                    , &theType
414                    , (unsigned char*)&IEId
415                    , &theSize) != ERROR_SUCCESS)
416                {
417                    ::RegCloseKey(encodingKey);
418                    continue;
419                }
420
421                CPMapEntry* newEntry = new (fManager) CPMapEntry(nameBuf, IEId, fManager);
422                fCPMap->put((void*)newEntry->getEncodingName(), newEntry);
423            }
424        }
425
426        // And close the subkey handle
427        ::RegCloseKey(encodingKey);
428    }
429
430    //
431    //  Now loop one more time and this time we do just the aliases. For
432    //  each one we find, we look up that name in the map we've already
433    //  built and add a new entry with this new name and the same id
434    //  values we stored for the original.
435    //
436    char aliasBuf[nameBufSz + 1];
437    for (subIndex = 0;;++subIndex)
438    {
439        // Get the name of the next key
440        theSize = nameBufSz;
441        if (::RegEnumKeyExA
442        (
443            charsetKey
444            , subIndex
445            , nameBuf
446            , &theSize
447            , 0, 0, 0, 0) == ERROR_NO_MORE_ITEMS)
448        {
449            break;
450        }
451
452        // Open this subkey
453        HKEY encodingKey;
454        if (::RegOpenKeyExA
455        (
456            charsetKey
457            , nameBuf
458            , 0
459            , KEY_READ
460            , &encodingKey))
461        {
462            continue;
463        }
464
465        //
466        //  If its an alias, look up the name in the map. If we find it,
467        //  then construct a new one with the new name and the aliased
468        //  ids.
469        //
470        if (isAlias(encodingKey, aliasBuf, nameBufSz))
471        {
472            int targetLen = ::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, aliasBuf, -1, NULL, 0);
473            if(targetLen!=0)
474            {
475                XMLCh* uniAlias = (XMLCh*) fManager->allocate
476                (
477                    (targetLen + 1) * sizeof(XMLCh)
478                );//new XMLCh[targetLen + 1];
479                ::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, aliasBuf, -1, (LPWSTR)uniAlias, targetLen);
480                uniAlias[targetLen] = 0;
481                _wcsupr(uniAlias);
482
483                // Look up the alias name
484                CPMapEntry* aliasedEntry = fCPMap->get(uniAlias);
485                if (aliasedEntry)
486                {
487                    int targetLen = ::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, nameBuf, -1, NULL, 0);
488                    if(targetLen!=0)
489                    {
490                        XMLCh* uniName = (XMLCh*) fManager->allocate
491                        (
492                            (targetLen + 1) * sizeof(XMLCh)
493                        );//new XMLCh[targetLen + 1];
494                        ::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, nameBuf, -1, (LPWSTR)uniName, targetLen);
495                        uniName[targetLen] = 0;
496                        _wcsupr(uniName);
497
498                        //
499                        //  If the name is actually different, then take it.
500                        //  Otherwise, don't take it. They map aliases that are
501                        //  just different case.
502                        //
503                                                if (!XMLString::equals(uniName, aliasedEntry->getEncodingName()))
504                        {
505                            CPMapEntry* newEntry = new (fManager) CPMapEntry(uniName, aliasedEntry->getIEEncoding(), fManager);
506                            fCPMap->put((void*)newEntry->getEncodingName(), newEntry);
507                        }
508
509                        fManager->deallocate(uniName);//delete [] uniName;
510                    }
511                }
512                fManager->deallocate(uniAlias);//delete [] uniAlias;
513            }
514        }
515
516        // And close the subkey handle
517        ::RegCloseKey(encodingKey);
518    }
519
520    // And close the main key handle
521    ::RegCloseKey(charsetKey);
522}
523
524Win32TransService::~Win32TransService()
525{
526    delete fCPMap;
527}
528
529
530// ---------------------------------------------------------------------------
531//  Win32TransService: The virtual transcoding service API
532// ---------------------------------------------------------------------------
533int Win32TransService::compareIString(  const   XMLCh* const    comp1
534                                        , const XMLCh* const    comp2)
535{
536    return _wcsicmp(comp1, comp2);
537}
538
539
540int Win32TransService::compareNIString( const   XMLCh* const    comp1
541                                        , const XMLCh* const    comp2
542                                        , const XMLSize_t       maxChars)
543{
544    return _wcsnicmp(comp1, comp2, maxChars);
545}
546
547
548const XMLCh* Win32TransService::getId() const
549{
550    return gMyServiceId;
551}
552
553XMLLCPTranscoder* Win32TransService::makeNewLCPTranscoder(MemoryManager* manager)
554{
555    // Just allocate a new LCP transcoder of our type
556    return new (manager) Win32LCPTranscoder;
557}
558
559
560bool Win32TransService::supportsSrcOfs() const
561{
562    //
563    //  Since the only mechanism we have to translate XML text in this
564    //  transcoder basically require us to do work that allows us to support
565    //  source offsets, we might as well do it.
566    //
567    return true;
568}
569
570
571void Win32TransService::upperCase(XMLCh* const toUpperCase)
572{
573    _wcsupr(toUpperCase);
574}
575
576void Win32TransService::lowerCase(XMLCh* const toLowerCase)
577{
578    _wcslwr(toLowerCase);
579}
580
581XMLTranscoder*
582Win32TransService::makeNewXMLTranscoder(const   XMLCh* const            encodingName
583                                        ,       XMLTransService::Codes& resValue
584                                        , const XMLSize_t               blockSize
585                                        ,       MemoryManager* const    manager)
586{
587    const XMLSize_t upLen = 1024;
588    XMLCh upEncoding[upLen + 1];
589
590    //
591    //  Get an upper cased copy of the encoding name, since we use a hash
592    //  table and we store them all in upper case.
593    //
594    XMLString::copyNString(upEncoding, encodingName, upLen);
595    _wcsupr(upEncoding);
596
597    // Now to try to find this guy in the CP map
598    CPMapEntry* theEntry = fCPMap->get(upEncoding);
599
600    // If not found, then return a null pointer
601    if (!theEntry)
602    {
603        resValue = XMLTransService::UnsupportedEncoding;
604        return 0;
605    }
606
607    // We found it, so return a Win32 transcoder for this encoding
608    return new (manager) Win32Transcoder
609    (
610        encodingName
611        , theEntry->getIEEncoding()
612        , blockSize
613        , manager
614    );
615}
616
617
618
619
620
621
622
623
624//---------------------------------------------------------------------------
625//
626//  class Win32Transcoder Implementation ...
627//
628//---------------------------------------------------------------------------
629
630
631inline DWORD
632getFlagsValue(
633            UINT    idCP,
634            DWORD   desiredFlags)
635{
636    if (idCP == 50220 ||
637        idCP == 50227 ||
638        (idCP >= 57002 &&
639         idCP <= 57011))
640    {
641        // These code pages do not support any
642        // flag options.
643        return 0;
644    }
645    else if (idCP == 65001)
646    {
647        // UTF-8 only supports MB_ERR_INVALID_CHARS on
648        // versions of Windows since XP
649        if (!onXPOrLater)
650        {
651            return 0;
652        }
653        else
654        {
655            return desiredFlags & MB_ERR_INVALID_CHARS ?
656                        MB_ERR_INVALID_CHARS : 0;
657        }
658    }
659    else
660    {
661        return desiredFlags;
662    }
663}
664
665
666
667// ---------------------------------------------------------------------------
668//  Win32Transcoder: Constructors and Destructor
669// ---------------------------------------------------------------------------
670Win32Transcoder::Win32Transcoder(const  XMLCh* const   encodingName
671                                , const unsigned int   ieCP
672                                , const XMLSize_t      blockSize
673                                , MemoryManager* const manager) :
674
675    XMLTranscoder(encodingName, blockSize, manager)
676    , fIECP(ieCP)
677    , fUsedDef(FALSE)
678    , fPtrUsedDef(0)
679    , fFromFlags(getFlagsValue(ieCP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS))
680#if defined(WC_NO_BEST_FIT_CHARS)
681    , fToFlags(getFlagsValue(ieCP, WC_COMPOSITECHECK | WC_SEPCHARS | WC_NO_BEST_FIT_CHARS))
682#else
683    , fToFlags(getFlagsValue(ieCP, WC_COMPOSITECHECK | WC_SEPCHARS))
684#endif
685{
686    // Some code pages require that MultiByteToWideChar and WideCharToMultiByte
687    // be passed 0 for their second parameters (dwFlags).  If that's the case,
688    // it's also necessary to pass null pointers for the last two parameters
689    // to WideCharToMultiByte.  This is apparently because it's impossible to
690    // determine whether or not a substitution (replacement) character was used.
691    if (fToFlags)
692    {
693        fPtrUsedDef = &fUsedDef;
694    }
695}
696
697Win32Transcoder::~Win32Transcoder()
698{
699}
700
701
702// ---------------------------------------------------------------------------
703//  Win32Transcoder: The virtual transcoder API
704// ---------------------------------------------------------------------------
705XMLSize_t
706Win32Transcoder::transcodeFrom( const   XMLByte* const      srcData
707                                , const XMLSize_t           srcCount
708                                ,       XMLCh* const        toFill
709                                , const XMLSize_t           maxChars
710                                ,       XMLSize_t&          bytesEaten
711                                ,       unsigned char* const charSizes)
712{
713    // Get temp pointers to the in and out buffers, and the chars sizes one
714    XMLCh*          outPtr = toFill;
715    const XMLByte*  inPtr  = srcData;
716    unsigned char*  sizesPtr = charSizes;
717
718    // Calc end pointers for each of them
719    XMLCh*          outEnd = toFill + maxChars;
720    const XMLByte*  inEnd  = srcData + srcCount;
721
722    //
723    //  Now loop until we either get our max chars, or cannot get a whole
724    //  character from the input buffer.
725    //
726    bytesEaten = 0;
727    while ((outPtr < outEnd) && (inPtr < inEnd))
728    {
729        //
730        //  If we are looking at a leading byte of a multibyte sequence,
731        //  then we are going to eat 2 bytes, else 1.
732        //
733        unsigned char toEat = ::IsDBCSLeadByteEx(fIECP, *inPtr) ?
734                                    2 : 1;
735
736        // Make sure a whole char is in the source
737        if (inPtr + toEat > inEnd)
738            break;
739
740        // Try to translate this next char and check for an error
741        const unsigned int converted = ::MultiByteToWideChar
742        (
743            fIECP
744            , fFromFlags
745            , (const char*)inPtr
746            , toEat
747            , outPtr
748            , 1
749        );
750
751        if (converted != 1)
752        {
753            if (toEat == 1)
754            {
755                XMLCh tmpBuf[17];
756                XMLString::binToText((unsigned int)(*inPtr), tmpBuf, 16, 16, getMemoryManager());
757                ThrowXMLwithMemMgr2
758                (
759                    TranscodingException
760                    , XMLExcepts::Trans_BadSrcCP
761                    , tmpBuf
762                    , getEncodingName()
763                    , getMemoryManager()
764                );
765            }
766             else
767            {
768                ThrowXMLwithMemMgr(TranscodingException, XMLExcepts::Trans_BadSrcSeq, getMemoryManager());
769            }
770        }
771
772        // Update the char sizes array for this round
773        *sizesPtr++ = toEat;
774
775        // And update the bytes eaten count
776        bytesEaten += toEat;
777
778        // And update our in/out ptrs
779        inPtr += toEat;
780        outPtr++;
781    }
782
783    // Return the chars we output
784    return (outPtr - toFill);
785}
786
787
788XMLSize_t
789Win32Transcoder::transcodeTo(const  XMLCh* const    srcData
790                            , const XMLSize_t       srcCount
791                            ,       XMLByte* const  toFill
792                            , const XMLSize_t       maxBytes
793                            ,       XMLSize_t&      charsEaten
794                            , const UnRepOpts       options)
795{
796    // Get pointers to the start and end of each buffer
797    const XMLCh*    srcPtr = srcData;
798    const XMLCh*    srcEnd = srcData + srcCount;
799    XMLByte*        outPtr = toFill;
800    XMLByte*        outEnd = toFill + maxBytes;
801
802    //
803    //  Now loop until we either get our max chars, or cannot get a whole
804    //  character from the input buffer.
805    //
806    //  NOTE: We have to use a loop for this unfortunately because the
807    //  conversion API is too dumb to tell us how many chars it converted if
808    //  it couldn't do the whole source.
809    //
810    fUsedDef = FALSE;
811    while ((outPtr < outEnd) && (srcPtr < srcEnd))
812    {
813        //
814        //  Do one char and see if it made it.
815        const int bytesStored = ::WideCharToMultiByte
816        (
817            fIECP
818            , fToFlags
819            , srcPtr
820            , 1
821            , (char*)outPtr
822            , (int)(outEnd - outPtr)
823            , 0
824            , fPtrUsedDef
825        );
826
827        // If we didn't transcode anything, then we are done
828        if (!bytesStored)
829            break;
830
831        //
832        //  If the defaault char was used and the options indicate that
833        //  this isn't allowed, then throw.
834        //
835        if (fUsedDef && (options == UnRep_Throw))
836        {
837            XMLCh tmpBuf[17];
838            XMLString::binToText((unsigned int)*srcPtr, tmpBuf, 16, 16, getMemoryManager());
839            ThrowXMLwithMemMgr2
840            (
841                TranscodingException
842                , XMLExcepts::Trans_Unrepresentable
843                , tmpBuf
844                , getEncodingName()
845                , getMemoryManager()
846            );
847        }
848
849        // Update our pointers
850        outPtr += bytesStored;
851        srcPtr++;
852    }
853
854    // Update the chars eaten
855    charsEaten = srcPtr - srcData;
856
857    // And return the bytes we stored
858    return outPtr - toFill;
859}
860
861
862bool Win32Transcoder::canTranscodeTo(const unsigned int toCheck)
863{
864    //
865    //  If the passed value is really a surrogate embedded together, then
866    //  we need to break it out into its two chars. Else just one.
867    //
868    XMLCh           srcBuf[2];
869    unsigned int    srcCount = 1;
870    if (toCheck & 0xFFFF0000)
871    {
872        srcBuf[0] = XMLCh((toCheck >> 10) + 0xD800);
873        srcBuf[1] = XMLCh((toCheck & 0x3FF) + 0xDC00);
874        srcCount++;
875    }
876     else
877    {
878        srcBuf[0] = XMLCh(toCheck);
879    }
880
881    //
882    //  Use a local temp buffer that would hold any sane multi-byte char
883    //  sequence and try to transcode this guy into it.
884    //
885    char tmpBuf[64];
886
887    fUsedDef = FALSE;
888
889    const unsigned int bytesStored = ::WideCharToMultiByte
890    (
891        fIECP
892        , fToFlags
893        , srcBuf
894        , srcCount
895        , tmpBuf
896        , 64
897        , 0
898        , fPtrUsedDef
899    );
900
901    if (!bytesStored || fUsedDef)
902        return false;
903
904    return true;
905}
906
907
908
909
910//---------------------------------------------------------------------------
911//
912//  class Win32Transcoder Implementation ...
913//
914//---------------------------------------------------------------------------
915
916// ---------------------------------------------------------------------------
917//  Win32LCPTranscoder: Constructors and Destructor
918// ---------------------------------------------------------------------------
919Win32LCPTranscoder::Win32LCPTranscoder()
920{
921}
922
923Win32LCPTranscoder::~Win32LCPTranscoder()
924{
925}
926
927
928// ---------------------------------------------------------------------------
929//  Win32LCPTranscoder: Implementation of the virtual transcoder interface
930// ---------------------------------------------------------------------------
931XMLSize_t Win32LCPTranscoder::calcRequiredSize(const char* const srcText
932                                                  , MemoryManager* const /*manager*/)
933{
934    if (!srcText)
935        return 0;
936
937    return ::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, srcText, -1, NULL, 0);
938}
939
940
941XMLSize_t Win32LCPTranscoder::calcRequiredSize(const XMLCh* const srcText
942                                                  , MemoryManager* const /*manager*/)
943{
944    if (!srcText)
945        return 0;
946
947    return ::WideCharToMultiByte(CP_ACP, 0, srcText, -1, NULL, 0, NULL, NULL);
948}
949
950char* Win32LCPTranscoder::transcode(const XMLCh* const toTranscode,
951                                    MemoryManager* const manager)
952{
953    if (!toTranscode)
954        return 0;
955
956    char* retVal = 0;
957    if (*toTranscode)
958    {
959        // Calc the needed size
960        const XMLSize_t neededLen = calcRequiredSize(toTranscode, manager);
961
962        // Allocate a buffer of that size plus one for the null and transcode
963        retVal = (char*) manager->allocate((neededLen + 1) * sizeof(char)); //new char[neededLen + 1];
964        ::WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)toTranscode, -1, retVal, (int)neededLen+1, NULL, NULL);
965
966        // And cap it off anyway just to make sure
967        retVal[neededLen] = 0;
968    }
969     else
970    {
971        retVal = (char*) manager->allocate(sizeof(char)); //new char[1];
972        retVal[0] = 0;
973    }
974    return retVal;
975}
976
977XMLCh* Win32LCPTranscoder::transcode(const char* const toTranscode,
978                                     MemoryManager* const manager)
979{
980    if (!toTranscode)
981        return 0;
982
983    XMLCh* retVal = 0;
984    if (*toTranscode)
985    {
986        // Calculate the buffer size required
987        const XMLSize_t neededLen = calcRequiredSize(toTranscode, manager);
988        if (neededLen == 0)
989        {
990            retVal = (XMLCh*) manager->allocate(sizeof(XMLCh)); //new XMLCh[1];
991            retVal[0] = 0;
992            return retVal;
993        }
994
995        // Allocate a buffer of that size plus one for the null and transcode
996        retVal = (XMLCh*) manager->allocate((neededLen + 1) * sizeof(XMLCh)); //new XMLCh[neededLen + 1];
997        ::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, toTranscode, -1, (LPWSTR)retVal, (int)neededLen + 1);
998
999        // Cap it off just to make sure. We are so paranoid!
1000        retVal[neededLen] = 0;
1001    }
1002     else
1003    {
1004        retVal = (XMLCh*) manager->allocate(sizeof(XMLCh)); //new XMLCh[1];
1005        retVal[0] = 0;
1006    }
1007    return retVal;
1008}
1009
1010
1011bool Win32LCPTranscoder::transcode( const   char* const     toTranscode
1012                                    ,       XMLCh* const    toFill
1013                                    , const XMLSize_t       maxChars
1014                                    , MemoryManager* const  /*manager*/)
1015{
1016    // Check for a couple of psycho corner cases
1017    if (!toTranscode || !maxChars)
1018    {
1019        toFill[0] = 0;
1020        return true;
1021    }
1022
1023    if (!*toTranscode)
1024    {
1025        toFill[0] = 0;
1026        return true;
1027    }
1028
1029    // This one has a fixed size output, so try it and if it fails it fails
1030    if ( 0 == ::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, toTranscode, -1, (LPWSTR)toFill, (int)(maxChars + 1)) )
1031        return false;
1032    return true;
1033}
1034
1035
1036bool Win32LCPTranscoder::transcode( const   XMLCh* const    toTranscode
1037                                    ,       char* const     toFill
1038                                    , const XMLSize_t       maxBytes
1039                                    , MemoryManager* const  /*manager*/)
1040{
1041    // Watch for a couple of pyscho corner cases
1042    if (!toTranscode || !maxBytes)
1043    {
1044        toFill[0] = 0;
1045        return true;
1046    }
1047
1048    if (!*toTranscode)
1049    {
1050        toFill[0] = 0;
1051        return true;
1052    }
1053
1054    // This one has a fixed size output, so try it and if it fails it fails
1055    if ( 0 == ::WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)toTranscode, -1, toFill, (int)(maxBytes + 1), NULL, NULL) )
1056        return false;
1057
1058    // Cap it off just in case
1059    toFill[maxBytes] = 0;
1060    return true;
1061}
1062
1063
1064XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.