~ubuntu-branches/ubuntu/vivid/freerdp/vivid

« back to all changes in this revision

Viewing changes to winpr/libwinpr/crt/unicode.c

  • Committer: Package Import Robot
  • Author(s): Iain Lane
  • Date: 2014-11-11 12:20:50 UTC
  • mfrom: (1.1.9) (9.1.17 sid)
  • Revision ID: package-import@ubuntu.com-20141111122050-wyr8hrnwco9fcmum
Tags: 1.1.0~git20140921.1.440916e+dfsg1-2ubuntu1
* Merge with Debian unstable, remaining changes
  - Disable ffmpeg support
* Disable gstreamer support, this relies on gstreamer 0.10 and we don't want
  to add any more deps on that.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * WinPR: Windows Portable Runtime
 
3
 * Unicode Conversion (CRT)
 
4
 *
 
5
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
 
6
 *
 
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
 
10
 *
 
11
 *     http://www.apache.org/licenses/LICENSE-2.0
 
12
 *
 
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.
 
18
 */
 
19
 
 
20
#ifdef HAVE_CONFIG_H
 
21
#include "config.h"
 
22
#endif
 
23
 
 
24
#include <errno.h>
 
25
#include <wctype.h>
 
26
 
 
27
#include <winpr/crt.h>
 
28
#include <winpr/print.h>
 
29
 
 
30
#ifndef _WIN32
 
31
 
 
32
#include "utf.h"
 
33
 
 
34
/**
 
35
 * Notes on cross-platform Unicode portability:
 
36
 *
 
37
 * Unicode has many possible Unicode Transformation Format (UTF) encodings,
 
38
 * where some of the most commonly used are UTF-8, UTF-16 and sometimes UTF-32.
 
39
 *
 
40
 * The number in the UTF encoding name (8, 16, 32) refers to the number of bits
 
41
 * per code unit. A code unit is the minimal bit combination that can represent
 
42
 * a unit of encoded text in the given encoding. For instance, UTF-8 encodes
 
43
 * the English alphabet using 8 bits (or one byte) each, just like in ASCII.
 
44
 *
 
45
 * However, the total number of code points (values in the Unicode codespace)
 
46
 * only fits completely within 32 bits. This means that for UTF-8 and UTF-16,
 
47
 * more than one code unit may be required to fully encode a specific value.
 
48
 * UTF-8 and UTF-16 are variable-width encodings, while UTF-32 is fixed-width.
 
49
 *
 
50
 * UTF-8 has the advantage of being backwards compatible with ASCII, and is
 
51
 * one of the most commonly used Unicode encoding.
 
52
 *
 
53
 * UTF-16 is used everywhere in the Windows API. The strategy employed by
 
54
 * Microsoft to provide backwards compatibility in their API was to create
 
55
 * an ANSI and a Unicode version of the same function, ending with A (ANSI)
 
56
 * and W (Wide character, or UTF-16 Unicode). In headers, the original
 
57
 * function name is replaced by a macro that defines to either the ANSI
 
58
 * or Unicode version based on the definition of the _UNICODE macro.
 
59
 *
 
60
 * UTF-32 has the advantage of being fixed width, but wastes a lot of space
 
61
 * for English text (4x more than UTF-8, 2x more than UTF-16).
 
62
 *
 
63
 * In C, wide character strings are often defined with the wchar_t type.
 
64
 * Many functions are provided to deal with those wide character strings,
 
65
 * such as wcslen (strlen equivalent) or wprintf (printf equivalent).
 
66
 *
 
67
 * This may lead to some confusion, since many of these functions exist
 
68
 * on both Windows and Linux, but they are *not* the same!
 
69
 *
 
70
 * This sample hello world is a good example:
 
71
 *
 
72
 * #include <wchar.h>
 
73
 *
 
74
 * wchar_t hello[] = L"Hello, World!\n";
 
75
 *
 
76
 * int main(int argc, char** argv)
 
77
 * {
 
78
 *      wprintf(hello);
 
79
 *      wprintf(L"sizeof(wchar_t): %d\n", sizeof(wchar_t));
 
80
 *      return 0;
 
81
 * }
 
82
 *
 
83
 * There is a reason why the sample prints the size of the wchar_t type:
 
84
 * On Windows, wchar_t is two bytes (UTF-16), while on most other systems
 
85
 * it is 4 bytes (UTF-32). This means that if you write code on Windows,
 
86
 * use L"" to define a string which is meant to be UTF-16 and not UTF-32,
 
87
 * you will have a little surprise when trying to port your code to Linux.
 
88
 *
 
89
 * Since the Windows API uses UTF-16, not UTF-32, WinPR defines the WCHAR
 
90
 * type to always be 2-bytes long and uses it instead of wchar_t. Do not
 
91
 * ever use wchar_t with WinPR unless you know what you are doing.
 
92
 *
 
93
 * As for L"", it is unfortunately unusable in a portable way, unless a
 
94
 * special option is passed to GCC to define wchar_t as being two bytes.
 
95
 * For string constants that must be UTF-16, it is a pain, but they can
 
96
 * be defined in a portable way like this:
 
97
 *
 
98
 * WCHAR hello[] = { 'H','e','l','l','o','\0' };
 
99
 *
 
100
 * Such strings cannot be passed to native functions like wcslen(), which
 
101
 * may expect a different wchar_t size. For this reason, WinPR provides
 
102
 * _wcslen, which expects UTF-16 WCHAR strings on all platforms.
 
103
 *
 
104
 */
 
