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