Avoid test failures on AIX and OSF/1.
[gnulib.git] / lib / uniconv / u-conv-to-enc.h
1 /* Conversion from UTF-16/UTF-32 to legacy encodings.
2    Copyright (C) 2002, 2006-2009 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 int
18 FUNC (const char *tocode,
19       enum iconv_ilseq_handler handler,
20       const UNIT *src, size_t srclen,
21       size_t *offsets,
22       char **resultp, size_t *lengthp)
23 {
24 #if HAVE_UTF_NAME
25   size_t *scaled_offsets;
26   int retval;
27
28   if (offsets != NULL && srclen > 0)
29     {
30       scaled_offsets =
31         (size_t *) malloc (srclen * sizeof (UNIT) * sizeof (size_t));
32       if (scaled_offsets == NULL)
33         {
34           errno = ENOMEM;
35           return -1;
36         }
37     }
38   else
39     scaled_offsets = NULL;
40
41   retval = mem_iconveha ((const char *) src, srclen * sizeof (UNIT),
42                          UTF_NAME, tocode,
43                          handler == iconveh_question_mark, handler,
44                          scaled_offsets, resultp, lengthp);
45
46   if (offsets != NULL)
47     {
48       if (retval >= 0)
49         {
50           /* Convert scaled_offsets[srclen * sizeof (UNIT)] to
51              offsets[srclen].  */
52           size_t i;
53
54           for (i = 0; i < srclen; i++)
55             offsets[i] = scaled_offsets[i * sizeof (UNIT)];
56         }
57       free (scaled_offsets);
58     }
59   return retval;
60 #else
61   uint8_t tmpbuf[4096];
62   size_t tmpbufsize = SIZEOF (tmpbuf);
63   uint8_t *utf8_src;
64   size_t utf8_srclen;
65   size_t *scaled_offsets;
66   int retval;
67
68   utf8_src = U_TO_U8 (src, srclen, tmpbuf, &tmpbufsize);
69   if (utf8_src == NULL)
70     return -1;
71   utf8_srclen = tmpbufsize;
72
73   if (offsets != NULL && utf8_srclen > 0)
74     {
75       scaled_offsets = (size_t *) malloc (utf8_srclen * sizeof (size_t));
76       if (scaled_offsets == NULL)
77         {
78           if (utf8_src != tmpbuf)
79             free (utf8_src);
80           errno = ENOMEM;
81           return -1;
82         }
83     }
84   else
85     scaled_offsets = NULL;
86
87   retval = u8_conv_to_encoding (tocode, handler, utf8_src, utf8_srclen,
88                                 scaled_offsets, resultp, lengthp);
89   if (retval < 0)
90     {
91       int saved_errno = errno;
92       free (scaled_offsets);
93       if (utf8_src != tmpbuf)
94         free (utf8_src);
95       errno = saved_errno;
96       return -1;
97     }
98   if (offsets != NULL)
99     {
100       size_t iunit;     /* offset into src */
101       size_t i8;        /* offset into utf8_src */
102
103       for (iunit = 0; iunit < srclen; iunit++)
104         offsets[iunit] = (size_t)(-1);
105
106       iunit = 0;
107       i8 = 0;
108       while (iunit < srclen && i8 < utf8_srclen)
109         {
110           int countunit;
111           int count8;
112
113           offsets[iunit] = scaled_offsets[i8];
114
115           countunit = U_MBLEN (src + iunit, srclen - iunit);
116           count8 = u8_mblen (utf8_src + i8, utf8_srclen - i8);
117           if (countunit < 0 || count8 < 0)
118             abort ();
119           iunit += countunit;
120           i8 += count8;
121         }
122       /* Check that utf8_src has been traversed entirely.  */
123       if (i8 < utf8_srclen)
124         abort ();
125       /* Check that src has been traversed entirely, except possibly for an
126          incomplete sequence of units at the end.  */
127       if (iunit < srclen)
128         {
129           offsets[iunit] = *lengthp;
130           if (!(U_MBLEN (src + iunit, srclen - iunit) < 0))
131             abort ();
132         }
133       free (scaled_offsets);
134     }
135   if (utf8_src != tmpbuf)
136     free (utf8_src);
137   return retval;
138 #endif
139 }