Initialize Tizen 2.3
[framework/base/tizen-locale.git] / iconvdata / tscii.c
1 /* Conversion from and to TSCII.
2    Copyright (C) 2002, 2004 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Bruno Haible <bruno@clisp.org>, 2002.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, write to the Free
18    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20
21 #include <dlfcn.h>
22 #include <stdint.h>
23 #include <gconv.h>
24 #include <assert.h>
25
26 /* TSCII is an 8-bit encoding consisting of:
27    0x00..0x7F:       ASCII
28    0x80..0x90, 0x95..0x9F, 0xAB..0xFE:
29                      Tamil letters and glyphs
30    0xA1..0xA5, 0xAA: Tamil combining letters (after the base character)
31    0xA6..0xA8:       Tamil combining letters (before the base character)
32    0x91..0x94:       Punctuation
33    0xA9:             Symbols
34 */
35
36 /* Definitions used in the body of the `gconv' function.  */
37 #define CHARSET_NAME            "TSCII//"
38 #define FROM_LOOP               from_tscii
39 #define TO_LOOP                 to_tscii
40 #define DEFINE_INIT             1
41 #define DEFINE_FINI             1
42 #define FROM_LOOP_MIN_NEEDED_FROM       1
43 #define FROM_LOOP_MAX_NEEDED_FROM       2
44 #define FROM_LOOP_MIN_NEEDED_TO         4
45 #define FROM_LOOP_MAX_NEEDED_TO        16
46 #define TO_LOOP_MIN_NEEDED_FROM         4
47 #define TO_LOOP_MAX_NEEDED_FROM         4
48 #define TO_LOOP_MIN_NEEDED_TO           1
49 #define TO_LOOP_MAX_NEEDED_TO           3
50 #define PREPARE_LOOP \
51   int saved_state;                                                            \
52   int *statep = &data->__statep->__count;
53 #define EXTRA_LOOP_ARGS         , statep
54
55
56 /* Since we might have to reset input pointer we must be able to save
57    and restore the state.  */
58 #define SAVE_RESET_STATE(Save) \
59   if (Save)                                                                   \
60     saved_state = *statep;                                                    \
61   else                                                                        \
62     *statep = saved_state
63
64
65 /* During TSCII to UCS-4 conversion, the COUNT element of the state contains
66    the last UCS-4 character to be output, shifted by 8 bits, and an encoded
67    representation of additional UCS-4 characters to be output (if any),
68    shifted by 4 bits.  This character can be:
69      0x0000                   Nothing pending.
70      0x0BCD                   Pending VIRAMA sign. If bit 3 is set, it may be
71                               omitted if followed by a vowel sign U or UU.
72      0x0BC6, 0x0BC7, 0x0BC8   Pending vowel sign.  Bit 3 is set after the
73                               consonant was seen.
74      Other                    Bit 3 always cleared.  */
75
76 /* During UCS-4 to TSCII conversion, the COUNT element of the state contains
77    the last byte (or sometimes the last two bytes) to be output, shifted by
78    3 bits. This can be:
79      0x00                     Nothing pending.
80      0xB8..0xC9, 0x83..0x86   A consonant.
81      0xEC, 0x8A               A consonant with VIRAMA sign (final or joining).
82      0x87, 0xC38A             Two consonants combined through a VIRAMA sign. */
83
84 /* Since this is a stateful encoding we have to provide code which resets
85    the output state to the initial state.  This has to be done during the
86    flushing.  */
87 #define EMIT_SHIFT_TO_INIT \
88   if (data->__statep->__count != 0)                                           \
89     {                                                                         \
90       if (FROM_DIRECTION)                                                     \
91         {                                                                     \
92           do                                                                  \
93             {                                                                 \
94               if (__builtin_expect (outbuf + 4 > outend, 0))                  \
95                 {                                                             \
96                   /* We don't have enough room in the output buffer.  */      \
97                   status = __GCONV_FULL_OUTPUT;                               \
98                   break;                                                      \
99                 }                                                             \
100               /* Write out the pending character.  */                         \
101               *((uint32_t *) outbuf) = data->__statep->__count >> 8;          \
102               outbuf += sizeof (uint32_t);                                    \
103               /* Retrieve the successor state.  */                            \
104               data->__statep->__count =                                       \
105                 tscii_next_state[(data->__statep->__count >> 4) & 0x0f];      \
106             }                                                                 \
107           while (data->__statep->__count != 0);                               \
108         }                                                                     \
109       else                                                                    \
110         {                                                                     \
111           uint32_t last = data->__statep->__count >> 3;                       \
112           if (__builtin_expect (last >> 8, 0))                                \
113             {                                                                 \
114               /* Write out the last character, two bytes.  */                 \
115               if (__builtin_expect (outbuf + 2 <= outend, 1))                 \
116                 {                                                             \
117                   *outbuf++ = last & 0xff;                                    \
118                   *outbuf++ = (last >> 8) & 0xff;                             \
119                   data->__statep->__count = 0;                                \
120                 }                                                             \
121               else                                                            \
122                 /* We don't have enough room in the output buffer.  */        \
123                 status = __GCONV_FULL_OUTPUT;                                 \
124             }                                                                 \
125           else                                                                \
126             {                                                                 \
127               /* Write out the last character, a single byte.  */             \
128               if (__builtin_expect (outbuf < outend, 1))                      \
129                 {                                                             \
130                   *outbuf++ = last & 0xff;                                    \
131                   data->__statep->__count = 0;                                \
132                 }                                                             \
133               else                                                            \
134                 /* We don't have enough room in the output buffer.  */        \
135                 status = __GCONV_FULL_OUTPUT;                                 \
136             }                                                                 \
137         }                                                                     \
138     }
139
140
141 /* First define the conversion function from TSCII to UCS-4.  */
142
143 static const uint16_t tscii_to_ucs4[128][2] =
144   {
145     { 0x0BE6,      0 },
146     { 0x0BE7,      0 },
147     {      0,      0 }, /* 0x82 - maps to <U0BB8><U0BCD><U0BB0><U0BC0> */
148     { 0x0B9C,      0 },
149     { 0x0BB7,      0 },
150     { 0x0BB8,      0 },
151     { 0x0BB9,      0 },
152     {      0,      0 }, /* 0x87 - maps to <U0B95><U0BCD><U0BB7> */
153     { 0x0B9C, 0x0BCD },
154     { 0x0BB7, 0x0BCD },
155     {      0,      0 }, /* 0x8a - maps to <U0BB8> and buffers <U0BCD> */
156     {      0,      0 }, /* 0x8b - maps to <U0BB9> and buffers <U0BCD> */
157     {      0,      0 }, /* 0x8c - maps to <U0B95><U0BCD><U0BB7><U0BCD> */
158     { 0x0BE8,      0 },
159     { 0x0BE9,      0 },
160     { 0x0BEA,      0 },
161     { 0x0BEB,      0 },
162     { 0x2018,      0 },
163     { 0x2019,      0 },
164     { 0x201C,      0 },
165     { 0x201D,      0 },
166     { 0x0BEC,      0 },
167     { 0x0BED,      0 },
168     { 0x0BEE,      0 },
169     { 0x0BEF,      0 },
170     { 0x0B99, 0x0BC1 },
171     { 0x0B9E, 0x0BC1 },
172     { 0x0B99, 0x0BC2 },
173     { 0x0B9E, 0x0BC2 },
174     { 0x0BF0,      0 },
175     { 0x0BF1,      0 },
176     { 0x0BF2,      0 },
177     {      0,      0 }, /* 0xa0 - unmapped */
178     { 0x0BBE,      0 },
179     { 0x0BBF,      0 },
180     { 0x0BC0,      0 },
181     { 0x0BC1,      0 },
182     { 0x0BC2,      0 },
183     {      0,      0 }, /* 0xa6 - buffers <U0BC6> */
184     {      0,      0 }, /* 0xa7 - buffers <U0BC7> */
185     {      0,      0 }, /* 0xa8 - buffers <U0BC8> */
186     { 0x00A9,      0 },
187     { 0x0BD7,      0 },
188     { 0x0B85,      0 },
189     { 0x0B86,      0 },
190     { 0x0B87,      0 },
191     { 0x0B88,      0 },
192     { 0x0B89,      0 },
193     { 0x0B8A,      0 },
194     { 0x0B8E,      0 },
195     { 0x0B8F,      0 },
196     { 0x0B90,      0 },
197     { 0x0B92,      0 },
198     { 0x0B93,      0 },
199     { 0x0B94,      0 },
200     { 0x0B83,      0 },
201     { 0x0B95,      0 },
202     { 0x0B99,      0 },
203     { 0x0B9A,      0 },
204     { 0x0B9E,      0 },
205     { 0x0B9F,      0 },
206     { 0x0BA3,      0 },
207     { 0x0BA4,      0 },
208     { 0x0BA8,      0 },
209     { 0x0BAA,      0 },
210     { 0x0BAE,      0 },
211     { 0x0BAF,      0 },
212     { 0x0BB0,      0 },
213     { 0x0BB2,      0 },
214     { 0x0BB5,      0 },
215     { 0x0BB4,      0 },
216     { 0x0BB3,      0 },
217     { 0x0BB1,      0 },
218     { 0x0BA9,      0 },
219     { 0x0B9F, 0x0BBF },
220     { 0x0B9F, 0x0BC0 },
221     { 0x0B95, 0x0BC1 },
222     { 0x0B9A, 0x0BC1 },
223     { 0x0B9F, 0x0BC1 },
224     { 0x0BA3, 0x0BC1 },
225     { 0x0BA4, 0x0BC1 },
226     { 0x0BA8, 0x0BC1 },
227     { 0x0BAA, 0x0BC1 },
228     { 0x0BAE, 0x0BC1 },
229     { 0x0BAF, 0x0BC1 },
230     { 0x0BB0, 0x0BC1 },
231     { 0x0BB2, 0x0BC1 },
232     { 0x0BB5, 0x0BC1 },
233     { 0x0BB4, 0x0BC1 },
234     { 0x0BB3, 0x0BC1 },
235     { 0x0BB1, 0x0BC1 },
236     { 0x0BA9, 0x0BC1 },
237     { 0x0B95, 0x0BC2 },
238     { 0x0B9A, 0x0BC2 },
239     { 0x0B9F, 0x0BC2 },
240     { 0x0BA3, 0x0BC2 },
241     { 0x0BA4, 0x0BC2 },
242     { 0x0BA8, 0x0BC2 },
243     { 0x0BAA, 0x0BC2 },
244     { 0x0BAE, 0x0BC2 },
245     { 0x0BAF, 0x0BC2 },
246     { 0x0BB0, 0x0BC2 },
247     { 0x0BB2, 0x0BC2 },
248     { 0x0BB5, 0x0BC2 },
249     { 0x0BB4, 0x0BC2 },
250     { 0x0BB3, 0x0BC2 },
251     { 0x0BB1, 0x0BC2 },
252     { 0x0BA9, 0x0BC2 },
253     { 0x0B95, 0x0BCD },
254     { 0x0B99, 0x0BCD },
255     { 0x0B9A, 0x0BCD },
256     { 0x0B9E, 0x0BCD },
257     { 0x0B9F, 0x0BCD },
258     { 0x0BA3, 0x0BCD },
259     { 0x0BA4, 0x0BCD },
260     { 0x0BA8, 0x0BCD },
261     { 0x0BAA, 0x0BCD },
262     { 0x0BAE, 0x0BCD },
263     { 0x0BAF, 0x0BCD },
264     { 0x0BB0, 0x0BCD },
265     { 0x0BB2, 0x0BCD },
266     { 0x0BB5, 0x0BCD },
267     { 0x0BB4, 0x0BCD },
268     { 0x0BB3, 0x0BCD },
269     { 0x0BB1, 0x0BCD },
270     { 0x0BA9, 0x0BCD },
271     { 0x0B87,      0 },
272     {      0,      0 }  /* 0xff - unmapped */
273   };
274
275 static const uint32_t tscii_next_state[6] =
276   {
277     /* 0 means no more pending Unicode characters.  */
278     0,
279     /* 1 means <U0BB7>.  */
280     (0x0BB7 << 8),
281     /* 2 means <U0BC0>.  */
282     (0x0BC0 << 8),
283     /* 3 means <U0BCD>.  */
284     (0x0BCD << 8),
285     /* 4 means <U0BB0><U0BC0>.  */
286     (0x0BB0 << 8) + (2 << 4),
287     /* 5 means <U0BB7><U0BCD>.  */
288     (0x0BB7 << 8) + (3 << 4)
289   };
290
291 #define MIN_NEEDED_INPUT        FROM_LOOP_MIN_NEEDED_FROM
292 #define MAX_NEEDED_INPUT        FROM_LOOP_MAX_NEEDED_FROM
293 #define MIN_NEEDED_OUTPUT       FROM_LOOP_MIN_NEEDED_TO
294 #define MAX_NEEDED_OUTPUT       FROM_LOOP_MAX_NEEDED_TO
295 #define LOOPFCT                 FROM_LOOP
296 #define BODY \
297   {                                                                           \
298     uint32_t ch = *inptr;                                                     \
299                                                                               \
300     if ((*statep >> 8) != 0)                                                  \
301       {                                                                       \
302         /* Attempt to combine the last character with this one.  */           \
303         uint32_t last = *statep >> 8;                                         \
304                                                                               \
305         if (last == 0x0BCD && (*statep & (1 << 3)))                           \
306           {                                                                   \
307             if (ch == 0xa4 || ch == 0xa5)                                     \
308               {                                                               \
309                 ch += 0xb1d;                                                  \
310                 /* Now ch = 0x0BC1 or ch = 0x0BC2.  */                        \
311                 put32 (outptr, ch);                                           \
312                 outptr += 4;                                                  \
313                 *statep = 0;                                                  \
314                 inptr++;                                                      \
315                 continue;                                                     \
316               }                                                               \
317           }                                                                   \
318         else if (last >= 0x0BC6 && last <= 0x0BC8)                            \
319           {                                                                   \
320             if ((last == 0x0BC6 && ch == 0xa1)                                \
321                 || (last == 0x0BC7 && (ch == 0xa1 || ch == 0xaa)))            \
322               {                                                               \
323                 ch = last + 4 + (ch != 0xa1);                                 \
324                 /* Now ch = 0x0BCA or ch = 0x0BCB or ch = 0x0BCC.  */         \
325                 put32 (outptr, ch);                                           \
326                 outptr += 4;                                                  \
327                 *statep = 0;                                                  \
328                 inptr++;                                                      \
329                 continue;                                                     \
330               }                                                               \
331             if ((ch >= 0xb8 && ch <= 0xc9) && (*statep & (1 << 3)) == 0)      \
332               {                                                               \
333                 ch = tscii_to_ucs4[ch - 0x80][0];                             \
334                 put32 (outptr, ch);                                           \
335                 outptr += 4;                                                  \
336                 *statep |= 1 << 3;                                            \
337                 inptr++;                                                      \
338                 continue;                                                     \
339               }                                                               \
340           }                                                                   \
341                                                                               \
342         do                                                                    \
343           {                                                                   \
344             /* Output the buffered character.  */                             \
345             put32 (outptr, last);                                             \
346             outptr += 4;                                                      \
347             /* Retrieve the successor state.  */                              \
348             *statep = tscii_next_state[(*statep >> 4) & 0x0f];                \
349           }                                                                   \
350         while (*statep != 0 && __builtin_expect (outptr + 4 <= outend, 1));   \
351                                                                               \
352         if (*statep != 0)                                                     \
353           {                                                                   \
354             /* We don't have enough room in the output buffer.                \
355                Tell the caller why we terminate the loop.  */                 \
356             result = __GCONV_FULL_OUTPUT;                                     \
357             break;                                                            \
358           }                                                                   \
359                                                                               \
360         continue;                                                             \
361       }                                                                       \
362                                                                               \
363     if (ch < 0x80)                                                            \
364       {                                                                       \
365         /* Plain ASCII character.  */                                         \
366         put32 (outptr, ch);                                                   \
367         outptr += 4;                                                          \
368       }                                                                       \
369     else                                                                      \
370       {                                                                       \
371         /* Tamil character.  */                                               \
372         uint32_t u1 = tscii_to_ucs4[ch - 0x80][0];                            \
373                                                                               \
374         if (u1 != 0)                                                          \
375           {                                                                   \
376             uint32_t u2 = tscii_to_ucs4[ch - 0x80][1];                        \
377                                                                               \
378             inptr++;                                                          \
379                                                                               \
380             put32 (outptr, u1);                                               \
381             outptr += 4;                                                      \
382                                                                               \
383             if (u2 != 0)                                                      \
384               {                                                               \
385                 /* See whether we have room for two characters.  Otherwise    \
386                    store only the first character now, and put the second     \
387                    one into the queue.  */                                    \
388                 if (__builtin_expect (outptr + 4 > outend, 0))                \
389                   {                                                           \
390                     *statep = u2 << 8;                                        \
391                     result = __GCONV_FULL_OUTPUT;                             \
392                     break;                                                    \
393                   }                                                           \
394                 put32 (outptr, u2);                                           \
395                 outptr += 4;                                                  \
396               }                                                               \
397             continue;                                                         \
398           }                                                                   \
399         /* Special handling of a few Tamil characters.  */                    \
400         else if (ch == 0xa6 || ch == 0xa7 || ch == 0xa8)                      \
401           {                                                                   \
402             ch += 0x0b20;                                                     \
403             /* Now ch = 0x0BC6 or ch = 0x0BC7 or ch = 0x0BC8.  */             \
404             *statep = ch << 8;                                                \
405             inptr++;                                                          \
406             continue;                                                         \
407           }                                                                   \
408         else if (ch == 0x8a || ch == 0x8b)                                    \
409           {                                                                   \
410             ch += 0x0b2e;                                                     \
411             /* Now ch = 0x0BB8 or ch = 0x0BB9.  */                            \
412             put32 (outptr, ch);                                               \
413             outptr += 4;                                                      \
414             *statep = (0x0BCD << 8) + (1 << 3);                               \
415             inptr++;                                                          \
416             continue;                                                         \
417           }                                                                   \
418         else if (ch == 0x82)                                                  \
419           {                                                                   \
420             /* Output <U0BB8><U0BCD><U0BB0><U0BC0>, if we have room for       \
421                four characters.  */                                           \
422             inptr++;                                                          \
423             put32 (outptr, 0x0BB8);                                           \
424             outptr += 4;                                                      \
425             if (__builtin_expect (outptr + 4 > outend, 0))                    \
426               {                                                               \
427                 *statep = (0x0BCD << 8) + (4 << 4);                           \
428                 result = __GCONV_FULL_OUTPUT;                                 \
429                 break;                                                        \
430               }                                                               \
431             put32 (outptr, 0x0BCD);                                           \
432             outptr += 4;                                                      \
433             if (__builtin_expect (outptr + 4 > outend, 0))                    \
434               {                                                               \
435                 *statep = (0x0BB0 << 8) + (2 << 4);                           \
436                 result = __GCONV_FULL_OUTPUT;                                 \
437                 break;                                                        \
438               }                                                               \
439             put32 (outptr, 0x0BB0);                                           \
440             outptr += 4;                                                      \
441             if (__builtin_expect (outptr + 4 > outend, 0))                    \
442               {                                                               \
443                 *statep = (0x0BC0 << 8);                                      \
444                 result = __GCONV_FULL_OUTPUT;                                 \
445                 break;                                                        \
446               }                                                               \
447             put32 (outptr, 0x0BC0);                                           \
448             outptr += 4;                                                      \
449             continue;                                                         \
450           }                                                                   \
451         else if (ch == 0x87)                                                  \
452           {                                                                   \
453             /* Output <U0B95><U0BCD><U0BB7>, if we have room for              \
454                three characters.  */                                          \
455             inptr++;                                                          \
456             put32 (outptr, 0x0B95);                                           \
457             outptr += 4;                                                      \
458             if (__builtin_expect (outptr + 4 > outend, 0))                    \
459               {                                                               \
460                 *statep = (0x0BCD << 8) + (1 << 4);                           \
461                 result = __GCONV_FULL_OUTPUT;                                 \
462                 break;                                                        \
463               }                                                               \
464             put32 (outptr, 0x0BCD);                                           \
465             outptr += 4;                                                      \
466             if (__builtin_expect (outptr + 4 > outend, 0))                    \
467               {                                                               \
468                 *statep = (0x0BB7 << 8);                                      \
469                 result = __GCONV_FULL_OUTPUT;                                 \
470                 break;                                                        \
471               }                                                               \
472             put32 (outptr, 0x0BB7);                                           \
473             outptr += 4;                                                      \
474             continue;                                                         \
475           }                                                                   \
476         else if (ch == 0x8c)                                                  \
477           {                                                                   \
478             /* Output <U0B95><U0BCD><U0BB7><U0BCD>, if we have room for       \
479                four characters.  */                                           \
480             inptr++;                                                          \
481             put32 (outptr, 0x0B95);                                           \
482             outptr += 4;                                                      \
483             if (__builtin_expect (outptr + 4 > outend, 0))                    \
484               {                                                               \
485                 *statep = (0x0BCD << 8) + (5 << 4);                           \
486                 result = __GCONV_FULL_OUTPUT;                                 \
487                 break;                                                        \
488               }                                                               \
489             put32 (outptr, 0x0BCD);                                           \
490             outptr += 4;                                                      \
491             if (__builtin_expect (outptr + 4 > outend, 0))                    \
492               {                                                               \
493                 *statep = (0x0BB7 << 8) + (3 << 4);                           \
494                 result = __GCONV_FULL_OUTPUT;                                 \
495                 break;                                                        \
496               }                                                               \
497             put32 (outptr, 0x0BB7);                                           \
498             outptr += 4;                                                      \
499             if (__builtin_expect (outptr + 4 > outend, 0))                    \
500               {                                                               \
501                 *statep = (0x0BCD << 8);                                      \
502                 result = __GCONV_FULL_OUTPUT;                                 \
503                 break;                                                        \
504               }                                                               \
505             put32 (outptr, 0x0BCD);                                           \
506             outptr += 4;                                                      \
507             continue;                                                         \
508           }                                                                   \
509         else                                                                  \
510           {                                                                   \
511             /* This is illegal.  */                                           \
512             STANDARD_FROM_LOOP_ERR_HANDLER (1);                               \
513           }                                                                   \
514       }                                                                       \
515                                                                               \
516     /* Now that we wrote the output increment the input pointer.  */          \
517     inptr++;                                                                  \
518   }
519 #define LOOP_NEED_FLAGS
520 #define EXTRA_LOOP_DECLS        , int *statep
521 #include <iconv/loop.c>
522
523
524 /* Next, define the other direction, from UCS-4 to TSCII.  */
525
526 static const uint8_t ucs4_to_tscii[128] =
527   {
528        0,    0,    0, 0xb7,    0, 0xab, 0xac, 0xfe, /* 0x0B80..0x0B87 */
529     0xae, 0xaf, 0xb0,    0,    0,    0, 0xb1, 0xb2, /* 0x0B88..0x0B8F */
530     0xb3,    0, 0xb4, 0xb5, 0xb6, 0xb8,    0,    0, /* 0x0B90..0x0B97 */
531        0, 0xb9, 0xba,    0, 0x83,    0, 0xbb, 0xbc, /* 0x0B98..0x0B9F */
532        0,    0,    0, 0xbd, 0xbe,    0,    0,    0, /* 0x0BA0..0x0BA7 */
533     0xbf, 0xc9, 0xc0,    0,    0,    0, 0xc1, 0xc2, /* 0x0BA8..0x0BAF */
534     0xc3, 0xc8, 0xc4, 0xc7, 0xc6, 0xc5,    0, 0x84, /* 0x0BB0..0x0BB7 */
535     0x85, 0x86,    0,    0,    0,    0, 0xa1, 0xa2, /* 0x0BB8..0x0BBF */
536     0xa3, 0xa4, 0xa5,    0,    0,    0, 0xa6, 0xa7, /* 0x0BC0..0x0BC7 */
537     0xa8,    0,    0,    0,    0,    0,    0,    0, /* 0x0BC8..0x0BCF */
538        0,    0,    0,    0,    0,    0,    0, 0xaa, /* 0x0BD0..0x0BD7 */
539        0,    0,    0,    0,    0,    0,    0,    0, /* 0x0BD8..0x0BDF */
540        0,    0,    0,    0,    0,    0, 0x80, 0x81, /* 0x0BE0..0x0BE7 */
541     0x8d, 0x8e, 0x8f, 0x90, 0x95, 0x96, 0x97, 0x98, /* 0x0BE8..0x0BEF */
542     0x9d, 0x9e, 0x9f,    0,    0,    0,    0,    0, /* 0x0BF0..0x0BF7 */
543        0,    0,    0,    0,    0,    0,    0,    0  /* 0x0BF8..0x0BFF */
544   };
545
546 static const uint8_t consonant_with_u[18] =
547   {
548     0xcc, 0x99, 0xcd, 0x9a, 0xce, 0xcf, 0xd0, 0xd1, 0xd2,
549     0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb
550   };
551
552 static const uint8_t consonant_with_uu[18] =
553   {
554     0xdc, 0x9b, 0xdd, 0x9c, 0xde, 0xdf, 0xe0, 0xe1, 0xe2,
555     0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb
556   };
557
558 static const uint8_t consonant_with_virama[18] =
559   {
560     0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4,
561     0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd
562   };
563
564 #define MIN_NEEDED_INPUT        TO_LOOP_MIN_NEEDED_FROM
565 #define MAX_NEEDED_INPUT        TO_LOOP_MAX_NEEDED_FROM
566 #define MIN_NEEDED_OUTPUT       TO_LOOP_MIN_NEEDED_TO
567 #define MAX_NEEDED_OUTPUT       TO_LOOP_MAX_NEEDED_TO
568 #define LOOPFCT                 TO_LOOP
569 #define BODY \
570   {                                                                           \
571     uint32_t ch = get32 (inptr);                                              \
572                                                                               \
573     if ((*statep >> 3) != 0)                                                  \
574       {                                                                       \
575         /* Attempt to combine the last character with this one.  */           \
576         uint32_t last = *statep >> 3;                                         \
577                                                                               \
578         if (last >= 0xb8 && last <= 0xc9)                                     \
579           {                                                                   \
580             if (ch == 0x0BC1)                                                 \
581               {                                                               \
582                 *outptr++ = consonant_with_u[last - 0xb8];                    \
583                 *statep = 0;                                                  \
584                 inptr += 4;                                                   \
585                 continue;                                                     \
586               }                                                               \
587             if (ch == 0x0BC2)                                                 \
588               {                                                               \
589                 *outptr++ = consonant_with_uu[last - 0xb8];                   \
590                 *statep = 0;                                                  \
591                 inptr += 4;                                                   \
592                 continue;                                                     \
593               }                                                               \
594             if (ch == 0x0BC6)                                                 \
595               {                                                               \
596                 if (__builtin_expect (outptr + 2 <= outend, 1))               \
597                   {                                                           \
598                     *outptr++ = 0xa6;                                         \
599                     *outptr++ = last;                                         \
600                     *statep = 0;                                              \
601                     inptr += 4;                                               \
602                     continue;                                                 \
603                   }                                                           \
604                 else                                                          \
605                   {                                                           \
606                     result = __GCONV_FULL_OUTPUT;                             \
607                     break;                                                    \
608                   }                                                           \
609               }                                                               \
610             if (ch == 0x0BC7)                                                 \
611               {                                                               \
612                 if (__builtin_expect (outptr + 2 <= outend, 1))               \
613                   {                                                           \
614                     *outptr++ = 0xa7;                                         \
615                     *outptr++ = last;                                         \
616                     *statep = 0;                                              \
617                     inptr += 4;                                               \
618                     continue;                                                 \
619                   }                                                           \
620                 else                                                          \
621                   {                                                           \
622                     result = __GCONV_FULL_OUTPUT;                             \
623                     break;                                                    \
624                   }                                                           \
625               }                                                               \
626             if (ch == 0x0BC8)                                                 \
627               {                                                               \
628                 if (__builtin_expect (outptr + 2 <= outend, 1))               \
629                   {                                                           \
630                     *outptr++ = 0xa8;                                         \
631                     *outptr++ = last;                                         \
632                     *statep = 0;                                              \
633                     inptr += 4;                                               \
634                     continue;                                                 \
635                   }                                                           \
636                 else                                                          \
637                   {                                                           \
638                     result = __GCONV_FULL_OUTPUT;                             \
639                     break;                                                    \
640                   }                                                           \
641               }                                                               \
642             if (ch == 0x0BCA)                                                 \
643               {                                                               \
644                 if (__builtin_expect (outptr + 3 <= outend, 1))               \
645                   {                                                           \
646                     *outptr++ = 0xa6;                                         \
647                     *outptr++ = last;                                         \
648                     *outptr++ = 0xa1;                                         \
649                     *statep = 0;                                              \
650                     inptr += 4;                                               \
651                     continue;                                                 \
652                   }                                                           \
653                 else                                                          \
654                   {                                                           \
655                     result = __GCONV_FULL_OUTPUT;                             \
656                     break;                                                    \
657                   }                                                           \
658               }                                                               \
659             if (ch == 0x0BCB)                                                 \
660               {                                                               \
661                 if (__builtin_expect (outptr + 3 <= outend, 1))               \
662                   {                                                           \
663                     *outptr++ = 0xa7;                                         \
664                     *outptr++ = last;                                         \
665                     *outptr++ = 0xa1;                                         \
666                     *statep = 0;                                              \
667                     inptr += 4;                                               \
668                     continue;                                                 \
669                   }                                                           \
670                 else                                                          \
671                   {                                                           \
672                     result = __GCONV_FULL_OUTPUT;                             \
673                     break;                                                    \
674                   }                                                           \
675               }                                                               \
676             if (ch == 0x0BCC)                                                 \
677               {                                                               \
678                 if (__builtin_expect (outptr + 3 <= outend, 1))               \
679                   {                                                           \
680                     *outptr++ = 0xa7;                                         \
681                     *outptr++ = last;                                         \
682                     *outptr++ = 0xaa;                                         \
683                     *statep = 0;                                              \
684                     inptr += 4;                                               \
685                     continue;                                                 \
686                   }                                                           \
687                 else                                                          \
688                   {                                                           \
689                     result = __GCONV_FULL_OUTPUT;                             \
690                     break;                                                    \
691                   }                                                           \
692               }                                                               \
693             if (ch == 0x0BCD)                                                 \
694               {                                                               \
695                 if (last != 0xb8)                                             \
696                   {                                                           \
697                     *outptr++ = consonant_with_virama[last - 0xb8];           \
698                     *statep = 0;                                              \
699                   }                                                           \
700                 else                                                          \
701                   *statep = 0xec << 3;                                        \
702                 inptr += 4;                                                   \
703                 continue;                                                     \
704               }                                                               \
705             if (last == 0xbc && (ch == 0x0BBF || ch == 0x0BC0))               \
706               {                                                               \
707                 *outptr++ = ch - 0x0af5;                                      \
708                 *statep = 0;                                                  \
709                 inptr += 4;                                                   \
710                 continue;                                                     \
711               }                                                               \
712           }                                                                   \
713         else if (last >= 0x83 && last <= 0x86)                                \
714           {                                                                   \
715             if (last >= 0x85 && (ch == 0x0BC1 || ch == 0x0BC2))               \
716               {                                                               \
717                 *outptr++ = last + 5;                                         \
718                 *statep = 0;                                                  \
719                 continue;                                                     \
720               }                                                               \
721             if (ch == 0x0BCD)                                                 \
722               {                                                               \
723                 if (last != 0x85)                                             \
724                   {                                                           \
725                     *outptr++ = last + 5;                                     \
726                     *statep = 0;                                              \
727                   }                                                           \
728                 else                                                          \
729                   *statep = 0x8a << 3;                                        \
730                 inptr += 4;                                                   \
731                 continue;                                                     \
732               }                                                               \
733           }                                                                   \
734         else if (last == 0xec)                                                \
735           {                                                                   \
736             if (ch == 0x0BB7)                                                 \
737               {                                                               \
738                 *statep = 0x87 << 3;                                          \
739                 inptr += 4;                                                   \
740                 continue;                                                     \
741               }                                                               \
742           }                                                                   \
743         else if (last == 0x8a)                                                \
744           {                                                                   \
745             if (ch == 0x0BB0)                                                 \
746               {                                                               \
747                 *statep = 0xc38a << 3;                                        \
748                 inptr += 4;                                                   \
749                 continue;                                                     \
750               }                                                               \
751           }                                                                   \
752         else if (last == 0x87)                                                \
753           {                                                                   \
754             if (ch == 0x0BCD)                                                 \
755               {                                                               \
756                 *outptr++ = 0x8c;                                             \
757                 *statep = 0;                                                  \
758                 inptr += 4;                                                   \
759                 continue;                                                     \
760               }                                                               \
761           }                                                                   \
762         else                                                                  \
763           {                                                                   \
764             assert (last == 0xc38a);                                          \
765             if (ch == 0x0BC0)                                                 \
766               {                                                               \
767                 *outptr++ = 0x82;                                             \
768                 *statep = 0;                                                  \
769                 inptr += 4;                                                   \
770                 continue;                                                     \
771               }                                                               \
772           }                                                                   \
773                                                                               \
774         /* Output the buffered character.  */                                 \
775         if (__builtin_expect (last >> 8, 0))                                  \
776           {                                                                   \
777             if (__builtin_expect (outptr + 2 <= outend, 1))                   \
778               {                                                               \
779                 *outptr++ = last & 0xff;                                      \
780                 *outptr++ = (last >> 8) & 0xff;                               \
781               }                                                               \
782             else                                                              \
783               {                                                               \
784                 result = __GCONV_FULL_OUTPUT;                                 \
785                 break;                                                        \
786               }                                                               \
787           }                                                                   \
788         else                                                                  \
789           *outptr++ = last & 0xff;                                            \
790         *statep = 0;                                                          \
791         continue;                                                             \
792       }                                                                       \
793                                                                               \
794     if (ch < 0x80)                                                            \
795       /* Plain ASCII character.  */                                           \
796       *outptr++ = ch;                                                         \
797     else if (ch >= 0x0B80 && ch <= 0x0BFF)                                    \
798       {                                                                       \
799         /* Tamil character.  */                                               \
800         uint8_t t = ucs4_to_tscii[ch - 0x0B80];                               \
801                                                                               \
802         if (t != 0)                                                           \
803           {                                                                   \
804             if ((t >= 0xb8 && t <= 0xc9) || (t >= 0x83 && t <= 0x86))         \
805               *statep = (uint32_t) t << 3;                                    \
806             else                                                              \
807               *outptr++ = t;                                                  \
808           }                                                                   \
809         else if (ch >= 0x0BCA && ch <= 0x0BCC)                                \
810           {                                                                   \
811             /* See whether we have room for two bytes.  */                    \
812             if (__builtin_expect (outptr + 2 <= outend, 1))                   \
813               {                                                               \
814                 *outptr++ = (ch == 0x0BCA ? 0xa6 : 0xa7);                     \
815                 *outptr++ = (ch != 0x0BCC ? 0xa1 : 0xaa);                     \
816               }                                                               \
817             else                                                              \
818               {                                                               \
819                 result = __GCONV_FULL_OUTPUT;                                 \
820                 break;                                                        \
821               }                                                               \
822           }                                                                   \
823         else                                                                  \
824           {                                                                   \
825             /* Illegal character.  */                                         \
826             STANDARD_TO_LOOP_ERR_HANDLER (4);                                 \
827           }                                                                   \
828       }                                                                       \
829     else if (ch == 0x00A9)                                                    \
830       *outptr++ = ch;                                                         \
831     else if (ch == 0x2018 || ch == 0x2019)                                    \
832       *outptr++ = ch - 0x1f87;                                                \
833     else if (ch == 0x201C || ch == 0x201D)                                    \
834       *outptr++ = ch - 0x1f89;                                                \
835     else                                                                      \
836       {                                                                       \
837         UNICODE_TAG_HANDLER (ch, 4);                                          \
838                                                                               \
839         /* Illegal character.  */                                             \
840         STANDARD_TO_LOOP_ERR_HANDLER (4);                                     \
841       }                                                                       \
842                                                                               \
843     /* Now that we wrote the output increment the input pointer.  */          \
844     inptr += 4;                                                               \
845   }
846 #define LOOP_NEED_FLAGS
847 #define EXTRA_LOOP_DECLS        , int *statep
848 #include <iconv/loop.c>
849
850
851 /* Now define the toplevel functions.  */
852 #include <iconv/skeleton.c>