license headers in libnetxms changed to LGPL
[public/netxms.git] / src / libnetxms / unicode.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2010 Victor Kirhenshtein
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 //
27 // Static data
28 //
29
30 static char m_cpDefault[MAX_CODEPAGE_LEN] = ICONV_DEFAULT_CODEPAGE;
31
32
33 #ifndef _WIN32
34
35 #if HAVE_ICONV_H
36 #include <iconv.h>
37 #endif
38
39
40 //
41 // UNICODE character set
42 //
43
44 #ifndef __DISABLE_ICONV
45
46 // configure first test for libiconv, then for iconv
47 // if libiconv was found, HAVE_ICONV will not be set correctly
48 #if HAVE_LIBICONV
49 #undef HAVE_ICONV
50 #define HAVE_ICONV 1
51 #endif
52
53 #if HAVE_ICONV_UCS_2_INTERNAL
54 #define UCS2_CODEPAGE_NAME "UCS-2-INTERNAL"
55 #elif HAVE_ICONV_UCS_2BE && WORDS_BIGENDIAN
56 #define UCS2_CODEPAGE_NAME "UCS-2BE"
57 #elif HAVE_ICONV_UCS_2LE && !WORDS_BIGENDIAN
58 #define UCS2_CODEPAGE_NAME "UCS-2LE"
59 #elif HAVE_ICONV_UCS_2
60 #define UCS2_CODEPAGE_NAME "UCS-2"
61 #elif HAVE_ICONV_UCS2
62 #define UCS2_CODEPAGE_NAME "UCS2"
63 #else
64 #ifdef UNICODE
65 #error Cannot determine valid UCS-2 codepage name
66 #else
67 #warning Cannot determine valid UCS-2 codepage name
68 #undef HAVE_ICONV
69 #endif
70 #endif
71
72 #if HAVE_ICONV_UCS_4_INTERNAL
73 #define UCS4_CODEPAGE_NAME "UCS-4-INTERNAL"
74 #elif HAVE_ICONV_UCS_4BE && WORDS_BIGENDIAN
75 #define UCS4_CODEPAGE_NAME "UCS-4BE"
76 #elif HAVE_ICONV_UCS_4LE && !WORDS_BIGENDIAN
77 #define UCS4_CODEPAGE_NAME "UCS-4LE"
78 #elif HAVE_ICONV_UCS_4
79 #define UCS4_CODEPAGE_NAME "UCS-4"
80 #elif HAVE_ICONV_UCS4
81 #define UCS4_CODEPAGE_NAME "UCS4"
82 #else
83 #if defined(UNICODE) && defined(UNICODE_UCS4)
84 #error Cannot determine valid UCS-4 codepage name
85 #else
86 #warning Cannot determine valid UCS-4 codepage name
87 #undef HAVE_ICONV
88 #endif
89 #endif
90
91 #ifdef UNICODE_UCS4
92 #define UNICODE_CODEPAGE_NAME UCS4_CODEPAGE_NAME
93 #else /* assume UCS-2 */
94 #define UNICODE_CODEPAGE_NAME UCS2_CODEPAGE_NAME
95 #endif
96
97 #endif /* __DISABLE_ICONV */
98
99
100 //
101 // Set application's default codepage
102 //
103
104 BOOL LIBNETXMS_EXPORTABLE SetDefaultCodepage(const char *cp)
105 {
106 BOOL rc;
107 #if HAVE_ICONV && !defined(__DISABLE_ICONV)
108 iconv_t cd;
109
110 cd = iconv_open(cp, "UTF-8");
111 if (cd != (iconv_t)(-1))
112 {
113 iconv_close(cd);
114 #endif
115 strncpy(m_cpDefault, cp, MAX_CODEPAGE_LEN);
116 m_cpDefault[MAX_CODEPAGE_LEN - 1] = 0;
117 rc = TRUE;
118 #if HAVE_ICONV && !defined(__DISABLE_ICONV)
119 }
120 else
121 {
122 rc = FALSE;
123 }
124 #endif
125 return rc;
126 }
127
128
129 //
130 // Calculate length of wide character string
131 //
132
133 #if !UNICODE_UCS2 || !HAVE_WCSLEN
134
135 int LIBNETXMS_EXPORTABLE ucs2_strlen(const UCS2CHAR *pStr)
136 {
137 int iLen = 0;
138 const UCS2CHAR *pCurr = pStr;
139
140 while(*pCurr++)
141 iLen++;
142 return iLen;
143 }
144
145 #endif
146
147
148 //
149 // Duplicate wide character string
150 //
151
152 #if !UNICODE_UCS2 || !HAVE_WCSDUP
153
154 UCS2CHAR LIBNETXMS_EXPORTABLE *ucs2_strdup(const UCS2CHAR *pStr)
155 {
156 return (UCS2CHAR *)nx_memdup(pStr, (ucs2_strlen(pStr) + 1) * sizeof(UCS2CHAR));
157 }
158
159 #endif
160
161
162 //
163 // Copy wide character string with length limitation
164 //
165
166 #if !UNICODE_UCS2 || !HAVE_WCSNCPY
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 //
183 // Convert UNICODE string to single-byte string
184 //
185
186 int LIBNETXMS_EXPORTABLE WideCharToMultiByte(int iCodePage, DWORD dwFlags,
187 const WCHAR *pWideCharStr, int cchWideChar,
188 char *pByteStr, int cchByteChar,
189 char *pDefaultChar, BOOL *pbUsedDefChar)
190 {
191 #if HAVE_ICONV && !defined(__DISABLE_ICONV)
192 iconv_t cd;
193 int nRet;
194 const char *inbuf;
195 char *outbuf;
196 size_t inbytes, outbytes;
197 char cp[MAX_CODEPAGE_LEN + 16];
198
199 // Calculate required length. Because iconv cannot calculate
200 // resulting multibyte string length, assume the worst case - 3 bytes
201 // per character for UTF-8 and 2 bytes per character for other encodings
202 if (cchByteChar == 0)
203 {
204 return wcslen(pWideCharStr) * (iCodePage == CP_UTF8 ? 3 : 2) + 1;
205 }
206
207 strcpy(cp, m_cpDefault);
208 #if HAVE_ICONV_IGNORE
209 strcat(cp, "//IGNORE");
210 #endif
211 cd = iconv_open(iCodePage == CP_UTF8 ? "UTF-8" : cp, UNICODE_CODEPAGE_NAME);
212 if (cd != (iconv_t)(-1))
213 {
214 inbuf = (const char *)pWideCharStr;
215 inbytes = ((cchWideChar == -1) ? wcslen(pWideCharStr) + 1 : cchWideChar) * sizeof(WCHAR);
216 outbuf = pByteStr;
217 outbytes = cchByteChar;
218 nRet = iconv(cd, (ICONV_CONST char **)&inbuf, &inbytes, &outbuf, &outbytes);
219 iconv_close(cd);
220 if (nRet == -1)
221 {
222 if (errno == EILSEQ)
223 {
224 nRet = cchByteChar - outbytes;
225 }
226 else
227 {
228 nRet = 0;
229 }
230 }
231 if ((cchWideChar == -1) && (outbytes > 0))
232 {
233 *outbuf = 0;
234 }
235 }
236 else
237 {
238 *pByteStr = 0;
239 nRet = 0;
240 }
241 return nRet;
242
243 #else
244
245 const WCHAR *pSrc;
246 char *pDest;
247 int iPos, iSize;
248
249 if (cchByteChar == 0)
250 {
251 return wcslen(pWideCharStr) + 1;
252 }
253
254 iSize = (cchWideChar == -1) ? wcslen(pWideCharStr) : cchWideChar;
255 if (iSize >= cchByteChar)
256 iSize = cchByteChar - 1;
257 for(pSrc = pWideCharStr, iPos = 0, pDest = pByteStr; iPos < iSize; iPos++, pSrc++, pDest++)
258 *pDest = (*pSrc < 256) ? (char)(*pSrc) : '?';
259 *pDest = 0;
260 return iSize;
261
262 #endif /* HAVE_ICONV */
263 }
264
265
266 //
267 // Convert single-byte to UNICODE string
268 //
269
270 int LIBNETXMS_EXPORTABLE MultiByteToWideChar(int iCodePage, DWORD dwFlags, const char *pByteStr,
271 int cchByteChar, WCHAR *pWideCharStr, int cchWideChar)
272 {
273 #if HAVE_ICONV && !defined(__DISABLE_ICONV)
274 iconv_t cd;
275 int nRet;
276 const char *inbuf;
277 char *outbuf;
278 size_t inbytes, outbytes;
279
280 if (cchWideChar == 0)
281 {
282 return strlen(pByteStr) + 1;
283 }
284
285 cd = iconv_open(UNICODE_CODEPAGE_NAME, iCodePage == CP_UTF8 ? "UTF-8" : m_cpDefault);
286 if (cd != (iconv_t)(-1))
287 {
288 inbuf = pByteStr;
289 inbytes = (cchByteChar == -1) ? strlen(pByteStr) + 1 : cchByteChar;
290 outbuf = (char *)pWideCharStr;
291 outbytes = cchWideChar * sizeof(WCHAR);
292 nRet = iconv(cd, (ICONV_CONST char **)&inbuf, &inbytes, &outbuf, &outbytes);
293 iconv_close(cd);
294 if (nRet == -1)
295 {
296 if (errno == EILSEQ)
297 {
298 nRet = (cchWideChar * sizeof(WCHAR) - outbytes) / sizeof(WCHAR);
299 }
300 else
301 {
302 nRet = 0;
303 }
304 }
305 if (((char *)outbuf - (char *)pWideCharStr > sizeof(WCHAR)) && (*pWideCharStr == 0xFEFF))
306 {
307 // Remove UNICODE byte order indicator if presented
308 memmove(pWideCharStr, &pWideCharStr[1], (char *)outbuf - (char *)pWideCharStr - sizeof(WCHAR));
309 outbuf -= sizeof(WCHAR);
310 }
311 if ((cchByteChar == -1) && (outbytes >= sizeof(WCHAR)))
312 {
313 *((WCHAR *)outbuf) = 0;
314 }
315 }
316 else
317 {
318 *pWideCharStr = 0;
319 nRet = 0;
320 }
321 return nRet;
322
323 #else
324
325 const char *pSrc;
326 WCHAR *pDest;
327 int iPos, iSize;
328
329 if (cchWideChar == 0)
330 {
331 return strlen(pByteStr) + 1;
332 }
333
334 iSize = (cchByteChar == -1) ? strlen(pByteStr) : cchByteChar;
335 if (iSize >= cchWideChar)
336 iSize = cchWideChar - 1;
337 for(pSrc = pByteStr, iPos = 0, pDest = pWideCharStr; iPos < iSize; iPos++, pSrc++, pDest++)
338 *pDest = (WCHAR)(*pSrc);
339 *pDest = 0;
340
341 return iSize;
342 #endif
343 }
344
345 #endif /* not _WIN32 */
346
347
348 //
349 // UNICODE version of inet_addr()
350 //
351
352 DWORD LIBNETXMS_EXPORTABLE inet_addr_w(const WCHAR *pszAddr)
353 {
354 char szBuffer[256];
355
356 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
357 pszAddr, -1, szBuffer, 256, NULL, NULL);
358 return inet_addr(szBuffer);
359 }
360
361
362 //
363 // Convert multibyte string to wide string using current codepage and
364 // allocating wide string dynamically
365 //
366
367 WCHAR LIBNETXMS_EXPORTABLE *WideStringFromMBString(const char *pszString)
368 {
369 WCHAR *pwszOut;
370 int nLen;
371
372 nLen = (int)strlen(pszString) + 1;
373 pwszOut = (WCHAR *)malloc(nLen * sizeof(WCHAR));
374 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszString, -1, pwszOut, nLen);
375 return pwszOut;
376 }
377
378
379 //
380 // Convert UTF8 string to wide string allocating wide string dynamically
381 //
382
383 WCHAR LIBNETXMS_EXPORTABLE *WideStringFromUTF8String(const char *pszString)
384 {
385 WCHAR *pwszOut;
386 int nLen;
387
388 nLen = (int)strlen(pszString) + 1;
389 pwszOut = (WCHAR *)malloc(nLen * sizeof(WCHAR));
390 MultiByteToWideChar(CP_UTF8, 0, pszString, -1, pwszOut, nLen);
391 return pwszOut;
392 }
393
394
395 //
396 // Convert wide string to multibyte string using current codepage and
397 // allocating multibyte string dynamically
398 //
399
400 char LIBNETXMS_EXPORTABLE *MBStringFromWideString(const WCHAR *pwszString)
401 {
402 char *pszOut;
403 int nLen;
404
405 nLen = (int)wcslen(pwszString) + 1;
406 pszOut = (char *)malloc(nLen);
407 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
408 pwszString, -1, pszOut, nLen, NULL, NULL);
409 return pszOut;
410 }
411
412
413 //
414 // Convert wide string to UTF8 string allocating UTF8 string dynamically
415 //
416
417 char LIBNETXMS_EXPORTABLE *UTF8StringFromWideString(const WCHAR *pwszString)
418 {
419 char *pszOut;
420 int nLen;
421
422 nLen = WideCharToMultiByte(CP_UTF8, 0, pwszString, -1, NULL, 0, NULL, NULL);
423 pszOut = (char *)malloc(nLen);
424 WideCharToMultiByte(CP_UTF8, 0, pwszString, -1, pszOut, nLen, NULL, NULL);
425 return pszOut;
426 }
427
428
429 //
430 // Get OpenSSL error string as UNICODE string
431 // Buffer must be at least 256 character long
432 //
433
434 #ifdef _WITH_ENCRYPTION
435
436 WCHAR LIBNETXMS_EXPORTABLE *ERR_error_string_W(int nError, WCHAR *pwszBuffer)
437 {
438 char text[256];
439
440 memset(text, 0, sizeof(text));
441 ERR_error_string(nError, text);
442 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, text, -1, pwszBuffer, 256);
443 return pwszBuffer;
444 }
445
446 #endif
447
448
449 #ifdef UNICODE_UCS4
450
451 #ifndef __DISABLE_ICONV
452
453 //
454 // Convert UCS-2 to UCS-4
455 //
456
457 size_t LIBNETXMS_EXPORTABLE ucs2_to_ucs4(const UCS2CHAR *src, size_t srcLen, WCHAR *dst, size_t dstLen)
458 {
459 iconv_t cd;
460 const char *inbuf;
461 char *outbuf;
462 size_t count, inbytes, outbytes;
463
464 cd = iconv_open(UCS4_CODEPAGE_NAME, UCS2_CODEPAGE_NAME);
465 if (cd != (iconv_t)(-1))
466 {
467 inbuf = (const char *)src;
468 inbytes = ((srcLen == -1) ? ucs2_strlen(src) + 1 : srcLen) * sizeof(UCS2CHAR);
469 outbuf = (char *)dst;
470 outbytes = dstLen * sizeof(WCHAR);
471 count = iconv(cd, (ICONV_CONST char **)&inbuf, &inbytes, &outbuf, &outbytes);
472 iconv_close(cd);
473 if (count == -1)
474 {
475 if (errno == EILSEQ)
476 {
477 count = (dstLen * sizeof(WCHAR) - outbytes) / sizeof(WCHAR);
478 }
479 else
480 {
481 count = 0;
482 }
483 }
484 else
485 {
486 count = (dstLen * sizeof(WCHAR) - outbytes) / sizeof(WCHAR);
487 }
488 if ((srcLen == -1) && (outbytes >= sizeof(WCHAR)))
489 {
490 *((WCHAR *)outbuf) = 0;
491 }
492 }
493 else
494 {
495 *dst = 0;
496 count = 0;
497 }
498 return count;
499 }
500
501
502 //
503 // Convert UCS-4 to UCS-2
504 //
505
506 size_t LIBNETXMS_EXPORTABLE ucs4_to_ucs2(const WCHAR *src, size_t srcLen, UCS2CHAR *dst, size_t dstLen)
507 {
508 iconv_t cd;
509 const char *inbuf;
510 char *outbuf;
511 size_t count, inbytes, outbytes;
512
513 cd = iconv_open(UCS2_CODEPAGE_NAME, UCS4_CODEPAGE_NAME);
514 if (cd != (iconv_t)(-1))
515 {
516 inbuf = (const char *)src;
517 inbytes = ((srcLen == -1) ? wcslen(src) + 1 : srcLen) * sizeof(WCHAR);
518 outbuf = (char *)dst;
519 outbytes = dstLen * sizeof(UCS2CHAR);
520 count = iconv(cd, (ICONV_CONST char **)&inbuf, &inbytes, &outbuf, &outbytes);
521 iconv_close(cd);
522 if (count == -1)
523 {
524 if (errno == EILSEQ)
525 {
526 count = (dstLen * sizeof(UCS2CHAR) - outbytes) / sizeof(UCS2CHAR);
527 }
528 else
529 {
530 count = 0;
531 }
532 }
533 else
534 {
535 count = (dstLen * sizeof(UCS2CHAR) - outbytes) / sizeof(UCS2CHAR);
536 }
537 if (((char *)outbuf - (char *)dst > sizeof(UCS2CHAR)) && (*dst == 0xFEFF))
538 {
539 // Remove UNICODE byte order indicator if presented
540 memmove(dst, &dst[1], (char *)outbuf - (char *)dst - sizeof(UCS2CHAR));
541 outbuf -= sizeof(UCS2CHAR);
542 }
543 if ((srcLen == -1) && (outbytes >= sizeof(UCS2CHAR)))
544 {
545 *((UCS2CHAR *)outbuf) = 0;
546 }
547 }
548 else
549 {
550 *dst = 0;
551 count = 0;
552 }
553 return count;
554 }
555
556 #else /* __DISABLE_ICONV */
557
558
559 //
560 // Convert UCS-2 to UCS-4
561 //
562
563 size_t LIBNETXMS_EXPORTABLE ucs2_to_ucs4(const UCS2CHAR *src, size_t srcLen, WCHAR *dst, size_t dstLen)
564 {
565 int i, len;
566
567 len = (int)((srcLen == -1) ? ucs2_strlen(src) : srcLen);
568 if (len > (int)dstLen - 1)
569 len = (int)dstLen - 1;
570 for(i = 0; i < len; i++)
571 dst[i] = (WCHAR)src[i];
572 dst[i] = 0;
573 return len;
574 }
575
576
577 //
578 // Convert UCS-4 to UCS-2
579 //
580
581 size_t LIBNETXMS_EXPORTABLE ucs4_to_ucs2(const WCHAR *src, size_t srcLen, UCS2CHAR *dst, size_t dstLen)
582 {
583 int i, len;
584
585 len = (int)((srcLen == -1) ? wcslen(src) : srcLen);
586 if (len > (int)dstLen - 1)
587 len = (int)dstLen - 1;
588 for(i = 0; i < len; i++)
589 dst[i] = (UCS2CHAR)src[i];
590 dst[i] = 0;
591 return len;
592 }
593
594 #endif /* __DISABLE_ICONV */
595
596
597 //
598 // Convert UCS-4 string to UCS-2 string allocating UCS-2 string dynamically
599 //
600
601 UCS2CHAR LIBNETXMS_EXPORTABLE *UCS2StringFromUCS4String(const WCHAR *pwszString)
602 {
603 UCS2CHAR *pszOut;
604 int nLen;
605
606 nLen = (int)wcslen(pwszString) + 1;
607 pszOut = (UCS2CHAR *)malloc(nLen * sizeof(UCS2CHAR));
608 ucs4_to_ucs2(pwszString, -1, pszOut, nLen);
609 return pszOut;
610 }
611
612
613 //
614 // Convert UCS-2 string to UCS-4 string allocating UCS-4 string dynamically
615 //
616
617 WCHAR LIBNETXMS_EXPORTABLE *UCS4StringFromUCS2String(const UCS2CHAR *pszString)
618 {
619 WCHAR *pwszOut;
620 int nLen;
621
622 nLen = (int)ucs2_strlen(pszString) + 1;
623 pwszOut = (WCHAR *)malloc(nLen * sizeof(WCHAR));
624 ucs2_to_ucs4(pszString, -1, pwszOut, nLen);
625 return pwszOut;
626 }
627
628
629 //
630 // Convert UCS-2 to UTF-8
631 //
632
633 size_t LIBNETXMS_EXPORTABLE ucs2_to_utf8(const UCS2CHAR *src, size_t srcLen, char *dst, size_t dstLen)
634 {
635 #if HAVE_ICONV && !defined(__DISABLE_ICONV)
636 iconv_t cd;
637 const char *inbuf;
638 char *outbuf;
639 size_t count, inbytes, outbytes;
640
641 cd = iconv_open("UTF-8", UCS2_CODEPAGE_NAME);
642 if (cd != (iconv_t)(-1))
643 {
644 inbuf = (const char *)src;
645 inbytes = ((srcLen == -1) ? ucs2_strlen(src) + 1 : srcLen) * sizeof(UCS2CHAR);
646 outbuf = (char *)dst;
647 outbytes = dstLen;
648 count = iconv(cd, (ICONV_CONST char **)&inbuf, &inbytes, &outbuf, &outbytes);
649 iconv_close(cd);
650 if (count == -1)
651 {
652 if (errno == EILSEQ)
653 {
654 count = (dstLen * sizeof(char) - outbytes) / sizeof(char);
655 }
656 else
657 {
658 count = 0;
659 }
660 }
661 else
662 {
663 count = dstLen - outbytes;
664 }
665 if ((srcLen == -1) && (outbytes >= sizeof(char)))
666 {
667 *((char *)outbuf) = 0;
668 }
669 }
670 else
671 {
672 *dst = 0;
673 count = 0;
674 }
675 return count;
676
677 #else
678
679 const UCS2CHAR *psrc;
680 char *pdst;
681 int pos, size;
682
683 size = (srcLen == -1) ? ucs2_strlen(src) : srcLen;
684 if (size >= dstLen)
685 size = dstLen - 1;
686 for(psrc = src, pos = 0, pdst = dst; pos < size; pos++, psrc++, pdst++)
687 *pdst = (*psrc < 256) ? (char)(*psrc) : '?';
688 *pdst = 0;
689 return size;
690 #endif
691 }
692
693 #endif /* UNICODE_UCS4 */
694
695
696 #if !defined(_WIN32) && !defined(UNICODE)
697
698 //
699 // Convert UCS-2 to multibyte
700 //
701
702 size_t LIBNETXMS_EXPORTABLE ucs2_to_mb(const UCS2CHAR *src, size_t srcLen, char *dst, size_t dstLen)
703 {
704 #if HAVE_ICONV && !defined(__DISABLE_ICONV)
705 iconv_t cd;
706 const char *inbuf;
707 char *outbuf;
708 size_t count, inbytes, outbytes;
709
710 cd = iconv_open(m_cpDefault, UCS2_CODEPAGE_NAME);
711 if (cd != (iconv_t)(-1))
712 {
713 inbuf = (const char *)src;
714 inbytes = ((srcLen == -1) ? ucs2_strlen(src) + 1 : srcLen) * sizeof(UCS2CHAR);
715 outbuf = (char *)dst;
716 outbytes = dstLen;
717 count = iconv(cd, (ICONV_CONST char **)&inbuf, &inbytes, &outbuf, &outbytes);
718 iconv_close(cd);
719 if (count == -1)
720 {
721 if (errno == EILSEQ)
722 {
723 count = (dstLen * sizeof(char) - outbytes) / sizeof(char);
724 }
725 else
726 {
727 count = 0;
728 }
729 }
730 if ((srcLen == -1) && (outbytes >= sizeof(char)))
731 {
732 *((char *)outbuf) = 0;
733 }
734 }
735 else
736 {
737 *dst = 0;
738 count = 0;
739 }
740 return count;
741
742 #else
743
744 const UCS2CHAR *psrc;
745 char *pdst;
746 int pos, size;
747
748 size = (srcLen == -1) ? ucs2_strlen(src) : srcLen;
749 if (size >= dstLen)
750 size = dstLen - 1;
751 for(psrc = src, pos = 0, pdst = dst; pos < size; pos++, psrc++, pdst++)
752 *pdst = (*psrc < 256) ? (char)(*psrc) : '?';
753 *pdst = 0;
754 return size;
755 #endif
756 }
757
758
759 //
760 // Convert multibyte to UCS-2
761 //
762
763 size_t LIBNETXMS_EXPORTABLE mb_to_ucs2(const char *src, size_t srcLen, UCS2CHAR *dst, size_t dstLen)
764 {
765 #if HAVE_ICONV && !defined(__DISABLE_ICONV)
766 iconv_t cd;
767 const char *inbuf;
768 char *outbuf;
769 size_t count, inbytes, outbytes;
770
771 cd = iconv_open(UCS2_CODEPAGE_NAME, m_cpDefault);
772 if (cd != (iconv_t)(-1))
773 {
774 inbuf = (const char *)src;
775 inbytes = (srcLen == -1) ? strlen(src) + 1 : srcLen;
776 outbuf = (char *)dst;
777 outbytes = dstLen * sizeof(UCS2CHAR);
778 count = iconv(cd, (ICONV_CONST char **)&inbuf, &inbytes, &outbuf, &outbytes);
779 iconv_close(cd);
780 if (count == -1)
781 {
782 if (errno == EILSEQ)
783 {
784 count = (dstLen * sizeof(UCS2CHAR) - outbytes) / sizeof(UCS2CHAR);
785 }
786 else
787 {
788 count = 0;
789 }
790 }
791 if (((char *)outbuf - (char *)dst > sizeof(UCS2CHAR)) && (*dst == 0xFEFF))
792 {
793 // Remove UNICODE byte order indicator if presented
794 memmove(dst, &dst[1], (char *)outbuf - (char *)dst - sizeof(UCS2CHAR));
795 outbuf -= sizeof(UCS2CHAR);
796 }
797 if ((srcLen == -1) && (outbytes >= sizeof(UCS2CHAR)))
798 {
799 *((UCS2CHAR *)outbuf) = 0;
800 }
801 }
802 else
803 {
804 *dst = 0;
805 count = 0;
806 }
807 return count;
808
809 #else
810
811 const char *psrc;
812 UCS2CHAR *pdst;
813 int pos, size;
814
815 size = (srcLen == -1) ? strlen(src) : srcLen;
816 if (size >= dstLen)
817 size = dstLen - 1;
818 for(psrc = src, pos = 0, pdst = dst; pos < size; pos++, psrc++, pdst++)
819 *pdst = (UCS2CHAR)(*psrc);
820 *pdst = 0;
821
822 return size;
823 #endif
824 }
825
826
827 //
828 // Convert multibyte string to UCS-2 string allocating UCS-2 string dynamically
829 //
830
831 #if !UNICODE_UCS2
832 UCS2CHAR LIBNETXMS_EXPORTABLE *UCS2StringFromMBString(const char *pszString)
833 {
834 UCS2CHAR *pszOut;
835 int nLen;
836
837 nLen = (int)strlen(pszString) + 1;
838 pszOut = (UCS2CHAR *)malloc(nLen * sizeof(UCS2CHAR));
839 mb_to_ucs2(pszString, -1, pszOut, nLen);
840 return pszOut;
841 }
842 #endif
843
844
845 //
846 // Convert UCS-2 string to multibyte string allocating multibyte string dynamically
847 //
848
849 #if !UNICODE_UCS2
850 char LIBNETXMS_EXPORTABLE *MBStringFromUCS2String(const UCS2CHAR *pszString)
851 {
852 char *pszOut;
853 int nLen;
854
855 nLen = (int)ucs2_strlen(pszString) + 1;
856 pszOut = (char *)malloc(nLen);
857 ucs2_to_mb(pszString, -1, pszOut, nLen);
858 return pszOut;
859 }
860 #endif
861
862 #endif /* !defined(_WIN32) && !defined(UNICODE) */
863
864
865 //
866 // UNIX UNICODE specific wrapper functions
867 //
868
869 #if !defined(_WIN32) && defined(UNICODE)
870
871
872 //
873 // Wide character version of some libc functions
874 //
875
876 #if !HAVE_WFOPEN
877
878 FILE LIBNETXMS_EXPORTABLE *wfopen(const WCHAR *_name, const WCHAR *_type)
879 {
880 char *name, *type;
881 FILE *f;
882
883 name = MBStringFromWideString(_name);
884 type = MBStringFromWideString(_type);
885 f = fopen(name, type);
886 free(name);
887 free(type);
888 return f;
889 }
890
891 #endif
892
893 #if !HAVE_WOPEN
894
895 int LIBNETXMS_EXPORTABLE wopen(const WCHAR *_name, int flags, ...)
896 {
897 char *name;
898 int rc;
899
900 name = MBStringFromWideString(_name);
901 if (flags & O_CREAT)
902 {
903 va_list args;
904
905 va_start(args, flags);
906 rc = open(name, flags, va_arg(args, mode_t));
907 va_end(args);
908 }
909 else
910 {
911 rc = open(name, flags);
912 }
913 free(name);
914 return rc;
915 }
916
917 #endif
918
919 #if !HAVE_WSTAT
920
921 int wstat(const WCHAR *_path, struct stat *_sbuf)
922 {
923 char path[MAX_PATH];
924
925 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
926 _path, -1, path, MAX_PATH, NULL, NULL);
927 return stat(path, _sbuf);
928 }
929
930 #endif
931
932 #if !HAVE_WUNLINK
933
934 int wunlink(const WCHAR *_path)
935 {
936 char path[MAX_PATH];
937
938 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
939 _path, -1, path, MAX_PATH, NULL, NULL);
940 return unlink(path);
941 }
942
943 #endif
944
945 #if !HAVE_WRENAME
946
947 int wrename(const WCHAR *_oldpath, const WCHAR *_newpath)
948 {
949 char oldpath[MAX_PATH], newpath[MAX_PATH];
950
951 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
952 _oldpath, -1, oldpath, MAX_PATH, NULL, NULL);
953 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
954 _newpath, -1, newpath, MAX_PATH, NULL, NULL);
955 return rename(oldpath, newpath);
956 }
957
958 #endif
959
960 #if !HAVE_WGETENV
961
962 WCHAR *wgetenv(const WCHAR *_string)
963 {
964 char name[256], *p;
965 static WCHAR value[8192];
966
967 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, _string, -1, name, 256, NULL, NULL);
968 p = getenv(name);
969 if (p == NULL)
970 return NULL;
971
972 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, p, -1, value, 8192);
973 return value;
974 }
975
976 #endif
977
978 #if !HAVE_WCSERROR && HAVE_STRERROR
979
980 WCHAR *wcserror(int errnum)
981 {
982 static WCHAR value[8192];
983
984 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, strerror(errnum), -1, value, 8192);
985 return value;
986 }
987
988 #endif
989
990 #if !HAVE_WCSERROR_R && HAVE_STRERROR_R
991
992 #if HAVE_POSIX_STRERROR_R
993 int wcserror_r(int errnum, WCHAR *strerrbuf, size_t buflen)
994 #else
995 WCHAR *wcserror_r(int errnum, WCHAR *strerrbuf, size_t buflen)
996 #endif
997 {
998 char *mbbuf;
999 #if HAVE_POSIX_STRERROR_R
1000 int err;
1001 #endif
1002
1003 mbbuf = (char *)malloc(buflen);
1004 if (mbbuf != NULL)
1005 {
1006 #if HAVE_POSIX_STRERROR_R
1007 err = strerror_r(errnum, mbbuf, buflen);
1008 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, mbbuf, -1, strerrbuf, buflen);
1009 #else
1010 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, strerror_r(errnum, mbbuf, buflen), -1, strerrbuf, buflen);
1011 #endif
1012 free(mbbuf);
1013 }
1014 else
1015 {
1016 *strerrbuf = 0;
1017 }
1018
1019 #if HAVE_POSIX_STRERROR_R
1020 return err;
1021 #else
1022 return strerrbuf;
1023 #endif
1024 }
1025
1026 #endif
1027
1028
1029 //
1030 // Wrappers for wprintf family
1031 //
1032 // All these wrappers replaces %s with %S and %c with %C
1033 // because in POSIX version of wprintf functions %s and %c
1034 // means "multibyte string/char" instead of expected "UNICODE string/char"
1035 //
1036
1037 int LIBNETXMS_EXPORTABLE nx_wprintf(const WCHAR *format, ...)
1038 {
1039 va_list args;
1040 int rc;
1041
1042 va_start(args, format);
1043 rc = nx_vwprintf(format, args);
1044 va_end(args);
1045 return rc;
1046 }
1047
1048 int LIBNETXMS_EXPORTABLE nx_fwprintf(FILE *fp, const WCHAR *format, ...)
1049 {
1050 va_list args;
1051 int rc;
1052
1053 va_start(args, format);
1054 rc = nx_vfwprintf(fp, format, args);
1055 va_end(args);
1056 return rc;
1057 }
1058
1059 int LIBNETXMS_EXPORTABLE nx_swprintf(WCHAR *buffer, size_t size, const WCHAR *format, ...)
1060 {
1061 va_list args;
1062 int rc;
1063
1064 va_start(args, format);
1065 rc = nx_vswprintf(buffer, size, format, args);
1066 va_end(args);
1067 return rc;
1068 }
1069
1070 static WCHAR *ReplaceFormatSpecs(const WCHAR *oldFormat)
1071 {
1072 WCHAR *fmt, *p;
1073
1074 fmt = wcsdup(oldFormat);
1075 for(p = fmt; *p != 0; p++)
1076 {
1077 if ((*p == _T('%')) && (*(p + 1) != 0))
1078 {
1079 p++;
1080 switch(*p)
1081 {
1082 case _T('s'):
1083 *p = _T('S');
1084 break;
1085 case _T('S'):
1086 *p = _T('s');
1087 break;
1088 case _T('c'):
1089 *p = _T('C');
1090 break;
1091 case _T('C'):
1092 *p = _T('c');
1093 break;
1094 default:
1095 break;
1096 }
1097 }
1098 }
1099 return fmt;
1100 }
1101
1102 int LIBNETXMS_EXPORTABLE nx_vwprintf(const WCHAR *format, va_list args)
1103 {
1104 WCHAR *fmt;
1105 int rc;
1106
1107 fmt = ReplaceFormatSpecs(format);
1108 rc = vwprintf(fmt, args);
1109 free(fmt);
1110 return rc;
1111 }
1112
1113 int LIBNETXMS_EXPORTABLE nx_vfwprintf(FILE *fp, const WCHAR *format, va_list args)
1114 {
1115 WCHAR *fmt;
1116 int rc;
1117
1118 fmt = ReplaceFormatSpecs(format);
1119 rc = vfwprintf(fp, fmt, args);
1120 free(fmt);
1121 return rc;
1122 }
1123
1124 int LIBNETXMS_EXPORTABLE nx_vswprintf(WCHAR *buffer, size_t size, const WCHAR *format, va_list args)
1125 {
1126 WCHAR *fmt;
1127 int rc;
1128
1129 fmt = ReplaceFormatSpecs(format);
1130 rc = vswprintf(buffer, size, fmt, args);
1131 free(fmt);
1132 return rc;
1133 }
1134
1135 #endif