2 * FreeRDP: A Remote Desktop Protocol Client
5 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
22 #include <freerdp/utils/memory.h>
24 #include <freerdp/utils/unicode.h>
26 /* Convert pin/in_len from WINDOWS_CODEPAGE - return like xstrdup, 0-terminated */
28 char* freerdp_uniconv_in(UNICONV* uniconv, unsigned char* pin, size_t in_len)
30 unsigned char *conv_pin = pin;
31 size_t conv_in_len = in_len;
32 char *pout = xmalloc(in_len * 2 + 1), *conv_pout = pout;
33 size_t conv_out_len = in_len * 2;
36 if (iconv(uniconv->in_iconv_h, (ICONV_CONST char **) &conv_pin, &conv_in_len, &conv_pout, &conv_out_len) == (size_t) - 1)
38 /* TODO: xrealloc if conv_out_len == 0 - it shouldn't be needed, but would allow a smaller initial alloc ... */
39 printf("freerdp_uniconv_in: iconv failure\n");
43 while (conv_in_len >= 2)
47 wc = (unsigned int)(unsigned char)(*conv_pin++);
48 wc += ((unsigned int)(unsigned char)(*conv_pin++)) << 8;
51 if (wc >= 0xD800 && wc <= 0xDFFF && conv_in_len >= 2)
53 /* Code points U+10000 to U+10FFFF using surrogate pair */
54 wc = ((wc - 0xD800) << 10) + 0x10000;
55 wc += (unsigned int)(unsigned char)(*conv_pin++);
56 wc += ((unsigned int)(unsigned char)(*conv_pin++) - 0xDC) << 8;
62 *conv_pout++ = (char)wc;
65 else if (wc <= 0x07FF)
67 *conv_pout++ = (char)(0xC0 + (wc >> 6));
68 *conv_pout++ = (char)(0x80 + (wc & 0x3F));
71 else if (wc <= 0xFFFF)
73 *conv_pout++ = (char)(0xE0 + (wc >> 12));
74 *conv_pout++ = (char)(0x80 + ((wc >> 6) & 0x3F));
75 *conv_pout++ = (char)(0x80 + (wc & 0x3F));
80 *conv_pout++ = (char)(0xF0 + (wc >> 18));
81 *conv_pout++ = (char)(0x80 + ((wc >> 12) & 0x3F));
82 *conv_pout++ = (char)(0x80 + ((wc >> 6) & 0x3F));
83 *conv_pout++ = (char)(0x80 + (wc & 0x3F));
91 printf("freerdp_uniconv_in: conversion failure - %d chars left\n", (int) conv_in_len);
98 /* Convert str from DEFAULT_CODEPAGE to WINDOWS_CODEPAGE and return buffer like xstrdup.
99 * Buffer is 0-terminated but that is not included in the returned length. */
101 char* freerdp_uniconv_out(UNICONV *uniconv, char *str, size_t *pout_len)
118 pout0 = xmalloc(obl + 2);
122 if (iconv(uniconv->out_iconv_h, (ICONV_CONST char **) &pin, &ibl, &pout, &obl) == (size_t) - 1)
124 printf("freerdp_uniconv_out: iconv() error\n");
128 while ((ibl > 0) && (obl > 0))
132 wc = (unsigned int)(unsigned char)(*pin++);
136 wc = (wc - 0xF0) << 18;
137 wc += ((unsigned int)(unsigned char)(*pin++) - 0x80) << 12;
138 wc += ((unsigned int)(unsigned char)(*pin++) - 0x80) << 6;
139 wc += ((unsigned int)(unsigned char)(*pin++) - 0x80);
144 wc = (wc - 0xE0) << 12;
145 wc += ((unsigned int)(unsigned char)(*pin++) - 0x80) << 6;
146 wc += ((unsigned int)(unsigned char)(*pin++) - 0x80);
151 wc = (wc - 0xC0) << 6;
152 wc += ((unsigned int)(unsigned char)(*pin++) - 0x80);
158 *pout++ = (char)(wc & 0xFF);
159 *pout++ = (char)(wc >> 8);
165 *pout++ = (char)((wc >> 10) & 0xFF);
166 *pout++ = (char)((wc >> 18) + 0xD8);
167 *pout++ = (char)(wc & 0xFF);
168 *pout++ = (char)(((wc >> 8) & 0x03) + 0xDC);
176 printf("freerdp_uniconv_out: string not fully converted - %d chars left\n", (int) ibl);
179 *pout_len = pout - pout0;
180 *pout++ = 0; /* Add extra double zero termination */
186 /* Uppercase a unicode string */
188 void freerdp_uniconv_uppercase(UNICONV *uniconv, char *wstr, int length)
192 unsigned int wc, uwc;
194 p = (unsigned char*)wstr;
195 for (i = 0; i < length; i++)
197 wc = (unsigned int)(*p);
198 wc += (unsigned int)(*(p + 1)) << 8;
203 *(p + 1) = (uwc >> 8) & 0xFF;
209 UNICONV* freerdp_uniconv_new()
211 UNICONV *uniconv = xnew(UNICONV);
215 uniconv->in_iconv_h = iconv_open(DEFAULT_CODEPAGE, WINDOWS_CODEPAGE);
218 printf("Error opening iconv converter to %s from %s\n", DEFAULT_CODEPAGE, WINDOWS_CODEPAGE);
220 uniconv->out_iconv_h = iconv_open(WINDOWS_CODEPAGE, DEFAULT_CODEPAGE);
223 printf("Error opening iconv converter to %s from %s\n", WINDOWS_CODEPAGE, DEFAULT_CODEPAGE);
230 void freerdp_uniconv_free(UNICONV *uniconv)
235 iconv_close(uniconv->in_iconv_h);
236 iconv_close(uniconv->out_iconv_h);