1 /* OS/2 iconv() implementation through OS/2 Unicode API
2 Copyright (C) 2001-2002 Free Software Foundation, Inc.
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 2.1 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
12 GNU 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 <https://www.gnu.org/licenses/>. */
16
17 /*
18 This file implements an iconv wrapper based on OS/2 Unicode API.
19 */
20
21 #include <uconv.h>
22
23 typedef struct _iconv_t
24 {
25 UconvObject from; /* "From" conversion handle */
26 UconvObject to; /* "To" conversion handle */
27 } *iconv_t;
28
29 /* Tell "iconv.h" to not define iconv_t by itself. */
30 #define _ICONV_T
31 #include "iconv.h"
32
33 #include <string.h>
34 #include <malloc.h>
35 #include <errno.h>
36 #include <alloca.h>
37
38 /* Convert an encoding name to te form understood by UniCreateUconvObject. */
39 static inline void
cp_convert(const char * cp,UniChar * ucp)40 cp_convert (const char *cp, UniChar *ucp)
41 {
42 size_t sl = 0;
43
44 if (!stricmp (cp, "EUC-JP"))
45 memcpy (ucp, L"IBM-954", 8*2);
46 else if (!stricmp (cp, "EUC-KR"))
47 memcpy (ucp, L"IBM-970", 8*2);
48 else if (!stricmp (cp, "EUC-TW"))
49 memcpy (ucp, L"IBM-964", 8*2);
50 else if (!stricmp (cp, "EUC-CN"))
51 memcpy (ucp, L"IBM-1383", 9*2);
52 else if (!stricmp (cp, "BIG5"))
53 memcpy (ucp, L"IBM-950", 8*2);
54 else
55 {
56 /* Transform CPXXX naming style to IBM-XXX style */
57 if ((cp[0] == 'C' || cp[0] == 'c') && (cp[1] == 'P' || cp[1] == 'p'))
58 {
59 ucp[sl++] = 'I';
60 ucp[sl++] = 'B';
61 ucp[sl++] = 'M';
62 ucp[sl++] = '-';
63 cp += 2;
64 }
65
66 while (*cp != '\0')
67 ucp[sl++] = *cp++;
68 ucp[sl] = 0;
69 }
70 }
71
72 iconv_t
iconv_open(const char * cp_to,const char * cp_from)73 iconv_open (const char *cp_to, const char *cp_from)
74 {
75 UniChar *ucp;
76 iconv_t conv;
77 uconv_attribute_t attr;
78
79 conv = (iconv_t) malloc (sizeof (struct _iconv_t));
80 if (conv == NULL)
81 {
82 errno = ENOMEM;
83 return (iconv_t)(-1);
84 }
85
86 ucp = (UniChar *) alloca ((strlen (cp_from) + 2 + 1) * sizeof (UniChar));
87 cp_convert (cp_from, ucp);
88 if (UniCreateUconvObject (ucp, &conv->from))
89 {
90 free (conv);
91 errno = EINVAL;
92 return (iconv_t)(-1);
93 }
94
95 ucp = (UniChar *) alloca ((strlen (cp_to) + 2 + 1) * sizeof (UniChar));
96 cp_convert (cp_to, ucp);
97 if (UniCreateUconvObject (ucp, &conv->to))
98 {
99 UniFreeUconvObject (conv->from);
100 free (conv);
101 errno = EINVAL;
102 return (iconv_t)(-1);
103 }
104
105 UniQueryUconvObject (conv->from, &attr, sizeof (attr), NULL, NULL, NULL);
106 /* Do not treat 0x7f as a control character
107 (don't understand what it exactly means but without it MBCS prefix
108 character detection sometimes could fail (when 0x7f is a prefix)).
109 And don't treat the string as a path (the docs also don't explain
110 what it exactly means, but I'm pretty sure converted texts will
111 mostly not be paths). */
112 attr.converttype &= ~(CVTTYPE_CTRL7F | CVTTYPE_PATH);
113 UniSetUconvObject (conv->from, &attr);
114
115 return conv;
116 }
117
118 size_t
iconv(iconv_t conv,const char ** in,size_t * in_left,char ** out,size_t * out_left)119 iconv (iconv_t conv,
120 const char **in, size_t *in_left,
121 char **out, size_t *out_left)
122 {
123 int rc;
124 size_t sl = *in_left, nonid;
125 UniChar *ucs = (UniChar *) alloca (sl * sizeof (UniChar));
126 UniChar *orig_ucs = ucs;
127 size_t retval = 0;
128
129 rc = UniUconvToUcs (conv->from, (void **)in, in_left, &ucs, &sl, &retval);
130 if (rc)
131 goto error;
132 sl = ucs - orig_ucs;
133 ucs = orig_ucs;
134 /* UniUconvFromUcs will stop at first nul byte (huh? indeed?)
135 while we want ALL the bytes converted. */
136 #if 1
137 rc = UniUconvFromUcs (conv->to, &ucs, &sl, (void **)out, out_left, &nonid);
138 if (rc)
139 goto error;
140 retval += nonid;
141 #else
142 while (sl)
143 {
144 size_t usl = 0;
145 while (sl && (ucs[usl] != 0))
146 usl++, sl--;
147 rc = UniUconvFromUcs (conv->to, &ucs, &usl, (void **)out, out_left, &nonid);
148 if (rc)
149 goto error;
150 retval += nonid;
151 if (sl && *out_left)
152 {
153 *(*out)++ = 0;
154 (*out_left)--;
155 ucs++; sl--;
156 }
157 }
158 #endif
159 return 0;
160
161 error:
162 /* Convert OS/2 error code to errno. */
163 switch (rc)
164 {
165 case ULS_ILLEGALSEQUENCE:
166 errno = EILSEQ;
167 break;
168 case ULS_INVALID:
169 errno = EINVAL;
170 break;
171 case ULS_BUFFERFULL:
172 errno = E2BIG;
173 break;
174 default:
175 errno = EBADF;
176 break;
177 }
178 return (size_t)(-1);
179 }
180
181 int
iconv_close(iconv_t conv)182 iconv_close (iconv_t conv)
183 {
184 if (conv != (iconv_t)(-1))
185 {
186 UniFreeUconvObject (conv->to);
187 UniFreeUconvObject (conv->from);
188 free (conv);
189 }
190 return 0;
191 }
192