1 /**
2 ***     Transcoding support and wrappers.
3 ***
4 ***     See Copyright for the status of this software.
5 ***
6 ***     Author: Patrick Monnerat <pm@datasphere.ch>, DATASPHERE S.A.
7 **/
8 
9 #define IN_LIBXML
10 #include "libxml.h"
11 
12 #include <sys/types.h>
13 #include <iconv.h>
14 #include "libxml/xmlmemory.h"
15 #include "libxml/dict.h"
16 #include "transcode.h"
17 
18 
19 /**
20 ***     Destroy a dictionary and mark as destroyed.
21 **/
22 
23 void
xmlZapDict(xmlDictPtr * dict)24 xmlZapDict(xmlDictPtr * dict)
25 
26 {
27         if (dict && *dict) {
28                 xmlDictFree(*dict);
29                 *dict = (xmlDictPtr) NULL;
30                 }
31 }
32 
33 
34 /**
35 ***     Support for inline conversion from/to UTF-8.
36 ***     This is targeted to function parameter encoding conversion.
37 ***     Method is:
38 ***     -       Convert string from/to UTF-8.
39 ***     -       Keep it in a dictionary.
40 ***     -       Free original string if a release procedure is provided.
41 ***     Can also be called without dictionary to convert a string from/to UTF-8
42 ***             into xmlMalloc'ed dynamic storage.
43 **/
44 
45 const char *
xmlTranscodeResult(const xmlChar * s,const char * encoding,xmlDictPtr * dict,void (* freeproc)(const void *))46 xmlTranscodeResult(const xmlChar * s, const char * encoding,
47                         xmlDictPtr * dict, void (*freeproc)(const void *))
48 
49 {
50         size_t l;
51         iconv_t cd;
52         char * srcp;
53         char * dstp;
54         size_t srcc;
55         size_t dstc;
56         char * ts;
57         const char * ret;
58         int err;
59         static const int nullstring[] = { 0 };
60 
61         /* Convert from UTF-8. */
62 
63         if (!s)
64                 return (const char *) NULL;
65 
66         ret = (const char *) NULL;
67         ts = (char *) NULL;
68         err = 0;
69         l = xmlStrlen(s);
70 
71         if (!l && dict)
72                 ret = (const char *) nullstring;
73         else {
74                 if (dict && !*dict)
75                         err = !(*dict = xmlDictCreate());
76 
77                 if (!err)
78                         err = !(ts = xmlMalloc(4 * l + 4));
79 
80                 dstp = ts;
81                 dstc = 4 * l;
82 
83                 if (!err && l) {
84                         if (!encoding)
85                                 encoding = "ibm-0";     /* Job's encoding. */
86 
87                         cd = iconv_open(encoding, "UTF-8");
88 
89                         if (cd == (iconv_t) -1)
90                                 err = 1;
91                         else {
92                                 srcp = (char *) s;
93                                 srcc = l;
94                                 srcc = iconv(cd, &srcp, &srcc, &dstp, &dstc);
95                                 iconv_close(cd);
96                                 err = srcc == (size_t) -1;
97                                 }
98                         }
99 
100                 if (!err) {
101                         dstp[0] = dstp[1] = dstp[2] = dstp[3] = '\0';
102 
103                         if (!dict) {
104                                 if (dstc)
105                                         ts = xmlRealloc(ts, (dstp - ts) + 4);
106 
107                                 ret = (const char *) ts;
108                                 ts = (char *) NULL;
109                                 }
110                         else
111                                 ret = (char *) xmlDictLookup(*dict,
112                                     (xmlChar *) ts, dstp - ts + 1);
113                         }
114                 }
115 
116         if (ts)
117                 xmlFree(ts);
118 
119         if (freeproc)
120                 (*freeproc)(s);
121 
122         return ret;
123 }
124 
125 
126 /**
127 ***     Support for inline conversion to UTF-8.
128 ***     Method is:
129 ***     -       Convert string to UTF-8.
130 ***     -       Keep it in a dictionary.
131 ***     Can also be called without dictionary to convert a string to UTF-8 into
132 ***             xmlMalloc'ed dynamic storage.
133 **/
134 
135 static const xmlChar *
inTranscode(const char * s,size_t l,const char * encoding,xmlDictPtr * dict)136 inTranscode(const char * s, size_t l, const char * encoding, xmlDictPtr * dict)
137 
138 {
139         iconv_t cd;
140         char * srcp;
141         char * dstp;
142         size_t srcc;
143         size_t dstc;
144         xmlChar * ts;
145         const xmlChar * ret;
146         static const xmlChar nullstring[] = { 0 };
147 
148         if (!l && dict)
149                 return nullstring;
150 
151         if (dict && !*dict)
152                 if (!(*dict = xmlDictCreate()))
153                         return (const xmlChar *) NULL;
154 
155         ts = (xmlChar *) xmlMalloc(6 * l + 1);
156 
157         if (!ts)
158                 return (const xmlChar *) NULL;
159 
160         dstp = (char *) ts;
161         dstc = 6 * l;
162 
163         if (l) {
164                 if (!encoding)
165                         encoding = "ibm-0";     /* Use job's encoding. */
166 
167                 cd = iconv_open("UTF-8", encoding);
168 
169                 if (cd == (iconv_t) -1) {
170                         xmlFree((char *) ts);
171                         return (const xmlChar *) NULL;
172                         }
173 
174                 srcp = (char *) s;
175                 srcc = l;
176                 srcc = iconv(cd, &srcp, &srcc, &dstp, &dstc);
177                 iconv_close(cd);
178 
179                 if (srcc == (size_t) -1) {
180                         xmlFree((char *) ts);
181                         return (const xmlChar *) NULL;
182                         }
183                 }
184 
185         *dstp = '\0';
186 
187         if (!dict) {
188                 if (dstc)
189                         ts = xmlRealloc(ts, (dstp - ts) + 1);
190 
191                 return ts;
192                 }
193 
194         ret = xmlDictLookup(*dict, ts, dstp - ts + 1);
195         xmlFree((char *) ts);
196         return ret;
197 }
198 
199 
200 /**
201 ***     Input 8-bit character string parameter.
202 **/
203 
204 const xmlChar *
xmlTranscodeString(const char * s,const char * encoding,xmlDictPtr * dict)205 xmlTranscodeString(const char * s, const char * encoding, xmlDictPtr * dict)
206 
207 {
208         if (!s)
209                 return (const xmlChar *) NULL;
210 
211         return inTranscode(s, xmlStrlen(s), encoding, dict);
212 }
213 
214 
215 /**
216 ***     Input 16-bit character string parameter.
217 **/
218 
219 const xmlChar *
xmlTranscodeWString(const char * s,const char * encoding,xmlDictPtr * dict)220 xmlTranscodeWString(const char * s, const char * encoding, xmlDictPtr * dict)
221 
222 {
223         size_t i;
224 
225         if (!s)
226                 return (const xmlChar *) NULL;
227 
228         for (i = 0; s[i] && s[i + 1]; i += 2)
229                 ;
230 
231         return inTranscode(s, i, encoding, dict);
232 }
233 
234 
235 /**
236 ***     Input 32-bit character string parameter.
237 **/
238 
239 const xmlChar *
xmlTranscodeHString(const char * s,const char * encoding,xmlDictPtr * dict)240 xmlTranscodeHString(const char * s, const char * encoding, xmlDictPtr * dict)
241 
242 {
243         size_t i;
244 
245         if (!s)
246                 return (const xmlChar *) NULL;
247 
248         for (i = 0; s[i] && s[i + 1] && s[i + 2] && s[i + 3]; i += 4)
249                 ;
250 
251         return inTranscode(s, i, encoding, dict);
252 }
253 
254 
255 /**
256 ***     vasprintf() implementation with result transcoding.
257 **/
258 
259 const char *
xmlVasprintf(xmlDictPtr * dict,const char * encoding,const xmlChar * fmt,va_list args)260 xmlVasprintf(xmlDictPtr * dict, const char * encoding,
261                                         const xmlChar * fmt, va_list args)
262 
263 {
264         char * s = NULL;
265 
266         vasprintf(&s, fmt, args);
267         return xmlTranscodeResult((const xmlChar *) s, encoding, dict, free);
268 }
269