• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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