New modules unistr/u*-mbsnlen.
[gnulib.git] / lib / uniconv / u-conv-to-enc.h
1 /* Conversion from UTF-16/UTF-32 to legacy encodings.
2    Copyright (C) 2002, 2006-2007 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 Library General Public License as published
6    by the Free Software Foundation; either version 2, or (at your option)
7    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    Library General Public License for more details.
13
14    You should have received a copy of the GNU Library General Public
15    License along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
17    USA.  */
18
19 int
20 FUNC (const char *tocode,
21       enum iconv_ilseq_handler handler,
22       const UNIT *src, size_t srclen,
23       size_t *offsets,
24       char **resultp, size_t *lengthp)
25 {
26 #if HAVE_UTF_NAME
27   size_t *scaled_offsets;
28   int retval;
29
30   if (offsets != NULL)
31     {
32       scaled_offsets =
33         (size_t *) malloc (srclen * sizeof (UNIT) * sizeof (size_t));
34       if (scaled_offsets == NULL)
35         {
36           errno = ENOMEM;
37           return -1;
38         }
39     }
40   else
41     scaled_offsets = NULL;
42
43   retval = mem_iconveha ((const char *) src, srclen * sizeof (UNIT),
44                          UTF_NAME, tocode,
45                          handler == iconveh_question_mark, handler,
46                          scaled_offsets, resultp, lengthp);
47
48   if (offsets != NULL)
49     {
50       if (retval >= 0)
51         {
52           /* Convert scaled_offsets[srclen * sizeof (UNIT)] to
53              offsets[srclen].  */
54           size_t i;
55
56           for (i = 0; i < srclen; i++)
57             offsets[i] = scaled_offsets[i * sizeof (UNIT)];
58         }
59       free (scaled_offsets);
60     }
61   return retval;
62 #else
63   uint8_t tmpbuf[4096];
64   size_t tmpbufsize = SIZEOF (tmpbuf);
65   uint8_t *utf8_src;
66   size_t utf8_srclen;
67   size_t *scaled_offsets;
68   int retval;
69
70   utf8_src = U_TO_U8 (src, srclen, tmpbuf, &tmpbufsize);
71   if (utf8_src == NULL)
72     return NULL;
73   utf8_srclen = tmpbufsize;
74
75   if (offsets != NULL)
76     {
77       scaled_offsets = (size_t *) malloc (utf8_srclen * sizeof (size_t));
78       if (scaled_offsets == NULL)
79         {
80           if (utf8_src != tmpbuf)
81             free (utf8_src);
82           errno = ENOMEM;
83           return -1;
84         }
85     }
86   else
87     scaled_offsets = NULL;
88
89   retval = u8_conv_to_encoding (tocode, handler, utf8_src, utf8_srclen,
90                                 scaled_offsets, resultp, lengthp);
91   if (retval < 0)
92     {
93       if (utf8_src != tmpbuf)
94         {
95           int saved_errno = errno;
96           free (utf8_src);
97           errno = saved_errno;
98         }
99       return -1;
100     }
101   if (offsets != NULL)
102     {
103       size_t iunit;     /* offset into src */
104       size_t i8;        /* offset into utf8_src */
105
106       for (iunit = 0; iunit < srclen; iunit++)
107         offsets[iunit] = (size_t)(-1);
108
109       iunit = 0;
110       i8 = 0;
111       while (iunit < srclen)
112         {
113           int countunit;
114           int count8;
115
116           offsets[iunit] = scaled_offsets[i8];
117
118           countunit = U_MBLEN (src + iunit, srclen - iunit);
119           count8 = u8_mblen (utf8_src + i8, utf8_srclen - i8);
120           if (countunit < 0 || count8 < 0)
121             abort ();
122           iunit += countunit;
123           i8 += count8;
124         }
125       free (scaled_offsets);
126     }
127   if (utf8_src != tmpbuf)
128     free (utf8_src);
129   return retval;
130 #endif
131 }