4d25b230957c5bda0a7f1e48d73b175d0e08dcdc
[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 #include "unicode_cc.h"
25 #include <nxcrypto.h>
26
27 /**
28 * Default codepage
29 */
30 char g_cpDefault[MAX_CODEPAGE_LEN] = ICONV_DEFAULT_CODEPAGE;
31
32 /**
33 * Set application's default codepage
34 */
35 bool LIBNETXMS_EXPORTABLE SetDefaultCodepage(const char *cp)
36 {
37 bool rc;
38 #if HAVE_ICONV && !defined(__DISABLE_ICONV)
39 iconv_t cd;
40
41 cd = iconv_open(cp, "UTF-8");
42 if (cd != (iconv_t)(-1))
43 {
44 iconv_close(cd);
45 #endif
46 strncpy(g_cpDefault, cp, MAX_CODEPAGE_LEN);
47 g_cpDefault[MAX_CODEPAGE_LEN - 1] = 0;
48 rc = true;
49 #if HAVE_ICONV && !defined(__DISABLE_ICONV)
50 }
51 else
52 {
53 rc = false;
54 }
55 #endif
56 return rc;
57 }
58
59 #ifndef UNICODE_UCS2
60
61 /**
62 * Calculate length of UCS-2 character string
63 */
64 size_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 */
80 size_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
92
93 /**
94 * Calculate length of wide character string
95 */
96 size_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 */
112 UCS2CHAR LIBNETXMS_EXPORTABLE *ucs2_strdup(const UCS2CHAR *src)
113 {
114 return (UCS2CHAR *)nx_memdup(src, (ucs2_strlen(src) + 1) * sizeof(UCS2CHAR));
115 }
116
117 #endif
118
119 #ifndef UNICODE_UCS4
120
121 /**
122 * Duplicate UCS-4 character string
123 */
124 UCS4CHAR LIBNETXMS_EXPORTABLE *ucs4_strdup(const UCS4CHAR *src)
125 {
126 return (UCS4CHAR *)nx_memdup(src, (ucs4_strlen(src) + 1) * sizeof(UCS4CHAR));
127 }
128
129 #endif
130
131 #if !UNICODE_UCS2
132
133 /**
134 * Copy UCS-2 character string with length limitation
135 */
136 UCS2CHAR LIBNETXMS_EXPORTABLE *ucs2_strncpy(UCS2CHAR *dest, const UCS2CHAR *src, size_t n)
137 {
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;
143 }
144
145 #endif
146
147 #if !UNICODE_UCS4
148
149 /**
150 * Copy UCS-2 character string with length limitation
151 */
152 UCS4CHAR LIBNETXMS_EXPORTABLE *ucs4_strncpy(UCS4CHAR *dest, const UCS4CHAR *src, size_t n)
153 {
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 }
160
161 #endif
162
163 #if !HAVE_WCSNCPY
164
165 /**
166 * Copy UCS-2 character string with length limitation
167 */
168 WCHAR 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;
175 }
176
177 #endif
178
179 #ifndef _WIN32
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, g_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 = (((BYTE)*pSrc & 0x80) == 0) ? (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" : g_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 /* __DISABLE_ICONV */
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 /* _WIN32 */
379
380 /**
381 * Convert multibyte string to wide string using current LC_CTYPE setting and
382 * allocating wide string dynamically
383 */
384 WCHAR LIBNETXMS_EXPORTABLE *WideStringFromMBStringSysLocale(const char *pszString)
385 {
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 }
401
402 /**
403 * Convert multibyte string to wide string using current codepage and
404 * allocating wide string dynamically
405 */
406 WCHAR 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;
414 }
415
416 /**
417 * Convert wide string to UTF8 string allocating wide string dynamically
418 */
419 WCHAR LIBNETXMS_EXPORTABLE *WideStringFromUTF8String(const char *pszString)
420 {
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 }
428
429 /**
430 * Convert wide string to multibyte string using current codepage and
431 * allocating multibyte string dynamically
432 */
433 char 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);
440 return pszOut;
441 }
442
443 /**
444 * Convert wide string to multibyte string using current LC_CTYPE setting and
445 * allocating multibyte string dynamically
446 */
447 char LIBNETXMS_EXPORTABLE *MBStringFromWideStringSysLocale(const WCHAR *pwszString)
448 {
449 #ifdef _WIN32
450 return MBStringFromWideString(pwszString);
451 #else
452 if (pwszString == NULL)
453 return NULL;
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);
456 #if HAVE_WCSTOMBS
457 wcstombs(out, pwszString, len);
458 #else
459 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, pwszString, -1, out, (int)len, NULL, NULL);
460 #endif
461 return out;
462 #endif
463 }
464
465 /**
466 * Convert wide string to UTF8 string allocating UTF8 string dynamically
467 */
468 char 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 }
475
476 /**
477 * Convert UTF8 string to multibyte string using current codepage and
478 * allocating multibyte string dynamically
479 */
480 char LIBNETXMS_EXPORTABLE *MBStringFromUTF8String(const char *s)
481 {
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 }
487
488 /**
489 * Convert multibyte string to UTF8 string allocating UTF8 string dynamically
490 */
491 char 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 }
498
499 /**
500 * Convert UCS-4 string to UCS-2 string allocating UCS-2 string dynamically
501 */
502 UCS2CHAR LIBNETXMS_EXPORTABLE *UCS2StringFromUCS4String(const UCS4CHAR *src)
503 {
504 UCS2CHAR *pszOut;
505 int nLen;
506
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 }
512
513 /**
514 * Convert UCS-2 string to UCS-4 string allocating UCS-4 string dynamically
515 */
516 UCS4CHAR 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;
522 }
523
524 #ifndef UNICODE_UCS2
525
526 /**
527 * Convert UTF-8 to UCS-2 (dynamically allocated output string)
528 */
529 UCS2CHAR LIBNETXMS_EXPORTABLE *UCS2StringFromUTF8String(const char *utf8String)
530 {
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;
537 }
538
539 /**
540 * Convert UCS-2 string to UTF-8 string allocating UTF-8 string dynamically
541 */
542 char LIBNETXMS_EXPORTABLE *UTF8StringFromUCS2String(const UCS2CHAR *src)
543 {
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;
548 }
549
550 /**
551 * Convert multibyte string to UCS-2 string allocating UCS-2 string dynamically
552 */
553 UCS2CHAR LIBNETXMS_EXPORTABLE *UCS2StringFromMBString(const char *src)
554 {
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 }
560
561 /**
562 * Convert UCS-2 string to multibyte string allocating multibyte string dynamically
563 */
564 char 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 }
571
572 #endif /* UNICODE_UCS2 */
573
574 #ifndef UNICODE_UCS4
575
576 /**
577 * Convert multibyte string to UCS-4 string allocating UCS-4 string dynamically
578 */
579 UCS4CHAR 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;
585 }
586
587 /**
588 * Convert UCS-4 string to multibyte string allocating multibyte string dynamically
589 */
590 char LIBNETXMS_EXPORTABLE *MBStringFromUCS4String(const UCS4CHAR *src)
591 {
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;
596 }
597
598 #endif /* UNICODE_UCS4 */
599
600 /**
601 * UNIX UNICODE specific wrapper functions
602 */
603 #if !defined(_WIN32)
604
605 #if !HAVE_WSTAT
606
607 int wstat(const WCHAR *_path, struct stat *_sbuf)
608 {
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);
614 }
615
616 #endif /* !HAVE_WSTAT */
617
618 #if defined(UNICODE)
619
620 /**
621 * Wide character version of some libc functions
622 */
623
624 #define DEFINE_PATH_FUNC(func) \
625 int w##func(const WCHAR *_path) \
626 { \
627 char path[MAX_PATH]; \
628 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, _path, -1, path, MAX_PATH, NULL, NULL); \
629 return func(path); \
630 }
631
632 #if !HAVE_WCHDIR
633 DEFINE_PATH_FUNC(chdir)
634 #endif
635
636 #if !HAVE_WRMDIR
637 DEFINE_PATH_FUNC(rmdir)
638 #endif
639
640 #if !HAVE_WUNLINK
641 DEFINE_PATH_FUNC(unlink)
642 #endif
643
644 #if !HAVE_WREMOVE
645 DEFINE_PATH_FUNC(remove)
646 #endif
647
648 #if !HAVE_WMKSTEMP
649
650 int 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
662 #endif
663
664 #if !HAVE_WPOPEN
665
666 FILE LIBNETXMS_EXPORTABLE *wpopen(const WCHAR *_command, const WCHAR *_type)
667 {
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;
677 }
678
679 #endif
680
681 #if !HAVE_WFOPEN
682
683 FILE LIBNETXMS_EXPORTABLE *wfopen(const WCHAR *_name, const WCHAR *_type)
684 {
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;
694 }
695
696 #endif
697
698 #if HAVE_FOPEN64 && !HAVE_WFOPEN64
699
700 FILE 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
715 #if !HAVE_WOPEN
716
717 int LIBNETXMS_EXPORTABLE wopen(const WCHAR *_name, int flags, ...)
718 {
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;
737 }
738
739 #endif
740
741 #if !HAVE_WCHMOD
742
743 int LIBNETXMS_EXPORTABLE wchmod(const WCHAR *_name, int mode)
744 {
745 char *name;
746 int rc;
747
748 name = MBStringFromWideString(_name);
749 rc = chmod(name, mode);
750 free(name);
751 return rc;
752 }
753
754 #endif
755
756 #if !HAVE_WRENAME
757
758 int wrename(const WCHAR *_oldpath, const WCHAR *_newpath)
759 {
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);
767 }
768
769 #endif
770
771 #if !HAVE_WSYSTEM
772
773 int wsystem(const WCHAR *_cmd)
774 {
775 char *cmd = MBStringFromWideStringSysLocale(_cmd);
776 int rc = system(cmd);
777 free(cmd);
778 return rc;
779 }
780
781 #endif
782
783 #if !HAVE_WACCESS
784
785 int waccess(const WCHAR *_path, int mode)
786 {
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);
792 }
793
794 #endif
795
796 #if !HAVE_WMKDIR
797
798 int wmkdir(const WCHAR *_path, int mode)
799 {
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);
805 }
806
807 #endif
808
809 #if !HAVE_WUTIME
810
811 int 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
822 #if !HAVE_WGETENV
823
824 WCHAR *wgetenv(const WCHAR *_string)
825 {
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)
832 return NULL;
833
834 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, p, -1, value, 8192);
835 return value;
836 }
837
838 #endif
839
840 #if !HAVE_WCTIME
841
842 WCHAR *wctime(const time_t *timep)
843 {
844 static WCHAR value[256];
845
846 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, ctime(timep), -1, value, 256);
847 return value;
848 }
849
850 #endif /* HAVE_WCTIME */
851
852 #if !HAVE_PUTWS
853
854 int putws(const WCHAR *s)
855 {
856 #if HAVE_FPUTWS
857 fputws(s, stdout);
858 putwc(L'\n', stdout);
859 #else
860 printf("%S\n", s);
861 #endif /* HAVE_FPUTWS */
862 return 1;
863 }
864
865 #endif /* !HAVE_PUTWS */
866
867 #if !HAVE_WCSERROR && (HAVE_STRERROR || HAVE_DECL_STRERROR)
868
869 WCHAR *wcserror(int errnum)
870 {
871 static WCHAR value[8192];
872
873 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, strerror(errnum), -1, value, 8192);
874 return value;
875 }
876
877 #endif /* !HAVE_WCSERROR && HAVE_STRERROR */
878
879 #if !HAVE_WCSERROR_R && HAVE_STRERROR_R
880
881 #if HAVE_POSIX_STRERROR_R
882 int wcserror_r(int errnum, WCHAR *strerrbuf, size_t buflen)
883 #else
884 WCHAR *wcserror_r(int errnum, WCHAR *strerrbuf, size_t buflen)
885 #endif /* HAVE_POSIX_STRERROR_R */
886 {
887 char *mbbuf;
888 #if HAVE_POSIX_STRERROR_R
889 int err = 0;
890 #endif /* HAVE_POSIX_STRERROR_R */
891
892 mbbuf = (char *)malloc(buflen);
893 if (mbbuf != NULL)
894 {
895 #if HAVE_POSIX_STRERROR_R
896 err = strerror_r(errnum, mbbuf, buflen);
897 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, mbbuf, -1, strerrbuf, buflen);
898 #else
899 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, strerror_r(errnum, mbbuf, buflen), -1, strerrbuf, buflen);
900 #endif
901 free(mbbuf);
902 }
903 else
904 {
905 *strerrbuf = 0;
906 }
907
908 #if HAVE_POSIX_STRERROR_R
909 return err;
910 #else
911 return strerrbuf;
912 #endif
913 }
914
915 #endif /* !HAVE_WCSERROR_R && HAVE_STRERROR_R */
916
917 #endif /* defined(UNICODE) */
918
919 /**
920 * Wrappers for wprintf/wscanf family
921 *
922 * All these wrappers replaces %s with %S and %c with %C
923 * because in POSIX version of wprintf functions %s and %c
924 * means "multibyte string/char" instead of expected "UNICODE string/char"
925 */
926
927 int LIBNETXMS_EXPORTABLE nx_wprintf(const WCHAR *format, ...)
928 {
929 va_list args;
930 int rc;
931
932 va_start(args, format);
933 rc = nx_vwprintf(format, args);
934 va_end(args);
935 return rc;
936 }
937
938 int LIBNETXMS_EXPORTABLE nx_fwprintf(FILE *fp, const WCHAR *format, ...)
939 {
940 va_list args;
941 int rc;
942
943 va_start(args, format);
944 rc = nx_vfwprintf(fp, format, args);
945 va_end(args);
946 return rc;
947 }
948
949 int LIBNETXMS_EXPORTABLE nx_swprintf(WCHAR *buffer, size_t size, const WCHAR *format, ...)
950 {
951 va_list args;
952 int rc;
953
954 va_start(args, format);
955 rc = nx_vswprintf(buffer, size, format, args);
956 va_end(args);
957 return rc;
958 }
959
960 int LIBNETXMS_EXPORTABLE nx_wscanf(const WCHAR *format, ...)
961 {
962 va_list args;
963 int rc;
964
965 va_start(args, format);
966 rc = nx_vwscanf(format, args);
967 va_end(args);
968 return rc;
969 }
970
971 int LIBNETXMS_EXPORTABLE nx_fwscanf(FILE *fp, const WCHAR *format, ...)
972 {
973 va_list args;
974 int rc;
975
976 va_start(args, format);
977 rc = nx_vfwscanf(fp, format, args);
978 va_end(args);
979 return rc;
980 }
981
982 int LIBNETXMS_EXPORTABLE nx_swscanf(const WCHAR *str, const WCHAR *format, ...)
983 {
984 va_list args;
985 int rc;
986
987 va_start(args, format);
988 rc = nx_vswscanf(str, format, args);
989 va_end(args);
990 return rc;
991 }
992
993 static WCHAR *ReplaceFormatSpecs(const WCHAR *oldFormat)
994 {
995 WCHAR *fmt, *p;
996 int state = 0;
997 bool hmod;
998
999 fmt = wcsdup(oldFormat);
1000 for(p = fmt; *p != 0; p++)
1001 {
1002 switch (state)
1003 {
1004 case 0: // Normal text
1005 if (*p == L'%')
1006 {
1007 state = 1;
1008 hmod = false;
1009 }
1010 break;
1011 case 1: // Format start
1012 switch (*p)
1013 {
1014 case L's':
1015 if (hmod)
1016 {
1017 memmove(p - 1, p, wcslen(p - 1) * sizeof(TCHAR));
1018 }
1019 else
1020 {
1021 *p = L'S';
1022 }
1023 state = 0;
1024 break;
1025 case L'S':
1026 *p = L's';
1027 state = 0;
1028 break;
1029 case L'c':
1030 if (hmod)
1031 {
1032 memmove(p - 1, p, wcslen(p - 1) * sizeof(TCHAR));
1033 }
1034 else
1035 {
1036 *p = L'C';
1037 }
1038 state = 0;
1039 break;
1040 case L'C':
1041 *p = L'c';
1042 state = 0;
1043 break;
1044 case L'.': // All this characters could be part of format specifier
1045 case L'*': // and has no interest for us
1046 case L'+':
1047 case L'-':
1048 case L' ':
1049 case L'#':
1050 case L'0':
1051 case L'1':
1052 case L'2':
1053 case L'3':
1054 case L'4':
1055 case L'5':
1056 case L'6':
1057 case L'7':
1058 case L'8':
1059 case L'9':
1060 case L'l':
1061 case L'L':
1062 case L'F':
1063 case L'N':
1064 case L'w':
1065 break;
1066 case L'h': // check for %hs
1067 hmod = true;
1068 break;
1069 default: // All other cahacters means end of format
1070 state = 0;
1071 break;
1072
1073 }
1074 break;
1075 }
1076 }
1077 return fmt;
1078 }
1079
1080 int LIBNETXMS_EXPORTABLE nx_vwprintf(const WCHAR *format, va_list args)
1081 {
1082 WCHAR *fmt;
1083 int rc;
1084
1085 fmt = ReplaceFormatSpecs(format);
1086 rc = vwprintf(fmt, args);
1087 free(fmt);
1088 return rc;
1089 }
1090
1091 int LIBNETXMS_EXPORTABLE nx_vfwprintf(FILE *fp, const WCHAR *format, va_list args)
1092 {
1093 WCHAR *fmt;
1094 int rc;
1095
1096 fmt = ReplaceFormatSpecs(format);
1097 rc = vfwprintf(fp, fmt, args);
1098 free(fmt);
1099 return rc;
1100 }
1101
1102 int LIBNETXMS_EXPORTABLE nx_vswprintf(WCHAR *buffer, size_t size, const WCHAR *format, va_list args)
1103 {
1104 WCHAR *fmt;
1105 int rc;
1106
1107 fmt = ReplaceFormatSpecs(format);
1108 rc = vswprintf(buffer, size, fmt, args);
1109 free(fmt);
1110 return rc;
1111 }
1112
1113 int LIBNETXMS_EXPORTABLE nx_vwscanf(const WCHAR *format, va_list args)
1114 {
1115 WCHAR *fmt;
1116 int rc;
1117
1118 fmt = ReplaceFormatSpecs(format);
1119 #if HAVE_VWSCANF
1120 rc = vwscanf(fmt, args);
1121 #else
1122 rc = -1; // FIXME: add workaround implementation
1123 #endif
1124 free(fmt);
1125 return rc;
1126 }
1127
1128 int LIBNETXMS_EXPORTABLE nx_vfwscanf(FILE *fp, const WCHAR *format, va_list args)
1129 {
1130 WCHAR *fmt;
1131 int rc;
1132
1133 fmt = ReplaceFormatSpecs(format);
1134 #if HAVE_VFWSCANF
1135 rc = vfwscanf(fp, fmt, args);
1136 #else
1137 rc = -1; // FIXME: add workaround implementation
1138 #endif
1139 free(fmt);
1140 return rc;
1141 }
1142
1143 int LIBNETXMS_EXPORTABLE nx_vswscanf(const WCHAR *str, const WCHAR *format, va_list args)
1144 {
1145 WCHAR *fmt;
1146 int rc;
1147
1148 fmt = ReplaceFormatSpecs(format);
1149 #if HAVE_VSWSCANF
1150 rc = vswscanf(str, fmt, args);
1151 #else
1152 rc = -1; // FIXME: add workaround implementation
1153 #endif
1154 free(fmt);
1155 return rc;
1156 }
1157 #endif /* !defined(_WIN32) */
1158
1159 /**
1160 * UNICODE version of inet_addr()
1161 */
1162 UINT32 LIBNETXMS_EXPORTABLE inet_addr_w(const WCHAR *pszAddr)
1163 {
1164 char szBuffer[256];
1165 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, pszAddr, -1, szBuffer, 256, NULL, NULL);
1166 return inet_addr(szBuffer);
1167 }
1168
1169 #if defined(_WITH_ENCRYPTION) && WITH_OPENSSL
1170
1171 /**
1172 * Get OpenSSL error string as UNICODE string
1173 * Buffer must be at least 256 character long
1174 */
1175 WCHAR LIBNETXMS_EXPORTABLE *ERR_error_string_W(int nError, WCHAR *pwszBuffer)
1176 {
1177 char text[256];
1178
1179 memset(text, 0, sizeof(text));
1180 ERR_error_string(nError, text);
1181 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, text, -1, pwszBuffer, 256);
1182 return pwszBuffer;
1183 }
1184
1185 #endif