1/*
2 * Copyright 1992, 1993 by TOSHIBA Corp.
3 *
4 * Permission to use, copy, modify, and distribute this software and its
5 * documentation for any purpose and without fee is hereby granted, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of TOSHIBA not be used in advertising
9 * or publicity pertaining to distribution of the software without specific,
10 * written prior permission. TOSHIBA make no representations about the
11 * suitability of this software for any purpose.  It is provided "as is"
12 * without express or implied warranty.
13 *
14 * TOSHIBA DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16 * TOSHIBA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20 * SOFTWARE.
21 *
22 * Author: Katsuhisa Yano	TOSHIBA Corp.
23 *			   	mopi@osa.ilab.toshiba.co.jp
24 */
25/*
26 * 2000
27 * Modifier: Ivan Pascal        The XFree86 Project
28 */
29
30/*
31 * The default locale loader.
32 * Supports: one byte per char (iso8859 like) locales.
33 * How: converts bytes to wide characters in a 1:1 manner.
34 * Platforms: all systems.
35 */
36
37#ifdef HAVE_CONFIG_H
38#include <config.h>
39#endif
40#include "Xlibint.h"
41#include "XlcGeneric.h"
42
43#ifndef MB_LEN_MAX
44#define MB_LEN_MAX 6
45#endif
46
47#ifndef X_LOCALE
48#define STDCVT
49#endif
50
51#define GR	0x80
52#define GL	0x7f
53
54typedef struct _StateRec *State;
55typedef struct _StateRec {
56    CodeSet     GL_codeset;
57    CodeSet     GR_codeset;
58    wchar_t     wc_mask;
59    wchar_t     wc_encode_mask;
60    Bool        (*MBtoWC) (State state, const char *ch, wchar_t *wc);
61    Bool        (*WCtoMB) (State state, wchar_t wc, char *ch);
62} StateRec;
63
64static
65Bool MBtoWCdef(
66    State    state,
67    const char *ch,
68    wchar_t  *wc)
69{
70    wchar_t wc_encoding;
71    CodeSet codeset = (*ch & GR) ? state->GR_codeset : state->GL_codeset;
72    if (!codeset)
73	return False;
74    wc_encoding = codeset->wc_encoding;
75    *wc = ((wchar_t) *ch & state->wc_mask) | wc_encoding;
76    return True;
77}
78
79#ifdef STDCVT
80static
81Bool MBtoWCstd(
82    State   state,
83    const char *ch,
84    wchar_t *wc)
85{
86    return (mbtowc(wc, ch, 1) == 1);
87}
88#endif
89
90static
91Bool WCtoMBdef(
92    State   state,
93    wchar_t wc,
94    char    *ch)
95{
96    wchar_t wc_encoding = wc & state->wc_encode_mask;
97    CodeSet codeset;
98
99    codeset = state->GL_codeset;
100    if (codeset && (wc_encoding == codeset->wc_encoding)) {
101	*ch = wc & state->wc_mask;
102	return True;
103    }
104    codeset = state->GR_codeset;
105    if (codeset && (wc_encoding == codeset->wc_encoding)) {
106	*ch = (wc & state->wc_mask) | GR;
107	return True;
108    }
109    return False;
110}
111
112#ifdef STDCVT
113static
114Bool WCtoMBstd(
115    State   state,
116    wchar_t wc,
117    char    *ch)
118{
119    return (wctomb(ch, wc) == 1);
120}
121#endif
122
123static
124XlcCharSet get_charset(
125    State  state,
126    char   side)
127{
128    CodeSet codeset = side ? state->GR_codeset : state->GL_codeset;
129    if (codeset) {
130	int i;
131	XlcCharSet charset;
132	for (i = 0; i < codeset->num_charsets; i++) {
133	    charset = codeset->charset_list[i];
134	    if (*charset->ct_sequence != '\0')
135		return charset;
136	}
137	return *(codeset->charset_list);
138    }
139    return (XlcCharSet) NULL;
140}
141
142static int
143def_mbstowcs(
144    XlcConv conv,
145    XPointer *from,
146    int *from_left,
147    XPointer *to,
148    int *to_left,
149    XPointer *args,
150    int num_args)
151{
152    const char *src;
153    wchar_t *dst = (wchar_t *) *to;
154    State state = (State) conv->state;
155    int unconv = 0;
156
157    if (from == NULL || *from == NULL)
158	return 0;
159
160    src = (const char *) *from;
161
162    while (*from_left && *to_left) {
163	(*from_left)--;
164	if (state->MBtoWC (state, src++, dst)) {
165	    dst++;
166	    (*to_left)--;
167	} else {
168	    unconv++;
169	}
170    }
171    *from = (XPointer) src;
172    *to = (XPointer) dst;
173    return unconv;
174}
175
176static int
177def_wcstombs(
178    XlcConv conv,
179    XPointer *from,
180    int *from_left,
181    XPointer *to,
182    int *to_left,
183    XPointer *args,
184    int num_args)
185{
186    const wchar_t *src;
187    char  *dst = (char *) *to;
188    State state = (State) conv->state;
189    char ch[MB_LEN_MAX];
190    int unconv = 0;
191
192    if (from == NULL || *from == NULL)
193	return 0;
194
195    src = (const wchar_t *) *from;
196
197    while (*from_left && *to_left) {
198	(*from_left)--;
199	if (state->WCtoMB (state, *src++, ch)) {
200	    *dst++ = *ch;
201	    (*to_left)--;
202	} else {
203	    unconv++;
204	}
205    }
206    *from = (XPointer) src;
207    *to = (XPointer) dst;
208    return unconv;
209}
210
211static int
212mbstostr(
213    XlcConv conv,
214    XPointer *from,
215    int *from_left,
216    XPointer *to,
217    int *to_left,
218    XPointer *args,
219    int num_args)
220{
221    const char *src;
222    char *dst = (char *) *to;
223    CodeSet codeset;
224    State state = (State) conv->state;
225    char ch;
226    int unconv = 0;
227
228    if (from == NULL || *from == NULL)
229	return 0;
230
231    src = (const char *) *from;
232
233    while (*from_left && *to_left) {
234	ch = *src++;
235	(*from_left)--;
236
237	codeset = (ch & GR) ? state->GR_codeset : state->GL_codeset;
238	if (codeset && codeset->string_encoding) {
239	    *dst++ = ch;
240	    (*to_left)--;
241	} else {
242	    unconv++;
243	}
244    }
245    *from = (XPointer) src;
246    *to = (XPointer) dst;
247    return unconv;
248}
249
250static int
251wcstostr(
252    XlcConv conv,
253    XPointer *from,
254    int *from_left,
255    XPointer *to,
256    int *to_left,
257    XPointer *args,
258    int num_args)
259{
260    const wchar_t *src;
261    char *dst = (char *) *to;
262    CodeSet codeset;
263    State state = (State) conv->state;
264    char ch[MB_LEN_MAX];
265    int unconv = 0;
266
267    if (from == NULL || *from == NULL)
268	return 0;
269
270    src = (const wchar_t *) *from;
271
272    while (*from_left && *to_left) {
273	(*from_left)--;
274	if (state->WCtoMB (state, *src++, ch)) {
275	    codeset = (*ch & GR) ? state->GR_codeset : state->GL_codeset;
276	    if (codeset && codeset->string_encoding) {
277		*dst++ = *ch;
278		(*to_left)--;
279	    } else {
280		unconv++;
281	    }
282	} else {
283	    unconv++;
284	}
285    }
286    *from = (XPointer) src;
287    *to = (XPointer) dst;
288    return unconv;
289}
290
291static int
292mbstocs(
293    XlcConv conv,
294    XPointer *from,
295    int *from_left,
296    XPointer *to,
297    int *to_left,
298    XPointer *args,
299    int num_args)
300{
301    const char *src;
302    char *dst = (char *) *to;
303    int length;
304    State state = (State) conv->state;
305    char cur_side;
306    int unconv = 0;
307
308    if (from == NULL || *from == NULL)
309	return 0;
310
311    src = (const char *) *from;
312    length = min(*from_left, *to_left);
313
314    cur_side = *src & GR;
315    while (length) {
316	if ((char) (*src & GR) != cur_side)
317	    break;
318	*dst++ = *src++;
319	length--;
320    }
321
322    if (num_args > 0) {
323	XlcCharSet      charset = get_charset(state, cur_side);
324	if (charset) {
325	    *((XlcCharSet *) args[0]) = charset;
326	} else {
327	    dst = *to;
328	    unconv = -1;
329	}
330    }
331    *from_left -= src - (char *) *from;
332    *to_left -= dst - (char *) *to;
333    *from = (XPointer) src;
334    *to = (XPointer) dst;
335    return unconv;
336}
337
338static int
339wcstocs(
340    XlcConv conv,
341    XPointer *from,
342    int *from_left,
343    XPointer *to,
344    int *to_left,
345    XPointer *args,
346    int num_args)
347{
348    const wchar_t *src;
349    char *dst = (char *) *to;
350    State state = (State) conv->state;
351    char cur_side = 0, ch[MB_LEN_MAX];
352    int unconv = 0;
353    Bool found = False;
354
355    if (from == NULL || *from == NULL)
356	return 0;
357
358    src = (const wchar_t *) *from;
359
360    while (*from_left) {
361	if ((found = state->WCtoMB (state, *src, ch)))
362	    break;
363	unconv++;
364	src++;
365	(*from_left)--;
366    }
367
368    if (found) {
369	cur_side = *ch & GR;
370	while (*from_left && *to_left) {
371	    (*from_left)--;
372	    if (state->WCtoMB (state, *src++, ch)) {
373		if ((char) (*ch & GR) != cur_side) {
374		    src--;
375		    (*from_left)++;
376		    break;
377		} else {
378		    *dst++ = *ch;
379		    (*to_left)--;
380		}
381	    } else {
382		unconv++;
383	    }
384	}
385    } else {
386	unconv++;
387    }
388
389    if (num_args > 0) {
390	XlcCharSet charset = get_charset(state, cur_side);
391	if (charset) {
392	    *((XlcCharSet *) args[0]) = charset;
393	} else {
394	    unconv = -1;
395	}
396    }
397    *from = (XPointer) src;
398    *to = (XPointer) dst;
399    return unconv;
400}
401
402static int
403cstombs(
404    XlcConv conv,
405    XPointer *from,
406    int *from_left,
407    XPointer *to,
408    int *to_left,
409    XPointer *args,
410    int num_args)
411{
412    const char *src;
413    char *dst = (char *) *to;
414    CodeSet codeset;
415    XlcCharSet charset;
416    State state = (State) conv->state;
417    unsigned char cur_side = 0;
418    int i;
419    Bool found = False;
420
421    if (from == NULL || *from == NULL)
422	return 0;
423
424    src = (const char *) *from;
425
426    if (num_args > 0) {
427	charset = (XlcCharSet) args[0];
428	if (charset == NULL)
429	    return -1;
430    } else {
431	return -1;
432    }
433
434    if ((charset->side == XlcGL) || (charset->side == XlcGLGR)) {
435	codeset = state->GL_codeset;
436	if (codeset) {
437	    for (i = 0; i < codeset->num_charsets; i++)
438		if (charset == codeset->charset_list[i]) {
439		    found = True;
440		    cur_side = 0;
441		    break;
442		}
443	}
444    }
445    if (!found && ((charset->side == XlcGR) || (charset->side == XlcGLGR))) {
446	codeset = state->GR_codeset;
447	if (codeset) {
448	    for (i = 0; i < codeset->num_charsets; i++)
449		if (charset == codeset->charset_list[i]) {
450		    found = True;
451		    cur_side = GR;
452		    break;
453		}
454	}
455    }
456    if (found) {
457	int length = min(*from_left, *to_left);
458	while (length) {
459	    *dst++ = *src++ | cur_side;
460	    length--;
461	}
462    } else {
463	return -1;
464    }
465
466    *from_left -= src - (char *) *from;
467    *to_left -= dst - (char *) *to;
468    *from = (XPointer) src;
469    *to = (XPointer) dst;
470    return 0;
471}
472
473static int
474cstowcs(
475    XlcConv conv,
476    XPointer *from,
477    int *from_left,
478    XPointer *to,
479    int *to_left,
480    XPointer *args,
481    int num_args)
482{
483    const char *src;
484    wchar_t *dst = (wchar_t *) *to;
485    CodeSet codeset;
486    XlcCharSet charset;
487    State state = (State) conv->state;
488    Bool found = False;
489    int i, unconv = 0;
490    unsigned char cur_side = 0;
491
492    if (from == NULL || *from == NULL)
493	return 0;
494
495    src = (const char *) *from;
496
497    if (num_args > 0) {
498	charset = (XlcCharSet) args[0];
499	if (charset == NULL)
500	    return -1;
501    } else {
502	return -1;
503    }
504
505    if ((charset->side == XlcGL) || (charset->side == XlcGLGR)) {
506	codeset = state->GL_codeset;
507	if (codeset) {
508	    for (i = 0; i < codeset->num_charsets; i++)
509		if (charset == codeset->charset_list[i]) {
510		    found = True;
511		    cur_side = 0;
512		    break;
513		}
514	}
515    }
516    if (!found && ((charset->side == XlcGR) || (charset->side == XlcGLGR))) {
517	codeset = state->GR_codeset;
518	if (codeset) {
519	    for (i = 0; i < codeset->num_charsets; i++)
520		if (charset == codeset->charset_list[i]) {
521		    found = True;
522		    cur_side = GR;
523		    break;
524		}
525	}
526    }
527    if (found) {
528	char ch;
529	while (*from_left && *to_left) {
530	    ch = *src++ | cur_side;
531	    (*from_left)--;
532	    if (state->MBtoWC (state, &ch, dst)) {
533		dst++;
534		(*to_left)--;
535	    } else {
536		unconv++;
537	    }
538	}
539    } else {
540	return -1;
541    }
542    *from = (XPointer) src;
543    *to = (XPointer) dst;
544    return unconv;
545}
546
547static int
548strtombs(
549    XlcConv conv,
550    XPointer *from,
551    int *from_left,
552    XPointer *to,
553    int *to_left,
554    XPointer *args,
555    int num_args)
556{
557    const char *src;
558    char *dst = (char *) *to;
559    int length;
560
561    if (from == NULL || *from == NULL)
562	return 0;
563
564    src = (const char *) *from;
565    length = min(*from_left, *to_left);
566    while (length) {
567	*dst++ = *src++;
568	length--;
569    }
570
571    *from_left -= src - (char *) *from;
572    *to_left -= dst - (char *) *to;
573    *from = (XPointer) src;
574    *to = (XPointer) dst;
575    return 0;
576}
577
578static void
579close_converter(
580    XlcConv conv)
581{
582
583    Xfree(conv->state);
584    Xfree(conv);
585}
586
587static XlcConv
588create_conv(
589    XLCd lcd,
590    XlcConvMethods methods)
591{
592    XlcConv conv;
593    State state;
594
595    conv = Xcalloc(1, sizeof(XlcConvRec));
596    if (conv == NULL)
597	return (XlcConv) NULL;
598
599    state = Xmalloc(sizeof(StateRec));
600    if (state == NULL) {
601	close_converter(conv);
602	return (XlcConv) NULL;
603    }
604    state->GL_codeset = XLC_GENERIC(lcd, initial_state_GL);
605    state->GR_codeset = XLC_GENERIC(lcd, initial_state_GR);
606    state->wc_mask = (1 << XLC_GENERIC(lcd, wc_shift_bits)) - 1;
607    state->wc_encode_mask = XLC_GENERIC(lcd, wc_encode_mask);
608
609#ifdef STDCVT
610    if (XLC_GENERIC(lcd, use_stdc_env) == True)
611	state->MBtoWC = &MBtoWCstd;
612    else
613#endif
614	state->MBtoWC = &MBtoWCdef;
615
616#ifdef STDCVT
617    if (XLC_GENERIC(lcd, use_stdc_env) == True)
618	state->WCtoMB = &WCtoMBstd;
619    else
620#endif
621	state->WCtoMB = &WCtoMBdef;
622
623    conv->methods = methods;
624    conv->state = (XPointer) state;
625
626    return conv;
627}
628
629static XlcConvMethodsRec mbstowcs_methods = {
630    close_converter,
631    def_mbstowcs,
632    NULL
633};
634
635static XlcConv
636open_mbstowcs(
637    XLCd from_lcd,
638    const char *from_type,
639    XLCd to_lcd,
640    const char *to_type)
641{
642    return create_conv(from_lcd, &mbstowcs_methods);
643}
644
645static XlcConvMethodsRec mbstostr_methods = {
646    close_converter,
647    mbstostr,
648    NULL
649};
650
651static XlcConv
652open_mbstostr(
653    XLCd from_lcd,
654    const char *from_type,
655    XLCd to_lcd,
656    const char *to_type)
657{
658    return create_conv(from_lcd, &mbstostr_methods);
659}
660
661static XlcConvMethodsRec mbstocs_methods = {
662    close_converter,
663    mbstocs,
664    NULL
665};
666
667static XlcConv
668open_mbstocs(
669    XLCd from_lcd,
670    const char *from_type,
671    XLCd to_lcd,
672    const char *to_type)
673{
674    return create_conv(from_lcd, &mbstocs_methods);
675}
676
677static XlcConvMethodsRec wcstombs_methods = {
678    close_converter,
679    def_wcstombs,
680    NULL
681};
682
683static XlcConv
684open_wcstombs(
685    XLCd from_lcd,
686    const char *from_type,
687    XLCd to_lcd,
688    const char *to_type)
689{
690    return create_conv(from_lcd, &wcstombs_methods);
691}
692
693static XlcConvMethodsRec wcstostr_methods = {
694    close_converter,
695    wcstostr,
696    NULL
697};
698
699static XlcConv
700open_wcstostr(
701    XLCd from_lcd,
702    const char *from_type,
703    XLCd to_lcd,
704    const char *to_type)
705{
706    return create_conv(from_lcd, &wcstostr_methods);
707}
708
709static XlcConvMethodsRec wcstocs_methods = {
710    close_converter,
711    wcstocs,
712    NULL
713};
714
715static XlcConv
716open_wcstocs(
717    XLCd from_lcd,
718    const char *from_type,
719    XLCd to_lcd,
720    const char *to_type)
721{
722    return create_conv(from_lcd, &wcstocs_methods);
723}
724
725static XlcConvMethodsRec strtombs_methods = {
726    close_converter,
727    strtombs,
728    NULL
729};
730
731static XlcConv
732open_strtombs(
733    XLCd from_lcd,
734    const char *from_type,
735    XLCd to_lcd,
736    const char *to_type)
737{
738    return create_conv(from_lcd, &strtombs_methods);
739}
740
741static XlcConvMethodsRec cstombs_methods = {
742    close_converter,
743    cstombs,
744    NULL
745};
746
747static XlcConv
748open_cstombs(
749    XLCd from_lcd,
750    const char *from_type,
751    XLCd to_lcd,
752    const char *to_type)
753{
754    return create_conv(from_lcd, &cstombs_methods);
755}
756
757static XlcConvMethodsRec cstowcs_methods = {
758    close_converter,
759    cstowcs,
760    NULL
761};
762
763static XlcConv
764open_cstowcs(
765    XLCd from_lcd,
766    const char *from_type,
767    XLCd to_lcd,
768    const char *to_type)
769{
770    return create_conv(from_lcd, &cstowcs_methods);
771}
772
773XLCd
774_XlcDefaultLoader(
775    const char *name)
776{
777    XLCd lcd;
778
779    lcd = _XlcCreateLC(name, _XlcGenericMethods);
780    if (lcd == NULL)
781	return lcd;
782
783    if (XLC_PUBLIC(lcd, mb_cur_max) != 1){
784        _XlcDestroyLC(lcd);
785        return (XLCd) NULL;
786    }
787
788    _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNWideChar, open_mbstowcs);
789    _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNString, open_mbstostr);
790    _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNCharSet, open_mbstocs);
791    _XlcSetConverter(lcd, XlcNMultiByte, lcd, XlcNChar, open_mbstocs);
792
793    _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNMultiByte, open_wcstombs);
794    _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNString, open_wcstostr);
795    _XlcSetConverter(lcd, XlcNWideChar, lcd, XlcNCharSet, open_wcstocs);
796
797    _XlcSetConverter(lcd, XlcNString, lcd, XlcNMultiByte, open_strtombs);
798    _XlcSetConverter(lcd, XlcNString, lcd, XlcNWideChar, open_mbstowcs);
799
800    _XlcSetConverter(lcd, XlcNCharSet, lcd, XlcNMultiByte, open_cstombs);
801    _XlcSetConverter(lcd, XlcNCharSet, lcd, XlcNWideChar, open_cstowcs);
802
803    _XlcAddUtf8Converters(lcd);
804
805    return lcd;
806}
807