Diffstat (limited to 'libetpan/src/data-types/charconv.c') (more/less context) (ignore whitespace changes)
-rw-r--r-- | libetpan/src/data-types/charconv.c | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/libetpan/src/data-types/charconv.c b/libetpan/src/data-types/charconv.c new file mode 100644 index 0000000..28549c9 --- a/dev/null +++ b/libetpan/src/data-types/charconv.c | |||
@@ -0,0 +1,251 @@ | |||
1 | /* | ||
2 | * libEtPan! -- a mail stuff library | ||
3 | * | ||
4 | * Copyright (C) 2001, 2005 - DINH Viet Hoa | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Redistribution and use in source and binary forms, with or without | ||
8 | * modification, are permitted provided that the following conditions | ||
9 | * are met: | ||
10 | * 1. Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * 2. Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in the | ||
14 | * documentation and/or other materials provided with the distribution. | ||
15 | * 3. Neither the name of the libEtPan! project nor the names of its | ||
16 | * contributors may be used to endorse or promote products derived | ||
17 | * from this software without specific prior written permission. | ||
18 | * | ||
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND | ||
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE | ||
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
29 | * SUCH DAMAGE. | ||
30 | */ | ||
31 | |||
32 | /* | ||
33 | * $Id$ | ||
34 | */ | ||
35 | |||
36 | #include "charconv.h" | ||
37 | |||
38 | #include "config.h" | ||
39 | #ifdef HAVE_ICONV | ||
40 | #include <iconv.h> | ||
41 | #endif | ||
42 | #include <stdlib.h> | ||
43 | #include <string.h> | ||
44 | #include <stdio.h> | ||
45 | #include <errno.h> | ||
46 | |||
47 | #include "mmapstring.h" | ||
48 | |||
49 | #ifdef HAVE_ICONV | ||
50 | static size_t mail_iconv (iconv_t cd, const char **inbuf, size_t *inbytesleft, | ||
51 | char **outbuf, size_t *outbytesleft, | ||
52 | char **inrepls, char *outrepl) | ||
53 | { | ||
54 | size_t ret = 0, ret1; | ||
55 | /* XXX - force const to mutable */ | ||
56 | char *ib = (char *) *inbuf; | ||
57 | size_t ibl = *inbytesleft; | ||
58 | char *ob = *outbuf; | ||
59 | size_t obl = *outbytesleft; | ||
60 | |||
61 | for (;;) | ||
62 | { | ||
63 | #ifdef HAVE_ICONV_PROTO_CONST | ||
64 | ret1 = iconv (cd, (const char **) &ib, &ibl, &ob, &obl); | ||
65 | #else | ||
66 | ret1 = iconv (cd, &ib, &ibl, &ob, &obl); | ||
67 | #endif | ||
68 | if (ret1 != (size_t)-1) | ||
69 | ret += ret1; | ||
70 | if (ibl && obl && errno == EILSEQ) | ||
71 | { | ||
72 | if (inrepls) | ||
73 | { | ||
74 | /* Try replacing the input */ | ||
75 | char **t; | ||
76 | for (t = inrepls; *t; t++) | ||
77 | { | ||
78 | char *ib1 = *t; | ||
79 | size_t ibl1 = strlen (*t); | ||
80 | char *ob1 = ob; | ||
81 | size_t obl1 = obl; | ||
82 | #ifdef HAVE_ICONV_PROTO_CONST | ||
83 | iconv (cd, (const char **) &ib1, &ibl1, &ob1, &obl1); | ||
84 | #else | ||
85 | iconv (cd, &ib1, &ibl1, &ob1, &obl1); | ||
86 | #endif | ||
87 | if (!ibl1) | ||
88 | { | ||
89 | ++ib, --ibl; | ||
90 | ob = ob1, obl = obl1; | ||
91 | ++ret; | ||
92 | break; | ||
93 | } | ||
94 | } | ||
95 | if (*t) | ||
96 | continue; | ||
97 | } | ||
98 | if (outrepl) | ||
99 | { | ||
100 | /* Try replacing the output */ | ||
101 | size_t n = strlen (outrepl); | ||
102 | if (n <= obl) | ||
103 | { | ||
104 | memcpy (ob, outrepl, n); | ||
105 | ++ib, --ibl; | ||
106 | ob += n, obl -= n; | ||
107 | ++ret; | ||
108 | continue; | ||
109 | } | ||
110 | } | ||
111 | } | ||
112 | *inbuf = ib, *inbytesleft = ibl; | ||
113 | *outbuf = ob, *outbytesleft = obl; | ||
114 | return ret; | ||
115 | } | ||
116 | } | ||
117 | #endif | ||
118 | |||
119 | int charconv(const char * tocode, const char * fromcode, | ||
120 | const char * str, size_t length, | ||
121 | char ** result) | ||
122 | { | ||
123 | #ifndef HAVE_ICONV | ||
124 | return MAIL_CHARCONV_ERROR_UNKNOWN_CHARSET; | ||
125 | #else | ||
126 | iconv_t conv; | ||
127 | size_t r; | ||
128 | char * out; | ||
129 | char * pout; | ||
130 | size_t out_size; | ||
131 | size_t old_out_size; | ||
132 | size_t count; | ||
133 | int res; | ||
134 | |||
135 | conv = iconv_open(tocode, fromcode); | ||
136 | if (conv == (iconv_t) -1) { | ||
137 | res = MAIL_CHARCONV_ERROR_UNKNOWN_CHARSET; | ||
138 | goto err; | ||
139 | } | ||
140 | |||
141 | out_size = 4 * length; | ||
142 | |||
143 | out = malloc(out_size + 1); | ||
144 | if (out == NULL) { | ||
145 | res = MAIL_CHARCONV_ERROR_MEMORY; | ||
146 | goto close_iconv; | ||
147 | } | ||
148 | |||
149 | pout = out; | ||
150 | old_out_size = out_size; | ||
151 | |||
152 | r = mail_iconv(conv, &str, &length, &pout, &out_size, NULL, "?"); | ||
153 | |||
154 | if (r == (size_t) -1) { | ||
155 | res = MAIL_CHARCONV_ERROR_CONV; | ||
156 | goto free; | ||
157 | } | ||
158 | |||
159 | iconv_close(conv); | ||
160 | |||
161 | * pout = '\0'; | ||
162 | count = old_out_size - out_size; | ||
163 | pout = realloc(out, count + 1); | ||
164 | if (pout != NULL) | ||
165 | out = pout; | ||
166 | |||
167 | * result = out; | ||
168 | |||
169 | return MAIL_CHARCONV_NO_ERROR; | ||
170 | |||
171 | free: | ||
172 | free(out); | ||
173 | close_iconv: | ||
174 | iconv_close(conv); | ||
175 | err: | ||
176 | return res; | ||
177 | #endif | ||
178 | }; | ||
179 | |||
180 | int charconv_buffer(const char * tocode, const char * fromcode, | ||
181 | const char * str, size_t length, | ||
182 | char ** result, size_t * result_len) | ||
183 | { | ||
184 | #ifndef HAVE_ICONV | ||
185 | return MAIL_CHARCONV_ERROR_UNKNOWN_CHARSET; | ||
186 | #else | ||
187 | iconv_t conv; | ||
188 | size_t iconv_r; | ||
189 | int r; | ||
190 | char * out; | ||
191 | char * pout; | ||
192 | size_t out_size; | ||
193 | size_t old_out_size; | ||
194 | size_t count; | ||
195 | MMAPString * mmapstr; | ||
196 | int res; | ||
197 | |||
198 | conv = iconv_open(tocode, fromcode); | ||
199 | if (conv == (iconv_t) -1) { | ||
200 | res = MAIL_CHARCONV_ERROR_UNKNOWN_CHARSET; | ||
201 | goto err; | ||
202 | } | ||
203 | |||
204 | out_size = 4 * length; | ||
205 | |||
206 | mmapstr = mmap_string_sized_new(out_size + 1); | ||
207 | if (mmapstr == NULL) { | ||
208 | res = MAIL_CHARCONV_ERROR_MEMORY; | ||
209 | goto err; | ||
210 | } | ||
211 | |||
212 | out = mmapstr->str; | ||
213 | |||
214 | pout = out; | ||
215 | old_out_size = out_size; | ||
216 | |||
217 | iconv_r = mail_iconv(conv, &str, &length, &pout, &out_size, NULL, "?"); | ||
218 | |||
219 | if (iconv_r == (size_t) -1) { | ||
220 | res = MAIL_CHARCONV_ERROR_CONV; | ||
221 | goto free; | ||
222 | } | ||
223 | |||
224 | iconv_close(conv); | ||
225 | |||
226 | * pout = '\0'; | ||
227 | |||
228 | count = old_out_size - out_size; | ||
229 | |||
230 | r = mmap_string_ref(mmapstr); | ||
231 | if (r < 0) { | ||
232 | res = MAIL_CHARCONV_ERROR_MEMORY; | ||
233 | goto free; | ||
234 | } | ||
235 | |||
236 | * result = out; | ||
237 | * result_len = count; | ||
238 | |||
239 | return MAIL_CHARCONV_NO_ERROR; | ||
240 | |||
241 | free: | ||
242 | mmap_string_free(mmapstr); | ||
243 | err: | ||
244 | return -1; | ||
245 | #endif | ||
246 | }; | ||
247 | |||
248 | void charconv_buffer_free(char * str) | ||
249 | { | ||
250 | mmap_string_unref(str); | ||
251 | } | ||