implemented iconv descriptor cache
[public/netxms.git] / src / libnetxms / unicode.cpp
CommitLineData
5039dede 1/*
284b15a4 2 ** NetXMS - Network Management System
bd96aa53 3 ** Copyright (C) 2003-2014 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"
24
29dc8792 25/**
bd96aa53 26 * Default codepage
29dc8792 27 */
29dc8792 28static char m_cpDefault[MAX_CODEPAGE_LEN] = ICONV_DEFAULT_CODEPAGE;
5039dede 29
5039dede
AK
30#ifndef _WIN32
31
32#if HAVE_ICONV_H
33#include <iconv.h>
34#endif
35
29dc8792
VP
36/**
37 * UNICODE character set
38 */
5039dede
AK
39#ifndef __DISABLE_ICONV
40
bd96aa53
VK
41// iconv cache functions
42#if WITH_ICONV_CACHE
43iconv_t IconvOpen(const char *to, const char *from);
44void IconvClose(iconv_t cd);
45#else
46#define IconvOpen iconv_open
47#define IconvClose iconv_close
48#endif
49
5039dede
AK
50// configure first test for libiconv, then for iconv
51// if libiconv was found, HAVE_ICONV will not be set correctly
52#if HAVE_LIBICONV
53#undef HAVE_ICONV
54#define HAVE_ICONV 1
55#endif
56
57#if HAVE_ICONV_UCS_2_INTERNAL
58#define UCS2_CODEPAGE_NAME "UCS-2-INTERNAL"
59#elif HAVE_ICONV_UCS_2BE && WORDS_BIGENDIAN
60#define UCS2_CODEPAGE_NAME "UCS-2BE"
61#elif HAVE_ICONV_UCS_2LE && !WORDS_BIGENDIAN
62#define UCS2_CODEPAGE_NAME "UCS-2LE"
63#elif HAVE_ICONV_UCS_2
64#define UCS2_CODEPAGE_NAME "UCS-2"
65#elif HAVE_ICONV_UCS2
66#define UCS2_CODEPAGE_NAME "UCS2"
4a4e1feb
VK
67#elif HAVE_ICONV_UTF_16
68#define UCS2_CODEPAGE_NAME "UTF-16"
5039dede
AK
69#else
70#ifdef UNICODE
71#error Cannot determine valid UCS-2 codepage name
72#else
73#warning Cannot determine valid UCS-2 codepage name
74#undef HAVE_ICONV
75#endif
76#endif
77
78#if HAVE_ICONV_UCS_4_INTERNAL
79#define UCS4_CODEPAGE_NAME "UCS-4-INTERNAL"
80#elif HAVE_ICONV_UCS_4BE && WORDS_BIGENDIAN
81#define UCS4_CODEPAGE_NAME "UCS-4BE"
82#elif HAVE_ICONV_UCS_4LE && !WORDS_BIGENDIAN
83#define UCS4_CODEPAGE_NAME "UCS-4LE"
84#elif HAVE_ICONV_UCS_4
85#define UCS4_CODEPAGE_NAME "UCS-4"
86#elif HAVE_ICONV_UCS4
87#define UCS4_CODEPAGE_NAME "UCS4"
4a4e1feb
VK
88#elif HAVE_ICONV_UTF_32
89#define UCS4_CODEPAGE_NAME "UTF-32"
5039dede
AK
90#else
91#if defined(UNICODE) && defined(UNICODE_UCS4)
92#error Cannot determine valid UCS-4 codepage name
93#else
94#warning Cannot determine valid UCS-4 codepage name
95#undef HAVE_ICONV
96#endif
97#endif
98
99#ifdef UNICODE_UCS4
100#define UNICODE_CODEPAGE_NAME UCS4_CODEPAGE_NAME
101#else /* assume UCS-2 */
102#define UNICODE_CODEPAGE_NAME UCS2_CODEPAGE_NAME
103#endif
104
105#endif /* __DISABLE_ICONV */
106
29dc8792
VP
107/**
108 * Set application's default codepage
109 */
5039dede
AK
110BOOL LIBNETXMS_EXPORTABLE SetDefaultCodepage(const char *cp)
111{
284b15a4 112 BOOL rc;
5039dede 113#if HAVE_ICONV && !defined(__DISABLE_ICONV)
284b15a4 114 iconv_t cd;
5039dede 115
284b15a4
VP
116 cd = iconv_open(cp, "UTF-8");
117 if (cd != (iconv_t) (-1))
118 {
119 iconv_close(cd);
5039dede 120#endif
284b15a4
VP
121 strncpy(m_cpDefault, cp, MAX_CODEPAGE_LEN);
122 m_cpDefault[MAX_CODEPAGE_LEN - 1] = 0;
123 rc = TRUE;
5039dede 124#if HAVE_ICONV && !defined(__DISABLE_ICONV)
284b15a4
VP
125 }
126 else
127 {
128 rc = FALSE;
129 }
5039dede 130#endif
284b15a4 131 return rc;
5039dede
AK
132}
133
1c1a6930 134#if !UNICODE_UCS2 || !HAVE_WCSLEN
5039dede 135
13469050
VP
136/**
137 * Calculate length of wide character string
138 */
5039dede
AK
139int LIBNETXMS_EXPORTABLE ucs2_strlen(const UCS2CHAR *pStr)
140{
141 int iLen = 0;
142 const UCS2CHAR *pCurr = pStr;
143
144 while(*pCurr++)
145 iLen++;
146 return iLen;
147}
148
149#endif
150
1c1a6930 151#if !UNICODE_UCS2 || !HAVE_WCSDUP
5039dede 152
29dc8792
VP
153/**
154 * Duplicate wide character string
155 */
5039dede
AK
156UCS2CHAR LIBNETXMS_EXPORTABLE *ucs2_strdup(const UCS2CHAR *pStr)
157{
284b15a4 158 return (UCS2CHAR *) nx_memdup(pStr, (ucs2_strlen(pStr) + 1) * sizeof(UCS2CHAR));
5039dede
AK
159}
160
161#endif
162
1c1a6930 163#if !UNICODE_UCS2 || !HAVE_WCSNCPY
5039dede 164
29dc8792
VP
165/**
166 * Copy wide character string with length limitation
167 */
5039dede
AK
168UCS2CHAR LIBNETXMS_EXPORTABLE *ucs2_strncpy(UCS2CHAR *pDst, const UCS2CHAR *pSrc, int nDstLen)
169{
284b15a4 170 int nLen;
5039dede 171
284b15a4
VP
172 nLen = ucs2_strlen(pSrc) + 1;
173 if (nLen > nDstLen)
174 nLen = nDstLen;
175 memcpy(pDst, pSrc, nLen * sizeof(UCS2CHAR));
176 return pDst;
5039dede
AK
177}
178
179#endif
180
9d4a020a 181/**
305e2330 182 * Convert UNICODE string to single-byte string using simple byte copy (works for ASCII only)
9d4a020a 183 */
13469050 184inline 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++)
817dce5b 195 *pDest = (*pSrc < 256) ? (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 */
13469050 206inline 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
29dc8792
VP
216 strcpy(cp, m_cpDefault);
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 }
248 if ((cchWideChar == -1) && (outbytes > 0))
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 */
305e2330 287inline 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++)
297 *pDest = (WCHAR) (*pSrc);
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 */
308inline 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
bd96aa53 316 cd = IconvOpen(UNICODE_CODEPAGE_NAME, iCodePage == CP_UTF8 ? "UTF-8" : m_cpDefault);
817dce5b 317 if (cd == (iconv_t)(-1))
13469050
VP
318 {
319 return MultiByteToWideCharSimpleCopy(iCodePage, dwFlags, pByteStr, cchByteChar, pWideCharStr, cchWideChar);
320 }
5039dede 321
13469050
VP
322 inbuf = pByteStr;
323 inbytes = (cchByteChar == -1) ? strlen(pByteStr) + 1 : cchByteChar;
6fbbf94d 324 outbuf = (char *)pWideCharStr;
13469050 325 outbytes = cchWideChar * sizeof(WCHAR);
6fbbf94d 326 nRet = iconv(cd, (ICONV_CONST char **)&inbuf, &inbytes, &outbuf, &outbytes);
bd96aa53 327 IconvClose(cd);
284b15a4 328
13469050
VP
329 if (nRet == -1)
330 {
331 if (errno == EILSEQ)
332 {
333 nRet = (cchWideChar * sizeof(WCHAR) - outbytes) / sizeof(WCHAR);
334 }
335 else
336 {
337 nRet = 0;
338 }
339 }
340 else
341 {
342 nRet = (cchWideChar * sizeof(WCHAR) - outbytes) / sizeof(WCHAR);
343 }
344 if (((char *) outbuf - (char *) pWideCharStr > sizeof(WCHAR)) && (*pWideCharStr == 0xFEFF))
345 {
346 // Remove UNICODE byte order indicator if presented
347 memmove(pWideCharStr, &pWideCharStr[1], (char *) outbuf - (char *) pWideCharStr - sizeof(WCHAR));
348 outbuf -= sizeof(WCHAR);
349 nRet--;
350 }
351 if ((cchByteChar == -1) && (outbytes >= sizeof(WCHAR)))
352 {
353 *((WCHAR *) outbuf) = 0;
354 }
045845e5 355
13469050
VP
356 return nRet;
357}
045845e5 358
5d0d2fc6
VK
359#endif
360
305e2330
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
VP
365{
366 if (cchWideChar == 0)
367 {
368 return strlen(pByteStr) + 1;
369 }
5039dede 370
13469050
VP
371#if HAVE_ICONV && !defined(__DISABLE_ICONV)
372 return MultiByteToWideCharIconv(iCodePage, dwFlags, pByteStr, cchByteChar, pWideCharStr, cchWideChar);
373#else
374 return MultiByteToWideCharSimpleCopy(iCodePage, dwFlags, pByteStr, cchByteChar, pWideCharStr, cchWideChar);
375#endif
5039dede
AK
376}
377
378#endif /* not _WIN32 */
379
967893bb
VK
380/**
381 * UNICODE version of inet_addr()
382 */
383UINT32 LIBNETXMS_EXPORTABLE inet_addr_w(const WCHAR *pszAddr)
5039dede
AK
384{
385 char szBuffer[256];
817dce5b 386 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, pszAddr, -1, szBuffer, 256, NULL, NULL);
5039dede
AK
387 return inet_addr(szBuffer);
388}
389
967893bb
VK
390/**
391 * Convert multibyte string to wide string using current codepage and
392 * allocating wide string dynamically
393 */
5039dede
AK
394WCHAR LIBNETXMS_EXPORTABLE *WideStringFromMBString(const char *pszString)
395{
396 WCHAR *pwszOut;
397 int nLen;
398
284b15a4
VP
399 nLen = (int) strlen(pszString) + 1;
400 pwszOut = (WCHAR *) malloc(nLen * sizeof(WCHAR));
5039dede
AK
401 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszString, -1, pwszOut, nLen);
402 return pwszOut;
403}
404
13469050 405/**
1c1a6930 406 * Convert wide string to UTF8 string allocating wide string dynamically
13469050 407 */
5039dede
AK
408WCHAR LIBNETXMS_EXPORTABLE *WideStringFromUTF8String(const char *pszString)
409{
410 WCHAR *pwszOut;
411 int nLen;
412
284b15a4
VP
413 nLen = (int) strlen(pszString) + 1;
414 pwszOut = (WCHAR *) malloc(nLen * sizeof(WCHAR));
5039dede
AK
415 MultiByteToWideChar(CP_UTF8, 0, pszString, -1, pwszOut, nLen);
416 return pwszOut;
417}
418
13469050
VP
419/**
420 * Convert wide string to multibyte string using current codepage and
421 * allocating multibyte string dynamically
422 */
5039dede
AK
423char LIBNETXMS_EXPORTABLE *MBStringFromWideString(const WCHAR *pwszString)
424{
425 char *pszOut;
426 int nLen;
427
428 nLen = (int)wcslen(pwszString) + 1;
429 pszOut = (char *)malloc(nLen);
1c1a6930 430 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, pwszString, -1, pszOut, nLen, NULL, NULL);
5039dede
AK
431 return pszOut;
432}
433
13469050
VP
434/**
435 * Convert wide string to UTF8 string allocating UTF8 string dynamically
436 */
5039dede
AK
437char LIBNETXMS_EXPORTABLE *UTF8StringFromWideString(const WCHAR *pwszString)
438{
439 char *pszOut;
440 int nLen;
441
442 nLen = WideCharToMultiByte(CP_UTF8, 0, pwszString, -1, NULL, 0, NULL, NULL);
284b15a4 443 pszOut = (char *) malloc(nLen);
5039dede
AK
444 WideCharToMultiByte(CP_UTF8, 0, pwszString, -1, pszOut, nLen, NULL, NULL);
445 return pszOut;
446}
447
13469050
VP
448/**
449 * Get OpenSSL error string as UNICODE string
450 * Buffer must be at least 256 character long
451 */
5039dede
AK
452
453#ifdef _WITH_ENCRYPTION
454
455WCHAR LIBNETXMS_EXPORTABLE *ERR_error_string_W(int nError, WCHAR *pwszBuffer)
456{
284b15a4 457 char text[256];
5039dede 458
284b15a4
VP
459 memset(text, 0, sizeof(text));
460 ERR_error_string(nError, text);
5039dede 461 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, text, -1, pwszBuffer, 256);
284b15a4 462 return pwszBuffer;
5039dede
AK
463}
464
465#endif
466
5039dede
AK
467#ifdef UNICODE_UCS4
468
13469050
VP
469/**
470 * Convert UCS-2 to UCS-4 - internal dumb method
471 */
045845e5
VK
472static size_t __internal_ucs2_to_ucs4(const UCS2CHAR *src, int srcLen, WCHAR *dst, int dstLen)
473{
284b15a4
VP
474 int i, len;
475
476 len = (int) ((srcLen == -1) ? ucs2_strlen(src) : srcLen);
477 if (len > (int) dstLen - 1)
478 len = (int) dstLen - 1;
479 for(i = 0; i < len; i++)
480 dst[i] = (WCHAR) src[i];
481 dst[i] = 0;
482 return len;
045845e5
VK
483}
484
13469050
VP
485/**
486 * Convert UCS-4 to UCS-2 - internal dumb method
487 */
045845e5
VK
488static size_t __internal_ucs4_to_ucs2(const WCHAR *src, int srcLen, UCS2CHAR *dst, int dstLen)
489{
284b15a4
VP
490 int i, len;
491
492 len = (int) ((srcLen == -1) ? wcslen(src) : srcLen);
493 if (len > (int) dstLen - 1)
494 len = (int) dstLen - 1;
495 for(i = 0; i < len; i++)
496 dst[i] = (UCS2CHAR) src[i];
497 dst[i] = 0;
498 return len;
045845e5
VK
499}
500
5039dede
AK
501#ifndef __DISABLE_ICONV
502
13469050
VP
503/**
504 * Convert UCS-2 to UCS-4
505 */
53c96e2d 506size_t LIBNETXMS_EXPORTABLE ucs2_to_ucs4(const UCS2CHAR *src, int srcLen, WCHAR *dst, int dstLen)
5039dede 507{
284b15a4
VP
508 iconv_t cd;
509 const char *inbuf;
510 char *outbuf;
511 size_t count, inbytes, outbytes;
512
bd96aa53 513 cd = IconvOpen(UCS4_CODEPAGE_NAME, UCS2_CODEPAGE_NAME);
e8b2f05d 514 if (cd == (iconv_t) (-1))
284b15a4
VP
515 {
516 return __internal_ucs2_to_ucs4(src, srcLen, dst, dstLen);
517 }
518
519 inbuf = (const char *) src;
520 inbytes = ((srcLen == -1) ? ucs2_strlen(src) + 1 : (size_t) srcLen) * sizeof(UCS2CHAR);
521 outbuf = (char *) dst;
522 outbytes = (size_t) dstLen * sizeof(WCHAR);
523 count = iconv(cd, (ICONV_CONST char **) &inbuf, &inbytes, &outbuf, &outbytes);
bd96aa53 524 IconvClose(cd);
284b15a4
VP
525
526 if (count == (size_t) - 1)
527 {
528 if (errno == EILSEQ)
529 {
530 count = (dstLen * sizeof(WCHAR) - outbytes) / sizeof(WCHAR);
531 }
532 else
533 {
534 count = 0;
535 }
536 }
537 else
538 {
539 count = (dstLen * sizeof(WCHAR) - outbytes) / sizeof(WCHAR);
540 }
541 if ((srcLen == -1) && (outbytes >= sizeof(WCHAR)))
542 {
543 *((WCHAR *) outbuf) = 0;
544 }
5039dede 545
284b15a4 546 return count;
5039dede
AK
547}
548
13469050
VP
549/**
550 * Convert UCS-4 to UCS-2
551 */
53c96e2d 552size_t LIBNETXMS_EXPORTABLE ucs4_to_ucs2(const WCHAR *src, int srcLen, UCS2CHAR *dst, int dstLen)
5039dede 553{
284b15a4
VP
554 iconv_t cd;
555 const char *inbuf;
556 char *outbuf;
557 size_t count, inbytes, outbytes;
558
bd96aa53 559 cd = IconvOpen(UCS2_CODEPAGE_NAME, UCS4_CODEPAGE_NAME);
284b15a4
VP
560 if (cd == (iconv_t) (-1))
561 {
562 return __internal_ucs4_to_ucs2(src, srcLen, dst, dstLen);
563 }
564
565 inbuf = (const char *) src;
566 inbytes = ((srcLen == -1) ? wcslen(src) + 1 : (size_t) srcLen) * sizeof(WCHAR);
567 outbuf = (char *) dst;
568 outbytes = (size_t) dstLen * sizeof(UCS2CHAR);
569 count = iconv(cd, (ICONV_CONST char **) &inbuf, &inbytes, &outbuf, &outbytes);
bd96aa53 570 IconvClose(cd);
284b15a4
VP
571
572 if (count == (size_t) - 1)
573 {
574 if (errno == EILSEQ)
575 {
576 count = (dstLen * sizeof(UCS2CHAR) - outbytes) / sizeof(UCS2CHAR);
577 }
578 else
579 {
580 count = 0;
581 }
582 }
583 else
584 {
585 count = (dstLen * sizeof(UCS2CHAR) - outbytes) / sizeof(UCS2CHAR);
586 }
587 if (((char *) outbuf - (char *) dst > sizeof(UCS2CHAR)) && (*dst == 0xFEFF))
588 {
589 // Remove UNICODE byte order indicator if presented
590 memmove(dst, &dst[1], (char *) outbuf - (char *) dst - sizeof(UCS2CHAR));
591 outbuf -= sizeof(UCS2CHAR);
592 }
593 if ((srcLen == -1) && (outbytes >= sizeof(UCS2CHAR)))
594 {
595 *((UCS2CHAR *) outbuf) = 0;
596 }
597
598 return count;
5039dede
AK
599}
600
1c45282c
VK
601#else /* __DISABLE_ICONV */
602
13469050
VP
603/**
604 * Convert UCS-2 to UCS-4
605 */
53c96e2d 606size_t LIBNETXMS_EXPORTABLE ucs2_to_ucs4(const UCS2CHAR *src, int srcLen, WCHAR *dst, int dstLen)
1c45282c 607{
284b15a4 608 return __internal_ucs2_to_ucs4(src, srcLen, dst, dstLen);
1c45282c
VK
609}
610
13469050
VP
611/**
612 * Convert UCS-4 to UCS-2
613 */
53c96e2d 614size_t LIBNETXMS_EXPORTABLE ucs4_to_ucs2(const WCHAR *src, int srcLen, UCS2CHAR *dst, int dstLen)
1c45282c 615{
284b15a4 616 return __internal_ucs4_to_ucs2(src, srcLen, dst, dstLen);
1c45282c
VK
617}
618
619#endif /* __DISABLE_ICONV */
620
13469050
VP
621/**
622 * Convert UCS-4 string to UCS-2 string allocating UCS-2 string dynamically
623 */
5039dede
AK
624UCS2CHAR LIBNETXMS_EXPORTABLE *UCS2StringFromUCS4String(const WCHAR *pwszString)
625{
626 UCS2CHAR *pszOut;
627 int nLen;
628
284b15a4
VP
629 nLen = (int) wcslen(pwszString) + 1;
630 pszOut = (UCS2CHAR *) malloc(nLen * sizeof(UCS2CHAR));
5039dede
AK
631 ucs4_to_ucs2(pwszString, -1, pszOut, nLen);
632 return pszOut;
633}
634
13469050
VP
635/**
636 * Convert UCS-2 string to UCS-4 string allocating UCS-4 string dynamically
637 */
5039dede
AK
638WCHAR LIBNETXMS_EXPORTABLE *UCS4StringFromUCS2String(const UCS2CHAR *pszString)
639{
640 WCHAR *pwszOut;
641 int nLen;
642
284b15a4
VP
643 nLen = (int) ucs2_strlen(pszString) + 1;
644 pwszOut = (WCHAR *) malloc(nLen * sizeof(WCHAR));
5039dede
AK
645 ucs2_to_ucs4(pszString, -1, pwszOut, nLen);
646 return pwszOut;
647}
648
13469050
VP
649/**
650 * Convert UCS-2 to UTF-8
651 */
284b15a4 652inline size_t ucs2_to_utf8_simple_copy(const UCS2CHAR *src, int srcLen, char *dst, int dstLen)
5039dede 653{
5039dede
AK
654 const UCS2CHAR *psrc;
655 char *pdst;
656 int pos, size;
657
658 size = (srcLen == -1) ? ucs2_strlen(src) : srcLen;
659 if (size >= dstLen)
660 size = dstLen - 1;
661 for(psrc = src, pos = 0, pdst = dst; pos < size; pos++, psrc++, pdst++)
284b15a4 662 *pdst = (*psrc < 256) ? (char) (*psrc) : '?';
5039dede
AK
663 *pdst = 0;
664 return size;
284b15a4
VP
665}
666
5d0d2fc6
VK
667#ifndef __DISABLE_ICONV
668
284b15a4
VP
669inline size_t ucs2_to_utf8_iconv(const UCS2CHAR *src, int srcLen, char *dst, int dstLen)
670{
671 iconv_t cd;
672 const char *inbuf;
673 char *outbuf;
674 size_t count, inbytes, outbytes;
675
bd96aa53 676 cd = IconvOpen("UTF-8", UCS2_CODEPAGE_NAME);
284b15a4
VP
677 if (cd == (iconv_t) (-1))
678 {
679 return ucs2_to_utf8_simple_copy(src, srcLen, dst, dstLen);
680 }
681
682 inbuf = (const char *) src;
683 inbytes = ((srcLen == -1) ? ucs2_strlen(src) + 1 : (size_t) srcLen) * sizeof(UCS2CHAR);
684 outbuf = (char *) dst;
685 outbytes = (size_t) dstLen;
686 count = iconv(cd, (ICONV_CONST char **) &inbuf, &inbytes, &outbuf, &outbytes);
bd96aa53 687 IconvClose(cd);
284b15a4
VP
688
689 if (count == (size_t) - 1)
690 {
691 if (errno == EILSEQ)
692 {
693 count = (dstLen * sizeof(char) - outbytes) / sizeof(char);
694 }
695 else
696 {
697 count = 0;
698 }
699 }
700 else
701 {
702 count = dstLen - outbytes;
703 }
704 if ((srcLen == -1) && (outbytes >= sizeof(char)))
705 {
706 *((char *) outbuf) = 0;
707 }
708
709 return count;
710}
711
5d0d2fc6
VK
712#endif
713
284b15a4
VP
714size_t LIBNETXMS_EXPORTABLE ucs2_to_utf8(const UCS2CHAR *src, int srcLen, char *dst, int dstLen)
715{
716#if HAVE_ICONV && !defined(__DISABLE_ICONV)
717 return ucs2_to_utf8_iconv(src, srcLen, dst, dstLen);
718#else
719 return ucs2_to_utf8_simple_copy(src, srcLen, dst, dstLen);
5039dede
AK
720#endif
721}
722
723#endif /* UNICODE_UCS4 */
724
76b1d3d8 725#if !defined(_WIN32)
5039dede 726
13469050
VP
727/**
728 * Convert UCS-2 to multibyte
729 */
13469050 730inline size_t ucs2_to_mb_simple_copy(const UCS2CHAR *src, int srcLen, char *dst, int dstLen)
5039dede 731{
5039dede
AK
732 const UCS2CHAR *psrc;
733 char *pdst;
734 int pos, size;
735
13469050 736 size = (srcLen == -1) ? (int) ucs2_strlen(src) : srcLen;
5039dede
AK
737 if (size >= dstLen)
738 size = dstLen - 1;
13469050 739
5039dede 740 for(psrc = src, pos = 0, pdst = dst; pos < size; pos++, psrc++, pdst++)
13469050 741 *pdst = (*psrc < 256) ? (char) (*psrc) : '?';
5039dede 742 *pdst = 0;
13469050 743
5039dede 744 return size;
13469050
VP
745}
746
5d0d2fc6
VK
747#ifndef __DISABLE_ICONV
748
13469050
VP
749inline size_t ucs2_to_mb_iconv(const UCS2CHAR *src, int srcLen, char *dst, int dstLen)
750{
751 iconv_t cd;
752 const char *inbuf;
753 char *outbuf;
754 size_t count, inbytes, outbytes;
755
bd96aa53 756 cd = IconvOpen(m_cpDefault, UCS2_CODEPAGE_NAME);
13469050
VP
757 if (cd == (iconv_t) (-1))
758 {
759 return ucs2_to_mb_simple_copy(src, srcLen, dst, dstLen);
760 }
761
762 inbuf = (const char *) src;
763 inbytes = ((srcLen == -1) ? ucs2_strlen(src) + 1 : (size_t) srcLen) * sizeof(UCS2CHAR);
764 outbuf = (char *) dst;
765 outbytes = (size_t) dstLen;
766 count = iconv(cd, (ICONV_CONST char **) &inbuf, &inbytes, &outbuf, &outbytes);
bd96aa53 767 IconvClose(cd);
13469050
VP
768
769 if (count == (size_t) - 1)
770 {
771 if (errno == EILSEQ)
772 {
773 count = (dstLen * sizeof(char) - outbytes) / sizeof(char);
774 }
775 else
776 {
777 count = 0;
778 }
779 }
780 if ((srcLen == -1) && (outbytes >= sizeof(char)))
781 {
782 *((char *) outbuf) = 0;
783 }
784
785 return count;
786}
787
5d0d2fc6
VK
788#endif
789
13469050
VP
790size_t LIBNETXMS_EXPORTABLE ucs2_to_mb(const UCS2CHAR *src, int srcLen, char *dst, int dstLen)
791{
792#if HAVE_ICONV && !defined(__DISABLE_ICONV)
284b15a4 793 return ucs2_to_mb_iconv(src, srcLen, dst, dstLen);
13469050 794#else
5d0d2fc6 795 return ucs2_to_mb_simple_copy(src, srcLen, dst, dstLen);
5039dede
AK
796#endif
797}
798
9fddfb91
VK
799/**
800 * Convert multibyte to UCS-2
801 */
13469050 802inline size_t mb_to_ucs2_simple_copy(const char *src, int srcLen, UCS2CHAR *dst, int dstLen)
5039dede 803{
13469050
VP
804 const char *psrc;
805 UCS2CHAR *pdst;
806 int pos, size;
807
808 size = (srcLen == -1) ? (int) strlen(src) : srcLen;
809 if (size >= dstLen)
810 size = dstLen - 1;
811
812 for(psrc = src, pos = 0, pdst = dst; pos < size; pos++, psrc++, pdst++)
813 *pdst = (UCS2CHAR) (*psrc);
814 *pdst = 0;
815
816 return size;
817}
818
5d0d2fc6
VK
819#ifndef __DISABLE_ICONV
820
13469050
VP
821inline size_t mb_to_ucs2_iconv(const char *src, int srcLen, UCS2CHAR *dst, int dstLen)
822{
823 iconv_t cd;
824 const char *inbuf;
825 char *outbuf;
826 size_t count, inbytes, outbytes;
827
bd96aa53 828 cd = IconvOpen(UCS2_CODEPAGE_NAME, m_cpDefault);
29dc8792
VP
829 if (cd == (iconv_t) (-1))
830 {
13469050 831 return mb_to_ucs2_simple_copy(src, srcLen, dst, dstLen);
29dc8792
VP
832 }
833
834 inbuf = (const char *) src;
835 inbytes = (srcLen == -1) ? strlen(src) + 1 : (size_t) srcLen;
836 outbuf = (char *) dst;
837 outbytes = (size_t) dstLen * sizeof(UCS2CHAR);
838 count = iconv(cd, (ICONV_CONST char **) &inbuf, &inbytes, &outbuf, &outbytes);
bd96aa53 839 IconvClose(cd);
13469050 840
29dc8792
VP
841 if (count == (size_t) - 1)
842 {
843 if (errno == EILSEQ)
844 {
845 count = (dstLen * sizeof(UCS2CHAR) - outbytes) / sizeof(UCS2CHAR);
846 }
847 else
848 {
849 count = 0;
850 }
851 }
852 if (((char *) outbuf - (char *) dst > sizeof(UCS2CHAR)) && (*dst == 0xFEFF))
853 {
854 // Remove UNICODE byte order indicator if presented
855 memmove(dst, &dst[1], (char *) outbuf - (char *) dst - sizeof(UCS2CHAR));
856 outbuf -= sizeof(UCS2CHAR);
857 }
858 if ((srcLen == -1) && (outbytes >= sizeof(UCS2CHAR)))
859 {
860 *((UCS2CHAR *) outbuf) = 0;
861 }
862
13469050
VP
863 return count;
864}
5039dede 865
5d0d2fc6
VK
866#endif
867
13469050
VP
868size_t LIBNETXMS_EXPORTABLE mb_to_ucs2(const char *src, int srcLen, UCS2CHAR *dst, int dstLen)
869{
870#if HAVE_ICONV && !defined(__DISABLE_ICONV)
871 return mb_to_ucs2_iconv(src, srcLen, dst, dstLen);
872#else
c6d16af6 873 return mb_to_ucs2_simple_copy(src, srcLen, dst, dstLen);
5039dede
AK
874#endif
875}
876
d47340fa 877#if !UNICODE_UCS2
9fddfb91
VK
878
879/**
880 * Convert multibyte string to UCS-2 string allocating UCS-2 string dynamically
881 */
39945910
VK
882UCS2CHAR LIBNETXMS_EXPORTABLE *UCS2StringFromMBString(const char *pszString)
883{
284b15a4
VP
884 UCS2CHAR *pszOut;
885 int nLen;
39945910 886
284b15a4
VP
887 nLen = (int) strlen(pszString) + 1;
888 pszOut = (UCS2CHAR *) malloc(nLen * sizeof(UCS2CHAR));
889 mb_to_ucs2(pszString, -1, pszOut, nLen);
890 return pszOut;
39945910 891}
39945910 892
9fddfb91
VK
893/**
894 * Convert UCS-2 string to multibyte string allocating multibyte string dynamically
895 */
39945910
VK
896char LIBNETXMS_EXPORTABLE *MBStringFromUCS2String(const UCS2CHAR *pszString)
897{
284b15a4
VP
898 char *pszOut;
899 int nLen;
39945910 900
284b15a4
VP
901 nLen = (int) ucs2_strlen(pszString) + 1;
902 pszOut = (char *) malloc(nLen);
903 ucs2_to_mb(pszString, -1, pszOut, nLen);
904 return pszOut;
39945910 905}
13469050
VP
906
907#endif /* !UNICODE_UCS2 */
39945910 908
76b1d3d8 909#endif /* !defined(_WIN32) */
5039dede 910
13469050
VP
911/**
912 * UNIX UNICODE specific wrapper functions
913 */
5039dede 914
842c22f4
AK
915#if !defined(_WIN32)
916
917#if !HAVE_WSTAT
918
919int wstat(const WCHAR *_path, struct stat *_sbuf)
920{
284b15a4
VP
921 char path[MAX_PATH];
922
923 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
924 _path, -1, path, MAX_PATH, NULL, NULL);
925 return stat(path, _sbuf);
842c22f4
AK
926}
927
13469050 928#endif /* !HAVE_WSTAT */
5039dede 929
842c22f4 930#if defined(UNICODE)
5039dede 931
13469050
VP
932/**
933 * Wide character version of some libc functions
934 */
5039dede 935
b07c50cc
VK
936#define DEFINE_PATH_FUNC(func) \
937int w##func(const WCHAR *_path) \
938{ \
939 char path[MAX_PATH]; \
1f2d100d
VK
940 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, _path, -1, path, MAX_PATH, NULL, NULL); \
941 return func(path); \
b07c50cc
VK
942}
943
944#if !HAVE_WCHDIR
945DEFINE_PATH_FUNC(chdir)
946#endif
947
948#if !HAVE_WRMDIR
949DEFINE_PATH_FUNC(rmdir)
950#endif
951
952#if !HAVE_WUNLINK
953DEFINE_PATH_FUNC(unlink)
954#endif
955
956#if !HAVE_WREMOVE
957DEFINE_PATH_FUNC(remove)
958#endif
959
dda7c270 960#if !HAVE_WMKSTEMP
3b864d8d
VK
961
962int LIBNETXMS_EXPORTABLE wmkstemp(WCHAR *_path)
963{
964 char path[MAX_PATH];
965 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, _path, -1, path, MAX_PATH, NULL, NULL);
966 int rc = mkstemp(path);
967 if (rc != -1)
968 {
969 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, path, -1, _path, wcslen(_path) + 1);
970 }
971 return rc;
972}
973
dda7c270
VK
974#endif
975
f3387429
VK
976#if !HAVE_WPOPEN
977
978FILE LIBNETXMS_EXPORTABLE *wpopen(const WCHAR *_command, const WCHAR *_type)
979{
284b15a4
VP
980 char *command, *type;
981 FILE *f;
982
983 command = MBStringFromWideString(_command);
984 type = MBStringFromWideString(_type);
985 f = popen(command, type);
986 free(command);
987 free(type);
988 return f;
f3387429
VK
989}
990
991#endif
992
5039dede
AK
993#if !HAVE_WFOPEN
994
995FILE LIBNETXMS_EXPORTABLE *wfopen(const WCHAR *_name, const WCHAR *_type)
996{
284b15a4
VP
997 char *name, *type;
998 FILE *f;
999
1000 name = MBStringFromWideString(_name);
1001 type = MBStringFromWideString(_type);
1002 f = fopen(name, type);
1003 free(name);
1004 free(type);
1005 return f;
5039dede
AK
1006}
1007
1008#endif
1009
8c2489aa
VK
1010#if HAVE_FOPEN64 && !HAVE_WFOPEN64
1011
1012FILE LIBNETXMS_EXPORTABLE *wfopen64(const WCHAR *_name, const WCHAR *_type)
1013{
1014 char *name, *type;
1015 FILE *f;
1016
1017 name = MBStringFromWideString(_name);
1018 type = MBStringFromWideString(_type);
1019 f = fopen64(name, type);
1020 free(name);
1021 free(type);
1022 return f;
1023}
1024
1025#endif
1026
5039dede
AK
1027#if !HAVE_WOPEN
1028
1029int LIBNETXMS_EXPORTABLE wopen(const WCHAR *_name, int flags, ...)
1030{
284b15a4
VP
1031 char *name;
1032 int rc;
1033
1034 name = MBStringFromWideString(_name);
1035 if (flags & O_CREAT)
1036 {
1037 va_list args;
1038
1039 va_start(args, flags);
1040 rc = open(name, flags, (mode_t)va_arg(args, int));
1041 va_end(args);
1042 }
1043 else
1044 {
1045 rc = open(name, flags);
1046 }
1047 free(name);
1048 return rc;
5039dede
AK
1049}
1050
1051#endif
1052
f3387429
VK
1053#if !HAVE_WCHMOD
1054
1055int LIBNETXMS_EXPORTABLE wchmod(const WCHAR *_name, int mode)
1056{
284b15a4
VP
1057 char *name;
1058 int rc;
1059
1060 name = MBStringFromWideString(_name);
1061 rc = chmod(name, mode);
1062 free(name);
1063 return rc;
f3387429
VK
1064}
1065
1066#endif
1067
b07c50cc 1068#if !HAVE_WRENAME
6d738067 1069
b07c50cc
VK
1070int wrename(const WCHAR *_oldpath, const WCHAR *_newpath)
1071{
284b15a4
VP
1072 char oldpath[MAX_PATH], newpath[MAX_PATH];
1073
1074 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
1075 _oldpath, -1, oldpath, MAX_PATH, NULL, NULL);
1076 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
1077 _newpath, -1, newpath, MAX_PATH, NULL, NULL);
1078 return rename(oldpath, newpath);
b07c50cc
VK
1079}
1080
1081#endif
1082
1083#if !HAVE_WSYSTEM
1084
1085int wsystem(const WCHAR *_cmd)
1086{
284b15a4
VP
1087 char *cmd = MBStringFromWideString(_cmd);
1088 int rc = system(cmd);
1089 free(cmd);
1090 return rc;
b07c50cc
VK
1091}
1092
1093#endif
1094
1095#if !HAVE_WACCESS
1096
1097int waccess(const WCHAR *_path, int mode)
6d738067 1098{
284b15a4
VP
1099 char path[MAX_PATH];
1100
1101 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
1102 _path, -1, path, MAX_PATH, NULL, NULL);
1103 return access(path, mode);
6d738067
VK
1104}
1105
1106#endif
1107
b07c50cc 1108#if !HAVE_WMKDIR
6d738067 1109
b07c50cc 1110int wmkdir(const WCHAR *_path, int mode)
6d738067 1111{
284b15a4
VP
1112 char path[MAX_PATH];
1113
1114 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
1115 _path, -1, path, MAX_PATH, NULL, NULL);
1116 return mkdir(path, mode);
6d738067
VK
1117}
1118
1119#endif
1120
5039dede
AK
1121#if !HAVE_WGETENV
1122
1123WCHAR *wgetenv(const WCHAR *_string)
1124{
284b15a4
VP
1125 char name[256], *p;
1126 static WCHAR value[8192];
1127
1128 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, _string, -1, name, 256, NULL, NULL);
1129 p = getenv(name);
1130 if (p == NULL)
4a7d46f4 1131 return NULL;
284b15a4
VP
1132
1133 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, p, -1, value, 8192);
1134 return value;
5039dede
AK
1135}
1136
1137#endif
1138
f3387429
VK
1139#if !HAVE_WCTIME
1140
1141WCHAR *wctime(const time_t *timep)
1142{
284b15a4
VP
1143 static WCHAR value[256];
1144
1145 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, ctime(timep), -1, value, 256);
1146 return value;
f3387429
VK
1147}
1148
29dc8792 1149#endif /* HAVE_WCTIME */
f3387429 1150
0186b5da
VK
1151#if !HAVE_PUTWS
1152
1153int putws(const WCHAR *s)
1154{
1155#if HAVE_FPUTWS
284b15a4
VP
1156 fputws(s, stdout);
1157 putwc(L'\n', stdout);
0186b5da 1158#else
284b15a4 1159 printf("%S\n", s);
13469050 1160#endif /* HAVE_FPUTWS */
284b15a4 1161 return 1;
0186b5da
VK
1162}
1163
13469050 1164#endif /* !HAVE_PUTWS */
0186b5da 1165
5039dede
AK
1166#if !HAVE_WCSERROR && HAVE_STRERROR
1167
1168WCHAR *wcserror(int errnum)
1169{
284b15a4 1170 static WCHAR value[8192];
5039dede 1171
284b15a4
VP
1172 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, strerror(errnum), -1, value, 8192);
1173 return value;
5039dede
AK
1174}
1175
13469050 1176#endif /* !HAVE_WCSERROR && HAVE_STRERROR */
5039dede
AK
1177
1178#if !HAVE_WCSERROR_R && HAVE_STRERROR_R
1179
b0823d06
VK
1180#if HAVE_POSIX_STRERROR_R
1181int wcserror_r(int errnum, WCHAR *strerrbuf, size_t buflen)
1182#else
5039dede 1183WCHAR *wcserror_r(int errnum, WCHAR *strerrbuf, size_t buflen)
13469050 1184#endif /* HAVE_POSIX_STRERROR_R */
5039dede 1185{
284b15a4 1186 char *mbbuf;
b0823d06 1187#if HAVE_POSIX_STRERROR_R
284b15a4 1188 int err;
13469050 1189#endif /* HAVE_POSIX_STRERROR_R */
5039dede 1190
284b15a4
VP
1191 mbbuf = (char *)malloc(buflen);
1192 if (mbbuf != NULL)
1193 {
b0823d06 1194#if HAVE_POSIX_STRERROR_R
284b15a4
VP
1195 err = strerror_r(errnum, mbbuf, buflen);
1196 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, mbbuf, -1, strerrbuf, buflen);
b0823d06 1197#else
284b15a4 1198 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, strerror_r(errnum, mbbuf, buflen), -1, strerrbuf, buflen);
b0823d06 1199#endif
284b15a4
VP
1200 free(mbbuf);
1201 }
1202 else
1203 {
1204 *strerrbuf = 0;
1205 }
b0823d06
VK
1206
1207#if HAVE_POSIX_STRERROR_R
284b15a4 1208 return err;
b0823d06 1209#else
284b15a4 1210 return strerrbuf;
b0823d06 1211#endif
5039dede
AK
1212}
1213
13469050
VP
1214#endif /* !HAVE_WCSERROR_R && HAVE_STRERROR_R */
1215
1216#endif /* defined(UNICODE) */
5039dede 1217
13469050
VP
1218/**
1219 * Wrappers for wprintf/wscanf family
1220 *
1221 * All these wrappers replaces %s with %S and %c with %C
1222 * because in POSIX version of wprintf functions %s and %c
1223 * means "multibyte string/char" instead of expected "UNICODE string/char"
1224 */
5039dede
AK
1225
1226int LIBNETXMS_EXPORTABLE nx_wprintf(const WCHAR *format, ...)
1227{
284b15a4
VP
1228 va_list args;
1229 int rc;
5039dede 1230
284b15a4
VP
1231 va_start(args, format);
1232 rc = nx_vwprintf(format, args);
1233 va_end(args);
1234 return rc;
5039dede
AK
1235}
1236
1237int LIBNETXMS_EXPORTABLE nx_fwprintf(FILE *fp, const WCHAR *format, ...)
1238{
284b15a4
VP
1239 va_list args;
1240 int rc;
5039dede 1241
284b15a4
VP
1242 va_start(args, format);
1243 rc = nx_vfwprintf(fp, format, args);
1244 va_end(args);
1245 return rc;
5039dede
AK
1246}
1247
1248int LIBNETXMS_EXPORTABLE nx_swprintf(WCHAR *buffer, size_t size, const WCHAR *format, ...)
1249{
284b15a4
VP
1250 va_list args;
1251 int rc;
5039dede 1252
284b15a4
VP
1253 va_start(args, format);
1254 rc = nx_vswprintf(buffer, size, format, args);
1255 va_end(args);
1256 return rc;
5039dede
AK
1257}
1258
25575d38
VK
1259int LIBNETXMS_EXPORTABLE nx_wscanf(const WCHAR *format, ...)
1260{
284b15a4
VP
1261 va_list args;
1262 int rc;
25575d38 1263
284b15a4
VP
1264 va_start(args, format);
1265 rc = nx_vwscanf(format, args);
1266 va_end(args);
1267 return rc;
25575d38
VK
1268}
1269
1270int LIBNETXMS_EXPORTABLE nx_fwscanf(FILE *fp, const WCHAR *format, ...)
1271{
284b15a4
VP
1272 va_list args;
1273 int rc;
25575d38 1274
284b15a4
VP
1275 va_start(args, format);
1276 rc = nx_vfwscanf(fp, format, args);
1277 va_end(args);
1278 return rc;
25575d38
VK
1279}
1280
7ff399a5 1281int LIBNETXMS_EXPORTABLE nx_swscanf(const WCHAR *str, const WCHAR *format, ...)
25575d38 1282{
284b15a4
VP
1283 va_list args;
1284 int rc;
25575d38 1285
284b15a4
VP
1286 va_start(args, format);
1287 rc = nx_vswscanf(str, format, args);
1288 va_end(args);
1289 return rc;
25575d38
VK
1290}
1291
5039dede
AK
1292static WCHAR *ReplaceFormatSpecs(const WCHAR *oldFormat)
1293{
284b15a4
VP
1294 WCHAR *fmt, *p;
1295 int state = 0;
1296 bool hmod;
1297
1298 fmt = wcsdup(oldFormat);
1299 for(p = fmt; *p != 0; p++)
1300 {
1301 switch (state)
1302 {
1303 case 0: // Normal text
1304 if (*p == L'%')
1305 {
1306 state = 1;
1307 hmod = false;
1308 }
1309 break;
1310 case 1: // Format start
1311 switch (*p)
1312 {
1313 case L's':
1314 if (hmod)
1315 {
1316 memmove(p - 1, p, wcslen(p - 1) * sizeof(TCHAR));
1317 }
1318 else
1319 {
1320 *p = L'S';
1321 }
1322 state = 0;
1323 break;
1324 case L'S':
1325 *p = L's';
1326 state = 0;
1327 break;
1328 case L'c':
1329 if (hmod)
1330 {
1331 memmove(p - 1, p, wcslen(p - 1) * sizeof(TCHAR));
1332 }
1333 else
1334 {
1335 *p = L'C';
1336 }
1337 state = 0;
1338 break;
1339 case L'C':
1340 *p = L'c';
1341 state = 0;
1342 break;
1343 case L'.': // All this characters could be part of format specifier
1344 case L'*': // and has no interest for us
1345 case L'+':
1346 case L'-':
1347 case L' ':
1348 case L'#':
1349 case L'0':
1350 case L'1':
1351 case L'2':
1352 case L'3':
1353 case L'4':
1354 case L'5':
1355 case L'6':
1356 case L'7':
1357 case L'8':
1358 case L'9':
1359 case L'l':
1360 case L'L':
1361 case L'F':
1362 case L'N':
1363 case L'w':
1364 break;
1365 case L'h': // check for %hs
1366 hmod = true;
1367 break;
1368 default: // All other cahacters means end of format
1369 state = 0;
1370 break;
1371
1372 }
1373 break;
1374 }
1375 }
1376 return fmt;
5039dede
AK
1377}
1378
1379int LIBNETXMS_EXPORTABLE nx_vwprintf(const WCHAR *format, va_list args)
1380{
284b15a4
VP
1381 WCHAR *fmt;
1382 int rc;
5039dede 1383
284b15a4
VP
1384 fmt = ReplaceFormatSpecs(format);
1385 rc = vwprintf(fmt, args);
1386 free(fmt);
1387 return rc;
5039dede
AK
1388}
1389
1390int LIBNETXMS_EXPORTABLE nx_vfwprintf(FILE *fp, const WCHAR *format, va_list args)
1391{
284b15a4
VP
1392 WCHAR *fmt;
1393 int rc;
5039dede 1394
284b15a4
VP
1395 fmt = ReplaceFormatSpecs(format);
1396 rc = vfwprintf(fp, fmt, args);
1397 free(fmt);
1398 return rc;
5039dede
AK
1399}
1400
1401int LIBNETXMS_EXPORTABLE nx_vswprintf(WCHAR *buffer, size_t size, const WCHAR *format, va_list args)
1402{
284b15a4
VP
1403 WCHAR *fmt;
1404 int rc;
5039dede 1405
284b15a4
VP
1406 fmt = ReplaceFormatSpecs(format);
1407 rc = vswprintf(buffer, size, fmt, args);
1408 free(fmt);
1409 return rc;
5039dede
AK
1410}
1411
25575d38
VK
1412int LIBNETXMS_EXPORTABLE nx_vwscanf(const WCHAR *format, va_list args)
1413{
284b15a4
VP
1414 WCHAR *fmt;
1415 int rc;
25575d38 1416
284b15a4 1417 fmt = ReplaceFormatSpecs(format);
5a64ab96 1418#if HAVE_VWSCANF
284b15a4 1419 rc = vwscanf(fmt, args);
5a64ab96 1420#else
284b15a4 1421 rc = -1; // FIXME: add workaround implementation
5a64ab96 1422#endif
284b15a4
VP
1423 free(fmt);
1424 return rc;
25575d38
VK
1425}
1426
1427int LIBNETXMS_EXPORTABLE nx_vfwscanf(FILE *fp, const WCHAR *format, va_list args)
1428{
284b15a4
VP
1429 WCHAR *fmt;
1430 int rc;
25575d38 1431
284b15a4 1432 fmt = ReplaceFormatSpecs(format);
5a64ab96 1433#if HAVE_VFWSCANF
284b15a4 1434 rc = vfwscanf(fp, fmt, args);
5a64ab96 1435#else
284b15a4 1436 rc = -1; // FIXME: add workaround implementation
5a64ab96 1437#endif
284b15a4
VP
1438 free(fmt);
1439 return rc;
25575d38
VK
1440}
1441
7ff399a5 1442int LIBNETXMS_EXPORTABLE nx_vswscanf(const WCHAR *str, const WCHAR *format, va_list args)
25575d38 1443{
284b15a4
VP
1444 WCHAR *fmt;
1445 int rc;
25575d38 1446
284b15a4 1447 fmt = ReplaceFormatSpecs(format);
5a64ab96 1448#if HAVE_VSWSCANF
284b15a4 1449 rc = vswscanf(str, fmt, args);
5a64ab96 1450#else
284b15a4 1451 rc = -1; // FIXME: add workaround implementation
5a64ab96 1452#endif
284b15a4
VP
1453 free(fmt);
1454 return rc;
25575d38 1455}
29dc8792 1456#endif /* !defined(_WIN32) */