105
 
 
106
/*
 
107
 * Conversion to Unicode (UTF-16)
 
108
 * MultiByteToWideChar: http://msdn.microsoft.com/en-us/library/windows/desktop/dd319072/
 
109
 *
 
110
 * cbMultiByte is an input size in bytes (BYTE)
 
111
 * cchWideChar is an output size in wide characters (WCHAR)
 
112
 *
 
113
 * Null-terminated UTF-8 strings:
 
114
 *
 
115
 * cchWideChar *cannot* be assumed to be cbMultiByte since UTF-8 is variable-width!
 
116
 *
 
117
 * Instead, obtain the required cchWideChar output size like this:
 
118
 * cchWideChar = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR) lpMultiByteStr, -1, NULL, 0);
 
119
 *
 
120
 * A value of -1 for cbMultiByte indicates that the input string is null-terminated,
 
121
 * and the null terminator *will* be processed. The size returned by MultiByteToWideChar
 
122
 * will therefore include the null terminator. Equivalent behavior can be obtained by
 
123
 * computing the length in bytes of the input buffer, including the null terminator:
 
124
 *
 
125
 * cbMultiByte = strlen((char*) lpMultiByteStr) + 1;
 
126
 *
 
127
 * An output buffer of the proper size can then be allocated:
 
128
 *
 
129
 * lpWideCharStr = (LPWSTR) malloc(cchWideChar * sizeof(WCHAR));
 
130
 *
 
131
 * Since cchWideChar is an output size in wide characters, the actual buffer size is:
 
132
 * (cchWideChar * sizeof(WCHAR)) or (cchWideChar * 2)
 
133
 *
 
134
 * Finally, perform the conversion:
 
135
 *
 
136
 * cchWideChar = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR) lpMultiByteStr, -1, lpWideCharStr, cchWideChar);
 
137
 *
 
138
 * The value returned by MultiByteToWideChar corresponds to the number of wide characters written
 
139
 * to the output buffer, and should match the value obtained on the first call to MultiByteToWideChar.
 
140
 *
 
141
 */
 
142
 
 
143
int MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr,
 
144
                int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar)
 
