]> git.saurik.com Git - wxWidgets.git/blame - src/common/strconv.cpp
Cleaner fix.
[wxWidgets.git] / src / common / strconv.cpp
CommitLineData
6001e347
RR
1/////////////////////////////////////////////////////////////////////////////
2// Name: strconv.cpp
3// Purpose: Unicode conversion classes
3a0d76bc 4// Author: Ove Kaaven, Robert Roebling, Vadim Zeitlin, Vaclav Slavik
6001e347
RR
5// Modified by:
6// Created: 29/01/98
7// RCS-ID: $Id$
e95354ec
VZ
8// Copyright: (c) 1999 Ove Kaaven, Robert Roebling, Vaclav Slavik
9// (c) 2000-2003 Vadim Zeitlin
55d99c7a 10// Licence: wxWindows licence
6001e347
RR
11/////////////////////////////////////////////////////////////////////////////
12
f6bcfd97
BP
13// ============================================================================
14// declarations
15// ============================================================================
16
17// ----------------------------------------------------------------------------
18// headers
19// ----------------------------------------------------------------------------
20
14f355c2 21#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
6001e347
RR
22 #pragma implementation "strconv.h"
23#endif
24
25// For compilers that support precompilation, includes "wx.h".
26#include "wx/wxprec.h"
27
28#ifdef __BORLANDC__
29 #pragma hdrstop
30#endif
31
373658eb
VZ
32#ifndef WX_PRECOMP
33 #include "wx/intl.h"
34 #include "wx/log.h"
35#endif // WX_PRECOMP
36
bde4baac
VZ
37#include "wx/strconv.h"
38
39#if wxUSE_WCHAR_T
40
0a1c1e62 41#ifdef __WXMSW__
373658eb 42 #include "wx/msw/private.h"
0a1c1e62
GRG
43#endif
44
1c193821 45#ifndef __WXWINCE__
1cd52418 46#include <errno.h>
1c193821
JS
47#endif
48
6001e347
RR
49#include <ctype.h>
50#include <string.h>
51#include <stdlib.h>
52
e95354ec
VZ
53#if defined(__WIN32__) && !defined(__WXMICROWIN__)
54 #define wxHAVE_WIN32_MB2WC
55#endif // __WIN32__ but !__WXMICROWIN__
56
373658eb
VZ
57// ----------------------------------------------------------------------------
58// headers
59// ----------------------------------------------------------------------------
7af284fd 60
6001e347 61#ifdef __SALFORDC__
373658eb 62 #include <clib.h>
6001e347
RR
63#endif
64
b040e242 65#ifdef HAVE_ICONV
373658eb 66 #include <iconv.h>
1cd52418 67#endif
1cd52418 68
373658eb
VZ
69#include "wx/encconv.h"
70#include "wx/fontmap.h"
71
335d31e0
SC
72#ifdef __WXMAC__
73#include "ATSUnicode.h"
74#include "TextCommon.h"
75#include "TextEncodingConverter.h"
76
77#include "wx/mac/private.h" // includes mac headers
78#endif
373658eb
VZ
79// ----------------------------------------------------------------------------
80// macros
81// ----------------------------------------------------------------------------
3e61dfb0 82
1cd52418 83#define BSWAP_UCS4(str, len) { unsigned _c; for (_c=0; _c<len; _c++) str[_c]=wxUINT32_SWAP_ALWAYS(str[_c]); }
3a0d76bc 84#define BSWAP_UTF16(str, len) { unsigned _c; for (_c=0; _c<len; _c++) str[_c]=wxUINT16_SWAP_ALWAYS(str[_c]); }
1cd52418
OK
85
86#if SIZEOF_WCHAR_T == 4
3a0d76bc
VS
87 #define WC_NAME "UCS4"
88 #define WC_BSWAP BSWAP_UCS4
89 #ifdef WORDS_BIGENDIAN
90 #define WC_NAME_BEST "UCS-4BE"
91 #else
92 #define WC_NAME_BEST "UCS-4LE"
93 #endif
1cd52418 94#elif SIZEOF_WCHAR_T == 2
3a0d76bc
VS
95 #define WC_NAME "UTF16"
96 #define WC_BSWAP BSWAP_UTF16
a3f2769e 97 #define WC_UTF16
3a0d76bc
VS
98 #ifdef WORDS_BIGENDIAN
99 #define WC_NAME_BEST "UTF-16BE"
100 #else
101 #define WC_NAME_BEST "UTF-16LE"
102 #endif
bab1e722 103#else // sizeof(wchar_t) != 2 nor 4
bde4baac
VZ
104 // does this ever happen?
105 #error "Unknown sizeof(wchar_t): please report this to wx-dev@lists.wxwindows.org"
1cd52418
OK
106#endif
107
373658eb
VZ
108// ============================================================================
109// implementation
110// ============================================================================
111
112// ----------------------------------------------------------------------------
c91830cb 113// UTF-16 en/decoding to/from UCS-4
373658eb 114// ----------------------------------------------------------------------------
6001e347 115
b0a6bb75 116
c91830cb 117static size_t encode_utf16(wxUint32 input, wxUint16 *output)
1cd52418 118{
dccce9ea 119 if (input<=0xffff)
4def3b35 120 {
999836aa
VZ
121 if (output)
122 *output = (wxUint16) input;
4def3b35 123 return 1;
dccce9ea
VZ
124 }
125 else if (input>=0x110000)
4def3b35
VS
126 {
127 return (size_t)-1;
dccce9ea
VZ
128 }
129 else
4def3b35 130 {
dccce9ea 131 if (output)
4def3b35 132 {
c91830cb 133 *output++ = (wxUint16) ((input >> 10)+0xd7c0);
999836aa 134 *output = (wxUint16) ((input&0x3ff)+0xdc00);
4def3b35
VS
135 }
136 return 2;
1cd52418 137 }
1cd52418
OK
138}
139
c91830cb 140static size_t decode_utf16(const wxUint16* input, wxUint32& output)
1cd52418 141{
dccce9ea 142 if ((*input<0xd800) || (*input>0xdfff))
4def3b35
VS
143 {
144 output = *input;
145 return 1;
dccce9ea
VZ
146 }
147 else if ((input[1]<0xdc00) || (input[1]>=0xdfff))
4def3b35
VS
148 {
149 output = *input;
150 return (size_t)-1;
dccce9ea
VZ
151 }
152 else
4def3b35
VS
153 {
154 output = ((input[0] - 0xd7c0) << 10) + (input[1] - 0xdc00);
155 return 2;
156 }
1cd52418
OK
157}
158
b0a6bb75 159
f6bcfd97 160// ----------------------------------------------------------------------------
6001e347 161// wxMBConv
f6bcfd97 162// ----------------------------------------------------------------------------
6001e347 163
2b5f62a0
VZ
164wxMBConv::~wxMBConv()
165{
166 // nothing to do here
167}
168
6001e347
RR
169const wxWCharBuffer wxMBConv::cMB2WC(const char *psz) const
170{
2b5f62a0 171 if ( psz )
6001e347 172 {
2b5f62a0
VZ
173 // calculate the length of the buffer needed first
174 size_t nLen = MB2WC(NULL, psz, 0);
175 if ( nLen != (size_t)-1 )
176 {
177 // now do the actual conversion
178 wxWCharBuffer buf(nLen);
179 MB2WC(buf.data(), psz, nLen + 1); // with the trailing NUL
180
181 return buf;
182 }
f6bcfd97 183 }
2b5f62a0
VZ
184
185 wxWCharBuffer buf((wchar_t *)NULL);
186
187 return buf;
6001e347
RR
188}
189
e5cceba0 190const wxCharBuffer wxMBConv::cWC2MB(const wchar_t *pwz) const
6001e347 191{
2b5f62a0
VZ
192 if ( pwz )
193 {
194 size_t nLen = WC2MB(NULL, pwz, 0);
195 if ( nLen != (size_t)-1 )
196 {
c91830cb
VZ
197 wxCharBuffer buf(nLen+3); // space for a wxUint32 trailing zero
198 WC2MB(buf.data(), pwz, nLen + 4);
2b5f62a0
VZ
199
200 return buf;
201 }
202 }
203
204 wxCharBuffer buf((char *)NULL);
e5cceba0 205
e5cceba0 206 return buf;
6001e347
RR
207}
208
6001e347 209// ----------------------------------------------------------------------------
bde4baac 210// wxMBConvLibc
6001e347
RR
211// ----------------------------------------------------------------------------
212
bde4baac
VZ
213size_t wxMBConvLibc::MB2WC(wchar_t *buf, const char *psz, size_t n) const
214{
215 return wxMB2WC(buf, psz, n);
216}
217
218size_t wxMBConvLibc::WC2MB(char *buf, const wchar_t *psz, size_t n) const
219{
220 return wxWC2MB(buf, psz, n);
221}
222
223// ----------------------------------------------------------------------------
224// UTF-7
225// ----------------------------------------------------------------------------
6001e347
RR
226
227#if 0
228static char utf7_setD[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
229 "abcdefghijklmnopqrstuvwxyz"
230 "0123456789'(),-./:?";
231static char utf7_setO[]="!\"#$%&*;<=>@[]^_`{|}";
232static char utf7_setB[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
233 "abcdefghijklmnopqrstuvwxyz"
234 "0123456789+/";
235#endif
236
237// TODO: write actual implementations of UTF-7 here
238size_t wxMBConvUTF7::MB2WC(wchar_t * WXUNUSED(buf),
239 const char * WXUNUSED(psz),
240 size_t WXUNUSED(n)) const
241{
242 return 0;
243}
244
245size_t wxMBConvUTF7::WC2MB(char * WXUNUSED(buf),
246 const wchar_t * WXUNUSED(psz),
247 size_t WXUNUSED(n)) const
248{
249 return 0;
250}
251
f6bcfd97 252// ----------------------------------------------------------------------------
6001e347 253// UTF-8
f6bcfd97 254// ----------------------------------------------------------------------------
6001e347 255
dccce9ea 256static wxUint32 utf8_max[]=
4def3b35 257 { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff, 0xffffffff };
6001e347
RR
258
259size_t wxMBConvUTF8::MB2WC(wchar_t *buf, const char *psz, size_t n) const
260{
4def3b35
VS
261 size_t len = 0;
262
dccce9ea 263 while (*psz && ((!buf) || (len < n)))
4def3b35
VS
264 {
265 unsigned char cc = *psz++, fc = cc;
266 unsigned cnt;
dccce9ea 267 for (cnt = 0; fc & 0x80; cnt++)
4def3b35 268 fc <<= 1;
dccce9ea 269 if (!cnt)
4def3b35
VS
270 {
271 // plain ASCII char
dccce9ea 272 if (buf)
4def3b35
VS
273 *buf++ = cc;
274 len++;
dccce9ea
VZ
275 }
276 else
4def3b35
VS
277 {
278 cnt--;
dccce9ea 279 if (!cnt)
4def3b35
VS
280 {
281 // invalid UTF-8 sequence
282 return (size_t)-1;
dccce9ea
VZ
283 }
284 else
4def3b35
VS
285 {
286 unsigned ocnt = cnt - 1;
287 wxUint32 res = cc & (0x3f >> cnt);
dccce9ea 288 while (cnt--)
4def3b35
VS
289 {
290 cc = *psz++;
dccce9ea 291 if ((cc & 0xC0) != 0x80)
4def3b35
VS
292 {
293 // invalid UTF-8 sequence
294 return (size_t)-1;
295 }
296 res = (res << 6) | (cc & 0x3f);
297 }
dccce9ea 298 if (res <= utf8_max[ocnt])
4def3b35
VS
299 {
300 // illegal UTF-8 encoding
301 return (size_t)-1;
302 }
1cd52418 303#ifdef WC_UTF16
b5153fd8
VZ
304 // cast is ok because wchar_t == wxUuint16 if WC_UTF16
305 size_t pa = encode_utf16(res, (wxUint16 *)buf);
4def3b35
VS
306 if (pa == (size_t)-1)
307 return (size_t)-1;
dccce9ea 308 if (buf)
4def3b35
VS
309 buf += pa;
310 len += pa;
373658eb 311#else // !WC_UTF16
dccce9ea 312 if (buf)
4def3b35
VS
313 *buf++ = res;
314 len++;
373658eb 315#endif // WC_UTF16/!WC_UTF16
4def3b35
VS
316 }
317 }
6001e347 318 }
dccce9ea 319 if (buf && (len < n))
4def3b35
VS
320 *buf = 0;
321 return len;
6001e347
RR
322}
323
324size_t wxMBConvUTF8::WC2MB(char *buf, const wchar_t *psz, size_t n) const
325{
4def3b35 326 size_t len = 0;
6001e347 327
dccce9ea 328 while (*psz && ((!buf) || (len < n)))
4def3b35
VS
329 {
330 wxUint32 cc;
1cd52418 331#ifdef WC_UTF16
b5153fd8
VZ
332 // cast is ok for WC_UTF16
333 size_t pa = decode_utf16((const wxUint16 *)psz, cc);
4def3b35 334 psz += (pa == (size_t)-1) ? 1 : pa;
1cd52418 335#else
4def3b35
VS
336 cc=(*psz++) & 0x7fffffff;
337#endif
338 unsigned cnt;
339 for (cnt = 0; cc > utf8_max[cnt]; cnt++) {}
dccce9ea 340 if (!cnt)
4def3b35
VS
341 {
342 // plain ASCII char
dccce9ea 343 if (buf)
574c939e 344 *buf++ = (char) cc;
4def3b35 345 len++;
dccce9ea
VZ
346 }
347
348 else
4def3b35
VS
349 {
350 len += cnt + 1;
dccce9ea 351 if (buf)
4def3b35 352 {
574c939e 353 *buf++ = (char) ((-128 >> cnt) | ((cc >> (cnt * 6)) & (0x3f >> cnt)));
4def3b35 354 while (cnt--)
574c939e 355 *buf++ = (char) (0x80 | ((cc >> (cnt * 6)) & 0x3f));
4def3b35
VS
356 }
357 }
6001e347 358 }
4def3b35
VS
359
360 if (buf && (len<n)) *buf = 0;
adb45366 361
4def3b35 362 return len;
6001e347
RR
363}
364
c91830cb
VZ
365
366
367
368// ----------------------------------------------------------------------------
369// UTF-16
370// ----------------------------------------------------------------------------
371
372#ifdef WORDS_BIGENDIAN
bde4baac
VZ
373 #define wxMBConvUTF16straight wxMBConvUTF16BE
374 #define wxMBConvUTF16swap wxMBConvUTF16LE
c91830cb 375#else
bde4baac
VZ
376 #define wxMBConvUTF16swap wxMBConvUTF16BE
377 #define wxMBConvUTF16straight wxMBConvUTF16LE
c91830cb
VZ
378#endif
379
380
c91830cb
VZ
381#ifdef WC_UTF16
382
c91830cb
VZ
383// copy 16bit MB to 16bit String
384size_t wxMBConvUTF16straight::MB2WC(wchar_t *buf, const char *psz, size_t n) const
385{
386 size_t len=0;
387
388 while (*(wxUint16*)psz && (!buf || len < n))
389 {
390 if (buf)
391 *buf++ = *(wxUint16*)psz;
392 len++;
393
394 psz += sizeof(wxUint16);
395 }
396 if (buf && len<n) *buf=0;
397
398 return len;
399}
400
401
402// copy 16bit String to 16bit MB
403size_t wxMBConvUTF16straight::WC2MB(char *buf, const wchar_t *psz, size_t n) const
404{
405 size_t len=0;
406
407 while (*psz && (!buf || len < n))
408 {
409 if (buf)
410 {
411 *(wxUint16*)buf = *psz;
412 buf += sizeof(wxUint16);
413 }
414 len += sizeof(wxUint16);
415 psz++;
416 }
417 if (buf && len<=n-sizeof(wxUint16)) *(wxUint16*)buf=0;
418
419 return len;
420}
421
422
423// swap 16bit MB to 16bit String
424size_t wxMBConvUTF16swap::MB2WC(wchar_t *buf, const char *psz, size_t n) const
425{
426 size_t len=0;
427
428 while (*(wxUint16*)psz && (!buf || len < n))
429 {
430 if (buf)
431 {
432 ((char *)buf)[0] = psz[1];
433 ((char *)buf)[1] = psz[0];
434 buf++;
435 }
436 len++;
437 psz += sizeof(wxUint16);
438 }
439 if (buf && len<n) *buf=0;
440
441 return len;
442}
443
444
445// swap 16bit MB to 16bit String
446size_t wxMBConvUTF16swap::WC2MB(char *buf, const wchar_t *psz, size_t n) const
447{
448 size_t len=0;
449
450 while (*psz && (!buf || len < n))
451 {
452 if (buf)
453 {
454 *buf++ = ((char*)psz)[1];
455 *buf++ = ((char*)psz)[0];
456 }
457 len += sizeof(wxUint16);
458 psz++;
459 }
460 if (buf && len<=n-sizeof(wxUint16)) *(wxUint16*)buf=0;
461
462 return len;
463}
464
465
466#else // WC_UTF16
467
468
469// copy 16bit MB to 32bit String
470size_t wxMBConvUTF16straight::MB2WC(wchar_t *buf, const char *psz, size_t n) const
471{
472 size_t len=0;
473
474 while (*(wxUint16*)psz && (!buf || len < n))
475 {
476 wxUint32 cc;
477 size_t pa=decode_utf16((wxUint16*)psz, cc);
478 if (pa == (size_t)-1)
479 return pa;
480
481 if (buf)
482 *buf++ = cc;
483 len++;
484 psz += pa * sizeof(wxUint16);
485 }
486 if (buf && len<n) *buf=0;
487
488 return len;
489}
490
491
492// copy 32bit String to 16bit MB
493size_t wxMBConvUTF16straight::WC2MB(char *buf, const wchar_t *psz, size_t n) const
494{
495 size_t len=0;
496
497 while (*psz && (!buf || len < n))
498 {
499 wxUint16 cc[2];
500 size_t pa=encode_utf16(*psz, cc);
501
502 if (pa == (size_t)-1)
503 return pa;
504
505 if (buf)
506 {
69b80d28 507 *(wxUint16*)buf = cc[0];
b5153fd8 508 buf += sizeof(wxUint16);
c91830cb 509 if (pa > 1)
69b80d28
VZ
510 {
511 *(wxUint16*)buf = cc[1];
512 buf += sizeof(wxUint16);
513 }
c91830cb
VZ
514 }
515
516 len += pa*sizeof(wxUint16);
517 psz++;
518 }
519 if (buf && len<=n-sizeof(wxUint16)) *(wxUint16*)buf=0;
520
521 return len;
522}
523
524
525// swap 16bit MB to 32bit String
526size_t wxMBConvUTF16swap::MB2WC(wchar_t *buf, const char *psz, size_t n) const
527{
528 size_t len=0;
529
530 while (*(wxUint16*)psz && (!buf || len < n))
531 {
532 wxUint32 cc;
533 char tmp[4];
534 tmp[0]=psz[1]; tmp[1]=psz[0];
535 tmp[2]=psz[3]; tmp[3]=psz[2];
536
537 size_t pa=decode_utf16((wxUint16*)tmp, cc);
538 if (pa == (size_t)-1)
539 return pa;
540
541 if (buf)
542 *buf++ = cc;
543
544 len++;
545 psz += pa * sizeof(wxUint16);
546 }
547 if (buf && len<n) *buf=0;
548
549 return len;
550}
551
552
553// swap 32bit String to 16bit MB
554size_t wxMBConvUTF16swap::WC2MB(char *buf, const wchar_t *psz, size_t n) const
555{
556 size_t len=0;
557
558 while (*psz && (!buf || len < n))
559 {
560 wxUint16 cc[2];
561 size_t pa=encode_utf16(*psz, cc);
562
563 if (pa == (size_t)-1)
564 return pa;
565
566 if (buf)
567 {
568 *buf++ = ((char*)cc)[1];
569 *buf++ = ((char*)cc)[0];
570 if (pa > 1)
571 {
572 *buf++ = ((char*)cc)[3];
573 *buf++ = ((char*)cc)[2];
574 }
575 }
576
577 len += pa*sizeof(wxUint16);
578 psz++;
579 }
580 if (buf && len<=n-sizeof(wxUint16)) *(wxUint16*)buf=0;
581
582 return len;
583}
584
585#endif // WC_UTF16
586
587
588// ----------------------------------------------------------------------------
589// UTF-32
590// ----------------------------------------------------------------------------
591
592#ifdef WORDS_BIGENDIAN
593#define wxMBConvUTF32straight wxMBConvUTF32BE
594#define wxMBConvUTF32swap wxMBConvUTF32LE
595#else
596#define wxMBConvUTF32swap wxMBConvUTF32BE
597#define wxMBConvUTF32straight wxMBConvUTF32LE
598#endif
599
600
601WXDLLIMPEXP_DATA_BASE(wxMBConvUTF32LE) wxConvUTF32LE;
602WXDLLIMPEXP_DATA_BASE(wxMBConvUTF32BE) wxConvUTF32BE;
603
604
605#ifdef WC_UTF16
606
607// copy 32bit MB to 16bit String
608size_t wxMBConvUTF32straight::MB2WC(wchar_t *buf, const char *psz, size_t n) const
609{
610 size_t len=0;
611
612 while (*(wxUint32*)psz && (!buf || len < n))
613 {
614 wxUint16 cc[2];
615
616 size_t pa=encode_utf16(*(wxUint32*)psz, cc);
617 if (pa == (size_t)-1)
618 return pa;
619
620 if (buf)
621 {
622 *buf++ = cc[0];
623 if (pa > 1)
624 *buf++ = cc[1];
625 }
626 len += pa;
627 psz += sizeof(wxUint32);
628 }
629 if (buf && len<n) *buf=0;
630
631 return len;
632}
633
634
635// copy 16bit String to 32bit MB
636size_t wxMBConvUTF32straight::WC2MB(char *buf, const wchar_t *psz, size_t n) const
637{
638 size_t len=0;
639
640 while (*psz && (!buf || len < n))
641 {
642 wxUint32 cc;
643
b5153fd8
VZ
644 // cast is ok for WC_UTF16
645 size_t pa = decode_utf16((const wxUint16 *)psz, cc);
c91830cb
VZ
646 if (pa == (size_t)-1)
647 return pa;
648
649 if (buf)
650 {
651 *(wxUint32*)buf = cc;
652 buf += sizeof(wxUint32);
653 }
654 len += sizeof(wxUint32);
655 psz += pa;
656 }
b5153fd8
VZ
657
658 if (buf && len<=n-sizeof(wxUint32))
659 *(wxUint32*)buf=0;
c91830cb
VZ
660
661 return len;
662}
663
664
665
666// swap 32bit MB to 16bit String
667size_t wxMBConvUTF32swap::MB2WC(wchar_t *buf, const char *psz, size_t n) const
668{
669 size_t len=0;
670
671 while (*(wxUint32*)psz && (!buf || len < n))
672 {
673 char tmp[4];
674 tmp[0] = psz[3]; tmp[1] = psz[2];
675 tmp[2] = psz[1]; tmp[3] = psz[0];
676
677
678 wxUint16 cc[2];
679
680 size_t pa=encode_utf16(*(wxUint32*)tmp, cc);
681 if (pa == (size_t)-1)
682 return pa;
683
684 if (buf)
685 {
686 *buf++ = cc[0];
687 if (pa > 1)
688 *buf++ = cc[1];
689 }
690 len += pa;
691 psz += sizeof(wxUint32);
692 }
b5153fd8
VZ
693
694 if (buf && len<n)
695 *buf=0;
c91830cb
VZ
696
697 return len;
698}
699
700
701// swap 16bit String to 32bit MB
702size_t wxMBConvUTF32swap::WC2MB(char *buf, const wchar_t *psz, size_t n) const
703{
704 size_t len=0;
705
706 while (*psz && (!buf || len < n))
707 {
708 char cc[4];
709
b5153fd8
VZ
710 // cast is ok for WC_UTF16
711 size_t pa=decode_utf16((const wxUint16 *)psz, *(wxUint32*)cc);
c91830cb
VZ
712 if (pa == (size_t)-1)
713 return pa;
714
715 if (buf)
716 {
717 *buf++ = cc[3];
718 *buf++ = cc[2];
719 *buf++ = cc[1];
720 *buf++ = cc[0];
721 }
722 len += sizeof(wxUint32);
723 psz += pa;
724 }
b5153fd8
VZ
725
726 if (buf && len<=n-sizeof(wxUint32))
727 *(wxUint32*)buf=0;
c91830cb
VZ
728
729 return len;
730}
731
732#else // WC_UTF16
733
734
735// copy 32bit MB to 32bit String
736size_t wxMBConvUTF32straight::MB2WC(wchar_t *buf, const char *psz, size_t n) const
737{
738 size_t len=0;
739
740 while (*(wxUint32*)psz && (!buf || len < n))
741 {
742 if (buf)
743 *buf++ = *(wxUint32*)psz;
744 len++;
745 psz += sizeof(wxUint32);
746 }
b5153fd8
VZ
747
748 if (buf && len<n)
749 *buf=0;
c91830cb
VZ
750
751 return len;
752}
753
754
755// copy 32bit String to 32bit MB
756size_t wxMBConvUTF32straight::WC2MB(char *buf, const wchar_t *psz, size_t n) const
757{
758 size_t len=0;
759
760 while (*psz && (!buf || len < n))
761 {
762 if (buf)
763 {
764 *(wxUint32*)buf = *psz;
765 buf += sizeof(wxUint32);
766 }
767
768 len += sizeof(wxUint32);
769 psz++;
770 }
771
b5153fd8
VZ
772 if (buf && len<=n-sizeof(wxUint32))
773 *(wxUint32*)buf=0;
c91830cb
VZ
774
775 return len;
776}
777
778
779// swap 32bit MB to 32bit String
780size_t wxMBConvUTF32swap::MB2WC(wchar_t *buf, const char *psz, size_t n) const
781{
782 size_t len=0;
783
784 while (*(wxUint32*)psz && (!buf || len < n))
785 {
786 if (buf)
787 {
788 ((char *)buf)[0] = psz[3];
789 ((char *)buf)[1] = psz[2];
790 ((char *)buf)[2] = psz[1];
791 ((char *)buf)[3] = psz[0];
792 buf++;
793 }
794 len++;
795 psz += sizeof(wxUint32);
796 }
b5153fd8
VZ
797
798 if (buf && len<n)
799 *buf=0;
c91830cb
VZ
800
801 return len;
802}
803
804
805// swap 32bit String to 32bit MB
806size_t wxMBConvUTF32swap::WC2MB(char *buf, const wchar_t *psz, size_t n) const
807{
808 size_t len=0;
809
810 while (*psz && (!buf || len < n))
811 {
812 if (buf)
813 {
814 *buf++ = ((char *)psz)[3];
815 *buf++ = ((char *)psz)[2];
816 *buf++ = ((char *)psz)[1];
817 *buf++ = ((char *)psz)[0];
818 }
819 len += sizeof(wxUint32);
820 psz++;
821 }
b5153fd8
VZ
822
823 if (buf && len<=n-sizeof(wxUint32))
824 *(wxUint32*)buf=0;
c91830cb
VZ
825
826 return len;
827}
828
829
830#endif // WC_UTF16
831
832
36acb880
VZ
833// ============================================================================
834// The classes doing conversion using the iconv_xxx() functions
835// ============================================================================
3caec1bb 836
b040e242 837#ifdef HAVE_ICONV
3a0d76bc 838
3caec1bb
VS
839// VS: glibc 2.1.3 is broken in that iconv() conversion to/from UCS4 fails with E2BIG
840// if output buffer is _exactly_ as big as needed. Such case is (unless there's
841// yet another bug in glibc) the only case when iconv() returns with (size_t)-1
842// (which means error) and says there are 0 bytes left in the input buffer --
843// when _real_ error occurs, bytes-left-in-input buffer is non-zero. Hence,
844// this alternative test for iconv() failure.
845// [This bug does not appear in glibc 2.2.]
846#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ <= 1
847#define ICONV_FAILED(cres, bufLeft) ((cres == (size_t)-1) && \
848 (errno != E2BIG || bufLeft != 0))
849#else
850#define ICONV_FAILED(cres, bufLeft) (cres == (size_t)-1)
851#endif
852
ab217dba 853#define ICONV_CHAR_CAST(x) ((ICONV_CONST char **)(x))
36acb880
VZ
854
855// ----------------------------------------------------------------------------
e95354ec 856// wxMBConv_iconv: encapsulates an iconv character set
36acb880
VZ
857// ----------------------------------------------------------------------------
858
e95354ec 859class wxMBConv_iconv : public wxMBConv
1cd52418
OK
860{
861public:
e95354ec
VZ
862 wxMBConv_iconv(const wxChar *name);
863 virtual ~wxMBConv_iconv();
36acb880 864
bde4baac
VZ
865 virtual size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const;
866 virtual size_t WC2MB(char *buf, const wchar_t *psz, size_t n) const;
36acb880 867
e95354ec 868 bool IsOk() const
36acb880
VZ
869 { return (m2w != (iconv_t)-1) && (w2m != (iconv_t)-1); }
870
871protected:
872 // the iconv handlers used to translate from multibyte to wide char and in
873 // the other direction
874 iconv_t m2w,
875 w2m;
876
877private:
e95354ec 878 // the name (for iconv_open()) of a wide char charset -- if none is
36acb880
VZ
879 // available on this machine, it will remain NULL
880 static const char *ms_wcCharsetName;
881
882 // true if the wide char encoding we use (i.e. ms_wcCharsetName) has
883 // different endian-ness than the native one
405d8f46 884 static bool ms_wcNeedsSwap;
36acb880
VZ
885};
886
e95354ec
VZ
887const char *wxMBConv_iconv::ms_wcCharsetName = NULL;
888bool wxMBConv_iconv::ms_wcNeedsSwap = false;
36acb880 889
e95354ec 890wxMBConv_iconv::wxMBConv_iconv(const wxChar *name)
36acb880 891{
04c79127
RR
892 // Do it the hard way
893 char cname[100];
894 for (size_t i = 0; i < wxStrlen(name)+1; i++)
895 cname[i] = (char) name[i];
896
36acb880
VZ
897 // check for charset that represents wchar_t:
898 if (ms_wcCharsetName == NULL)
f1339c56 899 {
e95354ec 900 ms_wcNeedsSwap = false;
dccce9ea 901
36acb880
VZ
902 // try charset with explicit bytesex info (e.g. "UCS-4LE"):
903 ms_wcCharsetName = WC_NAME_BEST;
04c79127 904 m2w = iconv_open(ms_wcCharsetName, cname);
3a0d76bc 905
36acb880
VZ
906 if (m2w == (iconv_t)-1)
907 {
908 // try charset w/o bytesex info (e.g. "UCS4")
909 // and check for bytesex ourselves:
910 ms_wcCharsetName = WC_NAME;
04c79127 911 m2w = iconv_open(ms_wcCharsetName, cname);
36acb880
VZ
912
913 // last bet, try if it knows WCHAR_T pseudo-charset
3a0d76bc
VS
914 if (m2w == (iconv_t)-1)
915 {
36acb880 916 ms_wcCharsetName = "WCHAR_T";
04c79127 917 m2w = iconv_open(ms_wcCharsetName, cname);
36acb880 918 }
3a0d76bc 919
36acb880
VZ
920 if (m2w != (iconv_t)-1)
921 {
922 char buf[2], *bufPtr;
923 wchar_t wbuf[2], *wbufPtr;
924 size_t insz, outsz;
925 size_t res;
926
927 buf[0] = 'A';
928 buf[1] = 0;
929 wbuf[0] = 0;
930 insz = 2;
931 outsz = SIZEOF_WCHAR_T * 2;
932 wbufPtr = wbuf;
933 bufPtr = buf;
934
935 res = iconv(m2w, ICONV_CHAR_CAST(&bufPtr), &insz,
936 (char**)&wbufPtr, &outsz);
937
938 if (ICONV_FAILED(res, insz))
3a0d76bc 939 {
36acb880
VZ
940 ms_wcCharsetName = NULL;
941 wxLogLastError(wxT("iconv"));
2b5f62a0 942 wxLogError(_("Conversion to charset '%s' doesn't work."), name);
3a0d76bc
VS
943 }
944 else
945 {
36acb880 946 ms_wcNeedsSwap = wbuf[0] != (wchar_t)buf[0];
3a0d76bc
VS
947 }
948 }
36acb880
VZ
949 else
950 {
951 ms_wcCharsetName = NULL;
373658eb 952
957686c8
VS
953 // VS: we must not output an error here, since wxWindows will safely
954 // fall back to using wxEncodingConverter.
955 wxLogTrace(wxT("strconv"), wxT("Impossible to convert to/from charset '%s' with iconv, falling back to wxEncodingConverter."), name);
956 //wxLogError(
36acb880 957 }
3a0d76bc 958 }
36acb880 959 wxLogTrace(wxT("strconv"), wxT("wchar_t charset is '%s', needs swap: %i"), ms_wcCharsetName, ms_wcNeedsSwap);
3a0d76bc 960 }
36acb880 961 else // we already have ms_wcCharsetName
3caec1bb 962 {
04c79127 963 m2w = iconv_open(ms_wcCharsetName, cname);
f1339c56 964 }
dccce9ea 965
36acb880
VZ
966 // NB: don't ever pass NULL to iconv_open(), it may crash!
967 if ( ms_wcCharsetName )
f1339c56 968 {
04c79127 969 w2m = iconv_open( cname, ms_wcCharsetName);
36acb880 970 }
405d8f46
VZ
971 else
972 {
973 w2m = (iconv_t)-1;
974 }
36acb880 975}
3caec1bb 976
e95354ec 977wxMBConv_iconv::~wxMBConv_iconv()
36acb880
VZ
978{
979 if ( m2w != (iconv_t)-1 )
980 iconv_close(m2w);
981 if ( w2m != (iconv_t)-1 )
982 iconv_close(w2m);
983}
3a0d76bc 984
bde4baac 985size_t wxMBConv_iconv::MB2WC(wchar_t *buf, const char *psz, size_t n) const
36acb880
VZ
986{
987 size_t inbuf = strlen(psz);
988 size_t outbuf = n * SIZEOF_WCHAR_T;
989 size_t res, cres;
990 // VS: Use these instead of psz, buf because iconv() modifies its arguments:
991 wchar_t *bufPtr = buf;
992 const char *pszPtr = psz;
993
994 if (buf)
995 {
996 // have destination buffer, convert there
997 cres = iconv(m2w,
998 ICONV_CHAR_CAST(&pszPtr), &inbuf,
999 (char**)&bufPtr, &outbuf);
1000 res = n - (outbuf / SIZEOF_WCHAR_T);
dccce9ea 1001
36acb880 1002 if (ms_wcNeedsSwap)
3a0d76bc 1003 {
36acb880
VZ
1004 // convert to native endianness
1005 WC_BSWAP(buf /* _not_ bufPtr */, res)
3a0d76bc 1006 }
adb45366 1007
49dd9820
VS
1008 // NB: iconv was given only strlen(psz) characters on input, and so
1009 // it couldn't convert the trailing zero. Let's do it ourselves
1010 // if there's some room left for it in the output buffer.
1011 if (res < n)
1012 buf[res] = 0;
36acb880
VZ
1013 }
1014 else
1015 {
1016 // no destination buffer... convert using temp buffer
1017 // to calculate destination buffer requirement
1018 wchar_t tbuf[8];
1019 res = 0;
1020 do {
1021 bufPtr = tbuf;
1022 outbuf = 8*SIZEOF_WCHAR_T;
1023
1024 cres = iconv(m2w,
1025 ICONV_CHAR_CAST(&pszPtr), &inbuf,
1026 (char**)&bufPtr, &outbuf );
1027
1028 res += 8-(outbuf/SIZEOF_WCHAR_T);
1029 } while ((cres==(size_t)-1) && (errno==E2BIG));
f1339c56 1030 }
dccce9ea 1031
36acb880 1032 if (ICONV_FAILED(cres, inbuf))
f1339c56 1033 {
36acb880
VZ
1034 //VS: it is ok if iconv fails, hence trace only
1035 wxLogTrace(wxT("strconv"), wxT("iconv failed: %s"), wxSysErrorMsg(wxSysErrorCode()));
1036 return (size_t)-1;
1037 }
1038
1039 return res;
1040}
1041
bde4baac 1042size_t wxMBConv_iconv::WC2MB(char *buf, const wchar_t *psz, size_t n) const
36acb880 1043{
f8d791e0 1044 size_t inbuf = wxWcslen(psz) * SIZEOF_WCHAR_T;
36acb880
VZ
1045 size_t outbuf = n;
1046 size_t res, cres;
3a0d76bc 1047
36acb880 1048 wchar_t *tmpbuf = 0;
3caec1bb 1049
36acb880
VZ
1050 if (ms_wcNeedsSwap)
1051 {
1052 // need to copy to temp buffer to switch endianness
1053 // this absolutely doesn't rock!
1054 // (no, doing WC_BSWAP twice on the original buffer won't help, as it
1055 // could be in read-only memory, or be accessed in some other thread)
1056 tmpbuf=(wchar_t*)malloc((inbuf+1)*SIZEOF_WCHAR_T);
1057 memcpy(tmpbuf,psz,(inbuf+1)*SIZEOF_WCHAR_T);
1058 WC_BSWAP(tmpbuf, inbuf)
1059 psz=tmpbuf;
1060 }
3a0d76bc 1061
36acb880
VZ
1062 if (buf)
1063 {
1064 // have destination buffer, convert there
1065 cres = iconv( w2m, ICONV_CHAR_CAST(&psz), &inbuf, &buf, &outbuf );
3a0d76bc 1066
36acb880 1067 res = n-outbuf;
adb45366 1068
49dd9820
VS
1069 // NB: iconv was given only wcslen(psz) characters on input, and so
1070 // it couldn't convert the trailing zero. Let's do it ourselves
1071 // if there's some room left for it in the output buffer.
1072 if (res < n)
1073 buf[0] = 0;
36acb880
VZ
1074 }
1075 else
1076 {
1077 // no destination buffer... convert using temp buffer
1078 // to calculate destination buffer requirement
1079 char tbuf[16];
1080 res = 0;
1081 do {
1082 buf = tbuf; outbuf = 16;
1083
1084 cres = iconv( w2m, ICONV_CHAR_CAST(&psz), &inbuf, &buf, &outbuf );
dccce9ea 1085
36acb880
VZ
1086 res += 16 - outbuf;
1087 } while ((cres==(size_t)-1) && (errno==E2BIG));
f1339c56 1088 }
dccce9ea 1089
36acb880
VZ
1090 if (ms_wcNeedsSwap)
1091 {
1092 free(tmpbuf);
1093 }
dccce9ea 1094
36acb880
VZ
1095 if (ICONV_FAILED(cres, inbuf))
1096 {
1097 //VS: it is ok if iconv fails, hence trace only
1098 wxLogTrace(wxT("strconv"), wxT("iconv failed: %s"), wxSysErrorMsg(wxSysErrorCode()));
1099 return (size_t)-1;
1100 }
1101
1102 return res;
1103}
1104
b040e242 1105#endif // HAVE_ICONV
36acb880 1106
e95354ec 1107
36acb880
VZ
1108// ============================================================================
1109// Win32 conversion classes
1110// ============================================================================
1cd52418 1111
e95354ec 1112#ifdef wxHAVE_WIN32_MB2WC
373658eb 1113
8b04d4c4
VZ
1114// from utils.cpp
1115extern WXDLLIMPEXP_BASE long wxCharsetToCodepage(const wxChar *charset);
1116extern WXDLLIMPEXP_BASE long wxEncodingToCodepage(wxFontEncoding encoding);
373658eb 1117
e95354ec 1118class wxMBConv_win32 : public wxMBConv
1cd52418
OK
1119{
1120public:
bde4baac
VZ
1121 wxMBConv_win32()
1122 {
1123 m_CodePage = CP_ACP;
1124 }
1125
e95354ec 1126 wxMBConv_win32(const wxChar* name)
bde4baac
VZ
1127 {
1128 m_CodePage = wxCharsetToCodepage(name);
1129 }
dccce9ea 1130
e95354ec 1131 wxMBConv_win32(wxFontEncoding encoding)
bde4baac
VZ
1132 {
1133 m_CodePage = wxEncodingToCodepage(encoding);
1134 }
8b04d4c4 1135
bde4baac 1136 size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const
f1339c56 1137 {
2b5f62a0
VZ
1138 const size_t len = ::MultiByteToWideChar
1139 (
1140 m_CodePage, // code page
1141 0, // flags (none)
1142 psz, // input string
1143 -1, // its length (NUL-terminated)
b4da152e 1144 buf, // output string
2b5f62a0
VZ
1145 buf ? n : 0 // size of output buffer
1146 );
1147
03a991bc
VZ
1148 // note that it returns count of written chars for buf != NULL and size
1149 // of the needed buffer for buf == NULL so in either case the length of
1150 // the string (which never includes the terminating NUL) is one less
1151 return len ? len - 1 : (size_t)-1;
f1339c56 1152 }
dccce9ea 1153
bde4baac 1154 size_t WC2MB(char *buf, const wchar_t *psz, size_t n) const
f1339c56 1155 {
2b5f62a0
VZ
1156 const size_t len = ::WideCharToMultiByte
1157 (
1158 m_CodePage, // code page
1159 0, // flags (none)
b4da152e 1160 psz, // input string
2b5f62a0
VZ
1161 -1, // it is (wide) NUL-terminated
1162 buf, // output buffer
1163 buf ? n : 0, // and its size
1164 NULL, // default "replacement" char
1165 NULL // [out] was it used?
1166 );
1167
03a991bc
VZ
1168 // see the comment above for the reason of "len - 1"
1169 return len ? len - 1 : (size_t)-1;
f1339c56 1170 }
dccce9ea 1171
e95354ec 1172 bool IsOk() const
b1d66b54 1173 { return m_CodePage != -1; }
f1339c56
RR
1174
1175public:
b1d66b54 1176 long m_CodePage;
1cd52418 1177};
e95354ec
VZ
1178
1179#endif // wxHAVE_WIN32_MB2WC
1180
335d31e0
SC
1181// ============================================================================
1182// Mac conversion classes
1183// ============================================================================
1184
1185#if defined(__WXMAC__) && defined(TARGET_CARBON)
1186
1187class wxMBConv_mac : public wxMBConv
1188{
1189public:
1190 wxMBConv_mac()
1191 {
1192 Init(CFStringGetSystemEncoding()) ;
1193 }
1194
1195 wxMBConv_mac(const wxChar* name)
1196 {
8057c6d6 1197 Init( wxMacGetSystemEncFromFontEnc(wxFontMapper::Get()->CharsetToEncoding(name, FALSE) ) ) ;
335d31e0
SC
1198 }
1199
1200 wxMBConv_mac(wxFontEncoding encoding)
1201 {
8057c6d6 1202 Init( wxMacGetSystemEncFromFontEnc(encoding) );
335d31e0
SC
1203 }
1204
1205 ~wxMBConv_mac()
1206 {
1207 OSStatus status = noErr ;
1208 status = TECDisposeConverter(m_MB2WC_converter);
1209 status = TECDisposeConverter(m_WC2MB_converter);
1210 }
1211
335d31e0
SC
1212
1213 void Init( TextEncodingBase encoding)
1214 {
1215 OSStatus status = noErr ;
1216 m_char_encoding = encoding ;
1217#if SIZEOF_WCHAR_T == 4
1218 m_unicode_encoding = CreateTextEncoding(kTextEncodingUnicodeDefault,0,kUnicode32BitFormat) ;
1219#else
1220 m_unicode_encoding = CreateTextEncoding(kTextEncodingUnicodeDefault,0,kUnicode16BitFormat) ;
1221#endif
1222 status = TECCreateConverter(&m_MB2WC_converter,
1223 m_char_encoding,
1224 m_unicode_encoding);
1225 status = TECCreateConverter(&m_WC2MB_converter,
1226 m_unicode_encoding,
1227 m_char_encoding);
1228 }
1229
1230 size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const
1231 {
1232 OSStatus status = noErr ;
1233 ByteCount byteOutLen ;
1234 ByteCount byteInLen = strlen(psz) ;
1235 ByteCount byteBufferLen = n ;
1236 wchar_t *tbuf = NULL ;
1237
1238 if (buf == NULL)
1239 {
1240 n = byteInLen * SIZEOF_WCHAR_T ;
1241 tbuf = (wchar_t*) malloc( n ) ;
1242 }
1243
1244 status = TECConvertText(m_MB2WC_converter, (ConstTextPtr) psz , byteInLen, &byteInLen,
1245 (TextPtr) (buf ? buf : tbuf) , byteBufferLen, &byteOutLen);
1246
1247 if ( buf == NULL )
1248 free(tbuf) ;
1249
1250 size_t res = byteOutLen / SIZEOF_WCHAR_T ;
1251 if ( buf && res < n)
1252 buf[res] = 0;
1253
1254 return res ;
1255 }
1256
1257 size_t WC2MB(char *buf, const wchar_t *psz, size_t n) const
1258 {
1259 OSStatus status = noErr ;
1260 ByteCount byteOutLen ;
1261 ByteCount byteInLen = wxWcslen(psz) * SIZEOF_WCHAR_T ;
1262 ByteCount byteBufferLen = n ;
1263
1264 char *tbuf = NULL ;
1265
1266 if (buf == NULL)
1267 {
1268 n = byteInLen ;
1269 tbuf = (char*) malloc( n ) ;
1270 }
1271
1272 status = TECConvertText(m_WC2MB_converter, (ConstTextPtr) psz , byteInLen, &byteInLen,
1273 (TextPtr) ( buf ? buf : tbuf ) , byteBufferLen, &byteOutLen);
1274
1275 if ( buf == NULL )
1276 free(tbuf) ;
1277
1278 size_t res = byteOutLen ;
1279 if ( buf && res < n)
1280 buf[res] = 0;
1281
1282 return res ;
1283 }
1284
1285 bool IsOk() const
1286 { return m_MB2WC_converter != NULL && m_WC2MB_converter != NULL ; }
1287
1288private:
1289 TECObjectRef m_MB2WC_converter ;
1290 TECObjectRef m_WC2MB_converter ;
1291
1292 TextEncodingBase m_char_encoding ;
1293 TextEncodingBase m_unicode_encoding ;
1294};
1295
1296#endif // defined(__WXMAC__) && defined(TARGET_CARBON)
1e6feb95 1297
36acb880
VZ
1298// ============================================================================
1299// wxEncodingConverter based conversion classes
1300// ============================================================================
1301
1e6feb95 1302#if wxUSE_FONTMAP
1cd52418 1303
e95354ec 1304class wxMBConv_wxwin : public wxMBConv
1cd52418 1305{
8b04d4c4
VZ
1306private:
1307 void Init()
1308 {
1309 m_ok = m2w.Init(m_enc, wxFONTENCODING_UNICODE) &&
1310 w2m.Init(wxFONTENCODING_UNICODE, m_enc);
1311 }
1312
6001e347 1313public:
f1339c56
RR
1314 // temporarily just use wxEncodingConverter stuff,
1315 // so that it works while a better implementation is built
e95354ec 1316 wxMBConv_wxwin(const wxChar* name)
f1339c56
RR
1317 {
1318 if (name)
e95354ec 1319 m_enc = wxFontMapper::Get()->CharsetToEncoding(name, false);
8b04d4c4
VZ
1320 else
1321 m_enc = wxFONTENCODING_SYSTEM;
cafbf6fb 1322
8b04d4c4
VZ
1323 Init();
1324 }
1325
e95354ec 1326 wxMBConv_wxwin(wxFontEncoding enc)
8b04d4c4
VZ
1327 {
1328 m_enc = enc;
1329
1330 Init();
f1339c56 1331 }
dccce9ea 1332
bde4baac 1333 size_t MB2WC(wchar_t *buf, const char *psz, size_t WXUNUSED(n)) const
f1339c56
RR
1334 {
1335 size_t inbuf = strlen(psz);
dccce9ea 1336 if (buf)
4def3b35 1337 m2w.Convert(psz,buf);
f1339c56
RR
1338 return inbuf;
1339 }
dccce9ea 1340
bde4baac 1341 size_t WC2MB(char *buf, const wchar_t *psz, size_t WXUNUSED(n)) const
f1339c56 1342 {
f8d791e0 1343 const size_t inbuf = wxWcslen(psz);
f1339c56
RR
1344 if (buf)
1345 w2m.Convert(psz,buf);
dccce9ea 1346
f1339c56
RR
1347 return inbuf;
1348 }
dccce9ea 1349
e95354ec 1350 bool IsOk() const { return m_ok; }
f1339c56
RR
1351
1352public:
8b04d4c4 1353 wxFontEncoding m_enc;
f1339c56 1354 wxEncodingConverter m2w, w2m;
cafbf6fb
VZ
1355
1356 // were we initialized successfully?
1357 bool m_ok;
fc7a2a60 1358
e95354ec 1359 DECLARE_NO_COPY_CLASS(wxMBConv_wxwin)
f6bcfd97 1360};
6001e347 1361
1e6feb95
VZ
1362#endif // wxUSE_FONTMAP
1363
36acb880
VZ
1364// ============================================================================
1365// wxCSConv implementation
1366// ============================================================================
1367
8b04d4c4 1368void wxCSConv::Init()
6001e347 1369{
e95354ec
VZ
1370 m_name = NULL;
1371 m_convReal = NULL;
1372 m_deferred = true;
1373}
1374
8b04d4c4
VZ
1375wxCSConv::wxCSConv(const wxChar *charset)
1376{
1377 Init();
82713003 1378
e95354ec
VZ
1379 if ( charset )
1380 {
e95354ec
VZ
1381 SetName(charset);
1382 }
bda3d86a
VZ
1383
1384 m_encoding = wxFONTENCODING_SYSTEM;
6001e347
RR
1385}
1386
8b04d4c4
VZ
1387wxCSConv::wxCSConv(wxFontEncoding encoding)
1388{
bda3d86a 1389 if ( encoding == wxFONTENCODING_MAX || encoding == wxFONTENCODING_DEFAULT )
e95354ec
VZ
1390 {
1391 wxFAIL_MSG( _T("invalid encoding value in wxCSConv ctor") );
1392
1393 encoding = wxFONTENCODING_SYSTEM;
1394 }
1395
8b04d4c4
VZ
1396 Init();
1397
bda3d86a 1398 m_encoding = encoding;
8b04d4c4
VZ
1399}
1400
6001e347
RR
1401wxCSConv::~wxCSConv()
1402{
65e50848
JS
1403 Clear();
1404}
1405
54380f29 1406wxCSConv::wxCSConv(const wxCSConv& conv)
8b04d4c4 1407 : wxMBConv()
54380f29 1408{
8b04d4c4
VZ
1409 Init();
1410
54380f29 1411 SetName(conv.m_name);
8b04d4c4 1412 m_encoding = conv.m_encoding;
54380f29
GD
1413}
1414
1415wxCSConv& wxCSConv::operator=(const wxCSConv& conv)
1416{
1417 Clear();
8b04d4c4 1418
54380f29 1419 SetName(conv.m_name);
8b04d4c4
VZ
1420 m_encoding = conv.m_encoding;
1421
54380f29
GD
1422 return *this;
1423}
1424
65e50848
JS
1425void wxCSConv::Clear()
1426{
8b04d4c4 1427 free(m_name);
e95354ec 1428 delete m_convReal;
8b04d4c4 1429
65e50848 1430 m_name = NULL;
e95354ec 1431 m_convReal = NULL;
6001e347
RR
1432}
1433
1434void wxCSConv::SetName(const wxChar *charset)
1435{
f1339c56
RR
1436 if (charset)
1437 {
1438 m_name = wxStrdup(charset);
e95354ec 1439 m_deferred = true;
f1339c56 1440 }
6001e347
RR
1441}
1442
e95354ec
VZ
1443wxMBConv *wxCSConv::DoCreate() const
1444{
c547282d
VZ
1445 // check for the special case of ASCII or ISO8859-1 charset: as we have
1446 // special knowledge of it anyhow, we don't need to create a special
1447 // conversion object
1448 if ( m_encoding == wxFONTENCODING_ISO8859_1 )
f1339c56 1449 {
e95354ec
VZ
1450 // don't convert at all
1451 return NULL;
1452 }
dccce9ea 1453
e95354ec
VZ
1454 // we trust OS to do conversion better than we can so try external
1455 // conversion methods first
1456 //
1457 // the full order is:
1458 // 1. OS conversion (iconv() under Unix or Win32 API)
1459 // 2. hard coded conversions for UTF
1460 // 3. wxEncodingConverter as fall back
1461
1462 // step (1)
1463#ifdef HAVE_ICONV
c547282d 1464#if !wxUSE_FONTMAP
e95354ec 1465 if ( m_name )
c547282d 1466#endif // !wxUSE_FONTMAP
e95354ec 1467 {
c547282d
VZ
1468 wxString name(m_name);
1469
1470#if wxUSE_FONTMAP
1471 if ( name.empty() )
1472 name = wxFontMapper::Get()->GetEncodingName(m_encoding);
1473#endif // wxUSE_FONTMAP
1474
1475 wxMBConv_iconv *conv = new wxMBConv_iconv(name);
e95354ec
VZ
1476 if ( conv->IsOk() )
1477 return conv;
1478
1479 delete conv;
1480 }
1481#endif // HAVE_ICONV
1482
1483#ifdef wxHAVE_WIN32_MB2WC
1484 {
1485 wxMBConv_win32 *conv = m_name ? new wxMBConv_win32(m_name)
1486 : new wxMBConv_win32(m_encoding);
1487 if ( conv->IsOk() )
1488 return conv;
1489
1490 delete conv;
1491 }
1492#endif // wxHAVE_WIN32_MB2WC
335d31e0
SC
1493#if defined(__WXMAC__)
1494 {
1495 if ( m_name || ( m_encoding < wxFONTENCODING_UTF16BE ) )
1496 {
1497
1498 wxMBConv_mac *conv = m_name ? new wxMBConv_mac(m_name)
1499 : new wxMBConv_mac(m_encoding);
1500 if ( conv->IsOk() )
1501 return conv;
1502
1503 delete conv;
1504 }
1505 }
1506#endif
e95354ec
VZ
1507 // step (2)
1508 wxFontEncoding enc = m_encoding;
1509#if wxUSE_FONTMAP
c547282d
VZ
1510 if ( enc == wxFONTENCODING_SYSTEM && m_name )
1511 {
1512 // use "false" to suppress interactive dialogs -- we can be called from
1513 // anywhere and popping up a dialog from here is the last thing we want to
1514 // do
1515 enc = wxFontMapper::Get()->CharsetToEncoding(m_name, false);
1516 }
e95354ec
VZ
1517#endif // wxUSE_FONTMAP
1518
1519 switch ( enc )
1520 {
1521 case wxFONTENCODING_UTF7:
1522 return new wxMBConvUTF7;
1523
1524 case wxFONTENCODING_UTF8:
1525 return new wxMBConvUTF8;
1526
e95354ec
VZ
1527 case wxFONTENCODING_UTF16BE:
1528 return new wxMBConvUTF16BE;
1529
1530 case wxFONTENCODING_UTF16LE:
1531 return new wxMBConvUTF16LE;
1532
e95354ec
VZ
1533 case wxFONTENCODING_UTF32BE:
1534 return new wxMBConvUTF32BE;
1535
1536 case wxFONTENCODING_UTF32LE:
1537 return new wxMBConvUTF32LE;
1538
1539 default:
1540 // nothing to do but put here to suppress gcc warnings
1541 ;
1542 }
1543
1544 // step (3)
1545#if wxUSE_FONTMAP
1546 {
1547 wxMBConv_wxwin *conv = m_name ? new wxMBConv_wxwin(m_name)
1548 : new wxMBConv_wxwin(m_encoding);
1549 if ( conv->IsOk() )
1550 return conv;
1551
1552 delete conv;
1553 }
1554#endif // wxUSE_FONTMAP
1555
a58d4f4d
VS
1556 // NB: This is a hack to prevent deadlock. What could otherwise happen
1557 // in Unicode build: wxConvLocal creation ends up being here
1558 // because of some failure and logs the error. But wxLog will try to
1559 // attach timestamp, for which it will need wxConvLocal (to convert
1560 // time to char* and then wchar_t*), but that fails, tries to log
1561 // error, but wxLog has a (already locked) critical section that
1562 // guards static buffer.
1563 static bool alreadyLoggingError = false;
1564 if (!alreadyLoggingError)
1565 {
1566 alreadyLoggingError = true;
1567 wxLogError(_("Cannot convert from the charset '%s'!"),
1568 m_name ? m_name
e95354ec
VZ
1569 :
1570#if wxUSE_FONTMAP
1571 wxFontMapper::GetEncodingDescription(m_encoding).c_str()
1572#else // !wxUSE_FONTMAP
1573 wxString::Format(_("encoding %s"), m_encoding).c_str()
1574#endif // wxUSE_FONTMAP/!wxUSE_FONTMAP
1575 );
a58d4f4d
VS
1576 alreadyLoggingError = false;
1577 }
e95354ec
VZ
1578
1579 return NULL;
1580}
1581
1582void wxCSConv::CreateConvIfNeeded() const
1583{
1584 if ( m_deferred )
1585 {
1586 wxCSConv *self = (wxCSConv *)this; // const_cast
bda3d86a
VZ
1587
1588#if wxUSE_INTL
1589 // if we don't have neither the name nor the encoding, use the default
1590 // encoding for this system
1591 if ( !m_name && m_encoding == wxFONTENCODING_SYSTEM )
1592 {
4d312c22 1593 self->m_name = wxStrdup(wxLocale::GetSystemEncodingName());
bda3d86a
VZ
1594 }
1595#endif // wxUSE_INTL
1596
e95354ec
VZ
1597 self->m_convReal = DoCreate();
1598 self->m_deferred = false;
6001e347 1599 }
6001e347
RR
1600}
1601
1602size_t wxCSConv::MB2WC(wchar_t *buf, const char *psz, size_t n) const
1603{
e95354ec 1604 CreateConvIfNeeded();
dccce9ea 1605
e95354ec
VZ
1606 if (m_convReal)
1607 return m_convReal->MB2WC(buf, psz, n);
f1339c56
RR
1608
1609 // latin-1 (direct)
4def3b35 1610 size_t len = strlen(psz);
dccce9ea 1611
f1339c56
RR
1612 if (buf)
1613 {
4def3b35 1614 for (size_t c = 0; c <= len; c++)
f1339c56
RR
1615 buf[c] = (unsigned char)(psz[c]);
1616 }
dccce9ea 1617
f1339c56 1618 return len;
6001e347
RR
1619}
1620
1621size_t wxCSConv::WC2MB(char *buf, const wchar_t *psz, size_t n) const
1622{
e95354ec 1623 CreateConvIfNeeded();
dccce9ea 1624
e95354ec
VZ
1625 if (m_convReal)
1626 return m_convReal->WC2MB(buf, psz, n);
1cd52418 1627
f1339c56 1628 // latin-1 (direct)
f8d791e0 1629 const size_t len = wxWcslen(psz);
f1339c56
RR
1630 if (buf)
1631 {
4def3b35 1632 for (size_t c = 0; c <= len; c++)
24642831
VS
1633 {
1634 if (psz[c] > 0xFF)
1635 return (size_t)-1;
1636 buf[c] = psz[c];
1637 }
1638 }
1639 else
1640 {
1641 for (size_t c = 0; c <= len; c++)
1642 {
1643 if (psz[c] > 0xFF)
1644 return (size_t)-1;
1645 }
f1339c56 1646 }
dccce9ea 1647
f1339c56 1648 return len;
6001e347
RR
1649}
1650
bde4baac
VZ
1651// ----------------------------------------------------------------------------
1652// globals
1653// ----------------------------------------------------------------------------
1654
1655#ifdef __WINDOWS__
1656 static wxMBConv_win32 wxConvLibcObj;
1657#else
dcc8fac0 1658 static wxMBConvLibc wxConvLibcObj;
bde4baac
VZ
1659#endif
1660
1661static wxCSConv wxConvLocalObj(wxFONTENCODING_SYSTEM);
1662static wxCSConv wxConvISO8859_1Obj(wxFONTENCODING_ISO8859_1);
1663static wxMBConvUTF7 wxConvUTF7Obj;
1664static wxMBConvUTF8 wxConvUTF8Obj;
1665
1666
1667WXDLLIMPEXP_DATA_BASE(wxMBConv&) wxConvLibc = wxConvLibcObj;
1668WXDLLIMPEXP_DATA_BASE(wxCSConv&) wxConvLocal = wxConvLocalObj;
1669WXDLLIMPEXP_DATA_BASE(wxCSConv&) wxConvISO8859_1 = wxConvISO8859_1Obj;
1670WXDLLIMPEXP_DATA_BASE(wxMBConvUTF7&) wxConvUTF7 = wxConvUTF7Obj;
1671WXDLLIMPEXP_DATA_BASE(wxMBConvUTF8&) wxConvUTF8 = wxConvUTF8Obj;
1672WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvCurrent = &wxConvLibcObj;
1673
1674#else // !wxUSE_WCHAR_T
1675
1676// stand-ins in absence of wchar_t
1677WXDLLIMPEXP_DATA_BASE(wxMBConv) wxConvLibc,
1678 wxConvISO8859_1,
1679 wxConvLocal,
1680 wxConvUTF8;
1681
1682#endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T
6001e347
RR
1683
1684