Commit | Line | Data |
---|---|---|
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 | ||
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 | ||
1c45282c VK |
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 | ||
5039dede AK |
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 | ||
5039dede AK |
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 | ||
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 |
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 | } | |
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 |
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 | } | |
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 | ||
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 | ||
6d738067 VK |
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 | ||
5039dede AK |
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 | ||
b0823d06 VK |
992 | #if HAVE_POSIX_STRERROR_R |
993 | int wcserror_r(int errnum, WCHAR *strerrbuf, size_t buflen) | |
994 | #else | |
5039dede | 995 | WCHAR *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 | ||
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++) | |
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 | ||
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 |