]> arthur.barton.de Git - netatalk.git/blob - libatalk/unicode/charsets/generic_cjk.c
Merge master
[netatalk.git] / libatalk / unicode / charsets / generic_cjk.c
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
29 static 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
39 size_t cjk_generic_push(size_t (*char_func)(uint8_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     uint8_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
81 size_t cjk_generic_pull(size_t (*char_func)(ucs2_t*, const uint8_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 uint8_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
123 size_t cjk_char_push(uint16_t c, uint8_t *out)
124 {
125   if (!c) return 0;
126   if (c == (uint16_t)-1) {
127     errno = EILSEQ;
128     return (size_t)-1;
129   }
130   if (c <= 0xff) {
131     out[0] = (uint8_t)c;
132     return 1;
133   }
134   out[0] = (uint8_t)(c >> 8);
135   out[1] = (uint8_t)c;
136   return 2;
137 }
138
139 size_t cjk_char_pull(ucs2_t wc, ucs2_t* out, const uint32_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       uint32_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
158 uint16_t cjk_lookup(uint16_t c, const cjk_index_t *index, const uint16_t *charset)
159 {
160   while (index->summary && c >= index->range[0]) {
161     if (c <= index->range[1]) {
162       const uint16_t* summary = index->summary[(c - index->range[0]) >> 4];
163       uint16_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
178 ucs2_t cjk_compose(ucs2_t base, ucs2_t comb, const uint32_t* table, size_t size)
179 {
180   uint32_t v = ((uint32_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
194 ucs2_t cjk_compose_seq(const ucs2_t* in, size_t* len, const uint32_t* table, size_t size)
195 {
196   static uint8_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