license headers in libnetxms changed to LGPL
[public/netxms.git] / src / libnetxms / unicode.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS - Network Management System
4b29d5a0 3** Copyright (C) 2003-2010 Victor Kirhenshtein
5039dede
AK
4**
5** This program is free software; you can redistribute it and/or modify
68f384ea
VK
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
5039dede
AK
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**
68f384ea 15** You should have received a copy of the GNU Lesser General Public License
5039dede
AK
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
30static 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
104BOOL 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
135int 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
154UCS2CHAR 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
168UCS2CHAR 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
186int 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
270int 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
352DWORD 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
367WCHAR 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
383WCHAR 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
400char 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
417char 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
436WCHAR 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
457size_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
506size_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
1c45282c
VK
556#else /* __DISABLE_ICONV */
557
558
559//
560// Convert UCS-2 to UCS-4
561//
562
563size_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
581size_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
5039dede
AK
596
597//
598// Convert UCS-4 string to UCS-2 string allocating UCS-2 string dynamically
599//
600
601UCS2CHAR 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
617WCHAR 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
5039dede
AK
628
629//
630// Convert UCS-2 to UTF-8
631//
632
633size_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
702size_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
763size_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
39945910
VK
826
827//
828// Convert multibyte string to UCS-2 string allocating UCS-2 string dynamically
829//
830
d47340fa 831#if !UNICODE_UCS2
39945910
VK
832UCS2CHAR 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}
d47340fa 842#endif
39945910
VK
843
844
845//
846// Convert UCS-2 string to multibyte string allocating multibyte string dynamically
847//
848
d47340fa 849#if !UNICODE_UCS2
39945910
VK
850char 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}
d47340fa 860#endif
39945910 861
5039dede
AK
862#endif /* !defined(_WIN32) && !defined(UNICODE) */
863
864
5039dede
AK
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
878FILE 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
895int 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
921int 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
6d738067
VK
932#if !HAVE_WUNLINK
933
934int 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
947int 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
5039dede
AK
960#if !HAVE_WGETENV
961
962WCHAR *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
980WCHAR *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
b0823d06
VK
992#if HAVE_POSIX_STRERROR_R
993int wcserror_r(int errnum, WCHAR *strerrbuf, size_t buflen)
994#else
5039dede 995WCHAR *wcserror_r(int errnum, WCHAR *strerrbuf, size_t buflen)
b0823d06 996#endif
5039dede
AK
997{
998 char *mbbuf;
b0823d06
VK
999#if HAVE_POSIX_STRERROR_R
1000 int err;
1001#endif
5039dede
AK
1002
1003 mbbuf = (char *)malloc(buflen);
1004 if (mbbuf != NULL)
1005 {
b0823d06
VK
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
5039dede 1010 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, strerror_r(errnum, mbbuf, buflen), -1, strerrbuf, buflen);
b0823d06 1011#endif
5039dede
AK
1012 free(mbbuf);
1013 }
1014 else
1015 {
1016 *strerrbuf = 0;
1017 }
b0823d06
VK
1018
1019#if HAVE_POSIX_STRERROR_R
1020 return err;
1021#else
5039dede 1022 return strerrbuf;
b0823d06 1023#endif
5039dede
AK
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
1037int 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
1048int 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
1059int 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
1070static WCHAR *ReplaceFormatSpecs(const WCHAR *oldFormat)
1071{
1072 WCHAR *fmt, *p;
1073
1074 fmt = wcsdup(oldFormat);
1075 for(p = fmt; *p != 0; p++)
209db0a9 1076 {
5039dede
AK
1077 if ((*p == _T('%')) && (*(p + 1) != 0))
1078 {
1079 p++;
ff175e91
VK
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;
209db0a9 1096 }
5039dede 1097 }
209db0a9 1098 }
5039dede
AK
1099 return fmt;
1100}
1101
1102int 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
1113int 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
1124int 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