]> git.saurik.com Git - wxWidgets.git/blob - src/common/strconv.cpp
popupcmn is needed by wxGTK too, why was it excluded?
[wxWidgets.git] / src / common / strconv.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: strconv.cpp
3 // Purpose: Unicode conversion classes
4 // Author: Ove Kaaven, Robert Roebling, Vadim Zeitlin
5 // Modified by:
6 // Created: 29/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) 1999 Ove Kaaven, Robert Roebling, Vadim Zeitlin
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "strconv.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #ifdef __WXMSW__
32 #include "wx/msw/private.h"
33 #endif
34
35 #include <errno.h>
36 #include <ctype.h>
37 #include <string.h>
38 #include <stdlib.h>
39
40 #ifdef __SALFORDC__
41 #include <clib.h>
42 #endif
43
44 #ifdef HAVE_ICONV_H
45 #include <iconv.h>
46 #endif
47
48 #ifdef __WXMSW__
49 #include <windows.h>
50 #endif
51
52 #include "wx/debug.h"
53 #include "wx/strconv.h"
54 #include "wx/intl.h"
55 #include "wx/log.h"
56
57 #if defined(WORDS_BIGENDIAN) || defined(__STDC_ISO_10646__)
58 #define BSWAP_UCS4(str, len)
59 #define BSWAP_UCS2(str, len)
60 #else
61 #define BSWAP_UCS4(str, len) { unsigned _c; for (_c=0; _c<len; _c++) str[_c]=wxUINT32_SWAP_ALWAYS(str[_c]); }
62 #define BSWAP_UCS2(str, len) { unsigned _c; for (_c=0; _c<len; _c++) str[_c]=wxUINT16_SWAP_ALWAYS(str[_c]); }
63 #define WC_NEED_BSWAP
64 #endif
65 #define BSWAP_UTF32(str, len) BSWAP_UCS4(str, len)
66 #define BSWAP_UTF16(str, len) BSWAP_UCS2(str, len)
67
68 // under Unix SIZEOF_WCHAR_T is defined by configure, but under other platforms
69 // it might be not defined - assume the most common value
70 #ifndef SIZEOF_WCHAR_T
71 #define SIZEOF_WCHAR_T 2
72 #endif // !defined(SIZEOF_WCHAR_T)
73
74 #if SIZEOF_WCHAR_T == 4
75 #define WC_NAME "UCS4"
76 #define WC_BSWAP BSWAP_UCS4
77 #elif SIZEOF_WCHAR_T == 2
78 #define WC_NAME "UTF16"
79 #define WC_BSWAP BSWAP_UTF16
80 #define WC_UTF16
81 #else // sizeof(wchar_t) != 2 nor 4
82 // I don't know what to do about this
83 #error "Weird sizeof(wchar_t): please report your platform details to wx-users mailing list"
84 #endif
85
86 // ----------------------------------------------------------------------------
87 // globals
88 // ----------------------------------------------------------------------------
89
90 WXDLLEXPORT_DATA(wxMBConv *) wxConvCurrent = &wxConvLibc;
91
92 // ============================================================================
93 // implementation
94 // ============================================================================
95
96 #if wxUSE_WCHAR_T
97
98 #ifdef WC_UTF16
99
100 static size_t encode_utf16(wxUint32 input, wchar_t *output)
101 {
102 if (input<=0xffff)
103 {
104 if (output) *output++ = input;
105 return 1;
106 }
107 else if (input>=0x110000)
108 {
109 return (size_t)-1;
110 }
111 else
112 {
113 if (output)
114 {
115 *output++ = (input >> 10)+0xd7c0;
116 *output++ = (input&0x3ff)+0xdc00;
117 }
118 return 2;
119 }
120 }
121
122 static size_t decode_utf16(const wchar_t* input, wxUint32& output)
123 {
124 if ((*input<0xd800) || (*input>0xdfff))
125 {
126 output = *input;
127 return 1;
128 }
129 else if ((input[1]<0xdc00) || (input[1]>=0xdfff))
130 {
131 output = *input;
132 return (size_t)-1;
133 }
134 else
135 {
136 output = ((input[0] - 0xd7c0) << 10) + (input[1] - 0xdc00);
137 return 2;
138 }
139 }
140
141 #endif // WC_UTF16
142
143 // ----------------------------------------------------------------------------
144 // wxMBConv
145 // ----------------------------------------------------------------------------
146
147 WXDLLEXPORT_DATA(wxMBConv) wxConvLibc;
148
149 size_t wxMBConv::MB2WC(wchar_t *buf, const char *psz, size_t n) const
150 {
151 return wxMB2WC(buf, psz, n);
152 }
153
154 size_t wxMBConv::WC2MB(char *buf, const wchar_t *psz, size_t n) const
155 {
156 return wxWC2MB(buf, psz, n);
157 }
158
159 const wxWCharBuffer wxMBConv::cMB2WC(const char *psz) const
160 {
161 if (psz)
162 {
163 size_t nLen = MB2WC((wchar_t *) NULL, psz, 0);
164 if (nLen == (size_t)-1)
165 return wxWCharBuffer((wchar_t *) NULL);
166 wxWCharBuffer buf(nLen);
167 MB2WC((wchar_t *)(const wchar_t *) buf, psz, nLen);
168 return buf;
169 }
170 else
171 return wxWCharBuffer((wchar_t *) NULL);
172 }
173
174 const wxCharBuffer wxMBConv::cWC2MB(const wchar_t *psz) const
175 {
176 if (psz)
177 {
178 size_t nLen = WC2MB((char *) NULL, psz, 0);
179 if (nLen == (size_t)-1)
180 return wxCharBuffer((char *) NULL);
181 wxCharBuffer buf(nLen);
182 WC2MB((char *)(const char *) buf, psz, nLen);
183 return buf;
184 }
185 else
186 return wxCharBuffer((char *) NULL);
187 }
188
189 // ----------------------------------------------------------------------------
190 // standard file conversion
191 // ----------------------------------------------------------------------------
192
193 WXDLLEXPORT_DATA(wxMBConvFile) wxConvFile;
194
195 // just use the libc conversion for now
196 size_t wxMBConvFile::MB2WC(wchar_t *buf, const char *psz, size_t n) const
197 {
198 return wxMB2WC(buf, psz, n);
199 }
200
201 size_t wxMBConvFile::WC2MB(char *buf, const wchar_t *psz, size_t n) const
202 {
203 return wxWC2MB(buf, psz, n);
204 }
205
206 // ----------------------------------------------------------------------------
207 // standard gdk conversion
208 // ----------------------------------------------------------------------------
209
210 #ifdef __WXGTK12__
211
212 WXDLLEXPORT_DATA(wxMBConvGdk) wxConvGdk;
213
214 #include <gdk/gdk.h>
215
216 size_t wxMBConvGdk::MB2WC(wchar_t *buf, const char *psz, size_t n) const
217 {
218 if (buf)
219 {
220 return gdk_mbstowcs((GdkWChar *)buf, psz, n);
221 }
222 else
223 {
224 GdkWChar *nbuf = new GdkWChar[n=strlen(psz)];
225 size_t len = gdk_mbstowcs(nbuf, psz, n);
226 delete[] nbuf;
227 return len;
228 }
229 }
230
231 size_t wxMBConvGdk::WC2MB(char *buf, const wchar_t *psz, size_t n) const
232 {
233 char *mbstr = gdk_wcstombs((GdkWChar *)psz);
234 size_t len = mbstr ? strlen(mbstr) : 0;
235 if (buf)
236 {
237 if (len > n)
238 len = n;
239 memcpy(buf, psz, len);
240 if (len < n)
241 buf[len] = 0;
242 }
243 return len;
244 }
245
246 #endif // GTK > 1.0
247
248 // ----------------------------------------------------------------------------
249 // UTF-7
250 // ----------------------------------------------------------------------------
251
252 WXDLLEXPORT_DATA(wxMBConvUTF7) wxConvUTF7;
253
254 #if 0
255 static char utf7_setD[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
256 "abcdefghijklmnopqrstuvwxyz"
257 "0123456789'(),-./:?";
258 static char utf7_setO[]="!\"#$%&*;<=>@[]^_`{|}";
259 static char utf7_setB[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
260 "abcdefghijklmnopqrstuvwxyz"
261 "0123456789+/";
262 #endif
263
264 // TODO: write actual implementations of UTF-7 here
265 size_t wxMBConvUTF7::MB2WC(wchar_t * WXUNUSED(buf),
266 const char * WXUNUSED(psz),
267 size_t WXUNUSED(n)) const
268 {
269 return 0;
270 }
271
272 size_t wxMBConvUTF7::WC2MB(char * WXUNUSED(buf),
273 const wchar_t * WXUNUSED(psz),
274 size_t WXUNUSED(n)) const
275 {
276 return 0;
277 }
278
279 // ----------------------------------------------------------------------------
280 // UTF-8
281 // ----------------------------------------------------------------------------
282
283 WXDLLEXPORT_DATA(wxMBConvUTF8) wxConvUTF8;
284
285 static wxUint32 utf8_max[]=
286 { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff, 0xffffffff };
287
288 size_t wxMBConvUTF8::MB2WC(wchar_t *buf, const char *psz, size_t n) const
289 {
290 size_t len = 0;
291
292 while (*psz && ((!buf) || (len < n)))
293 {
294 unsigned char cc = *psz++, fc = cc;
295 unsigned cnt;
296 for (cnt = 0; fc & 0x80; cnt++)
297 fc <<= 1;
298 if (!cnt)
299 {
300 // plain ASCII char
301 if (buf)
302 *buf++ = cc;
303 len++;
304 }
305 else
306 {
307 cnt--;
308 if (!cnt)
309 {
310 // invalid UTF-8 sequence
311 return (size_t)-1;
312 }
313 else
314 {
315 unsigned ocnt = cnt - 1;
316 wxUint32 res = cc & (0x3f >> cnt);
317 while (cnt--)
318 {
319 cc = *psz++;
320 if ((cc & 0xC0) != 0x80)
321 {
322 // invalid UTF-8 sequence
323 return (size_t)-1;
324 }
325 res = (res << 6) | (cc & 0x3f);
326 }
327 if (res <= utf8_max[ocnt])
328 {
329 // illegal UTF-8 encoding
330 return (size_t)-1;
331 }
332 #ifdef WC_UTF16
333 size_t pa = encode_utf16(res, buf);
334 if (pa == (size_t)-1)
335 return (size_t)-1;
336 if (buf)
337 buf += pa;
338 len += pa;
339 #else
340 if (buf)
341 *buf++ = res;
342 len++;
343 #endif
344 }
345 }
346 }
347 if (buf && (len < n))
348 *buf = 0;
349 return len;
350 }
351
352 size_t wxMBConvUTF8::WC2MB(char *buf, const wchar_t *psz, size_t n) const
353 {
354 size_t len = 0;
355
356 while (*psz && ((!buf) || (len < n)))
357 {
358 wxUint32 cc;
359 #ifdef WC_UTF16
360 size_t pa = decode_utf16(psz, cc);
361 psz += (pa == (size_t)-1) ? 1 : pa;
362 #else
363 cc=(*psz++) & 0x7fffffff;
364 #endif
365 unsigned cnt;
366 for (cnt = 0; cc > utf8_max[cnt]; cnt++) {}
367 if (!cnt)
368 {
369 // plain ASCII char
370 if (buf)
371 *buf++ = cc;
372 len++;
373 }
374
375 else
376 {
377 len += cnt + 1;
378 if (buf)
379 {
380 *buf++ = (-128 >> cnt) | ((cc >> (cnt * 6)) & (0x3f >> cnt));
381 while (cnt--)
382 *buf++ = 0x80 | ((cc >> (cnt * 6)) & 0x3f);
383 }
384 }
385 }
386
387 if (buf && (len<n)) *buf = 0;
388 return len;
389 }
390
391 // ----------------------------------------------------------------------------
392 // specified character set
393 // ----------------------------------------------------------------------------
394
395 WXDLLEXPORT_DATA(wxCSConv) wxConvLocal((const wxChar *)NULL);
396
397 #include "wx/encconv.h"
398 #include "wx/fontmap.h"
399
400 // TODO: add some tables here
401 // - perhaps common encodings to common codepages (for Win32)
402 // - perhaps common encodings to objects ("UTF8" -> wxConvUTF8)
403 // - move wxEncodingConverter meat in here
404
405 #if defined(__WIN32__) && !defined(__WXMICROWIN__)
406 #include "wx/msw/registry.h"
407 // this should work if M$ Internet Exploiter is installed
408 static long CharsetToCodepage(const wxChar *name)
409 {
410 if (!name)
411 return GetACP();
412
413 long CP=-1;
414
415 wxString cn(name);
416 do {
417 wxString path(wxT("MIME\\Database\\Charset\\"));
418 path += cn;
419 wxRegKey key(wxRegKey::HKCR, path);
420
421 if (!key.Exists()) break;
422
423 // two cases: either there's an AliasForCharset string,
424 // or there are Codepage and InternetEncoding dwords.
425 // The InternetEncoding gives us the actual encoding,
426 // the Codepage just says which Windows character set to
427 // use when displaying the data.
428 if (key.HasValue(wxT("InternetEncoding")) &&
429 key.QueryValue(wxT("InternetEncoding"), &CP)) break;
430
431 // no encoding, see if it's an alias
432 if (!key.HasValue(wxT("AliasForCharset")) ||
433 !key.QueryValue(wxT("AliasForCharset"), cn)) break;
434 } while (1);
435
436 return CP;
437 }
438 #endif
439
440 class wxCharacterSet
441 {
442 public:
443 wxCharacterSet(const wxChar*name)
444 : cname(name) {}
445 virtual ~wxCharacterSet()
446 {}
447 virtual size_t MB2WC(wchar_t *buf, const char *psz, size_t n)
448 { return (size_t)-1; }
449 virtual size_t WC2MB(char *buf, const wchar_t *psz, size_t n)
450 { return (size_t)-1; }
451 virtual bool usable()
452 { return FALSE; }
453 public:
454 const wxChar*cname;
455 };
456
457 class ID_CharSet : public wxCharacterSet
458 {
459 public:
460 ID_CharSet(const wxChar *name,wxMBConv *cnv)
461 : wxCharacterSet(name), work(cnv) {}
462
463 size_t MB2WC(wchar_t *buf, const char *psz, size_t n)
464 { return work ? work->MB2WC(buf,psz,n) : (size_t)-1; }
465
466 size_t WC2MB(char *buf, const wchar_t *psz, size_t n)
467 { return work ? work->WC2MB(buf,psz,n) : (size_t)-1; }
468
469 bool usable()
470 { return work!=NULL; }
471 public:
472 wxMBConv*work;
473 };
474
475
476 #ifdef HAVE_ICONV_H
477
478 // VS: glibc 2.1.3 is broken in that iconv() conversion to/from UCS4 fails with E2BIG
479 // if output buffer is _exactly_ as big as needed. Such case is (unless there's
480 // yet another bug in glibc) the only case when iconv() returns with (size_t)-1
481 // (which means error) and says there are 0 bytes left in the input buffer --
482 // when _real_ error occurs, bytes-left-in-input buffer is non-zero. Hence,
483 // this alternative test for iconv() failure.
484 // [This bug does not appear in glibc 2.2.]
485 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ <= 1
486 #define ICONV_FAILED(cres, bufLeft) ((cres == (size_t)-1) && \
487 (errno != E2BIG || bufLeft != 0))
488 #else
489 #define ICONV_FAILED(cres, bufLeft) (cres == (size_t)-1)
490 #endif
491
492 class IC_CharSet : public wxCharacterSet
493 {
494 public:
495 IC_CharSet(const wxChar *name)
496 : wxCharacterSet(name)
497 {
498 m2w = iconv_open(WC_NAME, wxConvLibc.cWX2MB(cname));
499 w2m = iconv_open(wxConvLibc.cWX2MB(cname), WC_NAME);
500 }
501
502 ~IC_CharSet()
503 {
504 if ( m2w != (iconv_t)-1 )
505 iconv_close(m2w);
506 if ( w2m != (iconv_t)-1 )
507 iconv_close(w2m);
508 }
509
510 size_t MB2WC(wchar_t *buf, const char *psz, size_t n)
511 {
512 size_t inbuf = strlen(psz);
513 size_t outbuf = n * SIZEOF_WCHAR_T;
514 size_t res, cres;
515 // VS: Use these instead of psz, buf because iconv() modifies its arguments:
516 wchar_t *bufPtr = buf;
517 const char *pszPtr = psz;
518
519 if (buf)
520 {
521 // have destination buffer, convert there
522 #ifdef WX_ICONV_TAKES_CHAR
523 cres = iconv(m2w, (char**)&pszPtr, &inbuf, (char**)&bufPtr, &outbuf);
524 #else
525 cres = iconv(m2w, &pszPtr, &inbuf, (char**)&bufPtr, &outbuf);
526 #endif
527 res = n - (outbuf / SIZEOF_WCHAR_T);
528 // convert to native endianness
529 #ifdef WC_NEED_BSWAP
530 WC_BSWAP(buf /* _not_ bufPtr */, res)
531 #endif
532 }
533 else
534 {
535 // no destination buffer... convert using temp buffer
536 // to calculate destination buffer requirement
537 wchar_t tbuf[8];
538 res = 0;
539 do {
540 bufPtr = tbuf; outbuf = 8*SIZEOF_WCHAR_T;
541 #ifdef WX_ICONV_TAKES_CHAR
542 cres = iconv( m2w, (char**)&pszPtr, &inbuf, (char**)&bufPtr, &outbuf );
543 #else
544 cres = iconv( m2w, &pszPtr, &inbuf, (char**)&bufPtr, &outbuf );
545 #endif
546 res += 8-(outbuf/SIZEOF_WCHAR_T);
547 } while ((cres==(size_t)-1) && (errno==E2BIG));
548 }
549
550 if (ICONV_FAILED(cres, inbuf))
551 return (size_t)-1;
552
553 return res;
554 }
555
556 size_t WC2MB(char *buf, const wchar_t *psz, size_t n)
557 {
558 #if defined(__BORLANDC__) && (__BORLANDC__ > 0x530)
559 size_t inbuf = std::wcslen(psz) * SIZEOF_WCHAR_T;
560 #else
561 size_t inbuf = ::wcslen(psz) * SIZEOF_WCHAR_T;
562 #endif
563 size_t outbuf = n;
564 size_t res, cres;
565
566 #ifdef WC_NEED_BSWAP
567 // need to copy to temp buffer to switch endianness
568 // this absolutely doesn't rock!
569 // (no, doing WC_BSWAP twice on the original buffer won't help, as it
570 // could be in read-only memory, or be accessed in some other thread)
571 wchar_t *tmpbuf=(wchar_t*)malloc((inbuf+1)*SIZEOF_WCHAR_T);
572 memcpy(tmpbuf,psz,(inbuf+1)*SIZEOF_WCHAR_T);
573 WC_BSWAP(tmpbuf, inbuf)
574 psz=tmpbuf;
575 #endif
576 if (buf)
577 {
578 // have destination buffer, convert there
579 #ifdef WX_ICONV_TAKES_CHAR
580 cres = iconv( w2m, (char**)&psz, &inbuf, &buf, &outbuf );
581 #else
582 cres = iconv( w2m, (const char**)&psz, &inbuf, &buf, &outbuf );
583 #endif
584 res = n-outbuf;
585 }
586 else
587 {
588 // no destination buffer... convert using temp buffer
589 // to calculate destination buffer requirement
590 char tbuf[16];
591 res = 0;
592 do {
593 buf = tbuf; outbuf = 16;
594 #ifdef WX_ICONV_TAKES_CHAR
595 cres = iconv( w2m, (char**)&psz, &inbuf, &buf, &outbuf );
596 #else
597 cres = iconv( w2m, (const char**)&psz, &inbuf, &buf, &outbuf );
598 #endif
599 res += 16 - outbuf;
600 } while ((cres==(size_t)-1) && (errno==E2BIG));
601 }
602 #ifdef WC_NEED_BSWAP
603 free(tmpbuf);
604 #endif
605 if (ICONV_FAILED(cres, inbuf))
606 return (size_t)-1;
607
608 return res;
609 }
610
611 bool usable()
612 { return (m2w != (iconv_t)-1) && (w2m != (iconv_t)-1); }
613
614 public:
615 iconv_t m2w, w2m;
616 };
617 #endif
618
619 #if defined(__WIN32__) && !defined(__WXMICROWIN__)
620 class CP_CharSet : public wxCharacterSet
621 {
622 public:
623 CP_CharSet(const wxChar*name)
624 : wxCharacterSet(name), CodePage(CharsetToCodepage(name)) {}
625
626 size_t MB2WC(wchar_t *buf, const char *psz, size_t n)
627 {
628 size_t len =
629 MultiByteToWideChar(CodePage, 0, psz, -1, buf, buf ? n : 0);
630 //VS: returns # of written chars for buf!=NULL and *size*
631 // needed buffer for buf==NULL
632 return len ? (buf ? len : len-1) : (size_t)-1;
633 }
634
635 size_t WC2MB(char *buf, const wchar_t *psz, size_t n)
636 {
637 size_t len = WideCharToMultiByte(CodePage, 0, psz, -1, buf,
638 buf ? n : 0, NULL, NULL);
639 //VS: returns # of written chars for buf!=NULL and *size*
640 // needed buffer for buf==NULL
641 return len ? (buf ? len : len-1) : (size_t)-1;
642 }
643
644 bool usable()
645 { return CodePage != -1; }
646
647 public:
648 long CodePage;
649 };
650 #endif // __WIN32__
651
652 #if wxUSE_FONTMAP
653
654 class EC_CharSet : public wxCharacterSet
655 {
656 public:
657 // temporarily just use wxEncodingConverter stuff,
658 // so that it works while a better implementation is built
659 EC_CharSet(const wxChar*name) : wxCharacterSet(name),
660 enc(wxFONTENCODING_SYSTEM)
661 {
662 if (name)
663 enc = wxTheFontMapper->CharsetToEncoding(name, FALSE);
664 m2w.Init(enc, wxFONTENCODING_UNICODE);
665 w2m.Init(wxFONTENCODING_UNICODE, enc);
666 }
667
668 size_t MB2WC(wchar_t *buf, const char *psz, size_t n)
669 {
670 size_t inbuf = strlen(psz);
671 if (buf)
672 m2w.Convert(psz,buf);
673 return inbuf;
674 }
675
676 size_t WC2MB(char *buf, const wchar_t *psz, size_t n)
677 {
678 #if defined(__BORLANDC__) && (__BORLANDC__ > 0x530)
679 size_t inbuf = std::wcslen(psz);
680 #else
681 size_t inbuf = ::wcslen(psz);
682 #endif
683 if (buf)
684 w2m.Convert(psz,buf);
685
686 return inbuf;
687 }
688
689 bool usable()
690 { return (enc!=wxFONTENCODING_SYSTEM) && (enc!=wxFONTENCODING_DEFAULT); }
691
692 public:
693 wxFontEncoding enc;
694 wxEncodingConverter m2w, w2m;
695 };
696
697 #endif // wxUSE_FONTMAP
698
699 static wxCharacterSet *wxGetCharacterSet(const wxChar *name)
700 {
701 wxCharacterSet *cset = NULL;
702 if (name)
703 {
704 if (wxStricmp(name, wxT("UTF8")) == 0 || wxStricmp(name, wxT("UTF-8")) == 0)
705 {
706 cset = new ID_CharSet(name, &wxConvUTF8);
707 }
708 else
709 {
710 #ifdef HAVE_ICONV_H
711 cset = new IC_CharSet(name); // may not take NULL
712 #endif
713 }
714 }
715
716 if (cset && cset->usable())
717 return cset;
718
719 if (cset)
720 {
721 delete cset;
722 cset = NULL;
723 }
724
725 #if defined(__WIN32__) && !defined(__WXMICROWIN__)
726 cset = new CP_CharSet(name); // may take NULL
727 if (cset->usable())
728 return cset;
729
730 delete cset;
731 #endif // __WIN32__
732
733 #if wxUSE_FONTMAP
734 cset = new EC_CharSet(name);
735 if (cset->usable())
736 return cset;
737 #endif // wxUSE_FONTMAP
738
739 delete cset;
740 wxLogError(_("Unknown encoding '%s'!"), name);
741 return NULL;
742 }
743
744 wxCSConv::wxCSConv(const wxChar *charset)
745 {
746 m_name = (wxChar *)NULL;
747 m_cset = (wxCharacterSet *) NULL;
748 m_deferred = TRUE;
749
750 SetName(charset);
751 }
752
753 wxCSConv::~wxCSConv()
754 {
755 free(m_name);
756 delete m_cset;
757 }
758
759 void wxCSConv::SetName(const wxChar *charset)
760 {
761 if (charset)
762 {
763 m_name = wxStrdup(charset);
764 m_deferred = TRUE;
765 }
766 }
767
768 void wxCSConv::LoadNow()
769 {
770 if (m_deferred)
771 {
772 if ( !m_name )
773 {
774 wxString name = wxLocale::GetSystemEncodingName();
775 if ( !name.empty() )
776 SetName(name);
777 }
778
779 // wxGetCharacterSet() complains about NULL name
780 m_cset = m_name ? wxGetCharacterSet(m_name) : NULL;
781 m_deferred = FALSE;
782 }
783 }
784
785 size_t wxCSConv::MB2WC(wchar_t *buf, const char *psz, size_t n) const
786 {
787 ((wxCSConv *)this)->LoadNow(); // discard constness
788
789 if (m_cset)
790 return m_cset->MB2WC(buf, psz, n);
791
792 // latin-1 (direct)
793 size_t len = strlen(psz);
794
795 if (buf)
796 {
797 for (size_t c = 0; c <= len; c++)
798 buf[c] = (unsigned char)(psz[c]);
799 }
800
801 return len;
802 }
803
804 size_t wxCSConv::WC2MB(char *buf, const wchar_t *psz, size_t n) const
805 {
806 ((wxCSConv *)this)->LoadNow(); // discard constness
807
808 if (m_cset)
809 return m_cset->WC2MB(buf, psz, n);
810
811 // latin-1 (direct)
812 #if defined(__BORLANDC__) && (__BORLANDC__ > 0x530)
813 size_t len=std::wcslen(psz);
814 #else
815 size_t len=::wcslen(psz);
816 #endif
817 if (buf)
818 {
819 for (size_t c = 0; c <= len; c++)
820 buf[c] = (psz[c] > 0xff) ? '?' : psz[c];
821 }
822
823 return len;
824 }
825
826 #ifdef HAVE_ICONV_H
827
828 class IC_CharSetConverter
829 {
830 public:
831 IC_CharSetConverter(IC_CharSet *from, IC_CharSet *to)
832 {
833 cnv = iconv_open(wxConvLibc.cWX2MB(to->cname),
834 wxConvLibc.cWX2MB(from->cname));
835 }
836
837 ~IC_CharSetConverter()
838 {
839 if (cnv != (iconv_t)-1)
840 iconv_close(cnv);
841 }
842
843 size_t Convert(char *buf, const char *psz, size_t n)
844 {
845 size_t inbuf = strlen(psz);
846 size_t outbuf = n;
847 #ifdef WX_ICONV_TAKES_CHAR
848 size_t res = iconv( cnv, (char**)&psz, &inbuf, &buf, &outbuf );
849 #else
850 size_t res = iconv( cnv, &psz, &inbuf, &buf, &outbuf );
851 #endif
852 if (res == (size_t)-1)
853 return (size_t)-1;
854 return (n - outbuf);
855 }
856
857 public:
858 iconv_t cnv;
859 };
860
861 #endif // HAVE_ICONV_H
862
863 class EC_CharSetConverter
864 {
865 public:
866 EC_CharSetConverter(EC_CharSet* from,EC_CharSet* to)
867 { cnv.Init(from->enc,to->enc); }
868
869 size_t Convert(char* buf, const char* psz, size_t n)
870 {
871 size_t inbuf = strlen(psz);
872 if (buf) cnv.Convert(psz,buf);
873 return inbuf;
874 }
875
876 public:
877 wxEncodingConverter cnv;
878 };
879
880 #else // !wxUSE_WCHAR_T
881
882 // ----------------------------------------------------------------------------
883 // stand-ins in absence of wchar_t
884 // ----------------------------------------------------------------------------
885
886 WXDLLEXPORT_DATA(wxMBConv) wxConvLibc, wxConvFile;
887
888 #endif // wxUSE_WCHAR_T
889
890