source: icXML/icXML-devel/src/icxercesc/util/Transcoders/Win32/Win32TransService.cpp @ 3153

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

Updates for build

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