1 /*
2  * toucs.c - convert charsets to Unicode.
3  */
4 
5 #include "charset.h"
6 #include "internal.h"
7 
8 struct unicode_emit_param {
9     wchar_t *output;
10     int outlen;
11     int writtenlen;
12     const wchar_t *errstr;
13     int errlen;
14     int stopped;
15 };
16 
unicode_emit(void * ctx,long int output)17 static void unicode_emit(void *ctx, long int output)
18 {
19     struct unicode_emit_param *param = (struct unicode_emit_param *)ctx;
20     wchar_t outval;
21     wchar_t const *p;
22     int outlen;
23 
24     if (output == ERROR) {
25 	if (param->errstr) {
26 	    p = param->errstr;
27 	    outlen = param->errlen;
28 	} else {
29 	    outval = 0xFFFD;	       /* U+FFFD REPLACEMENT CHARACTER */
30 	    p = &outval;
31 	    outlen = 1;
32 	}
33     } else {
34 	outval = output;
35 	p = &outval;
36 	outlen = 1;
37     }
38 
39     if (param->outlen < 0 || param->outlen >= outlen) {
40 	while (outlen > 0) {
41 	    if (param->output)
42 		*param->output++ = *p++;
43 	    if (param->outlen > 0)
44 		param->outlen--;
45 	    outlen--;
46 	    param->writtenlen++;
47 	}
48     } else {
49 	param->stopped = 1;
50     }
51 }
52 
charset_to_unicode(const char ** input,int * inlen,wchar_t * output,int outlen,int charset,charset_state * state,const wchar_t * errstr,int errlen)53 int charset_to_unicode(const char **input, int *inlen,
54 		       wchar_t *output, int outlen,
55 		       int charset, charset_state *state,
56 		       const wchar_t *errstr, int errlen)
57 {
58     charset_spec const *spec = charset_find_spec(charset);
59     charset_state localstate = CHARSET_INIT_STATE;
60     struct unicode_emit_param param;
61 
62     param.output = output;
63     param.outlen = outlen;
64     param.errstr = errstr;
65     param.errlen = errlen;
66     param.writtenlen = 0;
67     param.stopped = 0;
68 
69     if (state)
70 	localstate = *state;	       /* structure copy */
71 
72     while (*inlen > 0) {
73 	int lenbefore = param.writtenlen;
74 	spec->read(spec, (unsigned char)**input, &localstate,
75 		   unicode_emit, &param);
76 	if (param.stopped) {
77 	    /*
78 	     * The emit function has _tried_ to output some
79 	     * characters, but ran up against the end of the
80 	     * buffer. Leave immediately, and return what happened
81 	     * _before_ attempting to process this character.
82 	     */
83 	    return lenbefore;
84 	}
85 	if (state)
86 	    *state = localstate;   /* structure copy */
87 	(*input)++;
88 	(*inlen)--;
89     }
90 
91     return param.writtenlen;
92 }
93