Blame iconv/gconv_simple.c

Packit 6c4009
/* Simple transformations functions.
Packit 6c4009
   Copyright (C) 1997-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <byteswap.h>
Packit 6c4009
#include <dlfcn.h>
Packit 6c4009
#include <endian.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <gconv.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <wchar.h>
Packit 6c4009
#include <sys/param.h>
Packit 6c4009
#include <gconv_int.h>
Packit 6c4009
Packit 6c4009
#define BUILTIN_ALIAS(s1, s2) /* nothing */
Packit 6c4009
#define BUILTIN_TRANSFORMATION(From, To, Cost, Name, Fct, BtowcFct, \
Packit 6c4009
			       MinF, MaxF, MinT, MaxT) \
Packit 6c4009
  extern int Fct (struct __gconv_step *, struct __gconv_step_data *,	      \
Packit 6c4009
		  const unsigned char **, const unsigned char *,	      \
Packit 6c4009
		  unsigned char **, size_t *, int, int);
Packit 6c4009
#include "gconv_builtin.h"
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifndef EILSEQ
Packit 6c4009
# define EILSEQ EINVAL
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Specialized conversion function for a single byte to INTERNAL, recognizing
Packit 6c4009
   only ASCII characters.  */
Packit 6c4009
wint_t
Packit 6c4009
__gconv_btwoc_ascii (struct __gconv_step *step, unsigned char c)
Packit 6c4009
{
Packit 6c4009
  if (c < 0x80)
Packit 6c4009
    return c;
Packit 6c4009
  else
Packit 6c4009
    return WEOF;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Transform from the internal, UCS4-like format, to UCS4.  The
Packit 6c4009
   difference between the internal ucs4 format and the real UCS4
Packit 6c4009
   format is, if any, the endianess.  The Unicode/ISO 10646 says that
Packit 6c4009
   unless some higher protocol specifies it differently, the byte
Packit 6c4009
   order is big endian.*/
Packit 6c4009
#define DEFINE_INIT		0
Packit 6c4009
#define DEFINE_FINI		0
Packit 6c4009
#define MIN_NEEDED_FROM		4
Packit 6c4009
#define MIN_NEEDED_TO		4
Packit 6c4009
#define FROM_DIRECTION		1
Packit 6c4009
#define FROM_LOOP		internal_ucs4_loop
Packit 6c4009
#define TO_LOOP			internal_ucs4_loop /* This is not used.  */
Packit 6c4009
#define FUNCTION_NAME		__gconv_transform_internal_ucs4
Packit 6c4009
#define ONE_DIRECTION		0
Packit 6c4009
Packit 6c4009
Packit 6c4009
static inline int
Packit 6c4009
__attribute ((always_inline))
Packit 6c4009
internal_ucs4_loop (struct __gconv_step *step,
Packit 6c4009
		    struct __gconv_step_data *step_data,
Packit 6c4009
		    const unsigned char **inptrp, const unsigned char *inend,
Packit 6c4009
		    unsigned char **outptrp, unsigned char *outend,
Packit 6c4009
		    size_t *irreversible)
Packit 6c4009
{
Packit 6c4009
  const unsigned char *inptr = *inptrp;
Packit 6c4009
  unsigned char *outptr = *outptrp;
Packit 6c4009
  size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
Packit 6c4009
  int result;
Packit 6c4009
Packit 6c4009
#if __BYTE_ORDER == __LITTLE_ENDIAN
Packit 6c4009
  /* Sigh, we have to do some real work.  */
Packit 6c4009
  size_t cnt;
Packit 6c4009
  uint32_t *outptr32 = (uint32_t *) outptr;
Packit 6c4009
Packit 6c4009
  for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
Packit 6c4009
    *outptr32++ = bswap_32 (*(const uint32_t *) inptr);
Packit 6c4009
Packit 6c4009
  *inptrp = inptr;
Packit 6c4009
  *outptrp = (unsigned char *) outptr32;
Packit 6c4009
#elif __BYTE_ORDER == __BIG_ENDIAN
Packit 6c4009
  /* Simply copy the data.  */
Packit 6c4009
  *inptrp = inptr + n_convert * 4;
Packit 6c4009
  *outptrp = __mempcpy (outptr, inptr, n_convert * 4);
Packit 6c4009
#else
Packit 6c4009
# error "This endianess is not supported."
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  /* Determine the status.  */
Packit 6c4009
  if (*inptrp == inend)
Packit 6c4009
    result = __GCONV_EMPTY_INPUT;
Packit 6c4009
  else if (*outptrp + 4 > outend)
Packit 6c4009
    result = __GCONV_FULL_OUTPUT;
Packit 6c4009
  else
Packit 6c4009
    result = __GCONV_INCOMPLETE_INPUT;
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#if !_STRING_ARCH_unaligned
Packit 6c4009
static inline int
Packit 6c4009
__attribute ((always_inline))
Packit 6c4009
internal_ucs4_loop_unaligned (struct __gconv_step *step,
Packit 6c4009
			      struct __gconv_step_data *step_data,
Packit 6c4009
			      const unsigned char **inptrp,
Packit 6c4009
			      const unsigned char *inend,
Packit 6c4009
			      unsigned char **outptrp, unsigned char *outend,
Packit 6c4009
			      size_t *irreversible)
Packit 6c4009
{
Packit 6c4009
  const unsigned char *inptr = *inptrp;
Packit 6c4009
  unsigned char *outptr = *outptrp;
Packit 6c4009
  size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
Packit 6c4009
  int result;
Packit 6c4009
Packit 6c4009
# if __BYTE_ORDER == __LITTLE_ENDIAN
Packit 6c4009
  /* Sigh, we have to do some real work.  */
Packit 6c4009
  size_t cnt;
Packit 6c4009
Packit 6c4009
  for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4, outptr += 4)
Packit 6c4009
    {
Packit 6c4009
      outptr[0] = inptr[3];
Packit 6c4009
      outptr[1] = inptr[2];
Packit 6c4009
      outptr[2] = inptr[1];
Packit 6c4009
      outptr[3] = inptr[0];
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  *inptrp = inptr;
Packit 6c4009
  *outptrp = outptr;
Packit 6c4009
# elif __BYTE_ORDER == __BIG_ENDIAN
Packit 6c4009
  /* Simply copy the data.  */
Packit 6c4009
  *inptrp = inptr + n_convert * 4;
Packit 6c4009
  *outptrp = __mempcpy (outptr, inptr, n_convert * 4);
Packit 6c4009
# else
Packit 6c4009
#  error "This endianess is not supported."
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
  /* Determine the status.  */
Packit 6c4009
  if (*inptrp == inend)
Packit 6c4009
    result = __GCONV_EMPTY_INPUT;
Packit 6c4009
  else if (*outptrp + 4 > outend)
Packit 6c4009
    result = __GCONV_FULL_OUTPUT;
Packit 6c4009
  else
Packit 6c4009
    result = __GCONV_INCOMPLETE_INPUT;
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
static inline int
Packit 6c4009
__attribute ((always_inline))
Packit 6c4009
internal_ucs4_loop_single (struct __gconv_step *step,
Packit 6c4009
			   struct __gconv_step_data *step_data,
Packit 6c4009
			   const unsigned char **inptrp,
Packit 6c4009
			   const unsigned char *inend,
Packit 6c4009
			   unsigned char **outptrp, unsigned char *outend,
Packit 6c4009
			   size_t *irreversible)
Packit 6c4009
{
Packit 6c4009
  mbstate_t *state = step_data->__statep;
Packit 6c4009
  size_t cnt = state->__count & 7;
Packit 6c4009
Packit 6c4009
  while (*inptrp < inend && cnt < 4)
Packit 6c4009
    state->__value.__wchb[cnt++] = *(*inptrp)++;
Packit 6c4009
Packit 6c4009
  if (__glibc_unlikely (cnt < 4))
Packit 6c4009
    {
Packit 6c4009
      /* Still not enough bytes.  Store the ones in the input buffer.  */
Packit 6c4009
      state->__count &= ~7;
Packit 6c4009
      state->__count |= cnt;
Packit 6c4009
Packit 6c4009
      return __GCONV_INCOMPLETE_INPUT;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
#if __BYTE_ORDER == __LITTLE_ENDIAN
Packit 6c4009
  (*outptrp)[0] = state->__value.__wchb[3];
Packit 6c4009
  (*outptrp)[1] = state->__value.__wchb[2];
Packit 6c4009
  (*outptrp)[2] = state->__value.__wchb[1];
Packit 6c4009
  (*outptrp)[3] = state->__value.__wchb[0];
Packit 6c4009
Packit 6c4009
#elif __BYTE_ORDER == __BIG_ENDIAN
Packit 6c4009
  /* XXX unaligned */
Packit 6c4009
  (*outptrp)[0] = state->__value.__wchb[0];
Packit 6c4009
  (*outptrp)[1] = state->__value.__wchb[1];
Packit 6c4009
  (*outptrp)[2] = state->__value.__wchb[2];
Packit 6c4009
  (*outptrp)[3] = state->__value.__wchb[3];
Packit 6c4009
#else
Packit 6c4009
# error "This endianess is not supported."
Packit 6c4009
#endif
Packit 6c4009
  *outptrp += 4;
Packit 6c4009
Packit 6c4009
  /* Clear the state buffer.  */
Packit 6c4009
  state->__count &= ~7;
Packit 6c4009
Packit 6c4009
  return __GCONV_OK;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#include <iconv/skeleton.c>
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Transform from UCS4 to the internal, UCS4-like format.  Unlike
Packit 6c4009
   for the other direction we have to check for correct values here.  */
Packit 6c4009
#define DEFINE_INIT		0
Packit 6c4009
#define DEFINE_FINI		0
Packit 6c4009
#define MIN_NEEDED_FROM		4
Packit 6c4009
#define MIN_NEEDED_TO		4
Packit 6c4009
#define FROM_DIRECTION		1
Packit 6c4009
#define FROM_LOOP		ucs4_internal_loop
Packit 6c4009
#define TO_LOOP			ucs4_internal_loop /* This is not used.  */
Packit 6c4009
#define FUNCTION_NAME		__gconv_transform_ucs4_internal
Packit 6c4009
#define ONE_DIRECTION		0
Packit 6c4009
Packit 6c4009
Packit 6c4009
static inline int
Packit 6c4009
__attribute ((always_inline))
Packit 6c4009
ucs4_internal_loop (struct __gconv_step *step,
Packit 6c4009
		    struct __gconv_step_data *step_data,
Packit 6c4009
		    const unsigned char **inptrp, const unsigned char *inend,
Packit 6c4009
		    unsigned char **outptrp, unsigned char *outend,
Packit 6c4009
		    size_t *irreversible)
Packit 6c4009
{
Packit 6c4009
  int flags = step_data->__flags;
Packit 6c4009
  const unsigned char *inptr = *inptrp;
Packit 6c4009
  unsigned char *outptr = *outptrp;
Packit 6c4009
  size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
Packit 6c4009
  int result;
Packit 6c4009
  size_t cnt;
Packit 6c4009
Packit 6c4009
  for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
Packit 6c4009
    {
Packit 6c4009
      uint32_t inval;
Packit 6c4009
Packit 6c4009
#if __BYTE_ORDER == __LITTLE_ENDIAN
Packit 6c4009
      inval = bswap_32 (*(const uint32_t *) inptr);
Packit 6c4009
#else
Packit 6c4009
      inval = *(const uint32_t *) inptr;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
      if (__glibc_unlikely (inval > 0x7fffffff))
Packit 6c4009
	{
Packit 6c4009
	  /* The value is too large.  We don't try transliteration here since
Packit 6c4009
	     this is not an error because of the lack of possibilities to
Packit 6c4009
	     represent the result.  This is a genuine bug in the input since
Packit 6c4009
	     UCS4 does not allow such values.  */
Packit 6c4009
	  if (irreversible == NULL)
Packit 6c4009
	    /* We are transliterating, don't try to correct anything.  */
Packit 6c4009
	    return __GCONV_ILLEGAL_INPUT;
Packit 6c4009
Packit 6c4009
	  if (flags & __GCONV_IGNORE_ERRORS)
Packit 6c4009
	    {
Packit 6c4009
	      /* Just ignore this character.  */
Packit 6c4009
	      ++*irreversible;
Packit 6c4009
	      continue;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  *inptrp = inptr;
Packit 6c4009
	  *outptrp = outptr;
Packit 6c4009
	  return __GCONV_ILLEGAL_INPUT;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      *((uint32_t *) outptr) = inval;
Packit 6c4009
      outptr += sizeof (uint32_t);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  *inptrp = inptr;
Packit 6c4009
  *outptrp = outptr;
Packit 6c4009
Packit 6c4009
  /* Determine the status.  */
Packit 6c4009
  if (*inptrp == inend)
Packit 6c4009
    result = __GCONV_EMPTY_INPUT;
Packit 6c4009
  else if (*outptrp + 4 > outend)
Packit 6c4009
    result = __GCONV_FULL_OUTPUT;
Packit 6c4009
  else
Packit 6c4009
    result = __GCONV_INCOMPLETE_INPUT;
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#if !_STRING_ARCH_unaligned
Packit 6c4009
static inline int
Packit 6c4009
__attribute ((always_inline))
Packit 6c4009
ucs4_internal_loop_unaligned (struct __gconv_step *step,
Packit 6c4009
			      struct __gconv_step_data *step_data,
Packit 6c4009
			      const unsigned char **inptrp,
Packit 6c4009
			      const unsigned char *inend,
Packit 6c4009
			      unsigned char **outptrp, unsigned char *outend,
Packit 6c4009
			      size_t *irreversible)
Packit 6c4009
{
Packit 6c4009
  int flags = step_data->__flags;
Packit 6c4009
  const unsigned char *inptr = *inptrp;
Packit 6c4009
  unsigned char *outptr = *outptrp;
Packit 6c4009
  size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
Packit 6c4009
  int result;
Packit 6c4009
  size_t cnt;
Packit 6c4009
Packit 6c4009
  for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
Packit 6c4009
    {
Packit 6c4009
      if (__glibc_unlikely (inptr[0] > 0x80))
Packit 6c4009
	{
Packit 6c4009
	  /* The value is too large.  We don't try transliteration here since
Packit 6c4009
	     this is not an error because of the lack of possibilities to
Packit 6c4009
	     represent the result.  This is a genuine bug in the input since
Packit 6c4009
	     UCS4 does not allow such values.  */
Packit 6c4009
	  if (irreversible == NULL)
Packit 6c4009
	    /* We are transliterating, don't try to correct anything.  */
Packit 6c4009
	    return __GCONV_ILLEGAL_INPUT;
Packit 6c4009
Packit 6c4009
	  if (flags & __GCONV_IGNORE_ERRORS)
Packit 6c4009
	    {
Packit 6c4009
	      /* Just ignore this character.  */
Packit 6c4009
	      ++*irreversible;
Packit 6c4009
	      continue;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  *inptrp = inptr;
Packit 6c4009
	  *outptrp = outptr;
Packit 6c4009
	  return __GCONV_ILLEGAL_INPUT;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
# if __BYTE_ORDER == __LITTLE_ENDIAN
Packit 6c4009
      outptr[3] = inptr[0];
Packit 6c4009
      outptr[2] = inptr[1];
Packit 6c4009
      outptr[1] = inptr[2];
Packit 6c4009
      outptr[0] = inptr[3];
Packit 6c4009
# else
Packit 6c4009
      outptr[0] = inptr[0];
Packit 6c4009
      outptr[1] = inptr[1];
Packit 6c4009
      outptr[2] = inptr[2];
Packit 6c4009
      outptr[3] = inptr[3];
Packit 6c4009
# endif
Packit 6c4009
      outptr += 4;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  *inptrp = inptr;
Packit 6c4009
  *outptrp = outptr;
Packit 6c4009
Packit 6c4009
  /* Determine the status.  */
Packit 6c4009
  if (*inptrp == inend)
Packit 6c4009
    result = __GCONV_EMPTY_INPUT;
Packit 6c4009
  else if (*outptrp + 4 > outend)
Packit 6c4009
    result = __GCONV_FULL_OUTPUT;
Packit 6c4009
  else
Packit 6c4009
    result = __GCONV_INCOMPLETE_INPUT;
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
static inline int
Packit 6c4009
__attribute ((always_inline))
Packit 6c4009
ucs4_internal_loop_single (struct __gconv_step *step,
Packit 6c4009
			   struct __gconv_step_data *step_data,
Packit 6c4009
			   const unsigned char **inptrp,
Packit 6c4009
			   const unsigned char *inend,
Packit 6c4009
			   unsigned char **outptrp, unsigned char *outend,
Packit 6c4009
			   size_t *irreversible)
Packit 6c4009
{
Packit 6c4009
  mbstate_t *state = step_data->__statep;
Packit 6c4009
  int flags = step_data->__flags;
Packit 6c4009
  size_t cnt = state->__count & 7;
Packit 6c4009
Packit 6c4009
  while (*inptrp < inend && cnt < 4)
Packit 6c4009
    state->__value.__wchb[cnt++] = *(*inptrp)++;
Packit 6c4009
Packit 6c4009
  if (__glibc_unlikely (cnt < 4))
Packit 6c4009
    {
Packit 6c4009
      /* Still not enough bytes.  Store the ones in the input buffer.  */
Packit 6c4009
      state->__count &= ~7;
Packit 6c4009
      state->__count |= cnt;
Packit 6c4009
Packit 6c4009
      return __GCONV_INCOMPLETE_INPUT;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (__builtin_expect (((unsigned char *) state->__value.__wchb)[0] > 0x80,
Packit 6c4009
			0))
Packit 6c4009
    {
Packit 6c4009
      /* The value is too large.  We don't try transliteration here since
Packit 6c4009
	 this is not an error because of the lack of possibilities to
Packit 6c4009
	 represent the result.  This is a genuine bug in the input since
Packit 6c4009
	 UCS4 does not allow such values.  */
Packit 6c4009
      if (!(flags & __GCONV_IGNORE_ERRORS))
Packit 6c4009
	{
Packit 6c4009
	  *inptrp -= cnt - (state->__count & 7);
Packit 6c4009
	  return __GCONV_ILLEGAL_INPUT;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
#if __BYTE_ORDER == __LITTLE_ENDIAN
Packit 6c4009
      (*outptrp)[0] = state->__value.__wchb[3];
Packit 6c4009
      (*outptrp)[1] = state->__value.__wchb[2];
Packit 6c4009
      (*outptrp)[2] = state->__value.__wchb[1];
Packit 6c4009
      (*outptrp)[3] = state->__value.__wchb[0];
Packit 6c4009
#elif __BYTE_ORDER == __BIG_ENDIAN
Packit 6c4009
      (*outptrp)[0] = state->__value.__wchb[0];
Packit 6c4009
      (*outptrp)[1] = state->__value.__wchb[1];
Packit 6c4009
      (*outptrp)[2] = state->__value.__wchb[2];
Packit 6c4009
      (*outptrp)[3] = state->__value.__wchb[3];
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
      *outptrp += 4;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Clear the state buffer.  */
Packit 6c4009
  state->__count &= ~7;
Packit 6c4009
Packit 6c4009
  return __GCONV_OK;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#include <iconv/skeleton.c>
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Similarly for the little endian form.  */
Packit 6c4009
#define DEFINE_INIT		0
Packit 6c4009
#define DEFINE_FINI		0
Packit 6c4009
#define MIN_NEEDED_FROM		4
Packit 6c4009
#define MIN_NEEDED_TO		4
Packit 6c4009
#define FROM_DIRECTION		1
Packit 6c4009
#define FROM_LOOP		internal_ucs4le_loop
Packit 6c4009
#define TO_LOOP			internal_ucs4le_loop /* This is not used.  */
Packit 6c4009
#define FUNCTION_NAME		__gconv_transform_internal_ucs4le
Packit 6c4009
#define ONE_DIRECTION		0
Packit 6c4009
Packit 6c4009
Packit 6c4009
static inline int
Packit 6c4009
__attribute ((always_inline))
Packit 6c4009
internal_ucs4le_loop (struct __gconv_step *step,
Packit 6c4009
		      struct __gconv_step_data *step_data,
Packit 6c4009
		      const unsigned char **inptrp, const unsigned char *inend,
Packit 6c4009
		      unsigned char **outptrp, unsigned char *outend,
Packit 6c4009
		      size_t *irreversible)
Packit 6c4009
{
Packit 6c4009
  const unsigned char *inptr = *inptrp;
Packit 6c4009
  unsigned char *outptr = *outptrp;
Packit 6c4009
  size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
Packit 6c4009
  int result;
Packit 6c4009
Packit 6c4009
#if __BYTE_ORDER == __BIG_ENDIAN
Packit 6c4009
  /* Sigh, we have to do some real work.  */
Packit 6c4009
  size_t cnt;
Packit 6c4009
  uint32_t *outptr32 = (uint32_t *) outptr;
Packit 6c4009
Packit 6c4009
  for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
Packit 6c4009
    *outptr32++ = bswap_32 (*(const uint32_t *) inptr);
Packit 6c4009
  outptr = (unsigned char *) outptr32;
Packit 6c4009
Packit 6c4009
  *inptrp = inptr;
Packit 6c4009
  *outptrp = outptr;
Packit 6c4009
#elif __BYTE_ORDER == __LITTLE_ENDIAN
Packit 6c4009
  /* Simply copy the data.  */
Packit 6c4009
  *inptrp = inptr + n_convert * 4;
Packit 6c4009
  *outptrp = __mempcpy (outptr, inptr, n_convert * 4);
Packit 6c4009
#else
Packit 6c4009
# error "This endianess is not supported."
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  /* Determine the status.  */
Packit 6c4009
  if (*inptrp == inend)
Packit 6c4009
    result = __GCONV_EMPTY_INPUT;
Packit 6c4009
  else if (*outptrp + 4 > outend)
Packit 6c4009
    result = __GCONV_FULL_OUTPUT;
Packit 6c4009
  else
Packit 6c4009
    result = __GCONV_INCOMPLETE_INPUT;
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#if !_STRING_ARCH_unaligned
Packit 6c4009
static inline int
Packit 6c4009
__attribute ((always_inline))
Packit 6c4009
internal_ucs4le_loop_unaligned (struct __gconv_step *step,
Packit 6c4009
				struct __gconv_step_data *step_data,
Packit 6c4009
				const unsigned char **inptrp,
Packit 6c4009
				const unsigned char *inend,
Packit 6c4009
				unsigned char **outptrp, unsigned char *outend,
Packit 6c4009
				size_t *irreversible)
Packit 6c4009
{
Packit 6c4009
  const unsigned char *inptr = *inptrp;
Packit 6c4009
  unsigned char *outptr = *outptrp;
Packit 6c4009
  size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
Packit 6c4009
  int result;
Packit 6c4009
Packit 6c4009
# if __BYTE_ORDER == __BIG_ENDIAN
Packit 6c4009
  /* Sigh, we have to do some real work.  */
Packit 6c4009
  size_t cnt;
Packit 6c4009
Packit 6c4009
  for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4, outptr += 4)
Packit 6c4009
    {
Packit 6c4009
      outptr[0] = inptr[3];
Packit 6c4009
      outptr[1] = inptr[2];
Packit 6c4009
      outptr[2] = inptr[1];
Packit 6c4009
      outptr[3] = inptr[0];
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  *inptrp = inptr;
Packit 6c4009
  *outptrp = outptr;
Packit 6c4009
# elif __BYTE_ORDER == __LITTLE_ENDIAN
Packit 6c4009
  /* Simply copy the data.  */
Packit 6c4009
  *inptrp = inptr + n_convert * 4;
Packit 6c4009
  *outptrp = __mempcpy (outptr, inptr, n_convert * 4);
Packit 6c4009
# else
Packit 6c4009
#  error "This endianess is not supported."
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
  /* Determine the status.  */
Packit 6c4009
  if (*inptrp == inend)
Packit 6c4009
    result = __GCONV_EMPTY_INPUT;
Packit 6c4009
  else if (*inptrp + 4 > inend)
Packit 6c4009
    result = __GCONV_INCOMPLETE_INPUT;
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      assert (*outptrp + 4 > outend);
Packit 6c4009
      result = __GCONV_FULL_OUTPUT;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
static inline int
Packit 6c4009
__attribute ((always_inline))
Packit 6c4009
internal_ucs4le_loop_single (struct __gconv_step *step,
Packit 6c4009
			     struct __gconv_step_data *step_data,
Packit 6c4009
			     const unsigned char **inptrp,
Packit 6c4009
			     const unsigned char *inend,
Packit 6c4009
			     unsigned char **outptrp, unsigned char *outend,
Packit 6c4009
			     size_t *irreversible)
Packit 6c4009
{
Packit 6c4009
  mbstate_t *state = step_data->__statep;
Packit 6c4009
  size_t cnt = state->__count & 7;
Packit 6c4009
Packit 6c4009
  while (*inptrp < inend && cnt < 4)
Packit 6c4009
    state->__value.__wchb[cnt++] = *(*inptrp)++;
Packit 6c4009
Packit 6c4009
  if (__glibc_unlikely (cnt < 4))
Packit 6c4009
    {
Packit 6c4009
      /* Still not enough bytes.  Store the ones in the input buffer.  */
Packit 6c4009
      state->__count &= ~7;
Packit 6c4009
      state->__count |= cnt;
Packit 6c4009
Packit 6c4009
      return __GCONV_INCOMPLETE_INPUT;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
#if __BYTE_ORDER == __BIG_ENDIAN
Packit 6c4009
  (*outptrp)[0] = state->__value.__wchb[3];
Packit 6c4009
  (*outptrp)[1] = state->__value.__wchb[2];
Packit 6c4009
  (*outptrp)[2] = state->__value.__wchb[1];
Packit 6c4009
  (*outptrp)[3] = state->__value.__wchb[0];
Packit 6c4009
Packit 6c4009
#else
Packit 6c4009
  /* XXX unaligned */
Packit 6c4009
  (*outptrp)[0] = state->__value.__wchb[0];
Packit 6c4009
  (*outptrp)[1] = state->__value.__wchb[1];
Packit 6c4009
  (*outptrp)[2] = state->__value.__wchb[2];
Packit 6c4009
  (*outptrp)[3] = state->__value.__wchb[3];
Packit 6c4009
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  *outptrp += 4;
Packit 6c4009
Packit 6c4009
  /* Clear the state buffer.  */
Packit 6c4009
  state->__count &= ~7;
Packit 6c4009
Packit 6c4009
  return __GCONV_OK;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#include <iconv/skeleton.c>
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* And finally from UCS4-LE to the internal encoding.  */
Packit 6c4009
#define DEFINE_INIT		0
Packit 6c4009
#define DEFINE_FINI		0
Packit 6c4009
#define MIN_NEEDED_FROM		4
Packit 6c4009
#define MIN_NEEDED_TO		4
Packit 6c4009
#define FROM_DIRECTION		1
Packit 6c4009
#define FROM_LOOP		ucs4le_internal_loop
Packit 6c4009
#define TO_LOOP			ucs4le_internal_loop /* This is not used.  */
Packit 6c4009
#define FUNCTION_NAME		__gconv_transform_ucs4le_internal
Packit 6c4009
#define ONE_DIRECTION		0
Packit 6c4009
Packit 6c4009
Packit 6c4009
static inline int
Packit 6c4009
__attribute ((always_inline))
Packit 6c4009
ucs4le_internal_loop (struct __gconv_step *step,
Packit 6c4009
		      struct __gconv_step_data *step_data,
Packit 6c4009
		      const unsigned char **inptrp, const unsigned char *inend,
Packit 6c4009
		      unsigned char **outptrp, unsigned char *outend,
Packit 6c4009
		      size_t *irreversible)
Packit 6c4009
{
Packit 6c4009
  int flags = step_data->__flags;
Packit 6c4009
  const unsigned char *inptr = *inptrp;
Packit 6c4009
  unsigned char *outptr = *outptrp;
Packit 6c4009
  size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
Packit 6c4009
  int result;
Packit 6c4009
  size_t cnt;
Packit 6c4009
Packit 6c4009
  for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
Packit 6c4009
    {
Packit 6c4009
      uint32_t inval;
Packit 6c4009
Packit 6c4009
#if __BYTE_ORDER == __BIG_ENDIAN
Packit 6c4009
      inval = bswap_32 (*(const uint32_t *) inptr);
Packit 6c4009
#else
Packit 6c4009
      inval = *(const uint32_t *) inptr;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
      if (__glibc_unlikely (inval > 0x7fffffff))
Packit 6c4009
	{
Packit 6c4009
	  /* The value is too large.  We don't try transliteration here since
Packit 6c4009
	     this is not an error because of the lack of possibilities to
Packit 6c4009
	     represent the result.  This is a genuine bug in the input since
Packit 6c4009
	     UCS4 does not allow such values.  */
Packit 6c4009
	  if (irreversible == NULL)
Packit 6c4009
	    /* We are transliterating, don't try to correct anything.  */
Packit 6c4009
	    return __GCONV_ILLEGAL_INPUT;
Packit 6c4009
Packit 6c4009
	  if (flags & __GCONV_IGNORE_ERRORS)
Packit 6c4009
	    {
Packit 6c4009
	      /* Just ignore this character.  */
Packit 6c4009
	      ++*irreversible;
Packit 6c4009
	      continue;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  *inptrp = inptr;
Packit 6c4009
	  *outptrp = outptr;
Packit 6c4009
	  return __GCONV_ILLEGAL_INPUT;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      *((uint32_t *) outptr) = inval;
Packit 6c4009
      outptr += sizeof (uint32_t);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  *inptrp = inptr;
Packit 6c4009
  *outptrp = outptr;
Packit 6c4009
Packit 6c4009
  /* Determine the status.  */
Packit 6c4009
  if (*inptrp == inend)
Packit 6c4009
    result = __GCONV_EMPTY_INPUT;
Packit 6c4009
  else if (*inptrp + 4 > inend)
Packit 6c4009
    result = __GCONV_INCOMPLETE_INPUT;
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      assert (*outptrp + 4 > outend);
Packit 6c4009
      result = __GCONV_FULL_OUTPUT;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#if !_STRING_ARCH_unaligned
Packit 6c4009
static inline int
Packit 6c4009
__attribute ((always_inline))
Packit 6c4009
ucs4le_internal_loop_unaligned (struct __gconv_step *step,
Packit 6c4009
				struct __gconv_step_data *step_data,
Packit 6c4009
				const unsigned char **inptrp,
Packit 6c4009
				const unsigned char *inend,
Packit 6c4009
				unsigned char **outptrp, unsigned char *outend,
Packit 6c4009
				size_t *irreversible)
Packit 6c4009
{
Packit 6c4009
  int flags = step_data->__flags;
Packit 6c4009
  const unsigned char *inptr = *inptrp;
Packit 6c4009
  unsigned char *outptr = *outptrp;
Packit 6c4009
  size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
Packit 6c4009
  int result;
Packit 6c4009
  size_t cnt;
Packit 6c4009
Packit 6c4009
  for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
Packit 6c4009
    {
Packit 6c4009
      if (__glibc_unlikely (inptr[3] > 0x80))
Packit 6c4009
	{
Packit 6c4009
	  /* The value is too large.  We don't try transliteration here since
Packit 6c4009
	     this is not an error because of the lack of possibilities to
Packit 6c4009
	     represent the result.  This is a genuine bug in the input since
Packit 6c4009
	     UCS4 does not allow such values.  */
Packit 6c4009
	  if (irreversible == NULL)
Packit 6c4009
	    /* We are transliterating, don't try to correct anything.  */
Packit 6c4009
	    return __GCONV_ILLEGAL_INPUT;
Packit 6c4009
Packit 6c4009
	  if (flags & __GCONV_IGNORE_ERRORS)
Packit 6c4009
	    {
Packit 6c4009
	      /* Just ignore this character.  */
Packit 6c4009
	      ++*irreversible;
Packit 6c4009
	      continue;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  *inptrp = inptr;
Packit 6c4009
	  *outptrp = outptr;
Packit 6c4009
	  return __GCONV_ILLEGAL_INPUT;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
# if __BYTE_ORDER == __BIG_ENDIAN
Packit 6c4009
      outptr[3] = inptr[0];
Packit 6c4009
      outptr[2] = inptr[1];
Packit 6c4009
      outptr[1] = inptr[2];
Packit 6c4009
      outptr[0] = inptr[3];
Packit 6c4009
# else
Packit 6c4009
      outptr[0] = inptr[0];
Packit 6c4009
      outptr[1] = inptr[1];
Packit 6c4009
      outptr[2] = inptr[2];
Packit 6c4009
      outptr[3] = inptr[3];
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
      outptr += 4;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  *inptrp = inptr;
Packit 6c4009
  *outptrp = outptr;
Packit 6c4009
Packit 6c4009
  /* Determine the status.  */
Packit 6c4009
  if (*inptrp == inend)
Packit 6c4009
    result = __GCONV_EMPTY_INPUT;
Packit 6c4009
  else if (*inptrp + 4 > inend)
Packit 6c4009
    result = __GCONV_INCOMPLETE_INPUT;
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      assert (*outptrp + 4 > outend);
Packit 6c4009
      result = __GCONV_FULL_OUTPUT;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
static inline int
Packit 6c4009
__attribute ((always_inline))
Packit 6c4009
ucs4le_internal_loop_single (struct __gconv_step *step,
Packit 6c4009
			     struct __gconv_step_data *step_data,
Packit 6c4009
			     const unsigned char **inptrp,
Packit 6c4009
			     const unsigned char *inend,
Packit 6c4009
			     unsigned char **outptrp, unsigned char *outend,
Packit 6c4009
			     size_t *irreversible)
Packit 6c4009
{
Packit 6c4009
  mbstate_t *state = step_data->__statep;
Packit 6c4009
  int flags = step_data->__flags;
Packit 6c4009
  size_t cnt = state->__count & 7;
Packit 6c4009
Packit 6c4009
  while (*inptrp < inend && cnt < 4)
Packit 6c4009
    state->__value.__wchb[cnt++] = *(*inptrp)++;
Packit 6c4009
Packit 6c4009
  if (__glibc_unlikely (cnt < 4))
Packit 6c4009
    {
Packit 6c4009
      /* Still not enough bytes.  Store the ones in the input buffer.  */
Packit 6c4009
      state->__count &= ~7;
Packit 6c4009
      state->__count |= cnt;
Packit 6c4009
Packit 6c4009
      return __GCONV_INCOMPLETE_INPUT;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (__builtin_expect (((unsigned char *) state->__value.__wchb)[3] > 0x80,
Packit 6c4009
			0))
Packit 6c4009
    {
Packit 6c4009
      /* The value is too large.  We don't try transliteration here since
Packit 6c4009
	 this is not an error because of the lack of possibilities to
Packit 6c4009
	 represent the result.  This is a genuine bug in the input since
Packit 6c4009
	 UCS4 does not allow such values.  */
Packit 6c4009
      if (!(flags & __GCONV_IGNORE_ERRORS))
Packit 6c4009
	return __GCONV_ILLEGAL_INPUT;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
#if __BYTE_ORDER == __BIG_ENDIAN
Packit 6c4009
      (*outptrp)[0] = state->__value.__wchb[3];
Packit 6c4009
      (*outptrp)[1] = state->__value.__wchb[2];
Packit 6c4009
      (*outptrp)[2] = state->__value.__wchb[1];
Packit 6c4009
      (*outptrp)[3] = state->__value.__wchb[0];
Packit 6c4009
#else
Packit 6c4009
      (*outptrp)[0] = state->__value.__wchb[0];
Packit 6c4009
      (*outptrp)[1] = state->__value.__wchb[1];
Packit 6c4009
      (*outptrp)[2] = state->__value.__wchb[2];
Packit 6c4009
      (*outptrp)[3] = state->__value.__wchb[3];
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
      *outptrp += 4;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Clear the state buffer.  */
Packit 6c4009
  state->__count &= ~7;
Packit 6c4009
Packit 6c4009
  return __GCONV_OK;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#include <iconv/skeleton.c>
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Convert from ISO 646-IRV to the internal (UCS4-like) format.  */
Packit 6c4009
#define DEFINE_INIT		0
Packit 6c4009
#define DEFINE_FINI		0
Packit 6c4009
#define MIN_NEEDED_FROM		1
Packit 6c4009
#define MIN_NEEDED_TO		4
Packit 6c4009
#define FROM_DIRECTION		1
Packit 6c4009
#define FROM_LOOP		ascii_internal_loop
Packit 6c4009
#define TO_LOOP			ascii_internal_loop /* This is not used.  */
Packit 6c4009
#define FUNCTION_NAME		__gconv_transform_ascii_internal
Packit 6c4009
#define ONE_DIRECTION		1
Packit 6c4009
Packit 6c4009
#define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
Packit 6c4009
#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
Packit 6c4009
#define LOOPFCT			FROM_LOOP
Packit 6c4009
#define BODY \
Packit 6c4009
  {									      \
Packit 6c4009
    if (__glibc_unlikely (*inptr > '\x7f'))				      \
Packit 6c4009
      {									      \
Packit 6c4009
	/* The value is too large.  We don't try transliteration here since   \
Packit 6c4009
	   this is not an error because of the lack of possibilities to	      \
Packit 6c4009
	   represent the result.  This is a genuine bug in the input since    \
Packit 6c4009
	   ASCII does not allow such values.  */			      \
Packit 6c4009
	STANDARD_FROM_LOOP_ERR_HANDLER (1);				      \
Packit 6c4009
      }									      \
Packit 6c4009
    else								      \
Packit 6c4009
      {									      \
Packit 6c4009
	/* It's an one byte sequence.  */				      \
Packit 6c4009
	*((uint32_t *) outptr) = *inptr++;				      \
Packit 6c4009
	outptr += sizeof (uint32_t);					      \
Packit 6c4009
      }									      \
Packit 6c4009
  }
Packit 6c4009
#define LOOP_NEED_FLAGS
Packit 6c4009
#include <iconv/loop.c>
Packit 6c4009
#include <iconv/skeleton.c>
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Convert from the internal (UCS4-like) format to ISO 646-IRV.  */
Packit 6c4009
#define DEFINE_INIT		0
Packit 6c4009
#define DEFINE_FINI		0
Packit 6c4009
#define MIN_NEEDED_FROM		4
Packit 6c4009
#define MIN_NEEDED_TO		1
Packit 6c4009
#define FROM_DIRECTION		1
Packit 6c4009
#define FROM_LOOP		internal_ascii_loop
Packit 6c4009
#define TO_LOOP			internal_ascii_loop /* This is not used.  */
Packit 6c4009
#define FUNCTION_NAME		__gconv_transform_internal_ascii
Packit 6c4009
#define ONE_DIRECTION		1
Packit 6c4009
Packit 6c4009
#define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
Packit 6c4009
#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
Packit 6c4009
#define LOOPFCT			FROM_LOOP
Packit 6c4009
#define BODY \
Packit 6c4009
  {									      \
Packit 6c4009
    if (__glibc_unlikely (*((const uint32_t *) inptr) > 0x7f))		      \
Packit 6c4009
      {									      \
Packit 6c4009
	UNICODE_TAG_HANDLER (*((const uint32_t *) inptr), 4);		      \
Packit 6c4009
	STANDARD_TO_LOOP_ERR_HANDLER (4);				      \
Packit 6c4009
      }									      \
Packit 6c4009
    else								      \
Packit 6c4009
      {									      \
Packit 6c4009
	/* It's an one byte sequence.  */				      \
Packit 6c4009
	*outptr++ = *((const uint32_t *) inptr);			      \
Packit 6c4009
	inptr += sizeof (uint32_t);					      \
Packit 6c4009
      }									      \
Packit 6c4009
  }
Packit 6c4009
#define LOOP_NEED_FLAGS
Packit 6c4009
#include <iconv/loop.c>
Packit 6c4009
#include <iconv/skeleton.c>
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Convert from the internal (UCS4-like) format to UTF-8.  */
Packit 6c4009
#define DEFINE_INIT		0
Packit 6c4009
#define DEFINE_FINI		0
Packit 6c4009
#define MIN_NEEDED_FROM		4
Packit 6c4009
#define MIN_NEEDED_TO		1
Packit 6c4009
#define MAX_NEEDED_TO		6
Packit 6c4009
#define FROM_DIRECTION		1
Packit 6c4009
#define FROM_LOOP		internal_utf8_loop
Packit 6c4009
#define TO_LOOP			internal_utf8_loop /* This is not used.  */
Packit 6c4009
#define FUNCTION_NAME		__gconv_transform_internal_utf8
Packit 6c4009
#define ONE_DIRECTION		1
Packit 6c4009
Packit 6c4009
#define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
Packit 6c4009
#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
Packit 6c4009
#define MAX_NEEDED_OUTPUT	MAX_NEEDED_TO
Packit 6c4009
#define LOOPFCT			FROM_LOOP
Packit 6c4009
#define BODY \
Packit 6c4009
  {									      \
Packit 6c4009
    uint32_t wc = *((const uint32_t *) inptr);				      \
Packit 6c4009
									      \
Packit 6c4009
    if (__glibc_likely (wc < 0x80))					      \
Packit 6c4009
      /* It's an one byte sequence.  */					      \
Packit 6c4009
      *outptr++ = (unsigned char) wc;					      \
Packit 6c4009
    else if (__glibc_likely (wc <= 0x7fffffff				      \
Packit 6c4009
			     && (wc < 0xd800 || wc > 0xdfff)))		      \
Packit 6c4009
      {									      \
Packit 6c4009
	size_t step;							      \
Packit 6c4009
	unsigned char *start;						      \
Packit 6c4009
									      \
Packit 6c4009
	for (step = 2; step < 6; ++step)				      \
Packit 6c4009
	  if ((wc & (~(uint32_t)0 << (5 * step + 1))) == 0)		      \
Packit 6c4009
	    break;							      \
Packit 6c4009
									      \
Packit 6c4009
	if (__glibc_unlikely (outptr + step > outend))			      \
Packit 6c4009
	  {								      \
Packit 6c4009
	    /* Too long.  */						      \
Packit 6c4009
	    result = __GCONV_FULL_OUTPUT;				      \
Packit 6c4009
	    break;							      \
Packit 6c4009
	  }								      \
Packit 6c4009
									      \
Packit 6c4009
	start = outptr;							      \
Packit 6c4009
	*outptr = (unsigned char) (~0xff >> step);			      \
Packit 6c4009
	outptr += step;							      \
Packit 6c4009
	do								      \
Packit 6c4009
	  {								      \
Packit 6c4009
	    start[--step] = 0x80 | (wc & 0x3f);				      \
Packit 6c4009
	    wc >>= 6;							      \
Packit 6c4009
	  }								      \
Packit 6c4009
	while (step > 1);						      \
Packit 6c4009
	start[0] |= wc;							      \
Packit 6c4009
      }									      \
Packit 6c4009
    else								      \
Packit 6c4009
      {									      \
Packit 6c4009
	STANDARD_TO_LOOP_ERR_HANDLER (4);				      \
Packit 6c4009
      }									      \
Packit 6c4009
									      \
Packit 6c4009
    inptr += 4;								      \
Packit 6c4009
  }
Packit 6c4009
#define LOOP_NEED_FLAGS
Packit 6c4009
#include <iconv/loop.c>
Packit 6c4009
#include <iconv/skeleton.c>
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Convert from UTF-8 to the internal (UCS4-like) format.  */
Packit 6c4009
#define DEFINE_INIT		0
Packit 6c4009
#define DEFINE_FINI		0
Packit 6c4009
#define MIN_NEEDED_FROM		1
Packit 6c4009
#define MAX_NEEDED_FROM		6
Packit 6c4009
#define MIN_NEEDED_TO		4
Packit 6c4009
#define FROM_DIRECTION		1
Packit 6c4009
#define FROM_LOOP		utf8_internal_loop
Packit 6c4009
#define TO_LOOP			utf8_internal_loop /* This is not used.  */
Packit 6c4009
#define FUNCTION_NAME		__gconv_transform_utf8_internal
Packit 6c4009
#define ONE_DIRECTION		1
Packit 6c4009
Packit 6c4009
#define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
Packit 6c4009
#define MAX_NEEDED_INPUT	MAX_NEEDED_FROM
Packit 6c4009
#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
Packit 6c4009
#define LOOPFCT			FROM_LOOP
Packit 6c4009
#define BODY \
Packit 6c4009
  {									      \
Packit 6c4009
    /* Next input byte.  */						      \
Packit 6c4009
    uint32_t ch = *inptr;						      \
Packit 6c4009
									      \
Packit 6c4009
    if (__glibc_likely (ch < 0x80))					      \
Packit 6c4009
      {									      \
Packit 6c4009
	/* One byte sequence.  */					      \
Packit 6c4009
	++inptr;							      \
Packit 6c4009
      }									      \
Packit 6c4009
    else								      \
Packit 6c4009
      {									      \
Packit 6c4009
	uint_fast32_t cnt;						      \
Packit 6c4009
	uint_fast32_t i;						      \
Packit 6c4009
									      \
Packit 6c4009
	if (ch >= 0xc2 && ch < 0xe0)					      \
Packit 6c4009
	  {								      \
Packit 6c4009
	    /* We expect two bytes.  The first byte cannot be 0xc0 or 0xc1,   \
Packit 6c4009
	       otherwise the wide character could have been represented	      \
Packit 6c4009
	       using a single byte.  */					      \
Packit 6c4009
	    cnt = 2;							      \
Packit 6c4009
	    ch &= 0x1f;							      \
Packit 6c4009
	  }								      \
Packit 6c4009
	else if (__glibc_likely ((ch & 0xf0) == 0xe0))			      \
Packit 6c4009
	  {								      \
Packit 6c4009
	    /* We expect three bytes.  */				      \
Packit 6c4009
	    cnt = 3;							      \
Packit 6c4009
	    ch &= 0x0f;							      \
Packit 6c4009
	  }								      \
Packit 6c4009
	else if (__glibc_likely ((ch & 0xf8) == 0xf0))			      \
Packit 6c4009
	  {								      \
Packit 6c4009
	    /* We expect four bytes.  */				      \
Packit 6c4009
	    cnt = 4;							      \
Packit 6c4009
	    ch &= 0x07;							      \
Packit 6c4009
	  }								      \
Packit 6c4009
	else if (__glibc_likely ((ch & 0xfc) == 0xf8))			      \
Packit 6c4009
	  {								      \
Packit 6c4009
	    /* We expect five bytes.  */				      \
Packit 6c4009
	    cnt = 5;							      \
Packit 6c4009
	    ch &= 0x03;							      \
Packit 6c4009
	  }								      \
Packit 6c4009
	else if (__glibc_likely ((ch & 0xfe) == 0xfc))			      \
Packit 6c4009
	  {								      \
Packit 6c4009
	    /* We expect six bytes.  */					      \
Packit 6c4009
	    cnt = 6;							      \
Packit 6c4009
	    ch &= 0x01;							      \
Packit 6c4009
	  }								      \
Packit 6c4009
	else								      \
Packit 6c4009
	  {								      \
Packit 6c4009
	    /* Search the end of this ill-formed UTF-8 character.  This	      \
Packit 6c4009
	       is the next byte with (x & 0xc0) != 0x80.  */		      \
Packit 6c4009
	    i = 0;							      \
Packit 6c4009
	    do								      \
Packit 6c4009
	      ++i;							      \
Packit 6c4009
	    while (inptr + i < inend					      \
Packit 6c4009
		   && (*(inptr + i) & 0xc0) == 0x80			      \
Packit 6c4009
		   && i < 5);						      \
Packit 6c4009
									      \
Packit 6c4009
	  errout:							      \
Packit 6c4009
	    STANDARD_FROM_LOOP_ERR_HANDLER (i);				      \
Packit 6c4009
	  }								      \
Packit 6c4009
									      \
Packit 6c4009
	if (__glibc_unlikely (inptr + cnt > inend))			      \
Packit 6c4009
	  {								      \
Packit 6c4009
	    /* We don't have enough input.  But before we report that check   \
Packit 6c4009
	       that all the bytes are correct.  */			      \
Packit 6c4009
	    for (i = 1; inptr + i < inend; ++i)				      \
Packit 6c4009
	      if ((inptr[i] & 0xc0) != 0x80)				      \
Packit 6c4009
		break;							      \
Packit 6c4009
									      \
Packit 6c4009
	    if (__glibc_likely (inptr + i == inend))			      \
Packit 6c4009
	      {								      \
Packit 6c4009
		result = __GCONV_INCOMPLETE_INPUT;			      \
Packit 6c4009
		break;							      \
Packit 6c4009
	      }								      \
Packit 6c4009
									      \
Packit 6c4009
	    goto errout;						      \
Packit 6c4009
	  }								      \
Packit 6c4009
									      \
Packit 6c4009
	/* Read the possible remaining bytes.  */			      \
Packit 6c4009
	for (i = 1; i < cnt; ++i)					      \
Packit 6c4009
	  {								      \
Packit 6c4009
	    uint32_t byte = inptr[i];					      \
Packit 6c4009
									      \
Packit 6c4009
	    if ((byte & 0xc0) != 0x80)					      \
Packit 6c4009
	      /* This is an illegal encoding.  */			      \
Packit 6c4009
	      break;							      \
Packit 6c4009
									      \
Packit 6c4009
	    ch <<= 6;							      \
Packit 6c4009
	    ch |= byte & 0x3f;						      \
Packit 6c4009
	  }								      \
Packit 6c4009
									      \
Packit 6c4009
	/* If i < cnt, some trail byte was not >= 0x80, < 0xc0.		      \
Packit 6c4009
	   If cnt > 2 and ch < 2^(5*cnt-4), the wide character ch could	      \
Packit 6c4009
	   have been represented with fewer than cnt bytes.  */		      \
Packit 6c4009
	if (i < cnt || (cnt > 2 && (ch >> (5 * cnt - 4)) == 0)		      \
Packit 6c4009
	    /* Do not accept UTF-16 surrogates.  */			      \
Packit 6c4009
	    || (ch >= 0xd800 && ch <= 0xdfff))				      \
Packit 6c4009
	  {								      \
Packit 6c4009
	    /* This is an illegal encoding.  */				      \
Packit 6c4009
	    goto errout;						      \
Packit 6c4009
	  }								      \
Packit 6c4009
									      \
Packit 6c4009
	inptr += cnt;							      \
Packit 6c4009
      }									      \
Packit 6c4009
									      \
Packit 6c4009
    /* Now adjust the pointers and store the result.  */		      \
Packit 6c4009
    *((uint32_t *) outptr) = ch;					      \
Packit 6c4009
    outptr += sizeof (uint32_t);					      \
Packit 6c4009
  }
Packit 6c4009
#define LOOP_NEED_FLAGS
Packit 6c4009
Packit 6c4009
#define STORE_REST \
Packit 6c4009
  {									      \
Packit 6c4009
    /* We store the remaining bytes while converting them into the UCS4	      \
Packit 6c4009
       format.  We can assume that the first byte in the buffer is	      \
Packit 6c4009
       correct and that it requires a larger number of bytes than there	      \
Packit 6c4009
       are in the input buffer.  */					      \
Packit 6c4009
    wint_t ch = **inptrp;						      \
Packit 6c4009
    size_t cnt, r;							      \
Packit 6c4009
									      \
Packit 6c4009
    state->__count = inend - *inptrp;					      \
Packit 6c4009
									      \
Packit 6c4009
    assert (ch != 0xc0 && ch != 0xc1);					      \
Packit 6c4009
    if (ch >= 0xc2 && ch < 0xe0)					      \
Packit 6c4009
      {									      \
Packit 6c4009
	/* We expect two bytes.  The first byte cannot be 0xc0 or	      \
Packit 6c4009
	   0xc1, otherwise the wide character could have been		      \
Packit 6c4009
	   represented using a single byte.  */				      \
Packit 6c4009
	cnt = 2;							      \
Packit 6c4009
	ch &= 0x1f;							      \
Packit 6c4009
      }									      \
Packit 6c4009
    else if (__glibc_likely ((ch & 0xf0) == 0xe0))			      \
Packit 6c4009
      {									      \
Packit 6c4009
	/* We expect three bytes.  */					      \
Packit 6c4009
	cnt = 3;							      \
Packit 6c4009
	ch &= 0x0f;							      \
Packit 6c4009
      }									      \
Packit 6c4009
    else if (__glibc_likely ((ch & 0xf8) == 0xf0))			      \
Packit 6c4009
      {									      \
Packit 6c4009
	/* We expect four bytes.  */					      \
Packit 6c4009
	cnt = 4;							      \
Packit 6c4009
	ch &= 0x07;							      \
Packit 6c4009
      }									      \
Packit 6c4009
    else if (__glibc_likely ((ch & 0xfc) == 0xf8))			      \
Packit 6c4009
      {									      \
Packit 6c4009
	/* We expect five bytes.  */					      \
Packit 6c4009
	cnt = 5;							      \
Packit 6c4009
	ch &= 0x03;							      \
Packit 6c4009
      }									      \
Packit 6c4009
    else								      \
Packit 6c4009
      {									      \
Packit 6c4009
	/* We expect six bytes.  */					      \
Packit 6c4009
	cnt = 6;							      \
Packit 6c4009
	ch &= 0x01;							      \
Packit 6c4009
      }									      \
Packit 6c4009
									      \
Packit 6c4009
    /* The first byte is already consumed.  */				      \
Packit 6c4009
    r = cnt - 1;							      \
Packit 6c4009
    while (++(*inptrp) < inend)						      \
Packit 6c4009
      {									      \
Packit 6c4009
	ch <<= 6;							      \
Packit 6c4009
	ch |= **inptrp & 0x3f;						      \
Packit 6c4009
	--r;								      \
Packit 6c4009
      }									      \
Packit 6c4009
									      \
Packit 6c4009
    /* Shift for the so far missing bytes.  */				      \
Packit 6c4009
    ch <<= r * 6;							      \
Packit 6c4009
									      \
Packit 6c4009
    /* Store the number of bytes expected for the entire sequence.  */	      \
Packit 6c4009
    state->__count |= cnt << 8;						      \
Packit 6c4009
									      \
Packit 6c4009
    /* Store the value.  */						      \
Packit 6c4009
    state->__value.__wch = ch;						      \
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
#define UNPACK_BYTES \
Packit 6c4009
  {									      \
Packit 6c4009
    static const unsigned char inmask[5] = { 0xc0, 0xe0, 0xf0, 0xf8, 0xfc };  \
Packit 6c4009
    wint_t wch = state->__value.__wch;					      \
Packit 6c4009
    size_t ntotal = state->__count >> 8;				      \
Packit 6c4009
									      \
Packit 6c4009
    inlen = state->__count & 255;					      \
Packit 6c4009
									      \
Packit 6c4009
    bytebuf[0] = inmask[ntotal - 2];					      \
Packit 6c4009
									      \
Packit 6c4009
    do									      \
Packit 6c4009
      {									      \
Packit 6c4009
	if (--ntotal < inlen)						      \
Packit 6c4009
	  bytebuf[ntotal] = 0x80 | (wch & 0x3f);			      \
Packit 6c4009
	wch >>= 6;							      \
Packit 6c4009
      }									      \
Packit 6c4009
    while (ntotal > 1);							      \
Packit 6c4009
									      \
Packit 6c4009
    bytebuf[0] |= wch;							      \
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
#define CLEAR_STATE \
Packit 6c4009
  state->__count = 0
Packit 6c4009
Packit 6c4009
Packit 6c4009
#include <iconv/loop.c>
Packit 6c4009
#include <iconv/skeleton.c>
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Convert from UCS2 to the internal (UCS4-like) format.  */
Packit 6c4009
#define DEFINE_INIT		0
Packit 6c4009
#define DEFINE_FINI		0
Packit 6c4009
#define MIN_NEEDED_FROM		2
Packit 6c4009
#define MIN_NEEDED_TO		4
Packit 6c4009
#define FROM_DIRECTION		1
Packit 6c4009
#define FROM_LOOP		ucs2_internal_loop
Packit 6c4009
#define TO_LOOP			ucs2_internal_loop /* This is not used.  */
Packit 6c4009
#define FUNCTION_NAME		__gconv_transform_ucs2_internal
Packit 6c4009
#define ONE_DIRECTION		1
Packit 6c4009
Packit 6c4009
#define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
Packit 6c4009
#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
Packit 6c4009
#define LOOPFCT			FROM_LOOP
Packit 6c4009
#define BODY \
Packit 6c4009
  {									      \
Packit 6c4009
    uint16_t u1 = get16 (inptr);					      \
Packit 6c4009
									      \
Packit 6c4009
    if (__glibc_unlikely (u1 >= 0xd800 && u1 < 0xe000))			      \
Packit 6c4009
      {									      \
Packit 6c4009
	/* Surrogate characters in UCS-2 input are not valid.  Reject	      \
Packit 6c4009
	   them.  (Catching this here is not security relevant.)  */	      \
Packit 6c4009
	STANDARD_FROM_LOOP_ERR_HANDLER (2);				      \
Packit 6c4009
      }									      \
Packit 6c4009
									      \
Packit 6c4009
    *((uint32_t *) outptr) = u1;					      \
Packit 6c4009
    outptr += sizeof (uint32_t);					      \
Packit 6c4009
    inptr += 2;								      \
Packit 6c4009
  }
Packit 6c4009
#define LOOP_NEED_FLAGS
Packit 6c4009
#include <iconv/loop.c>
Packit 6c4009
#include <iconv/skeleton.c>
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Convert from the internal (UCS4-like) format to UCS2.  */
Packit 6c4009
#define DEFINE_INIT		0
Packit 6c4009
#define DEFINE_FINI		0
Packit 6c4009
#define MIN_NEEDED_FROM		4
Packit 6c4009
#define MIN_NEEDED_TO		2
Packit 6c4009
#define FROM_DIRECTION		1
Packit 6c4009
#define FROM_LOOP		internal_ucs2_loop
Packit 6c4009
#define TO_LOOP			internal_ucs2_loop /* This is not used.  */
Packit 6c4009
#define FUNCTION_NAME		__gconv_transform_internal_ucs2
Packit 6c4009
#define ONE_DIRECTION		1
Packit 6c4009
Packit 6c4009
#define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
Packit 6c4009
#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
Packit 6c4009
#define LOOPFCT			FROM_LOOP
Packit 6c4009
#define BODY \
Packit 6c4009
  {									      \
Packit 6c4009
    uint32_t val = *((const uint32_t *) inptr);				      \
Packit 6c4009
									      \
Packit 6c4009
    if (__glibc_unlikely (val >= 0x10000))				      \
Packit 6c4009
      {									      \
Packit 6c4009
	UNICODE_TAG_HANDLER (val, 4);					      \
Packit 6c4009
	STANDARD_TO_LOOP_ERR_HANDLER (4);				      \
Packit 6c4009
      }									      \
Packit 6c4009
    else if (__glibc_unlikely (val >= 0xd800 && val < 0xe000))		      \
Packit 6c4009
      {									      \
Packit 6c4009
	/* Surrogate characters in UCS-4 input are not valid.		      \
Packit 6c4009
	   We must catch this, because the UCS-2 output might be	      \
Packit 6c4009
	   interpreted as UTF-16 by other programs.  If we let		      \
Packit 6c4009
	   surrogates pass through, attackers could make a security	      \
Packit 6c4009
	   hole exploit by synthesizing any desired plane 1-16		      \
Packit 6c4009
	   character.  */						      \
Packit 6c4009
	result = __GCONV_ILLEGAL_INPUT;					      \
Packit 6c4009
	if (! ignore_errors_p ())					      \
Packit 6c4009
	  break;							      \
Packit 6c4009
	inptr += 4;							      \
Packit 6c4009
	++*irreversible;						      \
Packit 6c4009
	continue;							      \
Packit 6c4009
      }									      \
Packit 6c4009
    else								      \
Packit 6c4009
      {									      \
Packit 6c4009
	put16 (outptr, val);						      \
Packit 6c4009
	outptr += sizeof (uint16_t);					      \
Packit 6c4009
	inptr += 4;							      \
Packit 6c4009
      }									      \
Packit 6c4009
  }
Packit 6c4009
#define LOOP_NEED_FLAGS
Packit 6c4009
#include <iconv/loop.c>
Packit 6c4009
#include <iconv/skeleton.c>
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Convert from UCS2 in other endianness to the internal (UCS4-like) format. */
Packit 6c4009
#define DEFINE_INIT		0
Packit 6c4009
#define DEFINE_FINI		0
Packit 6c4009
#define MIN_NEEDED_FROM		2
Packit 6c4009
#define MIN_NEEDED_TO		4
Packit 6c4009
#define FROM_DIRECTION		1
Packit 6c4009
#define FROM_LOOP		ucs2reverse_internal_loop
Packit 6c4009
#define TO_LOOP			ucs2reverse_internal_loop/* This is not used.*/
Packit 6c4009
#define FUNCTION_NAME		__gconv_transform_ucs2reverse_internal
Packit 6c4009
#define ONE_DIRECTION		1
Packit 6c4009
Packit 6c4009
#define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
Packit 6c4009
#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
Packit 6c4009
#define LOOPFCT			FROM_LOOP
Packit 6c4009
#define BODY \
Packit 6c4009
  {									      \
Packit 6c4009
    uint16_t u1 = bswap_16 (get16 (inptr));				      \
Packit 6c4009
									      \
Packit 6c4009
    if (__glibc_unlikely (u1 >= 0xd800 && u1 < 0xe000))			      \
Packit 6c4009
      {									      \
Packit 6c4009
	/* Surrogate characters in UCS-2 input are not valid.  Reject	      \
Packit 6c4009
	   them.  (Catching this here is not security relevant.)  */	      \
Packit 6c4009
	if (! ignore_errors_p ())					      \
Packit 6c4009
	  {								      \
Packit 6c4009
	    result = __GCONV_ILLEGAL_INPUT;				      \
Packit 6c4009
	    break;							      \
Packit 6c4009
	  }								      \
Packit 6c4009
	inptr += 2;							      \
Packit 6c4009
	++*irreversible;						      \
Packit 6c4009
	continue;							      \
Packit 6c4009
      }									      \
Packit 6c4009
									      \
Packit 6c4009
    *((uint32_t *) outptr) = u1;					      \
Packit 6c4009
    outptr += sizeof (uint32_t);					      \
Packit 6c4009
    inptr += 2;								      \
Packit 6c4009
  }
Packit 6c4009
#define LOOP_NEED_FLAGS
Packit 6c4009
#include <iconv/loop.c>
Packit 6c4009
#include <iconv/skeleton.c>
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Convert from the internal (UCS4-like) format to UCS2 in other endianness. */
Packit 6c4009
#define DEFINE_INIT		0
Packit 6c4009
#define DEFINE_FINI		0
Packit 6c4009
#define MIN_NEEDED_FROM		4
Packit 6c4009
#define MIN_NEEDED_TO		2
Packit 6c4009
#define FROM_DIRECTION		1
Packit 6c4009
#define FROM_LOOP		internal_ucs2reverse_loop
Packit 6c4009
#define TO_LOOP			internal_ucs2reverse_loop/* This is not used.*/
Packit 6c4009
#define FUNCTION_NAME		__gconv_transform_internal_ucs2reverse
Packit 6c4009
#define ONE_DIRECTION		1
Packit 6c4009
Packit 6c4009
#define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
Packit 6c4009
#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
Packit 6c4009
#define LOOPFCT			FROM_LOOP
Packit 6c4009
#define BODY \
Packit 6c4009
  {									      \
Packit 6c4009
    uint32_t val = *((const uint32_t *) inptr);				      \
Packit 6c4009
    if (__glibc_unlikely (val >= 0x10000))				      \
Packit 6c4009
      {									      \
Packit 6c4009
	UNICODE_TAG_HANDLER (val, 4);					      \
Packit 6c4009
	STANDARD_TO_LOOP_ERR_HANDLER (4);				      \
Packit 6c4009
      }									      \
Packit 6c4009
    else if (__glibc_unlikely (val >= 0xd800 && val < 0xe000))		      \
Packit 6c4009
      {									      \
Packit 6c4009
	/* Surrogate characters in UCS-4 input are not valid.		      \
Packit 6c4009
	   We must catch this, because the UCS-2 output might be	      \
Packit 6c4009
	   interpreted as UTF-16 by other programs.  If we let		      \
Packit 6c4009
	   surrogates pass through, attackers could make a security	      \
Packit 6c4009
	   hole exploit by synthesizing any desired plane 1-16		      \
Packit 6c4009
	   character.  */						      \
Packit 6c4009
	if (! ignore_errors_p ())					      \
Packit 6c4009
	  {								      \
Packit 6c4009
	    result = __GCONV_ILLEGAL_INPUT;				      \
Packit 6c4009
	    break;							      \
Packit 6c4009
	  }								      \
Packit 6c4009
	inptr += 4;							      \
Packit 6c4009
	++*irreversible;						      \
Packit 6c4009
	continue;							      \
Packit 6c4009
      }									      \
Packit 6c4009
    else								      \
Packit 6c4009
      {									      \
Packit 6c4009
	put16 (outptr, bswap_16 (val));					      \
Packit 6c4009
	outptr += sizeof (uint16_t);					      \
Packit 6c4009
	inptr += 4;							      \
Packit 6c4009
      }									      \
Packit 6c4009
  }
Packit 6c4009
#define LOOP_NEED_FLAGS
Packit 6c4009
#include <iconv/loop.c>
Packit 6c4009
#include <iconv/skeleton.c>