1/* 2 * Copyright (c) 2004, 2012, 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/* Use THIS_FILE when it is available. */ 37#ifndef THIS_FILE 38 #define THIS_FILE __FILE__ 39#endif 40 41/* Error and assert macros */ 42#define UTF_ERROR(m) utfError(THIS_FILE, __LINE__, m) 43#define UTF_ASSERT(x) ( (x)==0 ? UTF_ERROR("ASSERT ERROR " #x) : (void)0 ) 44#define UTF_DEBUG(x) 45 46/* Global variables */ 47static iconv_t iconvToPlatform = (iconv_t)-1; 48static iconv_t iconvFromPlatform = (iconv_t)-1; 49 50/* 51 * Error handler 52 */ 53static void 54utfError(char *file, int line, char *message) 55{ 56 (void)fprintf(stderr, "UTF ERROR [\"%s\":%d]: %s\n", file, line, message); 57 abort(); 58} 59 60/* 61 * Initialize all utf processing. 62 */ 63static void 64utfInitialize(void) 65{ 66 char *codeset; 67 68 /* Set the locale from the environment */ 69 (void)setlocale(LC_ALL, ""); 70 71 /* Get the codeset name */ 72 codeset = (char*)nl_langinfo(CODESET); 73 if ( codeset == NULL || codeset[0] == 0 ) { 74 UTF_DEBUG(("NO codeset returned by nl_langinfo(CODESET)\n")); 75 return; 76 } 77 78 UTF_DEBUG(("Codeset = %s\n", codeset)); 79 80 /* If we don't need this, skip it */ 81 if (strcmp(codeset, "UTF-8") == 0 || strcmp(codeset, "utf8") == 0 ) { 82 UTF_DEBUG(("NO iconv() being used because it is not needed\n")); 83 return; 84 } 85 86 /* Open conversion descriptors */ 87 iconvToPlatform = iconv_open(codeset, "UTF-8"); 88 if ( iconvToPlatform == (iconv_t)-1 ) { 89 UTF_ERROR("Failed to complete iconv_open() setup"); 90 } 91 iconvFromPlatform = iconv_open("UTF-8", codeset); 92 if ( iconvFromPlatform == (iconv_t)-1 ) { 93 UTF_ERROR("Failed to complete iconv_open() setup"); 94 } 95} 96 97/* 98 * Terminate all utf processing 99 */ 100static void 101utfTerminate(void) 102{ 103 if ( iconvFromPlatform!=(iconv_t)-1 ) { 104 (void)iconv_close(iconvFromPlatform); 105 } 106 if ( iconvToPlatform!=(iconv_t)-1 ) { 107 (void)iconv_close(iconvToPlatform); 108 } 109 iconvToPlatform = (iconv_t)-1; 110 iconvFromPlatform = (iconv_t)-1; 111} 112 113/* 114 * Do iconv() conversion. 115 * Returns length or -1 if output overflows. 116 */ 117static int 118iconvConvert(iconv_t ic, char *bytes, int len, char *output, int outputMaxLen) 119{ 120 int outputLen = 0; 121 122 UTF_ASSERT(bytes); 123 UTF_ASSERT(len>=0); 124 UTF_ASSERT(output); 125 UTF_ASSERT(outputMaxLen>len); 126 127 output[0] = 0; 128 outputLen = 0; 129 130 if ( ic != (iconv_t)-1 ) { 131 int returnValue; 132 size_t inLeft; 133 size_t outLeft; 134 char *inbuf; 135 char *outbuf; 136 137 inbuf = bytes; 138 outbuf = output; 139 inLeft = len; 140 outLeft = outputMaxLen; 141 returnValue = iconv(ic, (void*)&inbuf, &inLeft, &outbuf, &outLeft); 142 if ( returnValue >= 0 && inLeft==0 ) { 143 outputLen = outputMaxLen-outLeft; 144 output[outputLen] = 0; 145 return outputLen; 146 } 147 148 /* Failed to do the conversion */ 149 return -1; 150 } 151 152 /* Just copy bytes */ 153 outputLen = len; 154 (void)memcpy(output, bytes, len); 155 output[len] = 0; 156 return outputLen; 157} 158 159/* 160 * Convert UTF-8 to Platform Encoding. 161 * Returns length or -1 if output overflows. 162 */ 163static int 164utf8ToPlatform(char *utf8, int len, char *output, int outputMaxLen) 165{ 166 return iconvConvert(iconvToPlatform, utf8, len, output, outputMaxLen); 167} 168 169/* 170 * Convert Platform Encoding to UTF-8. 171 * Returns length or -1 if output overflows. 172 */ 173static int 174platformToUtf8(char *str, int len, char *output, int outputMaxLen) 175{ 176 return iconvConvert(iconvFromPlatform, str, len, output, outputMaxLen); 177} 178 179int 180convertUft8ToPlatformString(char* utf8_str, int utf8_len, char* platform_str, int platform_len) { 181 if (iconvToPlatform == (iconv_t)-1) { 182 utfInitialize(); 183 } 184 return utf8ToPlatform(utf8_str, utf8_len, platform_str, platform_len); 185} 186