iconv.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. #include <iconv.h>
  2. #include <errno.h>
  3. #include <wchar.h>
  4. #include <string.h>
  5. #include <strings.h>
  6. #include <stdlib.h>
  7. #include <limits.h>
  8. #include <dirent.h>
  9. #include <fcntl.h>
  10. #include <sys/mman.h>
  11. #include <sys/stat.h>
  12. #include <unistd.h>
  13. #include <stdint.h>
  14. /* builtin charmaps */
  15. #include "charmaps.h"
  16. /* only 0-7 are valid as dest charset */
  17. #define UTF_16BE 000
  18. #define UTF_16LE 001
  19. #define UTF_32BE 002
  20. #define UTF_32LE 003
  21. #define WCHAR_T 004
  22. #define UTF_8 005
  23. #define US_ASCII 006
  24. #define LATIN_1 007
  25. /* additional charsets with algorithmic conversion */
  26. #define LATIN_9 010
  27. #define TIS_620 011
  28. #define JIS_0201 012
  29. /* some programs like php need this */
  30. int _libiconv_version = _LIBICONV_VERSION;
  31. /* these must match the constants above */
  32. static const unsigned char charsets[] =
  33. "\005" "UTF-8" "\0"
  34. "\004" "WCHAR_T" "\0"
  35. "\000" "UTF-16BE" "\0"
  36. "\001" "UTF-16LE" "\0"
  37. "\002" "UTF-32BE" "\0"
  38. "\003" "UTF-32LE" "\0"
  39. "\006" "ASCII" "\0"
  40. "\006" "US-ASCII" "\0"
  41. "\006" "ISO646-US" "\0"
  42. "\006" "ISO_646.IRV:1991" "\0"
  43. "\006" "ISO-IR-6" "\0"
  44. "\006" "ANSI_X3.4-1968" "\0"
  45. "\006" "ANSI_X3.4-1986" "\0"
  46. "\006" "CP367" "\0"
  47. "\006" "IBM367" "\0"
  48. "\006" "US" "\0"
  49. "\006" "CSASCII" "\0"
  50. "\007" "ISO-8859-1" "\0"
  51. "\007" "LATIN1" "\0"
  52. "\010" "ISO-8859-15""\0"
  53. "\010" "LATIN9" "\0"
  54. "\011" "ISO-8859-11""\0"
  55. "\011" "TIS-620" "\0"
  56. "\012" "JIS-0201" "\0"
  57. "\377";
  58. /* separate identifiers for sbcs/dbcs/etc map type */
  59. #define UCS2_8BIT 000
  60. #define UCS3_8BIT 001
  61. #define EUC 002
  62. #define EUC_TW 003
  63. #define SHIFT_JIS 004
  64. #define BIG5 005
  65. #define GBK 006
  66. /* FIXME: these are not implemented yet
  67. // EUC: A1-FE A1-FE
  68. // GBK: 81-FE 40-7E,80-FE
  69. // Big5: A1-FE 40-7E,A1-FE
  70. */
  71. static const unsigned short maplen[] = {
  72. [UCS2_8BIT] = 4+ 2* 128,
  73. [UCS3_8BIT] = 4+ 3* 128,
  74. [EUC] = 4+ 2* 94*94,
  75. [SHIFT_JIS] = 4+ 2* 94*94,
  76. [BIG5] = 4+ 2* 94*157,
  77. [GBK] = 4+ 2* 126*190,
  78. [EUC_TW] = 4+ 2* 2*94*94,
  79. };
  80. static int find_charmap(const char *name)
  81. {
  82. int i;
  83. for (i = 0; i < (sizeof(charmaps) / sizeof(charmaps[0])); i++)
  84. if (!strcasecmp(charmaps[i].name, name))
  85. return i;
  86. return -1;
  87. }
  88. static int find_charset(const char *name)
  89. {
  90. const unsigned char *s;
  91. for (s=charsets; *s<0xff && strcasecmp(s+1, name); s+=strlen(s)+1);
  92. return *s;
  93. }
  94. iconv_t iconv_open(const char *to, const char *from)
  95. {
  96. unsigned f, t;
  97. int m;
  98. if ((t = find_charset(to)) > 8)
  99. return -1;
  100. if ((f = find_charset(from)) < 255)
  101. return 0 | (t<<1) | (f<<8);
  102. if ((m = find_charmap(from)) > -1)
  103. return 1 | (t<<1) | (m<<8);
  104. return -1;
  105. }
  106. int iconv_close(iconv_t cd)
  107. {
  108. return 0;
  109. }
  110. static inline wchar_t get_16(const unsigned char *s, int endian)
  111. {
  112. endian &= 1;
  113. return s[endian]<<8 | s[endian^1];
  114. }
  115. static inline void put_16(unsigned char *s, wchar_t c, int endian)
  116. {
  117. endian &= 1;
  118. s[endian] = c>>8;
  119. s[endian^1] = c;
  120. }
  121. static inline int utf8enc_wchar(char *outb, wchar_t c)
  122. {
  123. if (c <= 0x7F) {
  124. *outb = c;
  125. return 1;
  126. }
  127. else if (c <= 0x7FF) {
  128. *outb++ = ((c >> 6) & 0x1F) | 0xC0;
  129. *outb++ = ( c & 0x3F) | 0x80;
  130. return 2;
  131. }
  132. else if (c <= 0xFFFF) {
  133. *outb++ = ((c >> 12) & 0x0F) | 0xE0;
  134. *outb++ = ((c >> 6) & 0x3F) | 0x80;
  135. *outb++ = ( c & 0x3F) | 0x80;
  136. return 3;
  137. }
  138. else if (c <= 0x10FFFF) {
  139. *outb++ = ((c >> 18) & 0x07) | 0xF0;
  140. *outb++ = ((c >> 12) & 0x3F) | 0x80;
  141. *outb++ = ((c >> 6) & 0x3F) | 0x80;
  142. *outb++ = ( c & 0x3F) | 0x80;
  143. return 4;
  144. }
  145. else {
  146. *outb++ = '?';
  147. return 1;
  148. }
  149. }
  150. static inline int utf8seq_is_overlong(char *s, int n)
  151. {
  152. switch (n)
  153. {
  154. case 2:
  155. /* 1100000x (10xxxxxx) */
  156. return (((*s >> 1) == 0x60) &&
  157. ((*(s+1) >> 6) == 0x02));
  158. case 3:
  159. /* 11100000 100xxxxx (10xxxxxx) */
  160. return ((*s == 0xE0) &&
  161. ((*(s+1) >> 5) == 0x04) &&
  162. ((*(s+2) >> 6) == 0x02));
  163. case 4:
  164. /* 11110000 1000xxxx (10xxxxxx 10xxxxxx) */
  165. return ((*s == 0xF0) &&
  166. ((*(s+1) >> 4) == 0x08) &&
  167. ((*(s+2) >> 6) == 0x02) &&
  168. ((*(s+3) >> 6) == 0x02));
  169. }
  170. return 0;
  171. }
  172. static inline int utf8seq_is_surrogate(char *s, int n)
  173. {
  174. return ((n == 3) && (*s == 0xED) && (*(s+1) >= 0xA0) && (*(s+1) <= 0xBF));
  175. }
  176. static inline int utf8seq_is_illegal(char *s, int n)
  177. {
  178. return ((n == 3) && (*s == 0xEF) && (*(s+1) == 0xBF) &&
  179. (*(s+2) >= 0xBE) && (*(s+2) <= 0xBF));
  180. }
  181. static inline int utf8dec_wchar(wchar_t *c, unsigned char *in, size_t inb)
  182. {
  183. int i;
  184. int n = -1;
  185. /* trivial char */
  186. if (*in <= 0x7F) {
  187. *c = *in;
  188. return 1;
  189. }
  190. /* find utf8 sequence length */
  191. if ((*in & 0xE0) == 0xC0) n = 2;
  192. else if ((*in & 0xF0) == 0xE0) n = 3;
  193. else if ((*in & 0xF8) == 0xF0) n = 4;
  194. else if ((*in & 0xFC) == 0xF8) n = 5;
  195. else if ((*in & 0xFE) == 0xFC) n = 6;
  196. /* starved? */
  197. if (n > inb)
  198. return -2;
  199. /* decode ... */
  200. if (n > 1 && n < 5) {
  201. /* reject invalid sequences */
  202. if (utf8seq_is_overlong(in, n) ||
  203. utf8seq_is_surrogate(in, n) ||
  204. utf8seq_is_illegal(in, n))
  205. return -1;
  206. /* decode ... */
  207. *c = (char)(*in++ & (0x7F >> n));
  208. for (i = 1; i < n; i++) {
  209. /* illegal continuation byte */
  210. if (*in < 0x80 || *in > 0xBF)
  211. return -1;
  212. *c = (*c << 6) | (*in++ & 0x3F);
  213. }
  214. return n;
  215. }
  216. /* unmapped sequence (> 4) */
  217. return -1;
  218. }
  219. static inline wchar_t latin9_translit(wchar_t c)
  220. {
  221. /* a number of trivial iso-8859-15 <> utf-8 transliterations */
  222. switch (c) {
  223. case 0x20AC: return 0xA4; /* Euro */
  224. case 0x0160: return 0xA6; /* S caron */
  225. case 0x0161: return 0xA8; /* s caron */
  226. case 0x017D: return 0xB4; /* Z caron */
  227. case 0x017E: return 0xB8; /* z caron */
  228. case 0x0152: return 0xBC; /* OE */
  229. case 0x0153: return 0xBD; /* oe */
  230. case 0x0178: return 0xBE; /* Y diaeresis */
  231. default: return 0xFFFD; /* cannot translate */
  232. }
  233. }
  234. size_t iconv(iconv_t cd, char **in, size_t *inb, char **out, size_t *outb)
  235. {
  236. size_t x=0;
  237. unsigned char to = (cd>>1)&127;
  238. unsigned char from = 255;
  239. const unsigned char *map = 0;
  240. char tmp[MB_LEN_MAX];
  241. wchar_t c, d;
  242. size_t k, l;
  243. int err;
  244. if (!in || !*in || !*inb) return 0;
  245. if (cd & 1)
  246. map = charmaps[cd>>8].map;
  247. else
  248. from = cd>>8;
  249. for (; *inb; *in+=l, *inb-=l) {
  250. c = *(unsigned char *)*in;
  251. l = 1;
  252. if (from >= UTF_8 && c < 0x80) goto charok;
  253. switch (from) {
  254. case WCHAR_T:
  255. l = sizeof(wchar_t);
  256. if (*inb < l) goto starved;
  257. c = *(wchar_t *)*in;
  258. break;
  259. case UTF_8:
  260. l = utf8dec_wchar(&c, *in, *inb);
  261. if (!l) l++;
  262. else if (l == (size_t)-1) goto ilseq;
  263. else if (l == (size_t)-2) goto starved;
  264. break;
  265. case US_ASCII:
  266. goto ilseq;
  267. case LATIN_9:
  268. if ((unsigned)c - 0xa4 <= 0xbe - 0xa4) {
  269. static const unsigned char map[] = {
  270. 0, 0x60, 0, 0x61, 0, 0, 0, 0, 0, 0, 0,
  271. 0, 0, 0, 0, 0x7d, 0, 0, 0, 0x7e, 0, 0, 0,
  272. 0x52, 0x53, 0x78
  273. };
  274. if (c == 0xa4) c = 0x20ac;
  275. else if (map[c-0xa5]) c = 0x100 | map[c-0xa5];
  276. }
  277. case LATIN_1:
  278. goto charok;
  279. case TIS_620:
  280. if (c >= 0xa1) c += 0x0e01-0xa1;
  281. goto charok;
  282. case JIS_0201:
  283. if (c >= 0xa1) {
  284. if (c <= 0xdf) c += 0xff61-0xa1;
  285. else goto ilseq;
  286. }
  287. goto charok;
  288. case UTF_16BE:
  289. case UTF_16LE:
  290. l = 2;
  291. if (*inb < 2) goto starved;
  292. c = get_16(*in, from);
  293. if ((unsigned)(c-0xdc00) < 0x400) goto ilseq;
  294. if ((unsigned)(c-0xd800) < 0x400) {
  295. l = 4;
  296. if (*inb < 4) goto starved;
  297. d = get_16(*in + 2, from);
  298. if ((unsigned)(c-0xdc00) >= 0x400) goto ilseq;
  299. c = ((c-0xd800)<<10) | (d-0xdc00);
  300. }
  301. break;
  302. case UTF_32BE:
  303. case UTF_32LE:
  304. l = 4;
  305. if (*inb < 4) goto starved;
  306. // FIXME
  307. // c = get_32(*in, from);
  308. break;
  309. default:
  310. /* only support ascii supersets */
  311. if (c < 0x80) break;
  312. switch (map[0]) {
  313. case UCS2_8BIT:
  314. c -= 0x80;
  315. break;
  316. case EUC:
  317. if ((unsigned)c - 0xa1 >= 94) goto ilseq;
  318. if ((unsigned)in[0][1] - 0xa1 >= 94) goto ilseq;
  319. c = (c-0xa1)*94 + (in[0][1]-0xa1);
  320. l = 2;
  321. break;
  322. case SHIFT_JIS:
  323. if ((unsigned)c - 0xa1 <= 0xdf-0xa1) {
  324. c += 0xff61-0xa1;
  325. goto charok;
  326. }
  327. // FIXME...
  328. l = 2;
  329. break;
  330. default:
  331. goto badf;
  332. }
  333. c = get_16(map + 4 + 2*c, 0);
  334. if (c == 0xffff) goto ilseq;
  335. goto charok;
  336. }
  337. if ((unsigned)c - 0xd800 < 0x800 || (unsigned)c >= 0x110000)
  338. goto ilseq;
  339. charok:
  340. switch (to) {
  341. case WCHAR_T:
  342. if (*outb < sizeof(wchar_t)) goto toobig;
  343. *(wchar_t *)*out = c;
  344. *out += sizeof(wchar_t);
  345. *outb -= sizeof(wchar_t);
  346. break;
  347. case UTF_8:
  348. if (*outb < 4) {
  349. k = utf8enc_wchar(tmp, c);
  350. if (*outb < k) goto toobig;
  351. memcpy(*out, tmp, k);
  352. } else k = utf8enc_wchar(*out, c);
  353. *out += k;
  354. *outb -= k;
  355. break;
  356. case US_ASCII:
  357. if (c > 0x7f) c = 0xfffd;
  358. /* fall thru and count replacement in latin1 case */
  359. case LATIN_9:
  360. if (c >= 0x100 && c != 0xfffd)
  361. c = latin9_translit(c);
  362. /* fall through */
  363. case LATIN_1:
  364. if (c > 0xff) goto ilseq;
  365. if (!*outb) goto toobig;
  366. **out = c;
  367. ++*out;
  368. --*outb;
  369. break;
  370. case UTF_16BE:
  371. case UTF_16LE:
  372. if (c < 0x10000) {
  373. if (*outb < 2) goto toobig;
  374. put_16(*out, c, to);
  375. *out += 2;
  376. *outb -= 2;
  377. break;
  378. }
  379. if (*outb < 4) goto toobig;
  380. put_16(*out, (c>>10)|0xd800, to);
  381. put_16(*out + 2, (c&0x3ff)|0xdc00, to);
  382. *out += 4;
  383. *outb -= 4;
  384. break;
  385. default:
  386. goto badf;
  387. }
  388. }
  389. return x;
  390. ilseq:
  391. err = EILSEQ;
  392. x = -1;
  393. goto end;
  394. badf:
  395. err = EBADF;
  396. x = -1;
  397. goto end;
  398. toobig:
  399. err = E2BIG;
  400. x = -1;
  401. goto end;
  402. starved:
  403. err = EINVAL;
  404. end:
  405. errno = err;
  406. return x;
  407. }