1/* Conversion from UTF-16 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 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 "striconveha.h" 29#include "unistr.h" 30 31#define SIZEOF(array) (sizeof (array) / sizeof (array[0])) 32 33/* Name of UTF-16 encoding with machine dependent endianness and alignment. */ 34#if defined _LIBICONV_VERSION || (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) 35# ifdef WORDS_BIGENDIAN 36# define UTF16_NAME "UTF-16BE" 37# else 38# define UTF16_NAME "UTF-16LE" 39# endif 40#endif 41 42 43#if !defined UTF16_NAME 44 45/* A variant of u16_to_u8 that treats an incomplete sequence of units at the 46 end as a harmless no-op, rather than reporting it as an EILSEQ error. */ 47 48#define FUNC u16_to_u8_lenient 49#define SRC_UNIT uint16_t 50#define DST_UNIT uint8_t 51 52static DST_UNIT * 53FUNC (const SRC_UNIT *s, size_t n, DST_UNIT *resultbuf, size_t *lengthp) 54{ 55 const SRC_UNIT *s_end = s + n; 56 /* Output string accumulator. */ 57 DST_UNIT *result; 58 size_t allocated; 59 size_t length; 60 61 if (resultbuf != NULL) 62 { 63 result = resultbuf; 64 allocated = *lengthp; 65 } 66 else 67 { 68 result = NULL; 69 allocated = 0; 70 } 71 length = 0; 72 /* Invariants: 73 result is either == resultbuf or == NULL or malloc-allocated. 74 If length > 0, then result != NULL. */ 75 76 while (s < s_end) 77 { 78 ucs4_t uc; 79 int count; 80 81 /* Fetch a Unicode character from the input string. */ 82 count = u16_mbtoucr (&uc, s, s_end - s); 83 if (count < 0) 84 { 85 if (count == -2) 86 /* Incomplete sequence of units. */ 87 break; 88 if (!(result == resultbuf || result == NULL)) 89 free (result); 90 errno = EILSEQ; 91 return NULL; 92 } 93 s += count; 94 95 /* Store it in the output string. */ 96 count = u8_uctomb (result + length, uc, allocated - length); 97 if (count == -1) 98 { 99 if (!(result == resultbuf || result == NULL)) 100 free (result); 101 errno = EILSEQ; 102 return NULL; 103 } 104 if (count == -2) 105 { 106 DST_UNIT *memory; 107 108 allocated = (allocated > 0 ? 2 * allocated : 12); 109 if (length + 6 > allocated) 110 allocated = length + 6; 111 if (result == resultbuf || result == NULL) 112 memory = (DST_UNIT *) malloc (allocated * sizeof (DST_UNIT)); 113 else 114 memory = 115 (DST_UNIT *) realloc (result, allocated * sizeof (DST_UNIT)); 116 117 if (memory == NULL) 118 { 119 if (!(result == resultbuf || result == NULL)) 120 free (result); 121 errno = ENOMEM; 122 return NULL; 123 } 124 if (result == resultbuf && length > 0) 125 memcpy ((char *) memory, (char *) result, 126 length * sizeof (DST_UNIT)); 127 result = memory; 128 count = u8_uctomb (result + length, uc, allocated - length); 129 if (count < 0) 130 abort (); 131 } 132 length += count; 133 } 134 135 if (length == 0) 136 { 137 if (result == NULL) 138 { 139 /* Return a non-NULL value. NULL means error. */ 140 result = (DST_UNIT *) malloc (1); 141 if (result == NULL) 142 { 143 errno = ENOMEM; 144 return NULL; 145 } 146 } 147 } 148 else if (result != resultbuf && length < allocated) 149 { 150 /* Shrink the allocated memory if possible. */ 151 DST_UNIT *memory; 152 153 memory = (DST_UNIT *) realloc (result, length * sizeof (DST_UNIT)); 154 if (memory != NULL) 155 result = memory; 156 } 157 158 *lengthp = length; 159 return result; 160} 161 162#undef DST_UNIT 163#undef SRC_UNIT 164#undef FUNC 165 166#endif 167 168 169#define FUNC u16_conv_to_encoding 170#define UNIT uint16_t 171#define U_TO_U8 u16_to_u8_lenient 172#define U_MBLEN u16_mblen 173#if defined UTF16_NAME 174# define UTF_NAME UTF16_NAME 175# define HAVE_UTF_NAME 1 176#endif 177#include "u-conv-to-enc.h" 178