145
{
 
146
        int length;
 
147
        LPWSTR targetStart;
 
148
        const BYTE* sourceStart;
 
149
        ConversionResult result;
 
150
 
 
151
        /* If cbMultiByte is 0, the function fails */
 
152
 
 
153
        if (cbMultiByte == 0)
 
154
                return 0;
 
155
 
 
156
        /* If cbMultiByte is -1, the string is null-terminated */
 
157
 
 
158
        if (cbMultiByte == -1)
 
159
                cbMultiByte = strlen((char*) lpMultiByteStr) + 1;
 
160
 
 
161
        /*
 
162
         * if cchWideChar is 0, the function returns the required buffer size
 
163
         * in characters for lpWideCharStr and makes no use of the output parameter itself.
 
164
         */
 
165
 
 
166
        if (cchWideChar == 0)
 
167
        {
 
168
                sourceStart = (const BYTE*) lpMultiByteStr;
 
169
                targetStart = (WCHAR*) NULL;
 
170
 
 
171
                result = ConvertUTF8toUTF16(&sourceStart, &sourceStart[cbMultiByte],
 
172
                                &targetStart, NULL, strictConversion);
 
173
 
 
174
                length = targetStart - ((WCHAR*) NULL);
 
175
                cchWideChar = length;
 
176
        }
 
177
        else
 
178
        {
 
179
                sourceStart = (const BYTE*) lpMultiByteStr;
 
180
                targetStart = lpWideCharStr;
 
181
 
 
182
                result = ConvertUTF8toUTF16(&sourceStart, &sourceStart[cbMultiByte],
 
183
                                &targetStart, &targetStart[cchWideChar], strictConversion);
 
184
 
 
185
                length = targetStart - ((WCHAR*) lpWideCharStr);
 
186
                cchWideChar = length;
 
187
        }
 
188
 
 
189
        return cchWideChar;
 
190
}
 
191
 
 
192
/*
 
193
 * Conversion from Unicode (UTF-16)
 
194
 * WideCharToMultiByte: http://msdn.microsoft.com/en-us/library/windows/desktop/dd374130/
 
195
 *
 
196
 * cchWideChar is an input size in wide characters (WCHAR)
 
197
 * cbMultiByte is an output size in bytes (BYTE)
 
198
 *
 
199
 * Null-terminated UTF-16 strings:
 
200
 *
 
201
 * cbMultiByte *cannot* be assumed to be cchWideChar since UTF-8 is variable-width!
 
202
 *
 
203
 * Instead, obtain the required cbMultiByte output size like this:
 
204
 * cbMultiByte = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) lpWideCharStr, -1, NULL, 0, NULL, NULL);
 
205
 *
 
206
 * A value of -1 for cbMultiByte indicates that the input string is null-terminated,
 
207
 * and the null terminator *will* be processed. The size returned by WideCharToMultiByte
 
208
 * will therefore include the null terminator. Equivalent behavior can be obtained by
 
209
 * computing the length in bytes of the input buffer, including the null terminator:
 
210
 *
 
211
 * cchWideChar = _wcslen((WCHAR*) lpWideCharStr) + 1;
 
212
 *
 
213
 * An output buffer of the proper size can then be allocated:
 
214
 * lpMultiByteStr = (LPSTR) malloc(cbMultiByte);
 
215
 *
 
216
 * Since cbMultiByte is an output size in bytes, it is the same as the buffer size
 
217
 *
 
218
 * Finally, perform the conversion:
 
219
 *
 
220
 * cbMultiByte = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) lpWideCharStr, -1, lpMultiByteStr, cbMultiByte, NULL, NULL);
 
221
 *
 
222
 * The value returned by WideCharToMultiByte corresponds to the number of bytes written
 
223
 * to the output buffer, and should match the value obtained on the first call to WideCharToMultiByte.
 
224
 *
 
225
 */
 
226
 
 
227
int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
 
228
                LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar)
 
