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