1 /*
2 * This file is part of the TINICONV Library.
3 *
4 * The TINICONV Library is free software; you can redistribute it
5 * and/or modify it under the terms of the GNU Library General Public
6 * License version 2 as published by the Free Software Foundation.
7 */
8 // ----------------------------------------------------------------------------
9 // Copyright (C) 2014
10 // David Freese, W1HKJ
11 //
12 // This file is part of fldigi
13 //
14 // fldigi is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 // ----------------------------------------------------------------------------
22
23 #include "tiniconv.h"
24 #include "tiniconv_int.h"
25
26 #include <string.h>
27 #include <assert.h>
28
tiniconv_init(int in_charset_id,int out_charset_id,int options,struct tiniconv_ctx_s * ctx)29 int tiniconv_init(int in_charset_id, int out_charset_id, int options, struct tiniconv_ctx_s *ctx)
30 {
31 assert(ctx != NULL);
32
33 if (in_charset_id < 0 || in_charset_id >= TINICONV_CHARSETSIZE)
34 return TINICONV_INIT_IN_CHARSET_NA;
35 if (out_charset_id < 0 || out_charset_id >= TINICONV_CHARSETSIZE)
36 return TINICONV_INIT_OUT_CHARSET_NA;
37
38 memset(ctx, 0, sizeof(*ctx));
39 ctx->mb2wc = tiniconv_charset_map[in_charset_id].mb2wc;
40 ctx->flushwc = tiniconv_charset_map[in_charset_id].flushwc;
41 ctx->wc2mb = tiniconv_charset_map[out_charset_id].wc2mb;
42 ctx->reset = tiniconv_charset_map[out_charset_id].reset;
43 ctx->options = options;
44 if (!TINICONV_OPTION_GET_OUT_ILSEQ_CHAR(options))
45 ctx->options = ctx->options | TINICONV_OPTION_OUT_ILSEQ_CHAR('?');
46
47 return TINICONV_INIT_OK;
48 }
49
tiniconv_convert(struct tiniconv_ctx_s * ctx,unsigned char const * in_buf,int in_size,int * p_in_size_consumed,unsigned char * out_buf,int out_size,int * p_out_size_consumed)50 int tiniconv_convert(struct tiniconv_ctx_s *ctx,
51 unsigned char const *in_buf, int in_size, int *p_in_size_consumed,
52 unsigned char *out_buf, int out_size, int *p_out_size_consumed)
53 {
54 ucs4_t wc;
55 int in_idx, out_idx;
56 int result, last_result;
57 conv_state_t last_istate;
58
59 assert(ctx != NULL);
60 assert(in_buf != NULL);
61 assert(out_buf != NULL);
62
63 for (in_idx = 0, out_idx = 0; in_idx < in_size && out_idx < out_size;)
64 {
65 last_istate = ctx->istate;
66 /* typedef int (*xxx_mb2wc_t) (conv_t conv, ucs4_t *pwc, unsigned char const *s, int n); */
67 result = ctx->mb2wc(ctx, &wc, in_buf + in_idx, in_size - in_idx);
68 assert(result <= in_size - in_idx);
69 if (result < 0)
70 {
71 if (result == RET_ILSEQ)
72 {
73 if (ctx->options & TINICONV_OPTION_IGNORE_IN_ILSEQ)
74 {
75 ctx->istate = 0;
76 in_idx ++;
77 continue;
78 }
79 else
80 {
81 result = TINICONV_CONVERT_IN_ILSEQ;
82 goto exit;
83 }
84 }
85 else if (result == RET_TOOSMALL)
86 {
87 result = TINICONV_CONVERT_IN_TOO_SMALL;
88 goto exit;
89 }
90 else
91 {
92 in_idx += RET_TOOFEW(result);
93 continue;
94 }
95 }
96 in_idx += last_result = result;
97
98 /* typedef int (*xxx_wc2mb_t) (conv_t conv, unsigned char *r, ucs4_t wc, int n); */
99 result = ctx->wc2mb(ctx, out_buf + out_idx, wc, out_size - out_idx);
100 assert(result <= out_size - out_idx);
101 if (result < 0)
102 {
103 if (result == RET_ILUNI)
104 {
105 if (ctx->options & TINICONV_OPTION_IGNORE_OUT_ILSEQ)
106 {
107 out_buf[out_idx ++] = TINICONV_OPTION_GET_OUT_ILSEQ_CHAR(ctx->options);
108 ctx->ostate = 0;
109 continue;
110 }
111 else
112 {
113 result = TINICONV_CONVERT_OUT_ILSEQ;
114 in_idx -= last_result; /* discarding the last read sequence */
115 ctx->istate = last_istate;
116 goto exit;
117 }
118 }
119 else if (result == RET_TOOSMALL)
120 {
121 result = TINICONV_CONVERT_OUT_TOO_SMALL;
122 in_idx -= last_result; /* discarding the last read sequence */
123 ctx->istate = last_istate;
124 goto exit;
125 }
126 }
127 out_idx += result;
128 }
129 result = TINICONV_CONVERT_OK;
130
131 exit:
132 if (p_in_size_consumed)
133 *p_in_size_consumed = in_idx;
134 if (p_out_size_consumed)
135 *p_out_size_consumed = out_idx;
136 return result;
137 }
138