iconv_xlat16.c 8.5 KB

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