Blame lib/unistring/unistr/u8-to-u16.c

Packit aea12f
/* Convert UTF-8 string to UTF-16 string.
Packit Service 991b93
   Copyright (C) 2002, 2006-2007, 2009-2020 Free Software Foundation, Inc.
Packit aea12f
   Written by Bruno Haible <bruno@clisp.org>, 2002.
Packit aea12f
Packit aea12f
   This program is free software: you can redistribute it and/or
Packit aea12f
   modify it under the terms of either:
Packit aea12f
Packit aea12f
     * the GNU Lesser General Public License as published by the Free
Packit aea12f
       Software Foundation; either version 3 of the License, or (at your
Packit aea12f
       option) any later version.
Packit aea12f
Packit aea12f
   or
Packit aea12f
Packit aea12f
     * the GNU General Public License as published by the Free
Packit aea12f
       Software Foundation; either version 2 of the License, or (at your
Packit aea12f
       option) any later version.
Packit aea12f
Packit aea12f
   or both in parallel, as here.
Packit aea12f
   This program is distributed in the hope that it will be useful,
Packit aea12f
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit aea12f
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit aea12f
   Lesser General Public License for more details.
Packit aea12f
Packit aea12f
   You should have received a copy of the GNU Lesser General Public License
Packit aea12f
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
Packit aea12f
Packit aea12f
#include <config.h>
Packit aea12f
Packit aea12f
/* Specification.  */
Packit aea12f
#include "unistr.h"
Packit aea12f
Packit aea12f
#define FUNC u8_to_u16
Packit aea12f
#define SRC_UNIT uint8_t
Packit aea12f
#define DST_UNIT uint16_t
Packit aea12f
Packit aea12f
#include <errno.h>
Packit aea12f
#include <stdlib.h>
Packit aea12f
#include <string.h>
Packit aea12f
Packit aea12f
DST_UNIT *
Packit aea12f
FUNC (const SRC_UNIT *s, size_t n, DST_UNIT *resultbuf, size_t *lengthp)
Packit aea12f
{
Packit aea12f
  const SRC_UNIT *s_end = s + n;
Packit aea12f
  /* Output string accumulator.  */
Packit aea12f
  DST_UNIT *result;
Packit aea12f
  size_t allocated;
Packit aea12f
  size_t length;
Packit aea12f
Packit aea12f
  if (resultbuf != NULL)
Packit aea12f
    {
Packit aea12f
      result = resultbuf;
Packit aea12f
      allocated = *lengthp;
Packit aea12f
    }
Packit aea12f
  else
Packit aea12f
    {
Packit aea12f
      result = NULL;
Packit aea12f
      allocated = 0;
Packit aea12f
    }
Packit aea12f
  length = 0;
Packit aea12f
  /* Invariants:
Packit aea12f
     result is either == resultbuf or == NULL or malloc-allocated.
Packit aea12f
     If length > 0, then result != NULL.  */
Packit aea12f
Packit aea12f
  while (s < s_end)
Packit aea12f
    {
Packit aea12f
      ucs4_t uc;
Packit aea12f
      int count;
Packit aea12f
Packit aea12f
      /* Fetch a Unicode character from the input string.  */
Packit aea12f
      count = u8_mbtoucr (&uc, s, s_end - s);
Packit aea12f
      if (count < 0)
Packit aea12f
        {
Packit aea12f
          if (!(result == resultbuf || result == NULL))
Packit aea12f
            free (result);
Packit aea12f
          errno = EILSEQ;
Packit aea12f
          return NULL;
Packit aea12f
        }
Packit aea12f
      s += count;
Packit aea12f
Packit aea12f
      /* Store it in the output string.  */
Packit aea12f
      count = u16_uctomb (result + length, uc, allocated - length);
Packit aea12f
      if (count == -1)
Packit aea12f
        {
Packit aea12f
          if (!(result == resultbuf || result == NULL))
Packit aea12f
            free (result);
Packit aea12f
          errno = EILSEQ;
Packit aea12f
          return NULL;
Packit aea12f
        }
Packit aea12f
      if (count == -2)
Packit aea12f
        {
Packit aea12f
          DST_UNIT *memory;
Packit aea12f
Packit aea12f
          allocated = (allocated > 0 ? 2 * allocated : 12);
Packit aea12f
          if (length + 2 > allocated)
Packit aea12f
            allocated = length + 2;
Packit aea12f
          if (result == resultbuf || result == NULL)
Packit aea12f
            memory = (DST_UNIT *) malloc (allocated * sizeof (DST_UNIT));
Packit aea12f
          else
Packit aea12f
            memory =
Packit aea12f
              (DST_UNIT *) realloc (result, allocated * sizeof (DST_UNIT));
Packit aea12f
Packit aea12f
          if (memory == NULL)
Packit aea12f
            {
Packit aea12f
              if (!(result == resultbuf || result == NULL))
Packit aea12f
                free (result);
Packit aea12f
              errno = ENOMEM;
Packit aea12f
              return NULL;
Packit aea12f
            }
Packit aea12f
          if (result == resultbuf && length > 0)
Packit aea12f
            memcpy ((char *) memory, (char *) result,
Packit aea12f
                    length * sizeof (DST_UNIT));
Packit aea12f
          result = memory;
Packit aea12f
          count = u16_uctomb (result + length, uc, allocated - length);
Packit aea12f
          if (count < 0)
Packit aea12f
            abort ();
Packit aea12f
        }
Packit aea12f
      length += count;
Packit aea12f
    }
Packit aea12f
Packit aea12f
  if (length == 0)
Packit aea12f
    {
Packit aea12f
      if (result == NULL)
Packit aea12f
        {
Packit aea12f
          /* Return a non-NULL value.  NULL means error.  */
Packit aea12f
          result = (DST_UNIT *) malloc (1);
Packit aea12f
          if (result == NULL)
Packit aea12f
            {
Packit aea12f
              errno = ENOMEM;
Packit aea12f
              return NULL;
Packit aea12f
            }
Packit aea12f
        }
Packit aea12f
    }
Packit aea12f
  else if (result != resultbuf && length < allocated)
Packit aea12f
    {
Packit aea12f
      /* Shrink the allocated memory if possible.  */
Packit aea12f
      DST_UNIT *memory;
Packit aea12f
Packit aea12f
      memory = (DST_UNIT *) realloc (result, length * sizeof (DST_UNIT));
Packit aea12f
      if (memory != NULL)
Packit aea12f
        result = memory;
Packit aea12f
    }
Packit aea12f
Packit aea12f
  *lengthp = length;
Packit aea12f
  return result;
Packit aea12f
}