1 /*----------------------------------------------------------------------
2  * Module name:  my_iconv
3  * Author name:  Arkadiusz Firus
4  * Create date:  07 Sep 08
5  * Purpose:    iconv handles
6  *----------------------------------------------------------------------
7  Changes:
8  * 04 Jan 10, daved@physiol.usyd.edu.au: use path specfied with -P to
9  *	load charmap file(s)
10  * 07 Oct 11, jf@dockes.org, major changes to unicode translations
11  *--------------------------------------------------------------------*/
12 
13 #include <stdio.h>
14 #include <string.h>
15 #ifndef _WIN32
16 #include <unistd.h>
17 #endif
18 #include <stdlib.h>
19 #include <errno.h>
20 
21 #include "malloc.h"
22 #include "my_iconv.h"
23 #include "util.h"
24 #include "unicode.h"
25 #include "path.h"
26 
27 extern int verbose_mode;
28 
29 /* Convert from charmap file entry to charmap table one.
30    1st byte in table entry is code length
31 */
32 static char *
get_code_str(FILE * f,iconv_t desc)33 get_code_str(FILE *f, iconv_t desc)
34 {
35 	char *icp, *ocp0, *ocp;
36 	size_t ibytes, obytes;
37 	char *obuf;
38 
39 	char *utf8 = get_unicode_utf8(f);
40 	if (utf8 == NULL || *utf8 == 0)
41 	{
42 		/* fprintf(stderr, "get_code_str: NULL entry\n");*/
43 		my_free(utf8);
44 		return NULL;
45 	}
46 #if 0 /* debug */
47 	fprintf(stderr, "get_code_str: utf8: ");
48 	for (ocp = utf8; *ocp; ocp++)
49 	{
50 		fprintf(stderr, "%x", (unsigned)*ocp);
51 	}
52 	fprintf(stderr, "\n");
53 #endif
54 
55 	obytes = 10;
56 	ibytes = strlen(utf8);
57 	obuf = malloc(obytes);
58 	if (obuf == NULL)
59 	{
60 		my_free(utf8);
61 		return NULL;
62 	}
63 	icp = utf8;
64 	ocp0 = ocp = obuf + 1;
65 	if (iconv(desc, &icp, &ibytes, &ocp, &obytes) == -1)
66 	{
67 		/*        fprintf(stderr, "unrtf: my_iconv: iconv error\n");*/
68 		my_free(utf8);
69 		return NULL;
70 	}
71 
72 	// Set 1st byte to length
73 	obuf[0] = ocp - ocp0;
74 	my_free(utf8);
75 	return obuf;
76 }
77 
78 my_iconv_t
my_iconv_open(const char * tocode,const char * fromcode)79 my_iconv_open(const char *tocode, const char *fromcode)
80 {
81 	FILE *f;
82 	my_iconv_t cd = MY_ICONV_T_CLEAR;
83 	int c, i;
84 	/*      fprintf(stderr, "my_iconv_open: from %s to %s\n", fromcode, tocode);*/
85 	if ((cd.desc = iconv_open(tocode, fromcode)) == (iconv_t) - 1)
86 	{
87 		char *path = search_in_path(fromcode, "charmap");
88 		if (path == NULL)
89 		{
90 			return cd;
91 		}
92 		if ((f = fopen(path, "r")) == NULL && verbose_mode)
93 		{
94 			fprintf(stderr, "failed to open charmap file %s\n", path);
95 		}
96 
97 		if (f != NULL)
98 		{
99 			/* Open iconv utf8->tocode conversion */
100 			iconv_t desc;
101 			if ((desc = iconv_open(tocode, "UTF-8")) == (iconv_t) - 1)
102 			{
103 				fclose(f);
104 				return cd;
105 			}
106 			cd.char_table = (char **)my_malloc(char_table_size *
107 			                                   sizeof(char *));
108 			c = fgetc(f);
109 
110 			for (i = 0; i < char_table_size && c != EOF; i++)
111 			{
112 				if (c == '<')
113 				{
114 					cd.char_table[i] = get_code_str(f, desc);
115 				}
116 				leave_line(f);//read up to including \n or eof
117 				c = fgetc(f);
118 			}
119 			iconv_close(desc);
120 			fclose(f);
121 		}
122 
123 		my_free(path);
124 	}
125 
126 	return cd;
127 }
128 
129 size_t
my_iconv(my_iconv_t cd,char ** inbuf,size_t * inbytesleft,char ** outbuf,size_t * outbytesleft)130 my_iconv(my_iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
131 {
132 	int c, i;
133 	size_t result = 0;
134 	**outbuf = 0;
135 	if (cd.desc == (iconv_t) - 1)
136 	{
137 		if (cd.char_table != NULL)
138 		{
139 			while (*inbytesleft > 0 && *outbytesleft > 0)
140 			{
141 				c = **(unsigned char **)inbuf;
142 				if (cd.char_table[c] != NULL)
143 				{
144 					for (i = 0; i < cd.char_table[c][0] && *outbytesleft > 0; i++)
145 					{
146 						**outbuf = cd.char_table[c][i + 1];
147 						(*outbytesleft)--;
148 						(*outbuf)++;
149 					}
150 				}
151 				else
152 				{
153 					/*                    fprintf(stderr, "my_iconv: no conversion for 0x%x\n",
154 						      (unsigned)c);*/
155 					errno = EILSEQ;
156 					return (size_t) - 1;
157 				}
158 
159 				(*inbuf)++;
160 				(*inbytesleft)--;
161 				result++;
162 			}
163 
164 			if (*outbytesleft == 0 && *inbytesleft > 0)
165 			{
166 				errno = E2BIG;
167 				result = (size_t) - 1;
168 			}
169 		}
170 	}
171 	else
172 	{
173 		result = iconv(cd.desc, inbuf, inbytesleft, outbuf, outbytesleft);
174 	}
175 
176 	return result;
177 }
178 
179 my_iconv_t
my_iconv_close(my_iconv_t cd)180 my_iconv_close(my_iconv_t cd)
181 {
182 	int i;
183 
184 	if (cd.char_table != NULL)
185 	{
186 		for (i = 0; i < char_table_size; i++)
187 		{
188 			if (cd.char_table[i] != NULL)
189 			{
190 				my_free(cd.char_table[i]);
191 			}
192 		}
193 
194 		my_free((void *)cd.char_table);
195 		cd.char_table = NULL;
196 	}
197 
198 	if (cd.desc != (iconv_t) - 1)
199 	{
200 		iconv_close(cd.desc);
201 		cd.desc = (iconv_t) - 1;
202 	}
203 
204 	return cd;
205 }
206 
207 int
my_iconv_is_valid(my_iconv_t cd)208 my_iconv_is_valid(my_iconv_t cd)
209 {
210 	if (cd.desc != (iconv_t) - 1 || cd.char_table != NULL)
211 	{
212 		return 1;
213 	}
214 
215 	return 0;
216 }
217 
218 void
my_iconv_t_make_invalid(my_iconv_t * cd)219 my_iconv_t_make_invalid(my_iconv_t *cd)
220 {
221 	cd->desc = (iconv_t) - 1;
222 	cd->char_table = NULL;
223 }
224 
225