1 /*
2  * Copyright (c) 2004, 2005, 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 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <locale.h>
30 #include <langinfo.h>
31 #include <iconv.h>
32 
33 #include "utf.h"
34 
35 /* Global variables */
36 
37 /*
38  * Initialize all utf processing.
39  */
40 struct UtfInst *JNICALL
utfInitialize(char * options)41 utfInitialize(char *options)
42 {
43     struct UtfInst *ui;
44     char           *codeset;
45 
46     ui = (struct UtfInst*)calloc(sizeof(struct UtfInst), 1);
47     ui->iconvToPlatform         = (void *)-1;
48     ui->iconvFromPlatform       = (void *)-1;
49 
50     /* Set the locale from the environment */
51     (void)setlocale(LC_ALL, "");
52 
53     /* Get the codeset name */
54     codeset = (char*)nl_langinfo(CODESET);
55     if ( codeset == NULL || codeset[0] == 0 ) {
56         return ui;
57     }
58 
59     /* If we don't need this, skip it */
60     if (strcmp(codeset, "UTF-8") == 0 || strcmp(codeset, "utf8") == 0 ) {
61         return ui;
62     }
63 
64     /* Open conversion descriptors */
65     ui->iconvToPlatform   = iconv_open(codeset, "UTF-8");
66     if ( ui->iconvToPlatform == (void *)-1 ) {
67         UTF_ERROR("Failed to complete iconv_open() setup");
68     }
69     ui->iconvFromPlatform = iconv_open("UTF-8", codeset);
70     if ( ui->iconvFromPlatform == (void *)-1 ) {
71         UTF_ERROR("Failed to complete iconv_open() setup");
72     }
73     return ui;
74 }
75 
76 /*
77  * Terminate all utf processing
78  */
79 void  JNICALL
utfTerminate(struct UtfInst * ui,char * options)80 utfTerminate(struct UtfInst *ui, char *options)
81 {
82     if ( ui->iconvFromPlatform != (void *)-1 ) {
83         (void)iconv_close(ui->iconvFromPlatform);
84     }
85     if ( ui->iconvToPlatform != (void *)-1 ) {
86         (void)iconv_close(ui->iconvToPlatform);
87     }
88     ui->iconvToPlatform   = (void *)-1;
89     ui->iconvFromPlatform = (void *)-1;
90     (void)free(ui);
91 }
92 
93 /*
94  * Do iconv() conversion.
95  *    Returns length or -1 if output overflows.
96  */
97 static int
iconvConvert(iconv_t ic,char * bytes,int len,char * output,int outputMaxLen)98 iconvConvert(iconv_t ic, char *bytes, int len, char *output, int outputMaxLen)
99 {
100     int outputLen = 0;
101 
102     UTF_ASSERT(bytes);
103     UTF_ASSERT(len>=0);
104     UTF_ASSERT(output);
105     UTF_ASSERT(outputMaxLen>len);
106 
107     output[0] = 0;
108     outputLen = 0;
109 
110     if ( ic != (iconv_t)(void *)-1 ) {
111         int          returnValue;
112         size_t       inLeft;
113         size_t       outLeft;
114         char        *inbuf;
115         char        *outbuf;
116 
117         inbuf        = bytes;
118         outbuf       = output;
119         inLeft       = len;
120         outLeft      = outputMaxLen;
121         returnValue  = iconv(ic, (void*)&inbuf, &inLeft, &outbuf, &outLeft);
122         if ( returnValue >= 0 && inLeft==0 ) {
123             outputLen = outputMaxLen-outLeft;
124             output[outputLen] = 0;
125             return outputLen;
126         }
127 
128         /* Failed to do the conversion */
129         return -1;
130     }
131 
132     /* Just copy bytes */
133     outputLen = len;
134     (void)memcpy(output, bytes, len);
135     output[len] = 0;
136     return outputLen;
137 }
138 
139 /*
140  * Convert UTF-8 to Platform Encoding.
141  *    Returns length or -1 if output overflows.
142  */
143 int  JNICALL
utf8ToPlatform(struct UtfInst * ui,jbyte * utf8,int len,char * output,int outputMaxLen)144 utf8ToPlatform(struct UtfInst*ui, jbyte *utf8, int len, char *output, int outputMaxLen)
145 {
146     /* Negative length is an error */
147     if ( len < 0 ) {
148         return -1;
149     }
150 
151     /* Zero length is ok, but we don't need to do much */
152     if ( len == 0 ) {
153         output[0] = 0;
154         return 0;
155     }
156 
157     return iconvConvert(ui->iconvToPlatform, (char*)utf8, len, output, outputMaxLen);
158 }
159 
160 /*
161  * Convert Platform Encoding to UTF-8.
162  *    Returns length or -1 if output overflows.
163  */
164 int  JNICALL
utf8FromPlatform(struct UtfInst * ui,char * str,int len,jbyte * output,int outputMaxLen)165 utf8FromPlatform(struct UtfInst*ui, char *str, int len, jbyte *output, int outputMaxLen)
166 {
167     /* Negative length is an error */
168     if ( len < 0 ) {
169         return -1;
170     }
171 
172     /* Zero length is ok, but we don't need to do much */
173     if ( len == 0 ) {
174         output[0] = 0;
175         return 0;
176     }
177 
178     return iconvConvert(ui->iconvFromPlatform, str, len, (char*)output, outputMaxLen);
179 }
180