Silly of me to overlook it: another obvious way you might like to
[sgt/charset] / toucs.c
CommitLineData
c6d25d8d 1/*
2 * toucs.c - convert charsets to Unicode.
3 */
4
5#include "charset.h"
6#include "internal.h"
7
8struct unicode_emit_param {
9 wchar_t *output;
10 int outlen;
49152469 11 int writtenlen;
c6d25d8d 12 const wchar_t *errstr;
13 int errlen;
14 int stopped;
15};
16
17static 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
49152469 39 if (param->outlen < 0 || param->outlen >= outlen) {
c6d25d8d 40 while (outlen > 0) {
49152469 41 if (param->output)
42 *param->output++ = *p++;
43 if (param->outlen > 0)
44 param->outlen--;
c6d25d8d 45 outlen--;
49152469 46 param->writtenlen++;
c6d25d8d 47 }
48 } else {
49 param->stopped = 1;
50 }
51}
52
53int 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;
49152469 66 param.writtenlen = 0;
c6d25d8d 67 param.stopped = 0;
68
69 if (state)
70 localstate = *state; /* structure copy */
71
72 while (*inlen > 0) {
49152469 73 int lenbefore = param.writtenlen;
c6d25d8d 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
49152469 91 return param.writtenlen;
c6d25d8d 92}