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
);
191 wxMBConv::cMB2WC(const char *in
, size_t inLen
, size_t *outLen
) const
193 // the currently accumulated wide characters
196 // the current length of wbuf
199 // we need to know the representation of L'\0' for this conversion
201 const char * const nul
= GetMBNul(&nulLen
);
202 if ( nulLen
== (size_t)-1 || nulLen
== 0 )
203 return wxWCharBuffer();
205 // make a copy of the input string unless it is already properly
209 // now we can compute the input size if we were not given it: notice that
210 // in this case the string must be properly NUL-terminated, of course, as
211 // otherwise we have no way of knowing how long it is
212 if ( inLen
== (size_t)-1 )
214 // not the most efficient algorithm but it shouldn't matter as normally
215 // there are not many NULs in the string and so normally memcmp()
216 // should stop on the first character
217 for ( const char *p
= in
; ; p
++ )
219 if ( memcmp(p
, nul
, nulLen
) == 0 )
223 inLen
= p
- in
+ nulLen
;
225 else // we already have the size
227 // check if it's not already NUL-terminated too to avoid the copy
228 if ( inLen
< nulLen
|| memcmp(in
+ inLen
- nulLen
, nul
, nulLen
) != 0 )
230 // make a copy in order to properly NUL-terminate the string
231 bufTmp
= wxCharBuffer(inLen
+ nulLen
- 1 /* 1 will be added */);
232 memcpy(bufTmp
.data(), in
, inLen
);
233 memcpy(bufTmp
.data() + inLen
, nul
, nulLen
);
240 for ( const char * const inEnd
= in
+ inLen
;; )
242 // try to convert the current chunk if anything left
243 size_t lenChunk
= in
< inEnd
? MB2WC(NULL
, in
, 0) : 0;
246 // nothing left in the input string, conversion succeeded
249 // we shouldn't include the last NUL in the result length
250 *outLen
= lenBuf
? lenBuf
- 1 : 0;
256 if ( lenChunk
== (size_t)-1 )
259 const size_t lenBufNew
= lenBuf
+ lenChunk
;
260 if ( !wbuf
.extend(lenBufNew
) )
263 lenChunk
= MB2WC(wbuf
.data() + lenBuf
, in
, lenChunk
+ 1 /* for NUL */);
264 if ( lenChunk
== (size_t)-1 )
267 // +! for the embedded NUL (if something follows)
268 lenBuf
= lenBufNew
+ 1;
270 // advance the input pointer past the end of this chunk
271 while ( memcmp(in
, nul
, nulLen
) != 0 )
274 in
+= nulLen
; // skipping over its terminator as well
281 return wxWCharBuffer();
285 wxMBConv::cWC2MB(const wchar_t *in
, size_t inLen
, size_t *outLen
) const
287 // the currently accumulated multibyte characters
290 // the current length of buf
293 // make a copy of the input string unless it is already properly
296 // if we don't know its length we have no choice but to assume that it is,
297 // indeed, properly terminated
298 wxWCharBuffer bufTmp
;
299 if ( inLen
== (size_t)-1 )
301 inLen
= wxWcslen(in
) + 1;
303 else if ( inLen
!= 0 && in
[inLen
- 1] != L
'\0' )
305 // make a copy in order to properly NUL-terminate the string
306 bufTmp
= wxWCharBuffer(inLen
);
307 memcpy(bufTmp
.data(), in
, inLen
*sizeof(wchar_t));
313 for ( const wchar_t * const inEnd
= in
+ inLen
;; )
315 // try to convert the current chunk, if anything left
316 size_t lenChunk
= in
< inEnd
? WC2MB(NULL
, in
, 0) : 0;
319 // nothing left in the input string, conversion succeeded
321 *outLen
= lenBuf
? lenBuf
- 1 : lenBuf
;
326 if ( lenChunk
== (size_t)-1 )
329 const size_t lenBufNew
= lenBuf
+ lenChunk
;
330 if ( !buf
.extend(lenBufNew
) )
333 lenChunk
= WC2MB(buf
.data() + lenBuf
, in
, lenChunk
+ 1 /* for NUL */);
334 if ( lenChunk
== (size_t)-1 )
337 // chunk successfully converted, go to the next one
338 in
+= wxWcslen(in
) + 1 /* skip NUL too */;
339 lenBuf
= lenBufNew
+ 1;
346 return wxCharBuffer();
349 // ----------------------------------------------------------------------------
351 // ----------------------------------------------------------------------------
353 size_t wxMBConvLibc::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
355 return wxMB2WC(buf
, psz
, n
);
358 size_t wxMBConvLibc::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
360 return wxWC2MB(buf
, psz
, n
);
363 // ----------------------------------------------------------------------------
364 // wxConvBrokenFileNames
365 // ----------------------------------------------------------------------------
369 wxConvBrokenFileNames::wxConvBrokenFileNames(const wxChar
*charset
)
371 if ( !charset
|| wxStricmp(charset
, _T("UTF-8")) == 0
372 || wxStricmp(charset
, _T("UTF8")) == 0 )
373 m_conv
= new wxMBConvUTF8(wxMBConvUTF8::MAP_INVALID_UTF8_TO_OCTAL
);
375 m_conv
= new wxCSConv(charset
);
380 // ----------------------------------------------------------------------------
382 // ----------------------------------------------------------------------------
384 // Implementation (C) 2004 Fredrik Roubert
387 // BASE64 decoding table
389 static const unsigned char utf7unb64
[] =
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, 0x3e, 0xff, 0xff, 0xff, 0x3f,
397 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
398 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
399 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
400 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
401 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
402 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
403 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
404 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
405 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
406 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
407 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
408 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
409 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
410 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
411 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
412 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
413 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
414 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
415 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
416 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
417 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
418 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
419 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
420 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
421 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
422 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
425 size_t wxMBConvUTF7::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
429 while ( *psz
&& (!buf
|| (len
< n
)) )
431 unsigned char cc
= *psz
++;
439 else if (*psz
== '-')
447 else // start of BASE64 encoded string
451 for ( ok
= lsb
= false, d
= 0, l
= 0;
452 (cc
= utf7unb64
[(unsigned char)*psz
]) != 0xff;
457 for (l
+= 6; l
>= 8; lsb
= !lsb
)
459 unsigned char c
= (unsigned char)((d
>> (l
-= 8)) % 256);
469 *buf
= (wchar_t)(c
<< 8);
478 // in valid UTF7 we should have valid characters after '+'
487 if ( buf
&& (len
< n
) )
494 // BASE64 encoding table
496 static const unsigned char utf7enb64
[] =
498 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
499 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
500 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
501 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
502 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
503 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
504 'w', 'x', 'y', 'z', '0', '1', '2', '3',
505 '4', '5', '6', '7', '8', '9', '+', '/'
509 // UTF-7 encoding table
511 // 0 - Set D (directly encoded characters)
512 // 1 - Set O (optional direct characters)
513 // 2 - whitespace characters (optional)
514 // 3 - special characters
516 static const unsigned char utf7encode
[128] =
518 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 2, 3, 3,
519 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
520 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 3, 0, 0, 0, 3,
521 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
522 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
523 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 1, 1, 1,
524 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
525 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 3, 3
528 size_t wxMBConvUTF7::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
532 while (*psz
&& ((!buf
) || (len
< n
)))
535 if (cc
< 0x80 && utf7encode
[cc
] < 1)
543 else if (((wxUint32
)cc
) > 0xffff)
545 // no surrogate pair generation (yet?)
556 // BASE64 encode string
557 unsigned int lsb
, d
, l
;
558 for (d
= 0, l
= 0; /*nothing*/; psz
++)
560 for (lsb
= 0; lsb
< 2; lsb
++)
563 d
+= lsb
? cc
& 0xff : (cc
& 0xff00) >> 8;
565 for (l
+= 8; l
>= 6; )
569 *buf
++ = utf7enb64
[(d
>> l
) % 64];
574 if (!(cc
) || (cc
< 0x80 && utf7encode
[cc
] < 1))
580 *buf
++ = utf7enb64
[((d
% 16) << (6 - l
)) % 64];
589 if (buf
&& (len
< n
))
594 // ----------------------------------------------------------------------------
596 // ----------------------------------------------------------------------------
598 static wxUint32 utf8_max
[]=
599 { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff, 0xffffffff };
601 // boundaries of the private use area we use to (temporarily) remap invalid
602 // characters invalid in a UTF-8 encoded string
603 const wxUint32 wxUnicodePUA
= 0x100000;
604 const wxUint32 wxUnicodePUAEnd
= wxUnicodePUA
+ 256;
606 size_t wxMBConvUTF8::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
610 while (*psz
&& ((!buf
) || (len
< n
)))
612 const char *opsz
= psz
;
613 bool invalid
= false;
614 unsigned char cc
= *psz
++, fc
= cc
;
616 for (cnt
= 0; fc
& 0x80; cnt
++)
625 // escape the escape character for octal escapes
626 if ((m_options
& MAP_INVALID_UTF8_TO_OCTAL
)
627 && cc
== '\\' && (!buf
|| len
< n
))
639 // invalid UTF-8 sequence
644 unsigned ocnt
= cnt
- 1;
645 wxUint32 res
= cc
& (0x3f >> cnt
);
649 if ((cc
& 0xC0) != 0x80)
651 // invalid UTF-8 sequence
656 res
= (res
<< 6) | (cc
& 0x3f);
658 if (invalid
|| res
<= utf8_max
[ocnt
])
660 // illegal UTF-8 encoding
663 else if ((m_options
& MAP_INVALID_UTF8_TO_PUA
) &&
664 res
>= wxUnicodePUA
&& res
< wxUnicodePUAEnd
)
666 // if one of our PUA characters turns up externally
667 // it must also be treated as an illegal sequence
668 // (a bit like you have to escape an escape character)
674 // cast is ok because wchar_t == wxUuint16 if WC_UTF16
675 size_t pa
= encode_utf16(res
, (wxUint16
*)buf
);
676 if (pa
== (size_t)-1)
688 *buf
++ = (wchar_t)res
;
690 #endif // WC_UTF16/!WC_UTF16
695 if (m_options
& MAP_INVALID_UTF8_TO_PUA
)
697 while (opsz
< psz
&& (!buf
|| len
< n
))
700 // cast is ok because wchar_t == wxUuint16 if WC_UTF16
701 size_t pa
= encode_utf16((unsigned char)*opsz
+ wxUnicodePUA
, (wxUint16
*)buf
);
702 wxASSERT(pa
!= (size_t)-1);
709 *buf
++ = (wchar_t)(wxUnicodePUA
+ (unsigned char)*opsz
);
715 else if (m_options
& MAP_INVALID_UTF8_TO_OCTAL
)
717 while (opsz
< psz
&& (!buf
|| len
< n
))
719 if ( buf
&& len
+ 3 < n
)
721 unsigned char on
= *opsz
;
723 *buf
++ = (wchar_t)( L
'0' + on
/ 0100 );
724 *buf
++ = (wchar_t)( L
'0' + (on
% 0100) / 010 );
725 *buf
++ = (wchar_t)( L
'0' + on
% 010 );
731 else // MAP_INVALID_UTF8_NOT
738 if (buf
&& (len
< n
))
743 static inline bool isoctal(wchar_t wch
)
745 return L
'0' <= wch
&& wch
<= L
'7';
748 size_t wxMBConvUTF8::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
752 while (*psz
&& ((!buf
) || (len
< n
)))
756 // cast is ok for WC_UTF16
757 size_t pa
= decode_utf16((const wxUint16
*)psz
, cc
);
758 psz
+= (pa
== (size_t)-1) ? 1 : pa
;
760 cc
=(*psz
++) & 0x7fffffff;
763 if ( (m_options
& MAP_INVALID_UTF8_TO_PUA
)
764 && cc
>= wxUnicodePUA
&& cc
< wxUnicodePUAEnd
)
767 *buf
++ = (char)(cc
- wxUnicodePUA
);
770 else if ( (m_options
& MAP_INVALID_UTF8_TO_OCTAL
)
771 && cc
== L
'\\' && psz
[0] == L
'\\' )
778 else if ( (m_options
& MAP_INVALID_UTF8_TO_OCTAL
) &&
780 isoctal(psz
[0]) && isoctal(psz
[1]) && isoctal(psz
[2]) )
784 *buf
++ = (char) ((psz
[0] - L
'0')*0100 +
785 (psz
[1] - L
'0')*010 +
795 for (cnt
= 0; cc
> utf8_max
[cnt
]; cnt
++) {}
809 *buf
++ = (char) ((-128 >> cnt
) | ((cc
>> (cnt
* 6)) & (0x3f >> cnt
)));
811 *buf
++ = (char) (0x80 | ((cc
>> (cnt
* 6)) & 0x3f));
823 // ----------------------------------------------------------------------------
825 // ----------------------------------------------------------------------------
827 #ifdef WORDS_BIGENDIAN
828 #define wxMBConvUTF16straight wxMBConvUTF16BE
829 #define wxMBConvUTF16swap wxMBConvUTF16LE
831 #define wxMBConvUTF16swap wxMBConvUTF16BE
832 #define wxMBConvUTF16straight wxMBConvUTF16LE
838 // copy 16bit MB to 16bit String
839 size_t wxMBConvUTF16straight::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
843 while (*(wxUint16
*)psz
&& (!buf
|| len
< n
))
846 *buf
++ = *(wxUint16
*)psz
;
849 psz
+= sizeof(wxUint16
);
851 if (buf
&& len
<n
) *buf
=0;
857 // copy 16bit String to 16bit MB
858 size_t wxMBConvUTF16straight::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
862 while (*psz
&& (!buf
|| len
< n
))
866 *(wxUint16
*)buf
= *psz
;
867 buf
+= sizeof(wxUint16
);
869 len
+= sizeof(wxUint16
);
872 if (buf
&& len
<=n
-sizeof(wxUint16
)) *(wxUint16
*)buf
=0;
878 // swap 16bit MB to 16bit String
879 size_t wxMBConvUTF16swap::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
883 // UTF16 string must be terminated by 2 NULs as single NULs may occur
885 while ( (psz
[0] || psz
[1]) && (!buf
|| len
< n
) )
889 ((char *)buf
)[0] = psz
[1];
890 ((char *)buf
)[1] = psz
[0];
897 if ( buf
&& len
< n
)
904 // swap 16bit MB to 16bit String
905 size_t wxMBConvUTF16swap::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
909 while ( *psz
&& (!buf
|| len
< n
) )
913 *buf
++ = ((char*)psz
)[1];
914 *buf
++ = ((char*)psz
)[0];
920 if ( buf
&& len
< n
)
930 // copy 16bit MB to 32bit String
931 size_t wxMBConvUTF16straight::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
935 while (*(wxUint16
*)psz
&& (!buf
|| len
< n
))
938 size_t pa
=decode_utf16((wxUint16
*)psz
, cc
);
939 if (pa
== (size_t)-1)
943 *buf
++ = (wchar_t)cc
;
945 psz
+= pa
* sizeof(wxUint16
);
947 if (buf
&& len
<n
) *buf
=0;
953 // copy 32bit String to 16bit MB
954 size_t wxMBConvUTF16straight::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
958 while (*psz
&& (!buf
|| len
< n
))
961 size_t pa
=encode_utf16(*psz
, cc
);
963 if (pa
== (size_t)-1)
968 *(wxUint16
*)buf
= cc
[0];
969 buf
+= sizeof(wxUint16
);
972 *(wxUint16
*)buf
= cc
[1];
973 buf
+= sizeof(wxUint16
);
977 len
+= pa
*sizeof(wxUint16
);
980 if (buf
&& len
<=n
-sizeof(wxUint16
)) *(wxUint16
*)buf
=0;
986 // swap 16bit MB to 32bit String
987 size_t wxMBConvUTF16swap::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
991 while (*(wxUint16
*)psz
&& (!buf
|| len
< n
))
995 tmp
[0]=psz
[1]; tmp
[1]=psz
[0];
996 tmp
[2]=psz
[3]; tmp
[3]=psz
[2];
998 size_t pa
=decode_utf16((wxUint16
*)tmp
, cc
);
999 if (pa
== (size_t)-1)
1003 *buf
++ = (wchar_t)cc
;
1006 psz
+= pa
* sizeof(wxUint16
);
1008 if (buf
&& len
<n
) *buf
=0;
1014 // swap 32bit String to 16bit MB
1015 size_t wxMBConvUTF16swap::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
1019 while (*psz
&& (!buf
|| len
< n
))
1022 size_t pa
=encode_utf16(*psz
, cc
);
1024 if (pa
== (size_t)-1)
1029 *buf
++ = ((char*)cc
)[1];
1030 *buf
++ = ((char*)cc
)[0];
1033 *buf
++ = ((char*)cc
)[3];
1034 *buf
++ = ((char*)cc
)[2];
1038 len
+= pa
*sizeof(wxUint16
);
1041 if (buf
&& len
<=n
-sizeof(wxUint16
)) *(wxUint16
*)buf
=0;
1049 // ----------------------------------------------------------------------------
1051 // ----------------------------------------------------------------------------
1053 #ifdef WORDS_BIGENDIAN
1054 #define wxMBConvUTF32straight wxMBConvUTF32BE
1055 #define wxMBConvUTF32swap wxMBConvUTF32LE
1057 #define wxMBConvUTF32swap wxMBConvUTF32BE
1058 #define wxMBConvUTF32straight wxMBConvUTF32LE
1062 WXDLLIMPEXP_DATA_BASE(wxMBConvUTF32LE
) wxConvUTF32LE
;
1063 WXDLLIMPEXP_DATA_BASE(wxMBConvUTF32BE
) wxConvUTF32BE
;
1068 // copy 32bit MB to 16bit String
1069 size_t wxMBConvUTF32straight::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
1073 while (*(wxUint32
*)psz
&& (!buf
|| len
< n
))
1077 size_t pa
=encode_utf16(*(wxUint32
*)psz
, cc
);
1078 if (pa
== (size_t)-1)
1088 psz
+= sizeof(wxUint32
);
1090 if (buf
&& len
<n
) *buf
=0;
1096 // copy 16bit String to 32bit MB
1097 size_t wxMBConvUTF32straight::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
1101 while (*psz
&& (!buf
|| len
< n
))
1105 // cast is ok for WC_UTF16
1106 size_t pa
= decode_utf16((const wxUint16
*)psz
, cc
);
1107 if (pa
== (size_t)-1)
1112 *(wxUint32
*)buf
= cc
;
1113 buf
+= sizeof(wxUint32
);
1115 len
+= sizeof(wxUint32
);
1119 if (buf
&& len
<=n
-sizeof(wxUint32
))
1127 // swap 32bit MB to 16bit String
1128 size_t wxMBConvUTF32swap::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
1132 while (*(wxUint32
*)psz
&& (!buf
|| len
< n
))
1135 tmp
[0] = psz
[3]; tmp
[1] = psz
[2];
1136 tmp
[2] = psz
[1]; tmp
[3] = psz
[0];
1141 size_t pa
=encode_utf16(*(wxUint32
*)tmp
, cc
);
1142 if (pa
== (size_t)-1)
1152 psz
+= sizeof(wxUint32
);
1162 // swap 16bit String to 32bit MB
1163 size_t wxMBConvUTF32swap::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
1167 while (*psz
&& (!buf
|| len
< n
))
1171 // cast is ok for WC_UTF16
1172 size_t pa
=decode_utf16((const wxUint16
*)psz
, *(wxUint32
*)cc
);
1173 if (pa
== (size_t)-1)
1183 len
+= sizeof(wxUint32
);
1187 if (buf
&& len
<=n
-sizeof(wxUint32
))
1196 // copy 32bit MB to 32bit String
1197 size_t wxMBConvUTF32straight::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
1201 while (*(wxUint32
*)psz
&& (!buf
|| len
< n
))
1204 *buf
++ = (wchar_t)(*(wxUint32
*)psz
);
1206 psz
+= sizeof(wxUint32
);
1216 // copy 32bit String to 32bit MB
1217 size_t wxMBConvUTF32straight::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
1221 while (*psz
&& (!buf
|| len
< n
))
1225 *(wxUint32
*)buf
= *psz
;
1226 buf
+= sizeof(wxUint32
);
1229 len
+= sizeof(wxUint32
);
1233 if (buf
&& len
<=n
-sizeof(wxUint32
))
1240 // swap 32bit MB to 32bit String
1241 size_t wxMBConvUTF32swap::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
1245 while (*(wxUint32
*)psz
&& (!buf
|| len
< n
))
1249 ((char *)buf
)[0] = psz
[3];
1250 ((char *)buf
)[1] = psz
[2];
1251 ((char *)buf
)[2] = psz
[1];
1252 ((char *)buf
)[3] = psz
[0];
1256 psz
+= sizeof(wxUint32
);
1266 // swap 32bit String to 32bit MB
1267 size_t wxMBConvUTF32swap::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
1271 while (*psz
&& (!buf
|| len
< n
))
1275 *buf
++ = ((char *)psz
)[3];
1276 *buf
++ = ((char *)psz
)[2];
1277 *buf
++ = ((char *)psz
)[1];
1278 *buf
++ = ((char *)psz
)[0];
1280 len
+= sizeof(wxUint32
);
1284 if (buf
&& len
<=n
-sizeof(wxUint32
))
1294 // ============================================================================
1295 // The classes doing conversion using the iconv_xxx() functions
1296 // ============================================================================
1300 // VS: glibc 2.1.3 is broken in that iconv() conversion to/from UCS4 fails with
1301 // E2BIG if output buffer is _exactly_ as big as needed. Such case is
1302 // (unless there's yet another bug in glibc) the only case when iconv()
1303 // returns with (size_t)-1 (which means error) and says there are 0 bytes
1304 // left in the input buffer -- when _real_ error occurs,
1305 // bytes-left-in-input buffer is non-zero. Hence, this alternative test for
1307 // [This bug does not appear in glibc 2.2.]
1308 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ <= 1
1309 #define ICONV_FAILED(cres, bufLeft) ((cres == (size_t)-1) && \
1310 (errno != E2BIG || bufLeft != 0))
1312 #define ICONV_FAILED(cres, bufLeft) (cres == (size_t)-1)
1315 #define ICONV_CHAR_CAST(x) ((ICONV_CONST char **)(x))
1317 #define ICONV_T_INVALID ((iconv_t)-1)
1319 #if SIZEOF_WCHAR_T == 4
1320 #define WC_BSWAP wxUINT32_SWAP_ALWAYS
1321 #define WC_ENC wxFONTENCODING_UTF32
1322 #elif SIZEOF_WCHAR_T == 2
1323 #define WC_BSWAP wxUINT16_SWAP_ALWAYS
1324 #define WC_ENC wxFONTENCODING_UTF16
1325 #else // sizeof(wchar_t) != 2 nor 4
1326 // does this ever happen?
1327 #error "Unknown sizeof(wchar_t): please report this to wx-dev@lists.wxwindows.org"
1330 // ----------------------------------------------------------------------------
1331 // wxMBConv_iconv: encapsulates an iconv character set
1332 // ----------------------------------------------------------------------------
1334 class wxMBConv_iconv
: public wxMBConv
1337 wxMBConv_iconv(const wxChar
*name
);
1338 virtual ~wxMBConv_iconv();
1340 virtual size_t MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const;
1341 virtual size_t WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const;
1344 { return (m2w
!= ICONV_T_INVALID
) && (w2m
!= ICONV_T_INVALID
); }
1347 // the iconv handlers used to translate from multibyte to wide char and in
1348 // the other direction
1352 // guards access to m2w and w2m objects
1353 wxMutex m_iconvMutex
;
1357 virtual const char *GetMBNul(size_t *nulLen
) const;
1359 // the name (for iconv_open()) of a wide char charset -- if none is
1360 // available on this machine, it will remain NULL
1361 static wxString ms_wcCharsetName
;
1363 // true if the wide char encoding we use (i.e. ms_wcCharsetName) has
1364 // different endian-ness than the native one
1365 static bool ms_wcNeedsSwap
;
1367 // NUL representation
1372 // make the constructor available for unit testing
1373 WXDLLIMPEXP_BASE wxMBConv
* new_wxMBConv_iconv( const wxChar
* name
)
1375 wxMBConv_iconv
* result
= new wxMBConv_iconv( name
);
1376 if ( !result
->IsOk() )
1384 wxString
wxMBConv_iconv::ms_wcCharsetName
;
1385 bool wxMBConv_iconv::ms_wcNeedsSwap
= false;
1387 wxMBConv_iconv::wxMBConv_iconv(const wxChar
*name
)
1389 m_nulLen
= (size_t)-2;
1391 // iconv operates with chars, not wxChars, but luckily it uses only ASCII
1392 // names for the charsets
1393 const wxCharBuffer
cname(wxString(name
).ToAscii());
1395 // check for charset that represents wchar_t:
1396 if ( ms_wcCharsetName
.empty() )
1398 wxLogTrace(TRACE_STRCONV
, _T("Looking for wide char codeset:"));
1401 const wxChar
**names
= wxFontMapperBase::GetAllEncodingNames(WC_ENC
);
1402 #else // !wxUSE_FONTMAP
1403 static const wxChar
*names
[] =
1405 #if SIZEOF_WCHAR_T == 4
1407 #elif SIZEOF_WCHAR_T = 2
1412 #endif // wxUSE_FONTMAP/!wxUSE_FONTMAP
1414 for ( ; *names
&& ms_wcCharsetName
.empty(); ++names
)
1416 const wxString
nameCS(*names
);
1418 // first try charset with explicit bytesex info (e.g. "UCS-4LE"):
1419 wxString
nameXE(nameCS
);
1420 #ifdef WORDS_BIGENDIAN
1422 #else // little endian
1426 wxLogTrace(TRACE_STRCONV
, _T(" trying charset \"%s\""),
1429 m2w
= iconv_open(nameXE
.ToAscii(), cname
);
1430 if ( m2w
== ICONV_T_INVALID
)
1432 // try charset w/o bytesex info (e.g. "UCS4")
1433 wxLogTrace(TRACE_STRCONV
, _T(" trying charset \"%s\""),
1435 m2w
= iconv_open(nameCS
.ToAscii(), cname
);
1437 // and check for bytesex ourselves:
1438 if ( m2w
!= ICONV_T_INVALID
)
1440 char buf
[2], *bufPtr
;
1441 wchar_t wbuf
[2], *wbufPtr
;
1449 outsz
= SIZEOF_WCHAR_T
* 2;
1453 res
= iconv(m2w
, ICONV_CHAR_CAST(&bufPtr
), &insz
,
1454 (char**)&wbufPtr
, &outsz
);
1456 if (ICONV_FAILED(res
, insz
))
1458 wxLogLastError(wxT("iconv"));
1459 wxLogError(_("Conversion to charset '%s' doesn't work."),
1462 else // ok, can convert to this encoding, remember it
1464 ms_wcCharsetName
= nameCS
;
1465 ms_wcNeedsSwap
= wbuf
[0] != (wchar_t)buf
[0];
1469 else // use charset not requiring byte swapping
1471 ms_wcCharsetName
= nameXE
;
1475 wxLogTrace(TRACE_STRCONV
,
1476 wxT("iconv wchar_t charset is \"%s\"%s"),
1477 ms_wcCharsetName
.empty() ? _T("<none>")
1478 : ms_wcCharsetName
.c_str(),
1479 ms_wcNeedsSwap
? _T(" (needs swap)")
1482 else // we already have ms_wcCharsetName
1484 m2w
= iconv_open(ms_wcCharsetName
.ToAscii(), cname
);
1487 if ( ms_wcCharsetName
.empty() )
1489 w2m
= ICONV_T_INVALID
;
1493 w2m
= iconv_open(cname
, ms_wcCharsetName
.ToAscii());
1494 if ( w2m
== ICONV_T_INVALID
)
1496 wxLogTrace(TRACE_STRCONV
,
1497 wxT("\"%s\" -> \"%s\" works but not the converse!?"),
1498 ms_wcCharsetName
.c_str(), cname
.data());
1503 wxMBConv_iconv::~wxMBConv_iconv()
1505 if ( m2w
!= ICONV_T_INVALID
)
1507 if ( w2m
!= ICONV_T_INVALID
)
1511 size_t wxMBConv_iconv::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
1514 // NB: iconv() is MT-safe, but each thread must use it's own iconv_t handle.
1515 // Unfortunately there is a couple of global wxCSConv objects such as
1516 // wxConvLocal that are used all over wx code, so we have to make sure
1517 // the handle is used by at most one thread at the time. Otherwise
1518 // only a few wx classes would be safe to use from non-main threads
1519 // as MB<->WC conversion would fail "randomly".
1520 wxMutexLocker
lock(wxConstCast(this, wxMBConv_iconv
)->m_iconvMutex
);
1523 size_t inbuf
= strlen(psz
);
1524 size_t outbuf
= n
* SIZEOF_WCHAR_T
;
1526 // VS: Use these instead of psz, buf because iconv() modifies its arguments:
1527 wchar_t *bufPtr
= buf
;
1528 const char *pszPtr
= psz
;
1532 // have destination buffer, convert there
1534 ICONV_CHAR_CAST(&pszPtr
), &inbuf
,
1535 (char**)&bufPtr
, &outbuf
);
1536 res
= n
- (outbuf
/ SIZEOF_WCHAR_T
);
1540 // convert to native endianness
1541 for ( unsigned i
= 0; i
< res
; i
++ )
1542 buf
[n
] = WC_BSWAP(buf
[i
]);
1545 // NB: iconv was given only strlen(psz) characters on input, and so
1546 // it couldn't convert the trailing zero. Let's do it ourselves
1547 // if there's some room left for it in the output buffer.
1553 // no destination buffer... convert using temp buffer
1554 // to calculate destination buffer requirement
1559 outbuf
= 8*SIZEOF_WCHAR_T
;
1562 ICONV_CHAR_CAST(&pszPtr
), &inbuf
,
1563 (char**)&bufPtr
, &outbuf
);
1565 res
+= 8-(outbuf
/SIZEOF_WCHAR_T
);
1566 } while ((cres
==(size_t)-1) && (errno
==E2BIG
));
1569 if (ICONV_FAILED(cres
, inbuf
))
1571 //VS: it is ok if iconv fails, hence trace only
1572 wxLogTrace(TRACE_STRCONV
, wxT("iconv failed: %s"), wxSysErrorMsg(wxSysErrorCode()));
1579 size_t wxMBConv_iconv::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
1582 // NB: explained in MB2WC
1583 wxMutexLocker
lock(wxConstCast(this, wxMBConv_iconv
)->m_iconvMutex
);
1586 size_t inlen
= wxWcslen(psz
);
1587 size_t inbuf
= inlen
* SIZEOF_WCHAR_T
;
1591 wchar_t *tmpbuf
= 0;
1595 // need to copy to temp buffer to switch endianness
1596 // (doing WC_BSWAP twice on the original buffer won't help, as it
1597 // could be in read-only memory, or be accessed in some other thread)
1598 tmpbuf
= (wchar_t *)malloc(inbuf
+ SIZEOF_WCHAR_T
);
1599 for ( size_t i
= 0; i
< inlen
; i
++ )
1600 tmpbuf
[n
] = WC_BSWAP(psz
[i
]);
1601 tmpbuf
[inlen
] = L
'\0';
1607 // have destination buffer, convert there
1608 cres
= iconv( w2m
, ICONV_CHAR_CAST(&psz
), &inbuf
, &buf
, &outbuf
);
1612 // NB: iconv was given only wcslen(psz) characters on input, and so
1613 // it couldn't convert the trailing zero. Let's do it ourselves
1614 // if there's some room left for it in the output buffer.
1620 // no destination buffer... convert using temp buffer
1621 // to calculate destination buffer requirement
1625 buf
= tbuf
; outbuf
= 16;
1627 cres
= iconv( w2m
, ICONV_CHAR_CAST(&psz
), &inbuf
, &buf
, &outbuf
);
1630 } while ((cres
==(size_t)-1) && (errno
==E2BIG
));
1638 if (ICONV_FAILED(cres
, inbuf
))
1640 wxLogTrace(TRACE_STRCONV
, wxT("iconv failed: %s"), wxSysErrorMsg(wxSysErrorCode()));
1647 const char *wxMBConv_iconv::GetMBNul(size_t *nulLen
) const
1649 if ( m_nulLen
== (size_t)-2 )
1651 wxMBConv_iconv
* const self
= wxConstCast(this, wxMBConv_iconv
);
1654 // NB: explained in MB2WC
1655 wxMutexLocker
lock(self
->m_iconvMutex
);
1659 outLen
= WXSIZEOF(m_nulBuf
);
1660 self
->m_nulLen
= iconv(w2m
, ICONV_CHAR_CAST(L
""), &inLen
,
1661 &self
->m_nulBuf
, &outLen
);
1668 #endif // HAVE_ICONV
1671 // ============================================================================
1672 // Win32 conversion classes
1673 // ============================================================================
1675 #ifdef wxHAVE_WIN32_MB2WC
1679 extern WXDLLIMPEXP_BASE
long wxCharsetToCodepage(const wxChar
*charset
);
1680 extern WXDLLIMPEXP_BASE
long wxEncodingToCodepage(wxFontEncoding encoding
);
1683 class wxMBConv_win32
: public wxMBConv
1688 m_CodePage
= CP_ACP
;
1689 m_nulLen
= (size_t)-2;
1693 wxMBConv_win32(const wxChar
* name
)
1695 m_CodePage
= wxCharsetToCodepage(name
);
1696 m_nulLen
= (size_t)-2;
1699 wxMBConv_win32(wxFontEncoding encoding
)
1701 m_CodePage
= wxEncodingToCodepage(encoding
);
1702 m_nulLen
= (size_t)-2;
1704 #endif // wxUSE_FONTMAP
1706 size_t MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
1708 // note that we have to use MB_ERR_INVALID_CHARS flag as it without it
1709 // the behaviour is not compatible with the Unix version (using iconv)
1710 // and break the library itself, e.g. wxTextInputStream::NextChar()
1711 // wouldn't work if reading an incomplete MB char didn't result in an
1714 // note however that using MB_ERR_INVALID_CHARS with CP_UTF7 results in
1715 // an error (tested under Windows Server 2003) and apparently it is
1716 // done on purpose, i.e. the function accepts any input in this case
1717 // and although I'd prefer to return error on ill-formed output, our
1718 // own wxMBConvUTF7 doesn't detect errors (e.g. lone "+" which is
1719 // explicitly ill-formed according to RFC 2152) neither so we don't
1720 // even have any fallback here...
1722 // Moreover, MB_ERR_INVALID_CHARS is only supported on Win 2K SP4 or
1723 // Win XP or newer and if it is specified on older versions, conversion
1724 // from CP_UTF8 (which can have flags only 0 or MB_ERR_INVALID_CHARS)
1725 // fails. So we can only use the flag on newer Windows versions.
1726 // Additionally, the flag is not supported by UTF7, symbol and CJK
1727 // encodings. See here:
1728 // http://blogs.msdn.com/michkap/archive/2005/04/19/409566.aspx
1729 // http://msdn.microsoft.com/library/en-us/intl/unicode_17si.asp
1731 if ( m_CodePage
!= CP_UTF7
&& m_CodePage
!= CP_SYMBOL
&&
1732 m_CodePage
< 50000 &&
1733 IsAtLeastWin2kSP4() )
1735 flags
= MB_ERR_INVALID_CHARS
;
1737 else if ( m_CodePage
== CP_UTF8
)
1739 // Avoid round-trip in the special case of UTF-8 by using our
1740 // own UTF-8 conversion code:
1741 return wxMBConvUTF8().MB2WC(buf
, psz
, n
);
1744 const size_t len
= ::MultiByteToWideChar
1746 m_CodePage
, // code page
1747 flags
, // flags: fall on error
1748 psz
, // input string
1749 -1, // its length (NUL-terminated)
1750 buf
, // output string
1751 buf
? n
: 0 // size of output buffer
1755 // function totally failed
1759 // if we were really converting and didn't use MB_ERR_INVALID_CHARS,
1760 // check if we succeeded, by doing a double trip:
1761 if ( !flags
&& buf
)
1763 const size_t mbLen
= strlen(psz
);
1764 wxCharBuffer
mbBuf(mbLen
);
1765 if ( ::WideCharToMultiByte
1772 mbLen
+ 1, // size in bytes, not length
1776 strcmp(mbBuf
, psz
) != 0 )
1778 // we didn't obtain the same thing we started from, hence
1779 // the conversion was lossy and we consider that it failed
1784 // note that it returns count of written chars for buf != NULL and size
1785 // of the needed buffer for buf == NULL so in either case the length of
1786 // the string (which never includes the terminating NUL) is one less
1790 size_t WC2MB(char *buf
, const wchar_t *pwz
, size_t n
) const
1793 we have a problem here: by default, WideCharToMultiByte() may
1794 replace characters unrepresentable in the target code page with bad
1795 quality approximations such as turning "1/2" symbol (U+00BD) into
1796 "1" for the code pages which don't have it and we, obviously, want
1797 to avoid this at any price
1799 the trouble is that this function does it _silently_, i.e. it won't
1800 even tell us whether it did or not... Win98/2000 and higher provide
1801 WC_NO_BEST_FIT_CHARS but it doesn't work for the older systems and
1802 we have to resort to a round trip, i.e. check that converting back
1803 results in the same string -- this is, of course, expensive but
1804 otherwise we simply can't be sure to not garble the data.
1807 // determine if we can rely on WC_NO_BEST_FIT_CHARS: according to MSDN
1808 // it doesn't work with CJK encodings (which we test for rather roughly
1809 // here...) nor with UTF-7/8 nor, of course, with Windows versions not
1811 BOOL usedDef
wxDUMMY_INITIALIZE(false);
1814 if ( CanUseNoBestFit() && m_CodePage
< 50000 )
1816 // it's our lucky day
1817 flags
= WC_NO_BEST_FIT_CHARS
;
1818 pUsedDef
= &usedDef
;
1820 else // old system or unsupported encoding
1826 const size_t len
= ::WideCharToMultiByte
1828 m_CodePage
, // code page
1829 flags
, // either none or no best fit
1830 pwz
, // input string
1831 -1, // it is (wide) NUL-terminated
1832 buf
, // output buffer
1833 buf
? n
: 0, // and its size
1834 NULL
, // default "replacement" char
1835 pUsedDef
// [out] was it used?
1840 // function totally failed
1844 // if we were really converting, check if we succeeded
1849 // check if the conversion failed, i.e. if any replacements
1854 else // we must resort to double tripping...
1856 wxWCharBuffer
wcBuf(n
);
1857 if ( MB2WC(wcBuf
.data(), buf
, n
) == (size_t)-1 ||
1858 wcscmp(wcBuf
, pwz
) != 0 )
1860 // we didn't obtain the same thing we started from, hence
1861 // the conversion was lossy and we consider that it failed
1867 // see the comment above for the reason of "len - 1"
1871 bool IsOk() const { return m_CodePage
!= -1; }
1874 static bool CanUseNoBestFit()
1876 static int s_isWin98Or2k
= -1;
1878 if ( s_isWin98Or2k
== -1 )
1881 switch ( wxGetOsVersion(&verMaj
, &verMin
) )
1884 s_isWin98Or2k
= verMaj
>= 4 && verMin
>= 10;
1888 s_isWin98Or2k
= verMaj
>= 5;
1892 // unknown, be conseravtive by default
1896 wxASSERT_MSG( s_isWin98Or2k
!= -1, _T("should be set above") );
1899 return s_isWin98Or2k
== 1;
1902 static bool IsAtLeastWin2kSP4()
1907 static int s_isAtLeastWin2kSP4
= -1;
1909 if ( s_isAtLeastWin2kSP4
== -1 )
1911 OSVERSIONINFOEX ver
;
1913 memset(&ver
, 0, sizeof(ver
));
1914 ver
.dwOSVersionInfoSize
= sizeof(ver
);
1915 GetVersionEx((OSVERSIONINFO
*)&ver
);
1917 s_isAtLeastWin2kSP4
=
1918 ((ver
.dwMajorVersion
> 5) || // Vista+
1919 (ver
.dwMajorVersion
== 5 && ver
.dwMinorVersion
> 0) || // XP/2003
1920 (ver
.dwMajorVersion
== 5 && ver
.dwMinorVersion
== 0 &&
1921 ver
.wServicePackMajor
>= 4)) // 2000 SP4+
1925 return s_isAtLeastWin2kSP4
== 1;
1929 virtual const char *GetMBNul(size_t *nulLen
) const
1931 if ( m_nulLen
== (size_t)-2 )
1933 wxMBConv_win32
* const self
= wxConstCast(this, wxMBConv_win32
);
1935 self
->m_nulLen
= ::WideCharToMultiByte
1937 m_CodePage
, // code page
1939 L
"", // input string
1940 1, // translate just NUL
1941 self
->m_nulBuf
, // output buffer
1942 WXSIZEOF(m_nulBuf
), // and its size
1943 NULL
, // "replacement" char
1944 NULL
// [out] was it used?
1947 if ( m_nulLen
== 0 )
1948 self
->m_nulLen
= (size_t)-1;
1960 #endif // wxHAVE_WIN32_MB2WC
1962 // ============================================================================
1963 // Cocoa conversion classes
1964 // ============================================================================
1966 #if defined(__WXCOCOA__)
1968 // RN: There is no UTF-32 support in either Core Foundation or
1969 // Cocoa. Strangely enough, internally Core Foundation uses
1970 // UTF 32 internally quite a bit - its just not public (yet).
1972 #include <CoreFoundation/CFString.h>
1973 #include <CoreFoundation/CFStringEncodingExt.h>
1975 CFStringEncoding
wxCFStringEncFromFontEnc(wxFontEncoding encoding
)
1977 CFStringEncoding enc
= kCFStringEncodingInvalidId
;
1978 if ( encoding
== wxFONTENCODING_DEFAULT
)
1980 enc
= CFStringGetSystemEncoding();
1982 else switch( encoding
)
1984 case wxFONTENCODING_ISO8859_1
:
1985 enc
= kCFStringEncodingISOLatin1
;
1987 case wxFONTENCODING_ISO8859_2
:
1988 enc
= kCFStringEncodingISOLatin2
;
1990 case wxFONTENCODING_ISO8859_3
:
1991 enc
= kCFStringEncodingISOLatin3
;
1993 case wxFONTENCODING_ISO8859_4
:
1994 enc
= kCFStringEncodingISOLatin4
;
1996 case wxFONTENCODING_ISO8859_5
:
1997 enc
= kCFStringEncodingISOLatinCyrillic
;
1999 case wxFONTENCODING_ISO8859_6
:
2000 enc
= kCFStringEncodingISOLatinArabic
;
2002 case wxFONTENCODING_ISO8859_7
:
2003 enc
= kCFStringEncodingISOLatinGreek
;
2005 case wxFONTENCODING_ISO8859_8
:
2006 enc
= kCFStringEncodingISOLatinHebrew
;
2008 case wxFONTENCODING_ISO8859_9
:
2009 enc
= kCFStringEncodingISOLatin5
;
2011 case wxFONTENCODING_ISO8859_10
:
2012 enc
= kCFStringEncodingISOLatin6
;
2014 case wxFONTENCODING_ISO8859_11
:
2015 enc
= kCFStringEncodingISOLatinThai
;
2017 case wxFONTENCODING_ISO8859_13
:
2018 enc
= kCFStringEncodingISOLatin7
;
2020 case wxFONTENCODING_ISO8859_14
:
2021 enc
= kCFStringEncodingISOLatin8
;
2023 case wxFONTENCODING_ISO8859_15
:
2024 enc
= kCFStringEncodingISOLatin9
;
2027 case wxFONTENCODING_KOI8
:
2028 enc
= kCFStringEncodingKOI8_R
;
2030 case wxFONTENCODING_ALTERNATIVE
: // MS-DOS CP866
2031 enc
= kCFStringEncodingDOSRussian
;
2034 // case wxFONTENCODING_BULGARIAN :
2038 case wxFONTENCODING_CP437
:
2039 enc
=kCFStringEncodingDOSLatinUS
;
2041 case wxFONTENCODING_CP850
:
2042 enc
= kCFStringEncodingDOSLatin1
;
2044 case wxFONTENCODING_CP852
:
2045 enc
= kCFStringEncodingDOSLatin2
;
2047 case wxFONTENCODING_CP855
:
2048 enc
= kCFStringEncodingDOSCyrillic
;
2050 case wxFONTENCODING_CP866
:
2051 enc
=kCFStringEncodingDOSRussian
;
2053 case wxFONTENCODING_CP874
:
2054 enc
= kCFStringEncodingDOSThai
;
2056 case wxFONTENCODING_CP932
:
2057 enc
= kCFStringEncodingDOSJapanese
;
2059 case wxFONTENCODING_CP936
:
2060 enc
=kCFStringEncodingDOSChineseSimplif
;
2062 case wxFONTENCODING_CP949
:
2063 enc
= kCFStringEncodingDOSKorean
;
2065 case wxFONTENCODING_CP950
:
2066 enc
= kCFStringEncodingDOSChineseTrad
;
2068 case wxFONTENCODING_CP1250
:
2069 enc
= kCFStringEncodingWindowsLatin2
;
2071 case wxFONTENCODING_CP1251
:
2072 enc
=kCFStringEncodingWindowsCyrillic
;
2074 case wxFONTENCODING_CP1252
:
2075 enc
=kCFStringEncodingWindowsLatin1
;
2077 case wxFONTENCODING_CP1253
:
2078 enc
= kCFStringEncodingWindowsGreek
;
2080 case wxFONTENCODING_CP1254
:
2081 enc
= kCFStringEncodingWindowsLatin5
;
2083 case wxFONTENCODING_CP1255
:
2084 enc
=kCFStringEncodingWindowsHebrew
;
2086 case wxFONTENCODING_CP1256
:
2087 enc
=kCFStringEncodingWindowsArabic
;
2089 case wxFONTENCODING_CP1257
:
2090 enc
= kCFStringEncodingWindowsBalticRim
;
2092 // This only really encodes to UTF7 (if that) evidently
2093 // case wxFONTENCODING_UTF7 :
2094 // enc = kCFStringEncodingNonLossyASCII ;
2096 case wxFONTENCODING_UTF8
:
2097 enc
= kCFStringEncodingUTF8
;
2099 case wxFONTENCODING_EUC_JP
:
2100 enc
= kCFStringEncodingEUC_JP
;
2102 case wxFONTENCODING_UTF16
:
2103 enc
= kCFStringEncodingUnicode
;
2105 case wxFONTENCODING_MACROMAN
:
2106 enc
= kCFStringEncodingMacRoman
;
2108 case wxFONTENCODING_MACJAPANESE
:
2109 enc
= kCFStringEncodingMacJapanese
;
2111 case wxFONTENCODING_MACCHINESETRAD
:
2112 enc
= kCFStringEncodingMacChineseTrad
;
2114 case wxFONTENCODING_MACKOREAN
:
2115 enc
= kCFStringEncodingMacKorean
;
2117 case wxFONTENCODING_MACARABIC
:
2118 enc
= kCFStringEncodingMacArabic
;
2120 case wxFONTENCODING_MACHEBREW
:
2121 enc
= kCFStringEncodingMacHebrew
;
2123 case wxFONTENCODING_MACGREEK
:
2124 enc
= kCFStringEncodingMacGreek
;
2126 case wxFONTENCODING_MACCYRILLIC
:
2127 enc
= kCFStringEncodingMacCyrillic
;
2129 case wxFONTENCODING_MACDEVANAGARI
:
2130 enc
= kCFStringEncodingMacDevanagari
;
2132 case wxFONTENCODING_MACGURMUKHI
:
2133 enc
= kCFStringEncodingMacGurmukhi
;
2135 case wxFONTENCODING_MACGUJARATI
:
2136 enc
= kCFStringEncodingMacGujarati
;
2138 case wxFONTENCODING_MACORIYA
:
2139 enc
= kCFStringEncodingMacOriya
;
2141 case wxFONTENCODING_MACBENGALI
:
2142 enc
= kCFStringEncodingMacBengali
;
2144 case wxFONTENCODING_MACTAMIL
:
2145 enc
= kCFStringEncodingMacTamil
;
2147 case wxFONTENCODING_MACTELUGU
:
2148 enc
= kCFStringEncodingMacTelugu
;
2150 case wxFONTENCODING_MACKANNADA
:
2151 enc
= kCFStringEncodingMacKannada
;
2153 case wxFONTENCODING_MACMALAJALAM
:
2154 enc
= kCFStringEncodingMacMalayalam
;
2156 case wxFONTENCODING_MACSINHALESE
:
2157 enc
= kCFStringEncodingMacSinhalese
;
2159 case wxFONTENCODING_MACBURMESE
:
2160 enc
= kCFStringEncodingMacBurmese
;
2162 case wxFONTENCODING_MACKHMER
:
2163 enc
= kCFStringEncodingMacKhmer
;
2165 case wxFONTENCODING_MACTHAI
:
2166 enc
= kCFStringEncodingMacThai
;
2168 case wxFONTENCODING_MACLAOTIAN
:
2169 enc
= kCFStringEncodingMacLaotian
;
2171 case wxFONTENCODING_MACGEORGIAN
:
2172 enc
= kCFStringEncodingMacGeorgian
;
2174 case wxFONTENCODING_MACARMENIAN
:
2175 enc
= kCFStringEncodingMacArmenian
;
2177 case wxFONTENCODING_MACCHINESESIMP
:
2178 enc
= kCFStringEncodingMacChineseSimp
;
2180 case wxFONTENCODING_MACTIBETAN
:
2181 enc
= kCFStringEncodingMacTibetan
;
2183 case wxFONTENCODING_MACMONGOLIAN
:
2184 enc
= kCFStringEncodingMacMongolian
;
2186 case wxFONTENCODING_MACETHIOPIC
:
2187 enc
= kCFStringEncodingMacEthiopic
;
2189 case wxFONTENCODING_MACCENTRALEUR
:
2190 enc
= kCFStringEncodingMacCentralEurRoman
;
2192 case wxFONTENCODING_MACVIATNAMESE
:
2193 enc
= kCFStringEncodingMacVietnamese
;
2195 case wxFONTENCODING_MACARABICEXT
:
2196 enc
= kCFStringEncodingMacExtArabic
;
2198 case wxFONTENCODING_MACSYMBOL
:
2199 enc
= kCFStringEncodingMacSymbol
;
2201 case wxFONTENCODING_MACDINGBATS
:
2202 enc
= kCFStringEncodingMacDingbats
;
2204 case wxFONTENCODING_MACTURKISH
:
2205 enc
= kCFStringEncodingMacTurkish
;
2207 case wxFONTENCODING_MACCROATIAN
:
2208 enc
= kCFStringEncodingMacCroatian
;
2210 case wxFONTENCODING_MACICELANDIC
:
2211 enc
= kCFStringEncodingMacIcelandic
;
2213 case wxFONTENCODING_MACROMANIAN
:
2214 enc
= kCFStringEncodingMacRomanian
;
2216 case wxFONTENCODING_MACCELTIC
:
2217 enc
= kCFStringEncodingMacCeltic
;
2219 case wxFONTENCODING_MACGAELIC
:
2220 enc
= kCFStringEncodingMacGaelic
;
2222 // case wxFONTENCODING_MACKEYBOARD :
2223 // enc = kCFStringEncodingMacKeyboardGlyphs ;
2226 // because gcc is picky
2232 class wxMBConv_cocoa
: public wxMBConv
2237 Init(CFStringGetSystemEncoding()) ;
2241 wxMBConv_cocoa(const wxChar
* name
)
2243 Init( wxCFStringEncFromFontEnc(wxFontMapperBase::Get()->CharsetToEncoding(name
, false) ) ) ;
2247 wxMBConv_cocoa(wxFontEncoding encoding
)
2249 Init( wxCFStringEncFromFontEnc(encoding
) );
2256 void Init( CFStringEncoding encoding
)
2258 m_encoding
= encoding
;
2261 size_t MB2WC(wchar_t * szOut
, const char * szUnConv
, size_t nOutSize
) const
2265 CFStringRef theString
= CFStringCreateWithBytes (
2266 NULL
, //the allocator
2267 (const UInt8
*)szUnConv
,
2270 false //no BOM/external representation
2273 wxASSERT(theString
);
2275 size_t nOutLength
= CFStringGetLength(theString
);
2279 CFRelease(theString
);
2283 CFRange theRange
= { 0, nOutSize
};
2285 #if SIZEOF_WCHAR_T == 4
2286 UniChar
* szUniCharBuffer
= new UniChar
[nOutSize
];
2289 CFStringGetCharacters(theString
, theRange
, szUniCharBuffer
);
2291 CFRelease(theString
);
2293 szUniCharBuffer
[nOutLength
] = '\0' ;
2295 #if SIZEOF_WCHAR_T == 4
2296 wxMBConvUTF16 converter
;
2297 converter
.MB2WC(szOut
, (const char*)szUniCharBuffer
, nOutSize
) ;
2298 delete[] szUniCharBuffer
;
2304 size_t WC2MB(char *szOut
, const wchar_t *szUnConv
, size_t nOutSize
) const
2308 size_t nRealOutSize
;
2309 size_t nBufSize
= wxWcslen(szUnConv
);
2310 UniChar
* szUniBuffer
= (UniChar
*) szUnConv
;
2312 #if SIZEOF_WCHAR_T == 4
2313 wxMBConvUTF16 converter
;
2314 nBufSize
= converter
.WC2MB( NULL
, szUnConv
, 0 );
2315 szUniBuffer
= new UniChar
[ (nBufSize
/ sizeof(UniChar
)) + 1] ;
2316 converter
.WC2MB( (char*) szUniBuffer
, szUnConv
, nBufSize
+ sizeof(UniChar
)) ;
2317 nBufSize
/= sizeof(UniChar
);
2320 CFStringRef theString
= CFStringCreateWithCharactersNoCopy(
2324 kCFAllocatorNull
//deallocator - we want to deallocate it ourselves
2327 wxASSERT(theString
);
2329 //Note that CER puts a BOM when converting to unicode
2330 //so we check and use getchars instead in that case
2331 if (m_encoding
== kCFStringEncodingUnicode
)
2334 CFStringGetCharacters(theString
, CFRangeMake(0, nOutSize
- 1), (UniChar
*) szOut
);
2336 nRealOutSize
= CFStringGetLength(theString
) + 1;
2342 CFRangeMake(0, CFStringGetLength(theString
)),
2344 0, //what to put in characters that can't be converted -
2345 //0 tells CFString to return NULL if it meets such a character
2346 false, //not an external representation
2349 (CFIndex
*) &nRealOutSize
2353 CFRelease(theString
);
2355 #if SIZEOF_WCHAR_T == 4
2356 delete[] szUniBuffer
;
2359 return nRealOutSize
- 1;
2364 return m_encoding
!= kCFStringEncodingInvalidId
&&
2365 CFStringIsEncodingAvailable(m_encoding
);
2369 CFStringEncoding m_encoding
;
2372 #endif // defined(__WXCOCOA__)
2374 // ============================================================================
2375 // Mac conversion classes
2376 // ============================================================================
2378 #if defined(__WXMAC__) && defined(TARGET_CARBON)
2380 class wxMBConv_mac
: public wxMBConv
2385 Init(CFStringGetSystemEncoding()) ;
2389 wxMBConv_mac(const wxChar
* name
)
2391 Init( wxMacGetSystemEncFromFontEnc(wxFontMapperBase::Get()->CharsetToEncoding(name
, false) ) ) ;
2395 wxMBConv_mac(wxFontEncoding encoding
)
2397 Init( wxMacGetSystemEncFromFontEnc(encoding
) );
2402 OSStatus status
= noErr
;
2403 status
= TECDisposeConverter(m_MB2WC_converter
);
2404 status
= TECDisposeConverter(m_WC2MB_converter
);
2408 void Init( TextEncodingBase encoding
)
2410 OSStatus status
= noErr
;
2411 m_char_encoding
= encoding
;
2412 m_unicode_encoding
= CreateTextEncoding(kTextEncodingUnicodeDefault
,0,kUnicode16BitFormat
) ;
2414 status
= TECCreateConverter(&m_MB2WC_converter
,
2416 m_unicode_encoding
);
2417 status
= TECCreateConverter(&m_WC2MB_converter
,
2422 size_t MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
2424 OSStatus status
= noErr
;
2425 ByteCount byteOutLen
;
2426 ByteCount byteInLen
= strlen(psz
) ;
2427 wchar_t *tbuf
= NULL
;
2428 UniChar
* ubuf
= NULL
;
2433 //apple specs say at least 32
2434 n
= wxMax( 32 , byteInLen
) ;
2435 tbuf
= (wchar_t*) malloc( n
* SIZEOF_WCHAR_T
) ;
2437 ByteCount byteBufferLen
= n
* sizeof( UniChar
) ;
2438 #if SIZEOF_WCHAR_T == 4
2439 ubuf
= (UniChar
*) malloc( byteBufferLen
+ 2 ) ;
2441 ubuf
= (UniChar
*) (buf
? buf
: tbuf
) ;
2443 status
= TECConvertText(m_MB2WC_converter
, (ConstTextPtr
) psz
, byteInLen
, &byteInLen
,
2444 (TextPtr
) ubuf
, byteBufferLen
, &byteOutLen
);
2445 #if SIZEOF_WCHAR_T == 4
2446 // we have to terminate here, because n might be larger for the trailing zero, and if UniChar
2447 // is not properly terminated we get random characters at the end
2448 ubuf
[byteOutLen
/ sizeof( UniChar
) ] = 0 ;
2449 wxMBConvUTF16 converter
;
2450 res
= converter
.MB2WC( (buf
? buf
: tbuf
) , (const char*)ubuf
, n
) ;
2453 res
= byteOutLen
/ sizeof( UniChar
) ;
2458 if ( buf
&& res
< n
)
2464 size_t WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
2466 OSStatus status
= noErr
;
2467 ByteCount byteOutLen
;
2468 ByteCount byteInLen
= wxWcslen(psz
) * SIZEOF_WCHAR_T
;
2474 //apple specs say at least 32
2475 n
= wxMax( 32 , ((byteInLen
/ SIZEOF_WCHAR_T
) * 8) + SIZEOF_WCHAR_T
);
2476 tbuf
= (char*) malloc( n
) ;
2479 ByteCount byteBufferLen
= n
;
2480 UniChar
* ubuf
= NULL
;
2481 #if SIZEOF_WCHAR_T == 4
2482 wxMBConvUTF16 converter
;
2483 size_t unicharlen
= converter
.WC2MB( NULL
, psz
, 0 ) ;
2484 byteInLen
= unicharlen
;
2485 ubuf
= (UniChar
*) malloc( byteInLen
+ 2 ) ;
2486 converter
.WC2MB( (char*) ubuf
, psz
, unicharlen
+ 2 ) ;
2488 ubuf
= (UniChar
*) psz
;
2490 status
= TECConvertText(m_WC2MB_converter
, (ConstTextPtr
) ubuf
, byteInLen
, &byteInLen
,
2491 (TextPtr
) (buf
? buf
: tbuf
) , byteBufferLen
, &byteOutLen
);
2492 #if SIZEOF_WCHAR_T == 4
2498 size_t res
= byteOutLen
;
2499 if ( buf
&& res
< n
)
2503 //we need to double-trip to verify it didn't insert any ? in place
2504 //of bogus characters
2505 wxWCharBuffer
wcBuf(n
);
2506 size_t pszlen
= wxWcslen(psz
);
2507 if ( MB2WC(wcBuf
.data(), buf
, n
) == (size_t)-1 ||
2508 wxWcslen(wcBuf
) != pszlen
||
2509 memcmp(wcBuf
, psz
, pszlen
* sizeof(wchar_t)) != 0 )
2511 // we didn't obtain the same thing we started from, hence
2512 // the conversion was lossy and we consider that it failed
2521 { return m_MB2WC_converter
!= NULL
&& m_WC2MB_converter
!= NULL
; }
2524 TECObjectRef m_MB2WC_converter
;
2525 TECObjectRef m_WC2MB_converter
;
2527 TextEncodingBase m_char_encoding
;
2528 TextEncodingBase m_unicode_encoding
;
2531 #endif // defined(__WXMAC__) && defined(TARGET_CARBON)
2533 // ============================================================================
2534 // wxEncodingConverter based conversion classes
2535 // ============================================================================
2539 class wxMBConv_wxwin
: public wxMBConv
2544 m_ok
= m2w
.Init(m_enc
, wxFONTENCODING_UNICODE
) &&
2545 w2m
.Init(wxFONTENCODING_UNICODE
, m_enc
);
2549 // temporarily just use wxEncodingConverter stuff,
2550 // so that it works while a better implementation is built
2551 wxMBConv_wxwin(const wxChar
* name
)
2554 m_enc
= wxFontMapperBase::Get()->CharsetToEncoding(name
, false);
2556 m_enc
= wxFONTENCODING_SYSTEM
;
2561 wxMBConv_wxwin(wxFontEncoding enc
)
2568 size_t MB2WC(wchar_t *buf
, const char *psz
, size_t WXUNUSED(n
)) const
2570 size_t inbuf
= strlen(psz
);
2573 if (!m2w
.Convert(psz
,buf
))
2579 size_t WC2MB(char *buf
, const wchar_t *psz
, size_t WXUNUSED(n
)) const
2581 const size_t inbuf
= wxWcslen(psz
);
2584 if (!w2m
.Convert(psz
,buf
))
2591 bool IsOk() const { return m_ok
; }
2594 wxFontEncoding m_enc
;
2595 wxEncodingConverter m2w
, w2m
;
2598 virtual const char *GetMBNul(size_t *nulLen
) const
2602 case wxFONTENCODING_UTF16BE
:
2603 case wxFONTENCODING_UTF16LE
:
2607 case wxFONTENCODING_UTF32BE
:
2608 case wxFONTENCODING_UTF32LE
:
2618 // were we initialized successfully?
2621 DECLARE_NO_COPY_CLASS(wxMBConv_wxwin
)
2624 // make the constructors available for unit testing
2625 WXDLLIMPEXP_BASE wxMBConv
* new_wxMBConv_wxwin( const wxChar
* name
)
2627 wxMBConv_wxwin
* result
= new wxMBConv_wxwin( name
);
2628 if ( !result
->IsOk() )
2636 #endif // wxUSE_FONTMAP
2638 // ============================================================================
2639 // wxCSConv implementation
2640 // ============================================================================
2642 void wxCSConv::Init()
2649 wxCSConv::wxCSConv(const wxChar
*charset
)
2659 m_encoding
= wxFontMapperBase::GetEncodingFromName(charset
);
2661 m_encoding
= wxFONTENCODING_SYSTEM
;
2665 wxCSConv::wxCSConv(wxFontEncoding encoding
)
2667 if ( encoding
== wxFONTENCODING_MAX
|| encoding
== wxFONTENCODING_DEFAULT
)
2669 wxFAIL_MSG( _T("invalid encoding value in wxCSConv ctor") );
2671 encoding
= wxFONTENCODING_SYSTEM
;
2676 m_encoding
= encoding
;
2679 wxCSConv::~wxCSConv()
2684 wxCSConv::wxCSConv(const wxCSConv
& conv
)
2689 SetName(conv
.m_name
);
2690 m_encoding
= conv
.m_encoding
;
2693 wxCSConv
& wxCSConv::operator=(const wxCSConv
& conv
)
2697 SetName(conv
.m_name
);
2698 m_encoding
= conv
.m_encoding
;
2703 void wxCSConv::Clear()
2712 void wxCSConv::SetName(const wxChar
*charset
)
2716 m_name
= wxStrdup(charset
);
2722 #include "wx/hashmap.h"
2724 WX_DECLARE_HASH_MAP( wxFontEncoding
, wxString
, wxIntegerHash
, wxIntegerEqual
,
2725 wxEncodingNameCache
);
2727 static wxEncodingNameCache gs_nameCache
;
2730 wxMBConv
*wxCSConv::DoCreate() const
2733 wxLogTrace(TRACE_STRCONV
,
2734 wxT("creating conversion for %s"),
2736 : wxFontMapperBase::GetEncodingName(m_encoding
).c_str()));
2737 #endif // wxUSE_FONTMAP
2739 // check for the special case of ASCII or ISO8859-1 charset: as we have
2740 // special knowledge of it anyhow, we don't need to create a special
2741 // conversion object
2742 if ( m_encoding
== wxFONTENCODING_ISO8859_1
||
2743 m_encoding
== wxFONTENCODING_DEFAULT
)
2745 // don't convert at all
2749 // we trust OS to do conversion better than we can so try external
2750 // conversion methods first
2752 // the full order is:
2753 // 1. OS conversion (iconv() under Unix or Win32 API)
2754 // 2. hard coded conversions for UTF
2755 // 3. wxEncodingConverter as fall back
2761 #endif // !wxUSE_FONTMAP
2763 wxString
name(m_name
);
2764 wxFontEncoding
encoding(m_encoding
);
2766 if ( !name
.empty() )
2768 wxMBConv_iconv
*conv
= new wxMBConv_iconv(name
);
2776 wxFontMapperBase::Get()->CharsetToEncoding(name
, false);
2777 #endif // wxUSE_FONTMAP
2781 const wxEncodingNameCache::iterator it
= gs_nameCache
.find(encoding
);
2782 if ( it
!= gs_nameCache
.end() )
2784 if ( it
->second
.empty() )
2787 wxMBConv_iconv
*conv
= new wxMBConv_iconv(it
->second
);
2794 const wxChar
** names
= wxFontMapperBase::GetAllEncodingNames(encoding
);
2796 for ( ; *names
; ++names
)
2798 wxMBConv_iconv
*conv
= new wxMBConv_iconv(*names
);
2801 gs_nameCache
[encoding
] = *names
;
2808 gs_nameCache
[encoding
] = _T(""); // cache the failure
2810 #endif // wxUSE_FONTMAP
2812 #endif // HAVE_ICONV
2814 #ifdef wxHAVE_WIN32_MB2WC
2817 wxMBConv_win32
*conv
= m_name
? new wxMBConv_win32(m_name
)
2818 : new wxMBConv_win32(m_encoding
);
2827 #endif // wxHAVE_WIN32_MB2WC
2828 #if defined(__WXMAC__)
2830 // leave UTF16 and UTF32 to the built-ins of wx
2831 if ( m_name
|| ( m_encoding
< wxFONTENCODING_UTF16BE
||
2832 ( m_encoding
>= wxFONTENCODING_MACMIN
&& m_encoding
<= wxFONTENCODING_MACMAX
) ) )
2836 wxMBConv_mac
*conv
= m_name
? new wxMBConv_mac(m_name
)
2837 : new wxMBConv_mac(m_encoding
);
2839 wxMBConv_mac
*conv
= new wxMBConv_mac(m_encoding
);
2848 #if defined(__WXCOCOA__)
2850 if ( m_name
|| ( m_encoding
<= wxFONTENCODING_UTF16
) )
2854 wxMBConv_cocoa
*conv
= m_name
? new wxMBConv_cocoa(m_name
)
2855 : new wxMBConv_cocoa(m_encoding
);
2857 wxMBConv_cocoa
*conv
= new wxMBConv_cocoa(m_encoding
);
2867 wxFontEncoding enc
= m_encoding
;
2869 if ( enc
== wxFONTENCODING_SYSTEM
&& m_name
)
2871 // use "false" to suppress interactive dialogs -- we can be called from
2872 // anywhere and popping up a dialog from here is the last thing we want to
2874 enc
= wxFontMapperBase::Get()->CharsetToEncoding(m_name
, false);
2876 #endif // wxUSE_FONTMAP
2880 case wxFONTENCODING_UTF7
:
2881 return new wxMBConvUTF7
;
2883 case wxFONTENCODING_UTF8
:
2884 return new wxMBConvUTF8
;
2886 case wxFONTENCODING_UTF16BE
:
2887 return new wxMBConvUTF16BE
;
2889 case wxFONTENCODING_UTF16LE
:
2890 return new wxMBConvUTF16LE
;
2892 case wxFONTENCODING_UTF32BE
:
2893 return new wxMBConvUTF32BE
;
2895 case wxFONTENCODING_UTF32LE
:
2896 return new wxMBConvUTF32LE
;
2899 // nothing to do but put here to suppress gcc warnings
2906 wxMBConv_wxwin
*conv
= m_name
? new wxMBConv_wxwin(m_name
)
2907 : new wxMBConv_wxwin(m_encoding
);
2913 #endif // wxUSE_FONTMAP
2915 // NB: This is a hack to prevent deadlock. What could otherwise happen
2916 // in Unicode build: wxConvLocal creation ends up being here
2917 // because of some failure and logs the error. But wxLog will try to
2918 // attach timestamp, for which it will need wxConvLocal (to convert
2919 // time to char* and then wchar_t*), but that fails, tries to log
2920 // error, but wxLog has a (already locked) critical section that
2921 // guards static buffer.
2922 static bool alreadyLoggingError
= false;
2923 if (!alreadyLoggingError
)
2925 alreadyLoggingError
= true;
2926 wxLogError(_("Cannot convert from the charset '%s'!"),
2930 wxFontMapperBase::GetEncodingDescription(m_encoding
).c_str()
2931 #else // !wxUSE_FONTMAP
2932 wxString::Format(_("encoding %s"), m_encoding
).c_str()
2933 #endif // wxUSE_FONTMAP/!wxUSE_FONTMAP
2935 alreadyLoggingError
= false;
2941 void wxCSConv::CreateConvIfNeeded() const
2945 wxCSConv
*self
= (wxCSConv
*)this; // const_cast
2948 // if we don't have neither the name nor the encoding, use the default
2949 // encoding for this system
2950 if ( !m_name
&& m_encoding
== wxFONTENCODING_SYSTEM
)
2952 self
->m_name
= wxStrdup(wxLocale::GetSystemEncodingName());
2954 #endif // wxUSE_INTL
2956 self
->m_convReal
= DoCreate();
2957 self
->m_deferred
= false;
2961 size_t wxCSConv::MB2WC(wchar_t *buf
, const char *psz
, size_t n
) const
2963 CreateConvIfNeeded();
2966 return m_convReal
->MB2WC(buf
, psz
, n
);
2969 size_t len
= strlen(psz
);
2973 for (size_t c
= 0; c
<= len
; c
++)
2974 buf
[c
] = (unsigned char)(psz
[c
]);
2980 size_t wxCSConv::WC2MB(char *buf
, const wchar_t *psz
, size_t n
) const
2982 CreateConvIfNeeded();
2985 return m_convReal
->WC2MB(buf
, psz
, n
);
2988 const size_t len
= wxWcslen(psz
);
2991 for (size_t c
= 0; c
<= len
; c
++)
2995 buf
[c
] = (char)psz
[c
];
3000 for (size_t c
= 0; c
<= len
; c
++)
3010 const char *wxCSConv::GetMBNul(size_t *nulLen
) const
3012 CreateConvIfNeeded();
3016 // cast needed just to call private function of m_convReal
3017 return ((wxCSConv
*)m_convReal
)->GetMBNul(nulLen
);
3024 // ----------------------------------------------------------------------------
3026 // ----------------------------------------------------------------------------
3029 static wxMBConv_win32 wxConvLibcObj
;
3030 #elif defined(__WXMAC__) && !defined(__MACH__)
3031 static wxMBConv_mac wxConvLibcObj
;
3033 static wxMBConvLibc wxConvLibcObj
;
3036 static wxCSConv
wxConvLocalObj(wxFONTENCODING_SYSTEM
);
3037 static wxCSConv
wxConvISO8859_1Obj(wxFONTENCODING_ISO8859_1
);
3038 static wxMBConvUTF7 wxConvUTF7Obj
;
3039 static wxMBConvUTF8 wxConvUTF8Obj
;
3041 WXDLLIMPEXP_DATA_BASE(wxMBConv
&) wxConvLibc
= wxConvLibcObj
;
3042 WXDLLIMPEXP_DATA_BASE(wxCSConv
&) wxConvLocal
= wxConvLocalObj
;
3043 WXDLLIMPEXP_DATA_BASE(wxCSConv
&) wxConvISO8859_1
= wxConvISO8859_1Obj
;
3044 WXDLLIMPEXP_DATA_BASE(wxMBConvUTF7
&) wxConvUTF7
= wxConvUTF7Obj
;
3045 WXDLLIMPEXP_DATA_BASE(wxMBConvUTF8
&) wxConvUTF8
= wxConvUTF8Obj
;
3046 WXDLLIMPEXP_DATA_BASE(wxMBConv
*) wxConvCurrent
= &wxConvLibcObj
;
3047 WXDLLIMPEXP_DATA_BASE(wxMBConv
*) wxConvFileName
= &
3055 #else // !wxUSE_WCHAR_T
3057 // stand-ins in absence of wchar_t
3058 WXDLLIMPEXP_DATA_BASE(wxMBConv
) wxConvLibc
,
3063 #endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T