tcvn.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. /*
  2. * Copyright (C) 1999-2002, 2004 Free Software Foundation, Inc.
  3. * This file is part of the GNU LIBICONV Library.
  4. *
  5. * The GNU LIBICONV Library is free software; you can redistribute it
  6. * and/or modify it under the terms of the GNU Library General Public
  7. * License as published by the Free Software Foundation; either version 2
  8. * of the License, or (at your option) any later version.
  9. *
  10. * The GNU LIBICONV Library is distributed in the hope that it will be
  11. * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Library General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Library General Public
  16. * License along with the GNU LIBICONV Library; see the file COPYING.LIB.
  17. * If not, write to the Free Software Foundation, Inc., 51 Franklin Street,
  18. * Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. /*
  21. * TCVN-5712
  22. */
  23. #include "flushwc.h"
  24. #include "vietcomb.h"
  25. static const unsigned char tcvn_comb_table[] = {
  26. 0xb0, 0xb3, 0xb2, 0xb1, 0xb4,
  27. };
  28. /* The possible bases in viet_comp_table_data:
  29. 0x0041..0x0045, 0x0047..0x0049, 0x004B..0x0050, 0x0052..0x0057,
  30. 0x0059..0x005A, 0x0061..0x0065, 0x0067..0x0069, 0x006B..0x0070,
  31. 0x0072..0x0077, 0x0079..0x007A, 0x00A5, 0x00C2, 0x00CA, 0x00D3..0x00D6,
  32. 0x00DA, 0x00E2, 0x00EA, 0x00F3..0x00F6, 0x00FA, 0x0102..0x0103,
  33. 0x0168..0x0169, 0x01A0..0x01A1, 0x01AF..0x01B0. */
  34. static const unsigned int tcvn_comp_bases[] = {
  35. 0x06fdfbbe, 0x06fdfbbe, 0x00000000, 0x00000020, 0x04780404, 0x04780404,
  36. 0x0000000c, 0x00000000, 0x00000000, 0x00000300, 0x00000000, 0x00018003
  37. };
  38. static const unsigned short tcvn_2uni_1[24] = {
  39. /* 0x00 */
  40. 0x0000, 0x00da, 0x1ee4, 0x0003, 0x1eea, 0x1eec, 0x1eee, 0x0007,
  41. 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
  42. /* 0x10 */
  43. 0x0010, 0x1ee8, 0x1ef0, 0x1ef2, 0x1ef6, 0x1ef8, 0x00dd, 0x1ef4,
  44. };
  45. static const unsigned short tcvn_2uni_2[128] = {
  46. /* 0x80 */
  47. 0x00c0, 0x1ea2, 0x00c3, 0x00c1, 0x1ea0, 0x1eb6, 0x1eac, 0x00c8,
  48. 0x1eba, 0x1ebc, 0x00c9, 0x1eb8, 0x1ec6, 0x00cc, 0x1ec8, 0x0128,
  49. /* 0x90 */
  50. 0x00cd, 0x1eca, 0x00d2, 0x1ece, 0x00d5, 0x00d3, 0x1ecc, 0x1ed8,
  51. 0x1edc, 0x1ede, 0x1ee0, 0x1eda, 0x1ee2, 0x00d9, 0x1ee6, 0x0168,
  52. /* 0xa0 */
  53. 0x00a0, 0x0102, 0x00c2, 0x00ca, 0x00d4, 0x01a0, 0x01af, 0x0110,
  54. 0x0103, 0x00e2, 0x00ea, 0x00f4, 0x01a1, 0x01b0, 0x0111, 0x1eb0,
  55. /* 0xb0 */
  56. 0x0300, 0x0309, 0x0303, 0x0301, 0x0323, 0x00e0, 0x1ea3, 0x00e3,
  57. 0x00e1, 0x1ea1, 0x1eb2, 0x1eb1, 0x1eb3, 0x1eb5, 0x1eaf, 0x1eb4,
  58. /* 0xc0 */
  59. 0x1eae, 0x1ea6, 0x1ea8, 0x1eaa, 0x1ea4, 0x1ec0, 0x1eb7, 0x1ea7,
  60. 0x1ea9, 0x1eab, 0x1ea5, 0x1ead, 0x00e8, 0x1ec2, 0x1ebb, 0x1ebd,
  61. /* 0xd0 */
  62. 0x00e9, 0x1eb9, 0x1ec1, 0x1ec3, 0x1ec5, 0x1ebf, 0x1ec7, 0x00ec,
  63. 0x1ec9, 0x1ec4, 0x1ebe, 0x1ed2, 0x0129, 0x00ed, 0x1ecb, 0x00f2,
  64. /* 0xe0 */
  65. 0x1ed4, 0x1ecf, 0x00f5, 0x00f3, 0x1ecd, 0x1ed3, 0x1ed5, 0x1ed7,
  66. 0x1ed1, 0x1ed9, 0x1edd, 0x1edf, 0x1ee1, 0x1edb, 0x1ee3, 0x00f9,
  67. /* 0xf0 */
  68. 0x1ed6, 0x1ee7, 0x0169, 0x00fa, 0x1ee5, 0x1eeb, 0x1eed, 0x1eef,
  69. 0x1ee9, 0x1ef1, 0x1ef3, 0x1ef7, 0x1ef9, 0x00fd, 0x1ef5, 0x1ed0,
  70. };
  71. /* In the TCVN to Unicode direction, the state contains a buffered
  72. character, or 0 if none. */
  73. static int
  74. tcvn_mbtowc (conv_t conv, ucs4_t *pwc, const unsigned char *s, int n)
  75. {
  76. unsigned char c = *s;
  77. unsigned short wc;
  78. unsigned short last_wc;
  79. if (c < 0x18)
  80. wc = tcvn_2uni_1[c];
  81. else if (c < 0x80)
  82. wc = c;
  83. else
  84. wc = tcvn_2uni_2[c-0x80];
  85. last_wc = conv->istate;
  86. if (last_wc) {
  87. if (wc >= 0x0300 && wc < 0x0340) {
  88. /* See whether last_wc and wc can be combined. */
  89. unsigned int k;
  90. unsigned int i1, i2;
  91. switch (wc) {
  92. case 0x0300: k = 0; break;
  93. case 0x0301: k = 1; break;
  94. case 0x0303: k = 2; break;
  95. case 0x0309: k = 3; break;
  96. case 0x0323: k = 4; break;
  97. default: abort();
  98. }
  99. i1 = viet_comp_table[k].idx;
  100. i2 = i1 + viet_comp_table[k].len-1;
  101. if (last_wc >= viet_comp_table_data[i1].base
  102. && last_wc <= viet_comp_table_data[i2].base) {
  103. unsigned int i;
  104. for (;;) {
  105. i = (i1+i2)>>1;
  106. if (last_wc == viet_comp_table_data[i].base)
  107. break;
  108. if (last_wc < viet_comp_table_data[i].base) {
  109. if (i1 == i)
  110. goto not_combining;
  111. i2 = i;
  112. } else {
  113. if (i1 != i)
  114. i1 = i;
  115. else {
  116. i = i2;
  117. if (last_wc == viet_comp_table_data[i].base)
  118. break;
  119. goto not_combining;
  120. }
  121. }
  122. }
  123. last_wc = viet_comp_table_data[i].composed;
  124. /* Output the combined character. */
  125. conv->istate = 0;
  126. *pwc = (ucs4_t) last_wc;
  127. return 1;
  128. }
  129. }
  130. not_combining:
  131. /* Output the buffered character. */
  132. conv->istate = 0;
  133. *pwc = (ucs4_t) last_wc;
  134. return 0; /* Don't advance the input pointer. */
  135. }
  136. if (wc >= 0x0041 && wc <= 0x01b0
  137. && ((tcvn_comp_bases[(wc - 0x0040) >> 5] >> (wc & 0x1f)) & 1)) {
  138. /* wc is a possible match in viet_comp_table_data. Buffer it. */
  139. conv->istate = wc;
  140. return RET_TOOFEW(1);
  141. } else {
  142. /* Output wc immediately. */
  143. *pwc = (ucs4_t) wc;
  144. return 1;
  145. }
  146. }
  147. #define tcvn_flushwc normal_flushwc
  148. static const unsigned char tcvn_page00[96+184] = {
  149. 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
  150. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
  151. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
  152. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
  153. 0x80, 0x83, 0xa2, 0x82, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
  154. 0x87, 0x8a, 0xa3, 0x00, 0x8d, 0x90, 0x00, 0x00, /* 0xc8-0xcf */
  155. 0x00, 0x00, 0x92, 0x95, 0xa4, 0x94, 0x00, 0x00, /* 0xd0-0xd7 */
  156. 0x00, 0x9d, 0x01, 0x00, 0x00, 0x16, 0x00, 0x00, /* 0xd8-0xdf */
  157. 0xb5, 0xb8, 0xa9, 0xb7, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
  158. 0xcc, 0xd0, 0xaa, 0x00, 0xd7, 0xdd, 0x00, 0x00, /* 0xe8-0xef */
  159. 0x00, 0x00, 0xdf, 0xe3, 0xab, 0xe2, 0x00, 0x00, /* 0xf0-0xf7 */
  160. 0x00, 0xef, 0xf3, 0x00, 0x00, 0xfd, 0x00, 0x00, /* 0xf8-0xff */
  161. /* 0x0100 */
  162. 0x00, 0x00, 0xa1, 0xa8, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
  163. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
  164. 0xa7, 0xae, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
  165. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
  166. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
  167. 0x8f, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
  168. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
  169. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
  170. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
  171. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
  172. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
  173. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
  174. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
  175. 0x9f, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
  176. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
  177. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
  178. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
  179. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
  180. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
  181. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
  182. 0xa5, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
  183. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6, /* 0xa8-0xaf */
  184. 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
  185. };
  186. static const unsigned char tcvn_page03[40] = {
  187. 0xb0, 0xb3, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
  188. 0x00, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
  189. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
  190. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
  191. 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
  192. };
  193. static const unsigned char tcvn_page1e[96] = {
  194. 0x84, 0xb9, 0x81, 0xb6, 0xc4, 0xca, 0xc1, 0xc7, /* 0xa0-0xa7 */
  195. 0xc2, 0xc8, 0xc3, 0xc9, 0x86, 0xcb, 0xc0, 0xbe, /* 0xa8-0xaf */
  196. 0xaf, 0xbb, 0xba, 0xbc, 0xbf, 0xbd, 0x85, 0xc6, /* 0xb0-0xb7 */
  197. 0x8b, 0xd1, 0x88, 0xce, 0x89, 0xcf, 0xda, 0xd5, /* 0xb8-0xbf */
  198. 0xc5, 0xd2, 0xcd, 0xd3, 0xd9, 0xd4, 0x8c, 0xd6, /* 0xc0-0xc7 */
  199. 0x8e, 0xd8, 0x91, 0xde, 0x96, 0xe4, 0x93, 0xe1, /* 0xc8-0xcf */
  200. 0xff, 0xe8, 0xdb, 0xe5, 0xe0, 0xe6, 0xf0, 0xe7, /* 0xd0-0xd7 */
  201. 0x97, 0xe9, 0x9b, 0xed, 0x98, 0xea, 0x99, 0xeb, /* 0xd8-0xdf */
  202. 0x9a, 0xec, 0x9c, 0xee, 0x02, 0xf4, 0x9e, 0xf1, /* 0xe0-0xe7 */
  203. 0x11, 0xf8, 0x04, 0xf5, 0x05, 0xf6, 0x06, 0xf7, /* 0xe8-0xef */
  204. 0x12, 0xf9, 0x13, 0xfa, 0x17, 0xfe, 0x14, 0xfb, /* 0xf0-0xf7 */
  205. 0x15, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
  206. };
  207. static int
  208. tcvn_wctomb (conv_t conv, unsigned char *r, ucs4_t wc, int n)
  209. {
  210. unsigned char c = 0;
  211. if (wc < 0x0080 && (wc >= 0x0020 || (0x00fe0076 & (1 << wc)) == 0)) {
  212. *r = wc;
  213. return 1;
  214. }
  215. else if (wc >= 0x00a0 && wc < 0x01b8)
  216. c = tcvn_page00[wc-0x00a0];
  217. else if (wc >= 0x0300 && wc < 0x0328)
  218. c = tcvn_page03[wc-0x0300];
  219. else if (wc >= 0x0340 && wc < 0x0342) /* deprecated Vietnamese tone marks */
  220. c = tcvn_page03[wc-0x0340];
  221. else if (wc >= 0x1ea0 && wc < 0x1f00)
  222. c = tcvn_page1e[wc-0x1ea0];
  223. if (c != 0) {
  224. *r = c;
  225. return 1;
  226. }
  227. /* Try compatibility or canonical decomposition. */
  228. {
  229. /* Binary search through viet_decomp_table. */
  230. unsigned int i1 = 0;
  231. unsigned int i2 = sizeof(viet_decomp_table)/sizeof(viet_decomp_table[0])-1;
  232. if (wc >= viet_decomp_table[i1].composed
  233. && wc <= viet_decomp_table[i2].composed) {
  234. unsigned int i;
  235. for (;;) {
  236. /* Here i2 - i1 > 0. */
  237. i = (i1+i2)>>1;
  238. if (wc == viet_decomp_table[i].composed)
  239. break;
  240. if (wc < viet_decomp_table[i].composed) {
  241. if (i1 == i)
  242. return RET_ILUNI;
  243. /* Here i1 < i < i2. */
  244. i2 = i;
  245. } else {
  246. /* Here i1 <= i < i2. */
  247. if (i1 != i)
  248. i1 = i;
  249. else {
  250. /* Here i2 - i1 = 1. */
  251. i = i2;
  252. if (wc == viet_decomp_table[i].composed)
  253. break;
  254. else
  255. return RET_ILUNI;
  256. }
  257. }
  258. }
  259. /* Found a compatibility or canonical decomposition. */
  260. wc = viet_decomp_table[i].base;
  261. /* wc is one of 0x0020, 0x0041..0x005a, 0x0061..0x007a, 0x00a5, 0x00a8,
  262. 0x00c2, 0x00c5..0x00c7, 0x00ca, 0x00cf, 0x00d3, 0x00d4, 0x00d6,
  263. 0x00d8, 0x00da, 0x00dc, 0x00e2, 0x00e5..0x00e7, 0x00ea, 0x00ef,
  264. 0x00f3, 0x00f4, 0x00f6, 0x00f8, 0x00fc, 0x0102, 0x0103, 0x01a0,
  265. 0x01a1, 0x01af, 0x01b0. */
  266. if (wc < 0x0080)
  267. c = wc;
  268. else {
  269. c = tcvn_page00[wc-0x00a0];
  270. if (c == 0)
  271. return RET_ILUNI;
  272. }
  273. if (n < 2)
  274. return RET_TOOSMALL;
  275. r[0] = c;
  276. r[1] = tcvn_comb_table[viet_decomp_table[i].comb1];
  277. return 2;
  278. }
  279. }
  280. return RET_ILUNI;
  281. }