]> mj.ucw.cz Git - libucw.git/blob - ucw/ff-unicode.c
Merge remote-tracking branch 'origin/dev-table' into dev-table
[libucw.git] / ucw / ff-unicode.c
1 /*
2  *      UCW Library: Reading and writing of UTF-8 on Fastbuf Streams
3  *
4  *      (c) 2001--2004 Martin Mares <mj@ucw.cz>
5  *      (c) 2004 Robert Spalek <robert@ucw.cz>
6  *
7  *      This software may be freely distributed and used according to the terms
8  *      of the GNU Lesser General Public License.
9  */
10
11 #include <ucw/lib.h>
12 #include <ucw/fastbuf.h>
13 #include <ucw/unicode.h>
14 #include <ucw/ff-unicode.h>
15 #include <ucw/ff-binary.h>
16
17 /*** UTF-8 ***/
18
19 int
20 bget_utf8_slow(struct fastbuf *b, uint repl)
21 {
22   int c = bgetc(b);
23   int code;
24
25   if (c < 0x80)                         /* Includes EOF */
26     return c;
27   if (c < 0xc0)                         /* Incorrect combination */
28     return repl;
29   if (c >= 0xf0)                        /* Too large, skip it */
30     {
31       while ((c = bgetc(b)) >= 0x80 && c < 0xc0)
32         ;
33       goto wrong;
34     }
35   if (c >= 0xe0)                        /* 3 bytes */
36     {
37       code = c & 0x0f;
38       if ((c = bgetc(b)) < 0x80 || c >= 0xc0)
39         goto wrong;
40       code = (code << 6) | (c & 0x3f);
41       if ((c = bgetc(b)) < 0x80 || c >= 0xc0)
42         goto wrong;
43       code = (code << 6) | (c & 0x3f);
44     }
45   else                                  /* 2 bytes */
46     {
47       code = c & 0x1f;
48       if ((c = bgetc(b)) < 0x80 || c >= 0xc0)
49         goto wrong;
50       code = (code << 6) | (c & 0x3f);
51     }
52   return code;
53
54  wrong:
55   if (c >= 0)
56     bungetc(b);
57   return repl;
58 }
59
60 int
61 bget_utf8_32_slow(struct fastbuf *b, uint repl)
62 {
63   int c = bgetc(b);
64   int code;
65   int nr;
66
67   if (c < 0x80)                         /* Includes EOF */
68     return c;
69   if (c < 0xc0)                         /* Incorrect combination */
70     return repl;
71   if (c < 0xe0)
72     {
73       code = c & 0x1f;
74       nr = 1;
75     }
76   else if (c < 0xf0)
77     {
78       code = c & 0x0f;
79       nr = 2;
80     }
81   else if (c < 0xf8)
82     {
83       code = c & 0x07;
84       nr = 3;
85     }
86   else if (c < 0xfc)
87     {
88       code = c & 0x03;
89       nr = 4;
90     }
91   else if (c < 0xfe)
92     {
93       code = c & 0x01;
94       nr = 5;
95     }
96   else                                  /* Too large, skip it */
97     {
98       while ((c = bgetc(b)) >= 0x80 && c < 0xc0)
99         ;
100       goto wrong;
101     }
102   while (nr-- > 0)
103     {
104       if ((c = bgetc(b)) < 0x80 || c >= 0xc0)
105         goto wrong;
106       code = (code << 6) | (c & 0x3f);
107     }
108   return code;
109
110  wrong:
111   if (c >= 0)
112     bungetc(b);
113   return repl;
114 }
115
116 void
117 bput_utf8_slow(struct fastbuf *b, uint u)
118 {
119   ASSERT(u < 65536);
120   if (u < 0x80)
121     bputc(b, u);
122   else
123     {
124       if (u < 0x800)
125         bputc(b, 0xc0 | (u >> 6));
126       else
127         {
128           bputc(b, 0xe0 | (u >> 12));
129           bputc(b, 0x80 | ((u >> 6) & 0x3f));
130         }
131       bputc(b, 0x80 | (u & 0x3f));
132     }
133 }
134
135 void
136 bput_utf8_32_slow(struct fastbuf *b, uint u)
137 {
138   ASSERT(u < (1U<<31));
139   if (u < 0x80)
140     bputc(b, u);
141   else
142     {
143       if (u < 0x800)
144         bputc(b, 0xc0 | (u >> 6));
145       else
146         {
147           if (u < (1<<16))
148             bputc(b, 0xe0 | (u >> 12));
149           else
150             {
151               if (u < (1<<21))
152                 bputc(b, 0xf0 | (u >> 18));
153               else
154                 {
155                   if (u < (1<<26))
156                     bputc(b, 0xf8 | (u >> 24));
157                   else
158                     {
159                       bputc(b, 0xfc | (u >> 30));
160                       bputc(b, 0x80 | ((u >> 24) & 0x3f));
161                     }
162                   bputc(b, 0x80 | ((u >> 18) & 0x3f));
163                 }
164               bputc(b, 0x80 | ((u >> 12) & 0x3f));
165             }
166           bputc(b, 0x80 | ((u >> 6) & 0x3f));
167         }
168       bputc(b, 0x80 | (u & 0x3f));
169     }
170 }
171
172 /*** UTF-16 ***/
173
174 int
175 bget_utf16_be_slow(struct fastbuf *b, uint repl)
176 {
177   if (bpeekc(b) < 0)
178     return -1;
179   uint u = bgetw_be(b), x, y;
180   if ((int)u < 0)
181     return repl;
182   if ((x = u - 0xd800) >= 0x800)
183     return u;
184   if (x >= 0x400 || bpeekc(b) < 0 || (y = bgetw_be(b) - 0xdc00) >= 0x400)
185     return repl;
186   return 0x10000 + (x << 10) + y;
187 }
188
189 int
190 bget_utf16_le_slow(struct fastbuf *b, uint repl)
191 {
192   if (bpeekc(b) < 0)
193     return -1;
194   uint u = bgetw_le(b), x, y;
195   if ((int)u < 0)
196     return repl;
197   if ((x = u - 0xd800) >= 0x800)
198     return u;
199   if (x >= 0x400 || bpeekc(b) < 0 || (y = bgetw_le(b) - 0xdc00) >= 0x400)
200     return repl;
201   return 0x10000 + (x << 10) + y;
202 }
203
204 void
205 bput_utf16_be_slow(struct fastbuf *b, uint u)
206 {
207   if (u < 0xd800 || (u < 0x10000 && u >= 0xe000))
208     {
209       bputc(b, u >> 8);
210       bputc(b, u & 0xff);
211     }
212   else if ((u -= 0x10000) < 0x100000)
213     {
214       bputc(b, 0xd8 | (u >> 18));
215       bputc(b, (u >> 10) & 0xff);
216       bputc(b, 0xdc | ((u >> 8) & 0x3));
217       bputc(b, u & 0xff);
218     }
219   else
220     ASSERT(0);
221 }
222
223 void
224 bput_utf16_le_slow(struct fastbuf *b, uint u)
225 {
226   if (u < 0xd800 || (u < 0x10000 && u >= 0xe000))
227     {
228       bputc(b, u & 0xff);
229       bputc(b, u >> 8);
230     }
231   else if ((u -= 0x10000) < 0x100000)
232     {
233       bputc(b, (u >> 10) & 0xff);
234       bputc(b, 0xd8 | (u >> 18));
235       bputc(b, u & 0xff);
236       bputc(b, 0xdc | ((u >> 8) & 0x3));
237     }
238   else
239     ASSERT(0);
240 }
241
242 #ifdef TEST
243
244 #include <stdlib.h>
245 #include <stdio.h>
246
247 int main(int argc, char **argv)
248 {
249 #define FUNCS \
250   F(BGET_UTF8) F(BGET_UTF8_32) F(BGET_UTF16_BE) F(BGET_UTF16_LE) \
251   F(BPUT_UTF8) F(BPUT_UTF8_32) F(BPUT_UTF16_BE) F(BPUT_UTF16_LE)
252
253   enum {
254 #define F(x) FUNC_##x,
255     FUNCS
256 #undef F
257   };
258   char *names[] = {
259 #define F(x) [FUNC_##x] = #x,
260     FUNCS
261 #undef F
262   };
263
264   uint func = ~0U;
265   if (argc > 1)
266     for (uint i = 0; i < ARRAY_SIZE(names); i++)
267       if (!strcasecmp(names[i], argv[1]))
268         func = i;
269   if (!~func)
270     {
271       fprintf(stderr, "Invalid usage!\n");
272       return 1;
273     }
274
275   struct fastbuf *b = fbgrow_create(8);
276   if (func < FUNC_BPUT_UTF8)
277     {
278       uint u;
279       while (scanf("%x", &u) == 1)
280         bputc(b, u);
281       fbgrow_rewind(b);
282       while (bpeekc(b) >= 0)
283         {
284           if (btell(b))
285             putchar(' ');
286           switch (func)
287             {
288               case FUNC_BGET_UTF8:
289                 u = bget_utf8_slow(b, UNI_REPLACEMENT);
290                 break;
291               case FUNC_BGET_UTF8_32:
292                 u = bget_utf8_32_slow(b, UNI_REPLACEMENT);
293                 break;
294               case FUNC_BGET_UTF16_BE:
295                 u = bget_utf16_be_slow(b, UNI_REPLACEMENT);
296                 break;
297               case FUNC_BGET_UTF16_LE:
298                 u = bget_utf16_le_slow(b, UNI_REPLACEMENT);
299                 break;
300               default:
301                 ASSERT(0);
302             }
303           printf("%04x", u);
304         }
305       putchar('\n');
306     }
307   else
308     {
309       uint u, i = 0;
310       while (scanf("%x", &u) == 1)
311         {
312           switch (func)
313             {
314               case FUNC_BPUT_UTF8:
315                 bput_utf8_slow(b, u);
316                 break;
317               case FUNC_BPUT_UTF8_32:
318                 bput_utf8_32_slow(b, u);
319                 break;
320               case FUNC_BPUT_UTF16_BE:
321                 bput_utf16_be_slow(b, u);
322                 break;
323               case FUNC_BPUT_UTF16_LE:
324                 bput_utf16_le_slow(b, u);
325                 break;
326               default:
327                 ASSERT(0);
328             }
329           fbgrow_rewind(b);
330           u = 0;
331           while (bpeekc(b) >= 0)
332             {
333               if (i++)
334                 putchar(' ');
335               printf("%02x", bgetc(b));
336             }
337           fbgrow_reset(b);
338         }
339       putchar('\n');
340     }
341   bclose(b);
342
343   return 0;
344 }
345
346 #endif