replace SPDX identifier GPL-2.0+ with GPL-2.0-or-later.
[metze/wireshark/wip.git] / wsutil / unicode-utils.c
1 /* unicode-utils.c
2  * Unicode utility routines
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 2006 Gerald Combs
7  *
8  * SPDX-License-Identifier: GPL-2.0-or-later
9  */
10
11 #include "unicode-utils.h"
12
13 int
14 ws_utf8_char_len(guint8 ch)
15 {
16   if (ch >= 0xfe) return -1;
17   if (ch >= 0xfc) return  6;
18   if (ch >= 0xf8) return  5;
19   if (ch >= 0xf0) return  4;
20   if (ch >= 0xe0) return  3;
21   if (ch >= 0xc0) return  2;
22   else            return  1;
23 }
24
25
26 #ifdef _WIN32
27
28 #include <shellapi.h>
29 #include <strsafe.h>
30
31 /** @file
32  * Unicode utilities (internal interface)
33  *
34  * We define UNICODE and _UNICODE under Windows.  This means that
35  * Windows SDK routines expect UTF-16 strings, in contrast to newer
36  * versions of Glib and GTK+ which expect UTF-8.  This module provides
37  * convenience routines for converting between UTF-8 and UTF-16.
38  */
39
40 #define INITIAL_UTFBUF_SIZE 128
41
42 /*
43  * XXX - Should we use g_utf8_to_utf16() and g_utf16_to_utf8()
44  * instead?  The goal of the functions below was to provide simple
45  * wrappers for UTF-8 <-> UTF-16 conversion without making the
46  * caller worry about freeing up memory afterward.
47  */
48
49 /* Convert from UTF-8 to UTF-16. */
50 const wchar_t *
51 utf_8to16(const char *utf8str)
52 {
53   static wchar_t *utf16buf[3];
54   static int utf16buf_len[3];
55   static int idx;
56
57   if (utf8str == NULL)
58     return NULL;
59
60   idx = (idx + 1) % 3;
61
62   /*
63    * Allocate the buffer if it's not already allocated.
64    */
65   if (utf16buf[idx] == NULL) {
66     utf16buf_len[idx] = INITIAL_UTFBUF_SIZE;
67     utf16buf[idx] = g_malloc(utf16buf_len[idx] * sizeof(wchar_t));
68   }
69
70   while (MultiByteToWideChar(CP_UTF8, 0, utf8str,
71       -1, NULL, 0) >= utf16buf_len[idx]) {
72     /*
73      * Double the buffer's size if it's not big enough.
74      * The size of the buffer starts at 128, so doubling its size
75      * adds at least another 128 bytes, which is more than enough
76      * for one more character plus a terminating '\0'.
77      */
78     utf16buf_len[idx] *= 2;
79     utf16buf[idx] = g_realloc(utf16buf[idx], utf16buf_len[idx] * sizeof(wchar_t));
80   }
81
82   if (MultiByteToWideChar(CP_UTF8, 0, utf8str,
83       -1, utf16buf[idx], utf16buf_len[idx]) == 0)
84     return NULL;
85
86   return utf16buf[idx];
87 }
88
89 void
90 utf_8to16_snprintf(TCHAR *utf16buf, gint utf16buf_len, const gchar* fmt, ...)
91 {
92   va_list ap;
93   gchar* dst;
94
95   va_start(ap,fmt);
96   dst = g_strdup_vprintf(fmt, ap);
97   va_end(ap);
98
99   StringCchPrintf(utf16buf, utf16buf_len, _T("%s"), utf_8to16(dst));
100
101   g_free(dst);
102 }
103
104 /* Convert from UTF-16 to UTF-8. */
105 gchar *
106 utf_16to8(const wchar_t *utf16str)
107 {
108   static gchar *utf8buf[3];
109   static int utf8buf_len[3];
110   static int idx;
111
112   if (utf16str == NULL)
113     return NULL;
114
115   idx = (idx + 1) % 3;
116
117   /*
118    * Allocate the buffer if it's not already allocated.
119    */
120   if (utf8buf[idx] == NULL) {
121     utf8buf_len[idx] = INITIAL_UTFBUF_SIZE;
122     utf8buf[idx] = g_malloc(utf8buf_len[idx]);
123   }
124
125   while (WideCharToMultiByte(CP_UTF8, 0, utf16str, -1,
126       NULL, 0, NULL, NULL) >= utf8buf_len[idx]) {
127     /*
128      * Double the buffer's size if it's not big enough.
129      * The size of the buffer starts at 128, so doubling its size
130      * adds at least another 128 bytes, which is more than enough
131      * for one more character plus a terminating '\0'.
132      */
133     utf8buf_len[idx] *= 2;
134     utf8buf[idx] = g_realloc(utf8buf[idx], utf8buf_len[idx]);
135   }
136
137   if (WideCharToMultiByte(CP_UTF8, 0, utf16str, -1,
138       utf8buf[idx], utf8buf_len[idx], NULL, NULL) == 0)
139     return NULL;
140
141   return utf8buf[idx];
142 }
143
144 /* Convert our argument list from UTF-16 to UTF-8. */
145 void
146 arg_list_utf_16to8(int argc, char *argv[]) {
147   LPWSTR              *wc_argv;
148   int                  wc_argc, i;
149
150   /* Convert our arg list to UTF-8. */
151   wc_argv = CommandLineToArgvW(GetCommandLineW(), &wc_argc);
152   if (wc_argv && wc_argc == argc) {
153     for (i = 0; i < argc; i++) {
154       argv[i] = g_utf16_to_utf8(wc_argv[i], -1, NULL, NULL, NULL);
155     }
156   } /* XXX else bail because something is horribly, horribly wrong? */
157   LocalFree(wc_argv);
158 }
159
160 #endif
161
162 /*
163  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
164  *
165  * Local Variables:
166  * c-basic-offset: 2
167  * tab-width: 8
168  * indent-tabs-mode: nil
169  * End:
170  *
171  * ex: set shiftwidth=2 tabstop=8 expandtab:
172  * :indentSize=2:tabSize=8:noTabs=true:
173  */