Move getenv_utf8() to wsutil.
[metze/wireshark/wip.git] / wsutil / unicode-utils.c
1 /* unicode-utils.c
2  * Unicode utility routines
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 2006 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifndef _WIN32
26 #error "This is only for Windows"
27 #endif
28
29 #include "unicode-utils.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 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     _snwprintf(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