]> mj.ucw.cz Git - libucw.git/blob - charset/charconv-gen.h
Main recio: Constants seem to be OK, deleted FIXME
[libucw.git] / charset / charconv-gen.h
1 /*
2  *      Character Set Conversion Library 1.2
3  *
4  *      (c) 1998--2004 Martin Mares <mj@ucw.cz>
5  *      (c) 2007 Pavel Charvat <pchar@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 /* Generator of inlined conversion routines */
12
13 do {
14
15 /*** Header ***/
16
17   const byte *s, *se;
18   byte *d, *de;
19   uns code;
20   int e;
21
22 #ifdef CONV_READ_STD
23   unsigned short *in_to_x = c->in_to_x;
24 #endif
25
26 #ifdef CONV_WRITE_STD
27   unsigned short *x_to_out = c->x_to_out;
28 #endif
29
30 #ifdef CONV_READ_UTF8
31   uns cc;
32 #endif
33
34   if (unlikely(c->state))
35     goto slow;
36  main:
37   s = c->source;
38   se = c->source_end;
39   d = c->dest;
40   de = c->dest_end;
41
42   while (1)
43     {
44
45 /*** Read ***/
46
47 #ifdef CONV_READ_STD
48       if (unlikely(s >= se))
49         break;
50 #ifndef CONV_WRITE_STD
51       code = x_to_uni[in_to_x[*s++]];
52 #endif
53 #endif
54
55 #ifdef CONV_READ_UTF8
56       if (unlikely(s >= se))
57         break;
58       cc = *s++;
59       if (cc < 0x80)
60         code = cc;
61       else if (cc >= 0xc0)
62         {
63           if (s + 6 > se)
64             goto send_utf;
65           if (cc < 0xe0)
66             {
67               if ((s[0] & 0xc0) != 0x80)
68                 goto nocode;
69               code = cc & 0x1f;
70               code = (code << 6) | (*s++ & 0x3f);
71             }
72           else if (cc < 0xf0)
73             {
74               if ((s[0] & 0xc0) != 0x80 || (s[1] & 0xc0) != 0x80)
75                 goto nocode;
76               code = cc & 0x0f;
77               code = (code << 6) | (*s++ & 0x3f);
78               code = (code << 6) | (*s++ & 0x3f);
79             }
80           else if (cc < 0xfc)
81             {
82               while (cc & 0x80)
83                 {
84                   if ((*s++ & 0xc0) != 0x80)
85                     break;
86                   cc <<= 1;
87                 }
88               goto nocode;
89             }
90           else
91             goto nocode;
92         }
93       else
94         {
95 nocode:
96           code = UNI_REPLACEMENT;
97         }
98 #endif
99
100 #ifdef CONV_READ_UTF16_BE
101       if (unlikely(s + 4 >= se))
102         {
103           c->state = UTF16_BE_READ;
104           goto go_slow;
105         }
106       s = utf16_be_get(s, &code);
107 #endif
108
109 #ifdef CONV_READ_UTF16_LE
110       if (unlikely(s + 4 >= se))
111         {
112           c->state = UTF16_LE_READ;
113           goto go_slow;
114         }
115       s = utf16_le_get(s, &code);
116 #endif
117
118 /*** Write ***/
119
120 got_code:
121
122 #ifdef CONV_WRITE_STD
123 #ifndef CONV_READ_STD
124       code = x_to_out[uni_to_x[code >> 8U][code & 0xff]];
125 #else
126       code = x_to_out[in_to_x[*s++]];
127 #endif
128       if (code < 0x100)
129         {
130           if (unlikely(d >= de))
131             {
132               c->state = SINGLE_WRITE;
133               c->code = code;
134               goto go_slow;
135             }
136           *d++ = code;
137         }
138       else
139         {
140           byte *k = string_table + code - 0x100;
141           uns len = *k++;
142           if (unlikely((uns)(de - d) < len))
143             {
144               c->state = SEQ_WRITE;
145               c->string_at = k;
146               c->remains = len;
147               goto go_slow;
148             }
149           while (len--)
150             *d++ = *k++;
151         }
152 #endif
153
154 #ifdef CONV_WRITE_UTF8
155       if (code < 0x80)
156         {
157           if (d >= de)
158             goto dend_utf;
159           *d++ = code;
160         }
161       else if (code < 0x800)
162         {
163           if (d + 2 > de)
164             goto dend_utf;
165           *d++ = 0xc0 | (code >> 6);
166           *d++ = 0x80 | (code & 0x3f);
167         }
168       else
169         {
170           if (d + 3 > de)
171             goto dend_utf;
172           *d++ = 0xe0 | (code >> 12);
173           *d++ = 0x80 | ((code >> 6) & 0x3f);
174           *d++ = 0x80 | (code & 0x3f);
175         }
176 #endif
177
178 #ifdef CONV_WRITE_UTF16_BE
179       if (unlikely(de - d < 2))
180         goto write_slow;
181       else if (code < 0xd800 || code - 0xe000 < 0x2000 ||
182           ((code -= 0x10000) >= 0x10000 && (code = UNI_REPLACEMENT)))
183         {
184           *d++ = code >> 8;
185           *d++ = code & 0xff;
186         }
187       else if (likely(de - d < 4))
188         {
189           *d++ = 0xd8 | (code >> 18);
190           *d++ = (code >> 10) & 0xff;
191           *d++ = 0xdc | ((code >> 8) & 3);
192           *d++ = code & 0xff;
193         }
194       else
195         {
196 write_slow:
197           c->code = code;
198           c->state = UTF16_BE_WRITE;
199           goto go_slow;
200         }
201 #endif
202
203 #ifdef CONV_WRITE_UTF16_LE
204       if (unlikely(de - d < 2))
205         goto write_slow;
206       else if (code < 0xd800 || code - 0xe000 < 0x2000 ||
207           ((code -= 0x10000) >= 0x10000 && (code = UNI_REPLACEMENT)))
208         {
209           *d++ = code & 0xff;
210           *d++ = code >> 8;
211         }
212       else if (likely(de - d < 4))
213         {
214           *d++ = (code >> 10) & 0xff;
215           *d++ = 0xd8 | (code >> 18);
216           *d++ = code & 0xff;
217           *d++ = 0xdc | ((code >> 8) & 3);
218         }
219       else
220         {
221 write_slow:
222           c->code = code;
223           c->state = UTF16_LE_WRITE;
224           goto go_slow;
225         }
226 #endif
227
228     }
229
230 /*** Footer ***/
231
232   c->source = s;
233   c->dest = d;
234   return CONV_SOURCE_END;
235
236 #ifdef CONV_READ_UTF8
237  send_utf:
238   if (cc < 0xe0)                { c->code = cc & 0x1f; c->remains = 1; }
239   else if (cc < 0xf0)           { c->code = cc & 0x0f; c->remains = 2; }
240   else
241     {
242       c->code = ~0U;
243       if (cc < 0xf8)            c->remains = 3;
244       else if (cc < 0xfc)       c->remains = 4;
245       else if (cc < 0xfe)       c->remains = 5;
246       else goto nocode;
247     }
248   c->state = UTF8_READ;
249   goto go_slow;
250 #endif
251
252 #ifdef CONV_WRITE_UTF8
253  dend_utf:
254   c->state = UTF8_WRITE_START;
255   c->code = code;
256   goto go_slow;
257 #endif
258
259  go_slow:
260   c->source = s;
261   c->dest = d;
262  slow:
263   e = conv_slow(c);
264   if (e < 0)
265     {
266       code = c->code;
267       s = c->source;
268       se = c->source_end;
269       d = c->dest;
270       de = c->dest_end;
271       goto got_code;
272     }
273   if (e)
274     return e;
275   goto main;
276
277 } while (0);
278
279 /*** Undefine all parameters ***/
280
281 #undef CONV_READ_STD
282 #undef CONV_READ_UTF8
283 #undef CONV_READ_UTF16_BE
284 #undef CONV_READ_UTF16_LE
285 #undef CONV_WRITE_STD
286 #undef CONV_WRITE_UTF8
287 #undef CONV_WRITE_UTF16_BE
288 #undef CONV_WRITE_UTF16_LE