"Fossies" - the Fresh Open Source Software Archive 
Member "jpilot-2_0_1/otherconv.c" (3 Apr 2021, 9129 Bytes) of package /linux/privat/jpilot-2_0_1.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /*******************************************************************************
2 * otherconv.c
3 * A module of J-Pilot http://jpilot.org
4 *
5 * Copyright (C) 2004 by Amit Aronovitch
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 ******************************************************************************/
20
21 /*
22 * General charset conversion library (using gconv)
23 * Convert Palm <-> Unix:
24 * Palm : Any - according to the "other-pda-charset" setup option.
25 * Unix : UTF-8
26 */
27
28 /********************************* Includes ***********************************/
29 #include "config.h"
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <glib.h>
35
36 #include "otherconv.h"
37 #include "i18n.h"
38 #include "prefs.h"
39 #include "log.h"
40
41 /********************************* Constants **********************************/
42 #define HOST_CS "UTF-8"
43
44 #define min(a,b) (((a) < (b)) ? (a) : (b))
45
46 /* You can't do #ifndef __FUNCTION__ */
47 #if !defined(__GNUC__) && !defined(__IBMC__)
48 #define __FUNCTION__ ""
49 #endif
50
51 #define OC_FREE_ICONV(conv) oc_free_iconv(__FUNCTION__, conv,#conv)
52
53 /* #define OTHERCONV_DEBUG */
54
55 /******************************* Global vars **********************************/
56 static GIConv glob_topda = NULL;
57 static GIConv glob_frompda = NULL;
58
59 /****************************** Main Code *************************************/
60 /*
61 * strnlen is not ANSI.
62 * To avoid conflicting declarations, it is reimplemented as a thin
63 * inline function over the library function strlen
64 */
65 static inline size_t oc_strnlen(const char *s, size_t maxlen)
66 {
67 return min(strlen(s), maxlen);
68 }
69
70 static void oc_free_iconv(const char *funcname, GIConv conv, char *convname)
71 {
72 if (conv != NULL) {
73 if (g_iconv_close(conv) != 0) {
74 jp_logf(JP_LOG_WARN, _("%s: error exit from g_iconv_close(%s)\n"),
75 funcname,convname);
76 }
77 }
78 }
79
80 /*
81 * Convert char_set integer code to iconv charset text string
82 */
83 static const char *char_set_to_text(int char_set)
84 {
85 switch (char_set) {
86 case CHAR_SET_1250_UTF:
87 return "CP1250";
88
89 case CHAR_SET_1253_UTF:
90 return "CP1253";
91
92 case CHAR_SET_ISO8859_2_UTF:
93 return "ISO8859-2";
94
95 case CHAR_SET_KOI8_R_UTF:
96 return "KOI8-R";
97
98 case CHAR_SET_1251_UTF:
99 return "CP1251";
100
101 case CHAR_SET_GBK_UTF:
102 return "GBK";
103
104 case CHAR_SET_BIG5_UTF:
105 return "BIG-5";
106
107 case CHAR_SET_SJIS_UTF:
108 return "SJIS";
109
110 case CHAR_SET_1255_UTF:
111 return "CP1255";
112
113 case CHAR_SET_949_UTF:
114 return "CP949";
115
116 case CHAR_SET_1252_UTF:
117 default:
118 return "CP1252";
119 }
120 }
121
122 /*
123 * Module initialization function
124 * Call this before any conversion routine.
125 * Can also be used if you want to reread the 'charset' option
126 *
127 * Returns 0 if OK, -1 if iconv could not be initialized
128 * (probably because of bad charset string)
129 */
130 int otherconv_init(void)
131 {
132 long char_set;
133
134 get_pref(PREF_CHAR_SET, &char_set, NULL);
135
136 /* (re)open the "to" iconv */
137 OC_FREE_ICONV(glob_topda);
138 glob_topda = g_iconv_open(char_set_to_text(char_set), HOST_CS);
139 if (glob_topda == (GIConv)(-1))
140 return EXIT_FAILURE;
141
142 /* (re)open the "from" iconv */
143 OC_FREE_ICONV(glob_frompda);
144 glob_frompda = g_iconv_open(HOST_CS, char_set_to_text(char_set));
145 if (glob_frompda == (GIConv)(-1)) {
146 OC_FREE_ICONV(glob_topda);
147 return EXIT_FAILURE;
148 }
149 return EXIT_SUCCESS;
150 }
151
152 /*
153 * Module finalization function
154 * closes the iconvs
155 */
156 void otherconv_free(void)
157 {
158 OC_FREE_ICONV(glob_topda);
159 OC_FREE_ICONV(glob_frompda);
160 }
161
162 /*
163 * Conversion to UTF using g_convert_with_iconv
164 * A new buffer is now allocated and the old one remains unchanged
165 */
166 char *other_to_UTF(const char *buf, int buf_len)
167 {
168 char *outbuf;
169 gsize bytes_read;
170 GError *err = NULL;
171 size_t str_len;
172
173 #ifdef OTHERCONV_DEBUG
174 jp_logf(JP_LOG_DEBUG, "%s:%s reset iconv state...\n", __FILE__, __FUNCTION__);
175 #endif
176 g_iconv(glob_frompda, NULL, NULL, NULL, NULL);
177 #ifdef OTHERCONV_DEBUG
178 jp_logf(JP_LOG_DEBUG, "%s:%s converting [%s]\n", __FILE__, __FUNCTION__, buf);
179 #endif
180
181 if (buf_len == -1) {
182 str_len = -1;
183 } else {
184 str_len = oc_strnlen(buf, buf_len-1); // -1 leaves room for \0 terminator
185 }
186
187 outbuf = (char *)g_convert_with_iconv((gchar *)buf,
188 str_len, glob_frompda, &bytes_read, NULL, &err);
189
190 if (err != NULL) {
191 char c;
192 char *head, *tail;
193 int outbuf_len;
194 char *tmp_buf = (char *)buf;
195 static int call_depth = 0;
196 printf("ERROR HAPPENED\n");
197 if (0 == call_depth)
198 jp_logf(JP_LOG_WARN, _("%s:%s g_convert_with_iconv error: %s, buff: %s\n"),
199 __FILE__, __FUNCTION__,
200 err ? err->message : _("last char truncated"),
201 buf);
202 if (err != NULL)
203 g_error_free(err);
204 else
205 g_free(outbuf);
206
207 if (buf_len == -1) {
208 buf_len = strlen(buf);
209 }
210
211 /* convert the head, skip the problematic char, convert the tail */
212 c = tmp_buf[bytes_read];
213 tmp_buf[bytes_read] = '\0';
214 head = g_convert_with_iconv(tmp_buf,
215 oc_strnlen(tmp_buf, buf_len),
216 glob_frompda,
217 &bytes_read,
218 NULL, NULL);
219 tmp_buf[bytes_read] = c;
220
221 call_depth++;
222 tail = other_to_UTF(tmp_buf + bytes_read +1, buf_len - bytes_read - 1);
223 call_depth--;
224
225 outbuf_len = strlen(head) +4 + strlen(tail)+1;
226 outbuf = g_malloc(outbuf_len);
227 g_snprintf(outbuf, outbuf_len, "%s\\%02X%s", head, (unsigned char)c, tail);
228
229 g_free(head);
230 g_free(tail);
231 }
232
233 #ifdef OTHERCONV_DEBUG
234 jp_logf(JP_LOG_DEBUG, "%s:%s converted to [%s]\n", __FILE__, __FUNCTION__, outbuf);
235 #endif
236 /*
237 * Note: outbuf was allocated by glib, so should be freed with g_free
238 * To be 100% safe, I should have done strncpy to a new malloc-allocated
239 * string. (at least under an 'if (!g_mem_is_system_malloc())' test)
240 *
241 * However, unless you replace the default GMemVTable, freeing with C free
242 * should be fine so I decided this is not worth the overhead.
243 * -- Amit Aronovitch
244 */
245 return outbuf;
246 }
247
248 /*
249 * Conversion to pda encoding using g_iconv
250 */
251 void UTF_to_other(char *const buf, int buf_len)
252 {
253 gsize inleft,outleft;
254 gchar *inptr, *outptr;
255 size_t rc;
256 char *errstr = NULL;
257 char buf_out[1000];
258 char *buf_out_ptr = NULL;
259 int failed = FALSE;
260
261 #ifdef OTHERCONV_DEBUG
262 jp_logf(JP_LOG_DEBUG, "%s:%s reset iconv state...\n", __FILE__, __FUNCTION__);
263 #endif
264 rc = g_iconv(glob_topda, NULL, NULL, NULL, NULL);
265 #ifdef OTHERCONV_DEBUG
266 jp_logf(JP_LOG_DEBUG, "%s:%s converting [%s]\n", __FILE__, __FUNCTION__, buf);
267 #endif
268
269 inleft = oc_strnlen(buf, buf_len);
270 outleft = buf_len-1;
271 inptr = buf;
272
273 /* Most strings can be converted without recourse to malloc */
274 if (buf_len > sizeof(buf_out)) {
275 buf_out_ptr = malloc(buf_len);
276 if (NULL == buf_out_ptr) {
277 jp_logf(JP_LOG_WARN, _("UTF_to_other: %s\n"), _("Out of memory"));
278 return;
279 }
280 outptr = buf_out_ptr;
281 } else {
282 outptr = buf_out;
283 }
284
285 rc = g_iconv(glob_topda, &inptr, &inleft, &outptr, &outleft);
286 *outptr = 0; /* NULL terminate whatever fraction was converted */
287
288 if ((size_t)(-1) == rc) {
289 switch (errno) {
290 case EILSEQ:
291 errstr = _("iconv: unconvertible sequence at place %d in \'%s\'\n");
292 failed = TRUE;
293 break;
294 case EINVAL:
295 errstr = _("iconv: incomplete UTF-8 sequence at place %d in \'%s\'\n");
296 break;
297 case E2BIG:
298 errstr = _("iconv: buffer filled. stopped at place %d in \'%s\'\n");
299 break;
300 default:
301 errstr = _("iconv: unexpected error at place %d in \'%s\'\n");
302 }
303 }
304
305 if (buf_out_ptr) {
306 g_strlcpy(buf, buf_out_ptr, buf_len);
307 free(buf_out_ptr);
308 } else {
309 g_strlcpy(buf, buf_out, buf_len);
310 }
311
312 if ((size_t)(-1) == rc)
313 jp_logf(JP_LOG_WARN, errstr, inptr - buf, buf);
314
315 if (failed)
316 {
317 /* convert the end of the string */
318 int l = inptr - buf;
319
320 buf[l] = '?';
321 UTF_to_other(inptr+1, buf_len-l-1);
322 memmove(buf+l+1, inptr+1, buf_len-l-1);
323 }
324
325 #ifdef OTHERCONV_DEBUG
326 jp_logf(JP_LOG_DEBUG, "%s:%s converted to [%s]\n", __FILE__, __FUNCTION__, buf);
327 #endif
328 }
329