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