Back to index

glibc  2.9
tscii.c
Go to the documentation of this file.
00001 /* Conversion from and to TSCII.
00002    Copyright (C) 2002, 2004 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Bruno Haible <bruno@clisp.org>, 2002.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <dlfcn.h>
00022 #include <stdint.h>
00023 #include <gconv.h>
00024 #include <assert.h>
00025 
00026 /* TSCII is an 8-bit encoding consisting of:
00027    0x00..0x7F:       ASCII
00028    0x80..0x90, 0x95..0x9F, 0xAB..0xFE:
00029                      Tamil letters and glyphs
00030    0xA1..0xA5, 0xAA: Tamil combining letters (after the base character)
00031    0xA6..0xA8:       Tamil combining letters (before the base character)
00032    0x91..0x94:       Punctuation
00033    0xA9:             Symbols
00034 */
00035 
00036 /* Definitions used in the body of the `gconv' function.  */
00037 #define CHARSET_NAME        "TSCII//"
00038 #define FROM_LOOP           from_tscii
00039 #define TO_LOOP                    to_tscii
00040 #define DEFINE_INIT         1
00041 #define DEFINE_FINI         1
00042 #define FROM_LOOP_MIN_NEEDED_FROM  1
00043 #define FROM_LOOP_MAX_NEEDED_FROM  2
00044 #define FROM_LOOP_MIN_NEEDED_TO           4
00045 #define FROM_LOOP_MAX_NEEDED_TO           16
00046 #define TO_LOOP_MIN_NEEDED_FROM           4
00047 #define TO_LOOP_MAX_NEEDED_FROM           4
00048 #define TO_LOOP_MIN_NEEDED_TO             1
00049 #define TO_LOOP_MAX_NEEDED_TO             3
00050 #define PREPARE_LOOP \
00051   int saved_state;                                                   \
00052   int *statep = &data->__statep->__count;
00053 #define EXTRA_LOOP_ARGS            , statep
00054 
00055 
00056 /* Since we might have to reset input pointer we must be able to save
00057    and restore the state.  */
00058 #define SAVE_RESET_STATE(Save) \
00059   if (Save)                                                          \
00060     saved_state = *statep;                                           \
00061   else                                                               \
00062     *statep = saved_state
00063 
00064 
00065 /* During TSCII to UCS-4 conversion, the COUNT element of the state contains
00066    the last UCS-4 character to be output, shifted by 8 bits, and an encoded
00067    representation of additional UCS-4 characters to be output (if any),
00068    shifted by 4 bits.  This character can be:
00069      0x0000                   Nothing pending.
00070      0x0BCD                   Pending VIRAMA sign. If bit 3 is set, it may be
00071                               omitted if followed by a vowel sign U or UU.
00072      0x0BC6, 0x0BC7, 0x0BC8   Pending vowel sign.  Bit 3 is set after the
00073                               consonant was seen.
00074      Other                    Bit 3 always cleared.  */
00075 
00076 /* During UCS-4 to TSCII conversion, the COUNT element of the state contains
00077    the last byte (or sometimes the last two bytes) to be output, shifted by
00078    3 bits. This can be:
00079      0x00                     Nothing pending.
00080      0xB8..0xC9, 0x83..0x86   A consonant.
00081      0xEC, 0x8A               A consonant with VIRAMA sign (final or joining).
00082      0x87, 0xC38A             Two consonants combined through a VIRAMA sign. */
00083 
00084 /* Since this is a stateful encoding we have to provide code which resets
00085    the output state to the initial state.  This has to be done during the
00086    flushing.  */
00087 #define EMIT_SHIFT_TO_INIT \
00088   if (data->__statep->__count != 0)                                         \
00089     {                                                                \
00090       if (FROM_DIRECTION)                                            \
00091        {                                                             \
00092          do                                                          \
00093            {                                                         \
00094              if (__builtin_expect (outbuf + 4 > outend, 0))                 \
00095               {                                                      \
00096                 /* We don't have enough room in the output buffer.  */      \
00097                 status = __GCONV_FULL_OUTPUT;                               \
00098                 break;                                               \
00099               }                                                      \
00100              /* Write out the pending character.  */                        \
00101              *((uint32_t *) outbuf) = data->__statep->__count >> 8;         \
00102              outbuf += sizeof (uint32_t);                            \
00103              /* Retrieve the successor state.  */                           \
00104              data->__statep->__count =                                      \
00105               tscii_next_state[(data->__statep->__count >> 4) & 0x0f];      \
00106            }                                                         \
00107          while (data->__statep->__count != 0);                              \
00108        }                                                             \
00109       else                                                           \
00110        {                                                             \
00111          uint32_t last = data->__statep->__count >> 3;                      \
00112          if (__builtin_expect (last >> 8, 0))                               \
00113            {                                                         \
00114              /* Write out the last character, two bytes.  */                \
00115              if (__builtin_expect (outbuf + 2 <= outend, 1))                \
00116               {                                                      \
00117                 *outbuf++ = last & 0xff;                             \
00118                 *outbuf++ = (last >> 8) & 0xff;                      \
00119                 data->__statep->__count = 0;                                \
00120               }                                                      \
00121              else                                                    \
00122               /* We don't have enough room in the output buffer.  */        \
00123               status = __GCONV_FULL_OUTPUT;                                 \
00124            }                                                         \
00125          else                                                        \
00126            {                                                         \
00127              /* Write out the last character, a single byte.  */            \
00128              if (__builtin_expect (outbuf < outend, 1))              \
00129               {                                                      \
00130                 *outbuf++ = last & 0xff;                             \
00131                 data->__statep->__count = 0;                                \
00132               }                                                      \
00133              else                                                    \
00134               /* We don't have enough room in the output buffer.  */        \
00135               status = __GCONV_FULL_OUTPUT;                                 \
00136            }                                                         \
00137        }                                                             \
00138     }
00139 
00140 
00141 /* First define the conversion function from TSCII to UCS-4.  */
00142 
00143 static const uint16_t tscii_to_ucs4[128][2] =
00144   {
00145     { 0x0BE6,      0 },
00146     { 0x0BE7,      0 },
00147     {      0,      0 },     /* 0x82 - maps to <U0BB8><U0BCD><U0BB0><U0BC0> */
00148     { 0x0B9C,      0 },
00149     { 0x0BB7,      0 },
00150     { 0x0BB8,      0 },
00151     { 0x0BB9,      0 },
00152     {      0,      0 },     /* 0x87 - maps to <U0B95><U0BCD><U0BB7> */
00153     { 0x0B9C, 0x0BCD },
00154     { 0x0BB7, 0x0BCD },
00155     {      0,      0 }, /* 0x8a - maps to <U0BB8> and buffers <U0BCD> */
00156     {      0,      0 }, /* 0x8b - maps to <U0BB9> and buffers <U0BCD> */
00157     {      0,      0 },     /* 0x8c - maps to <U0B95><U0BCD><U0BB7><U0BCD> */
00158     { 0x0BE8,      0 },
00159     { 0x0BE9,      0 },
00160     { 0x0BEA,      0 },
00161     { 0x0BEB,      0 },
00162     { 0x2018,      0 },
00163     { 0x2019,      0 },
00164     { 0x201C,      0 },
00165     { 0x201D,      0 },
00166     { 0x0BEC,      0 },
00167     { 0x0BED,      0 },
00168     { 0x0BEE,      0 },
00169     { 0x0BEF,      0 },
00170     { 0x0B99, 0x0BC1 },
00171     { 0x0B9E, 0x0BC1 },
00172     { 0x0B99, 0x0BC2 },
00173     { 0x0B9E, 0x0BC2 },
00174     { 0x0BF0,      0 },
00175     { 0x0BF1,      0 },
00176     { 0x0BF2,      0 },
00177     {      0,      0 },     /* 0xa0 - unmapped */
00178     { 0x0BBE,      0 },
00179     { 0x0BBF,      0 },
00180     { 0x0BC0,      0 },
00181     { 0x0BC1,      0 },
00182     { 0x0BC2,      0 },
00183     {      0,      0 }, /* 0xa6 - buffers <U0BC6> */
00184     {      0,      0 }, /* 0xa7 - buffers <U0BC7> */
00185     {      0,      0 }, /* 0xa8 - buffers <U0BC8> */
00186     { 0x00A9,      0 },
00187     { 0x0BD7,      0 },
00188     { 0x0B85,      0 },
00189     { 0x0B86,      0 },
00190     { 0x0B87,      0 },
00191     { 0x0B88,      0 },
00192     { 0x0B89,      0 },
00193     { 0x0B8A,      0 },
00194     { 0x0B8E,      0 },
00195     { 0x0B8F,      0 },
00196     { 0x0B90,      0 },
00197     { 0x0B92,      0 },
00198     { 0x0B93,      0 },
00199     { 0x0B94,      0 },
00200     { 0x0B83,      0 },
00201     { 0x0B95,      0 },
00202     { 0x0B99,      0 },
00203     { 0x0B9A,      0 },
00204     { 0x0B9E,      0 },
00205     { 0x0B9F,      0 },
00206     { 0x0BA3,      0 },
00207     { 0x0BA4,      0 },
00208     { 0x0BA8,      0 },
00209     { 0x0BAA,      0 },
00210     { 0x0BAE,      0 },
00211     { 0x0BAF,      0 },
00212     { 0x0BB0,      0 },
00213     { 0x0BB2,      0 },
00214     { 0x0BB5,      0 },
00215     { 0x0BB4,      0 },
00216     { 0x0BB3,      0 },
00217     { 0x0BB1,      0 },
00218     { 0x0BA9,      0 },
00219     { 0x0B9F, 0x0BBF },
00220     { 0x0B9F, 0x0BC0 },
00221     { 0x0B95, 0x0BC1 },
00222     { 0x0B9A, 0x0BC1 },
00223     { 0x0B9F, 0x0BC1 },
00224     { 0x0BA3, 0x0BC1 },
00225     { 0x0BA4, 0x0BC1 },
00226     { 0x0BA8, 0x0BC1 },
00227     { 0x0BAA, 0x0BC1 },
00228     { 0x0BAE, 0x0BC1 },
00229     { 0x0BAF, 0x0BC1 },
00230     { 0x0BB0, 0x0BC1 },
00231     { 0x0BB2, 0x0BC1 },
00232     { 0x0BB5, 0x0BC1 },
00233     { 0x0BB4, 0x0BC1 },
00234     { 0x0BB3, 0x0BC1 },
00235     { 0x0BB1, 0x0BC1 },
00236     { 0x0BA9, 0x0BC1 },
00237     { 0x0B95, 0x0BC2 },
00238     { 0x0B9A, 0x0BC2 },
00239     { 0x0B9F, 0x0BC2 },
00240     { 0x0BA3, 0x0BC2 },
00241     { 0x0BA4, 0x0BC2 },
00242     { 0x0BA8, 0x0BC2 },
00243     { 0x0BAA, 0x0BC2 },
00244     { 0x0BAE, 0x0BC2 },
00245     { 0x0BAF, 0x0BC2 },
00246     { 0x0BB0, 0x0BC2 },
00247     { 0x0BB2, 0x0BC2 },
00248     { 0x0BB5, 0x0BC2 },
00249     { 0x0BB4, 0x0BC2 },
00250     { 0x0BB3, 0x0BC2 },
00251     { 0x0BB1, 0x0BC2 },
00252     { 0x0BA9, 0x0BC2 },
00253     { 0x0B95, 0x0BCD },
00254     { 0x0B99, 0x0BCD },
00255     { 0x0B9A, 0x0BCD },
00256     { 0x0B9E, 0x0BCD },
00257     { 0x0B9F, 0x0BCD },
00258     { 0x0BA3, 0x0BCD },
00259     { 0x0BA4, 0x0BCD },
00260     { 0x0BA8, 0x0BCD },
00261     { 0x0BAA, 0x0BCD },
00262     { 0x0BAE, 0x0BCD },
00263     { 0x0BAF, 0x0BCD },
00264     { 0x0BB0, 0x0BCD },
00265     { 0x0BB2, 0x0BCD },
00266     { 0x0BB5, 0x0BCD },
00267     { 0x0BB4, 0x0BCD },
00268     { 0x0BB3, 0x0BCD },
00269     { 0x0BB1, 0x0BCD },
00270     { 0x0BA9, 0x0BCD },
00271     { 0x0B87,      0 },
00272     {      0,      0 }      /* 0xff - unmapped */
00273   };
00274 
00275 static const uint32_t tscii_next_state[6] =
00276   {
00277     /* 0 means no more pending Unicode characters.  */
00278     0,
00279     /* 1 means <U0BB7>.  */
00280     (0x0BB7 << 8),
00281     /* 2 means <U0BC0>.  */
00282     (0x0BC0 << 8),
00283     /* 3 means <U0BCD>.  */
00284     (0x0BCD << 8),
00285     /* 4 means <U0BB0><U0BC0>.  */
00286     (0x0BB0 << 8) + (2 << 4),
00287     /* 5 means <U0BB7><U0BCD>.  */
00288     (0x0BB7 << 8) + (3 << 4)
00289   };
00290 
00291 #define MIN_NEEDED_INPUT    FROM_LOOP_MIN_NEEDED_FROM
00292 #define MAX_NEEDED_INPUT    FROM_LOOP_MAX_NEEDED_FROM
00293 #define MIN_NEEDED_OUTPUT   FROM_LOOP_MIN_NEEDED_TO
00294 #define MAX_NEEDED_OUTPUT   FROM_LOOP_MAX_NEEDED_TO
00295 #define LOOPFCT                    FROM_LOOP
00296 #define BODY \
00297   {                                                                  \
00298     uint32_t ch = *inptr;                                            \
00299                                                                      \
00300     if ((*statep >> 8) != 0)                                                \
00301       {                                                                     \
00302        /* Attempt to combine the last character with this one.  */          \
00303        uint32_t last = *statep >> 8;                                        \
00304                                                                      \
00305        if (last == 0x0BCD && (*statep & (1 << 3)))                          \
00306          {                                                           \
00307            if (ch == 0xa4 || ch == 0xa5)                             \
00308              {                                                              \
00309               ch += 0xb1d;                                           \
00310               /* Now ch = 0x0BC1 or ch = 0x0BC2.  */                        \
00311               put32 (outptr, ch);                                    \
00312               outptr += 4;                                           \
00313               *statep = 0;                                           \
00314               inptr++;                                               \
00315               continue;                                              \
00316              }                                                              \
00317          }                                                           \
00318        else if (last >= 0x0BC6 && last <= 0x0BC8)                           \
00319          {                                                           \
00320            if ((last == 0x0BC6 && ch == 0xa1)                               \
00321               || (last == 0x0BC7 && (ch == 0xa1 || ch == 0xaa)))            \
00322              {                                                              \
00323               ch = last + 4 + (ch != 0xa1);                                 \
00324               /* Now ch = 0x0BCA or ch = 0x0BCB or ch = 0x0BCC.  */         \
00325               put32 (outptr, ch);                                    \
00326               outptr += 4;                                           \
00327               *statep = 0;                                           \
00328               inptr++;                                               \
00329               continue;                                              \
00330              }                                                              \
00331            if ((ch >= 0xb8 && ch <= 0xc9) && (*statep & (1 << 3)) == 0)      \
00332              {                                                              \
00333               ch = tscii_to_ucs4[ch - 0x80][0];                      \
00334               put32 (outptr, ch);                                    \
00335               outptr += 4;                                           \
00336               *statep |= 1 << 3;                                     \
00337               inptr++;                                               \
00338               continue;                                              \
00339              }                                                              \
00340          }                                                           \
00341                                                                      \
00342        do                                                            \
00343          {                                                           \
00344            /* Output the buffered character.  */                     \
00345            put32 (outptr, last);                                     \
00346            outptr += 4;                                              \
00347            /* Retrieve the successor state.  */                      \
00348            *statep = tscii_next_state[(*statep >> 4) & 0x0f];               \
00349          }                                                           \
00350        while (*statep != 0 && __builtin_expect (outptr + 4 <= outend, 1));   \
00351                                                                      \
00352        if (*statep != 0)                                             \
00353          {                                                           \
00354            /* We don't have enough room in the output buffer.               \
00355               Tell the caller why we terminate the loop.  */                \
00356            result = __GCONV_FULL_OUTPUT;                             \
00357            break;                                                    \
00358          }                                                           \
00359                                                                      \
00360        continue;                                                     \
00361       }                                                                     \
00362                                                                      \
00363     if (ch < 0x80)                                                   \
00364       {                                                                     \
00365        /* Plain ASCII character.  */                                        \
00366        put32 (outptr, ch);                                           \
00367        outptr += 4;                                                  \
00368       }                                                                     \
00369     else                                                             \
00370       {                                                                     \
00371        /* Tamil character.  */                                              \
00372        uint32_t u1 = tscii_to_ucs4[ch - 0x80][0];                           \
00373                                                                      \
00374        if (u1 != 0)                                                  \
00375          {                                                           \
00376            uint32_t u2 = tscii_to_ucs4[ch - 0x80][1];                       \
00377                                                                      \
00378            inptr++;                                                  \
00379                                                                      \
00380            put32 (outptr, u1);                                              \
00381            outptr += 4;                                              \
00382                                                                      \
00383            if (u2 != 0)                                              \
00384              {                                                              \
00385               /* See whether we have room for two characters.  Otherwise    \
00386                  store only the first character now, and put the second     \
00387                  one into the queue.  */                             \
00388               if (__builtin_expect (outptr + 4 > outend, 0))                \
00389                 {                                                    \
00390                   *statep = u2 << 8;                                        \
00391                   result = __GCONV_FULL_OUTPUT;                      \
00392                   break;                                             \
00393                 }                                                    \
00394               put32 (outptr, u2);                                    \
00395               outptr += 4;                                           \
00396              }                                                              \
00397            continue;                                                 \
00398          }                                                           \
00399        /* Special handling of a few Tamil characters.  */                   \
00400        else if (ch == 0xa6 || ch == 0xa7 || ch == 0xa8)              \
00401          {                                                           \
00402            ch += 0x0b20;                                             \
00403            /* Now ch = 0x0BC6 or ch = 0x0BC7 or ch = 0x0BC8.  */            \
00404            *statep = ch << 8;                                               \
00405            inptr++;                                                  \
00406            continue;                                                 \
00407          }                                                           \
00408        else if (ch == 0x8a || ch == 0x8b)                            \
00409          {                                                           \
00410            ch += 0x0b2e;                                             \
00411            /* Now ch = 0x0BB8 or ch = 0x0BB9.  */                           \
00412            put32 (outptr, ch);                                              \
00413            outptr += 4;                                              \
00414            *statep = (0x0BCD << 8) + (1 << 3);                              \
00415            inptr++;                                                  \
00416            continue;                                                 \
00417          }                                                           \
00418        else if (ch == 0x82)                                          \
00419          {                                                           \
00420            /* Output <U0BB8><U0BCD><U0BB0><U0BC0>, if we have room for             \
00421               four characters.  */                                   \
00422            inptr++;                                                  \
00423            put32 (outptr, 0x0BB8);                                   \
00424            outptr += 4;                                              \
00425            if (__builtin_expect (outptr + 4 > outend, 0))                   \
00426              {                                                              \
00427               *statep = (0x0BCD << 8) + (4 << 4);                           \
00428               result = __GCONV_FULL_OUTPUT;                                 \
00429               break;                                                 \
00430              }                                                              \
00431            put32 (outptr, 0x0BCD);                                   \
00432            outptr += 4;                                              \
00433            if (__builtin_expect (outptr + 4 > outend, 0))                   \
00434              {                                                              \
00435               *statep = (0x0BB0 << 8) + (2 << 4);                           \
00436               result = __GCONV_FULL_OUTPUT;                                 \
00437               break;                                                 \
00438              }                                                              \
00439            put32 (outptr, 0x0BB0);                                   \
00440            outptr += 4;                                              \
00441            if (__builtin_expect (outptr + 4 > outend, 0))                   \
00442              {                                                              \
00443               *statep = (0x0BC0 << 8);                               \
00444               result = __GCONV_FULL_OUTPUT;                                 \
00445               break;                                                 \
00446              }                                                              \
00447            put32 (outptr, 0x0BC0);                                   \
00448            outptr += 4;                                              \
00449            continue;                                                 \
00450          }                                                           \
00451        else if (ch == 0x87)                                          \
00452          {                                                           \
00453            /* Output <U0B95><U0BCD><U0BB7>, if we have room for             \
00454               three characters.  */                                         \
00455            inptr++;                                                  \
00456            put32 (outptr, 0x0B95);                                   \
00457            outptr += 4;                                              \
00458            if (__builtin_expect (outptr + 4 > outend, 0))                   \
00459              {                                                              \
00460               *statep = (0x0BCD << 8) + (1 << 4);                           \
00461               result = __GCONV_FULL_OUTPUT;                                 \
00462               break;                                                 \
00463              }                                                              \
00464            put32 (outptr, 0x0BCD);                                   \
00465            outptr += 4;                                              \
00466            if (__builtin_expect (outptr + 4 > outend, 0))                   \
00467              {                                                              \
00468               *statep = (0x0BB7 << 8);                               \
00469               result = __GCONV_FULL_OUTPUT;                                 \
00470               break;                                                 \
00471              }                                                              \
00472            put32 (outptr, 0x0BB7);                                   \
00473            outptr += 4;                                              \
00474            continue;                                                 \
00475          }                                                           \
00476        else if (ch == 0x8c)                                          \
00477          {                                                           \
00478            /* Output <U0B95><U0BCD><U0BB7><U0BCD>, if we have room for             \
00479               four characters.  */                                   \
00480            inptr++;                                                  \
00481            put32 (outptr, 0x0B95);                                   \
00482            outptr += 4;                                              \
00483            if (__builtin_expect (outptr + 4 > outend, 0))                   \
00484              {                                                              \
00485               *statep = (0x0BCD << 8) + (5 << 4);                           \
00486               result = __GCONV_FULL_OUTPUT;                                 \
00487               break;                                                 \
00488              }                                                              \
00489            put32 (outptr, 0x0BCD);                                   \
00490            outptr += 4;                                              \
00491            if (__builtin_expect (outptr + 4 > outend, 0))                   \
00492              {                                                              \
00493               *statep = (0x0BB7 << 8) + (3 << 4);                           \
00494               result = __GCONV_FULL_OUTPUT;                                 \
00495               break;                                                 \
00496              }                                                              \
00497            put32 (outptr, 0x0BB7);                                   \
00498            outptr += 4;                                              \
00499            if (__builtin_expect (outptr + 4 > outend, 0))                   \
00500              {                                                              \
00501               *statep = (0x0BCD << 8);                               \
00502               result = __GCONV_FULL_OUTPUT;                                 \
00503               break;                                                 \
00504              }                                                              \
00505            put32 (outptr, 0x0BCD);                                   \
00506            outptr += 4;                                              \
00507            continue;                                                 \
00508          }                                                           \
00509        else                                                          \
00510          {                                                           \
00511            /* This is illegal.  */                                   \
00512            STANDARD_FROM_LOOP_ERR_HANDLER (1);                              \
00513          }                                                           \
00514       }                                                                     \
00515                                                                      \
00516     /* Now that we wrote the output increment the input pointer.  */        \
00517     inptr++;                                                         \
00518   }
00519 #define LOOP_NEED_FLAGS
00520 #define EXTRA_LOOP_DECLS    , int *statep
00521 #include <iconv/loop.c>
00522 
00523 
00524 /* Next, define the other direction, from UCS-4 to TSCII.  */
00525 
00526 static const uint8_t ucs4_to_tscii[128] =
00527   {
00528        0,    0,    0, 0xb7,    0, 0xab, 0xac, 0xfe, /* 0x0B80..0x0B87 */
00529     0xae, 0xaf, 0xb0,    0,    0,    0, 0xb1, 0xb2, /* 0x0B88..0x0B8F */
00530     0xb3,    0, 0xb4, 0xb5, 0xb6, 0xb8,    0,    0, /* 0x0B90..0x0B97 */
00531        0, 0xb9, 0xba,    0, 0x83,    0, 0xbb, 0xbc, /* 0x0B98..0x0B9F */
00532        0,    0,    0, 0xbd, 0xbe,    0,    0,    0, /* 0x0BA0..0x0BA7 */
00533     0xbf, 0xc9, 0xc0,    0,    0,    0, 0xc1, 0xc2, /* 0x0BA8..0x0BAF */
00534     0xc3, 0xc8, 0xc4, 0xc7, 0xc6, 0xc5,    0, 0x84, /* 0x0BB0..0x0BB7 */
00535     0x85, 0x86,    0,    0,    0,    0, 0xa1, 0xa2, /* 0x0BB8..0x0BBF */
00536     0xa3, 0xa4, 0xa5,    0,    0,    0, 0xa6, 0xa7, /* 0x0BC0..0x0BC7 */
00537     0xa8,    0,    0,    0,    0,    0,    0,    0, /* 0x0BC8..0x0BCF */
00538        0,    0,    0,    0,    0,    0,    0, 0xaa, /* 0x0BD0..0x0BD7 */
00539        0,    0,    0,    0,    0,    0,    0,    0, /* 0x0BD8..0x0BDF */
00540        0,    0,    0,    0,    0,    0, 0x80, 0x81, /* 0x0BE0..0x0BE7 */
00541     0x8d, 0x8e, 0x8f, 0x90, 0x95, 0x96, 0x97, 0x98, /* 0x0BE8..0x0BEF */
00542     0x9d, 0x9e, 0x9f,    0,    0,    0,    0,    0, /* 0x0BF0..0x0BF7 */
00543        0,    0,    0,    0,    0,    0,    0,    0  /* 0x0BF8..0x0BFF */
00544   };
00545 
00546 static const uint8_t consonant_with_u[18] =
00547   {
00548     0xcc, 0x99, 0xcd, 0x9a, 0xce, 0xcf, 0xd0, 0xd1, 0xd2,
00549     0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb
00550   };
00551 
00552 static const uint8_t consonant_with_uu[18] =
00553   {
00554     0xdc, 0x9b, 0xdd, 0x9c, 0xde, 0xdf, 0xe0, 0xe1, 0xe2,
00555     0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb
00556   };
00557 
00558 static const uint8_t consonant_with_virama[18] =
00559   {
00560     0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4,
00561     0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd
00562   };
00563 
00564 #define MIN_NEEDED_INPUT    TO_LOOP_MIN_NEEDED_FROM
00565 #define MAX_NEEDED_INPUT    TO_LOOP_MAX_NEEDED_FROM
00566 #define MIN_NEEDED_OUTPUT   TO_LOOP_MIN_NEEDED_TO
00567 #define MAX_NEEDED_OUTPUT   TO_LOOP_MAX_NEEDED_TO
00568 #define LOOPFCT                    TO_LOOP
00569 #define BODY \
00570   {                                                                  \
00571     uint32_t ch = get32 (inptr);                                     \
00572                                                                      \
00573     if ((*statep >> 3) != 0)                                                \
00574       {                                                                     \
00575        /* Attempt to combine the last character with this one.  */          \
00576        uint32_t last = *statep >> 3;                                        \
00577                                                                      \
00578        if (last >= 0xb8 && last <= 0xc9)                             \
00579          {                                                           \
00580            if (ch == 0x0BC1)                                                \
00581              {                                                              \
00582               *outptr++ = consonant_with_u[last - 0xb8];                    \
00583               *statep = 0;                                           \
00584               inptr += 4;                                            \
00585               continue;                                              \
00586              }                                                              \
00587            if (ch == 0x0BC2)                                                \
00588              {                                                              \
00589               *outptr++ = consonant_with_uu[last - 0xb8];                   \
00590               *statep = 0;                                           \
00591               inptr += 4;                                            \
00592               continue;                                              \
00593              }                                                              \
00594            if (ch == 0x0BC6)                                                \
00595              {                                                              \
00596               if (__builtin_expect (outptr + 2 <= outend, 1))               \
00597                 {                                                    \
00598                   *outptr++ = 0xa6;                                         \
00599                   *outptr++ = last;                                         \
00600                   *statep = 0;                                       \
00601                   inptr += 4;                                               \
00602                   continue;                                          \
00603                 }                                                    \
00604               else                                                   \
00605                 {                                                    \
00606                   result = __GCONV_FULL_OUTPUT;                      \
00607                   break;                                             \
00608                 }                                                    \
00609              }                                                              \
00610            if (ch == 0x0BC7)                                                \
00611              {                                                              \
00612               if (__builtin_expect (outptr + 2 <= outend, 1))               \
00613                 {                                                    \
00614                   *outptr++ = 0xa7;                                         \
00615                   *outptr++ = last;                                         \
00616                   *statep = 0;                                       \
00617                   inptr += 4;                                               \
00618                   continue;                                          \
00619                 }                                                    \
00620               else                                                   \
00621                 {                                                    \
00622                   result = __GCONV_FULL_OUTPUT;                      \
00623                   break;                                             \
00624                 }                                                    \
00625              }                                                              \
00626            if (ch == 0x0BC8)                                                \
00627              {                                                              \
00628               if (__builtin_expect (outptr + 2 <= outend, 1))               \
00629                 {                                                    \
00630                   *outptr++ = 0xa8;                                         \
00631                   *outptr++ = last;                                         \
00632                   *statep = 0;                                       \
00633                   inptr += 4;                                               \
00634                   continue;                                          \
00635                 }                                                    \
00636               else                                                   \
00637                 {                                                    \
00638                   result = __GCONV_FULL_OUTPUT;                      \
00639                   break;                                             \
00640                 }                                                    \
00641              }                                                              \
00642            if (ch == 0x0BCA)                                                \
00643              {                                                              \
00644               if (__builtin_expect (outptr + 3 <= outend, 1))               \
00645                 {                                                    \
00646                   *outptr++ = 0xa6;                                         \
00647                   *outptr++ = last;                                         \
00648                   *outptr++ = 0xa1;                                         \
00649                   *statep = 0;                                       \
00650                   inptr += 4;                                               \
00651                   continue;                                          \
00652                 }                                                    \
00653               else                                                   \
00654                 {                                                    \
00655                   result = __GCONV_FULL_OUTPUT;                      \
00656                   break;                                             \
00657                 }                                                    \
00658              }                                                              \
00659            if (ch == 0x0BCB)                                                \
00660              {                                                              \
00661               if (__builtin_expect (outptr + 3 <= outend, 1))               \
00662                 {                                                    \
00663                   *outptr++ = 0xa7;                                         \
00664                   *outptr++ = last;                                         \
00665                   *outptr++ = 0xa1;                                         \
00666                   *statep = 0;                                       \
00667                   inptr += 4;                                               \
00668                   continue;                                          \
00669                 }                                                    \
00670               else                                                   \
00671                 {                                                    \
00672                   result = __GCONV_FULL_OUTPUT;                      \
00673                   break;                                             \
00674                 }                                                    \
00675              }                                                              \
00676            if (ch == 0x0BCC)                                                \
00677              {                                                              \
00678               if (__builtin_expect (outptr + 3 <= outend, 1))               \
00679                 {                                                    \
00680                   *outptr++ = 0xa7;                                         \
00681                   *outptr++ = last;                                         \
00682                   *outptr++ = 0xaa;                                         \
00683                   *statep = 0;                                       \
00684                   inptr += 4;                                               \
00685                   continue;                                          \
00686                 }                                                    \
00687               else                                                   \
00688                 {                                                    \
00689                   result = __GCONV_FULL_OUTPUT;                      \
00690                   break;                                             \
00691                 }                                                    \
00692              }                                                              \
00693            if (ch == 0x0BCD)                                                \
00694              {                                                              \
00695               if (last != 0xb8)                                      \
00696                 {                                                    \
00697                   *outptr++ = consonant_with_virama[last - 0xb8];           \
00698                   *statep = 0;                                       \
00699                 }                                                    \
00700               else                                                   \
00701                 *statep = 0xec << 3;                                        \
00702               inptr += 4;                                            \
00703               continue;                                              \
00704              }                                                              \
00705            if (last == 0xbc && (ch == 0x0BBF || ch == 0x0BC0))              \
00706              {                                                              \
00707               *outptr++ = ch - 0x0af5;                               \
00708               *statep = 0;                                           \
00709               inptr += 4;                                            \
00710               continue;                                              \
00711              }                                                              \
00712          }                                                           \
00713        else if (last >= 0x83 && last <= 0x86)                               \
00714          {                                                           \
00715            if (last >= 0x85 && (ch == 0x0BC1 || ch == 0x0BC2))              \
00716              {                                                              \
00717               *outptr++ = last + 5;                                         \
00718               *statep = 0;                                           \
00719               continue;                                              \
00720              }                                                              \
00721            if (ch == 0x0BCD)                                                \
00722              {                                                              \
00723               if (last != 0x85)                                      \
00724                 {                                                    \
00725                   *outptr++ = last + 5;                              \
00726                   *statep = 0;                                       \
00727                 }                                                    \
00728               else                                                   \
00729                 *statep = 0x8a << 3;                                        \
00730               inptr += 4;                                            \
00731               continue;                                              \
00732              }                                                              \
00733          }                                                           \
00734        else if (last == 0xec)                                               \
00735          {                                                           \
00736            if (ch == 0x0BB7)                                                \
00737              {                                                              \
00738               *statep = 0x87 << 3;                                   \
00739               inptr += 4;                                            \
00740               continue;                                              \
00741              }                                                              \
00742          }                                                           \
00743        else if (last == 0x8a)                                               \
00744          {                                                           \
00745            if (ch == 0x0BB0)                                                \
00746              {                                                              \
00747               *statep = 0xc38a << 3;                                        \
00748               inptr += 4;                                            \
00749               continue;                                              \
00750              }                                                              \
00751          }                                                           \
00752        else if (last == 0x87)                                               \
00753          {                                                           \
00754            if (ch == 0x0BCD)                                                \
00755              {                                                              \
00756               *outptr++ = 0x8c;                                      \
00757               *statep = 0;                                           \
00758               inptr += 4;                                            \
00759               continue;                                              \
00760              }                                                              \
00761          }                                                           \
00762        else                                                          \
00763          {                                                           \
00764            assert (last == 0xc38a);                                         \
00765            if (ch == 0x0BC0)                                                \
00766              {                                                              \
00767               *outptr++ = 0x82;                                      \
00768               *statep = 0;                                           \
00769               inptr += 4;                                            \
00770               continue;                                              \
00771              }                                                              \
00772          }                                                           \
00773                                                                      \
00774        /* Output the buffered character.  */                                \
00775        if (__builtin_expect (last >> 8, 0))                                 \
00776          {                                                           \
00777            if (__builtin_expect (outptr + 2 <= outend, 1))                  \
00778              {                                                              \
00779               *outptr++ = last & 0xff;                               \
00780               *outptr++ = (last >> 8) & 0xff;                               \
00781              }                                                              \
00782            else                                                      \
00783              {                                                              \
00784               result = __GCONV_FULL_OUTPUT;                                 \
00785               break;                                                 \
00786              }                                                              \
00787          }                                                           \
00788         else                                                         \
00789          *outptr++ = last & 0xff;                                    \
00790        *statep = 0;                                                  \
00791        continue;                                                     \
00792       }                                                                     \
00793                                                                      \
00794     if (ch < 0x80)                                                   \
00795       /* Plain ASCII character.  */                                         \
00796       *outptr++ = ch;                                                       \
00797     else if (ch >= 0x0B80 && ch <= 0x0BFF)                                  \
00798       {                                                                     \
00799        /* Tamil character.  */                                              \
00800        uint8_t t = ucs4_to_tscii[ch - 0x0B80];                              \
00801                                                                      \
00802        if (t != 0)                                                   \
00803          {                                                           \
00804            if ((t >= 0xb8 && t <= 0xc9) || (t >= 0x83 && t <= 0x86))        \
00805              *statep = (uint32_t) t << 3;                            \
00806            else                                                      \
00807              *outptr++ = t;                                          \
00808          }                                                           \
00809        else if (ch >= 0x0BCA && ch <= 0x0BCC)                               \
00810          {                                                           \
00811            /* See whether we have room for two bytes.  */                   \
00812            if (__builtin_expect (outptr + 2 <= outend, 1))                  \
00813              {                                                              \
00814               *outptr++ = (ch == 0x0BCA ? 0xa6 : 0xa7);              \
00815               *outptr++ = (ch != 0x0BCC ? 0xa1 : 0xaa);              \
00816              }                                                              \
00817            else                                                      \
00818              {                                                              \
00819               result = __GCONV_FULL_OUTPUT;                                 \
00820               break;                                                 \
00821              }                                                              \
00822          }                                                           \
00823        else                                                          \
00824          {                                                           \
00825            /* Illegal character.  */                                        \
00826            STANDARD_TO_LOOP_ERR_HANDLER (4);                                \
00827          }                                                           \
00828       }                                                                     \
00829     else if (ch == 0x00A9)                                           \
00830       *outptr++ = ch;                                                       \
00831     else if (ch == 0x2018 || ch == 0x2019)                                  \
00832       *outptr++ = ch - 0x1f87;                                              \
00833     else if (ch == 0x201C || ch == 0x201D)                                  \
00834       *outptr++ = ch - 0x1f89;                                              \
00835     else                                                             \
00836       {                                                                     \
00837        UNICODE_TAG_HANDLER (ch, 4);                                         \
00838                                                                      \
00839        /* Illegal character.  */                                     \
00840        STANDARD_TO_LOOP_ERR_HANDLER (4);                             \
00841       }                                                                     \
00842                                                                      \
00843     /* Now that we wrote the output increment the input pointer.  */        \
00844     inptr += 4;                                                             \
00845   }
00846 #define LOOP_NEED_FLAGS
00847 #define EXTRA_LOOP_DECLS    , int *statep
00848 #include <iconv/loop.c>
00849 
00850 
00851 /* Now define the toplevel functions.  */
00852 #include <iconv/skeleton.c>