1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/strconv.cpp
3 // Purpose: Unicode conversion classes
4 // Author: Ove Kaaven, Robert Roebling, Vadim Zeitlin, Vaclav Slavik,
5 // Ryan Norton, Fredrik Roubert (UTF7)
9 // Copyright: (c) 1999 Ove Kaaven, Robert Roebling, Vaclav Slavik
10 // (c) 2000-2003 Vadim Zeitlin
11 // (c) 2004 Ryan Norton, Fredrik Roubert
12 // Licence: wxWindows licence
13 /////////////////////////////////////////////////////////////////////////////
15 // ============================================================================
17 // ============================================================================
19 // ----------------------------------------------------------------------------
21 // ----------------------------------------------------------------------------
23 // For compilers that support precompilation, includes "wx.h".
24 #include "wx/wxprec.h"
35 #include "wx/strconv.h"
40 #include "wx/msw/private.h"
41 #include "wx/msw/missing.h"
52 #if defined(__WIN32__) && !defined(__WXMICROWIN__)
53 #define wxHAVE_WIN32_MB2WC
54 #endif // __WIN32__ but !__WXMICROWIN__
62 #include "wx/thread.h"
65 #include "wx/encconv.h"
66 #include "wx/fontmap.h"
71 #include <ATSUnicode.h>
72 #include <TextCommon.h>
73 #include <TextEncodingConverter.h>
76 #include "wx/mac/private.h" // includes mac headers
79 #define TRACE_STRCONV _T("strconv")
81 #if SIZEOF_WCHAR_T == 2
85 // ============================================================================
87 // ============================================================================
89 // ----------------------------------------------------------------------------
90 // UTF-16 en/decoding to/from UCS-4
91 // ----------------------------------------------------------------------------
94 static size_t encode_utf16(wxUint32 input
, wxUint16
*output
)
99 *output
= (wxUint16
) input
;
102 else if (input
>=0x110000)
110 *output
++ = (wxUint16
) ((input
>> 10)+0xd7c0);
111 *output
= (wxUint16
) ((input
&0x3ff)+0xdc00);
117 static size_t decode_utf16(const wxUint16
* input
, wxUint32
& output
)
119 if ((*input
<0xd800) || (*input
>0xdfff))
124 else if ((input
[1]<0xdc00) || (input
[1]>0xdfff))
131 output
= ((input
[0] - 0xd7c0) << 10) + (input
[1] - 0xdc00);
137 // ----------------------------------------------------------------------------
139 // ----------------------------------------------------------------------------
141 wxMBConv::~wxMBConv()
143 // nothing to do here (necessary for Darwin linking probably)
146 const wxWCharBuffer
wxMBConv::cMB2WC(const char *psz
) const
150 // calculate the length of the buffer needed first
151 size_t nLen
= MB2WC(NULL
, psz
, 0);
152 if ( nLen
!= (size_t)-1 )
154 // now do the actual conversion
155 wxWCharBuffer
buf(nLen
);
156 nLen
= MB2WC(buf
.data(), psz
, nLen
+ 1); // with the trailing NULL
157 if ( nLen
!= (size_t)-1 )
164 wxWCharBuffer
buf((wchar_t *)NULL
);
169 const wxCharBuffer
wxMBConv::cWC2MB(const wchar_t *pwz
) const
173 size_t nLen
= WC2MB(NULL
, pwz
, 0);
174 if ( nLen
!= (size_t)-1 )
176 wxCharBuffer
buf(nLen
+3); // space for a wxUint32 trailing zero
177 nLen
= WC2MB(buf
.data(), pwz
, nLen
+ 4);
178 if ( nLen
!= (size_t)-1 )
185 wxCharBuffer
buf((char *)NULL
);
190 const wxWCharBuffer
wxMBConv::cMB2WC(const char *szString
, size_t nStringLen
, size_t* pOutSize
) const
192 wxASSERT(pOutSize
!= NULL
);
194 const char* szEnd
= szString
+ nStringLen
+ 1;
195 const char* szPos
= szString
;
196 const char* szStart
= szPos
;
198 size_t nActualLength
= 0;
199 size_t nCurrentSize
= nStringLen
; //try normal size first (should never resize?)
201 wxWCharBuffer
theBuffer(nCurrentSize
);
203 //Convert the string until the length() is reached, continuing the
204 //loop every time a null character is reached
205 while(szPos
!= szEnd
)
207 wxASSERT(szPos
< szEnd
); //something is _really_ screwed up if this rings true
209 //Get the length of the current (sub)string
210 size_t nLen
= MB2WC(NULL
, szPos
, 0);
212 //Invalid conversion?
213 if( nLen
== (size_t)-1 )
216 theBuffer
.data()[0u] = wxT('\0');
221 //Increase the actual length (+1 for current null character)
222 nActualLength
+= nLen
+ 1;
224 //if buffer too big, realloc the buffer
225 if (nActualLength
> (nCurrentSize
+1))
227 wxWCharBuffer
theNewBuffer(nCurrentSize
<< 1);
228 memcpy(theNewBuffer
.data(), theBuffer
.data(), nCurrentSize
* sizeof(wchar_t));
229 theBuffer
= theNewBuffer
;
233 //Convert the current (sub)string
234 if ( MB2WC(&theBuffer
.data()[szPos
- szStart
], szPos
, nLen
+ 1) == (size_t)-1 )
237 theBuffer
.data()[0u] = wxT('\0');
241 //Increment to next (sub)string
242 //Note that we have to use strlen instead of nLen here
243 //because XX2XX gives us the size of the output buffer,
244 //which is not necessarily the length of the string
245 szPos
+= strlen(szPos
) + 1;
248 //success - return actual length and the buffer
249 *pOutSize
= nActualLength
;
253 const wxCharBuffer
wxMBConv::cWC2MB(const wchar_t *szString
, size_t nStringLen
, size_t* pOutSize
) const
255 wxASSERT(pOutSize
!= NULL
);
257 const wchar_t* szEnd
= szString
+ nStringLen
+ 1;
258 const wchar_t* szPos
= szString
;
259 const wchar_t* szStart
= szPos
;
261 size_t nActualLength
= 0;
262 size_t nCurrentSize
= nStringLen
<< 2; //try * 4 first
264 wxCharBuffer
theBuffer(nCurrentSize
);
266 //Convert the string until the length() is reached, continuing the
267 //loop every time a null character is reached
268 while(szPos
!= szEnd
)
270 wxASSERT(szPos
< szEnd
); //something is _really_ screwed up if this rings true
272 //Get the length of the current (sub)string
273 size_t nLen
= WC2MB(NULL
, szPos
, 0);
275 //Invalid conversion?
276 if( nLen
== (size_t)-1 )
279 theBuffer
.data()[0u] = wxT('\0');
283 //Increase the actual length (+1 for current null character)
284 nActualLength
+= nLen
+ 1;
286 //if buffer too big, realloc the buffer
287 if (nActualLength
> (nCurrentSize
+1))
289 wxCharBuffer
theNewBuffer(nCurrentSize
<< 1);
290 memcpy(theNewBuffer
.data(), theBuffer
.data(), nCurrentSize
);
291 theBuffer
= theNewBuffer
;
295 //Convert the current (sub)string
296 if(WC2MB(&theBuffer
.data()[szPos
- szStart
], szPos
, nLen
+ 1) == (size_t)-1 )
299 theBuffer
.data()[0u] = wxT('\0');
303 //Increment to next (sub)string
304 //Note that we have to use wxWcslen instead of nLen here
305 //because XX2XX gives us the size of the output buffer,
306 //which is not necessarily the length of the string
307 szPos
+= wxWcslen(szPos
) + 1;
310 //success - return actual length and the buffer
311 *pOutSize
= nActualLength
;
315 // ----------------------------------------------------------------------------
317 // ----------------------------------------------------------------------------
319 size_t wxMBConvLibc::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
321 return wxMB2WC(buf
, psz
, n
);
324 size_t wxMBConvLibc::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
326 return wxWC2MB(buf
, psz
, n
);
331 // ----------------------------------------------------------------------------
332 // wxConvBrokenFileNames
333 // ----------------------------------------------------------------------------
335 wxConvBrokenFileNames::wxConvBrokenFileNames(const wxChar
*charset
)
337 if ( !charset
|| wxStricmp(charset
, _T("UTF-8")) == 0
338 || wxStricmp(charset
, _T("UTF8")) == 0 )
339 m_conv
= new wxMBConvUTF8(wxMBConvUTF8::MAP_INVALID_UTF8_TO_OCTAL
);
341 m_conv
= new wxCSConv(charset
);
345 wxConvBrokenFileNames::MB2WC(wchar_t *outputBuf
,
347 size_t outputSize
) const
349 return m_conv
->MB2WC( outputBuf
, psz
, outputSize
);
353 wxConvBrokenFileNames::WC2MB(char *outputBuf
,
355 size_t outputSize
) const
357 return m_conv
->WC2MB( outputBuf
, psz
, outputSize
);
362 // ----------------------------------------------------------------------------
364 // ----------------------------------------------------------------------------
366 // Implementation (C) 2004 Fredrik Roubert
369 // BASE64 decoding table
371 static const unsigned char utf7unb64
[] =
373 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
374 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
375 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
376 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
377 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
378 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
379 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
380 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
381 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
382 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
383 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
384 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
385 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
386 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
387 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
388 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
389 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
390 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
391 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
392 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
393 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
394 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
395 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
396 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
397 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
398 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
399 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
400 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
401 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
402 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
403 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
404 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
407 size_t wxMBConvUTF7::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
411 while ( *psz
&& (!buf
|| (len
< n
)) )
413 unsigned char cc
= *psz
++;
421 else if (*psz
== '-')
429 else // start of BASE64 encoded string
433 for ( ok
= lsb
= false, d
= 0, l
= 0;
434 (cc
= utf7unb64
[(unsigned char)*psz
]) != 0xff;
439 for (l
+= 6; l
>= 8; lsb
= !lsb
)
441 unsigned char c
= (unsigned char)((d
>> (l
-= 8)) % 256);
451 *buf
= (wchar_t)(c
<< 8);
460 // in valid UTF7 we should have valid characters after '+'
469 if ( buf
&& (len
< n
) )
476 // BASE64 encoding table
478 static const unsigned char utf7enb64
[] =
480 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
481 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
482 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
483 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
484 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
485 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
486 'w', 'x', 'y', 'z', '0', '1', '2', '3',
487 '4', '5', '6', '7', '8', '9', '+', '/'
491 // UTF-7 encoding table
493 // 0 - Set D (directly encoded characters)
494 // 1 - Set O (optional direct characters)
495 // 2 - whitespace characters (optional)
496 // 3 - special characters
498 static const unsigned char utf7encode
[128] =
500 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 2, 3, 3,
501 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
502 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 3, 0, 0, 0, 3,
503 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
504 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
505 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 1, 1, 1,
506 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
507 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 3, 3
510 size_t wxMBConvUTF7::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
516 while (*psz
&& ((!buf
) || (len
< n
)))
519 if (cc
< 0x80 && utf7encode
[cc
] < 1)
527 else if (((wxUint32
)cc
) > 0xffff)
529 // no surrogate pair generation (yet?)
540 // BASE64 encode string
541 unsigned int lsb
, d
, l
;
542 for (d
= 0, l
= 0; /*nothing*/; psz
++)
544 for (lsb
= 0; lsb
< 2; lsb
++)
547 d
+= lsb
? cc
& 0xff : (cc
& 0xff00) >> 8;
549 for (l
+= 8; l
>= 6; )
553 *buf
++ = utf7enb64
[(d
>> l
) % 64];
558 if (!(cc
) || (cc
< 0x80 && utf7encode
[cc
] < 1))
564 *buf
++ = utf7enb64
[((d
% 16) << (6 - l
)) % 64];
573 if (buf
&& (len
< n
))
578 // ----------------------------------------------------------------------------
580 // ----------------------------------------------------------------------------
582 static wxUint32 utf8_max
[]=
583 { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff, 0xffffffff };
585 // boundaries of the private use area we use to (temporarily) remap invalid
586 // characters invalid in a UTF-8 encoded string
587 const wxUint32 wxUnicodePUA
= 0x100000;
588 const wxUint32 wxUnicodePUAEnd
= wxUnicodePUA
+ 256;
590 size_t wxMBConvUTF8::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
594 while (*psz
&& ((!buf
) || (len
< n
)))
596 const char *opsz
= psz
;
597 bool invalid
= false;
598 unsigned char cc
= *psz
++, fc
= cc
;
600 for (cnt
= 0; fc
& 0x80; cnt
++)
609 // escape the escape character for octal escapes
610 if ((m_options
& MAP_INVALID_UTF8_TO_OCTAL
)
611 && cc
== '\\' && (!buf
|| len
< n
))
623 // invalid UTF-8 sequence
628 unsigned ocnt
= cnt
- 1;
629 wxUint32 res
= cc
& (0x3f >> cnt
);
633 if ((cc
& 0xC0) != 0x80)
635 // invalid UTF-8 sequence
640 res
= (res
<< 6) | (cc
& 0x3f);
642 if (invalid
|| res
<= utf8_max
[ocnt
])
644 // illegal UTF-8 encoding
647 else if ((m_options
& MAP_INVALID_UTF8_TO_PUA
) &&
648 res
>= wxUnicodePUA
&& res
< wxUnicodePUAEnd
)
650 // if one of our PUA characters turns up externally
651 // it must also be treated as an illegal sequence
652 // (a bit like you have to escape an escape character)
658 // cast is ok because wchar_t == wxUuint16 if WC_UTF16
659 size_t pa
= encode_utf16(res
, (wxUint16
*)buf
);
660 if (pa
== (size_t)-1)
672 *buf
++ = (wchar_t)res
;
674 #endif // WC_UTF16/!WC_UTF16
679 if (m_options
& MAP_INVALID_UTF8_TO_PUA
)
681 while (opsz
< psz
&& (!buf
|| len
< n
))
684 // cast is ok because wchar_t == wxUuint16 if WC_UTF16
685 size_t pa
= encode_utf16((unsigned char)*opsz
+ wxUnicodePUA
, (wxUint16
*)buf
);
686 wxASSERT(pa
!= (size_t)-1);
693 *buf
++ = (wchar_t)(wxUnicodePUA
+ (unsigned char)*opsz
);
699 else if (m_options
& MAP_INVALID_UTF8_TO_OCTAL
)
701 while (opsz
< psz
&& (!buf
|| len
< n
))
703 if ( buf
&& len
+ 3 < n
)
705 unsigned char on
= *opsz
;
707 *buf
++ = (wchar_t)( L
'0' + on
/ 0100 );
708 *buf
++ = (wchar_t)( L
'0' + (on
% 0100) / 010 );
709 *buf
++ = (wchar_t)( L
'0' + on
% 010 );
715 else // MAP_INVALID_UTF8_NOT
722 if (buf
&& (len
< n
))
727 static inline bool isoctal(wchar_t wch
)
729 return L
'0' <= wch
&& wch
<= L
'7';
732 size_t wxMBConvUTF8::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
736 while (*psz
&& ((!buf
) || (len
< n
)))
740 // cast is ok for WC_UTF16
741 size_t pa
= decode_utf16((const wxUint16
*)psz
, cc
);
742 psz
+= (pa
== (size_t)-1) ? 1 : pa
;
744 cc
=(*psz
++) & 0x7fffffff;
747 if ( (m_options
& MAP_INVALID_UTF8_TO_PUA
)
748 && cc
>= wxUnicodePUA
&& cc
< wxUnicodePUAEnd
)
751 *buf
++ = (char)(cc
- wxUnicodePUA
);
754 else if ( (m_options
& MAP_INVALID_UTF8_TO_OCTAL
)
755 && cc
== L
'\\' && psz
[0] == L
'\\' )
762 else if ( (m_options
& MAP_INVALID_UTF8_TO_OCTAL
) &&
764 isoctal(psz
[0]) && isoctal(psz
[1]) && isoctal(psz
[2]) )
768 *buf
++ = (char) ((psz
[0] - L
'0')*0100 +
769 (psz
[1] - L
'0')*010 +
779 for (cnt
= 0; cc
> utf8_max
[cnt
]; cnt
++) {}
793 *buf
++ = (char) ((-128 >> cnt
) | ((cc
>> (cnt
* 6)) & (0x3f >> cnt
)));
795 *buf
++ = (char) (0x80 | ((cc
>> (cnt
* 6)) & 0x3f));
807 // ----------------------------------------------------------------------------
809 // ----------------------------------------------------------------------------
811 #ifdef WORDS_BIGENDIAN
812 #define wxMBConvUTF16straight wxMBConvUTF16BE
813 #define wxMBConvUTF16swap wxMBConvUTF16LE
815 #define wxMBConvUTF16swap wxMBConvUTF16BE
816 #define wxMBConvUTF16straight wxMBConvUTF16LE
822 // copy 16bit MB to 16bit String
823 size_t wxMBConvUTF16straight::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
827 while (*(wxUint16
*)psz
&& (!buf
|| len
< n
))
830 *buf
++ = *(wxUint16
*)psz
;
833 psz
+= sizeof(wxUint16
);
835 if (buf
&& len
<n
) *buf
=0;
841 // copy 16bit String to 16bit MB
842 size_t wxMBConvUTF16straight::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
846 while (*psz
&& (!buf
|| len
< n
))
850 *(wxUint16
*)buf
= *psz
;
851 buf
+= sizeof(wxUint16
);
853 len
+= sizeof(wxUint16
);
856 if (buf
&& len
<=n
-sizeof(wxUint16
)) *(wxUint16
*)buf
=0;
862 // swap 16bit MB to 16bit String
863 size_t wxMBConvUTF16swap::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
867 while (*(wxUint16
*)psz
&& (!buf
|| len
< n
))
871 ((char *)buf
)[0] = psz
[1];
872 ((char *)buf
)[1] = psz
[0];
876 psz
+= sizeof(wxUint16
);
878 if (buf
&& len
<n
) *buf
=0;
884 // swap 16bit MB to 16bit String
885 size_t wxMBConvUTF16swap::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
889 while (*psz
&& (!buf
|| len
< n
))
893 *buf
++ = ((char*)psz
)[1];
894 *buf
++ = ((char*)psz
)[0];
896 len
+= sizeof(wxUint16
);
899 if (buf
&& len
<=n
-sizeof(wxUint16
)) *(wxUint16
*)buf
=0;
908 // copy 16bit MB to 32bit String
909 size_t wxMBConvUTF16straight::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
913 while (*(wxUint16
*)psz
&& (!buf
|| len
< n
))
916 size_t pa
=decode_utf16((wxUint16
*)psz
, cc
);
917 if (pa
== (size_t)-1)
921 *buf
++ = (wchar_t)cc
;
923 psz
+= pa
* sizeof(wxUint16
);
925 if (buf
&& len
<n
) *buf
=0;
931 // copy 32bit String to 16bit MB
932 size_t wxMBConvUTF16straight::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
936 while (*psz
&& (!buf
|| len
< n
))
939 size_t pa
=encode_utf16(*psz
, cc
);
941 if (pa
== (size_t)-1)
946 *(wxUint16
*)buf
= cc
[0];
947 buf
+= sizeof(wxUint16
);
950 *(wxUint16
*)buf
= cc
[1];
951 buf
+= sizeof(wxUint16
);
955 len
+= pa
*sizeof(wxUint16
);
958 if (buf
&& len
<=n
-sizeof(wxUint16
)) *(wxUint16
*)buf
=0;
964 // swap 16bit MB to 32bit String
965 size_t wxMBConvUTF16swap::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
969 while (*(wxUint16
*)psz
&& (!buf
|| len
< n
))
973 tmp
[0]=psz
[1]; tmp
[1]=psz
[0];
974 tmp
[2]=psz
[3]; tmp
[3]=psz
[2];
976 size_t pa
=decode_utf16((wxUint16
*)tmp
, cc
);
977 if (pa
== (size_t)-1)
981 *buf
++ = (wchar_t)cc
;
984 psz
+= pa
* sizeof(wxUint16
);
986 if (buf
&& len
<n
) *buf
=0;
992 // swap 32bit String to 16bit MB
993 size_t wxMBConvUTF16swap::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
997 while (*psz
&& (!buf
|| len
< n
))
1000 size_t pa
=encode_utf16(*psz
, cc
);
1002 if (pa
== (size_t)-1)
1007 *buf
++ = ((char*)cc
)[1];
1008 *buf
++ = ((char*)cc
)[0];
1011 *buf
++ = ((char*)cc
)[3];
1012 *buf
++ = ((char*)cc
)[2];
1016 len
+= pa
*sizeof(wxUint16
);
1019 if (buf
&& len
<=n
-sizeof(wxUint16
)) *(wxUint16
*)buf
=0;
1027 // ----------------------------------------------------------------------------
1029 // ----------------------------------------------------------------------------
1031 #ifdef WORDS_BIGENDIAN
1032 #define wxMBConvUTF32straight wxMBConvUTF32BE
1033 #define wxMBConvUTF32swap wxMBConvUTF32LE
1035 #define wxMBConvUTF32swap wxMBConvUTF32BE
1036 #define wxMBConvUTF32straight wxMBConvUTF32LE
1040 WXDLLIMPEXP_DATA_BASE(wxMBConvUTF32LE
) wxConvUTF32LE
;
1041 WXDLLIMPEXP_DATA_BASE(wxMBConvUTF32BE
) wxConvUTF32BE
;
1046 // copy 32bit MB to 16bit String
1047 size_t wxMBConvUTF32straight::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
1051 while (*(wxUint32
*)psz
&& (!buf
|| len
< n
))
1055 size_t pa
=encode_utf16(*(wxUint32
*)psz
, cc
);
1056 if (pa
== (size_t)-1)
1066 psz
+= sizeof(wxUint32
);
1068 if (buf
&& len
<n
) *buf
=0;
1074 // copy 16bit String to 32bit MB
1075 size_t wxMBConvUTF32straight::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
1079 while (*psz
&& (!buf
|| len
< n
))
1083 // cast is ok for WC_UTF16
1084 size_t pa
= decode_utf16((const wxUint16
*)psz
, cc
);
1085 if (pa
== (size_t)-1)
1090 *(wxUint32
*)buf
= cc
;
1091 buf
+= sizeof(wxUint32
);
1093 len
+= sizeof(wxUint32
);
1097 if (buf
&& len
<=n
-sizeof(wxUint32
))
1105 // swap 32bit MB to 16bit String
1106 size_t wxMBConvUTF32swap::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
1110 while (*(wxUint32
*)psz
&& (!buf
|| len
< n
))
1113 tmp
[0] = psz
[3]; tmp
[1] = psz
[2];
1114 tmp
[2] = psz
[1]; tmp
[3] = psz
[0];
1119 size_t pa
=encode_utf16(*(wxUint32
*)tmp
, cc
);
1120 if (pa
== (size_t)-1)
1130 psz
+= sizeof(wxUint32
);
1140 // swap 16bit String to 32bit MB
1141 size_t wxMBConvUTF32swap::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
1145 while (*psz
&& (!buf
|| len
< n
))
1149 // cast is ok for WC_UTF16
1150 size_t pa
=decode_utf16((const wxUint16
*)psz
, *(wxUint32
*)cc
);
1151 if (pa
== (size_t)-1)
1161 len
+= sizeof(wxUint32
);
1165 if (buf
&& len
<=n
-sizeof(wxUint32
))
1174 // copy 32bit MB to 32bit String
1175 size_t wxMBConvUTF32straight::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
1179 while (*(wxUint32
*)psz
&& (!buf
|| len
< n
))
1182 *buf
++ = (wchar_t)(*(wxUint32
*)psz
);
1184 psz
+= sizeof(wxUint32
);
1194 // copy 32bit String to 32bit MB
1195 size_t wxMBConvUTF32straight::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
1199 while (*psz
&& (!buf
|| len
< n
))
1203 *(wxUint32
*)buf
= *psz
;
1204 buf
+= sizeof(wxUint32
);
1207 len
+= sizeof(wxUint32
);
1211 if (buf
&& len
<=n
-sizeof(wxUint32
))
1218 // swap 32bit MB to 32bit String
1219 size_t wxMBConvUTF32swap::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
1223 while (*(wxUint32
*)psz
&& (!buf
|| len
< n
))
1227 ((char *)buf
)[0] = psz
[3];
1228 ((char *)buf
)[1] = psz
[2];
1229 ((char *)buf
)[2] = psz
[1];
1230 ((char *)buf
)[3] = psz
[0];
1234 psz
+= sizeof(wxUint32
);
1244 // swap 32bit String to 32bit MB
1245 size_t wxMBConvUTF32swap::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
1249 while (*psz
&& (!buf
|| len
< n
))
1253 *buf
++ = ((char *)psz
)[3];
1254 *buf
++ = ((char *)psz
)[2];
1255 *buf
++ = ((char *)psz
)[1];
1256 *buf
++ = ((char *)psz
)[0];
1258 len
+= sizeof(wxUint32
);
1262 if (buf
&& len
<=n
-sizeof(wxUint32
))
1272 // ============================================================================
1273 // The classes doing conversion using the iconv_xxx() functions
1274 // ============================================================================
1278 // VS: glibc 2.1.3 is broken in that iconv() conversion to/from UCS4 fails with
1279 // E2BIG if output buffer is _exactly_ as big as needed. Such case is
1280 // (unless there's yet another bug in glibc) the only case when iconv()
1281 // returns with (size_t)-1 (which means error) and says there are 0 bytes
1282 // left in the input buffer -- when _real_ error occurs,
1283 // bytes-left-in-input buffer is non-zero. Hence, this alternative test for
1285 // [This bug does not appear in glibc 2.2.]
1286 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ <= 1
1287 #define ICONV_FAILED(cres, bufLeft) ((cres == (size_t)-1) && \
1288 (errno != E2BIG || bufLeft != 0))
1290 #define ICONV_FAILED(cres, bufLeft) (cres == (size_t)-1)
1293 #define ICONV_CHAR_CAST(x) ((ICONV_CONST char **)(x))
1295 #define ICONV_T_INVALID ((iconv_t)-1)
1297 #if SIZEOF_WCHAR_T == 4
1298 #define WC_BSWAP wxUINT32_SWAP_ALWAYS
1299 #define WC_ENC wxFONTENCODING_UTF32
1300 #elif SIZEOF_WCHAR_T == 2
1301 #define WC_BSWAP wxUINT16_SWAP_ALWAYS
1302 #define WC_ENC wxFONTENCODING_UTF16
1303 #else // sizeof(wchar_t) != 2 nor 4
1304 // does this ever happen?
1305 #error "Unknown sizeof(wchar_t): please report this to wx-dev@lists.wxwindows.org"
1308 // ----------------------------------------------------------------------------
1309 // wxMBConv_iconv: encapsulates an iconv character set
1310 // ----------------------------------------------------------------------------
1312 class wxMBConv_iconv
: public wxMBConv
1315 wxMBConv_iconv(const wxChar
*name
);
1316 virtual ~wxMBConv_iconv();
1318 virtual size_t MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const;
1319 virtual size_t WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const;
1322 { return (m2w
!= ICONV_T_INVALID
) && (w2m
!= ICONV_T_INVALID
); }
1325 // the iconv handlers used to translate from multibyte to wide char and in
1326 // the other direction
1330 // guards access to m2w and w2m objects
1331 wxMutex m_iconvMutex
;
1335 // the name (for iconv_open()) of a wide char charset -- if none is
1336 // available on this machine, it will remain NULL
1337 static wxString ms_wcCharsetName
;
1339 // true if the wide char encoding we use (i.e. ms_wcCharsetName) has
1340 // different endian-ness than the native one
1341 static bool ms_wcNeedsSwap
;
1344 // make the constructor available for unit testing
1345 WXDLLIMPEXP_BASE wxMBConv
* new_wxMBConv_iconv( const wxChar
* name
)
1347 wxMBConv_iconv
* result
= new wxMBConv_iconv( name
);
1348 if ( !result
->IsOk() )
1356 wxString
wxMBConv_iconv::ms_wcCharsetName
;
1357 bool wxMBConv_iconv::ms_wcNeedsSwap
= false;
1359 wxMBConv_iconv::wxMBConv_iconv(const wxChar
*name
)
1361 // iconv operates with chars, not wxChars, but luckily it uses only ASCII
1362 // names for the charsets
1363 const wxCharBuffer
cname(wxString(name
).ToAscii());
1365 // check for charset that represents wchar_t:
1366 if ( ms_wcCharsetName
.empty() )
1368 wxLogTrace(TRACE_STRCONV
, _T("Looking for wide char codeset:"));
1371 const wxChar
**names
= wxFontMapperBase::GetAllEncodingNames(WC_ENC
);
1372 #else // !wxUSE_FONTMAP
1373 static const wxChar
*names
[] =
1375 #if SIZEOF_WCHAR_T == 4
1377 #elif SIZEOF_WCHAR_T = 2
1382 #endif // wxUSE_FONTMAP/!wxUSE_FONTMAP
1384 for ( ; *names
&& ms_wcCharsetName
.empty(); ++names
)
1386 const wxString
nameCS(*names
);
1388 // first try charset with explicit bytesex info (e.g. "UCS-4LE"):
1389 wxString
nameXE(nameCS
);
1390 #ifdef WORDS_BIGENDIAN
1392 #else // little endian
1396 wxLogTrace(TRACE_STRCONV
, _T(" trying charset \"%s\""),
1399 m2w
= iconv_open(nameXE
.ToAscii(), cname
);
1400 if ( m2w
== ICONV_T_INVALID
)
1402 // try charset w/o bytesex info (e.g. "UCS4")
1403 wxLogTrace(TRACE_STRCONV
, _T(" trying charset \"%s\""),
1405 m2w
= iconv_open(nameCS
.ToAscii(), cname
);
1407 // and check for bytesex ourselves:
1408 if ( m2w
!= ICONV_T_INVALID
)
1410 char buf
[2], *bufPtr
;
1411 wchar_t wbuf
[2], *wbufPtr
;
1419 outsz
= SIZEOF_WCHAR_T
* 2;
1423 res
= iconv(m2w
, ICONV_CHAR_CAST(&bufPtr
), &insz
,
1424 (char**)&wbufPtr
, &outsz
);
1426 if (ICONV_FAILED(res
, insz
))
1428 wxLogLastError(wxT("iconv"));
1429 wxLogError(_("Conversion to charset '%s' doesn't work."),
1432 else // ok, can convert to this encoding, remember it
1434 ms_wcCharsetName
= nameCS
;
1435 ms_wcNeedsSwap
= wbuf
[0] != (wchar_t)buf
[0];
1439 else // use charset not requiring byte swapping
1441 ms_wcCharsetName
= nameXE
;
1445 wxLogTrace(TRACE_STRCONV
,
1446 wxT("iconv wchar_t charset is \"%s\"%s"),
1447 ms_wcCharsetName
.empty() ? _T("<none>")
1448 : ms_wcCharsetName
.c_str(),
1449 ms_wcNeedsSwap
? _T(" (needs swap)")
1452 else // we already have ms_wcCharsetName
1454 m2w
= iconv_open(ms_wcCharsetName
.ToAscii(), cname
);
1457 if ( ms_wcCharsetName
.empty() )
1459 w2m
= ICONV_T_INVALID
;
1463 w2m
= iconv_open(cname
, ms_wcCharsetName
.ToAscii());
1464 if ( w2m
== ICONV_T_INVALID
)
1466 wxLogTrace(TRACE_STRCONV
,
1467 wxT("\"%s\" -> \"%s\" works but not the converse!?"),
1468 ms_wcCharsetName
.c_str(), cname
.data());
1473 wxMBConv_iconv::~wxMBConv_iconv()
1475 if ( m2w
!= ICONV_T_INVALID
)
1477 if ( w2m
!= ICONV_T_INVALID
)
1481 size_t wxMBConv_iconv::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
1484 // NB: iconv() is MT-safe, but each thread must use it's own iconv_t handle.
1485 // Unfortunately there is a couple of global wxCSConv objects such as
1486 // wxConvLocal that are used all over wx code, so we have to make sure
1487 // the handle is used by at most one thread at the time. Otherwise
1488 // only a few wx classes would be safe to use from non-main threads
1489 // as MB<->WC conversion would fail "randomly".
1490 wxMutexLocker
lock(wxConstCast(this, wxMBConv_iconv
)->m_iconvMutex
);
1493 size_t inbuf
= strlen(psz
);
1494 size_t outbuf
= n
* SIZEOF_WCHAR_T
;
1496 // VS: Use these instead of psz, buf because iconv() modifies its arguments:
1497 wchar_t *bufPtr
= buf
;
1498 const char *pszPtr
= psz
;
1502 // have destination buffer, convert there
1504 ICONV_CHAR_CAST(&pszPtr
), &inbuf
,
1505 (char**)&bufPtr
, &outbuf
);
1506 res
= n
- (outbuf
/ SIZEOF_WCHAR_T
);
1510 // convert to native endianness
1511 for ( unsigned i
= 0; i
< res
; i
++ )
1512 buf
[n
] = WC_BSWAP(buf
[i
]);
1515 // NB: iconv was given only strlen(psz) characters on input, and so
1516 // it couldn't convert the trailing zero. Let's do it ourselves
1517 // if there's some room left for it in the output buffer.
1523 // no destination buffer... convert using temp buffer
1524 // to calculate destination buffer requirement
1529 outbuf
= 8*SIZEOF_WCHAR_T
;
1532 ICONV_CHAR_CAST(&pszPtr
), &inbuf
,
1533 (char**)&bufPtr
, &outbuf
);
1535 res
+= 8-(outbuf
/SIZEOF_WCHAR_T
);
1536 } while ((cres
==(size_t)-1) && (errno
==E2BIG
));
1539 if (ICONV_FAILED(cres
, inbuf
))
1541 //VS: it is ok if iconv fails, hence trace only
1542 wxLogTrace(TRACE_STRCONV
, wxT("iconv failed: %s"), wxSysErrorMsg(wxSysErrorCode()));
1549 size_t wxMBConv_iconv::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
1552 // NB: explained in MB2WC
1553 wxMutexLocker
lock(wxConstCast(this, wxMBConv_iconv
)->m_iconvMutex
);
1556 size_t inlen
= wxWcslen(psz
);
1557 size_t inbuf
= inlen
* SIZEOF_WCHAR_T
;
1561 wchar_t *tmpbuf
= 0;
1565 // need to copy to temp buffer to switch endianness
1566 // (doing WC_BSWAP twice on the original buffer won't help, as it
1567 // could be in read-only memory, or be accessed in some other thread)
1568 tmpbuf
= (wchar_t *)malloc(inbuf
+ SIZEOF_WCHAR_T
);
1569 for ( size_t i
= 0; i
< inlen
; i
++ )
1570 tmpbuf
[n
] = WC_BSWAP(psz
[i
]);
1571 tmpbuf
[inlen
] = L
'\0';
1577 // have destination buffer, convert there
1578 cres
= iconv( w2m
, ICONV_CHAR_CAST(&psz
), &inbuf
, &buf
, &outbuf
);
1582 // NB: iconv was given only wcslen(psz) characters on input, and so
1583 // it couldn't convert the trailing zero. Let's do it ourselves
1584 // if there's some room left for it in the output buffer.
1590 // no destination buffer... convert using temp buffer
1591 // to calculate destination buffer requirement
1595 buf
= tbuf
; outbuf
= 16;
1597 cres
= iconv( w2m
, ICONV_CHAR_CAST(&psz
), &inbuf
, &buf
, &outbuf
);
1600 } while ((cres
==(size_t)-1) && (errno
==E2BIG
));
1608 if (ICONV_FAILED(cres
, inbuf
))
1610 wxLogTrace(TRACE_STRCONV
, wxT("iconv failed: %s"), wxSysErrorMsg(wxSysErrorCode()));
1617 #endif // HAVE_ICONV
1620 // ============================================================================
1621 // Win32 conversion classes
1622 // ============================================================================
1624 #ifdef wxHAVE_WIN32_MB2WC
1628 extern WXDLLIMPEXP_BASE
long wxCharsetToCodepage(const wxChar
*charset
);
1629 extern WXDLLIMPEXP_BASE
long wxEncodingToCodepage(wxFontEncoding encoding
);
1632 class wxMBConv_win32
: public wxMBConv
1637 m_CodePage
= CP_ACP
;
1641 wxMBConv_win32(const wxChar
* name
)
1643 m_CodePage
= wxCharsetToCodepage(name
);
1646 wxMBConv_win32(wxFontEncoding encoding
)
1648 m_CodePage
= wxEncodingToCodepage(encoding
);
1652 size_t MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
1654 // note that we have to use MB_ERR_INVALID_CHARS flag as it without it
1655 // the behaviour is not compatible with the Unix version (using iconv)
1656 // and break the library itself, e.g. wxTextInputStream::NextChar()
1657 // wouldn't work if reading an incomplete MB char didn't result in an
1660 // note however that using MB_ERR_INVALID_CHARS with CP_UTF7 results in
1661 // an error (tested under Windows Server 2003) and apparently it is
1662 // done on purpose, i.e. the function accepts any input in this case
1663 // and although I'd prefer to return error on ill-formed output, our
1664 // own wxMBConvUTF7 doesn't detect errors (e.g. lone "+" which is
1665 // explicitly ill-formed according to RFC 2152) neither so we don't
1666 // even have any fallback here...
1668 // Moreover, MB_ERR_INVALID_CHARS is only supported on Win 2K SP4 or
1669 // Win XP or newer and if it is specified on older versions, conversion
1670 // from CP_UTF8 (which can have flags only 0 or MB_ERR_INVALID_CHARS)
1671 // fails. So we can only use the flag on newer Windows versions.
1672 // Additionally, the flag is not supported by UTF7, symbol and CJK
1673 // encodings. See here:
1674 // http://blogs.msdn.com/michkap/archive/2005/04/19/409566.aspx
1675 // http://msdn.microsoft.com/library/en-us/intl/unicode_17si.asp
1677 if ( m_CodePage
!= CP_UTF7
&& m_CodePage
!= CP_SYMBOL
&&
1678 m_CodePage
< 50000 &&
1679 IsAtLeastWin2kSP4() )
1681 flags
= MB_ERR_INVALID_CHARS
;
1683 else if ( m_CodePage
== CP_UTF8
)
1685 // Avoid round-trip in the special case of UTF-8 by using our
1686 // own UTF-8 conversion code:
1687 return wxMBConvUTF8().MB2WC(buf
, psz
, n
);
1690 const size_t len
= ::MultiByteToWideChar
1692 m_CodePage
, // code page
1693 flags
, // flags: fall on error
1694 psz
, // input string
1695 -1, // its length (NUL-terminated)
1696 buf
, // output string
1697 buf
? n
: 0 // size of output buffer
1701 // function totally failed
1705 // if we were really converting and didn't use MB_ERR_INVALID_CHARS,
1706 // check if we succeeded, by doing a double trip:
1707 if ( !flags
&& buf
)
1709 const size_t mbLen
= strlen(psz
);
1710 wxCharBuffer
mbBuf(mbLen
);
1711 if ( ::WideCharToMultiByte
1718 mbLen
+ 1, // size in bytes, not length
1722 strcmp(mbBuf
, psz
) != 0 )
1724 // we didn't obtain the same thing we started from, hence
1725 // the conversion was lossy and we consider that it failed
1730 // note that it returns count of written chars for buf != NULL and size
1731 // of the needed buffer for buf == NULL so in either case the length of
1732 // the string (which never includes the terminating NUL) is one less
1736 size_t WC2MB(char *buf
, const wchar_t *pwz
, size_t n
) const
1739 we have a problem here: by default, WideCharToMultiByte() may
1740 replace characters unrepresentable in the target code page with bad
1741 quality approximations such as turning "1/2" symbol (U+00BD) into
1742 "1" for the code pages which don't have it and we, obviously, want
1743 to avoid this at any price
1745 the trouble is that this function does it _silently_, i.e. it won't
1746 even tell us whether it did or not... Win98/2000 and higher provide
1747 WC_NO_BEST_FIT_CHARS but it doesn't work for the older systems and
1748 we have to resort to a round trip, i.e. check that converting back
1749 results in the same string -- this is, of course, expensive but
1750 otherwise we simply can't be sure to not garble the data.
1753 // determine if we can rely on WC_NO_BEST_FIT_CHARS: according to MSDN
1754 // it doesn't work with CJK encodings (which we test for rather roughly
1755 // here...) nor with UTF-7/8 nor, of course, with Windows versions not
1757 BOOL usedDef
wxDUMMY_INITIALIZE(false);
1760 if ( CanUseNoBestFit() && m_CodePage
< 50000 )
1762 // it's our lucky day
1763 flags
= WC_NO_BEST_FIT_CHARS
;
1764 pUsedDef
= &usedDef
;
1766 else // old system or unsupported encoding
1772 const size_t len
= ::WideCharToMultiByte
1774 m_CodePage
, // code page
1775 flags
, // either none or no best fit
1776 pwz
, // input string
1777 -1, // it is (wide) NUL-terminated
1778 buf
, // output buffer
1779 buf
? n
: 0, // and its size
1780 NULL
, // default "replacement" char
1781 pUsedDef
// [out] was it used?
1786 // function totally failed
1790 // if we were really converting, check if we succeeded
1795 // check if the conversion failed, i.e. if any replacements
1800 else // we must resort to double tripping...
1802 wxWCharBuffer
wcBuf(n
);
1803 if ( MB2WC(wcBuf
.data(), buf
, n
) == (size_t)-1 ||
1804 wcscmp(wcBuf
, pwz
) != 0 )
1806 // we didn't obtain the same thing we started from, hence
1807 // the conversion was lossy and we consider that it failed
1813 // see the comment above for the reason of "len - 1"
1817 bool IsOk() const { return m_CodePage
!= -1; }
1820 static bool CanUseNoBestFit()
1822 static int s_isWin98Or2k
= -1;
1824 if ( s_isWin98Or2k
== -1 )
1827 switch ( wxGetOsVersion(&verMaj
, &verMin
) )
1830 s_isWin98Or2k
= verMaj
>= 4 && verMin
>= 10;
1834 s_isWin98Or2k
= verMaj
>= 5;
1838 // unknown, be conseravtive by default
1842 wxASSERT_MSG( s_isWin98Or2k
!= -1, _T("should be set above") );
1845 return s_isWin98Or2k
== 1;
1848 static bool IsAtLeastWin2kSP4()
1853 static int s_isAtLeastWin2kSP4
= -1;
1855 if ( s_isAtLeastWin2kSP4
== -1 )
1857 OSVERSIONINFOEX ver
;
1859 memset(&ver
, 0, sizeof(ver
));
1860 ver
.dwOSVersionInfoSize
= sizeof(ver
);
1861 GetVersionEx((OSVERSIONINFO
*)&ver
);
1863 s_isAtLeastWin2kSP4
=
1864 ((ver
.dwMajorVersion
> 5) || // Vista+
1865 (ver
.dwMajorVersion
== 5 && ver
.dwMinorVersion
> 0) || // XP/2003
1866 (ver
.dwMajorVersion
== 5 && ver
.dwMinorVersion
== 0 &&
1867 ver
.wServicePackMajor
>= 4)) // 2000 SP4+
1871 return s_isAtLeastWin2kSP4
== 1;
1878 #endif // wxHAVE_WIN32_MB2WC
1880 // ============================================================================
1881 // Cocoa conversion classes
1882 // ============================================================================
1884 #if defined(__WXCOCOA__)
1886 // RN: There is no UTF-32 support in either Core Foundation or
1887 // Cocoa. Strangely enough, internally Core Foundation uses
1888 // UTF 32 internally quite a bit - its just not public (yet).
1890 #include <CoreFoundation/CFString.h>
1891 #include <CoreFoundation/CFStringEncodingExt.h>
1893 CFStringEncoding
wxCFStringEncFromFontEnc(wxFontEncoding encoding
)
1895 CFStringEncoding enc
= kCFStringEncodingInvalidId
;
1896 if ( encoding
== wxFONTENCODING_DEFAULT
)
1898 enc
= CFStringGetSystemEncoding();
1900 else switch( encoding
)
1902 case wxFONTENCODING_ISO8859_1
:
1903 enc
= kCFStringEncodingISOLatin1
;
1905 case wxFONTENCODING_ISO8859_2
:
1906 enc
= kCFStringEncodingISOLatin2
;
1908 case wxFONTENCODING_ISO8859_3
:
1909 enc
= kCFStringEncodingISOLatin3
;
1911 case wxFONTENCODING_ISO8859_4
:
1912 enc
= kCFStringEncodingISOLatin4
;
1914 case wxFONTENCODING_ISO8859_5
:
1915 enc
= kCFStringEncodingISOLatinCyrillic
;
1917 case wxFONTENCODING_ISO8859_6
:
1918 enc
= kCFStringEncodingISOLatinArabic
;
1920 case wxFONTENCODING_ISO8859_7
:
1921 enc
= kCFStringEncodingISOLatinGreek
;
1923 case wxFONTENCODING_ISO8859_8
:
1924 enc
= kCFStringEncodingISOLatinHebrew
;
1926 case wxFONTENCODING_ISO8859_9
:
1927 enc
= kCFStringEncodingISOLatin5
;
1929 case wxFONTENCODING_ISO8859_10
:
1930 enc
= kCFStringEncodingISOLatin6
;
1932 case wxFONTENCODING_ISO8859_11
:
1933 enc
= kCFStringEncodingISOLatinThai
;
1935 case wxFONTENCODING_ISO8859_13
:
1936 enc
= kCFStringEncodingISOLatin7
;
1938 case wxFONTENCODING_ISO8859_14
:
1939 enc
= kCFStringEncodingISOLatin8
;
1941 case wxFONTENCODING_ISO8859_15
:
1942 enc
= kCFStringEncodingISOLatin9
;
1945 case wxFONTENCODING_KOI8
:
1946 enc
= kCFStringEncodingKOI8_R
;
1948 case wxFONTENCODING_ALTERNATIVE
: // MS-DOS CP866
1949 enc
= kCFStringEncodingDOSRussian
;
1952 // case wxFONTENCODING_BULGARIAN :
1956 case wxFONTENCODING_CP437
:
1957 enc
=kCFStringEncodingDOSLatinUS
;
1959 case wxFONTENCODING_CP850
:
1960 enc
= kCFStringEncodingDOSLatin1
;
1962 case wxFONTENCODING_CP852
:
1963 enc
= kCFStringEncodingDOSLatin2
;
1965 case wxFONTENCODING_CP855
:
1966 enc
= kCFStringEncodingDOSCyrillic
;
1968 case wxFONTENCODING_CP866
:
1969 enc
=kCFStringEncodingDOSRussian
;
1971 case wxFONTENCODING_CP874
:
1972 enc
= kCFStringEncodingDOSThai
;
1974 case wxFONTENCODING_CP932
:
1975 enc
= kCFStringEncodingDOSJapanese
;
1977 case wxFONTENCODING_CP936
:
1978 enc
=kCFStringEncodingDOSChineseSimplif
;
1980 case wxFONTENCODING_CP949
:
1981 enc
= kCFStringEncodingDOSKorean
;
1983 case wxFONTENCODING_CP950
:
1984 enc
= kCFStringEncodingDOSChineseTrad
;
1986 case wxFONTENCODING_CP1250
:
1987 enc
= kCFStringEncodingWindowsLatin2
;
1989 case wxFONTENCODING_CP1251
:
1990 enc
=kCFStringEncodingWindowsCyrillic
;
1992 case wxFONTENCODING_CP1252
:
1993 enc
=kCFStringEncodingWindowsLatin1
;
1995 case wxFONTENCODING_CP1253
:
1996 enc
= kCFStringEncodingWindowsGreek
;
1998 case wxFONTENCODING_CP1254
:
1999 enc
= kCFStringEncodingWindowsLatin5
;
2001 case wxFONTENCODING_CP1255
:
2002 enc
=kCFStringEncodingWindowsHebrew
;
2004 case wxFONTENCODING_CP1256
:
2005 enc
=kCFStringEncodingWindowsArabic
;
2007 case wxFONTENCODING_CP1257
:
2008 enc
= kCFStringEncodingWindowsBalticRim
;
2010 // This only really encodes to UTF7 (if that) evidently
2011 // case wxFONTENCODING_UTF7 :
2012 // enc = kCFStringEncodingNonLossyASCII ;
2014 case wxFONTENCODING_UTF8
:
2015 enc
= kCFStringEncodingUTF8
;
2017 case wxFONTENCODING_EUC_JP
:
2018 enc
= kCFStringEncodingEUC_JP
;
2020 case wxFONTENCODING_UTF16
:
2021 enc
= kCFStringEncodingUnicode
;
2023 case wxFONTENCODING_MACROMAN
:
2024 enc
= kCFStringEncodingMacRoman
;
2026 case wxFONTENCODING_MACJAPANESE
:
2027 enc
= kCFStringEncodingMacJapanese
;
2029 case wxFONTENCODING_MACCHINESETRAD
:
2030 enc
= kCFStringEncodingMacChineseTrad
;
2032 case wxFONTENCODING_MACKOREAN
:
2033 enc
= kCFStringEncodingMacKorean
;
2035 case wxFONTENCODING_MACARABIC
:
2036 enc
= kCFStringEncodingMacArabic
;
2038 case wxFONTENCODING_MACHEBREW
:
2039 enc
= kCFStringEncodingMacHebrew
;
2041 case wxFONTENCODING_MACGREEK
:
2042 enc
= kCFStringEncodingMacGreek
;
2044 case wxFONTENCODING_MACCYRILLIC
:
2045 enc
= kCFStringEncodingMacCyrillic
;
2047 case wxFONTENCODING_MACDEVANAGARI
:
2048 enc
= kCFStringEncodingMacDevanagari
;
2050 case wxFONTENCODING_MACGURMUKHI
:
2051 enc
= kCFStringEncodingMacGurmukhi
;
2053 case wxFONTENCODING_MACGUJARATI
:
2054 enc
= kCFStringEncodingMacGujarati
;
2056 case wxFONTENCODING_MACORIYA
:
2057 enc
= kCFStringEncodingMacOriya
;
2059 case wxFONTENCODING_MACBENGALI
:
2060 enc
= kCFStringEncodingMacBengali
;
2062 case wxFONTENCODING_MACTAMIL
:
2063 enc
= kCFStringEncodingMacTamil
;
2065 case wxFONTENCODING_MACTELUGU
:
2066 enc
= kCFStringEncodingMacTelugu
;
2068 case wxFONTENCODING_MACKANNADA
:
2069 enc
= kCFStringEncodingMacKannada
;
2071 case wxFONTENCODING_MACMALAJALAM
:
2072 enc
= kCFStringEncodingMacMalayalam
;
2074 case wxFONTENCODING_MACSINHALESE
:
2075 enc
= kCFStringEncodingMacSinhalese
;
2077 case wxFONTENCODING_MACBURMESE
:
2078 enc
= kCFStringEncodingMacBurmese
;
2080 case wxFONTENCODING_MACKHMER
:
2081 enc
= kCFStringEncodingMacKhmer
;
2083 case wxFONTENCODING_MACTHAI
:
2084 enc
= kCFStringEncodingMacThai
;
2086 case wxFONTENCODING_MACLAOTIAN
:
2087 enc
= kCFStringEncodingMacLaotian
;
2089 case wxFONTENCODING_MACGEORGIAN
:
2090 enc
= kCFStringEncodingMacGeorgian
;
2092 case wxFONTENCODING_MACARMENIAN
:
2093 enc
= kCFStringEncodingMacArmenian
;
2095 case wxFONTENCODING_MACCHINESESIMP
:
2096 enc
= kCFStringEncodingMacChineseSimp
;
2098 case wxFONTENCODING_MACTIBETAN
:
2099 enc
= kCFStringEncodingMacTibetan
;
2101 case wxFONTENCODING_MACMONGOLIAN
:
2102 enc
= kCFStringEncodingMacMongolian
;
2104 case wxFONTENCODING_MACETHIOPIC
:
2105 enc
= kCFStringEncodingMacEthiopic
;
2107 case wxFONTENCODING_MACCENTRALEUR
:
2108 enc
= kCFStringEncodingMacCentralEurRoman
;
2110 case wxFONTENCODING_MACVIATNAMESE
:
2111 enc
= kCFStringEncodingMacVietnamese
;
2113 case wxFONTENCODING_MACARABICEXT
:
2114 enc
= kCFStringEncodingMacExtArabic
;
2116 case wxFONTENCODING_MACSYMBOL
:
2117 enc
= kCFStringEncodingMacSymbol
;
2119 case wxFONTENCODING_MACDINGBATS
:
2120 enc
= kCFStringEncodingMacDingbats
;
2122 case wxFONTENCODING_MACTURKISH
:
2123 enc
= kCFStringEncodingMacTurkish
;
2125 case wxFONTENCODING_MACCROATIAN
:
2126 enc
= kCFStringEncodingMacCroatian
;
2128 case wxFONTENCODING_MACICELANDIC
:
2129 enc
= kCFStringEncodingMacIcelandic
;
2131 case wxFONTENCODING_MACROMANIAN
:
2132 enc
= kCFStringEncodingMacRomanian
;
2134 case wxFONTENCODING_MACCELTIC
:
2135 enc
= kCFStringEncodingMacCeltic
;
2137 case wxFONTENCODING_MACGAELIC
:
2138 enc
= kCFStringEncodingMacGaelic
;
2140 // case wxFONTENCODING_MACKEYBOARD :
2141 // enc = kCFStringEncodingMacKeyboardGlyphs ;
2144 // because gcc is picky
2150 class wxMBConv_cocoa
: public wxMBConv
2155 Init(CFStringGetSystemEncoding()) ;
2159 wxMBConv_cocoa(const wxChar
* name
)
2161 Init( wxCFStringEncFromFontEnc(wxFontMapperBase::Get()->CharsetToEncoding(name
, false) ) ) ;
2165 wxMBConv_cocoa(wxFontEncoding encoding
)
2167 Init( wxCFStringEncFromFontEnc(encoding
) );
2174 void Init( CFStringEncoding encoding
)
2176 m_encoding
= encoding
;
2179 size_t MB2WC(wchar_t * szOut
, const char * szUnConv
, size_t nOutSize
) const
2183 CFStringRef theString
= CFStringCreateWithBytes (
2184 NULL
, //the allocator
2185 (const UInt8
*)szUnConv
,
2188 false //no BOM/external representation
2191 wxASSERT(theString
);
2193 size_t nOutLength
= CFStringGetLength(theString
);
2197 CFRelease(theString
);
2201 CFRange theRange
= { 0, nOutSize
};
2203 #if SIZEOF_WCHAR_T == 4
2204 UniChar
* szUniCharBuffer
= new UniChar
[nOutSize
];
2207 CFStringGetCharacters(theString
, theRange
, szUniCharBuffer
);
2209 CFRelease(theString
);
2211 szUniCharBuffer
[nOutLength
] = '\0' ;
2213 #if SIZEOF_WCHAR_T == 4
2214 wxMBConvUTF16 converter
;
2215 converter
.MB2WC(szOut
, (const char*)szUniCharBuffer
, nOutSize
) ;
2216 delete[] szUniCharBuffer
;
2222 size_t WC2MB(char *szOut
, const wchar_t *szUnConv
, size_t nOutSize
) const
2226 size_t nRealOutSize
;
2227 size_t nBufSize
= wxWcslen(szUnConv
);
2228 UniChar
* szUniBuffer
= (UniChar
*) szUnConv
;
2230 #if SIZEOF_WCHAR_T == 4
2231 wxMBConvUTF16 converter
;
2232 nBufSize
= converter
.WC2MB( NULL
, szUnConv
, 0 );
2233 szUniBuffer
= new UniChar
[ (nBufSize
/ sizeof(UniChar
)) + 1] ;
2234 converter
.WC2MB( (char*) szUniBuffer
, szUnConv
, nBufSize
+ sizeof(UniChar
)) ;
2235 nBufSize
/= sizeof(UniChar
);
2238 CFStringRef theString
= CFStringCreateWithCharactersNoCopy(
2242 kCFAllocatorNull
//deallocator - we want to deallocate it ourselves
2245 wxASSERT(theString
);
2247 //Note that CER puts a BOM when converting to unicode
2248 //so we check and use getchars instead in that case
2249 if (m_encoding
== kCFStringEncodingUnicode
)
2252 CFStringGetCharacters(theString
, CFRangeMake(0, nOutSize
- 1), (UniChar
*) szOut
);
2254 nRealOutSize
= CFStringGetLength(theString
) + 1;
2260 CFRangeMake(0, CFStringGetLength(theString
)),
2262 0, //what to put in characters that can't be converted -
2263 //0 tells CFString to return NULL if it meets such a character
2264 false, //not an external representation
2267 (CFIndex
*) &nRealOutSize
2271 CFRelease(theString
);
2273 #if SIZEOF_WCHAR_T == 4
2274 delete[] szUniBuffer
;
2277 return nRealOutSize
- 1;
2282 return m_encoding
!= kCFStringEncodingInvalidId
&&
2283 CFStringIsEncodingAvailable(m_encoding
);
2287 CFStringEncoding m_encoding
;
2290 #endif // defined(__WXCOCOA__)
2292 // ============================================================================
2293 // Mac conversion classes
2294 // ============================================================================
2296 #if defined(__WXMAC__) && defined(TARGET_CARBON)
2298 class wxMBConv_mac
: public wxMBConv
2303 Init(CFStringGetSystemEncoding()) ;
2307 wxMBConv_mac(const wxChar
* name
)
2309 Init( wxMacGetSystemEncFromFontEnc(wxFontMapperBase::Get()->CharsetToEncoding(name
, false) ) ) ;
2313 wxMBConv_mac(wxFontEncoding encoding
)
2315 Init( wxMacGetSystemEncFromFontEnc(encoding
) );
2320 OSStatus status
= noErr
;
2321 status
= TECDisposeConverter(m_MB2WC_converter
);
2322 status
= TECDisposeConverter(m_WC2MB_converter
);
2326 void Init( TextEncodingBase encoding
)
2328 OSStatus status
= noErr
;
2329 m_char_encoding
= encoding
;
2330 m_unicode_encoding
= CreateTextEncoding(kTextEncodingUnicodeDefault
,0,kUnicode16BitFormat
) ;
2332 status
= TECCreateConverter(&m_MB2WC_converter
,
2334 m_unicode_encoding
);
2335 status
= TECCreateConverter(&m_WC2MB_converter
,
2340 size_t MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
2342 OSStatus status
= noErr
;
2343 ByteCount byteOutLen
;
2344 ByteCount byteInLen
= strlen(psz
) ;
2345 wchar_t *tbuf
= NULL
;
2346 UniChar
* ubuf
= NULL
;
2351 //apple specs say at least 32
2352 n
= wxMax( 32 , byteInLen
) ;
2353 tbuf
= (wchar_t*) malloc( n
* SIZEOF_WCHAR_T
) ;
2355 ByteCount byteBufferLen
= n
* sizeof( UniChar
) ;
2356 #if SIZEOF_WCHAR_T == 4
2357 ubuf
= (UniChar
*) malloc( byteBufferLen
+ 2 ) ;
2359 ubuf
= (UniChar
*) (buf
? buf
: tbuf
) ;
2361 status
= TECConvertText(m_MB2WC_converter
, (ConstTextPtr
) psz
, byteInLen
, &byteInLen
,
2362 (TextPtr
) ubuf
, byteBufferLen
, &byteOutLen
);
2363 #if SIZEOF_WCHAR_T == 4
2364 // we have to terminate here, because n might be larger for the trailing zero, and if UniChar
2365 // is not properly terminated we get random characters at the end
2366 ubuf
[byteOutLen
/ sizeof( UniChar
) ] = 0 ;
2367 wxMBConvUTF16 converter
;
2368 res
= converter
.MB2WC( (buf
? buf
: tbuf
) , (const char*)ubuf
, n
) ;
2371 res
= byteOutLen
/ sizeof( UniChar
) ;
2376 if ( buf
&& res
< n
)
2382 size_t WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
2384 OSStatus status
= noErr
;
2385 ByteCount byteOutLen
;
2386 ByteCount byteInLen
= wxWcslen(psz
) * SIZEOF_WCHAR_T
;
2392 //apple specs say at least 32
2393 n
= wxMax( 32 , ((byteInLen
/ SIZEOF_WCHAR_T
) * 8) + SIZEOF_WCHAR_T
);
2394 tbuf
= (char*) malloc( n
) ;
2397 ByteCount byteBufferLen
= n
;
2398 UniChar
* ubuf
= NULL
;
2399 #if SIZEOF_WCHAR_T == 4
2400 wxMBConvUTF16 converter
;
2401 size_t unicharlen
= converter
.WC2MB( NULL
, psz
, 0 ) ;
2402 byteInLen
= unicharlen
;
2403 ubuf
= (UniChar
*) malloc( byteInLen
+ 2 ) ;
2404 converter
.WC2MB( (char*) ubuf
, psz
, unicharlen
+ 2 ) ;
2406 ubuf
= (UniChar
*) psz
;
2408 status
= TECConvertText(m_WC2MB_converter
, (ConstTextPtr
) ubuf
, byteInLen
, &byteInLen
,
2409 (TextPtr
) (buf
? buf
: tbuf
) , byteBufferLen
, &byteOutLen
);
2410 #if SIZEOF_WCHAR_T == 4
2416 size_t res
= byteOutLen
;
2417 if ( buf
&& res
< n
)
2421 //we need to double-trip to verify it didn't insert any ? in place
2422 //of bogus characters
2423 wxWCharBuffer
wcBuf(n
);
2424 size_t pszlen
= wxWcslen(psz
);
2425 if ( MB2WC(wcBuf
.data(), buf
, n
) == (size_t)-1 ||
2426 wxWcslen(wcBuf
) != pszlen
||
2427 memcmp(wcBuf
, psz
, pszlen
* sizeof(wchar_t)) != 0 )
2429 // we didn't obtain the same thing we started from, hence
2430 // the conversion was lossy and we consider that it failed
2439 { return m_MB2WC_converter
!= NULL
&& m_WC2MB_converter
!= NULL
; }
2442 TECObjectRef m_MB2WC_converter
;
2443 TECObjectRef m_WC2MB_converter
;
2445 TextEncodingBase m_char_encoding
;
2446 TextEncodingBase m_unicode_encoding
;
2449 #endif // defined(__WXMAC__) && defined(TARGET_CARBON)
2451 // ============================================================================
2452 // wxEncodingConverter based conversion classes
2453 // ============================================================================
2457 class wxMBConv_wxwin
: public wxMBConv
2462 m_ok
= m2w
.Init(m_enc
, wxFONTENCODING_UNICODE
) &&
2463 w2m
.Init(wxFONTENCODING_UNICODE
, m_enc
);
2467 // temporarily just use wxEncodingConverter stuff,
2468 // so that it works while a better implementation is built
2469 wxMBConv_wxwin(const wxChar
* name
)
2472 m_enc
= wxFontMapperBase::Get()->CharsetToEncoding(name
, false);
2474 m_enc
= wxFONTENCODING_SYSTEM
;
2479 wxMBConv_wxwin(wxFontEncoding enc
)
2486 size_t MB2WC(wchar_t *buf
, const char *psz
, size_t WXUNUSED(n
)) const
2488 size_t inbuf
= strlen(psz
);
2491 if (!m2w
.Convert(psz
,buf
))
2497 size_t WC2MB(char *buf
, const wchar_t *psz
, size_t WXUNUSED(n
)) const
2499 const size_t inbuf
= wxWcslen(psz
);
2502 if (!w2m
.Convert(psz
,buf
))
2509 bool IsOk() const { return m_ok
; }
2512 wxFontEncoding m_enc
;
2513 wxEncodingConverter m2w
, w2m
;
2515 // were we initialized successfully?
2518 DECLARE_NO_COPY_CLASS(wxMBConv_wxwin
)
2521 // make the constructors available for unit testing
2522 WXDLLIMPEXP_BASE wxMBConv
* new_wxMBConv_wxwin( const wxChar
* name
)
2524 wxMBConv_wxwin
* result
= new wxMBConv_wxwin( name
);
2525 if ( !result
->IsOk() )
2533 #endif // wxUSE_FONTMAP
2535 // ============================================================================
2536 // wxCSConv implementation
2537 // ============================================================================
2539 void wxCSConv::Init()
2546 wxCSConv::wxCSConv(const wxChar
*charset
)
2556 m_encoding
= wxFontMapperBase::GetEncodingFromName(charset
);
2558 m_encoding
= wxFONTENCODING_SYSTEM
;
2562 wxCSConv::wxCSConv(wxFontEncoding encoding
)
2564 if ( encoding
== wxFONTENCODING_MAX
|| encoding
== wxFONTENCODING_DEFAULT
)
2566 wxFAIL_MSG( _T("invalid encoding value in wxCSConv ctor") );
2568 encoding
= wxFONTENCODING_SYSTEM
;
2573 m_encoding
= encoding
;
2576 wxCSConv::~wxCSConv()
2581 wxCSConv::wxCSConv(const wxCSConv
& conv
)
2586 SetName(conv
.m_name
);
2587 m_encoding
= conv
.m_encoding
;
2590 wxCSConv
& wxCSConv::operator=(const wxCSConv
& conv
)
2594 SetName(conv
.m_name
);
2595 m_encoding
= conv
.m_encoding
;
2600 void wxCSConv::Clear()
2609 void wxCSConv::SetName(const wxChar
*charset
)
2613 m_name
= wxStrdup(charset
);
2619 #include "wx/hashmap.h"
2621 WX_DECLARE_HASH_MAP( wxFontEncoding
, wxString
, wxIntegerHash
, wxIntegerEqual
,
2622 wxEncodingNameCache
);
2624 static wxEncodingNameCache gs_nameCache
;
2627 wxMBConv
*wxCSConv::DoCreate() const
2630 wxLogTrace(TRACE_STRCONV
,
2631 wxT("creating conversion for %s"),
2633 : wxFontMapperBase::GetEncodingName(m_encoding
).c_str()));
2634 #endif // wxUSE_FONTMAP
2636 // check for the special case of ASCII or ISO8859-1 charset: as we have
2637 // special knowledge of it anyhow, we don't need to create a special
2638 // conversion object
2639 if ( m_encoding
== wxFONTENCODING_ISO8859_1
||
2640 m_encoding
== wxFONTENCODING_DEFAULT
)
2642 // don't convert at all
2646 // we trust OS to do conversion better than we can so try external
2647 // conversion methods first
2649 // the full order is:
2650 // 1. OS conversion (iconv() under Unix or Win32 API)
2651 // 2. hard coded conversions for UTF
2652 // 3. wxEncodingConverter as fall back
2658 #endif // !wxUSE_FONTMAP
2660 wxString
name(m_name
);
2661 wxFontEncoding
encoding(m_encoding
);
2663 if ( !name
.empty() )
2665 wxMBConv_iconv
*conv
= new wxMBConv_iconv(name
);
2673 wxFontMapperBase::Get()->CharsetToEncoding(name
, false);
2674 #endif // wxUSE_FONTMAP
2678 const wxEncodingNameCache::iterator it
= gs_nameCache
.find(encoding
);
2679 if ( it
!= gs_nameCache
.end() )
2681 if ( it
->second
.empty() )
2684 wxMBConv_iconv
*conv
= new wxMBConv_iconv(it
->second
);
2691 const wxChar
** names
= wxFontMapperBase::GetAllEncodingNames(encoding
);
2693 for ( ; *names
; ++names
)
2695 wxMBConv_iconv
*conv
= new wxMBConv_iconv(*names
);
2698 gs_nameCache
[encoding
] = *names
;
2705 gs_nameCache
[encoding
] = _T(""); // cache the failure
2707 #endif // wxUSE_FONTMAP
2709 #endif // HAVE_ICONV
2711 #ifdef wxHAVE_WIN32_MB2WC
2714 wxMBConv_win32
*conv
= m_name
? new wxMBConv_win32(m_name
)
2715 : new wxMBConv_win32(m_encoding
);
2724 #endif // wxHAVE_WIN32_MB2WC
2725 #if defined(__WXMAC__)
2727 // leave UTF16 and UTF32 to the built-ins of wx
2728 if ( m_name
|| ( m_encoding
< wxFONTENCODING_UTF16BE
||
2729 ( m_encoding
>= wxFONTENCODING_MACMIN
&& m_encoding
<= wxFONTENCODING_MACMAX
) ) )
2733 wxMBConv_mac
*conv
= m_name
? new wxMBConv_mac(m_name
)
2734 : new wxMBConv_mac(m_encoding
);
2736 wxMBConv_mac
*conv
= new wxMBConv_mac(m_encoding
);
2745 #if defined(__WXCOCOA__)
2747 if ( m_name
|| ( m_encoding
<= wxFONTENCODING_UTF16
) )
2751 wxMBConv_cocoa
*conv
= m_name
? new wxMBConv_cocoa(m_name
)
2752 : new wxMBConv_cocoa(m_encoding
);
2754 wxMBConv_cocoa
*conv
= new wxMBConv_cocoa(m_encoding
);
2764 wxFontEncoding enc
= m_encoding
;
2766 if ( enc
== wxFONTENCODING_SYSTEM
&& m_name
)
2768 // use "false" to suppress interactive dialogs -- we can be called from
2769 // anywhere and popping up a dialog from here is the last thing we want to
2771 enc
= wxFontMapperBase::Get()->CharsetToEncoding(m_name
, false);
2773 #endif // wxUSE_FONTMAP
2777 case wxFONTENCODING_UTF7
:
2778 return new wxMBConvUTF7
;
2780 case wxFONTENCODING_UTF8
:
2781 return new wxMBConvUTF8
;
2783 case wxFONTENCODING_UTF16BE
:
2784 return new wxMBConvUTF16BE
;
2786 case wxFONTENCODING_UTF16LE
:
2787 return new wxMBConvUTF16LE
;
2789 case wxFONTENCODING_UTF32BE
:
2790 return new wxMBConvUTF32BE
;
2792 case wxFONTENCODING_UTF32LE
:
2793 return new wxMBConvUTF32LE
;
2796 // nothing to do but put here to suppress gcc warnings
2803 wxMBConv_wxwin
*conv
= m_name
? new wxMBConv_wxwin(m_name
)
2804 : new wxMBConv_wxwin(m_encoding
);
2810 #endif // wxUSE_FONTMAP
2812 // NB: This is a hack to prevent deadlock. What could otherwise happen
2813 // in Unicode build: wxConvLocal creation ends up being here
2814 // because of some failure and logs the error. But wxLog will try to
2815 // attach timestamp, for which it will need wxConvLocal (to convert
2816 // time to char* and then wchar_t*), but that fails, tries to log
2817 // error, but wxLog has a (already locked) critical section that
2818 // guards static buffer.
2819 static bool alreadyLoggingError
= false;
2820 if (!alreadyLoggingError
)
2822 alreadyLoggingError
= true;
2823 wxLogError(_("Cannot convert from the charset '%s'!"),
2827 wxFontMapperBase::GetEncodingDescription(m_encoding
).c_str()
2828 #else // !wxUSE_FONTMAP
2829 wxString::Format(_("encoding %s"), m_encoding
).c_str()
2830 #endif // wxUSE_FONTMAP/!wxUSE_FONTMAP
2832 alreadyLoggingError
= false;
2838 void wxCSConv::CreateConvIfNeeded() const
2842 wxCSConv
*self
= (wxCSConv
*)this; // const_cast
2845 // if we don't have neither the name nor the encoding, use the default
2846 // encoding for this system
2847 if ( !m_name
&& m_encoding
== wxFONTENCODING_SYSTEM
)
2849 self
->m_name
= wxStrdup(wxLocale::GetSystemEncodingName());
2851 #endif // wxUSE_INTL
2853 self
->m_convReal
= DoCreate();
2854 self
->m_deferred
= false;
2858 size_t wxCSConv::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
2860 CreateConvIfNeeded();
2863 return m_convReal
->MB2WC(buf
, psz
, n
);
2866 size_t len
= strlen(psz
);
2870 for (size_t c
= 0; c
<= len
; c
++)
2871 buf
[c
] = (unsigned char)(psz
[c
]);
2877 size_t wxCSConv::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
2879 CreateConvIfNeeded();
2882 return m_convReal
->WC2MB(buf
, psz
, n
);
2885 const size_t len
= wxWcslen(psz
);
2888 for (size_t c
= 0; c
<= len
; c
++)
2892 buf
[c
] = (char)psz
[c
];
2897 for (size_t c
= 0; c
<= len
; c
++)
2907 // ----------------------------------------------------------------------------
2909 // ----------------------------------------------------------------------------
2912 static wxMBConv_win32 wxConvLibcObj
;
2913 #elif defined(__WXMAC__) && !defined(__MACH__)
2914 static wxMBConv_mac wxConvLibcObj
;
2916 static wxMBConvLibc wxConvLibcObj
;
2919 static wxCSConv
wxConvLocalObj(wxFONTENCODING_SYSTEM
);
2920 static wxCSConv
wxConvISO8859_1Obj(wxFONTENCODING_ISO8859_1
);
2921 static wxMBConvUTF7 wxConvUTF7Obj
;
2922 static wxMBConvUTF8 wxConvUTF8Obj
;
2924 WXDLLIMPEXP_DATA_BASE(wxMBConv
&) wxConvLibc
= wxConvLibcObj
;
2925 WXDLLIMPEXP_DATA_BASE(wxCSConv
&) wxConvLocal
= wxConvLocalObj
;
2926 WXDLLIMPEXP_DATA_BASE(wxCSConv
&) wxConvISO8859_1
= wxConvISO8859_1Obj
;
2927 WXDLLIMPEXP_DATA_BASE(wxMBConvUTF7
&) wxConvUTF7
= wxConvUTF7Obj
;
2928 WXDLLIMPEXP_DATA_BASE(wxMBConvUTF8
&) wxConvUTF8
= wxConvUTF8Obj
;
2929 WXDLLIMPEXP_DATA_BASE(wxMBConv
*) wxConvCurrent
= &wxConvLibcObj
;
2930 WXDLLIMPEXP_DATA_BASE(wxMBConv
*) wxConvFileName
= &
2938 #else // !wxUSE_WCHAR_T
2940 // stand-ins in absence of wchar_t
2941 WXDLLIMPEXP_DATA_BASE(wxMBConv
) wxConvLibc
,
2946 #endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T