1/* Conversion to UTF-8 from legacy encodings.
2   Copyright (C) 2002, 2006-2007, 2009-2010 Free Software Foundation, Inc.
3
4   This program is free software: you can redistribute it and/or modify it
5   under the terms of the GNU Lesser General Public License as published
6   by the Free Software Foundation; either version 3 of the License, or
7   (at your option) any later version.
8
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   Lesser General Public License for more details.
13
14   You should have received a copy of the GNU Lesser General Public License
15   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17/* Written by Bruno Haible <bruno@clisp.org>.  */
18
19#include <config.h>
20
21/* Specification.  */
22#include "uniconv.h"
23
24#include <errno.h>
25#include <stdlib.h>
26#include <string.h>
27
28#include "c-strcaseeq.h"
29#include "striconveha.h"
30#include "unistr.h"
31
32uint8_t *
33u8_conv_from_encoding (const char *fromcode,
34                       enum iconv_ilseq_handler handler,
35                       const char *src, size_t srclen,
36                       size_t *offsets,
37                       uint8_t *resultbuf, size_t *lengthp)
38{
39  if (STRCASEEQ (fromcode, "UTF-8", 'U','T','F','-','8',0,0,0,0))
40    {
41      /* Conversion from UTF-8 to UTF-8.  No need to go through iconv().  */
42      uint8_t *result;
43
44      if (u8_check ((const uint8_t *) src, srclen))
45        {
46          errno = EILSEQ;
47          return NULL;
48        }
49
50      if (offsets != NULL)
51        {
52          size_t i;
53
54          for (i = 0; i < srclen; )
55            {
56              int count = u8_mblen ((const uint8_t *) src + i, srclen - i);
57              /* We can rely on count > 0 because of the previous u8_check.  */
58              if (count <= 0)
59                abort ();
60              offsets[i] = i;
61              i++;
62              while (--count > 0)
63                offsets[i++] = (size_t)(-1);
64            }
65        }
66
67      /* Memory allocation.  */
68      if (resultbuf != NULL && *lengthp >= srclen)
69        result = resultbuf;
70      else
71        {
72          result = (uint8_t *) malloc (srclen > 0 ? srclen : 1);
73          if (result == NULL)
74            {
75              errno = ENOMEM;
76              return NULL;
77            }
78        }
79
80      memcpy ((char *) result, src, srclen);
81      *lengthp = srclen;
82      return result;
83    }
84  else
85    {
86      char *result = (char *) resultbuf;
87      size_t length = *lengthp;
88
89      if (mem_iconveha (src, srclen, fromcode, "UTF-8", true, handler,
90                        offsets, &result, &length) < 0)
91        return NULL;
92
93      if (result == NULL) /* when (resultbuf == NULL && length == 0)  */
94        {
95          result = (char *) malloc (1);
96          if (result == NULL)
97            {
98              errno = ENOMEM;
99              return NULL;
100            }
101        }
102      *lengthp = length;
103      return (uint8_t *) result;
104    }
105}
106