fixed incorrect fallback character conversion
[public/netxms.git] / src / libnetxms / unicode.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2016 Raden Solutions
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 **/
22
23 #include "libnetxms.h"
24
25 /**
26 * Default codepage
27 */
28 static char m_cpDefault[MAX_CODEPAGE_LEN] = ICONV_DEFAULT_CODEPAGE;
29
30 #ifndef _WIN32
31
32 #if HAVE_ICONV_H
33 #include <iconv.h>
34 #endif
35
36 /**
37 * UNICODE character set
38 */
39 #ifndef __DISABLE_ICONV
40
41 // iconv cache functions
42 #if WITH_ICONV_CACHE
43 iconv_t IconvOpen(const char *to, const char *from);
44 void IconvClose(iconv_t cd);
45 #else
46 #define IconvOpen iconv_open
47 #define IconvClose iconv_close
48 #endif
49
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"
67 #elif HAVE_ICONV_UTF_16
68 #define UCS2_CODEPAGE_NAME "UTF-16"
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"
88 #elif HAVE_ICONV_UTF_32
89 #define UCS4_CODEPAGE_NAME "UTF-32"
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
107 /**
108 * Set application's default codepage
109 */
110 BOOL LIBNETXMS_EXPORTABLE SetDefaultCodepage(const char *cp)
111 {
112 BOOL rc;
113 #if HAVE_ICONV && !defined(__DISABLE_ICONV)
114 iconv_t cd;
115
116 cd = iconv_open(cp, "UTF-8");
117 if (cd != (iconv_t) (-1))
118 {
119 iconv_close(cd);
120 #endif
121 strncpy(m_cpDefault, cp, MAX_CODEPAGE_LEN);
122 m_cpDefault[MAX_CODEPAGE_LEN - 1] = 0;
123 rc = TRUE;
124 #if HAVE_ICONV && !defined(__DISABLE_ICONV)
125 }
126 else
127 {
128 rc = FALSE;
129 }
130 #endif
131 return rc;
132 }
133
134 #if !UNICODE_UCS2 || !HAVE_WCSLEN
135
136 /**
137 * Calculate length of wide character string
138 */
139 int 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
151 #if !UNICODE_UCS2 || !HAVE_WCSDUP
152
153 /**
154 * Duplicate wide character string
155 */
156 UCS2CHAR LIBNETXMS_EXPORTABLE *ucs2_strdup(const UCS2CHAR *pStr)
157 {
158 return (UCS2CHAR *) nx_memdup(pStr, (ucs2_strlen(pStr) + 1) * sizeof(UCS2CHAR));
159 }
160
161 #endif
162
163 #if !UNICODE_UCS2 || !HAVE_WCSNCPY
164
165 /**
166 * Copy wide character string with length limitation
167 */
168 UCS2CHAR LIBNETXMS_EXPORTABLE *ucs2_strncpy(UCS2CHAR *pDst, const UCS2CHAR *pSrc, int nDstLen)
169 {
170 int nLen;
171
172 nLen = ucs2_strlen(pSrc) + 1;
173 if (nLen > nDstLen)
174 nLen = nDstLen;
175 memcpy(pDst, pSrc, nLen * sizeof(UCS2CHAR));
176 return pDst;
177 }
178
179 #endif
180
181 /**
182 * Convert UNICODE string to single-byte string using simple byte copy (works for ASCII only)
183 */
184 static int WideCharToMultiByteSimpleCopy(int iCodePage, DWORD dwFlags, const WCHAR *pWideCharStr,
185 int cchWideChar, char *pByteStr, int cchByteChar, char *pDefaultChar, BOOL *pbUsedDefChar)
186 {
187 const WCHAR *pSrc;
188 char *pDest;
189 int iPos, iSize;
190
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++)
195 *pDest = (*pSrc < 128) ? (char)(*pSrc) : '?';
196 *pDest = 0;
197
198 return iSize;
199 }
200
201 #ifndef __DISABLE_ICONV
202
203 /**
204 * Convert UNICODE string to single-byte string using iconv
205 */
206 static int WideCharToMultiByteIconv(int iCodePage, DWORD dwFlags, const WCHAR *pWideCharStr, int cchWideChar,
207 char *pByteStr, int cchByteChar, char *pDefaultChar, BOOL *pbUsedDefChar)
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
216 strcpy(cp, m_cpDefault);
217 #if HAVE_ICONV_IGNORE
218 strcat(cp, "//IGNORE");
219 #endif /* HAVE_ICONV_IGNORE */
220
221 cd = IconvOpen(iCodePage == CP_UTF8 ? "UTF-8" : cp, UNICODE_CODEPAGE_NAME);
222 if (cd == (iconv_t)(-1))
223 {
224 return WideCharToMultiByteSimpleCopy(iCodePage, dwFlags, pWideCharStr, cchWideChar, pByteStr, cchByteChar, pDefaultChar, pbUsedDefChar);
225 }
226
227 inbuf = (const char *)pWideCharStr;
228 inbytes = ((cchWideChar == -1) ? wcslen(pWideCharStr) + 1 : cchWideChar) * sizeof(WCHAR);
229 outbuf = pByteStr;
230 outbytes = cchByteChar;
231 nRet = iconv(cd, (ICONV_CONST char **)&inbuf, &inbytes, &outbuf, &outbytes);
232 IconvClose(cd);
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 (outbytes > 0)
249 {
250 *outbuf = 0;
251 }
252
253 return nRet;
254 }
255
256 #endif
257
258 /**
259 * Convert UNICODE string to single-byte string
260 */
261 int LIBNETXMS_EXPORTABLE WideCharToMultiByte(int iCodePage, DWORD dwFlags, const WCHAR *pWideCharStr, int cchWideChar,
262 char *pByteStr, int cchByteChar, char *pDefaultChar, BOOL *pbUsedDefChar)
263 {
264 #if HAVE_ICONV && !defined(__DISABLE_ICONV)
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
273 return WideCharToMultiByteIconv(iCodePage, dwFlags, pWideCharStr, cchWideChar, pByteStr, cchByteChar, pDefaultChar, pbUsedDefChar);
274 #else
275 if (cchByteChar == 0)
276 {
277 return wcslen(pWideCharStr) + 1;
278 }
279
280 return WideCharToMultiByteSimpleCopy(iCodePage, dwFlags, pWideCharStr, cchWideChar, pByteStr, cchByteChar, pDefaultChar, pbUsedDefChar);
281 #endif
282 }
283
284 /**
285 * Convert single-byte to UNICODE string using simple byte copy (works correctly for ASCII only)
286 */
287 static int MultiByteToWideCharSimpleCopy(int iCodePage, DWORD dwFlags, const char *pByteStr, int cchByteChar, WCHAR *pWideCharStr, int cchWideChar)
288 {
289 const char *pSrc;
290 WCHAR *pDest;
291 int iPos, iSize;
292
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 = ((*pSrc) < 128) ? (WCHAR)(*pSrc) : L'?';
298 *pDest = 0;
299
300 return iSize;
301 }
302
303 #ifndef __DISABLE_ICONV
304
305 /**
306 * Convert single-byte to UNICODE string using iconv
307 */
308 static int MultiByteToWideCharIconv(int iCodePage, DWORD dwFlags, const char *pByteStr, int cchByteChar, WCHAR *pWideCharStr, int cchWideChar)
309 {
310 iconv_t cd;
311 int nRet;
312 const char *inbuf;
313 char *outbuf;
314 size_t inbytes, outbytes;
315
316 cd = IconvOpen(UNICODE_CODEPAGE_NAME, iCodePage == CP_UTF8 ? "UTF-8" : m_cpDefault);
317 if (cd == (iconv_t)(-1))
318 {
319 return MultiByteToWideCharSimpleCopy(iCodePage, dwFlags, pByteStr, cchByteChar, pWideCharStr, cchWideChar);
320 }
321
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);
327 IconvClose(cd);
328
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 (outbytes >= sizeof(WCHAR))
352 {
353 *((WCHAR *)outbuf) = 0;
354 }
355
356 return nRet;
357 }
358
359 #endif
360
361 /**
362 * Convert single-byte to UNICODE string
363 */
364 int LIBNETXMS_EXPORTABLE MultiByteToWideChar(int iCodePage, DWORD dwFlags, const char *pByteStr, int cchByteChar, WCHAR *pWideCharStr, int cchWideChar)
365 {
366 if (cchWideChar == 0)
367 {
368 return strlen(pByteStr) + 1;
369 }
370
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
376 }
377
378 #endif /* not _WIN32 */
379
380 /**
381 * UNICODE version of inet_addr()
382 */
383 UINT32 LIBNETXMS_EXPORTABLE inet_addr_w(const WCHAR *pszAddr)
384 {
385 char szBuffer[256];
386 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, pszAddr, -1, szBuffer, 256, NULL, NULL);
387 return inet_addr(szBuffer);
388 }
389
390 /**
391 * Convert multibyte string to wide string using current LC_CTYPE setting and
392 * allocating wide string dynamically
393 */
394 WCHAR LIBNETXMS_EXPORTABLE *WideStringFromMBStringSysLocale(const char *pszString)
395 {
396 #ifdef _WIN32
397 return WideStringFromMBString(pszString);
398 #else
399 if (pszString == NULL)
400 return NULL;
401 int nLen = (int)strlen(pszString) + 1;
402 WCHAR *pwszOut = (WCHAR *) malloc(nLen * sizeof(WCHAR));
403 #if HAVE_MBSTOWCS
404 mbstowcs(pwszOut, pszString, nLen);
405 #else
406 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszString, -1, pwszOut, nLen);
407 #endif
408 return pwszOut;
409 #endif
410 }
411
412 /**
413 * Convert multibyte string to wide string using current codepage and
414 * allocating wide string dynamically
415 */
416 WCHAR LIBNETXMS_EXPORTABLE *WideStringFromMBString(const char *pszString)
417 {
418 if (pszString == NULL)
419 return NULL;
420 int nLen = (int) strlen(pszString) + 1;
421 WCHAR *pwszOut = (WCHAR *) malloc(nLen * sizeof(WCHAR));
422 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszString, -1, pwszOut, nLen);
423 return pwszOut;
424 }
425
426 /**
427 * Convert wide string to UTF8 string allocating wide string dynamically
428 */
429 WCHAR LIBNETXMS_EXPORTABLE *WideStringFromUTF8String(const char *pszString)
430 {
431 if (pszString == NULL)
432 return NULL;
433 int nLen = (int)strlen(pszString) + 1;
434 WCHAR *pwszOut = (WCHAR *) malloc(nLen * sizeof(WCHAR));
435 MultiByteToWideChar(CP_UTF8, 0, pszString, -1, pwszOut, nLen);
436 return pwszOut;
437 }
438
439 /**
440 * Convert wide string to multibyte string using current codepage and
441 * allocating multibyte string dynamically
442 */
443 char LIBNETXMS_EXPORTABLE *MBStringFromWideString(const WCHAR *pwszString)
444 {
445 if (pwszString == NULL)
446 return NULL;
447 int nLen = (int)wcslen(pwszString) + 1;
448 char *pszOut = (char *)malloc(nLen);
449 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, pwszString, -1, pszOut, nLen, NULL, NULL);
450 return pszOut;
451 }
452
453 /**
454 * Convert wide string to multibyte string using current LC_CTYPE setting and
455 * allocating multibyte string dynamically
456 */
457 char LIBNETXMS_EXPORTABLE *MBStringFromWideStringSysLocale(const WCHAR *pwszString)
458 {
459 #ifdef _WIN32
460 return MBStringFromWideString(pwszString);
461 #else
462 if (pwszString == NULL)
463 return NULL;
464 int nLen = (int)wcslen(pwszString) + 1;
465 char *pszOut = (char *)malloc(nLen);
466 #if HAVE_WCSTOMBS
467 wcstombs(pszOut, pwszString, nLen);
468 #else
469 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, pwszString, -1, pszOut, nLen, NULL, NULL);
470 #endif
471 return pszOut;
472 #endif
473 }
474
475 /**
476 * Convert wide string to UTF8 string allocating UTF8 string dynamically
477 */
478 char LIBNETXMS_EXPORTABLE *UTF8StringFromWideString(const WCHAR *pwszString)
479 {
480 char *pszOut;
481 int nLen;
482
483 nLen = WideCharToMultiByte(CP_UTF8, 0, pwszString, -1, NULL, 0, NULL, NULL);
484 pszOut = (char *)malloc(nLen);
485 WideCharToMultiByte(CP_UTF8, 0, pwszString, -1, pszOut, nLen, NULL, NULL);
486 return pszOut;
487 }
488
489 /**
490 * Convert UTF8 string to multibyte string using current codepage and
491 * allocating multibyte string dynamically
492 */
493 char LIBNETXMS_EXPORTABLE *MBStringFromUTF8String(const char *s)
494 {
495 int len = (int)strlen(s) + 1;
496 char *out = (char *)malloc(len);
497 utf8_to_mb(s, -1, out, len);
498 return out;
499 }
500
501 /**
502 * Convert multibyte string to UTF8 string allocating UTF8 string dynamically
503 */
504 char LIBNETXMS_EXPORTABLE *UTF8StringFromMBString(const char *s)
505 {
506 int len = (int)strlen(s) * 3 + 1; // assume worst case - 3 bytes per character
507 char *out = (char *)malloc(len);
508 mb_to_utf8(s, -1, out, len);
509 return out;
510 }
511
512 /**
513 * Get OpenSSL error string as UNICODE string
514 * Buffer must be at least 256 character long
515 */
516
517 #ifdef _WITH_ENCRYPTION
518
519 WCHAR LIBNETXMS_EXPORTABLE *ERR_error_string_W(int nError, WCHAR *pwszBuffer)
520 {
521 char text[256];
522
523 memset(text, 0, sizeof(text));
524 ERR_error_string(nError, text);
525 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, text, -1, pwszBuffer, 256);
526 return pwszBuffer;
527 }
528
529 #endif
530
531 #ifdef UNICODE_UCS4
532
533 /**
534 * Convert UCS-2 to UCS-4 - internal dumb method
535 */
536 static size_t __internal_ucs2_to_ucs4(const UCS2CHAR *src, int srcLen, WCHAR *dst, int dstLen)
537 {
538 int i, len;
539
540 len = (int) ((srcLen == -1) ? ucs2_strlen(src) : srcLen);
541 if (len > (int) dstLen - 1)
542 len = (int) dstLen - 1;
543 for(i = 0; i < len; i++)
544 dst[i] = (WCHAR) src[i];
545 dst[i] = 0;
546 return len;
547 }
548
549 /**
550 * Convert UCS-4 to UCS-2 - internal dumb method
551 */
552 static size_t __internal_ucs4_to_ucs2(const WCHAR *src, int srcLen, UCS2CHAR *dst, int dstLen)
553 {
554 int i, len;
555
556 len = (int) ((srcLen == -1) ? wcslen(src) : srcLen);
557 if (len > (int) dstLen - 1)
558 len = (int) dstLen - 1;
559 for(i = 0; i < len; i++)
560 dst[i] = (UCS2CHAR) src[i];
561 dst[i] = 0;
562 return len;
563 }
564
565 #ifndef __DISABLE_ICONV
566
567 /**
568 * Convert UCS-2 to UCS-4
569 */
570 size_t LIBNETXMS_EXPORTABLE ucs2_to_ucs4(const UCS2CHAR *src, int srcLen, WCHAR *dst, int dstLen)
571 {
572 iconv_t cd;
573 const char *inbuf;
574 char *outbuf;
575 size_t count, inbytes, outbytes;
576
577 cd = IconvOpen(UCS4_CODEPAGE_NAME, UCS2_CODEPAGE_NAME);
578 if (cd == (iconv_t) (-1))
579 {
580 return __internal_ucs2_to_ucs4(src, srcLen, dst, dstLen);
581 }
582
583 inbuf = (const char *) src;
584 inbytes = ((srcLen == -1) ? ucs2_strlen(src) + 1 : (size_t) srcLen) * sizeof(UCS2CHAR);
585 outbuf = (char *) dst;
586 outbytes = (size_t) dstLen * sizeof(WCHAR);
587 count = iconv(cd, (ICONV_CONST char **) &inbuf, &inbytes, &outbuf, &outbytes);
588 IconvClose(cd);
589
590 if (count == (size_t) - 1)
591 {
592 if (errno == EILSEQ)
593 {
594 count = (dstLen * sizeof(WCHAR) - outbytes) / sizeof(WCHAR);
595 }
596 else
597 {
598 count = 0;
599 }
600 }
601 else
602 {
603 count = (dstLen * sizeof(WCHAR) - outbytes) / sizeof(WCHAR);
604 }
605 if ((srcLen == -1) && (outbytes >= sizeof(WCHAR)))
606 {
607 *((WCHAR *) outbuf) = 0;
608 }
609
610 return count;
611 }
612
613 /**
614 * Convert UCS-4 to UCS-2
615 */
616 size_t LIBNETXMS_EXPORTABLE ucs4_to_ucs2(const WCHAR *src, int srcLen, UCS2CHAR *dst, int dstLen)
617 {
618 iconv_t cd;
619 const char *inbuf;
620 char *outbuf;
621 size_t count, inbytes, outbytes;
622
623 cd = IconvOpen(UCS2_CODEPAGE_NAME, UCS4_CODEPAGE_NAME);
624 if (cd == (iconv_t) (-1))
625 {
626 return __internal_ucs4_to_ucs2(src, srcLen, dst, dstLen);
627 }
628
629 inbuf = (const char *) src;
630 inbytes = ((srcLen == -1) ? wcslen(src) + 1 : (size_t) srcLen) * sizeof(WCHAR);
631 outbuf = (char *) dst;
632 outbytes = (size_t) dstLen * sizeof(UCS2CHAR);
633 count = iconv(cd, (ICONV_CONST char **) &inbuf, &inbytes, &outbuf, &outbytes);
634 IconvClose(cd);
635
636 if (count == (size_t) - 1)
637 {
638 if (errno == EILSEQ)
639 {
640 count = (dstLen * sizeof(UCS2CHAR) - outbytes) / sizeof(UCS2CHAR);
641 }
642 else
643 {
644 count = 0;
645 }
646 }
647 else
648 {
649 count = (dstLen * sizeof(UCS2CHAR) - outbytes) / sizeof(UCS2CHAR);
650 }
651 if (((char *) outbuf - (char *) dst > sizeof(UCS2CHAR)) && (*dst == 0xFEFF))
652 {
653 // Remove UNICODE byte order indicator if presented
654 memmove(dst, &dst[1], (char *) outbuf - (char *) dst - sizeof(UCS2CHAR));
655 outbuf -= sizeof(UCS2CHAR);
656 }
657 if ((srcLen == -1) && (outbytes >= sizeof(UCS2CHAR)))
658 {
659 *((UCS2CHAR *) outbuf) = 0;
660 }
661
662 return count;
663 }
664
665 #else /* __DISABLE_ICONV */
666
667 /**
668 * Convert UCS-2 to UCS-4
669 */
670 size_t LIBNETXMS_EXPORTABLE ucs2_to_ucs4(const UCS2CHAR *src, int srcLen, WCHAR *dst, int dstLen)
671 {
672 return __internal_ucs2_to_ucs4(src, srcLen, dst, dstLen);
673 }
674
675 /**
676 * Convert UCS-4 to UCS-2
677 */
678 size_t LIBNETXMS_EXPORTABLE ucs4_to_ucs2(const WCHAR *src, int srcLen, UCS2CHAR *dst, int dstLen)
679 {
680 return __internal_ucs4_to_ucs2(src, srcLen, dst, dstLen);
681 }
682
683 #endif /* __DISABLE_ICONV */
684
685 /**
686 * Convert UCS-4 string to UCS-2 string allocating UCS-2 string dynamically
687 */
688 UCS2CHAR LIBNETXMS_EXPORTABLE *UCS2StringFromUCS4String(const WCHAR *pwszString)
689 {
690 UCS2CHAR *pszOut;
691 int nLen;
692
693 nLen = (int) wcslen(pwszString) + 1;
694 pszOut = (UCS2CHAR *) malloc(nLen * sizeof(UCS2CHAR));
695 ucs4_to_ucs2(pwszString, -1, pszOut, nLen);
696 return pszOut;
697 }
698
699 /**
700 * Convert UCS-2 string to UCS-4 string allocating UCS-4 string dynamically
701 */
702 WCHAR LIBNETXMS_EXPORTABLE *UCS4StringFromUCS2String(const UCS2CHAR *pszString)
703 {
704 WCHAR *pwszOut;
705 int nLen;
706
707 nLen = (int) ucs2_strlen(pszString) + 1;
708 pwszOut = (WCHAR *) malloc(nLen * sizeof(WCHAR));
709 ucs2_to_ucs4(pszString, -1, pwszOut, nLen);
710 return pwszOut;
711 }
712
713 /**
714 * Convert UCS-2 to UTF-8 using stub (no actual conversion for character codes above 0x007F)
715 */
716 static size_t ucs2_to_utf8_simple_copy(const UCS2CHAR *src, int srcLen, char *dst, int dstLen)
717 {
718 const UCS2CHAR *psrc;
719 char *pdst;
720 int pos, size;
721
722 size = (srcLen == -1) ? ucs2_strlen(src) : srcLen;
723 if (size >= dstLen)
724 size = dstLen - 1;
725 for(psrc = src, pos = 0, pdst = dst; pos < size; pos++, psrc++, pdst++)
726 *pdst = (*psrc < 128) ? (char) (*psrc) : '?';
727 *pdst = 0;
728 return size;
729 }
730
731 #ifndef __DISABLE_ICONV
732
733 /**
734 * Convert UCS-2 to UTF-8 using iconv
735 */
736 static size_t ucs2_to_utf8_iconv(const UCS2CHAR *src, int srcLen, char *dst, int dstLen)
737 {
738 iconv_t cd;
739 const char *inbuf;
740 char *outbuf;
741 size_t count, inbytes, outbytes;
742
743 cd = IconvOpen("UTF-8", UCS2_CODEPAGE_NAME);
744 if (cd == (iconv_t) (-1))
745 {
746 return ucs2_to_utf8_simple_copy(src, srcLen, dst, dstLen);
747 }
748
749 inbuf = (const char *) src;
750 inbytes = ((srcLen == -1) ? ucs2_strlen(src) + 1 : (size_t) srcLen) * sizeof(UCS2CHAR);
751 outbuf = (char *) dst;
752 outbytes = (size_t) dstLen;
753 count = iconv(cd, (ICONV_CONST char **) &inbuf, &inbytes, &outbuf, &outbytes);
754 IconvClose(cd);
755
756 if (count == (size_t) - 1)
757 {
758 if (errno == EILSEQ)
759 {
760 count = (dstLen * sizeof(char) - outbytes) / sizeof(char);
761 }
762 else
763 {
764 count = 0;
765 }
766 }
767 else
768 {
769 count = dstLen - outbytes;
770 }
771 if ((srcLen == -1) && (outbytes >= sizeof(char)))
772 {
773 *((char *) outbuf) = 0;
774 }
775
776 return count;
777 }
778
779 #endif
780
781 /**
782 * Convert UCS-2 to UTF-8
783 */
784 size_t LIBNETXMS_EXPORTABLE ucs2_to_utf8(const UCS2CHAR *src, int srcLen, char *dst, int dstLen)
785 {
786 #if HAVE_ICONV && !defined(__DISABLE_ICONV)
787 return ucs2_to_utf8_iconv(src, srcLen, dst, dstLen);
788 #else
789 return ucs2_to_utf8_simple_copy(src, srcLen, dst, dstLen);
790 #endif
791 }
792
793 #endif /* UNICODE_UCS4 */
794
795 #ifdef _WIN32
796
797 /**
798 * Convert UTF-8 to multibyte
799 */
800 size_t LIBNETXMS_EXPORTABLE utf8_to_mb(const char *src, int srcLen, char *dst, int dstLen)
801 {
802 int len = (int)strlen(src) + 1;
803 WCHAR *buffer = (len <= 32768) ? (WCHAR *)alloca(len) : (WCHAR *)malloc(len);
804 MultiByteToWideChar(CP_UTF8, 0, src, -1, buffer, len);
805 return WideCharToMultiByte(CP_ACP, WC_DEFAULTCHAR | WC_COMPOSITECHECK, buffer, -1, dst, dstLen, NULL, NULL);
806 }
807
808 /**
809 * Convert multibyte to UTF-8
810 */
811 size_t LIBNETXMS_EXPORTABLE mb_to_utf8(const char *src, int srcLen, char *dst, int dstLen)
812 {
813 int len = (int)strlen(src) + 1;
814 WCHAR *buffer = (len <= 32768) ? (WCHAR *)alloca(len) : (WCHAR *)malloc(len);
815 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, src, -1, buffer, len);
816 return WideCharToMultiByte(CP_UTF8, 0, buffer, -1, dst, dstLen, NULL, NULL);
817 }
818
819 #else /* not _WIN32 */
820
821 /**
822 * Convert UCS-2 to multibyte
823 */
824 static size_t ucs2_to_mb_simple_copy(const UCS2CHAR *src, int srcLen, char *dst, int dstLen)
825 {
826 const UCS2CHAR *psrc;
827 char *pdst;
828 int pos, size;
829
830 size = (srcLen == -1) ? (int) ucs2_strlen(src) : srcLen;
831 if (size >= dstLen)
832 size = dstLen - 1;
833
834 for(psrc = src, pos = 0, pdst = dst; pos < size; pos++, psrc++, pdst++)
835 *pdst = (*psrc < 256) ? (char) (*psrc) : '?';
836 *pdst = 0;
837
838 return size;
839 }
840
841 #ifndef __DISABLE_ICONV
842
843 static size_t ucs2_to_mb_iconv(const UCS2CHAR *src, int srcLen, char *dst, int dstLen)
844 {
845 iconv_t cd;
846 const char *inbuf;
847 char *outbuf;
848 size_t count, inbytes, outbytes;
849
850 cd = IconvOpen(m_cpDefault, UCS2_CODEPAGE_NAME);
851 if (cd == (iconv_t) (-1))
852 {
853 return ucs2_to_mb_simple_copy(src, srcLen, dst, dstLen);
854 }
855
856 inbuf = (const char *) src;
857 inbytes = ((srcLen == -1) ? ucs2_strlen(src) + 1 : (size_t) srcLen) * sizeof(UCS2CHAR);
858 outbuf = (char *) dst;
859 outbytes = (size_t) dstLen;
860 count = iconv(cd, (ICONV_CONST char **) &inbuf, &inbytes, &outbuf, &outbytes);
861 IconvClose(cd);
862
863 if (count == (size_t) - 1)
864 {
865 if (errno == EILSEQ)
866 {
867 count = (dstLen * sizeof(char) - outbytes) / sizeof(char);
868 }
869 else
870 {
871 count = 0;
872 }
873 }
874 if ((srcLen == -1) && (outbytes >= sizeof(char)))
875 {
876 *((char *) outbuf) = 0;
877 }
878
879 return count;
880 }
881
882 #endif
883
884 size_t LIBNETXMS_EXPORTABLE ucs2_to_mb(const UCS2CHAR *src, int srcLen, char *dst, int dstLen)
885 {
886 #if HAVE_ICONV && !defined(__DISABLE_ICONV)
887 return ucs2_to_mb_iconv(src, srcLen, dst, dstLen);
888 #else
889 return ucs2_to_mb_simple_copy(src, srcLen, dst, dstLen);
890 #endif
891 }
892
893 /**
894 * Convert multibyte to UCS-2
895 */
896 static size_t mb_to_ucs2_simple_copy(const char *src, int srcLen, UCS2CHAR *dst, int dstLen)
897 {
898 const char *psrc;
899 UCS2CHAR *pdst;
900 int pos, size;
901
902 size = (srcLen == -1) ? (int) strlen(src) : srcLen;
903 if (size >= dstLen)
904 size = dstLen - 1;
905
906 for(psrc = src, pos = 0, pdst = dst; pos < size; pos++, psrc++, pdst++)
907 *pdst = (UCS2CHAR) (*psrc);
908 *pdst = 0;
909
910 return size;
911 }
912
913 #ifndef __DISABLE_ICONV
914
915 static size_t mb_to_ucs2_iconv(const char *src, int srcLen, UCS2CHAR *dst, int dstLen)
916 {
917 iconv_t cd;
918 const char *inbuf;
919 char *outbuf;
920 size_t count, inbytes, outbytes;
921
922 cd = IconvOpen(UCS2_CODEPAGE_NAME, m_cpDefault);
923 if (cd == (iconv_t) (-1))
924 {
925 return mb_to_ucs2_simple_copy(src, srcLen, dst, dstLen);
926 }
927
928 inbuf = (const char *) src;
929 inbytes = (srcLen == -1) ? strlen(src) + 1 : (size_t) srcLen;
930 outbuf = (char *) dst;
931 outbytes = (size_t) dstLen * sizeof(UCS2CHAR);
932 count = iconv(cd, (ICONV_CONST char **) &inbuf, &inbytes, &outbuf, &outbytes);
933 IconvClose(cd);
934
935 if (count == (size_t) - 1)
936 {
937 if (errno == EILSEQ)
938 {
939 count = (dstLen * sizeof(UCS2CHAR) - outbytes) / sizeof(UCS2CHAR);
940 }
941 else
942 {
943 count = 0;
944 }
945 }
946 if (((char *) outbuf - (char *) dst > sizeof(UCS2CHAR)) && (*dst == 0xFEFF))
947 {
948 // Remove UNICODE byte order indicator if presented
949 memmove(dst, &dst[1], (char *) outbuf - (char *) dst - sizeof(UCS2CHAR));
950 outbuf -= sizeof(UCS2CHAR);
951 }
952 if ((srcLen == -1) && (outbytes >= sizeof(UCS2CHAR)))
953 {
954 *((UCS2CHAR *) outbuf) = 0;
955 }
956
957 return count;
958 }
959
960 #endif
961
962 size_t LIBNETXMS_EXPORTABLE mb_to_ucs2(const char *src, int srcLen, UCS2CHAR *dst, int dstLen)
963 {
964 #if HAVE_ICONV && !defined(__DISABLE_ICONV)
965 return mb_to_ucs2_iconv(src, srcLen, dst, dstLen);
966 #else
967 return mb_to_ucs2_simple_copy(src, srcLen, dst, dstLen);
968 #endif
969 }
970
971 #if !UNICODE_UCS2
972
973 /**
974 * Convert multibyte string to UCS-2 string allocating UCS-2 string dynamically
975 */
976 UCS2CHAR LIBNETXMS_EXPORTABLE *UCS2StringFromMBString(const char *pszString)
977 {
978 UCS2CHAR *pszOut;
979 int nLen;
980
981 nLen = (int) strlen(pszString) + 1;
982 pszOut = (UCS2CHAR *) malloc(nLen * sizeof(UCS2CHAR));
983 mb_to_ucs2(pszString, -1, pszOut, nLen);
984 return pszOut;
985 }
986
987 /**
988 * Convert UCS-2 string to multibyte string allocating multibyte string dynamically
989 */
990 char LIBNETXMS_EXPORTABLE *MBStringFromUCS2String(const UCS2CHAR *pszString)
991 {
992 char *pszOut;
993 int nLen;
994
995 nLen = (int) ucs2_strlen(pszString) + 1;
996 pszOut = (char *) malloc(nLen);
997 ucs2_to_mb(pszString, -1, pszOut, nLen);
998 return pszOut;
999 }
1000
1001 #endif /* !UNICODE_UCS2 */
1002
1003 /**
1004 * Convert multibyte to UTF-8 using stub (no actual conversion for character codes above 0x7F)
1005 */
1006 static size_t mb_to_utf8_simple_copy(const char *src, int srcLen, char *dst, int dstLen)
1007 {
1008 const char *psrc;
1009 char *pdst;
1010 int pos, size;
1011
1012 size = (srcLen == -1) ? strlen(src) : srcLen;
1013 if (size >= dstLen)
1014 size = dstLen - 1;
1015 for(psrc = src, pos = 0, pdst = dst; pos < size; pos++, psrc++, pdst++)
1016 *pdst = ((unsigned char)(*psrc) < 128) ? *psrc : '?';
1017 *pdst = 0;
1018 return size;
1019 }
1020
1021 #ifndef __DISABLE_ICONV
1022
1023 /**
1024 * Convert multibyte to UTF-8 using iconv
1025 */
1026 static size_t mb_to_utf8_iconv(const char *src, int srcLen, char *dst, int dstLen)
1027 {
1028 iconv_t cd;
1029 const char *inbuf;
1030 char *outbuf;
1031 size_t count, inbytes, outbytes;
1032
1033 cd = IconvOpen("UTF-8", m_cpDefault);
1034 if (cd == (iconv_t)(-1))
1035 {
1036 return mb_to_utf8_simple_copy(src, srcLen, dst, dstLen);
1037 }
1038
1039 inbuf = (const char *)src;
1040 inbytes = (srcLen == -1) ? strlen(src) + 1 : (size_t)srcLen;
1041 outbuf = (char *)dst;
1042 outbytes = (size_t)dstLen;
1043 count = iconv(cd, (ICONV_CONST char **)&inbuf, &inbytes, &outbuf, &outbytes);
1044 IconvClose(cd);
1045
1046 if (count == (size_t) - 1)
1047 {
1048 if (errno == EILSEQ)
1049 {
1050 count = dstLen * sizeof(char) - outbytes;
1051 }
1052 else
1053 {
1054 count = 0;
1055 }
1056 }
1057 else
1058 {
1059 count = dstLen - outbytes;
1060 }
1061 if ((srcLen == -1) && (outbytes >= 1))
1062 {
1063 *((char *)outbuf) = 0;
1064 }
1065
1066 return count;
1067 }
1068
1069 #endif
1070
1071 /**
1072 * Convert multibyte to UTF-8
1073 */
1074 size_t LIBNETXMS_EXPORTABLE mb_to_utf8(const char *src, int srcLen, char *dst, int dstLen)
1075 {
1076 #if HAVE_ICONV && !defined(__DISABLE_ICONV)
1077 return mb_to_utf8_iconv(src, srcLen, dst, dstLen);
1078 #else
1079 return mb_to_utf8_simple_copy(src, srcLen, dst, dstLen);
1080 #endif
1081 }
1082
1083 /**
1084 * Convert UTF-8 to multibyte using stub (no actual conversion for character codes above 0x7F)
1085 */
1086 static size_t utf8_to_mb_simple_copy(const char *src, int srcLen, char *dst, int dstLen)
1087 {
1088 const char *psrc = src;
1089 char *pdst = dst;
1090 int dsize = 0;
1091 int ssize = (srcLen == -1) ? strlen(src) : srcLen;
1092 for(int pos = 0; (pos < ssize) && (dsize < dstLen - 1); pos++, psrc++)
1093 {
1094 BYTE b = (BYTE)*psrc;
1095 if ((b & 0x80) == 0) // ASCII-7 character
1096 {
1097 *pdst = (char)b;
1098 pdst++;
1099 dsize++;
1100 }
1101 else if ((b & 0xC0) == 0xC0) // UTF-8 start byte
1102 {
1103 *pdst = '?';
1104 pdst++;
1105 dsize++;
1106 }
1107 }
1108 *pdst = 0;
1109 return dsize;
1110 }
1111
1112 #ifndef __DISABLE_ICONV
1113
1114 /**
1115 * Convert UTF-8 to multibyte using iconv
1116 */
1117 static size_t utf8_to_mb_iconv(const char *src, int srcLen, char *dst, int dstLen)
1118 {
1119 iconv_t cd;
1120 const char *inbuf;
1121 char *outbuf;
1122 size_t count, inbytes, outbytes;
1123
1124 cd = IconvOpen(m_cpDefault, "UTF-8");
1125 if (cd == (iconv_t)(-1))
1126 {
1127 return utf8_to_mb_simple_copy(src, srcLen, dst, dstLen);
1128 }
1129
1130 inbuf = (const char *)src;
1131 inbytes = (srcLen == -1) ? strlen(src) + 1 : (size_t)srcLen;
1132 outbuf = (char *)dst;
1133 outbytes = (size_t)dstLen;
1134 count = iconv(cd, (ICONV_CONST char **)&inbuf, &inbytes, &outbuf, &outbytes);
1135 IconvClose(cd);
1136
1137 if (count == (size_t) - 1)
1138 {
1139 if (errno == EILSEQ)
1140 {
1141 count = dstLen * sizeof(char) - outbytes;
1142 }
1143 else
1144 {
1145 count = 0;
1146 }
1147 }
1148 else
1149 {
1150 count = dstLen - outbytes;
1151 }
1152 if ((srcLen == -1) && (outbytes >= 1))
1153 {
1154 *((char *)outbuf) = 0;
1155 }
1156
1157 return count;
1158 }
1159
1160 #endif
1161
1162 /**
1163 * Convert UTF-8 to multibyte
1164 */
1165 size_t LIBNETXMS_EXPORTABLE utf8_to_mb(const char *src, int srcLen, char *dst, int dstLen)
1166 {
1167 #if HAVE_ICONV && !defined(__DISABLE_ICONV)
1168 return utf8_to_mb_iconv(src, srcLen, dst, dstLen);
1169 #else
1170 return utf8_to_mb_simple_copy(src, srcLen, dst, dstLen);
1171 #endif
1172 }
1173
1174 #endif /* !defined(_WIN32) */
1175
1176 /**
1177 * UNIX UNICODE specific wrapper functions
1178 */
1179
1180 #if !defined(_WIN32)
1181
1182 #if !HAVE_WSTAT
1183
1184 int wstat(const WCHAR *_path, struct stat *_sbuf)
1185 {
1186 char path[MAX_PATH];
1187
1188 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
1189 _path, -1, path, MAX_PATH, NULL, NULL);
1190 return stat(path, _sbuf);
1191 }
1192
1193 #endif /* !HAVE_WSTAT */
1194
1195 #if defined(UNICODE)
1196
1197 /**
1198 * Wide character version of some libc functions
1199 */
1200
1201 #define DEFINE_PATH_FUNC(func) \
1202 int w##func(const WCHAR *_path) \
1203 { \
1204 char path[MAX_PATH]; \
1205 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, _path, -1, path, MAX_PATH, NULL, NULL); \
1206 return func(path); \
1207 }
1208
1209 #if !HAVE_WCHDIR
1210 DEFINE_PATH_FUNC(chdir)
1211 #endif
1212
1213 #if !HAVE_WRMDIR
1214 DEFINE_PATH_FUNC(rmdir)
1215 #endif
1216
1217 #if !HAVE_WUNLINK
1218 DEFINE_PATH_FUNC(unlink)
1219 #endif
1220
1221 #if !HAVE_WREMOVE
1222 DEFINE_PATH_FUNC(remove)
1223 #endif
1224
1225 #if !HAVE_WMKSTEMP
1226
1227 int LIBNETXMS_EXPORTABLE wmkstemp(WCHAR *_path)
1228 {
1229 char path[MAX_PATH];
1230 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, _path, -1, path, MAX_PATH, NULL, NULL);
1231 int rc = mkstemp(path);
1232 if (rc != -1)
1233 {
1234 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, path, -1, _path, wcslen(_path) + 1);
1235 }
1236 return rc;
1237 }
1238
1239 #endif
1240
1241 #if !HAVE_WPOPEN
1242
1243 FILE LIBNETXMS_EXPORTABLE *wpopen(const WCHAR *_command, const WCHAR *_type)
1244 {
1245 char *command, *type;
1246 FILE *f;
1247
1248 command = MBStringFromWideString(_command);
1249 type = MBStringFromWideString(_type);
1250 f = popen(command, type);
1251 free(command);
1252 free(type);
1253 return f;
1254 }
1255
1256 #endif
1257
1258 #if !HAVE_WFOPEN
1259
1260 FILE LIBNETXMS_EXPORTABLE *wfopen(const WCHAR *_name, const WCHAR *_type)
1261 {
1262 char *name, *type;
1263 FILE *f;
1264
1265 name = MBStringFromWideString(_name);
1266 type = MBStringFromWideString(_type);
1267 f = fopen(name, type);
1268 free(name);
1269 free(type);
1270 return f;
1271 }
1272
1273 #endif
1274
1275 #if HAVE_FOPEN64 && !HAVE_WFOPEN64
1276
1277 FILE LIBNETXMS_EXPORTABLE *wfopen64(const WCHAR *_name, const WCHAR *_type)
1278 {
1279 char *name, *type;
1280 FILE *f;
1281
1282 name = MBStringFromWideString(_name);
1283 type = MBStringFromWideString(_type);
1284 f = fopen64(name, type);
1285 free(name);
1286 free(type);
1287 return f;
1288 }
1289
1290 #endif
1291
1292 #if !HAVE_WOPEN
1293
1294 int LIBNETXMS_EXPORTABLE wopen(const WCHAR *_name, int flags, ...)
1295 {
1296 char *name;
1297 int rc;
1298
1299 name = MBStringFromWideString(_name);
1300 if (flags & O_CREAT)
1301 {
1302 va_list args;
1303
1304 va_start(args, flags);
1305 rc = open(name, flags, (mode_t)va_arg(args, int));
1306 va_end(args);
1307 }
1308 else
1309 {
1310 rc = open(name, flags);
1311 }
1312 free(name);
1313 return rc;
1314 }
1315
1316 #endif
1317
1318 #if !HAVE_WCHMOD
1319
1320 int LIBNETXMS_EXPORTABLE wchmod(const WCHAR *_name, int mode)
1321 {
1322 char *name;
1323 int rc;
1324
1325 name = MBStringFromWideString(_name);
1326 rc = chmod(name, mode);
1327 free(name);
1328 return rc;
1329 }
1330
1331 #endif
1332
1333 #if !HAVE_WRENAME
1334
1335 int wrename(const WCHAR *_oldpath, const WCHAR *_newpath)
1336 {
1337 char oldpath[MAX_PATH], newpath[MAX_PATH];
1338
1339 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
1340 _oldpath, -1, oldpath, MAX_PATH, NULL, NULL);
1341 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
1342 _newpath, -1, newpath, MAX_PATH, NULL, NULL);
1343 return rename(oldpath, newpath);
1344 }
1345
1346 #endif
1347
1348 #if !HAVE_WSYSTEM
1349
1350 int wsystem(const WCHAR *_cmd)
1351 {
1352 char *cmd = MBStringFromWideString(_cmd);
1353 int rc = system(cmd);
1354 free(cmd);
1355 return rc;
1356 }
1357
1358 #endif
1359
1360 #if !HAVE_WACCESS
1361
1362 int waccess(const WCHAR *_path, int mode)
1363 {
1364 char path[MAX_PATH];
1365
1366 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
1367 _path, -1, path, MAX_PATH, NULL, NULL);
1368 return access(path, mode);
1369 }
1370
1371 #endif
1372
1373 #if !HAVE_WMKDIR
1374
1375 int wmkdir(const WCHAR *_path, int mode)
1376 {
1377 char path[MAX_PATH];
1378
1379 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
1380 _path, -1, path, MAX_PATH, NULL, NULL);
1381 return mkdir(path, mode);
1382 }
1383
1384 #endif
1385
1386 #if !HAVE_WGETENV
1387
1388 WCHAR *wgetenv(const WCHAR *_string)
1389 {
1390 char name[256], *p;
1391 static WCHAR value[8192];
1392
1393 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, _string, -1, name, 256, NULL, NULL);
1394 p = getenv(name);
1395 if (p == NULL)
1396 return NULL;
1397
1398 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, p, -1, value, 8192);
1399 return value;
1400 }
1401
1402 #endif
1403
1404 #if !HAVE_WCTIME
1405
1406 WCHAR *wctime(const time_t *timep)
1407 {
1408 static WCHAR value[256];
1409
1410 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, ctime(timep), -1, value, 256);
1411 return value;
1412 }
1413
1414 #endif /* HAVE_WCTIME */
1415
1416 #if !HAVE_PUTWS
1417
1418 int putws(const WCHAR *s)
1419 {
1420 #if HAVE_FPUTWS
1421 fputws(s, stdout);
1422 putwc(L'\n', stdout);
1423 #else
1424 printf("%S\n", s);
1425 #endif /* HAVE_FPUTWS */
1426 return 1;
1427 }
1428
1429 #endif /* !HAVE_PUTWS */
1430
1431 #if !HAVE_WCSERROR && (HAVE_STRERROR || HAVE_DECL_STRERROR)
1432
1433 WCHAR *wcserror(int errnum)
1434 {
1435 static WCHAR value[8192];
1436
1437 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, strerror(errnum), -1, value, 8192);
1438 return value;
1439 }
1440
1441 #endif /* !HAVE_WCSERROR && HAVE_STRERROR */
1442
1443 #if !HAVE_WCSERROR_R && HAVE_STRERROR_R
1444
1445 #if HAVE_POSIX_STRERROR_R
1446 int wcserror_r(int errnum, WCHAR *strerrbuf, size_t buflen)
1447 #else
1448 WCHAR *wcserror_r(int errnum, WCHAR *strerrbuf, size_t buflen)
1449 #endif /* HAVE_POSIX_STRERROR_R */
1450 {
1451 char *mbbuf;
1452 #if HAVE_POSIX_STRERROR_R
1453 int err = 0;
1454 #endif /* HAVE_POSIX_STRERROR_R */
1455
1456 mbbuf = (char *)malloc(buflen);
1457 if (mbbuf != NULL)
1458 {
1459 #if HAVE_POSIX_STRERROR_R
1460 err = strerror_r(errnum, mbbuf, buflen);
1461 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, mbbuf, -1, strerrbuf, buflen);
1462 #else
1463 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, strerror_r(errnum, mbbuf, buflen), -1, strerrbuf, buflen);
1464 #endif
1465 free(mbbuf);
1466 }
1467 else
1468 {
1469 *strerrbuf = 0;
1470 }
1471
1472 #if HAVE_POSIX_STRERROR_R
1473 return err;
1474 #else
1475 return strerrbuf;
1476 #endif
1477 }
1478
1479 #endif /* !HAVE_WCSERROR_R && HAVE_STRERROR_R */
1480
1481 #endif /* defined(UNICODE) */
1482
1483 /**
1484 * Wrappers for wprintf/wscanf family
1485 *
1486 * All these wrappers replaces %s with %S and %c with %C
1487 * because in POSIX version of wprintf functions %s and %c
1488 * means "multibyte string/char" instead of expected "UNICODE string/char"
1489 */
1490
1491 int LIBNETXMS_EXPORTABLE nx_wprintf(const WCHAR *format, ...)
1492 {
1493 va_list args;
1494 int rc;
1495
1496 va_start(args, format);
1497 rc = nx_vwprintf(format, args);
1498 va_end(args);
1499 return rc;
1500 }
1501
1502 int LIBNETXMS_EXPORTABLE nx_fwprintf(FILE *fp, const WCHAR *format, ...)
1503 {
1504 va_list args;
1505 int rc;
1506
1507 va_start(args, format);
1508 rc = nx_vfwprintf(fp, format, args);
1509 va_end(args);
1510 return rc;
1511 }
1512
1513 int LIBNETXMS_EXPORTABLE nx_swprintf(WCHAR *buffer, size_t size, const WCHAR *format, ...)
1514 {
1515 va_list args;
1516 int rc;
1517
1518 va_start(args, format);
1519 rc = nx_vswprintf(buffer, size, format, args);
1520 va_end(args);
1521 return rc;
1522 }
1523
1524 int LIBNETXMS_EXPORTABLE nx_wscanf(const WCHAR *format, ...)
1525 {
1526 va_list args;
1527 int rc;
1528
1529 va_start(args, format);
1530 rc = nx_vwscanf(format, args);
1531 va_end(args);
1532 return rc;
1533 }
1534
1535 int LIBNETXMS_EXPORTABLE nx_fwscanf(FILE *fp, const WCHAR *format, ...)
1536 {
1537 va_list args;
1538 int rc;
1539
1540 va_start(args, format);
1541 rc = nx_vfwscanf(fp, format, args);
1542 va_end(args);
1543 return rc;
1544 }
1545
1546 int LIBNETXMS_EXPORTABLE nx_swscanf(const WCHAR *str, const WCHAR *format, ...)
1547 {
1548 va_list args;
1549 int rc;
1550
1551 va_start(args, format);
1552 rc = nx_vswscanf(str, format, args);
1553 va_end(args);
1554 return rc;
1555 }
1556
1557 static WCHAR *ReplaceFormatSpecs(const WCHAR *oldFormat)
1558 {
1559 WCHAR *fmt, *p;
1560 int state = 0;
1561 bool hmod;
1562
1563 fmt = wcsdup(oldFormat);
1564 for(p = fmt; *p != 0; p++)
1565 {
1566 switch (state)
1567 {
1568 case 0: // Normal text
1569 if (*p == L'%')
1570 {
1571 state = 1;
1572 hmod = false;
1573 }
1574 break;
1575 case 1: // Format start
1576 switch (*p)
1577 {
1578 case L's':
1579 if (hmod)
1580 {
1581 memmove(p - 1, p, wcslen(p - 1) * sizeof(TCHAR));
1582 }
1583 else
1584 {
1585 *p = L'S';
1586 }
1587 state = 0;
1588 break;
1589 case L'S':
1590 *p = L's';
1591 state = 0;
1592 break;
1593 case L'c':
1594 if (hmod)
1595 {
1596 memmove(p - 1, p, wcslen(p - 1) * sizeof(TCHAR));
1597 }
1598 else
1599 {
1600 *p = L'C';
1601 }
1602 state = 0;
1603 break;
1604 case L'C':
1605 *p = L'c';
1606 state = 0;
1607 break;
1608 case L'.': // All this characters could be part of format specifier
1609 case L'*': // and has no interest for us
1610 case L'+':
1611 case L'-':
1612 case L' ':
1613 case L'#':
1614 case L'0':
1615 case L'1':
1616 case L'2':
1617 case L'3':
1618 case L'4':
1619 case L'5':
1620 case L'6':
1621 case L'7':
1622 case L'8':
1623 case L'9':
1624 case L'l':
1625 case L'L':
1626 case L'F':
1627 case L'N':
1628 case L'w':
1629 break;
1630 case L'h': // check for %hs
1631 hmod = true;
1632 break;
1633 default: // All other cahacters means end of format
1634 state = 0;
1635 break;
1636
1637 }
1638 break;
1639 }
1640 }
1641 return fmt;
1642 }
1643
1644 int LIBNETXMS_EXPORTABLE nx_vwprintf(const WCHAR *format, va_list args)
1645 {
1646 WCHAR *fmt;
1647 int rc;
1648
1649 fmt = ReplaceFormatSpecs(format);
1650 rc = vwprintf(fmt, args);
1651 free(fmt);
1652 return rc;
1653 }
1654
1655 int LIBNETXMS_EXPORTABLE nx_vfwprintf(FILE *fp, const WCHAR *format, va_list args)
1656 {
1657 WCHAR *fmt;
1658 int rc;
1659
1660 fmt = ReplaceFormatSpecs(format);
1661 rc = vfwprintf(fp, fmt, args);
1662 free(fmt);
1663 return rc;
1664 }
1665
1666 int LIBNETXMS_EXPORTABLE nx_vswprintf(WCHAR *buffer, size_t size, const WCHAR *format, va_list args)
1667 {
1668 WCHAR *fmt;
1669 int rc;
1670
1671 fmt = ReplaceFormatSpecs(format);
1672 rc = vswprintf(buffer, size, fmt, args);
1673 free(fmt);
1674 return rc;
1675 }
1676
1677 int LIBNETXMS_EXPORTABLE nx_vwscanf(const WCHAR *format, va_list args)
1678 {
1679 WCHAR *fmt;
1680 int rc;
1681
1682 fmt = ReplaceFormatSpecs(format);
1683 #if HAVE_VWSCANF
1684 rc = vwscanf(fmt, args);
1685 #else
1686 rc = -1; // FIXME: add workaround implementation
1687 #endif
1688 free(fmt);
1689 return rc;
1690 }
1691
1692 int LIBNETXMS_EXPORTABLE nx_vfwscanf(FILE *fp, const WCHAR *format, va_list args)
1693 {
1694 WCHAR *fmt;
1695 int rc;
1696
1697 fmt = ReplaceFormatSpecs(format);
1698 #if HAVE_VFWSCANF
1699 rc = vfwscanf(fp, fmt, args);
1700 #else
1701 rc = -1; // FIXME: add workaround implementation
1702 #endif
1703 free(fmt);
1704 return rc;
1705 }
1706
1707 int LIBNETXMS_EXPORTABLE nx_vswscanf(const WCHAR *str, const WCHAR *format, va_list args)
1708 {
1709 WCHAR *fmt;
1710 int rc;
1711
1712 fmt = ReplaceFormatSpecs(format);
1713 #if HAVE_VSWSCANF
1714 rc = vswscanf(str, fmt, args);
1715 #else
1716 rc = -1; // FIXME: add workaround implementation
1717 #endif
1718 free(fmt);
1719 return rc;
1720 }
1721 #endif /* !defined(_WIN32) */