FreeBSD kernel libkern code
iconv_xlat16.c
Go to the documentation of this file.
1 /*-
2  * Copyright (c) 2003, 2005 Ryuichiro Imura
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$BSDSUniX$");
29 
30 #include <sys/param.h>
31 #include <sys/kernel.h>
32 #include <sys/systm.h>
33 #include <sys/malloc.h>
34 #include <sys/iconv.h>
35 
36 #include "iconv_converter_if.h"
37 
38 /*
39  * "XLAT16" converter
40  */
41 
42 #ifdef MODULE_DEPEND
43 MODULE_DEPEND(iconv_xlat16, libiconv, 2, 2, 2);
44 #endif
45 
46 #define C2I1(c) ((c) & 0x8000 ? ((c) & 0xff) | 0x100 : (c) & 0xff)
47 #define C2I2(c) ((c) & 0x8000 ? ((c) >> 8) & 0x7f : ((c) >> 8) & 0xff)
48 
49 /*
50  * XLAT16 converter instance
51  */
52 struct iconv_xlat16 {
54  uint32_t * d_table[0x200];
55  void * f_ctp;
56  void * t_ctp;
57  struct iconv_cspair * d_csp;
58 };
59 
60 static int
61 iconv_xlat16_open(struct iconv_converter_class *dcp,
62  struct iconv_cspair *csp, struct iconv_cspair *cspf, void **dpp)
63 {
64  struct iconv_xlat16 *dp;
65  uint32_t *headp, **idxp;
66  int i;
67 
68  dp = (struct iconv_xlat16 *)kobj_create((struct kobj_class*)dcp, M_ICONV, M_WAITOK);
69  headp = (uint32_t *)((caddr_t)csp->cp_data + sizeof(dp->d_table));
70  idxp = (uint32_t **)csp->cp_data;
71  for (i = 0 ; i < 0x200 ; i++) {
72  if (*idxp) {
73  dp->d_table[i] = headp;
74  headp += 0x80;
75  } else {
76  dp->d_table[i] = NULL;
77  }
78  idxp++;
79  }
80 
81  if (strcmp(csp->cp_to, KICONV_WCTYPE_NAME) != 0) {
82  if (iconv_open(KICONV_WCTYPE_NAME, csp->cp_from, &dp->f_ctp) != 0)
83  dp->f_ctp = NULL;
84  if (iconv_open(KICONV_WCTYPE_NAME, csp->cp_to, &dp->t_ctp) != 0)
85  dp->t_ctp = NULL;
86  } else {
87  dp->f_ctp = dp->t_ctp = dp;
88  }
89 
90  dp->d_csp = csp;
91  csp->cp_refcount++;
92  *dpp = (void*)dp;
93  return (0);
94 }
95 
96 static int
97 iconv_xlat16_close(void *data)
98 {
99  struct iconv_xlat16 *dp = data;
100 
101  if (dp->f_ctp && dp->f_ctp != data)
102  iconv_close(dp->f_ctp);
103  if (dp->t_ctp && dp->t_ctp != data)
104  iconv_close(dp->t_ctp);
105  dp->d_csp->cp_refcount--;
106  kobj_delete((struct kobj*)data, M_ICONV);
107  return (0);
108 }
109 
110 static int
111 iconv_xlat16_conv(void *d2p, const char **inbuf,
112  size_t *inbytesleft, char **outbuf, size_t *outbytesleft,
113  int convchar, int casetype)
114 {
115  struct iconv_xlat16 *dp = (struct iconv_xlat16*)d2p;
116  const char *src;
117  char *dst;
118  int nullin, ret = 0;
119  size_t in, on, ir, or, inlen;
120  uint32_t code;
121  u_char u, l;
122  uint16_t c1, c2, ctmp;
123 
124  if (inbuf == NULL || *inbuf == NULL || outbuf == NULL || *outbuf == NULL)
125  return (0);
126  ir = in = *inbytesleft;
127  or = on = *outbytesleft;
128  src = *inbuf;
129  dst = *outbuf;
130 
131  while(ir > 0 && or > 0) {
132 
133  inlen = 0;
134  code = 0;
135 
136  c1 = ir > 1 ? *(src+1) & 0xff : 0;
137  c2 = *src & 0xff;
138  ctmp = 0;
139 
140  c1 = c2 & 0x80 ? c1 | 0x100 : c1;
141  c2 = c2 & 0x80 ? c2 & 0x7f : c2;
142 
143  if (ir > 1 && dp->d_table[c1] && dp->d_table[c1][c2]) {
144  /*
145  * inbuf char is a double byte char
146  */
147  inlen = 2;
148 
149  /* toupper,tolower */
150  if (casetype == KICONV_FROM_LOWER && dp->f_ctp)
151  ctmp = towlower(((u_char)*src << 8) | (u_char)*(src + 1),
152  dp->f_ctp);
153  else if (casetype == KICONV_FROM_UPPER && dp->f_ctp)
154  ctmp = towupper(((u_char)*src << 8) | (u_char)*(src + 1),
155  dp->f_ctp);
156  if (ctmp) {
157  c1 = C2I1(ctmp);
158  c2 = C2I2(ctmp);
159  }
160  }
161 
162  if (inlen == 0) {
163  c1 &= 0xff00;
164  if (!dp->d_table[c1]) {
165  ret = -1;
166  break;
167  }
168  /*
169  * inbuf char is a single byte char
170  */
171  inlen = 1;
172 
173  if (casetype & (KICONV_FROM_LOWER|KICONV_FROM_UPPER))
174  code = dp->d_table[c1][c2];
175 
176  if (casetype == KICONV_FROM_LOWER) {
177  if (dp->f_ctp)
178  ctmp = towlower((u_char)*src, dp->f_ctp);
179  else if (code & XLAT16_HAS_FROM_LOWER_CASE)
180  ctmp = (u_char)(code >> 16);
181  } else if (casetype == KICONV_FROM_UPPER) {
182  if (dp->f_ctp)
183  ctmp = towupper((u_char)*src, dp->f_ctp);
184  else if (code & XLAT16_HAS_FROM_UPPER_CASE)
185  ctmp = (u_char)(code >> 16);
186  }
187  if (ctmp) {
188  c1 = C2I1(ctmp << 8);
189  c2 = C2I2(ctmp << 8);
190  }
191  }
192 
193  code = dp->d_table[c1][c2];
194  if (!code) {
195  ret = -1;
196  break;
197  }
198 
199  nullin = (code & XLAT16_ACCEPT_NULL_IN) ? 1 : 0;
200  if (inlen == 1 && nullin) {
201  /*
202  * XLAT16_ACCEPT_NULL_IN requires inbuf has 2byte
203  */
204  ret = -1;
205  break;
206  }
207 
208  /*
209  * now start translation
210  */
211  u = (u_char)(code >> 8);
212  l = (u_char)code;
213 
214 #ifdef XLAT16_ACCEPT_3BYTE_CHR
215  if (code & XLAT16_IS_3BYTE_CHR) {
216  if (or < 3) {
217  ret = -1;
218  break;
219  }
220  *dst++ = u;
221  *dst++ = l;
222  *dst++ = (u_char)(code >> 16);
223  or -= 3;
224  } else
225 #endif
226  if (u || code & XLAT16_ACCEPT_NULL_OUT) {
227  if (or < 2) {
228  ret = -1;
229  break;
230  }
231 
232  /* toupper,tolower */
233  if (casetype == KICONV_LOWER && dp->t_ctp) {
234  code = towlower((uint16_t)code, dp->t_ctp);
235  u = (u_char)(code >> 8);
236  l = (u_char)code;
237  }
238  if (casetype == KICONV_UPPER && dp->t_ctp) {
239  code = towupper((uint16_t)code, dp->t_ctp);
240  u = (u_char)(code >> 8);
241  l = (u_char)code;
242  }
243 
244  *dst++ = u;
245  *dst++ = l;
246  or -= 2;
247  } else {
248  /* toupper,tolower */
249  if (casetype == KICONV_LOWER) {
250  if (dp->t_ctp)
251  l = (u_char)towlower(l, dp->t_ctp);
252  else if (code & XLAT16_HAS_LOWER_CASE)
253  l = (u_char)(code >> 16);
254  }
255  if (casetype == KICONV_UPPER) {
256  if (dp->t_ctp)
257  l = (u_char)towupper(l, dp->t_ctp);
258  else if (code & XLAT16_HAS_UPPER_CASE)
259  l = (u_char)(code >> 16);
260  }
261 
262  *dst++ = l;
263  or--;
264  }
265 
266  if (inlen == 2) {
267  /*
268  * there is a case that inbuf char is a single
269  * byte char while inlen == 2
270  */
271  if ((u_char)*(src+1) == 0 && !nullin ) {
272  src++;
273  ir--;
274  } else {
275  src += 2;
276  ir -= 2;
277  }
278  } else {
279  src++;
280  ir--;
281  }
282 
283  if (convchar == 1)
284  break;
285  }
286 
287  *inbuf += in - ir;
288  *outbuf += on - or;
289  *inbytesleft -= in - ir;
290  *outbytesleft -= on - or;
291  return (ret);
292 }
293 
294 static const char *
295 iconv_xlat16_name(struct iconv_converter_class *dcp)
296 {
297  return ("xlat16");
298 }
299 
300 static int
301 iconv_xlat16_tolower(void *d2p, register int c)
302 {
303  struct iconv_xlat16 *dp = (struct iconv_xlat16*)d2p;
304  register int c1, c2, out;
305 
306  if (c < 0x100) {
307  c1 = C2I1(c << 8);
308  c2 = C2I2(c << 8);
309  } else if (c < 0x10000) {
310  c1 = C2I1(c);
311  c2 = C2I2(c);
312  } else
313  return (c);
314 
315  if (dp->d_table[c1] && dp->d_table[c1][c2] & XLAT16_HAS_LOWER_CASE) {
316  /*return (int)(dp->d_table[c1][c2] & 0xffff);*/
317  out = dp->d_table[c1][c2] & 0xffff;
318  if ((out & 0xff) == 0)
319  out = (out >> 8) & 0xff;
320  return (out);
321  } else
322  return (c);
323 }
324 
325 static int
326 iconv_xlat16_toupper(void *d2p, register int c)
327 {
328  struct iconv_xlat16 *dp = (struct iconv_xlat16*)d2p;
329  register int c1, c2, out;
330 
331  if (c < 0x100) {
332  c1 = C2I1(c << 8);
333  c2 = C2I2(c << 8);
334  } else if (c < 0x10000) {
335  c1 = C2I1(c);
336  c2 = C2I2(c);
337  } else
338  return (c);
339 
340  if (dp->d_table[c1] && dp->d_table[c1][c2] & XLAT16_HAS_UPPER_CASE) {
341  out = dp->d_table[c1][c2] & 0xffff;
342  if ((out & 0xff) == 0)
343  out = (out >> 8) & 0xff;
344  return (out);
345  } else
346  return (c);
347 }
348 
349 static kobj_method_t iconv_xlat16_methods[] = {
350  KOBJMETHOD(iconv_converter_open, iconv_xlat16_open),
351  KOBJMETHOD(iconv_converter_close, iconv_xlat16_close),
352  KOBJMETHOD(iconv_converter_conv, iconv_xlat16_conv),
353 #if 0
354  KOBJMETHOD(iconv_converter_init, iconv_xlat16_init),
355  KOBJMETHOD(iconv_converter_done, iconv_xlat16_done),
356 #endif
357  KOBJMETHOD(iconv_converter_name, iconv_xlat16_name),
358  KOBJMETHOD(iconv_converter_tolower, iconv_xlat16_tolower),
359  KOBJMETHOD(iconv_converter_toupper, iconv_xlat16_toupper),
360  {0, 0}
361 };
362 
363 KICONV_CONVERTER(xlat16, sizeof(struct iconv_xlat16));
const char ** inbuf
static int iconv_xlat16_tolower(void *d2p, register int c)
Definition: iconv_xlat16.c:301
int c
static int iconv_xlat16_conv(void *d2p, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft, int convchar, int casetype)
Definition: iconv_xlat16.c:111
__FBSDID("$BSDSUniX$")
int iconv_close(void *handle)
Definition: iconv.c:273
#define C2I2(c)
Definition: iconv_xlat16.c:47
int iconv_open(const char *to, const char *from, void **handle)
Definition: iconv.c:236
int convchar
int towlower(int c, void *handle)
Definition: iconv.c:307
static int iconv_xlat16_close(void *data)
Definition: iconv_xlat16.c:97
int casetype
static int iconv_xlat16_toupper(void *d2p, register int c)
Definition: iconv_xlat16.c:326
static const char * iconv_xlat16_name(struct iconv_converter_class *dcp)
Definition: iconv_xlat16.c:295
int towupper(int c, void *handle)
Definition: iconv.c:313
char ** outbuf
static kobj_method_t iconv_xlat16_methods[]
Definition: iconv_xlat16.c:349
uint32_t * d_table[0x200]
Definition: iconv_xlat16.c:54
static int iconv_xlat16_open(struct iconv_converter_class *dcp, struct iconv_cspair *csp, struct iconv_cspair *cspf, void **dpp)
Definition: iconv_xlat16.c:61
size_t * outbytesleft
#define C2I1(c)
Definition: iconv_xlat16.c:46
KICONV_CONVERTER(xlat16, sizeof(struct iconv_xlat16))
struct iconv_cspair * d_csp
Definition: iconv_xlat16.c:57
int strcmp(const char *s1, const char *s2)
Definition: strcmp.c:42
size_t * inbytesleft
void * f_ctp
Definition: iconv_xlat16.c:55
void * t_ctp
Definition: iconv_xlat16.c:56