1 /* 2 * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 #include <stdio.h> 26 #include <stddef.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <ctype.h> 30 #include <locale.h> 31 #include <langinfo.h> 32 #include <iconv.h> 33 34 /* Routines to convert back and forth between Platform Encoding and UTF-8 */ 35 36 /* Error and assert macros */ 37 #define UTF_ERROR(m) utfError(__FILE__, __LINE__, m) 38 #define UTF_ASSERT(x) ( (x)==0 ? UTF_ERROR("ASSERT ERROR " #x) : (void)0 ) 39 #define UTF_DEBUG(x) 40 41 /* Global variables */ 42 static iconv_t iconvToPlatform = (iconv_t)-1; 43 static iconv_t iconvFromPlatform = (iconv_t)-1; 44 45 /* 46 * Error handler 47 */ 48 static void 49 utfError(char *file, int line, char *message) 50 { 51 (void)fprintf(stderr, "UTF ERROR [\"%s\":%d]: %s\n", file, line, message); 52 abort(); 53 } 54 55 /* 56 * Initialize all utf processing. 57 */ 58 static void 59 utfInitialize(void) 60 { 61 char *codeset; 62 63 /* Set the locale from the environment */ 64 (void)setlocale(LC_ALL, ""); 65 66 /* Get the codeset name */ 67 codeset = (char*)nl_langinfo(CODESET); 68 if ( codeset == NULL || codeset[0] == 0 ) { 69 UTF_DEBUG(("NO codeset returned by nl_langinfo(CODESET)\n")); 70 return; 71 } 72 73 UTF_DEBUG(("Codeset = %s\n", codeset)); 74 75 /* If we don't need this, skip it */ 76 if (strcmp(codeset, "UTF-8") == 0 || strcmp(codeset, "utf8") == 0 ) { 77 UTF_DEBUG(("NO iconv() being used because it is not needed\n")); 78 return; 79 } 80 81 /* Open conversion descriptors */ 82 iconvToPlatform = iconv_open(codeset, "UTF-8"); 83 if ( iconvToPlatform == (iconv_t)-1 ) { 84 UTF_ERROR("Failed to complete iconv_open() setup"); 85 } 86 iconvFromPlatform = iconv_open("UTF-8", codeset); 87 if ( iconvFromPlatform == (iconv_t)-1 ) { 88 UTF_ERROR("Failed to complete iconv_open() setup"); 89 } 90 } 91 92 /* 93 * Terminate all utf processing 94 */ 95 static void 96 utfTerminate(void) 97 { 98 if ( iconvFromPlatform!=(iconv_t)-1 ) { 99 (void)iconv_close(iconvFromPlatform); 100 } 101 if ( iconvToPlatform!=(iconv_t)-1 ) { 102 (void)iconv_close(iconvToPlatform); 103 } 104 iconvToPlatform = (iconv_t)-1; 105 iconvFromPlatform = (iconv_t)-1; 106 } 107 108 /* 109 * Do iconv() conversion. 110 * Returns length or -1 if output overflows. 111 */ 112 static int 113 iconvConvert(iconv_t ic, char *bytes, int len, char *output, int outputMaxLen) 114 { 115 int outputLen = 0; 116 117 UTF_ASSERT(bytes); 118 UTF_ASSERT(len>=0); 119 UTF_ASSERT(output); 120 UTF_ASSERT(outputMaxLen>len); 121 122 output[0] = 0; 123 outputLen = 0; 124 125 if ( ic != (iconv_t)-1 ) { 126 int returnValue; 127 size_t inLeft; 128 size_t outLeft; 129 char *inbuf; 130 char *outbuf; 131 132 inbuf = bytes; 133 outbuf = output; 134 inLeft = len; 135 outLeft = outputMaxLen; 136 returnValue = iconv(ic, (void*)&inbuf, &inLeft, &outbuf, &outLeft); 137 if ( returnValue >= 0 && inLeft==0 ) { 138 outputLen = outputMaxLen-outLeft; 139 output[outputLen] = 0; 140 return outputLen; 141 } 142 143 /* Failed to do the conversion */ 144 return -1; 145 } 146 147 /* Just copy bytes */ 148 outputLen = len; 149 (void)memcpy(output, bytes, len); 150 output[len] = 0; 151 return outputLen; 152 } 153 154 /* 155 * Convert UTF-8 to Platform Encoding. 156 * Returns length or -1 if output overflows. 157 */ 158 static int 159 utf8ToPlatform(char *utf8, int len, char *output, int outputMaxLen) 160 { 161 return iconvConvert(iconvToPlatform, utf8, len, output, outputMaxLen); 162 } 163 164 /* 165 * Convert Platform Encoding to UTF-8. 166 * Returns length or -1 if output overflows. 167 */ 168 static int 169 platformToUtf8(char *str, int len, char *output, int outputMaxLen) 170 { 171 return iconvConvert(iconvFromPlatform, str, len, output, outputMaxLen); 172 } 173 174 int 175 convertUft8ToPlatformString(char* utf8_str, int utf8_len, char* platform_str, int platform_len) { 176 if (iconvToPlatform == (iconv_t)-1) { 177 utfInitialize(); 178 } 179 return utf8ToPlatform(utf8_str, utf8_len, platform_str, platform_len); 180 }