229
{
 
230
        int length;
 
231
        BYTE* targetStart;
 
232
        const WCHAR* sourceStart;
 
233
        ConversionResult result;
 
234
 
 
235
        /* If cchWideChar is 0, the function fails */
 
236
 
 
237
        if (cchWideChar == 0)
 
238
                return 0;
 
239
 
 
240
        /* If cchWideChar is -1, the string is null-terminated */
 
241
 
 
242
        if (cchWideChar == -1)
 
243
                cchWideChar = _wcslen(lpWideCharStr) + 1;
 
244
 
 
245
        /*
 
246
         * if cbMultiByte is 0, the function returns the required buffer size
 
247
         * in bytes for lpMultiByteStr and makes no use of the output parameter itself.
 
248
         */
 
249
 
 
250
        if (cbMultiByte == 0)
 
251
        {
 
252
                sourceStart = (WCHAR*) lpWideCharStr;
 
253
                targetStart = (BYTE*) NULL;
 
254
 
 
255
                result = ConvertUTF16toUTF8(&sourceStart, &sourceStart[cchWideChar],
 
256
                                &targetStart, NULL, strictConversion);
 
257
 
 
258
                length = targetStart - ((BYTE*) NULL);
 
259
                cbMultiByte = length;
 
260
        }
 
261
        else
 
262
        {
 
263
                sourceStart = (WCHAR*) lpWideCharStr;
 
264
                targetStart = (BYTE*) lpMultiByteStr;
 
265
 
 
266
                result = ConvertUTF16toUTF8(&sourceStart, &sourceStart[cchWideChar],
 
267
                                &targetStart, &targetStart[cbMultiByte], strictConversion);
 
268
 
 
269
                length = targetStart - ((BYTE*) lpMultiByteStr);
 
270
                cbMultiByte = length;
 
271
        }
 
272
 
 
273
        return cbMultiByte;
 
274
}
 
275
 
 
276
#endif
 
277
 
 
278
int ConvertToUnicode(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr,
 
279
                int cbMultiByte, LPWSTR* lpWideCharStr, int cchWideChar)
 
280
{
 
281
        int status;
 
282
        BOOL allocate = FALSE;
 
283
 
 
284
        if (!lpMultiByteStr)
 
285
                return 0;
 
286
 
 
287
        if (!lpWideCharStr)
 
288
                return 0;
 
289
 
 
290
        if (cbMultiByte == -1)
 
291
                cbMultiByte = strlen(lpMultiByteStr) + 1;
 
292
 
 
293
        if (cchWideChar == 0)
 
294
        {
 
295
                cchWideChar = MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0);
 
296
                allocate = TRUE;
 
297
        }
 
298
 
 
299
        if (cchWideChar < 1)
 
300
                return 0;
 
301
 
 
302
        if (!(*lpWideCharStr))
 
303
                allocate = TRUE;
 
304
 
 
305
        if (allocate)
 
306
                *lpWideCharStr = (LPWSTR) malloc(cchWideChar * sizeof(WCHAR));
 
307
 
 
308
        status = MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, *lpWideCharStr, cchWideChar);
 
309
 
 
310
        if (status != cchWideChar)
 
311
                status = 0;
 
312
 
 
313
        return status;
 
314
}
 
315
 
 
316
int ConvertFromUnicode(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
 
317
                LPSTR* lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar)
 
318
{
 
319
        int status;
 
320
        BOOL allocate = FALSE;
 
321
 
 
322
        if (!lpWideCharStr)
 
323
                return 0;
 
324
 
 
325
        if (!lpMultiByteStr)
 
326
                return 0;
 
327
 
 
328
        if (cchWideChar == -1)
 
329
                cchWideChar = _wcslen(lpWideCharStr) + 1;
 
330
 
 
331
        if (cbMultiByte == 0)
 
332
        {
 
333
                cbMultiByte = WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, NULL, NULL);
 
334
                allocate = TRUE;
 
335
        }
 
336
 
 
337
        if (cbMultiByte < 1)
 
338
                return 0;
 
339
 
 
340
        if (!(*lpMultiByteStr))
 
341
                allocate = TRUE;
 
342
 
 
343
        if (allocate)
 
344
        {
 
345
                *lpMultiByteStr = (LPSTR) malloc(cbMultiByte + 1);
 
346
                ZeroMemory(*lpMultiByteStr, cbMultiByte + 1);
 
347
        }
 
348
 
 
349
        status = WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar,
 
350
                        *lpMultiByteStr, cbMultiByte, lpDefaultChar, lpUsedDefaultChar);
 
351
 
 
352
        if (status != cbMultiByte)
 
353
                status = 0;
 
354
 
 
355
        return status;
 
356
}