1/* 2 * generic_cjk 3 * Copyright (C) TSUBAKIMOTO Hiroya <zorac@4000do.co.jp> 2004 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 */ 19 20#ifdef HAVE_CONFIG_H 21#include "config.h" 22#endif /* HAVE_CONFIG_H */ 23 24#if HAVE_USABLE_ICONV 25 26#include "generic_cjk.h" 27#include <string.h> 28 29static size_t cjk_iconv(void *cd, char **inbuf, char *end, 30 char **outbuf, size_t *outbytesleft) 31{ 32 size_t n = end - *inbuf; 33 if (iconv(cd, (ICONV_CONST char**)inbuf, &n, outbuf, outbytesleft) == (size_t)-1) { 34 iconv(cd, NULL, NULL, NULL, NULL); 35 } 36 return n; 37} 38 39size_t cjk_generic_push(size_t (*char_func)(u_int8_t*, const ucs2_t*, size_t*), 40 void *cd, char **inbuf, size_t *inbytesleft, 41 char **outbuf, size_t *outbytesleft) 42{ 43 char *in = *inbuf; 44 45 while (*inbytesleft >= sizeof(ucs2_t) && *outbytesleft > 0) { 46 u_int8_t buf[CJK_PUSH_BUFFER]; 47 size_t size = *inbytesleft / sizeof(ucs2_t); 48 size_t n = (char_func)(buf, (const ucs2_t*)in, &size); 49 if (n == 0) { 50 in += size * sizeof(ucs2_t); 51 *inbytesleft -= size * sizeof(ucs2_t); 52 continue; 53 } 54 if (in != *inbuf) { 55 int err = errno; 56 57 *inbytesleft += cjk_iconv(cd, inbuf, in, outbuf, outbytesleft); 58 if (in != *inbuf) return -1; 59 errno = err; 60 } 61 if (n == (size_t)-1) return -1; 62 if (*outbytesleft < n) break; 63 memcpy(*outbuf, buf, n); 64 *outbuf += n; 65 *outbytesleft -= n; 66 in += size * sizeof(ucs2_t); 67 *inbytesleft -= size * sizeof(ucs2_t); 68 *inbuf = in; 69 } 70 if (in != *inbuf) { 71 *inbytesleft += cjk_iconv(cd, inbuf, in, outbuf, outbytesleft); 72 if (in != *inbuf) return -1; 73 } 74 if (*inbytesleft > 0) { 75 errno = (*inbytesleft < sizeof(ucs2_t) ? EINVAL : E2BIG); 76 return -1; 77 } 78 return 0; 79} 80 81size_t cjk_generic_pull(size_t (*char_func)(ucs2_t*, const u_int8_t*, size_t*), 82 void *cd, char **inbuf, size_t *inbytesleft, 83 char **outbuf, size_t *outbytesleft) 84{ 85 char *in = *inbuf; 86 87 while (*inbytesleft > 0 && *outbytesleft >= sizeof(ucs2_t)) { 88 ucs2_t buf[CJK_PULL_BUFFER]; 89 size_t size = *inbytesleft; 90 size_t n = (char_func)(buf, (const u_int8_t*)in, &size); 91 if (n == 0) { 92 in += size; 93 *inbytesleft -= size; 94 continue; 95 } 96 if (in != *inbuf) { 97 int err = errno; 98 99 *inbytesleft += cjk_iconv(cd, inbuf, in, outbuf, outbytesleft); 100 if (in != *inbuf) return -1; 101 errno = err; 102 } 103 if (n == (size_t)-1) return -1; 104 if (*outbytesleft < n * sizeof(ucs2_t)) break; 105 memcpy(*outbuf, buf, n * sizeof(ucs2_t)); 106 *outbuf += n * sizeof(ucs2_t); 107 *outbytesleft -= n * sizeof(ucs2_t); 108 in += size; 109 *inbytesleft -= size; 110 *inbuf = in; 111 } 112 if (in != *inbuf) { 113 *inbytesleft += cjk_iconv(cd, inbuf, in, outbuf, outbytesleft); 114 if (in != *inbuf) return -1; 115 } 116 if (*inbytesleft > 0) { 117 errno = E2BIG; 118 return -1; 119 } 120 return 0; 121} 122 123size_t cjk_char_push(u_int16_t c, u_int8_t *out) 124{ 125 if (!c) return 0; 126 if (c == (u_int16_t)-1) { 127 errno = EILSEQ; 128 return (size_t)-1; 129 } 130 if (c <= 0xff) { 131 out[0] = (u_int8_t)c; 132 return 1; 133 } 134 out[0] = (u_int8_t)(c >> 8); 135 out[1] = (u_int8_t)c; 136 return 2; 137} 138 139size_t cjk_char_pull(ucs2_t wc, ucs2_t* out, const u_int32_t* compose) 140{ 141 if (!wc) return 0; 142 if ((wc & 0xf000) == 0xe000) { 143 ucs2_t buf[CJK_PULL_BUFFER]; 144 size_t i = sizeof(buf) / sizeof(*buf) - 1; 145 do { 146 u_int32_t v = compose[wc & 0xfff]; 147 buf[i] = (ucs2_t)v; 148 wc = (ucs2_t)(v >> 16); 149 } while (--i && (wc & 0xf000) == 0xe000); 150 buf[i] = wc; 151 memcpy(out, buf + i, sizeof(buf) - sizeof(*buf) * i); 152 return sizeof(buf) / sizeof(*buf) - i; 153 } 154 *out = wc; 155 return 1; 156} 157 158u_int16_t cjk_lookup(u_int16_t c, const cjk_index_t *index, const u_int16_t *charset) 159{ 160 while (index->summary && c >= index->range[0]) { 161 if (c <= index->range[1]) { 162 const u_int16_t* summary = index->summary[(c - index->range[0]) >> 4]; 163 u_int16_t used = 1 << (c & 15); 164 165 if (summary[0] & used) { 166 used = summary[0] & (used - 1); 167 charset += summary[1]; 168 while (used) used &= used - 1, ++charset; 169 return *charset; 170 } 171 return 0; 172 } 173 ++index; 174 } 175 return 0; 176} 177 178ucs2_t cjk_compose(ucs2_t base, ucs2_t comb, const u_int32_t* table, size_t size) 179{ 180 u_int32_t v = ((u_int32_t)base << 16) | comb; 181 size_t low = 0; 182 while (size > low) { 183 size_t n = (low + size) / 2; 184 if (table[n] == v) return 0xe000 + n; 185 if (table[n] < v) { 186 low = n + 1; 187 } else { 188 size = n; 189 } 190 } 191 return 0; 192} 193 194ucs2_t cjk_compose_seq(const ucs2_t* in, size_t* len, const u_int32_t* table, size_t size) 195{ 196 static u_int8_t sz[] = { 3, 4, 5, 5, 5, 5, 5, 3 }; 197 ucs2_t wc = in[0]; 198 size_t n = sz[wc & 7]; 199 size_t i = 0; 200 201 if (n > *len) { 202 errno = EINVAL; 203 return 0; 204 } 205 while (++i < n) { 206 wc = cjk_compose(wc, in[i], table, size); 207 if (!wc) { 208 errno = EILSEQ; 209 return 0; 210 } 211 } 212 *len = n; 213 return wc; 214} 215#endif 216