fixed OpenBSD 4.8 compatibility issues (non-UNICODE build only)
[public/netxms.git] / src / libnetxms / unicode.cpp
CommitLineData
5039dede 1/*
284b15a4 2 ** NetXMS - Network Management System
fe8ea784 3 ** Copyright (C) 2003-2016 Raden Solutions
284b15a4
VP
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU Lesser General Public License as published
7 ** by the Free Software Foundation; either version 3 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU Lesser General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** File: unicode.cpp
20 **
21 **/
5039dede
AK
22
23#include "libnetxms.h"
7768852d 24#include "unicode_cc.h"
c7c23e6d 25#include <nxcrypto.h>
5039dede 26
29dc8792 27/**
bd96aa53 28 * Default codepage
29dc8792 29 */
7768852d 30char g_cpDefault[MAX_CODEPAGE_LEN] = ICONV_DEFAULT_CODEPAGE;
5039dede 31
29dc8792
VP
32/**
33 * Set application's default codepage
34 */
7768852d 35bool LIBNETXMS_EXPORTABLE SetDefaultCodepage(const char *cp)
5039dede 36{
7768852d 37 bool rc;
5039dede 38#if HAVE_ICONV && !defined(__DISABLE_ICONV)
284b15a4 39 iconv_t cd;
5039dede 40
284b15a4 41 cd = iconv_open(cp, "UTF-8");
7768852d 42 if (cd != (iconv_t)(-1))
284b15a4
VP
43 {
44 iconv_close(cd);
7b45b90d 45#endif
7768852d
VK
46 strncpy(g_cpDefault, cp, MAX_CODEPAGE_LEN);
47 g_cpDefault[MAX_CODEPAGE_LEN - 1] = 0;
48 rc = true;
5039dede 49#if HAVE_ICONV && !defined(__DISABLE_ICONV)
284b15a4
VP
50 }
51 else
52 {
7768852d 53 rc = false;
284b15a4 54 }
5039dede 55#endif
284b15a4 56 return rc;
5039dede
AK
57}
58
7768852d
VK
59#ifndef UNICODE_UCS2
60
61/**
62 * Calculate length of UCS-2 character string
63 */
64size_t LIBNETXMS_EXPORTABLE ucs2_strlen(const UCS2CHAR *s)
65{
66 size_t len = 0;
67 const UCS2CHAR *curr = s;
68 while(*curr++)
69 len++;
70 return len;
71}
72
73#endif
74
75#ifndef UNICODE_UCS4
76
77/**
78 * Calculate length of UCS-4 character string
79 */
80size_t LIBNETXMS_EXPORTABLE ucs4_strlen(const UCS4CHAR *s)
81{
82 size_t len = 0;
83 const UCS4CHAR *curr = s;
84 while(*curr++)
85 len++;
86 return len;
87}
88
89#endif
90
91#if !HAVE_WCSLEN
5039dede 92
13469050
VP
93/**
94 * Calculate length of wide character string
95 */
7768852d
VK
96size_t LIBNETXMS_EXPORTABLE wcslen(const WCHAR *s)
97{
98 size_t len = 0;
99 const WCHAR *curr = s;
100 while(*curr++)
101 len++;
102 return len;
103}
104
105#endif
106
107#ifndef UNICODE_UCS2
108
109/**
110 * Duplicate UCS-2 character string
111 */
112UCS2CHAR LIBNETXMS_EXPORTABLE *ucs2_strdup(const UCS2CHAR *src)
5039dede 113{
7768852d
VK
114 return (UCS2CHAR *)nx_memdup(src, (ucs2_strlen(src) + 1) * sizeof(UCS2CHAR));
115}
116
117#endif
118
119#ifndef UNICODE_UCS4
5039dede 120
7768852d
VK
121/**
122 * Duplicate UCS-4 character string
123 */
124UCS4CHAR LIBNETXMS_EXPORTABLE *ucs4_strdup(const UCS4CHAR *src)
125{
126 return (UCS4CHAR *)nx_memdup(src, (ucs4_strlen(src) + 1) * sizeof(UCS4CHAR));
5039dede
AK
127}
128
129#endif
130
7768852d 131#if !UNICODE_UCS2
5039dede 132
29dc8792 133/**
7768852d 134 * Copy UCS-2 character string with length limitation
29dc8792 135 */
7768852d 136UCS2CHAR LIBNETXMS_EXPORTABLE *ucs2_strncpy(UCS2CHAR *dest, const UCS2CHAR *src, size_t n)
5039dede 137{
7768852d
VK
138 size_t len = ucs2_strlen(src) + 1;
139 if (len > n)
140 len = n;
141 memcpy(dest, src, len * sizeof(UCS2CHAR));
142 return dest;
5039dede
AK
143}
144
145#endif
146
7768852d 147#if !UNICODE_UCS4
5039dede 148
29dc8792 149/**
7768852d 150 * Copy UCS-2 character string with length limitation
29dc8792 151 */
7768852d 152UCS4CHAR LIBNETXMS_EXPORTABLE *ucs4_strncpy(UCS4CHAR *dest, const UCS4CHAR *src, size_t n)
5039dede 153{
7768852d
VK
154 size_t len = ucs4_strlen(src) + 1;
155 if (len > n)
156 len = n;
157 memcpy(dest, src, len * sizeof(UCS4CHAR));
158 return dest;
159}
5039dede 160
7768852d
VK
161#endif
162
163#if !HAVE_WCSNCPY
164
165/**
166 * Copy UCS-2 character string with length limitation
167 */
168WCHAR LIBNETXMS_EXPORTABLE *wcsncpy(WCHAR *dest, const WCHAR *src, size_t n)
169{
170 size_t len = wcslen(src) + 1;
171 if (len > n)
172 len = n;
173 memcpy(dest, src, len * sizeof(WCHAR));
174 return dest;
5039dede
AK
175}
176
177#endif
178
7768852d
VK
179#ifndef _WIN32
180
9d4a020a 181/**
305e2330 182 * Convert UNICODE string to single-byte string using simple byte copy (works for ASCII only)
9d4a020a 183 */
219565b2 184static int WideCharToMultiByteSimpleCopy(int iCodePage, DWORD dwFlags, const WCHAR *pWideCharStr,
305e2330 185 int cchWideChar, char *pByteStr, int cchByteChar, char *pDefaultChar, BOOL *pbUsedDefChar)
29dc8792 186{
045845e5
VK
187 const WCHAR *pSrc;
188 char *pDest;
189 int iPos, iSize;
190
5039dede
AK
191 iSize = (cchWideChar == -1) ? wcslen(pWideCharStr) : cchWideChar;
192 if (iSize >= cchByteChar)
193 iSize = cchByteChar - 1;
194 for(pSrc = pWideCharStr, iPos = 0, pDest = pByteStr; iPos < iSize; iPos++, pSrc++, pDest++)
767f18f6 195 *pDest = (*pSrc < 128) ? (char)(*pSrc) : '?';
5039dede 196 *pDest = 0;
29dc8792 197
5039dede 198 return iSize;
29dc8792 199}
5039dede 200
5d0d2fc6
VK
201#ifndef __DISABLE_ICONV
202
305e2330
VK
203/**
204 * Convert UNICODE string to single-byte string using iconv
205 */
219565b2 206static int WideCharToMultiByteIconv(int iCodePage, DWORD dwFlags, const WCHAR *pWideCharStr, int cchWideChar,
305e2330 207 char *pByteStr, int cchByteChar, char *pDefaultChar, BOOL *pbUsedDefChar)
29dc8792
VP
208{
209 iconv_t cd;
210 int nRet;
211 const char *inbuf;
212 char *outbuf;
213 size_t inbytes, outbytes;
214 char cp[MAX_CODEPAGE_LEN + 16];
215
7768852d 216 strcpy(cp, g_cpDefault);
29dc8792
VP
217#if HAVE_ICONV_IGNORE
218 strcat(cp, "//IGNORE");
219#endif /* HAVE_ICONV_IGNORE */
13469050 220
bd96aa53 221 cd = IconvOpen(iCodePage == CP_UTF8 ? "UTF-8" : cp, UNICODE_CODEPAGE_NAME);
817dce5b 222 if (cd == (iconv_t)(-1))
29dc8792 223 {
817dce5b 224 return WideCharToMultiByteSimpleCopy(iCodePage, dwFlags, pWideCharStr, cchWideChar, pByteStr, cchByteChar, pDefaultChar, pbUsedDefChar);
29dc8792
VP
225 }
226
817dce5b 227 inbuf = (const char *)pWideCharStr;
29dc8792
VP
228 inbytes = ((cchWideChar == -1) ? wcslen(pWideCharStr) + 1 : cchWideChar) * sizeof(WCHAR);
229 outbuf = pByteStr;
230 outbytes = cchByteChar;
817dce5b 231 nRet = iconv(cd, (ICONV_CONST char **)&inbuf, &inbytes, &outbuf, &outbytes);
bd96aa53 232 IconvClose(cd);
29dc8792
VP
233 if (nRet == -1)
234 {
235 if (errno == EILSEQ)
236 {
237 nRet = cchByteChar - outbytes;
238 }
239 else
240 {
241 nRet = 0;
242 }
243 }
244 else
245 {
246 nRet = cchByteChar - outbytes;
247 }
219565b2 248 if (outbytes > 0)
29dc8792
VP
249 {
250 *outbuf = 0;
251 }
252
253 return nRet;
254}
255
5d0d2fc6
VK
256#endif
257
305e2330
VK
258/**
259 * Convert UNICODE string to single-byte string
260 */
29dc8792 261int LIBNETXMS_EXPORTABLE WideCharToMultiByte(int iCodePage, DWORD dwFlags, const WCHAR *pWideCharStr, int cchWideChar,
305e2330 262 char *pByteStr, int cchByteChar, char *pDefaultChar, BOOL *pbUsedDefChar)
29dc8792
VP
263{
264#if HAVE_ICONV && !defined(__DISABLE_ICONV)
13469050
VP
265 // Calculate required length. Because iconv cannot calculate
266 // resulting multibyte string length, assume the worst case - 3 bytes
267 // per character for UTF-8 and 2 bytes per character for other encodings
268 if (cchByteChar == 0)
269 {
270 return wcslen(pWideCharStr) * (iCodePage == CP_UTF8 ? 3 : 2) + 1;
271 }
272
fca654e6 273 return WideCharToMultiByteIconv(iCodePage, dwFlags, pWideCharStr, cchWideChar, pByteStr, cchByteChar, pDefaultChar, pbUsedDefChar);
29dc8792 274#else
13469050
VP
275 if (cchByteChar == 0)
276 {
277 return wcslen(pWideCharStr) + 1;
278 }
279
5d0d2fc6 280 return WideCharToMultiByteSimpleCopy(iCodePage, dwFlags, pWideCharStr, cchWideChar, pByteStr, cchByteChar, pDefaultChar, pbUsedDefChar);
29dc8792 281#endif
5039dede
AK
282}
283
9d4a020a 284/**
305e2330 285 * Convert single-byte to UNICODE string using simple byte copy (works correctly for ASCII only)
9d4a020a 286 */
219565b2 287static int MultiByteToWideCharSimpleCopy(int iCodePage, DWORD dwFlags, const char *pByteStr, int cchByteChar, WCHAR *pWideCharStr, int cchWideChar)
13469050
VP
288{
289 const char *pSrc;
290 WCHAR *pDest;
291 int iPos, iSize;
5039dede 292
13469050
VP
293 iSize = (cchByteChar == -1) ? strlen(pByteStr) : cchByteChar;
294 if (iSize >= cchWideChar)
295 iSize = cchWideChar - 1;
296 for(pSrc = pByteStr, iPos = 0, pDest = pWideCharStr; iPos < iSize; iPos++, pSrc++, pDest++)
b88e1c3e 297 *pDest = (((BYTE)*pSrc & 0x80) == 0) ? (WCHAR)(*pSrc) : L'?';
13469050 298 *pDest = 0;
5039dede 299
13469050
VP
300 return iSize;
301}
5039dede 302
5d0d2fc6
VK
303#ifndef __DISABLE_ICONV
304
305e2330
VK
305/**
306 * Convert single-byte to UNICODE string using iconv
307 */
219565b2 308static int MultiByteToWideCharIconv(int iCodePage, DWORD dwFlags, const char *pByteStr, int cchByteChar, WCHAR *pWideCharStr, int cchWideChar)
13469050
VP
309{
310 iconv_t cd;
311 int nRet;
312 const char *inbuf;
313 char *outbuf;
314 size_t inbytes, outbytes;
5039dede 315
7768852d 316 cd = IconvOpen(UNICODE_CODEPAGE_NAME, iCodePage == CP_UTF8 ? "UTF-8" : g_cpDefault);
817dce5b 317 if (cd == (iconv_t)(-1))
13469050 318 {
7768852d 319 return MultiByteToWideCharSimpleCopy(iCodePage, dwFlags, pByteStr, cchByteChar, pWideCharStr, cchWideChar);
29dc8792
VP
320 }
321
7768852d
VK
322 inbuf = pByteStr;
323 inbytes = (cchByteChar == -1) ? strlen(pByteStr) + 1 : cchByteChar;
324 outbuf = (char *)pWideCharStr;
325 outbytes = cchWideChar * sizeof(WCHAR);
326 nRet = iconv(cd, (ICONV_CONST char **)&inbuf, &inbytes, &outbuf, &outbytes);
bd96aa53 327 IconvClose(cd);
13469050 328
7768852d 329 if (nRet == -1)
29dc8792
VP
330 {
331 if (errno == EILSEQ)
332 {
7768852d 333 nRet = (cchWideChar * sizeof(WCHAR) - outbytes) / sizeof(WCHAR);
29dc8792
VP
334 }
335 else
336 {
7768852d 337 nRet = 0;
29dc8792
VP
338 }
339 }
7768852d
VK
340 else
341 {
342 nRet = (cchWideChar * sizeof(WCHAR) - outbytes) / sizeof(WCHAR);
343 }
344 if (((char *) outbuf - (char *) pWideCharStr > sizeof(WCHAR)) && (*pWideCharStr == 0xFEFF))
29dc8792
VP
345 {
346 // Remove UNICODE byte order indicator if presented
7768852d
VK
347 memmove(pWideCharStr, &pWideCharStr[1], (char *) outbuf - (char *) pWideCharStr - sizeof(WCHAR));
348 outbuf -= sizeof(WCHAR);
349 nRet--;
29dc8792 350 }
7768852d 351 if (outbytes >= sizeof(WCHAR))
29dc8792 352 {
7768852d 353 *((WCHAR *)outbuf) = 0;
29dc8792
VP
354 }
355
7768852d 356 return nRet;
13469050 357}
5039dede 358
7768852d 359#endif /* __DISABLE_ICONV */
5d0d2fc6 360
7768852d
VK
361/**
362 * Convert single-byte to UNICODE string
363 */
364int LIBNETXMS_EXPORTABLE MultiByteToWideChar(int iCodePage, DWORD dwFlags, const char *pByteStr, int cchByteChar, WCHAR *pWideCharStr, int cchWideChar)
13469050 365{
7768852d
VK
366 if (cchWideChar == 0)
367 {
368 return strlen(pByteStr) + 1;
369 }
370
13469050 371#if HAVE_ICONV && !defined(__DISABLE_ICONV)
7768852d 372 return MultiByteToWideCharIconv(iCodePage, dwFlags, pByteStr, cchByteChar, pWideCharStr, cchWideChar);
13469050 373#else
7768852d 374 return MultiByteToWideCharSimpleCopy(iCodePage, dwFlags, pByteStr, cchByteChar, pWideCharStr, cchWideChar);
5039dede
AK
375#endif
376}
377
7768852d 378#endif /* _WIN32 */
9fddfb91
VK
379
380/**
7768852d
VK
381 * Convert multibyte string to wide string using current LC_CTYPE setting and
382 * allocating wide string dynamically
9fddfb91 383 */
7768852d 384WCHAR LIBNETXMS_EXPORTABLE *WideStringFromMBStringSysLocale(const char *pszString)
39945910 385{
7768852d
VK
386#ifdef _WIN32
387 return WideStringFromMBString(pszString);
388#else
389 if (pszString == NULL)
390 return NULL;
391 int nLen = (int)strlen(pszString) + 1;
392 WCHAR *pwszOut = (WCHAR *) malloc(nLen * sizeof(WCHAR));
393#if HAVE_MBSTOWCS
394 mbstowcs(pwszOut, pszString, nLen);
395#else
396 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszString, -1, pwszOut, nLen);
397#endif
398 return pwszOut;
399#endif
400}
39945910 401
7768852d
VK
402/**
403 * Convert multibyte string to wide string using current codepage and
404 * allocating wide string dynamically
405 */
406WCHAR LIBNETXMS_EXPORTABLE *WideStringFromMBString(const char *src)
407{
408 if (src == NULL)
409 return NULL;
410 int len = (int)strlen(src) + 1;
411 WCHAR *out = (WCHAR *)malloc(len * sizeof(WCHAR));
412 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, src, -1, out, len);
413 return out;
39945910 414}
39945910 415
9fddfb91 416/**
7768852d 417 * Convert wide string to UTF8 string allocating wide string dynamically
9fddfb91 418 */
7768852d 419WCHAR LIBNETXMS_EXPORTABLE *WideStringFromUTF8String(const char *pszString)
39945910 420{
7768852d
VK
421 if (pszString == NULL)
422 return NULL;
423 int nLen = (int)strlen(pszString) + 1;
424 WCHAR *pwszOut = (WCHAR *) malloc(nLen * sizeof(WCHAR));
425 MultiByteToWideChar(CP_UTF8, 0, pszString, -1, pwszOut, nLen);
426 return pwszOut;
427}
39945910 428
7768852d
VK
429/**
430 * Convert wide string to multibyte string using current codepage and
431 * allocating multibyte string dynamically
432 */
433char LIBNETXMS_EXPORTABLE *MBStringFromWideString(const WCHAR *pwszString)
434{
435 if (pwszString == NULL)
436 return NULL;
437 int nLen = (int)wcslen(pwszString) + 1;
438 char *pszOut = (char *)malloc(nLen);
439 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, pwszString, -1, pszOut, nLen, NULL, NULL);
284b15a4 440 return pszOut;
39945910 441}
13469050 442
ebe98224 443/**
7768852d
VK
444 * Convert wide string to multibyte string using current LC_CTYPE setting and
445 * allocating multibyte string dynamically
ebe98224 446 */
7768852d 447char LIBNETXMS_EXPORTABLE *MBStringFromWideStringSysLocale(const WCHAR *pwszString)
ebe98224 448{
7768852d
VK
449#ifdef _WIN32
450 return MBStringFromWideString(pwszString);
451#else
452 if (pwszString == NULL)
453 return NULL;
1c2a6492
VK
454 size_t len = wcslen(pwszString) * 3 + 1; // add extra bytes in case of UTF-8 as target encoding
455 char *out = (char *)malloc(len);
7768852d 456#if HAVE_WCSTOMBS
1c2a6492 457 wcstombs(out, pwszString, len);
7768852d 458#else
1c2a6492 459 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, pwszString, -1, out, (int)len, NULL, NULL);
7768852d 460#endif
1c2a6492 461 return out;
7768852d 462#endif
ebe98224
VK
463}
464
7768852d
VK
465/**
466 * Convert wide string to UTF8 string allocating UTF8 string dynamically
467 */
468char LIBNETXMS_EXPORTABLE *UTF8StringFromWideString(const WCHAR *src)
469{
470 int len = WideCharToMultiByte(CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL);
471 char *out = (char *)malloc(len);
472 WideCharToMultiByte(CP_UTF8, 0, src, -1, out, len, NULL, NULL);
473 return out;
474}
ebe98224
VK
475
476/**
7768852d
VK
477 * Convert UTF8 string to multibyte string using current codepage and
478 * allocating multibyte string dynamically
ebe98224 479 */
7768852d 480char LIBNETXMS_EXPORTABLE *MBStringFromUTF8String(const char *s)
ebe98224 481{
7768852d
VK
482 int len = (int)strlen(s) + 1;
483 char *out = (char *)malloc(len);
484 utf8_to_mb(s, -1, out, len);
485 return out;
486}
ebe98224 487
7768852d
VK
488/**
489 * Convert multibyte string to UTF8 string allocating UTF8 string dynamically
490 */
491char LIBNETXMS_EXPORTABLE *UTF8StringFromMBString(const char *s)
492{
493 int len = (int)strlen(s) * 3 + 1; // assume worst case - 3 bytes per character
494 char *out = (char *)malloc(len);
495 mb_to_utf8(s, -1, out, len);
496 return out;
497}
ebe98224 498
7768852d
VK
499/**
500 * Convert UCS-4 string to UCS-2 string allocating UCS-2 string dynamically
501 */
502UCS2CHAR LIBNETXMS_EXPORTABLE *UCS2StringFromUCS4String(const UCS4CHAR *src)
503{
504 UCS2CHAR *pszOut;
505 int nLen;
ebe98224 506
7768852d
VK
507 nLen = (int)ucs4_strlen(src) + 1;
508 pszOut = (UCS2CHAR *)malloc(nLen * sizeof(UCS2CHAR));
509 ucs4_to_ucs2(src, -1, pszOut, nLen);
510 return pszOut;
511}
ebe98224 512
7768852d
VK
513/**
514 * Convert UCS-2 string to UCS-4 string allocating UCS-4 string dynamically
515 */
516UCS4CHAR LIBNETXMS_EXPORTABLE *UCS4StringFromUCS2String(const UCS2CHAR *src)
517{
518 int len = (int)ucs2_strlen(src) + 1;
519 UCS4CHAR *out = (UCS4CHAR *)malloc(len * sizeof(UCS4CHAR));
520 ucs2_to_ucs4(src, -1, out, len);
521 return out;
ebe98224
VK
522}
523
7768852d 524#ifndef UNICODE_UCS2
ebe98224
VK
525
526/**
7768852d 527 * Convert UTF-8 to UCS-2 (dynamically allocated output string)
ebe98224 528 */
7768852d 529UCS2CHAR LIBNETXMS_EXPORTABLE *UCS2StringFromUTF8String(const char *utf8String)
ebe98224 530{
7768852d
VK
531 if (utf8String == NULL)
532 return NULL;
533 int nLen = (int)strlen(utf8String) + 1;
534 UCS2CHAR *out = (UCS2CHAR *)malloc(nLen * sizeof(UCS2CHAR));
535 utf8_to_ucs2(utf8String, -1, out, nLen);
536 return out;
ebe98224
VK
537}
538
539/**
7768852d 540 * Convert UCS-2 string to UTF-8 string allocating UTF-8 string dynamically
ebe98224 541 */
7768852d 542char LIBNETXMS_EXPORTABLE *UTF8StringFromUCS2String(const UCS2CHAR *src)
ebe98224 543{
7768852d
VK
544 int len = (int)ucs2_strlen(src) + 1;
545 char *out = (char *)malloc(len * 2);
546 ucs2_to_utf8(src, -1, out, len);
547 return out;
ebe98224
VK
548}
549
ebe98224 550/**
7768852d 551 * Convert multibyte string to UCS-2 string allocating UCS-2 string dynamically
ebe98224 552 */
7768852d 553UCS2CHAR LIBNETXMS_EXPORTABLE *UCS2StringFromMBString(const char *src)
ebe98224 554{
7768852d
VK
555 int len = (int)strlen(src) + 1;
556 UCS2CHAR *out = (UCS2CHAR *)malloc(len * sizeof(UCS2CHAR));
557 mb_to_ucs2(src, -1, out, len);
558 return out;
559}
ebe98224 560
7768852d
VK
561/**
562 * Convert UCS-2 string to multibyte string allocating multibyte string dynamically
563 */
564char LIBNETXMS_EXPORTABLE *MBStringFromUCS2String(const UCS2CHAR *src)
565{
566 int len = (int)ucs2_strlen(src) + 1;
567 char *out = (char *)malloc(len);
568 ucs2_to_mb(src, -1, out, len);
569 return out;
570}
ebe98224 571
7768852d 572#endif /* UNICODE_UCS2 */
ebe98224 573
7768852d 574#ifndef UNICODE_UCS4
ebe98224 575
7768852d
VK
576/**
577 * Convert multibyte string to UCS-4 string allocating UCS-4 string dynamically
578 */
579UCS4CHAR LIBNETXMS_EXPORTABLE *UCS4StringFromMBString(const char *src)
580{
581 int len = (int)strlen(src) + 1;
582 UCS4CHAR *out = (UCS4CHAR *)malloc(len * sizeof(UCS4CHAR));
583 mb_to_ucs4(src, -1, out, len);
584 return out;
ebe98224
VK
585}
586
ebe98224 587/**
7768852d 588 * Convert UCS-4 string to multibyte string allocating multibyte string dynamically
ebe98224 589 */
7768852d 590char LIBNETXMS_EXPORTABLE *MBStringFromUCS4String(const UCS4CHAR *src)
ebe98224 591{
7768852d
VK
592 int len = (int)ucs4_strlen(src) + 1;
593 char *out = (char *)malloc(len);
594 ucs4_to_mb(src, -1, out, len);
595 return out;
ebe98224
VK
596}
597
7768852d 598#endif /* UNICODE_UCS4 */
5039dede 599
13469050
VP
600/**
601 * UNIX UNICODE specific wrapper functions
602 */
842c22f4
AK
603#if !defined(_WIN32)
604
605#if !HAVE_WSTAT
606
607int wstat(const WCHAR *_path, struct stat *_sbuf)
608{
284b15a4
VP
609 char path[MAX_PATH];
610
611 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
612 _path, -1, path, MAX_PATH, NULL, NULL);
613 return stat(path, _sbuf);
842c22f4
AK
614}
615
13469050 616#endif /* !HAVE_WSTAT */
5039dede 617
842c22f4 618#if defined(UNICODE)
5039dede 619
13469050
VP
620/**
621 * Wide character version of some libc functions
622 */
5039dede 623
b07c50cc
VK
624#define DEFINE_PATH_FUNC(func) \
625int w##func(const WCHAR *_path) \
626{ \
627 char path[MAX_PATH]; \
1f2d100d
VK
628 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, _path, -1, path, MAX_PATH, NULL, NULL); \
629 return func(path); \
b07c50cc
VK
630}
631
632#if !HAVE_WCHDIR
633DEFINE_PATH_FUNC(chdir)
634#endif
635
636#if !HAVE_WRMDIR
637DEFINE_PATH_FUNC(rmdir)
638#endif
639
640#if !HAVE_WUNLINK
641DEFINE_PATH_FUNC(unlink)
642#endif
643
644#if !HAVE_WREMOVE
645DEFINE_PATH_FUNC(remove)
646#endif
647
dda7c270 648#if !HAVE_WMKSTEMP
3b864d8d
VK
649
650int LIBNETXMS_EXPORTABLE wmkstemp(WCHAR *_path)
651{
652 char path[MAX_PATH];
653 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, _path, -1, path, MAX_PATH, NULL, NULL);
654 int rc = mkstemp(path);
655 if (rc != -1)
656 {
657 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, path, -1, _path, wcslen(_path) + 1);
658 }
659 return rc;
660}
661
dda7c270
VK
662#endif
663
f3387429
VK
664#if !HAVE_WPOPEN
665
666FILE LIBNETXMS_EXPORTABLE *wpopen(const WCHAR *_command, const WCHAR *_type)
667{
284b15a4
VP
668 char *command, *type;
669 FILE *f;
670
671 command = MBStringFromWideString(_command);
672 type = MBStringFromWideString(_type);
673 f = popen(command, type);
674 free(command);
675 free(type);
676 return f;
f3387429
VK
677}
678
679#endif
680
5039dede
AK
681#if !HAVE_WFOPEN
682
683FILE LIBNETXMS_EXPORTABLE *wfopen(const WCHAR *_name, const WCHAR *_type)
684{
284b15a4
VP
685 char *name, *type;
686 FILE *f;
687
688 name = MBStringFromWideString(_name);
689 type = MBStringFromWideString(_type);
690 f = fopen(name, type);
691 free(name);
692 free(type);
693 return f;
5039dede
AK
694}
695
696#endif
697
8c2489aa
VK
698#if HAVE_FOPEN64 && !HAVE_WFOPEN64
699
700FILE LIBNETXMS_EXPORTABLE *wfopen64(const WCHAR *_name, const WCHAR *_type)
701{
702 char *name, *type;
703 FILE *f;
704
705 name = MBStringFromWideString(_name);
706 type = MBStringFromWideString(_type);
707 f = fopen64(name, type);
708 free(name);
709 free(type);
710 return f;
711}
712
713#endif
714
5039dede
AK
715#if !HAVE_WOPEN
716
717int LIBNETXMS_EXPORTABLE wopen(const WCHAR *_name, int flags, ...)
718{
284b15a4
VP
719 char *name;
720 int rc;
721
722 name = MBStringFromWideString(_name);
723 if (flags & O_CREAT)
724 {
725 va_list args;
726
727 va_start(args, flags);
728 rc = open(name, flags, (mode_t)va_arg(args, int));
729 va_end(args);
730 }
731 else
732 {
733 rc = open(name, flags);
734 }
735 free(name);
736 return rc;
5039dede
AK
737}
738
739#endif
740
f3387429
VK
741#if !HAVE_WCHMOD
742
743int LIBNETXMS_EXPORTABLE wchmod(const WCHAR *_name, int mode)
744{
284b15a4
VP
745 char *name;
746 int rc;
747
748 name = MBStringFromWideString(_name);
749 rc = chmod(name, mode);
750 free(name);
751 return rc;
f3387429
VK
752}
753
754#endif
755
b07c50cc 756#if !HAVE_WRENAME
6d738067 757
b07c50cc
VK
758int wrename(const WCHAR *_oldpath, const WCHAR *_newpath)
759{
284b15a4
VP
760 char oldpath[MAX_PATH], newpath[MAX_PATH];
761
762 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
763 _oldpath, -1, oldpath, MAX_PATH, NULL, NULL);
764 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
765 _newpath, -1, newpath, MAX_PATH, NULL, NULL);
766 return rename(oldpath, newpath);
b07c50cc
VK
767}
768
769#endif
770
771#if !HAVE_WSYSTEM
772
773int wsystem(const WCHAR *_cmd)
774{
1c2a6492 775 char *cmd = MBStringFromWideStringSysLocale(_cmd);
284b15a4
VP
776 int rc = system(cmd);
777 free(cmd);
778 return rc;
b07c50cc
VK
779}
780
781#endif
782
783#if !HAVE_WACCESS
784
785int waccess(const WCHAR *_path, int mode)
6d738067 786{
284b15a4
VP
787 char path[MAX_PATH];
788
789 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
790 _path, -1, path, MAX_PATH, NULL, NULL);
791 return access(path, mode);
6d738067
VK
792}
793
794#endif
795
b07c50cc 796#if !HAVE_WMKDIR
6d738067 797
b07c50cc 798int wmkdir(const WCHAR *_path, int mode)
6d738067 799{
284b15a4
VP
800 char path[MAX_PATH];
801
802 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
803 _path, -1, path, MAX_PATH, NULL, NULL);
804 return mkdir(path, mode);
6d738067
VK
805}
806
807#endif
808
7b45b90d 809#if !HAVE_WUTIME
810
811int wutime(const WCHAR *_path, utimbuf *buf)
812{
813 char path[MAX_PATH];
814
815 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
816 _path, -1, path, MAX_PATH, NULL, NULL);
817 return utime(path, buf);
818}
819
820#endif
821
5039dede
AK
822#if !HAVE_WGETENV
823
824WCHAR *wgetenv(const WCHAR *_string)
825{
284b15a4
VP
826 char name[256], *p;
827 static WCHAR value[8192];
828
829 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, _string, -1, name, 256, NULL, NULL);
830 p = getenv(name);
831 if (p == NULL)
4a7d46f4 832 return NULL;
284b15a4
VP
833
834 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, p, -1, value, 8192);
835 return value;
5039dede
AK
836}
837
838#endif
839
f3387429
VK
840#if !HAVE_WCTIME
841
842WCHAR *wctime(const time_t *timep)
843{
284b15a4
VP
844 static WCHAR value[256];
845
846 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, ctime(timep), -1, value, 256);
847 return value;
f3387429
VK
848}
849
29dc8792 850#endif /* HAVE_WCTIME */
f3387429 851
0186b5da
VK
852#if !HAVE_PUTWS
853
854int putws(const WCHAR *s)
855{
856#if HAVE_FPUTWS
284b15a4
VP
857 fputws(s, stdout);
858 putwc(L'\n', stdout);
0186b5da 859#else
284b15a4 860 printf("%S\n", s);
13469050 861#endif /* HAVE_FPUTWS */
284b15a4 862 return 1;
0186b5da
VK
863}
864
13469050 865#endif /* !HAVE_PUTWS */
0186b5da 866
9757ca46 867#if !HAVE_WCSERROR && (HAVE_STRERROR || HAVE_DECL_STRERROR)
5039dede
AK
868
869WCHAR *wcserror(int errnum)
870{
284b15a4 871 static WCHAR value[8192];
5039dede 872
284b15a4
VP
873 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, strerror(errnum), -1, value, 8192);
874 return value;
5039dede
AK
875}
876
13469050 877#endif /* !HAVE_WCSERROR && HAVE_STRERROR */
5039dede
AK
878
879#if !HAVE_WCSERROR_R && HAVE_STRERROR_R
880
b0823d06
VK
881#if HAVE_POSIX_STRERROR_R
882int wcserror_r(int errnum, WCHAR *strerrbuf, size_t buflen)
883#else
5039dede 884WCHAR *wcserror_r(int errnum, WCHAR *strerrbuf, size_t buflen)
13469050 885#endif /* HAVE_POSIX_STRERROR_R */
5039dede 886{
284b15a4 887 char *mbbuf;
b0823d06 888#if HAVE_POSIX_STRERROR_R
4ccffa2f 889 int err = 0;
13469050 890#endif /* HAVE_POSIX_STRERROR_R */
5039dede 891
284b15a4
VP
892 mbbuf = (char *)malloc(buflen);
893 if (mbbuf != NULL)
894 {
b0823d06 895#if HAVE_POSIX_STRERROR_R
284b15a4
VP
896 err = strerror_r(errnum, mbbuf, buflen);
897 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, mbbuf, -1, strerrbuf, buflen);
b0823d06 898#else
284b15a4 899 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, strerror_r(errnum, mbbuf, buflen), -1, strerrbuf, buflen);
b0823d06 900#endif
284b15a4
VP
901 free(mbbuf);
902 }
903 else
904 {
905 *strerrbuf = 0;
906 }
b0823d06
VK
907
908#if HAVE_POSIX_STRERROR_R
284b15a4 909 return err;
b0823d06 910#else
284b15a4 911 return strerrbuf;
b0823d06 912#endif
5039dede
AK
913}
914
13469050
VP
915#endif /* !HAVE_WCSERROR_R && HAVE_STRERROR_R */
916
13469050
VP
917/**
918 * Wrappers for wprintf/wscanf family
919 *
920 * All these wrappers replaces %s with %S and %c with %C
921 * because in POSIX version of wprintf functions %s and %c
922 * means "multibyte string/char" instead of expected "UNICODE string/char"
923 */
5039dede
AK
924
925int LIBNETXMS_EXPORTABLE nx_wprintf(const WCHAR *format, ...)
926{
284b15a4
VP
927 va_list args;
928 int rc;
5039dede 929
284b15a4
VP
930 va_start(args, format);
931 rc = nx_vwprintf(format, args);
932 va_end(args);
933 return rc;
5039dede
AK
934}
935
936int LIBNETXMS_EXPORTABLE nx_fwprintf(FILE *fp, const WCHAR *format, ...)
937{
284b15a4
VP
938 va_list args;
939 int rc;
5039dede 940
284b15a4
VP
941 va_start(args, format);
942 rc = nx_vfwprintf(fp, format, args);
943 va_end(args);
944 return rc;
5039dede
AK
945}
946
947int LIBNETXMS_EXPORTABLE nx_swprintf(WCHAR *buffer, size_t size, const WCHAR *format, ...)
948{
284b15a4
VP
949 va_list args;
950 int rc;
5039dede 951
284b15a4
VP
952 va_start(args, format);
953 rc = nx_vswprintf(buffer, size, format, args);
954 va_end(args);
955 return rc;
5039dede
AK
956}
957
25575d38
VK
958int LIBNETXMS_EXPORTABLE nx_wscanf(const WCHAR *format, ...)
959{
284b15a4
VP
960 va_list args;
961 int rc;
25575d38 962
284b15a4
VP
963 va_start(args, format);
964 rc = nx_vwscanf(format, args);
965 va_end(args);
966 return rc;
25575d38
VK
967}
968
969int LIBNETXMS_EXPORTABLE nx_fwscanf(FILE *fp, const WCHAR *format, ...)
970{
284b15a4
VP
971 va_list args;
972 int rc;
25575d38 973
284b15a4
VP
974 va_start(args, format);
975 rc = nx_vfwscanf(fp, format, args);
976 va_end(args);
977 return rc;
25575d38
VK
978}
979
7ff399a5 980int LIBNETXMS_EXPORTABLE nx_swscanf(const WCHAR *str, const WCHAR *format, ...)
25575d38 981{
284b15a4
VP
982 va_list args;
983 int rc;
25575d38 984
284b15a4
VP
985 va_start(args, format);
986 rc = nx_vswscanf(str, format, args);
987 va_end(args);
988 return rc;
25575d38
VK
989}
990
5039dede
AK
991static WCHAR *ReplaceFormatSpecs(const WCHAR *oldFormat)
992{
284b15a4
VP
993 WCHAR *fmt, *p;
994 int state = 0;
995 bool hmod;
996
997 fmt = wcsdup(oldFormat);
998 for(p = fmt; *p != 0; p++)
999 {
1000 switch (state)
1001 {
1002 case 0: // Normal text
1003 if (*p == L'%')
1004 {
1005 state = 1;
1006 hmod = false;
1007 }
1008 break;
1009 case 1: // Format start
1010 switch (*p)
1011 {
1012 case L's':
1013 if (hmod)
1014 {
1015 memmove(p - 1, p, wcslen(p - 1) * sizeof(TCHAR));
1016 }
1017 else
1018 {
1019 *p = L'S';
1020 }
1021 state = 0;
1022 break;
1023 case L'S':
1024 *p = L's';
1025 state = 0;
1026 break;
1027 case L'c':
1028 if (hmod)
1029 {
1030 memmove(p - 1, p, wcslen(p - 1) * sizeof(TCHAR));
1031 }
1032 else
1033 {
1034 *p = L'C';
1035 }
1036 state = 0;
1037 break;
1038 case L'C':
1039 *p = L'c';
1040 state = 0;
1041 break;
1042 case L'.': // All this characters could be part of format specifier
1043 case L'*': // and has no interest for us
1044 case L'+':
1045 case L'-':
1046 case L' ':
1047 case L'#':
1048 case L'0':
1049 case L'1':
1050 case L'2':
1051 case L'3':
1052 case L'4':
1053 case L'5':
1054 case L'6':
1055 case L'7':
1056 case L'8':
1057 case L'9':
1058 case L'l':
1059 case L'L':
1060 case L'F':
1061 case L'N':
1062 case L'w':
1063 break;
1064 case L'h': // check for %hs
1065 hmod = true;
1066 break;
c6d5c1b0 1067 default: // All other characters means end of format
284b15a4
VP
1068 state = 0;
1069 break;
1070
1071 }
1072 break;
1073 }
1074 }
1075 return fmt;
5039dede
AK
1076}
1077
1078int LIBNETXMS_EXPORTABLE nx_vwprintf(const WCHAR *format, va_list args)
1079{
284b15a4
VP
1080 WCHAR *fmt;
1081 int rc;
5039dede 1082
284b15a4
VP
1083 fmt = ReplaceFormatSpecs(format);
1084 rc = vwprintf(fmt, args);
1085 free(fmt);
1086 return rc;
5039dede
AK
1087}
1088
1089int LIBNETXMS_EXPORTABLE nx_vfwprintf(FILE *fp, const WCHAR *format, va_list args)
1090{
284b15a4
VP
1091 WCHAR *fmt;
1092 int rc;
5039dede 1093
284b15a4
VP
1094 fmt = ReplaceFormatSpecs(format);
1095 rc = vfwprintf(fp, fmt, args);
1096 free(fmt);
1097 return rc;
5039dede
AK
1098}
1099
1100int LIBNETXMS_EXPORTABLE nx_vswprintf(WCHAR *buffer, size_t size, const WCHAR *format, va_list args)
1101{
284b15a4
VP
1102 WCHAR *fmt;
1103 int rc;
5039dede 1104
284b15a4
VP
1105 fmt = ReplaceFormatSpecs(format);
1106 rc = vswprintf(buffer, size, fmt, args);
1107 free(fmt);
1108 return rc;
5039dede
AK
1109}
1110
25575d38
VK
1111int LIBNETXMS_EXPORTABLE nx_vwscanf(const WCHAR *format, va_list args)
1112{
284b15a4
VP
1113 WCHAR *fmt;
1114 int rc;
25575d38 1115
284b15a4 1116 fmt = ReplaceFormatSpecs(format);
5a64ab96 1117#if HAVE_VWSCANF
284b15a4 1118 rc = vwscanf(fmt, args);
5a64ab96 1119#else
284b15a4 1120 rc = -1; // FIXME: add workaround implementation
5a64ab96 1121#endif
284b15a4
VP
1122 free(fmt);
1123 return rc;
25575d38
VK
1124}
1125
1126int LIBNETXMS_EXPORTABLE nx_vfwscanf(FILE *fp, const WCHAR *format, va_list args)
1127{
284b15a4
VP
1128 WCHAR *fmt;
1129 int rc;
25575d38 1130
284b15a4 1131 fmt = ReplaceFormatSpecs(format);
5a64ab96 1132#if HAVE_VFWSCANF
284b15a4 1133 rc = vfwscanf(fp, fmt, args);
5a64ab96 1134#else
284b15a4 1135 rc = -1; // FIXME: add workaround implementation
5a64ab96 1136#endif
284b15a4
VP
1137 free(fmt);
1138 return rc;
25575d38
VK
1139}
1140
7ff399a5 1141int LIBNETXMS_EXPORTABLE nx_vswscanf(const WCHAR *str, const WCHAR *format, va_list args)
25575d38 1142{
284b15a4
VP
1143 WCHAR *fmt;
1144 int rc;
25575d38 1145
284b15a4 1146 fmt = ReplaceFormatSpecs(format);
5a64ab96 1147#if HAVE_VSWSCANF
284b15a4 1148 rc = vswscanf(str, fmt, args);
5a64ab96 1149#else
284b15a4 1150 rc = -1; // FIXME: add workaround implementation
5a64ab96 1151#endif
284b15a4
VP
1152 free(fmt);
1153 return rc;
25575d38 1154}
c6d5c1b0
VK
1155
1156#endif /* defined(UNICODE) */
1157
29dc8792 1158#endif /* !defined(_WIN32) */
7768852d
VK
1159
1160/**
1161 * UNICODE version of inet_addr()
1162 */
1163UINT32 LIBNETXMS_EXPORTABLE inet_addr_w(const WCHAR *pszAddr)
1164{
1165 char szBuffer[256];
1166 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, pszAddr, -1, szBuffer, 256, NULL, NULL);
1167 return inet_addr(szBuffer);
1168}
1169
c7c23e6d 1170#if defined(_WITH_ENCRYPTION) && WITH_OPENSSL
7768852d
VK
1171
1172/**
1173 * Get OpenSSL error string as UNICODE string
1174 * Buffer must be at least 256 character long
1175 */
1176WCHAR LIBNETXMS_EXPORTABLE *ERR_error_string_W(int nError, WCHAR *pwszBuffer)
1177{
1178 char text[256];
1179
1180 memset(text, 0, sizeof(text));
1181 ERR_error_string(nError, text);
1182 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, text, -1, pwszBuffer, 256);
1183 return pwszBuffer;
1184}
1185
1186#endif