(root)/
glibc-2.38/
iconvdata/
tcvn5712-1.c
       1  /* Conversion to and from TCVN5712-1.
       2     Copyright (C) 2001-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <dlfcn.h>
      20  #include <stdint.h>
      21  #include <stdlib.h>
      22  
      23  #define NELEMS(arr) (sizeof (arr) / sizeof (arr[0]))
      24  
      25  /* Definitions used in the body of the `gconv' function.  */
      26  #define CHARSET_NAME		"TCVN5712-1//"
      27  #define FROM_LOOP		from_tcvn5712_1
      28  #define TO_LOOP			to_tcvn5712_1
      29  #define DEFINE_INIT		1
      30  #define DEFINE_FINI		1
      31  #define ONE_DIRECTION		0
      32  #define FROM_LOOP_MIN_NEEDED_FROM	1
      33  #define FROM_LOOP_MAX_NEEDED_FROM	1
      34  #define FROM_LOOP_MIN_NEEDED_TO		4
      35  #define FROM_LOOP_MAX_NEEDED_TO		4
      36  #define TO_LOOP_MIN_NEEDED_FROM		4
      37  #define TO_LOOP_MAX_NEEDED_FROM		4
      38  #define TO_LOOP_MIN_NEEDED_TO		1
      39  #define TO_LOOP_MAX_NEEDED_TO		2
      40  #define PREPARE_LOOP \
      41    int saved_state;							      \
      42    int *statep = &data->__statep->__count;
      43  #define EXTRA_LOOP_ARGS		, statep
      44  
      45  
      46  /* Since we might have to reset input pointer we must be able to save
      47     and restore the state.  */
      48  #define SAVE_RESET_STATE(Save) \
      49    if (Save)								      \
      50      saved_state = *statep;						      \
      51    else									      \
      52      *statep = saved_state
      53  
      54  
      55  /* During TCVN5712-1 to UCS4 conversion, the COUNT element of the state
      56     contains the last UCS4 character, shifted by 3 bits.  */
      57  
      58  
      59  /* Since this is a stateful encoding we have to provide code which resets
      60     the output state to the initial state.  This has to be done during the
      61     flushing.  */
      62  #define EMIT_SHIFT_TO_INIT \
      63    if (data->__statep->__count != 0)					      \
      64      {									      \
      65        if (FROM_DIRECTION)						      \
      66  	{								      \
      67  	  if (__glibc_likely (outbuf + 4 <= outend))			      \
      68  	    {								      \
      69  	      /* Write out the last character.  */			      \
      70  	      *((uint32_t *) outbuf) = data->__statep->__count >> 3;	      \
      71  	      outbuf += sizeof (uint32_t);				      \
      72  	      data->__statep->__count = 0;				      \
      73  	    }								      \
      74  	  else								      \
      75  	    /* We don't have enough room in the output buffer.  */	      \
      76  	    status = __GCONV_FULL_OUTPUT;				      \
      77  	}								      \
      78        else								      \
      79  	/* We don't use shift states in the TO_DIRECTION.  */		      \
      80  	data->__statep->__count = 0;					      \
      81      }
      82  
      83  
      84  static const uint16_t map_from_tcvn_low[0x18] =
      85    {
      86      0x0000, 0x00da, 0x1ee4, 0x0003, 0x1eea, 0x1eec, 0x1eee, 0x0007,
      87      0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
      88      0x0010, 0x1ee8, 0x1ef0, 0x1ef2, 0x1ef6, 0x1ef8, 0x00dd, 0x1ef4
      89    };
      90  
      91  static const uint16_t map_from_tcvn_high[0x80] =
      92    {
      93      0x00c0, 0x1ea2, 0x00c3, 0x00c1, 0x1ea0, 0x1eb6, 0x1eac, 0x00c8,
      94      0x1eba, 0x1ebc, 0x00c9, 0x1eb8, 0x1ec6, 0x00cc, 0x1ec8, 0x0128,
      95      0x00cd, 0x1eca, 0x00d2, 0x1ece, 0x00d5, 0x00d3, 0x1ecc, 0x1ed8,
      96      0x1edc, 0x1ede, 0x1ee0, 0x1eda, 0x1ee2, 0x00d9, 0x1ee6, 0x0168,
      97      0x00a0, 0x0102, 0x00c2, 0x00ca, 0x00d4, 0x01a0, 0x01af, 0x0110,
      98      0x0103, 0x00e2, 0x00ea, 0x00f4, 0x01a1, 0x01b0, 0x0111, 0x1eb0,
      99      0x0300, 0x0309, 0x0303, 0x0301, 0x0323, 0x00e0, 0x1ea3, 0x00e3,
     100      0x00e1, 0x1ea1, 0x1eb2, 0x1eb1, 0x1eb3, 0x1eb5, 0x1eaf, 0x1eb4,
     101      0x1eae, 0x1ea6, 0x1ea8, 0x1eaa, 0x1ea4, 0x1ec0, 0x1eb7, 0x1ea7,
     102      0x1ea9, 0x1eab, 0x1ea5, 0x1ead, 0x00e8, 0x1ec2, 0x1ebb, 0x1ebd,
     103      0x00e9, 0x1eb9, 0x1ec1, 0x1ec3, 0x1ec5, 0x1ebf, 0x1ec7, 0x00ec,
     104      0x1ec9, 0x1ec4, 0x1ebe, 0x1ed2, 0x0129, 0x00ed, 0x1ecb, 0x00f2,
     105      0x1ed4, 0x1ecf, 0x00f5, 0x00f3, 0x1ecd, 0x1ed3, 0x1ed5, 0x1ed7,
     106      0x1ed1, 0x1ed9, 0x1edd, 0x1edf, 0x1ee1, 0x1edb, 0x1ee3, 0x00f9,
     107      0x1ed6, 0x1ee7, 0x0169, 0x00fa, 0x1ee5, 0x1eeb, 0x1eed, 0x1eef,
     108      0x1ee9, 0x1ef1, 0x1ef3, 0x1ef7, 0x1ef9, 0x00fd, 0x1ef5, 0x1ed0
     109    };
     110  
     111  
     112  /* TCVN5712-1 contains five combining characters:
     113     0x0300, 0x0301, 0x0303, 0x0309, 0x0323.  */
     114  
     115  /* Composition tables for each of the relevant combining characters.  */
     116  static const struct
     117  {
     118    uint16_t base;
     119    uint16_t composed;
     120  } comp_table_data[] =
     121    {
     122  #define COMP_TABLE_IDX_0300 0
     123  #define COMP_TABLE_LEN_0300 28
     124      { 0x0041, 0x00C0 },
     125      { 0x0045, 0x00C8 },
     126      { 0x0049, 0x00CC },
     127      { 0x004E, 0x01F8 },
     128      { 0x004F, 0x00D2 },
     129      { 0x0055, 0x00D9 },
     130      { 0x0057, 0x1E80 },
     131      { 0x0059, 0x1EF2 },
     132      { 0x0061, 0x00E0 },
     133      { 0x0065, 0x00E8 },
     134      { 0x0069, 0x00EC },
     135      { 0x006E, 0x01F9 },
     136      { 0x006F, 0x00F2 },
     137      { 0x0075, 0x00F9 },
     138      { 0x0077, 0x1E81 },
     139      { 0x0079, 0x1EF3 },
     140    /*{ 0x00A8, 0x1FED },*/
     141      { 0x00C2, 0x1EA6 },
     142      { 0x00CA, 0x1EC0 },
     143      { 0x00D4, 0x1ED2 },
     144    /*{ 0x00DC, 0x01DB },*/
     145      { 0x00E2, 0x1EA7 },
     146      { 0x00EA, 0x1EC1 },
     147      { 0x00F4, 0x1ED3 },
     148    /*{ 0x00FC, 0x01DC },*/
     149      { 0x0102, 0x1EB0 },
     150      { 0x0103, 0x1EB1 },
     151    /*{ 0x0112, 0x1E14 },*/
     152    /*{ 0x0113, 0x1E15 },*/
     153    /*{ 0x014C, 0x1E50 },*/
     154    /*{ 0x014D, 0x1E51 },*/
     155      { 0x01A0, 0x1EDC },
     156      { 0x01A1, 0x1EDD },
     157      { 0x01AF, 0x1EEA },
     158      { 0x01B0, 0x1EEB },
     159  #define COMP_TABLE_IDX_0301 (COMP_TABLE_IDX_0300 + COMP_TABLE_LEN_0300)
     160  #define COMP_TABLE_LEN_0301 50
     161      { 0x0041, 0x00C1 },
     162      { 0x0043, 0x0106 },
     163      { 0x0045, 0x00C9 },
     164      { 0x0047, 0x01F4 },
     165      { 0x0049, 0x00CD },
     166      { 0x004B, 0x1E30 },
     167      { 0x004C, 0x0139 },
     168      { 0x004D, 0x1E3E },
     169      { 0x004E, 0x0143 },
     170      { 0x004F, 0x00D3 },
     171      { 0x0050, 0x1E54 },
     172      { 0x0052, 0x0154 },
     173      { 0x0053, 0x015A },
     174      { 0x0055, 0x00DA },
     175      { 0x0057, 0x1E82 },
     176      { 0x0059, 0x00DD },
     177      { 0x005A, 0x0179 },
     178      { 0x0061, 0x00E1 },
     179      { 0x0063, 0x0107 },
     180      { 0x0065, 0x00E9 },
     181      { 0x0067, 0x01F5 },
     182      { 0x0069, 0x00ED },
     183      { 0x006B, 0x1E31 },
     184      { 0x006C, 0x013A },
     185      { 0x006D, 0x1E3F },
     186      { 0x006E, 0x0144 },
     187      { 0x006F, 0x00F3 },
     188      { 0x0070, 0x1E55 },
     189      { 0x0072, 0x0155 },
     190      { 0x0073, 0x015B },
     191      { 0x0075, 0x00FA },
     192      { 0x0077, 0x1E83 },
     193      { 0x0079, 0x00FD },
     194      { 0x007A, 0x017A },
     195    /*{ 0x00A8, 0x0385 },*//* prefer U+0385 over U+1FEE */
     196      { 0x00C2, 0x1EA4 },
     197    /*{ 0x00C5, 0x01FA },*/
     198    /*{ 0x00C6, 0x01FC },*/
     199    /*{ 0x00C7, 0x1E08 },*/
     200      { 0x00CA, 0x1EBE },
     201    /*{ 0x00CF, 0x1E2E },*/
     202      { 0x00D4, 0x1ED0 },
     203      { 0x00D5, 0x1E4C },
     204    /*{ 0x00D8, 0x01FE },*/
     205    /*{ 0x00DC, 0x01D7 },*/
     206      { 0x00E2, 0x1EA5 },
     207    /*{ 0x00E5, 0x01FB },*/
     208    /*{ 0x00E6, 0x01FD },*/
     209    /*{ 0x00E7, 0x1E09 },*/
     210      { 0x00EA, 0x1EBF },
     211    /*{ 0x00EF, 0x1E2F },*/
     212      { 0x00F4, 0x1ED1 },
     213      { 0x00F5, 0x1E4D },
     214    /*{ 0x00F8, 0x01FF },*/
     215    /*{ 0x00FC, 0x01D8 },*/
     216      { 0x0102, 0x1EAE },
     217      { 0x0103, 0x1EAF },
     218    /*{ 0x0112, 0x1E16 },*/
     219    /*{ 0x0113, 0x1E17 },*/
     220    /*{ 0x014C, 0x1E52 },*/
     221    /*{ 0x014D, 0x1E53 },*/
     222      { 0x0168, 0x1E78 },
     223      { 0x0169, 0x1E79 },
     224      { 0x01A0, 0x1EDA },
     225      { 0x01A1, 0x1EDB },
     226      { 0x01AF, 0x1EE8 },
     227      { 0x01B0, 0x1EE9 },
     228  #define COMP_TABLE_IDX_0303 (COMP_TABLE_IDX_0301 + COMP_TABLE_LEN_0301)
     229  #define COMP_TABLE_LEN_0303 34
     230      { 0x0041, 0x00C3 },
     231      { 0x0045, 0x1EBC },
     232      { 0x0049, 0x0128 },
     233      { 0x004E, 0x00D1 },
     234      { 0x004F, 0x00D5 },
     235      { 0x0055, 0x0168 },
     236      { 0x0056, 0x1E7C },
     237      { 0x0059, 0x1EF8 },
     238      { 0x0061, 0x00E3 },
     239      { 0x0065, 0x1EBD },
     240      { 0x0069, 0x0129 },
     241      { 0x006E, 0x00F1 },
     242      { 0x006F, 0x00F5 },
     243      { 0x0075, 0x0169 },
     244      { 0x0076, 0x1E7D },
     245      { 0x0079, 0x1EF9 },
     246      { 0x00C2, 0x1EAA },
     247      { 0x00CA, 0x1EC4 },
     248      { 0x00D3, 0x1E4C },
     249      { 0x00D4, 0x1ED6 },
     250      { 0x00D6, 0x1E4E },
     251      { 0x00DA, 0x1E78 },
     252      { 0x00E2, 0x1EAB },
     253      { 0x00EA, 0x1EC5 },
     254      { 0x00F3, 0x1E4D },
     255      { 0x00F4, 0x1ED7 },
     256      { 0x00F6, 0x1E4F },
     257      { 0x00FA, 0x1E79 },
     258      { 0x0102, 0x1EB4 },
     259      { 0x0103, 0x1EB5 },
     260      { 0x01A0, 0x1EE0 },
     261      { 0x01A1, 0x1EE1 },
     262      { 0x01AF, 0x1EEE },
     263      { 0x01B0, 0x1EEF },
     264  #define COMP_TABLE_IDX_0309 (COMP_TABLE_IDX_0303 + COMP_TABLE_LEN_0303)
     265  #define COMP_TABLE_LEN_0309 24
     266      { 0x0041, 0x1EA2 },
     267      { 0x0045, 0x1EBA },
     268      { 0x0049, 0x1EC8 },
     269      { 0x004F, 0x1ECE },
     270      { 0x0055, 0x1EE6 },
     271      { 0x0059, 0x1EF6 },
     272      { 0x0061, 0x1EA3 },
     273      { 0x0065, 0x1EBB },
     274      { 0x0069, 0x1EC9 },
     275      { 0x006F, 0x1ECF },
     276      { 0x0075, 0x1EE7 },
     277      { 0x0079, 0x1EF7 },
     278      { 0x00C2, 0x1EA8 },
     279      { 0x00CA, 0x1EC2 },
     280      { 0x00D4, 0x1ED4 },
     281      { 0x00E2, 0x1EA9 },
     282      { 0x00EA, 0x1EC3 },
     283      { 0x00F4, 0x1ED5 },
     284      { 0x0102, 0x1EB2 },
     285      { 0x0103, 0x1EB3 },
     286      { 0x01A0, 0x1EDE },
     287      { 0x01A1, 0x1EDF },
     288      { 0x01AF, 0x1EEC },
     289      { 0x01B0, 0x1EED },
     290  #define COMP_TABLE_IDX_0323 (COMP_TABLE_IDX_0309 + COMP_TABLE_LEN_0309)
     291  #define COMP_TABLE_LEN_0323 50
     292      { 0x0041, 0x1EA0 },
     293      { 0x0042, 0x1E04 },
     294      { 0x0044, 0x1E0C },
     295      { 0x0045, 0x1EB8 },
     296      { 0x0048, 0x1E24 },
     297      { 0x0049, 0x1ECA },
     298      { 0x004B, 0x1E32 },
     299      { 0x004C, 0x1E36 },
     300      { 0x004D, 0x1E42 },
     301      { 0x004E, 0x1E46 },
     302      { 0x004F, 0x1ECC },
     303      { 0x0052, 0x1E5A },
     304      { 0x0053, 0x1E62 },
     305      { 0x0054, 0x1E6C },
     306      { 0x0055, 0x1EE4 },
     307      { 0x0056, 0x1E7E },
     308      { 0x0057, 0x1E88 },
     309      { 0x0059, 0x1EF4 },
     310      { 0x005A, 0x1E92 },
     311      { 0x0061, 0x1EA1 },
     312      { 0x0062, 0x1E05 },
     313      { 0x0064, 0x1E0D },
     314      { 0x0065, 0x1EB9 },
     315      { 0x0068, 0x1E25 },
     316      { 0x0069, 0x1ECB },
     317      { 0x006B, 0x1E33 },
     318      { 0x006C, 0x1E37 },
     319      { 0x006D, 0x1E43 },
     320      { 0x006E, 0x1E47 },
     321      { 0x006F, 0x1ECD },
     322      { 0x0072, 0x1E5B },
     323      { 0x0073, 0x1E63 },
     324      { 0x0074, 0x1E6D },
     325      { 0x0075, 0x1EE5 },
     326      { 0x0076, 0x1E7F },
     327      { 0x0077, 0x1E89 },
     328      { 0x0079, 0x1EF5 },
     329      { 0x007A, 0x1E93 },
     330      { 0x00C2, 0x1EAC },
     331      { 0x00CA, 0x1EC6 },
     332      { 0x00D4, 0x1ED8 },
     333      { 0x00E2, 0x1EAD },
     334      { 0x00EA, 0x1EC7 },
     335      { 0x00F4, 0x1ED9 },
     336      { 0x0102, 0x1EB6 },
     337      { 0x0103, 0x1EB7 },
     338      { 0x01A0, 0x1EE2 },
     339      { 0x01A1, 0x1EE3 },
     340      { 0x01AF, 0x1EF0 },
     341      { 0x01B0, 0x1EF1 },
     342  #define COMP_TABLE_IDX_END (COMP_TABLE_IDX_0323 + COMP_TABLE_LEN_0323)
     343    };
     344  /* Compile-time verification of table size.  */
     345  typedef int verify1[(NELEMS (comp_table_data) == COMP_TABLE_IDX_END) - 1];
     346  
     347  static const struct
     348  {
     349    unsigned int idx;
     350    unsigned int len;
     351  } comp_table[5] =
     352    {
     353      { COMP_TABLE_IDX_0300, COMP_TABLE_LEN_0300 },
     354      { COMP_TABLE_IDX_0301, COMP_TABLE_LEN_0301 },
     355      { COMP_TABLE_IDX_0303, COMP_TABLE_LEN_0303 },
     356      { COMP_TABLE_IDX_0309, COMP_TABLE_LEN_0309 },
     357      { COMP_TABLE_IDX_0323, COMP_TABLE_LEN_0323 },
     358    };
     359  
     360  
     361  /* First define the conversion function from TCVN5712-1 to UCS4.  */
     362  #define MIN_NEEDED_INPUT	FROM_LOOP_MIN_NEEDED_FROM
     363  #define MAX_NEEDED_INPUT	FROM_LOOP_MAX_NEEDED_FROM
     364  #define MIN_NEEDED_OUTPUT	FROM_LOOP_MIN_NEEDED_TO
     365  #define MAX_NEEDED_OUTPUT	FROM_LOOP_MAX_NEEDED_TO
     366  #define LOOPFCT			FROM_LOOP
     367  #define BODY \
     368    {									      \
     369      uint32_t ch = *inptr;						      \
     370      uint32_t last_ch;							      \
     371      int must_buffer_ch;							      \
     372  									      \
     373      if (ch < 0x18)							      \
     374        ch = map_from_tcvn_low[ch];					      \
     375      else if (ch >= 0x80)						      \
     376        ch = map_from_tcvn_high[ch - 0x80];				      \
     377  									      \
     378      /* Determine whether there is a buffered character pending.  */	      \
     379      last_ch = *statep >> 3;						      \
     380  									      \
     381      /* We have to buffer ch if it is a possible match in comp_table_data.  */ \
     382      must_buffer_ch = (ch >= 0x0041 && ch <= 0x01b0);                          \
     383  									      \
     384      if (last_ch)							      \
     385        {									      \
     386  	if (ch >= 0x0300 && ch < 0x0340)				      \
     387  	  {								      \
     388  	    /* See whether last_ch and ch can be combined.  */		      \
     389  	    unsigned int i;						      \
     390  	    unsigned int i1;						      \
     391  	    unsigned int i2;						      \
     392  									      \
     393  	    switch (ch)							      \
     394  	      {								      \
     395  	      case 0x0300:						      \
     396  		i = 0;							      \
     397  		break;							      \
     398  	      case 0x0301:						      \
     399  		i = 1;							      \
     400  		break;							      \
     401  	      case 0x0303:						      \
     402  		i = 2;							      \
     403  		break;							      \
     404  	      case 0x0309:						      \
     405  		i = 3;							      \
     406  		break;							      \
     407  	      case 0x0323:						      \
     408  		i = 4;							      \
     409  		break;							      \
     410  	      default:							      \
     411  		abort ();						      \
     412  	      }								      \
     413  									      \
     414  	    i1 = comp_table[i].idx;					      \
     415  	    i2 = i1 + comp_table[i].len - 1;				      \
     416  									      \
     417  	    if (last_ch >= comp_table_data[i1].base			      \
     418  		&& last_ch <= comp_table_data[i2].base)			      \
     419  	      {								      \
     420  		for (;;)						      \
     421  		  {							      \
     422  		    i = (i1 + i2) >> 1;					      \
     423  		    if (last_ch == comp_table_data[i].base)		      \
     424  		      break;						      \
     425  		    if (last_ch < comp_table_data[i].base)		      \
     426  		      {							      \
     427  			if (i1 == i)					      \
     428  			  goto not_combining;				      \
     429  			i2 = i;						      \
     430  		      }							      \
     431  		    else						      \
     432  		      {							      \
     433  			if (i1 != i)					      \
     434  			  i1 = i;					      \
     435  			else						      \
     436  			  {						      \
     437  			    i = i2;					      \
     438  			    if (last_ch == comp_table_data[i].base)	      \
     439  			      break;					      \
     440  			    goto not_combining;				      \
     441  			  }						      \
     442  		      }							      \
     443  		  }							      \
     444  		last_ch = comp_table_data[i].composed;			      \
     445  		/* Output the combined character.  */			      \
     446  		put32 (outptr, last_ch);				      \
     447  		outptr += 4;						      \
     448  		*statep = 0;						      \
     449  		++inptr;						      \
     450  		continue;						      \
     451  	      }								      \
     452  	  }								      \
     453  									      \
     454        not_combining:							      \
     455  	/* Output the buffered character.  */				      \
     456  	put32 (outptr, last_ch);					      \
     457  	outptr += 4;							      \
     458  	*statep = 0;							      \
     459  									      \
     460  	/* If we don't have enough room to output ch as well, then deal	      \
     461  	   with it in another round.  */				      \
     462  	if (!must_buffer_ch && __builtin_expect (outptr + 4 > outend, 0))     \
     463  	  continue;							      \
     464        }									      \
     465  									      \
     466      if (must_buffer_ch)							      \
     467        *statep = ch << 3;						      \
     468      else								      \
     469        {									      \
     470  	put32 (outptr, ch);						      \
     471  	outptr += 4;							      \
     472        }									      \
     473      ++inptr;								      \
     474    }
     475  #define EXTRA_LOOP_DECLS	, int *statep
     476  #define ONEBYTE_BODY \
     477    {									      \
     478      uint32_t ch;							      \
     479  									      \
     480      if (c < 0x18)							      \
     481        ch = map_from_tcvn_low[c];					      \
     482      else if (c >= 0x80)							      \
     483        ch = map_from_tcvn_high[c - 0x80];				      \
     484      else								      \
     485        ch = c;								      \
     486      if (ch >= 0x0041 && ch <= 0x01b0)					      \
     487        return WEOF;							      \
     488      return ch;								      \
     489    }
     490  #include <iconv/loop.c>
     491  
     492  
     493  /* Next, define the conversion function from UCS4 to TCVN5712-1.  */
     494  
     495  static const unsigned char from_ucs4[] =
     496    {
     497  #define FROM_IDX_00 0
     498      0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, /* 0x0001-0x0007 */
     499      0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x0008-0x000f */
     500      0x10,                                           /* 0x0010-0x0010 */
     501  
     502  #define FROM_IDX_01 (FROM_IDX_00 + 16)
     503      0x80, 0x83, 0xa2, 0x82, 0x00, 0x00, 0x00, 0x00, /* 0x00c0-0x00c7 */
     504      0x87, 0x8a, 0xa3, 0x00, 0x8d, 0x90, 0x00, 0x00, /* 0x00c8-0x00cf */
     505      0x00, 0x00, 0x92, 0x95, 0xa4, 0x94, 0x00, 0x00, /* 0x00d0-0x00d7 */
     506      0x00, 0x9d, 0x01, 0x00, 0x00, 0x16, 0x00, 0x00, /* 0x00d8-0x00df */
     507      0xb5, 0xb8, 0xa9, 0xb7, 0x00, 0x00, 0x00, 0x00, /* 0x00e0-0x00e7 */
     508      0xcc, 0xd0, 0xaa, 0x00, 0xd7, 0xdd, 0x00, 0x00, /* 0x00e8-0x00ef */
     509      0x00, 0x00, 0xdf, 0xe3, 0xab, 0xe2, 0x00, 0x00, /* 0x00f0-0x00f7 */
     510      0x00, 0xef, 0xf3, 0x00, 0x00, 0xfd, 0x00, 0x00, /* 0x00f8-0x00ff */
     511      0x00, 0x00, 0xa1, 0xa8, 0x00, 0x00, 0x00, 0x00, /* 0x0100-0x0107 */
     512      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0108-0x010f */
     513      0xa7, 0xae, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0110-0x0117 */
     514      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0118-0x011f */
     515      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0120-0x0127 */
     516      0x8f, 0xdc,                                     /* 0x0128-0x0129 */
     517  
     518  #define FROM_IDX_02 (FROM_IDX_01 + 106)
     519      0x9f, 0xf2,                                     /* 0x0168-0x0169 */
     520  
     521  #define FROM_IDX_03 (FROM_IDX_02 + 2)
     522      0xa5, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01a0-0x01a7 */
     523      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6, /* 0x01a8-0x01af */
     524      0xad,                                           /* 0x01b0-0x01b0 */
     525  
     526  #define FROM_IDX_04 (FROM_IDX_03 + 17)
     527      0xb0, 0xb3, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x0300-0x0307 */
     528      0x00, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0308-0x030f */
     529      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0310-0x0317 */
     530      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0318-0x031f */
     531      0x00, 0x00, 0x00, 0xb4,                         /* 0x0320-0x0323 */
     532  
     533  #define FROM_IDX_05 (FROM_IDX_04 + 36)
     534      0x84, 0xb9, 0x81, 0xb6, 0xc4, 0xca, 0xc1, 0xc7, /* 0x1ea0-0x1ea7 */
     535      0xc2, 0xc8, 0xc3, 0xc9, 0x86, 0xcb, 0xc0, 0xbe, /* 0x1ea8-0x1eaf */
     536      0xaf, 0xbb, 0xba, 0xbc, 0xbf, 0xbd, 0x85, 0xc6, /* 0x1eb0-0x1eb7 */
     537      0x8b, 0xd1, 0x88, 0xce, 0x89, 0xcf, 0xda, 0xd5, /* 0x1eb8-0x1ebf */
     538      0xc5, 0xd2, 0xcd, 0xd3, 0xd9, 0xd4, 0x8c, 0xd6, /* 0x1ec0-0x1ec7 */
     539      0x8e, 0xd8, 0x91, 0xde, 0x96, 0xe4, 0x93, 0xe1, /* 0x1ec8-0x1ecf */
     540      0xff, 0xe8, 0xdb, 0xe5, 0xe0, 0xe6, 0xf0, 0xe7, /* 0x1ed0-0x1ed7 */
     541      0x97, 0xe9, 0x9b, 0xed, 0x98, 0xea, 0x99, 0xeb, /* 0x1ed8-0x1edf */
     542      0x9a, 0xec, 0x9c, 0xee, 0x02, 0xf4, 0x9e, 0xf1, /* 0x1ee0-0x1ee7 */
     543      0x11, 0xf8, 0x04, 0xf5, 0x05, 0xf6, 0x06, 0xf7, /* 0x1ee8-0x1eef */
     544      0x12, 0xf9, 0x13, 0xfa, 0x17, 0xfe, 0x14, 0xfb, /* 0x1ef0-0x1ef7 */
     545      0x15, 0xfc                                      /* 0x1ef8-0x1ef9 */
     546  #define FROM_IDX_END (FROM_IDX_05 + 90)
     547    };
     548  /* Compile-time verification of table size.  */
     549  typedef int verify2[(NELEMS (from_ucs4) == FROM_IDX_END) - 1];
     550  
     551  /* Decomposition table for the relevant Unicode characters. */
     552  static const struct
     553  {
     554    uint16_t composed;
     555    uint32_t base:8;
     556    uint32_t comb1:8;
     557  } decomp_table[] =
     558    {
     559      { 0x00d1, 0x4e, 0xb2 },
     560      { 0x00f1, 0x6e, 0xb2 },
     561      { 0x0106, 0x43, 0xb3 },
     562      { 0x0107, 0x63, 0xb3 },
     563      { 0x0139, 0x4c, 0xb3 },
     564      { 0x013a, 0x6c, 0xb3 },
     565      { 0x0143, 0x4e, 0xb3 },
     566      { 0x0144, 0x6e, 0xb3 },
     567      { 0x0154, 0x52, 0xb3 },
     568      { 0x0155, 0x72, 0xb3 },
     569      { 0x015a, 0x53, 0xb3 },
     570      { 0x015b, 0x73, 0xb3 },
     571      { 0x0179, 0x5a, 0xb3 },
     572      { 0x017a, 0x7a, 0xb3 },
     573      { 0x01f4, 0x47, 0xb3 },
     574      { 0x01f5, 0x67, 0xb3 },
     575      { 0x01f8, 0x4e, 0xb0 },
     576      { 0x01f9, 0x6e, 0xb0 },
     577      { 0x1e04, 0x42, 0xb4 },
     578      { 0x1e05, 0x62, 0xb4 },
     579      { 0x1e0c, 0x44, 0xb4 },
     580      { 0x1e0d, 0x64, 0xb4 },
     581      { 0x1e24, 0x48, 0xb4 },
     582      { 0x1e25, 0x68, 0xb4 },
     583      { 0x1e30, 0x4b, 0xb3 },
     584      { 0x1e31, 0x6b, 0xb3 },
     585      { 0x1e32, 0x4b, 0xb4 },
     586      { 0x1e33, 0x6b, 0xb4 },
     587      { 0x1e36, 0x4c, 0xb4 },
     588      { 0x1e37, 0x6c, 0xb4 },
     589      { 0x1e3e, 0x4d, 0xb3 },
     590      { 0x1e3f, 0x6d, 0xb3 },
     591      { 0x1e42, 0x4d, 0xb4 },
     592      { 0x1e43, 0x6d, 0xb4 },
     593      { 0x1e46, 0x4e, 0xb4 },
     594      { 0x1e47, 0x6e, 0xb4 },
     595      { 0x1e54, 0x50, 0xb3 },
     596      { 0x1e55, 0x70, 0xb3 },
     597      { 0x1e5a, 0x52, 0xb4 },
     598      { 0x1e5b, 0x72, 0xb4 },
     599      { 0x1e62, 0x53, 0xb4 },
     600      { 0x1e63, 0x73, 0xb4 },
     601      { 0x1e6c, 0x54, 0xb4 },
     602      { 0x1e6d, 0x74, 0xb4 },
     603      { 0x1e7c, 0x56, 0xb2 },
     604      { 0x1e7d, 0x76, 0xb2 },
     605      { 0x1e7e, 0x56, 0xb4 },
     606      { 0x1e7f, 0x76, 0xb4 },
     607      { 0x1e80, 0x57, 0xb0 },
     608      { 0x1e81, 0x77, 0xb0 },
     609      { 0x1e82, 0x57, 0xb3 },
     610      { 0x1e83, 0x77, 0xb3 },
     611      { 0x1e88, 0x57, 0xb4 },
     612      { 0x1e89, 0x77, 0xb4 },
     613      { 0x1e92, 0x5a, 0xb4 },
     614      { 0x1e93, 0x7a, 0xb4 },
     615    };
     616  
     617  
     618  /* Next, define the other direction.  */
     619  #define MIN_NEEDED_INPUT	TO_LOOP_MIN_NEEDED_FROM
     620  #define MAX_NEEDED_INPUT	TO_LOOP_MAX_NEEDED_FROM
     621  #define MIN_NEEDED_OUTPUT	TO_LOOP_MIN_NEEDED_TO
     622  #define MAX_NEEDED_OUTPUT	TO_LOOP_MAX_NEEDED_TO
     623  #define LOOPFCT			TO_LOOP
     624  #define BODY \
     625    {									      \
     626      uint32_t ch = get32 (inptr);					      \
     627  									      \
     628      if (ch == 0x00 || (ch >= 0x18 && ch < 0x80) || ch == 0xa0)		      \
     629        {									      \
     630  	*outptr++ = ch;							      \
     631  	inptr += 4;							      \
     632        }									      \
     633      else								      \
     634        {									      \
     635  	unsigned char res;						      \
     636  									      \
     637  	if (ch <= 0x0010)						      \
     638  	  res = from_ucs4[ch - 0x0001 + FROM_IDX_00];			      \
     639  	else if (ch >= 0x00c0 && ch <= 0x0129)				      \
     640  	  res = from_ucs4[ch - 0x00c0 + FROM_IDX_01];			      \
     641  	else if (ch >= 0x0168 && ch <= 0x0169)				      \
     642  	  res = from_ucs4[ch - 0x0168 + FROM_IDX_02];			      \
     643  	else if (ch >= 0x01a0 && ch <= 0x01b0)				      \
     644  	  res = from_ucs4[ch - 0x01a0 + FROM_IDX_03];			      \
     645  	else if (ch >= 0x0300 && ch <= 0x0323)				      \
     646  	  res = from_ucs4[ch - 0x0300 + FROM_IDX_04];			      \
     647  	else if (ch >= 0x1ea0 && ch <= 0x1ef9)				      \
     648  	  res = from_ucs4[ch - 0x1ea0 + FROM_IDX_05];			      \
     649  	else								      \
     650  	  {								      \
     651  	    UNICODE_TAG_HANDLER (ch, 4);				      \
     652  	    res = 0;							      \
     653  	  }								      \
     654  									      \
     655  	if (__glibc_likely (res != 0))					      \
     656  	  {								      \
     657  	    *outptr++ = res;						      \
     658  	    inptr += 4;							      \
     659  	  }								      \
     660  	else								      \
     661  	  {								      \
     662  	    /* Try canonical decomposition.  */				      \
     663  	    unsigned int i1;						      \
     664  	    unsigned int i2;						      \
     665  									      \
     666  	    i1 = 0;							      \
     667  	    i2 = sizeof (decomp_table) / sizeof (decomp_table[0]) - 1;	      \
     668  	    if (ch >= decomp_table[i1].composed				      \
     669  		&& ch <= decomp_table[i2].composed)			      \
     670  	      {								      \
     671  		unsigned int i;						      \
     672  									      \
     673  		for (;;)						      \
     674  		  {							      \
     675  		    i = (i1 + i2) >> 1;					      \
     676  		    if (ch == decomp_table[i].composed)			      \
     677  		      break;						      \
     678  		    if (ch < decomp_table[i].composed)			      \
     679  		      {							      \
     680  			if (i1 == i)					      \
     681  			  goto failed;					      \
     682  			i2 = i;						      \
     683  		      }							      \
     684  		    else						      \
     685  		      {							      \
     686  			if (i1 != i)					      \
     687  			  i1 = i;					      \
     688  			else						      \
     689  			  {						      \
     690  			    i = i2;					      \
     691  			    if (ch == decomp_table[i].composed)		      \
     692  			      break;					      \
     693  			    goto failed;				      \
     694  			  }						      \
     695  		      }							      \
     696  		  }							      \
     697  									      \
     698  		/* See whether we have room for two bytes.  */		      \
     699  		if (__glibc_unlikely (outptr + 1 >= outend))		      \
     700  		  {							      \
     701  		    result = __GCONV_FULL_OUTPUT;			      \
     702  		    break;						      \
     703  		  }							      \
     704  									      \
     705  		/* Found a canonical decomposition.  */			      \
     706  		*outptr++ = decomp_table[i].base;			      \
     707  		*outptr++ = decomp_table[i].comb1;			      \
     708  		inptr += 4;						      \
     709  		continue;						      \
     710  	      }								      \
     711  									      \
     712  	  failed:							      \
     713  	    /* This is an illegal character.  */			      \
     714  	    STANDARD_TO_LOOP_ERR_HANDLER (4);				      \
     715  	  }								      \
     716        }									      \
     717    }
     718  #define LOOP_NEED_FLAGS
     719  #define EXTRA_LOOP_DECLS	, int *statep
     720  #include <iconv/loop.c>
     721  
     722  
     723  /* Now define the toplevel functions.  */
     724  #include <iconv/skeleton.c>