Blame wcsmbs/mbrtoc16.c

Packit Service 82fcde
/* Copyright (C) 2011-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
   Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <assert.h>
Packit Service 82fcde
#include <dlfcn.h>
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <gconv.h>
Packit Service 82fcde
#include <uchar.h>
Packit Service 82fcde
#include <wcsmbsload.h>
Packit Service 82fcde
Packit Service 82fcde
#include <sysdep.h>
Packit Service 82fcde
Packit Service 82fcde
#ifndef EILSEQ
Packit Service 82fcde
# define EILSEQ EINVAL
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* This is the private state used if PS is NULL.  */
Packit Service 82fcde
static mbstate_t state;
Packit Service 82fcde
Packit Service 82fcde
size_t
Packit Service 82fcde
mbrtoc16 (char16_t *pc16, const char *s, size_t n, mbstate_t *ps)
Packit Service 82fcde
{
Packit Service 82fcde
  if (ps == NULL)
Packit Service 82fcde
    ps = &stat;;
Packit Service 82fcde
Packit Service 82fcde
  /* The standard text does not say that S being NULL means the state
Packit Service 82fcde
     is reset even if the second half of a surrogate still have to be
Packit Service 82fcde
     returned.  In fact, the error code description indicates
Packit Service 82fcde
     otherwise.  Therefore always first try to return a second
Packit Service 82fcde
     half.  */
Packit Service 82fcde
  if (ps->__count & 0x80000000)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* We have to return the second word for a surrogate.  */
Packit Service 82fcde
      ps->__count &= 0x7fffffff;
Packit Service 82fcde
      *pc16 = ps->__value.__wch;
Packit Service 82fcde
      ps->__value.__wch = L'\0';
Packit Service 82fcde
      return (size_t) -3;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  wchar_t wc;
Packit Service 82fcde
  struct __gconv_step_data data;
Packit Service 82fcde
  int status;
Packit Service 82fcde
  size_t result;
Packit Service 82fcde
  size_t dummy;
Packit Service 82fcde
  const unsigned char *inbuf, *endbuf;
Packit Service 82fcde
  unsigned char *outbuf = (unsigned char *) &wc;
Packit Service 82fcde
  const struct gconv_fcts *fcts;
Packit Service 82fcde
Packit Service 82fcde
  /* Set information for this step.  */
Packit Service 82fcde
  data.__invocation_counter = 0;
Packit Service 82fcde
  data.__internal_use = 1;
Packit Service 82fcde
  data.__flags = __GCONV_IS_LAST;
Packit Service 82fcde
  data.__statep = ps;
Packit Service 82fcde
Packit Service 82fcde
  /* A first special case is if S is NULL.  This means put PS in the
Packit Service 82fcde
     initial state.  */
Packit Service 82fcde
  if (s == NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      pc16 = NULL;
Packit Service 82fcde
      s = "";
Packit Service 82fcde
      n = 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (n == 0)
Packit Service 82fcde
    return (size_t) -2;
Packit Service 82fcde
Packit Service 82fcde
  /* Tell where we want the result.  */
Packit Service 82fcde
  data.__outbuf = outbuf;
Packit Service 82fcde
  data.__outbufend = outbuf + sizeof (wchar_t);
Packit Service 82fcde
Packit Service 82fcde
  /* Get the conversion functions.  */
Packit Service 82fcde
  fcts = get_gconv_fcts (_NL_CURRENT_DATA (LC_CTYPE));
Packit Service 82fcde
Packit Service 82fcde
  /* Do a normal conversion.  */
Packit Service 82fcde
  inbuf = (const unsigned char *) s;
Packit Service 82fcde
  endbuf = inbuf + n;
Packit Service 82fcde
  if (__glibc_unlikely (endbuf < inbuf))
Packit Service 82fcde
    {
Packit Service 82fcde
      endbuf = (const unsigned char *) ~(uintptr_t) 0;
Packit Service 82fcde
      if (endbuf == inbuf)
Packit Service 82fcde
	goto ilseq;
Packit Service 82fcde
    }
Packit Service 82fcde
  __gconv_fct fct = fcts->towc->__fct;
Packit Service 82fcde
#ifdef PTR_DEMANGLE
Packit Service 82fcde
  if (fcts->towc->__shlib_handle != NULL)
Packit Service 82fcde
    PTR_DEMANGLE (fct);
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  status = DL_CALL_FCT (fct, (fcts->towc, &data, &inbuf, endbuf,
Packit Service 82fcde
			      NULL, &dummy, 0, 1));
Packit Service 82fcde
Packit Service 82fcde
  /* There must not be any problems with the conversion but illegal input
Packit Service 82fcde
     characters.  The output buffer must be large enough, otherwise the
Packit Service 82fcde
     definition of MB_CUR_MAX is not correct.  All the other possible
Packit Service 82fcde
     errors also must not happen.  */
Packit Service 82fcde
  assert (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT
Packit Service 82fcde
	  || status == __GCONV_ILLEGAL_INPUT
Packit Service 82fcde
	  || status == __GCONV_INCOMPLETE_INPUT
Packit Service 82fcde
	  || status == __GCONV_FULL_OUTPUT);
Packit Service 82fcde
Packit Service 82fcde
  if (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT
Packit Service 82fcde
      || status == __GCONV_FULL_OUTPUT)
Packit Service 82fcde
    {
Packit Service 82fcde
      result = inbuf - (const unsigned char *) s;
Packit Service 82fcde
Packit Service 82fcde
      if (wc < 0x10000)
Packit Service 82fcde
	{
Packit Service 82fcde
	  if (pc16 != NULL)
Packit Service 82fcde
	    *pc16 = wc;
Packit Service 82fcde
Packit Service 82fcde
	  if (data.__outbuf != outbuf && wc == L'\0')
Packit Service 82fcde
	    {
Packit Service 82fcde
	      /* The converted character is the NUL character.  */
Packit Service 82fcde
	      assert (__mbsinit (data.__statep));
Packit Service 82fcde
	      result = 0;
Packit Service 82fcde
	    }
Packit Service 82fcde
	}
Packit Service 82fcde
      else
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* This is a surrogate.  */
Packit Service 82fcde
	  if (pc16 != NULL)
Packit Service 82fcde
	    *pc16 = 0xd7c0 + (wc >> 10);
Packit Service 82fcde
Packit Service 82fcde
	  ps->__count |= 0x80000000;
Packit Service 82fcde
	  ps->__value.__wch = 0xdc00 + (wc & 0x3ff);
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
  else if (status == __GCONV_INCOMPLETE_INPUT)
Packit Service 82fcde
    result = (size_t) -2;
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
    ilseq:
Packit Service 82fcde
      result = (size_t) -1;
Packit Service 82fcde
      __set_errno (EILSEQ);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return result;
Packit Service 82fcde
}