1 /*
2 * Copyright (c) 1999, 2021 Tanuki Software, Ltd.
3 * http://www.tanukisoftware.com
4 * All rights reserved.
5 *
6 * This software is the proprietary information of Tanuki Software.
7 * You shall use it only in accordance with the terms of the
8 * license agreement you entered into with Tanuki Software.
9 * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html
10 */
11
12 #ifdef WIN32
13 #include <windows.h>
14 #include <tchar.h>
15 #else
16 #ifndef FREEBSD
17 #include <iconv.h>
18 #endif
19 #include <langinfo.h>
20 #include <errno.h>
21 #include <limits.h>
22 #endif
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <assert.h>
26 #include <sys/stat.h>
27 #include <string.h>
28 #include "logger_base.h"
29 #ifdef FREEBSD
30 #include "wrapperinfo.h"
31 #endif
32
33 #ifndef TRUE
34 #define TRUE -1
35 #endif
36
37 #ifndef FALSE
38 #define FALSE 0
39 #endif
40
41 /**
42 * Dynamically load the symbols for the iconv library
43 */
44 #ifdef FREEBSD
45 typedef void *iconv_t;
46 static iconv_t (*wrapper_iconv_open)(const char *, const char *);
47 static size_t (*wrapper_iconv)(iconv_t, const char **, size_t *, char **, size_t *);
48 static int (*wrapper_iconv_close)(iconv_t);
49 static char iconvLibNameMB[128];
50 static TCHAR iconvLibNameW[128];
51 #else
52 #define wrapper_iconv_open iconv_open
53 #define wrapper_iconv iconv
54 #define wrapper_iconv_close iconv_close
55 #endif
56
57 #if defined(UNICODE) && defined(WIN32)
58 /**
59 * @param multiByteChars The MultiByte encoded source string.
60 * @param encoding Encoding of the MultiByte characters.
61 * @param outputBuffer If return is TRUE then this will be an error message. If return is FALSE then this will contain the
62 * requested WideChars string. If there were any memory problems, the return will be TRUE and the
63 * buffer will be set to NULL. In any case, it is the responsibility of the caller to free the output
64 * buffer memory.
65 * @param localizeErrorMessage TRUE if the error message can be localized.
66 *
67 * @return TRUE if there were problems, FALSE if Ok.
68 *
69 */
multiByteToWideChar(const char * multiByteChars,int encoding,TCHAR ** outputBufferW,int localizeErrorMessage)70 int multiByteToWideChar(const char *multiByteChars, int encoding, TCHAR **outputBufferW, int localizeErrorMessage) {
71 const TCHAR *errorTemplate;
72 size_t errorTemplateLen;
73 int req;
74
75 /* Clear the output buffer as a sanity check. Shouldn't be needed. */
76 *outputBufferW = NULL;
77
78 req = MultiByteToWideChar(encoding, MB_ERR_INVALID_CHARS, multiByteChars, -1, NULL, 0);
79 if (req <= 0) {
80 if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
81 errorTemplate = (localizeErrorMessage ? TEXT("Invalid multibyte sequence.") : TEXT("Invalid multibyte sequence."));
82 errorTemplateLen = _tcslen(errorTemplate) + 1;
83 *outputBufferW = malloc(sizeof(TCHAR) * errorTemplateLen);
84 if (*outputBufferW) {
85 _sntprintf(*outputBufferW, errorTemplateLen, TEXT("%s"), errorTemplate);
86 } else {
87 /* Out of memory. *outputBufferW already NULL. */
88 }
89 return TRUE;
90 } else {
91 errorTemplate = (localizeErrorMessage ? TEXT("Unexpected conversion error: %d") : TEXT("Unexpected conversion error: %d"));
92 errorTemplateLen = _tcslen(errorTemplate) + 10 + 1;
93 *outputBufferW = malloc(sizeof(TCHAR) * errorTemplateLen);
94 if (*outputBufferW) {
95 _sntprintf(*outputBufferW, errorTemplateLen, errorTemplate, GetLastError());
96 } else {
97 /* Out of memory. *outputBufferW already NULL. */
98 }
99 return TRUE;
100 }
101 }
102 *outputBufferW = malloc((req + 1) * sizeof(TCHAR));
103 if (!(*outputBufferW)) {
104 _tprintf(TEXT("Out of memory (%s%02d)"), TEXT("MBTWC"), 1);
105 /* Out of memory. *outputBufferW already NULL. */
106 return TRUE;
107 }
108
109 MultiByteToWideChar(encoding, MB_ERR_INVALID_CHARS, multiByteChars, -1, *outputBufferW, req + 1);
110 return FALSE;
111 }
112 #endif
113
114
115 #if defined(UNICODE) && !defined(WIN32)
116 #include <fcntl.h>
117
118
119
120 /**
121 * Converts a MultiByte encoded string to a WideChars string specifying the output encoding.
122 *
123 * @param multiByteChars The MultiByte encoded source string.
124 * @param multiByteEncoding The source encoding.
125 * @param interumEncoding The interum encoding before transforming to Wide Chars (On solaris this is the result encoding.)
126 * If the ecoding is appended by "//TRANSLIT", "//IGNORE", "//TRANSLIT//IGNORE" then the conversion
127 * will try to transliterate and or ignore invalid characters without warning.
128 * @param outputBufferW If return is TRUE then this will be an error message. If return is FALSE then this will contain the
129 * requested WideChars string. If there were any memory problems, the return will be TRUE and the
130 * buffer will be set to NULL. In any case, it is the responsibility of the caller to free the output
131 * buffer memory.
132 * @param localizeErrorMessage TRUE if the error message can be localized.
133 *
134 * @return TRUE if there were problems, FALSE if Ok.
135 */
multiByteToWideChar(const char * multiByteChars,const char * multiByteEncoding,char * interumEncoding,wchar_t ** outputBufferW,int localizeErrorMessage)136 int multiByteToWideChar(const char *multiByteChars, const char *multiByteEncoding, char *interumEncoding, wchar_t **outputBufferW, int localizeErrorMessage) {
137 const TCHAR *errorTemplate;
138 size_t errorTemplateLen;
139 size_t iconv_value;
140 char *nativeChar;
141 char *nativeCharStart;
142 size_t multiByteCharsLen;
143 size_t nativeCharLen;
144 size_t outBytesLeft;
145 size_t inBytesLeft;
146 #if defined(FREEBSD) || defined(SOLARIS) || (defined(AIX) && defined(USE_LIBICONV_GNU))
147 const char* multiByteCharsStart;
148 #else
149 char* multiByteCharsStart;
150 #endif
151 iconv_t conv_desc;
152 int didIConv;
153 size_t wideCharLen;
154 int err;
155
156 /* Clear the output buffer as a sanity check. Shouldn't be needed. */
157 *outputBufferW = NULL;
158
159 multiByteCharsLen = strlen(multiByteChars);
160 if (!multiByteCharsLen) {
161 /* The input string is empty, so the output will be as well. */
162 *outputBufferW = malloc(sizeof(TCHAR));
163 if (*outputBufferW) {
164 (*outputBufferW)[0] = TEXT('\0');
165 return FALSE;
166 } else {
167 /* Out of memory. *outputBufferW already NULL. */
168 return TRUE;
169 }
170 }
171
172 /* First we need to convert from the multi-byte string to native. */
173 /* If the multiByteEncoding and interumEncoding encodings are equal then there is nothing to do. */
174 if ((strcmp(multiByteEncoding, interumEncoding) != 0) && strcmp(interumEncoding, "646") != 0) {
175 conv_desc = wrapper_iconv_open(interumEncoding, multiByteEncoding); /* convert multiByte encoding to interum-encoding*/
176 if (conv_desc == (iconv_t)(-1)) {
177 /* Initialization failure. */
178 err = errno;
179 if (err == EINVAL) {
180 errorTemplate = (localizeErrorMessage ? TEXT("Conversion from '% s' to '% s' is not supported.") : TEXT("Conversion from '% s' to '% s' is not supported."));
181 errorTemplateLen = _tcslen(errorTemplate) + strlen(multiByteEncoding) + strlen(interumEncoding) + 1;
182 *outputBufferW = malloc(sizeof(TCHAR) * errorTemplateLen);
183 if (*outputBufferW) {
184 _sntprintf(*outputBufferW, errorTemplateLen, errorTemplate, multiByteEncoding, interumEncoding);
185 } else {
186 /* Out of memory. *outputBufferW already NULL. */
187 }
188 return TRUE;
189 } else {
190 errorTemplate = (localizeErrorMessage ? TEXT("Initialization failure in iconv: %d") : TEXT("Initialization failure in iconv: %d"));
191 errorTemplateLen = _tcslen(errorTemplate) + 10 + 1;
192 *outputBufferW = malloc(sizeof(TCHAR) * errorTemplateLen);
193 if (*outputBufferW) {
194 _sntprintf(*outputBufferW, errorTemplateLen, errorTemplate, err);
195 } else {
196 /* Out of memory. *outputBufferW already NULL. */
197 }
198 return TRUE;
199 }
200 }
201 ++multiByteCharsLen; /* add 1 in order to store \0 - especially necessary in UTF-8 -> UTF-8 conversions. Note: it would be better to do it like in converterMBToMB(). */
202
203 /* We need to figure out how many bytes we need to store the native encoded string. */
204 nativeCharLen = multiByteCharsLen;
205 do {
206 #if defined(FREEBSD) || defined(SOLARIS) || (defined(AIX) && defined(USE_LIBICONV_GNU))
207 multiByteCharsStart = multiByteChars;
208 #else
209 multiByteCharsStart = (char *)multiByteChars;
210 #endif
211 nativeChar = malloc(nativeCharLen);
212 if (!nativeChar) {
213 wrapper_iconv_close(conv_desc);
214 /* Out of memory. */
215 *outputBufferW = NULL;
216 return TRUE;
217 }
218
219 nativeCharStart = nativeChar;
220
221 /* Make a copy of nativeCharLen & multiByteCharsLen (Iconv will decrement inBytesLeft and increment outBytesLeft). */
222 inBytesLeft = multiByteCharsLen;
223 outBytesLeft = nativeCharLen;
224 iconv_value = wrapper_iconv(conv_desc, &multiByteCharsStart, &inBytesLeft, &nativeCharStart, &outBytesLeft);
225 /* Handle failures. */
226 if (iconv_value == (size_t)-1) {
227 /* See "man 3 iconv" for an explanation. */
228 err = errno;
229 free(nativeChar);
230 switch (err) {
231 case EILSEQ:
232 errorTemplate = (localizeErrorMessage ? TEXT("Invalid multibyte sequence.") : TEXT("Invalid multibyte sequence."));
233 errorTemplateLen = _tcslen(errorTemplate) + 1;
234 *outputBufferW = malloc(sizeof(TCHAR) * errorTemplateLen);
235 if (*outputBufferW) {
236 _sntprintf(*outputBufferW, errorTemplateLen, errorTemplate);
237 } else {
238 /* Out of memory. *outputBufferW already NULL. */
239 }
240 wrapper_iconv_close(conv_desc);
241 return TRUE;
242
243 case EINVAL:
244 errorTemplate = (localizeErrorMessage ? TEXT("Incomplete multibyte sequence.") : TEXT("Incomplete multibyte sequence."));
245 errorTemplateLen = _tcslen(errorTemplate) + 1;
246 *outputBufferW = malloc(sizeof(TCHAR) * errorTemplateLen);
247 if (*outputBufferW) {
248 _sntprintf(*outputBufferW, errorTemplateLen, errorTemplate);
249 } else {
250 /* Out of memory. *outputBufferW already NULL. */
251 }
252 wrapper_iconv_close(conv_desc);
253 return TRUE;
254
255 case E2BIG:
256 /* The output buffer was too small, extend it and redo.
257 * iconv decrements inBytesLeft by the number of converted input bytes.
258 * The remaining bytes to convert may not correspond exactly to the additional size
259 * required in the output buffer, but it is a good value to minimize the number of
260 * conversions while ensuring not to extend too much the output buffer. */
261 if (inBytesLeft > 0) {
262 /* Testing that inBytesLeft is >0 should not be needed, but it's a
263 * sanity check to make sure we never fall into an infinite loop. */
264 nativeCharLen += inBytesLeft;
265 continue;
266 }
267 wrapper_iconv_close(conv_desc);
268 return TRUE;
269
270 default:
271 errorTemplate = (localizeErrorMessage ? TEXT("Unexpected iconv error: %d") : TEXT("Unexpected iconv error: %d"));
272 errorTemplateLen = _tcslen(errorTemplate) + 10 + 1;
273 *outputBufferW = malloc(sizeof(TCHAR) * errorTemplateLen);
274 if (*outputBufferW) {
275 _sntprintf(*outputBufferW, errorTemplateLen, errorTemplate, err);
276 } else {
277 /* Out of memory. *outputBufferW already NULL. */
278 }
279 wrapper_iconv_close(conv_desc);
280 return TRUE;
281 }
282 }
283 break;
284 } while (TRUE);
285
286 /* finish iconv */
287 if (wrapper_iconv_close(conv_desc)) {
288 err = errno;
289 free(nativeChar);
290 errorTemplate = (localizeErrorMessage ? TEXT("Cleanup failure in iconv: %d") : TEXT("Cleanup failure in iconv: %d"));
291 errorTemplateLen = _tcslen(errorTemplate) + 10 + 1;
292 *outputBufferW = malloc(sizeof(TCHAR) * errorTemplateLen);
293 if (*outputBufferW) {
294 _sntprintf(*outputBufferW, errorTemplateLen, errorTemplate, err);
295 } else {
296 /* Out of memory. *outputBufferW already NULL. */
297 }
298 return TRUE;
299 }
300 didIConv = TRUE;
301 } else {
302 nativeChar = (char *)multiByteChars;
303 didIConv = FALSE;
304 }
305
306 /* now store the result into a wchar_t */
307 wideCharLen = mbstowcs(NULL, nativeChar, MBSTOWCS_QUERY_LENGTH);
308 if (wideCharLen == (size_t)-1) {
309 err = errno;
310 if (didIConv) {
311 free(nativeChar);
312 }
313 if (err == EILSEQ) {
314 errorTemplate = (localizeErrorMessage ? TEXT("Invalid multibyte sequence.") : TEXT("Invalid multibyte sequence."));
315 errorTemplateLen = _tcslen(errorTemplate) + 1;
316 } else {
317 errorTemplate = (localizeErrorMessage ? TEXT("Unexpected iconv error: %d") : TEXT("Unexpected iconv error: %d"));
318 errorTemplateLen = _tcslen(errorTemplate) + 10 + 1;
319 }
320 *outputBufferW = malloc(sizeof(TCHAR) * errorTemplateLen);
321 if (*outputBufferW) {
322 _sntprintf(*outputBufferW, errorTemplateLen, errorTemplate, err);
323 } else {
324 /* Out of memory. *outputBufferW already NULL. */
325 }
326 return TRUE;
327 }
328 *outputBufferW = malloc(sizeof(wchar_t) * (wideCharLen + 1));
329 if (!(*outputBufferW)) {
330 /* Out of memory. *outputBufferW already NULL. */
331 if (didIConv) {
332 free(nativeChar);
333 }
334 return TRUE;
335 }
336 mbstowcs(*outputBufferW, nativeChar, wideCharLen + 1);
337 (*outputBufferW)[wideCharLen] = TEXT('\0'); /* Avoid bufferflows caused by badly encoded characters. */
338
339 /* free the native char */
340 if (didIConv) {
341 free(nativeChar);
342 }
343 return FALSE;
344 }
345
346 /**
347 * Converts a MultiByte encoded string to a WideChars string using the locale encoding.
348 *
349 * @param multiByteChars The MultiByte encoded source string.
350 * @param multiByteEncoding The source encoding (if NULL use the locale encoding).
351 * @param outputBufferW If return is TRUE then this will be an error message. If return is FALSE then this will contain the
352 * requested WideChars string. If there were any memory problems, the return will be TRUE and the
353 * buffer will be set to NULL. In any case, it is the responsibility of the caller to free the output
354 * buffer memory.
355 * @param localizeErrorMessage TRUE if the error message can be localized.
356 *
357 * @return TRUE if there were problems, FALSE if Ok.
358 */
converterMBToWide(const char * multiByteChars,const char * multiByteEncoding,wchar_t ** outputBufferW,int localizeErrorMessage)359 int converterMBToWide(const char *multiByteChars, const char *multiByteEncoding, wchar_t **outputBufferW, int localizeErrorMessage) {
360 char* loc;
361 loc = nl_langinfo(CODESET);
362 #ifdef MACOSX
363 if (strlen(loc) == 0) {
364 loc = "UTF-8";
365 }
366 #endif
367 if (multiByteEncoding) {
368 return multiByteToWideChar(multiByteChars, multiByteEncoding, loc, outputBufferW, localizeErrorMessage);
369 } else {
370 return multiByteToWideChar(multiByteChars, loc, loc, outputBufferW, localizeErrorMessage);
371 }
372 }
373
_treadlink(TCHAR * exe,TCHAR * fullPath,size_t size)374 size_t _treadlink(TCHAR* exe, TCHAR* fullPath, size_t size) {
375 char* cExe;
376 char* cFullPath;
377 size_t req;
378
379 req = wcstombs(NULL, exe, 0);
380 if (req == (size_t)-1) {
381 return (size_t)-1;
382 }
383 cExe = malloc(req + 1);
384 if (cExe) {
385 wcstombs(cExe, exe, req + 1);
386 cFullPath = malloc(size);
387 if (cFullPath) {
388 req = readlink(cExe, cFullPath, size);
389 if (req == (size_t)-1) {
390 free(cFullPath);
391 free(cExe);
392 return (size_t)-1;
393 }
394
395 req = mbstowcs(fullPath, cFullPath, size);
396 if (req == (size_t)-1) {
397 free(cFullPath);
398 free(cExe);
399 return (size_t)-1;
400 }
401 fullPath[size - 1] = TEXT('\0'); /* Avoid bufferflows caused by badly encoded characters. */
402
403 free(cFullPath);
404 free(cExe);
405 return req * sizeof(TCHAR);
406 } else {
407 free(cExe);
408 }
409 }
410 return (size_t)-1;
411 }
412
413 /**
414 * This Wrapper function internally does a malloc to generate the
415 * Wide-char version of the return string. This must be freed by the caller.
416 */
_tgetcwd(TCHAR * buf,size_t size)417 TCHAR* _tgetcwd(TCHAR *buf, size_t size) {
418 char* cBuf;
419 size_t len;
420
421 if (buf) {
422 cBuf = malloc(size);
423 if (cBuf) {
424 if (getcwd(cBuf, size) != NULL) {
425 len = mbstowcs(buf, cBuf, size);
426 if (len == (size_t)-1) {
427 /* Failed. */
428 free(cBuf);
429 return NULL;
430 }
431 buf[size - 1] = TEXT('\0'); /* Avoid bufferflows caused by badly encoded characters. */
432 free(cBuf);
433 return buf;
434 }
435 free(cBuf);
436 }
437 }
438 return NULL;
439 }
440
_tpathconf(const TCHAR * path,int name)441 long _tpathconf(const TCHAR *path, int name) {
442 char* cPath;
443 size_t req;
444 long retVal;
445
446 req = wcstombs(NULL, path, 0);
447 if (req == (size_t)-1) {
448 return -1;
449 }
450 cPath = malloc(req + 1);
451 if (cPath) {
452 wcstombs(cPath, path, req + 1);
453 retVal = pathconf(cPath, name);
454 free(cPath);
455 return retVal;
456 }
457 return -1;
458 }
459
460 /**
461 * Set the current locale.
462 *
463 * This Wrapper function internally does a malloc to generate the
464 * Wide-char version of the return string. This must be freed by the caller.
465 *
466 * @param category
467 * @param locale The requested locale. TEXT("") for the default.
468 *
469 * @return NULL if there are any errors, otherwise return locale.
470 */
_tsetlocale(int category,const TCHAR * locale)471 TCHAR *_tsetlocale(int category, const TCHAR *locale) {
472 char* cLocale;
473 char* cReturn;
474 TCHAR* tReturn;
475 size_t req;
476
477 if (locale) {
478 req = wcstombs(NULL, locale, 0);
479 if (req == (size_t)-1) {
480 return NULL;
481 }
482 cLocale = malloc(sizeof(char) * (req + 1));
483 if (!cLocale) {
484 return NULL;
485 }
486 wcstombs(cLocale, locale, req + 1);
487 } else {
488 cLocale = NULL;
489 }
490
491 cReturn = setlocale(category, cLocale);
492 if (cLocale) {
493 free(cLocale);
494 }
495
496 if (cReturn) {
497 req = mbstowcs(NULL, cReturn, MBSTOWCS_QUERY_LENGTH);
498 if (req != (size_t)-1) {
499 tReturn = malloc(sizeof(TCHAR) * (req + 1));
500 if (tReturn) {
501 mbstowcs(tReturn, cReturn, req + 1);
502 tReturn[req] = TEXT('\0'); /* Avoid bufferflows caused by badly encoded characters. */
503 return tReturn;
504 }
505 }
506 }
507 return NULL;
508 }
509
createWideFormat(const wchar_t * fmt,wchar_t ** wFmt)510 int createWideFormat(const wchar_t *fmt, wchar_t **wFmt) {
511 int i, result;
512
513 if (wcsstr(fmt, TEXT("%s")) != NULL) {
514 *wFmt = malloc(sizeof(wchar_t) * (wcslen(fmt) + 1));
515 if (*wFmt) {
516 wcsncpy(*wFmt, fmt, wcslen(fmt) + 1);
517 for (i = 0; i < wcslen(fmt); i++){
518 if (fmt[i] == TEXT('%') && i < wcslen(fmt) && fmt[i + 1] == TEXT('s') && (i == 0 || fmt[i - 1] != TEXT('%'))) {
519 (*wFmt)[i + 1] = TEXT('S');
520 i++;
521 }
522 }
523 (*wFmt)[wcslen(fmt)] = TEXT('\0');
524 }
525 result = TRUE;
526 } else {
527 *wFmt = (wchar_t*)fmt;
528 result = FALSE;
529 }
530 return result;
531 }
532
_tprintf(const wchar_t * fmt,...)533 int _tprintf(const wchar_t *fmt,...) {
534 int i, flag;
535 wchar_t *wFmt = NULL;
536 va_list args;
537
538 flag = createWideFormat(fmt, &wFmt);
539 if (wFmt) {
540 va_start(args, fmt);
541 i = vwprintf(wFmt, args);
542 va_end (args);
543 if (flag == TRUE) {
544 free(wFmt);
545 }
546 return i;
547 }
548 return -1;
549 }
550
_ftprintf(FILE * stream,const wchar_t * fmt,...)551 int _ftprintf(FILE *stream, const wchar_t *fmt, ...) {
552 int i, flag;
553 wchar_t *wFmt = NULL;
554 va_list args;
555
556 flag = createWideFormat(fmt, &wFmt);
557 if (wFmt) {
558 va_start(args, fmt);
559 i = vfwprintf(stream, wFmt, args);
560 va_end (args);
561 if (flag == TRUE) {
562 free(wFmt);
563 }
564 return i;
565 }
566 return -1;
567 }
568
_sntprintf(TCHAR * str,size_t size,const TCHAR * fmt,...)569 int _sntprintf(TCHAR *str, size_t size, const TCHAR *fmt, ...) {
570 int i, flag;
571 wchar_t *wFmt = NULL;
572 va_list args;
573
574 flag = createWideFormat(fmt, &wFmt);
575 if (wFmt) {
576 va_start(args, fmt);
577 i = vswprintf(str, size, wFmt, args);
578 va_end (args);
579 if (flag == TRUE) {
580 free(wFmt);
581 }
582 return i;
583 }
584 return -1;
585 }
586
_tremove(const TCHAR * path)587 int _tremove(const TCHAR *path) {
588 char* cPath;
589 size_t req;
590 int result;
591
592 req = wcstombs(NULL, path, 0);
593 if (req == (size_t)-1) {
594 return -1;
595 }
596
597 cPath = malloc(req + 1);
598 if (cPath) {
599 wcstombs(cPath, path, req + 1);
600 result = remove(cPath);
601 free(cPath);
602 return result;
603 }
604 return -1;
605 }
606
_trename(const TCHAR * path,const TCHAR * to)607 int _trename(const TCHAR *path, const TCHAR *to) {
608 char* cPath;
609 char* cTo;
610 size_t req;
611 int ret;
612
613 ret = -1;
614 req = wcstombs(NULL, path, 0);
615 if (req == (size_t)-1) {
616 return ret;
617 }
618
619 cPath = malloc(req + 1);
620 if (cPath) {
621 wcstombs(cPath, path, req + 1);
622
623 req = wcstombs(NULL, to, 0);
624 if (req == (size_t)-1) {
625 free(cPath);
626 return ret;
627 }
628
629 cTo = malloc(req + 1);
630 if (cTo) {
631 wcstombs(cTo, to, req + 1);
632 ret = rename(cPath, cTo);
633 free(cTo);
634 }
635 free(cPath);
636 }
637 return ret;
638 }
639
_tsyslog(int priority,const TCHAR * message)640 void _tsyslog(int priority, const TCHAR *message) {
641 char* cMessage;
642 size_t req;
643
644 req = wcstombs(NULL, message, 0);
645 if (req == (size_t)-1) {
646 return;
647 }
648
649 cMessage = malloc(req + 1);
650 if (cMessage) {
651 wcstombs(cMessage, message, req + 1);
652 syslog(priority, "%s", cMessage);
653 free(cMessage);
654 }
655 }
656
657 /**
658 * This Wrapper function internally does a malloc to generate the
659 * Wide-char version of the return string. This must be freed by the caller.
660 * Only needed inside the following:
661 * #if !defined(WIN32) && defined(UNICODE)
662 * #endif
663 */
_tgetenv(const TCHAR * name)664 TCHAR * _tgetenv( const TCHAR * name ) {
665 char* cName;
666 TCHAR* val;
667 size_t req;
668 char *cVal;
669
670 req = wcstombs(NULL, name, 0);
671 if (req == (size_t)-1) {
672 return NULL;
673 }
674 cName = malloc(sizeof(char) * (req + 1));
675 if (cName) {
676 wcstombs(cName, name, req + 1);
677 cVal = getenv(cName);
678 free(cName);
679 if (cVal == NULL) {
680 return NULL;
681 }
682
683 req = mbstowcs(NULL, cVal, MBSTOWCS_QUERY_LENGTH);
684 if (req == (size_t)-1) {
685 /* Failed. */
686 return NULL;
687 }
688 val = malloc(sizeof(TCHAR) * (req + 1));
689 if (val) {
690 mbstowcs(val, cVal, req + 1);
691 val[req] = TEXT('\0'); /* Avoid bufferflows caused by badly encoded characters. */
692 return val;
693 }
694 }
695 return NULL;
696 }
697
_tfopen(const wchar_t * file,const wchar_t * mode)698 FILE* _tfopen(const wchar_t* file, const wchar_t* mode) {
699 int sizeFile, sizeMode;
700 char* cFile;
701 char* cMode;
702 FILE *f = NULL;
703
704 sizeFile = wcstombs(NULL, (wchar_t*)file, 0);
705 if (sizeFile == (size_t)-1) {
706 return NULL;
707 }
708
709 cFile= malloc(sizeFile + 1);
710 if (cFile) {
711 wcstombs(cFile, (wchar_t*) file, sizeFile + 1);
712
713 sizeMode = wcstombs(NULL, (wchar_t*)mode, 0);
714 if (sizeMode == (size_t)-1) {
715 free(cFile);
716 return NULL;
717 }
718
719 cMode= malloc(sizeMode + 1);
720 if (cMode) {
721 wcstombs(cMode, (wchar_t*) mode, sizeMode + 1);
722 f = fopen(cFile, cMode);
723 free(cMode);
724 }
725 free(cFile);
726 }
727 return f;
728 }
729
_tpopen(const wchar_t * command,const wchar_t * mode)730 FILE* _tpopen(const wchar_t* command, const wchar_t* mode) {
731 int sizeFile, sizeMode;
732 char* cFile;
733 char* cMode;
734 FILE *f = NULL;
735
736 sizeFile = wcstombs(NULL, (wchar_t*)command, 0);
737 if (sizeFile == (size_t)-1) {
738 return NULL;
739 }
740
741 cFile= malloc(sizeFile + 1);
742 if (cFile) {
743 wcstombs(cFile, (wchar_t*) command, sizeFile + 1);
744
745 sizeMode = wcstombs(NULL, (wchar_t*)mode, 0);
746 if (sizeMode == (size_t)-1) {
747 free(cFile);
748 return NULL;
749 }
750
751 cMode= malloc(sizeMode + 1);
752 if (cMode) {
753 wcstombs(cMode, (wchar_t*) mode, sizeMode + 1);
754 f = popen(cFile, cMode);
755 free(cMode);
756 }
757 free(cFile);
758 }
759 return f;
760 }
761
_tunlink(const wchar_t * address)762 int _tunlink(const wchar_t* address) {
763 int size;
764 char *cAddress;
765
766 size = wcstombs(NULL, (wchar_t*)address, 0);
767 if (size == (size_t)-1) {
768 return -1;
769 }
770
771 cAddress= malloc(size + 1);
772 if (cAddress) {
773 wcstombs(cAddress, (wchar_t*) address, size + 1);
774 size = unlink(cAddress);
775 free(cAddress);
776 return size;
777 }
778 return -1;
779 }
780
781
_tmkfifo(TCHAR * arg,mode_t mode)782 int _tmkfifo(TCHAR* arg, mode_t mode) {
783 size_t size;
784 char *cStr;
785 int r;
786
787 r = -1;
788 size = wcstombs(NULL, arg, 0);
789 if (size == (size_t)-1) {
790 return r;
791 }
792
793 cStr = malloc(size + 1);
794 if (cStr) {
795 wcstombs(cStr, arg, size + 1);
796 r = mkfifo(cStr, mode);
797 free(cStr);
798 }
799 return r;
800 }
801
_tchdir(const TCHAR * path)802 int _tchdir(const TCHAR *path) {
803 int r;
804 size_t size;
805 char *cStr;
806
807 r = -1;
808 size = wcstombs(NULL, path, 0);
809 if (size == (size_t)-1) {
810 return r;
811 }
812
813 cStr = malloc(size + 1);
814 if (cStr) {
815 wcstombs(cStr, path, size + 1);
816 r = chdir(cStr);
817 free(cStr);
818 }
819 return r;
820 }
821
_texecvp(TCHAR * arg,TCHAR ** cmd)822 int _texecvp(TCHAR* arg, TCHAR **cmd) {
823 char** cCmd;
824 char *cArg;
825 int i, size;
826 size_t req;
827
828 for (i = 0; cmd[i] != NULL; i++) {
829 ;
830 }
831 size = i;
832 cCmd = malloc((i + 1) * sizeof *cCmd);
833 if (cCmd) {
834 for (i = 0; i < size; i++) {
835 req = wcstombs(NULL, cmd[i], 0);
836 if (req == (size_t)-1) {
837 i--;
838 for (; i > 0; i--) {
839 free(cCmd[i]);
840 }
841 free(cCmd);
842 return -1;
843 }
844
845 cCmd[i] = malloc(req + 1);
846 if (cCmd[i]) {
847 wcstombs(cCmd[i], cmd[i], req + 1);
848 } else {
849 i--;
850 for (; i > 0; i--) {
851 free(cCmd[i]);
852 }
853 free(cCmd);
854 return -1;
855 }
856 }
857 cCmd[size] = NULL;
858
859 req = wcstombs(NULL, arg, 0);
860 if (req == (size_t)-1) {
861 for (; size >= 0; size--) {
862 free(cCmd[size]);
863 }
864 free(cCmd);
865 return -1;
866 }
867
868 cArg = malloc(req + 1);
869 if (cArg) {
870 wcstombs(cArg, arg, req + 1);
871 i = execvp(cArg, cCmd);
872 free(cArg);
873 } else {
874 i = -1;
875 }
876 for (; size >= 0; size--) {
877 free(cCmd[size]);
878 }
879 free(cCmd);
880 return i;
881 }
882 return -1;
883 }
884
885 #ifdef ECSCASECMP
wcscasecmp(const wchar_t * s1,const wchar_t * s2)886 int wcscasecmp(const wchar_t* s1, const wchar_t* s2) {
887 wint_t a1, a2;
888
889 if (s1 == s2) {
890 return 0;
891 }
892
893 do {
894 a1 = towlower(*s1++);
895 a2 = towlower(*s2++);
896 if (a1 == L'\0') {
897 break;
898 }
899 } while (a1 == a2);
900
901 return a1 - a2;
902 }
903 #endif
904
905
906 #if defined(HPUX)
_vsntprintf(wchar_t * ws,size_t n,const wchar_t * format,va_list arg)907 int _vsntprintf(wchar_t *ws, size_t n, const wchar_t *format, va_list arg) {
908 /* z/OS shows unexpected behaviour if the format string is empty */
909 if (ws) {
910 ws[0] = TEXT('\0');
911 }
912 return vswprintf(ws, n, format, arg);
913 }
914 #endif
915
_texecve(TCHAR * arg,TCHAR ** cmd,TCHAR ** env)916 int _texecve(TCHAR* arg, TCHAR **cmd, TCHAR** env) {
917 char **cCmd;
918 char *cArg;
919 char **cEnv;
920 int i, sizeCmd, sizeEnv;
921 size_t req;
922
923 for (i = 0; cmd[i] != NULL; i++) {
924 ;
925 }
926 sizeCmd = i;
927 cCmd = malloc((i + 1) * sizeof *cCmd);
928 if (cCmd) {
929 for (i = 0; i < sizeCmd; i++) {
930 req = wcstombs(NULL, cmd[i], 0);
931 if (req == (size_t)-1) {
932 i--;
933 for (; i > 0; i--) {
934 free(cCmd[i]);
935 }
936 free(cCmd);
937 return -1;
938 }
939
940 cCmd[i] = malloc(req + 1);
941 if (cCmd[i]) {
942 wcstombs(cCmd[i], cmd[i], req + 1);
943 } else {
944 i--;
945 for (; i > 0; i--) {
946 free(cCmd[i]);
947 }
948 free(cCmd);
949 return -1;
950 }
951 }
952 cCmd[sizeCmd] = NULL;
953 for (i = 0; env[i] != NULL; i++) {
954 ;
955 }
956 sizeEnv = i;
957 cEnv = malloc((i + 1) * sizeof *cEnv);
958 if (!cEnv) {
959 for (; sizeCmd >= 0; sizeCmd--) {
960 free(cCmd[sizeCmd]);
961 }
962 free(cCmd);
963 return -1;
964 }
965 for (i = 0; i < sizeEnv; i++) {
966 req = wcstombs(NULL, env[i], 0);
967 if (req == (size_t)-1) {
968 i--;
969 for (; i > 0; i--) {
970 free(cEnv[i]);
971 }
972 free(cEnv);
973 for (; sizeCmd >= 0; sizeCmd--) {
974 free(cCmd[sizeCmd]);
975 }
976 free(cCmd);
977 return -1;
978 }
979
980 cEnv[i] = malloc(req + 1);
981 if (cEnv[i]) {
982 wcstombs(cEnv[i], env[i], req + 1);
983 } else {
984 i--;
985 for (; i > 0; i--) {
986 free(cEnv[i]);
987 }
988 free(cEnv);
989 for (; sizeCmd >= 0; sizeCmd--) {
990 free(cCmd[sizeCmd]);
991 }
992 free(cCmd);
993 return -1;
994 }
995 }
996 cEnv[sizeEnv] = NULL;
997
998 req = wcstombs(NULL, arg, 0);
999 if (req == (size_t)-1) {
1000 for (; sizeEnv >= 0; sizeEnv--) {
1001 free(cEnv[sizeEnv]);
1002 }
1003 free(cEnv);
1004 for (; sizeCmd >= 0; sizeCmd--) {
1005 free(cCmd[sizeCmd]);
1006 }
1007 free(cCmd);
1008 return -1;
1009 }
1010
1011 cArg = malloc(req + 1);
1012 if (cArg) {
1013 wcstombs(cArg, arg, req + 1);
1014 i = execve(cArg, cCmd, cEnv);
1015 free(cArg);
1016 } else {
1017 i = -1;
1018 }
1019 for (; sizeEnv >= 0; sizeEnv--) {
1020 free(cEnv[sizeEnv]);
1021 }
1022 free(cEnv);
1023 for (; sizeCmd >= 0; sizeCmd--) {
1024 free(cCmd[sizeCmd]);
1025 }
1026 free(cCmd);
1027 return i;
1028 }
1029 return -1;
1030 }
1031
_topen(const TCHAR * path,int oflag,mode_t mode)1032 int _topen(const TCHAR *path, int oflag, mode_t mode) {
1033 char* cPath;
1034 int r;
1035 size_t size;
1036
1037 size = wcstombs(NULL, path, 0);
1038 if (size == (size_t)-1) {
1039 return -1;
1040 }
1041
1042 cPath = malloc(size + 1);
1043 if (cPath) {
1044 wcstombs(cPath, path, size + 1);
1045 r = open(cPath, oflag, mode);
1046 free(cPath);
1047 return r;
1048 }
1049 return -1;
1050 }
1051
1052 #if defined(WRAPPER_USE_PUTENV)
1053 /**
1054 * Normal calls to putenv do not free the string parameter, but UNICODE calls can and should.
1055 */
_tputenv(const TCHAR * string)1056 int _tputenv(const TCHAR *string) {
1057 int r;
1058 size_t size;
1059 char *cStr;
1060
1061 size = wcstombs(NULL, (wchar_t*)string, 0);
1062 if (size == (size_t)-1) {
1063 return -1;
1064 }
1065
1066 cStr = malloc(size + 1);
1067 if (cStr) {
1068 wcstombs(cStr, string, size + 1);
1069 r = putenv(cStr);
1070 /* Can't free cStr as it becomes part of the environment. */
1071 /* free(cstr); */
1072 return r;
1073 }
1074 return -1;
1075 }
1076 #else
_tsetenv(const TCHAR * name,const TCHAR * value,int overwrite)1077 int _tsetenv(const TCHAR *name, const TCHAR *value, int overwrite) {
1078 int r = -1;
1079 size_t size;
1080 char *cName;
1081 char *cValue;
1082
1083 size = wcstombs(NULL, (wchar_t*)name, 0);
1084 if (size == (size_t)-1) {
1085 return -1;
1086 }
1087
1088 cName = malloc(size + 1);
1089 if (cName) {
1090 wcstombs(cName, name, size + 1);
1091
1092 size = wcstombs(NULL, (wchar_t*)value, 0);
1093 if (size == (size_t)-1) {
1094 free(cName);
1095 return -1;
1096 }
1097
1098 cValue = malloc(size + 1);
1099 if (cValue) {
1100 wcstombs(cValue, value, size + 1);
1101
1102 r = setenv(cName, cValue, overwrite);
1103
1104 free(cValue);
1105 }
1106
1107 free(cName);
1108 }
1109 return r;
1110 }
1111
_tunsetenv(const TCHAR * name)1112 void _tunsetenv(const TCHAR *name) {
1113 size_t size;
1114 char *cName;
1115
1116 size = wcstombs(NULL, (wchar_t*)name, 0);
1117 if (size == (size_t)-1) {
1118 return;
1119 }
1120
1121 cName = malloc(size + 1);
1122 if (cName) {
1123 wcstombs(cName, name, size + 1);
1124
1125 unsetenv(cName);
1126
1127 free(cName);
1128 }
1129 }
1130 #endif
1131
_tstat(const wchar_t * filename,struct stat * buf)1132 int _tstat(const wchar_t* filename, struct stat *buf) {
1133 int size;
1134 char *cFileName;
1135
1136 size = wcstombs(NULL, (wchar_t*)filename, 0);
1137 if (size == (size_t)-1) {
1138 return -1;
1139 }
1140
1141 cFileName = malloc(size + 1);
1142 if (cFileName) {
1143 wcstombs(cFileName, (wchar_t*) filename, size + 1);
1144 size = stat(cFileName, buf);
1145 free(cFileName);
1146 }
1147 return size;
1148 }
1149
_tchown(const TCHAR * path,uid_t owner,gid_t group)1150 int _tchown(const TCHAR *path, uid_t owner, gid_t group) {
1151 char* cPath;
1152 int r;
1153 size_t size;
1154
1155 size = wcstombs(NULL, path, 0);
1156 if (size == (size_t)-1) {
1157 return -1;
1158 }
1159
1160 cPath = malloc(size + 1);
1161 if (cPath) {
1162 wcstombs(cPath, path, size + 1);
1163 r = chown(cPath, owner, group);
1164 free(cPath);
1165 return r;
1166 }
1167 return -1;
1168 }
1169
1170 /**
1171 * Expands symlinks and resolves /./, /../ and extra '/' characters to produce a
1172 * canonicalized absolute pathname.
1173 * On some platforms (e.g MACOSX), even if the full path could not be resolved,
1174 * the valid part will be copied to resolvedName until a non-existant folder is
1175 * encountered. resolvedName can then be used to point out where the problem was.
1176 *
1177 * @param fileName The file name to be resolved.
1178 * @param resolvedName A buffer large enough to hold the expanded path.
1179 * @param resolvedNameSize The size of the resolvedName buffer, should usually be PATH_MAX + 1.
1180 *
1181 * @return pointer to resolvedName if successful, otherwise NULL and errno is set to indicate the error.
1182 */
_trealpathN(const wchar_t * fileName,wchar_t * resolvedName,size_t resolvedNameSize)1183 wchar_t* _trealpathN(const wchar_t* fileName, wchar_t *resolvedName, size_t resolvedNameSize) {
1184 char *cFile;
1185 char resolved[PATH_MAX + 1];
1186 int sizeFile;
1187 int req;
1188 char* returnVal;
1189 int err = 0;
1190
1191 sizeFile = wcstombs(NULL, fileName, 0);
1192 if (sizeFile == (size_t)-1) {
1193 return NULL;
1194 }
1195
1196 cFile = malloc(sizeFile + 1);
1197 if (cFile) {
1198 /* Initialize the return value. */
1199 resolvedName[0] = TEXT('\0');
1200
1201 wcstombs(cFile, fileName, sizeFile + 1);
1202
1203 /* get the canonicalized absolute pathname */
1204 resolved[0] = '\0';
1205 returnVal = realpath(cFile, resolved);
1206 err = errno;
1207
1208 free(cFile);
1209
1210 if (strlen(resolved) > 0) {
1211 /* In case realpath failed, 'resolved' may contain a part of the path (until the invalid folder).
1212 * Example: cFile is "/home/user/alex/../nina" but "/home/user/nina" doesn't exist.
1213 * => realpath will return NULL and resolved will be set to "/home/user" */
1214 req = mbstowcs(NULL, resolved, MBSTOWCS_QUERY_LENGTH);
1215 if (req == (size_t)-1) {
1216 if (err != 0) {
1217 /* use errno set by realpath() if it failed. */
1218 errno = err;
1219 }
1220 return NULL;
1221 }
1222 mbstowcs(resolvedName, resolved, resolvedNameSize);
1223 resolvedName[resolvedNameSize - 1] = TEXT('\0'); /* Avoid bufferflows caused by badly encoded characters. */
1224 }
1225
1226 errno = err;
1227 if (returnVal == NULL) {
1228 return NULL;
1229 } else {
1230 return resolvedName;
1231 }
1232 }
1233 return NULL;
1234 }
1235 #endif
1236
1237 /**
1238 * Fill a block of memory with zeros.
1239 * Use this function to ensure no sensitive data remains in memory.
1240 *
1241 * @param str A pointer to the starting address of the block of memory to fill with zeros.
1242 * @param size The size of the block of memory to fill with zeros, in bytes.
1243 */
wrapperSecureZero(void * str,size_t size)1244 void wrapperSecureZero(void* str, size_t size) {
1245 if (str) {
1246 #ifdef WIN32
1247 SecureZeroMemory(str, size);
1248 #else
1249 memset (str, '\0', size);
1250 #ifdef __GNUC__
1251 /* Compiler barrier. */
1252 asm volatile ("" ::: "memory");
1253 #endif
1254 #endif
1255 }
1256 }
1257
1258 /**
1259 * Fill a block of memory with zeros, then free it.
1260 * Use this function to ensure no sensitive data remains in memory.
1261 *
1262 * @param str A pointer to the starting address of the block of memory to fill with zeros.
1263 * @param size The size of the block of memory to fill with zeros, in bytes.
1264 */
wrapperSecureFree(void * str,size_t size)1265 void wrapperSecureFree(void* str, size_t size) {
1266 wrapperSecureZero(str, size);
1267 free(str);
1268 }
1269
1270 /**
1271 * Fill a Wide-char sequence with zeros, then free it.
1272 * Use this function to ensure no sensitive data remains in memory.
1273 *
1274 * @param str String to erase and free.
1275 */
wrapperSecureFreeStrW(TCHAR * str)1276 void wrapperSecureFreeStrW(TCHAR* str) {
1277 if (str) {
1278 wrapperSecureFree(str, _tcslen(str) * sizeof(TCHAR));
1279 }
1280 }
1281
1282 /**
1283 * Fill a multi-byte sequence with zeros, then free it.
1284 * Use this function to ensure no sensitive data remains in memory.
1285 *
1286 * @param str String to erase and free.
1287 */
wrapperSecureFreeStrMB(char * str)1288 void wrapperSecureFreeStrMB(char* str) {
1289 if (str) {
1290 wrapperSecureFree(str, strlen(str));
1291 }
1292 }
1293
1294 /**
1295 * Convert a string to lowercase. A new string will be allocated.
1296 *
1297 * @param value Input string
1298 *
1299 * @return The converted string.
1300 */
toLower(const TCHAR * value)1301 TCHAR* toLower(const TCHAR* value) {
1302 TCHAR* result;
1303 size_t len;
1304 size_t i;
1305
1306 len = _tcslen(value);
1307 result = malloc(sizeof(TCHAR) * (len + 1));
1308 if (!result) {
1309 outOfMemory(TEXT("TL"), 1);
1310 return NULL;
1311 }
1312
1313 for (i = 0; i < len; i++) {
1314 result[i] = _totlower(value[i]);
1315 }
1316 result[len] = TEXT('\0');
1317
1318 return result;
1319 }
1320
1321 /**
1322 * Convert a string to uppercase. A new string will be allocated.
1323 *
1324 * @param value Input string
1325 *
1326 * @return The converted string.
1327 */
toUpper(const TCHAR * value)1328 TCHAR* toUpper(const TCHAR* value) {
1329 TCHAR* result;
1330 size_t len;
1331 size_t i;
1332
1333 len = _tcslen(value);
1334 result = malloc(sizeof(TCHAR) * (len + 1));
1335 if (!result) {
1336 outOfMemory(TEXT("TU"), 1);
1337 return NULL;
1338 }
1339
1340 for (i = 0; i < len; i++) {
1341 result[i] = _totupper(value[i]);
1342 }
1343 result[len] = TEXT('\0');
1344
1345 return result;
1346 }
1347
1348 /**
1349 * Clear any non-alphanumeric characters.
1350 * Generally the OS will ignore the canonical dashes and punctuation in the encoding notation when setting the locale.
1351 * This function is used when comparing two notations to check if they refer to the same encoding.
1352 *
1353 * @param bufferIn input string
1354 * @param bufferOut output string
1355 */
clearNonAlphanumeric(TCHAR * bufferIn,TCHAR * bufferOut)1356 void clearNonAlphanumeric(TCHAR* bufferIn, TCHAR* bufferOut) {
1357 while (*bufferIn) {
1358 if (_istdigit(*bufferIn) || _istalpha(*bufferIn)) {
1359 *bufferOut = *bufferIn;
1360 bufferOut++;
1361 }
1362 bufferIn++;
1363 }
1364 *bufferOut = TEXT('\0');
1365 }
1366
1367 #ifndef WIN32
1368 /**
1369 * Check if the encoding is specified with the canonical name.
1370 * Ex: 'UTF-8' is canonical, 'utf8' isn't.
1371 *
1372 * @param encoding
1373 *
1374 * @return TRUE if this is a canonical name, FALSE otherwise.
1375 */
encodingIsCanonicalName(TCHAR * encoding)1376 int encodingIsCanonicalName(TCHAR* encoding) {
1377 TCHAR c;
1378 int i;
1379
1380 for (i = 0; i < _tcslen(encoding); i++) {
1381 c = encoding[i];
1382 if (c >= TEXT('A') && c <= TEXT('Z')) {
1383 return TRUE;
1384 }
1385 if (c == TEXT('-')) {
1386 return TRUE;
1387 }
1388 }
1389 return FALSE;
1390 }
1391
1392 /**
1393 * Compares two encodings.
1394 *
1395 * @param encoding1 When using systemMode, this should be the system encoding
1396 * @param encoding2
1397 * @param ignoreCase TRUE if the case should be ignored
1398 * TRUE if dashes and punctuation should be ignored.
1399 *
1400 * @return TRUE if the encodings are identical, FALSE otherwise.
1401 */
compareEncodings(TCHAR * encoding1,TCHAR * encoding2,int ignoreCase,int ignorePunctuation)1402 int compareEncodings(TCHAR* encoding1, TCHAR* encoding2, int ignoreCase, int ignorePunctuation) {
1403 TCHAR encoding1Buff[ENCODING_BUFFER_SIZE];
1404 TCHAR encoding2Buff[ENCODING_BUFFER_SIZE];
1405 TCHAR *enc1Ptr;
1406 TCHAR *enc2Ptr;
1407
1408 if (encoding1 && encoding2) {
1409 if (ignorePunctuation) {
1410 clearNonAlphanumeric(encoding1, encoding1Buff);
1411 clearNonAlphanumeric(encoding2, encoding2Buff);
1412 enc1Ptr = encoding1Buff;
1413 enc2Ptr = encoding2Buff;
1414 } else {
1415 enc1Ptr = encoding1;
1416 enc2Ptr = encoding2;
1417 }
1418 if (ignoreCase) {
1419 return (strcmpIgnoreCase(enc1Ptr, enc2Ptr) == 0);
1420 } else {
1421 return (_tcscmp(enc1Ptr, enc2Ptr) == 0);
1422 }
1423 }
1424 return (!encoding1 && !encoding2);
1425 }
1426
1427 /**
1428 * Compares two encodings with the rules of the OS.
1429 * On Linux the comparison ignores case, dashes and punctuation
1430 * (except when the encoding of the system locale is displayed with a canonical name, e.g. C.UTF-8).
1431 * On HPUX, Solaris, AIX and FreeBSD, the comparison is strict.
1432 * On MAC and zOS, the comparison ignores case, but is strict regarding dashes and punctuation.
1433 *
1434 * @param encoding1 system encoding
1435 * @param encoding2 other encoding
1436 *
1437 * @return TRUE if the encodings are identical, FALSE otherwise.
1438 */
compareEncodingsSysMode(TCHAR * encoding1,TCHAR * encoding2)1439 int compareEncodingsSysMode(TCHAR* encoding1, TCHAR* encoding2) {
1440 int ignoreCase = FALSE;
1441 int ignorePunctuation = FALSE;
1442
1443 #ifdef LINUX
1444 if (!encodingIsCanonicalName(encoding1)) {
1445 ignoreCase = TRUE;
1446 ignorePunctuation = TRUE;
1447 }
1448 #elif defined(MACOSX) || defined(ZOS)
1449 ignoreCase = TRUE;
1450 #endif
1451 return compareEncodings(encoding1, encoding2, ignoreCase, ignorePunctuation);
1452 }
1453
1454 /**
1455 * Get the encoding of the current locale.
1456 *
1457 * @param buffer output buffer
1458 *
1459 * @return the buffer or NULL if the encoding could not be retrieved.
1460 */
getCurrentLocaleEncoding(TCHAR * buffer)1461 TCHAR* getCurrentLocaleEncoding(TCHAR* buffer) {
1462 char* sysEncodingChar;
1463 size_t size;
1464
1465 sysEncodingChar = nl_langinfo(CODESET);
1466 #ifdef MACOSX
1467 if (strlen(sysEncodingChar) == 0) {
1468 sysEncodingChar = "UTF-8";
1469 }
1470 #endif
1471 size = mbstowcs(NULL, sysEncodingChar, MBSTOWCS_QUERY_LENGTH);
1472 if ((size > (size_t)0) && (size < (size_t)32)) {
1473 mbstowcs(buffer, sysEncodingChar, size + 1);
1474 buffer[size] = TEXT('\0');
1475 return buffer;
1476 }
1477 return NULL;
1478 }
1479 #endif
1480
1481 /**
1482 * Function to get the system encoding name/number for the encoding
1483 * of the conf file
1484 *
1485 * @para String holding the encoding from the conf file
1486 *
1487 * @return TRUE if not found, FALSE otherwise
1488 *
1489 */
1490 #ifdef WIN32
getEncodingByName(char * encodingMB,int * encoding)1491 int getEncodingByName(char* encodingMB, int *encoding) {
1492 #else
1493 int getEncodingByName(char* encodingMB, char** encoding) {
1494 #endif
1495 if (strIgnoreCaseCmp(encodingMB, "Shift_JIS") == 0) {
1496 #if defined(FREEBSD) || defined (AIX) || defined(MACOSX)
1497 *encoding = "SJIS";
1498 #elif defined(WIN32)
1499 *encoding = 932;
1500 #else
1501 *encoding = "shiftjis";
1502 #endif
1503 } else if (strIgnoreCaseCmp(encodingMB, "eucJP") == 0) {
1504 #if defined(AIX)
1505 *encoding = "IBM-eucJP";
1506 #elif defined(WIN32)
1507 *encoding = 20932;
1508 #else
1509 *encoding = "eucJP";
1510 #endif
1511 } else if (strIgnoreCaseCmp(encodingMB, "UTF-8") == 0) {
1512 #if defined(HPUX)
1513 *encoding = "utf8";
1514 #elif defined(WIN32)
1515 *encoding = 65001;
1516 #else
1517 *encoding = "UTF-8";
1518 #endif
1519 } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-1") == 0) {
1520 #if defined(WIN32)
1521 *encoding = 28591;
1522 #elif defined(LINUX)
1523 *encoding = "ISO-8859-1";
1524 #else
1525 *encoding = "ISO8859-1";
1526 #endif
1527 } else if (strIgnoreCaseCmp(encodingMB, "CP1252") == 0) {
1528 #if defined(WIN32)
1529 *encoding = 1252;
1530 #else
1531 *encoding = "CP1252";
1532 #endif
1533 } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-2") == 0) {
1534 #if defined(WIN32)
1535 *encoding = 28592;
1536 #elif defined(LINUX)
1537 *encoding = "ISO-8859-2";
1538 #else
1539 *encoding = "ISO8859-2";
1540 #endif
1541 } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-3") == 0) {
1542 #if defined(WIN32)
1543 *encoding = 28593;
1544 #elif defined(LINUX)
1545 *encoding = "ISO-8859-3";
1546 #else
1547 *encoding = "ISO8859-3";
1548 #endif
1549 } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-4") == 0) {
1550 #if defined(WIN32)
1551 *encoding = 28594;
1552 #elif defined(LINUX)
1553 *encoding = "ISO-8859-4";
1554 #else
1555 *encoding = "ISO8859-4";
1556 #endif
1557 } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-5") == 0) {
1558 #if defined(WIN32)
1559 *encoding = 28595;
1560 #elif defined(LINUX)
1561 *encoding = "ISO-8859-5";
1562 #else
1563 *encoding = "ISO8859-5";
1564 #endif
1565 } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-6") == 0) {
1566 #if defined(WIN32)
1567 *encoding = 28596;
1568 #elif defined(LINUX)
1569 *encoding = "ISO-8859-6";
1570 #else
1571 *encoding = "ISO8859-6";
1572 #endif
1573 } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-7") == 0) {
1574 #if defined(WIN32)
1575 *encoding = 28597;
1576 #elif defined(LINUX)
1577 *encoding = "ISO-8859-7";
1578 #else
1579 *encoding = "ISO8859-7";
1580 #endif
1581 } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-8") == 0) {
1582 #if defined(WIN32)
1583 *encoding = 28598;
1584 #elif defined(LINUX)
1585 *encoding = "ISO-8859-8";
1586 #else
1587 *encoding = "ISO8859-8";
1588 #endif
1589 } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-9") == 0) {
1590 #if defined(WIN32)
1591 *encoding = 28599;
1592 #elif defined(LINUX)
1593 *encoding = "ISO-8859-9";
1594 #else
1595 *encoding = "ISO8859-9";
1596 #endif
1597 } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-10") == 0) {
1598 #if defined(WIN32)
1599 *encoding = 28600;
1600 #elif defined(LINUX)
1601 *encoding = "ISO-8859-10";
1602 #else
1603 *encoding = "ISO8859-10";
1604 #endif
1605 } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-11") == 0) {
1606 #if defined(WIN32)
1607 *encoding = 28601;
1608 #elif defined(LINUX)
1609 *encoding = "ISO-8859-11";
1610 #else
1611 *encoding = "ISO8859-11";
1612 #endif
1613 } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-13") == 0) {
1614 #if defined(WIN32)
1615 *encoding = 28603;
1616 #elif defined(LINUX)
1617 *encoding = "ISO-8859-13";
1618 #else
1619 *encoding = "ISO8859-13";
1620 #endif
1621 } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-14") == 0) {
1622 #if defined(WIN32)
1623 *encoding = 28604;
1624 #elif defined(LINUX)
1625 *encoding = "ISO-8859-14";
1626 #else
1627 *encoding = "ISO8859-14";
1628 #endif
1629 } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-15") == 0) {
1630 #if defined(WIN32)
1631 *encoding = 28605;
1632 #elif defined(LINUX)
1633 *encoding = "ISO-8859-15";
1634 #else
1635 *encoding = "ISO8859-15";
1636 #endif
1637 } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-16") == 0) {
1638 #if defined(WIN32)
1639 *encoding = 28606;
1640 #elif defined(LINUX)
1641 *encoding = "ISO-8859-16";
1642 #else
1643 *encoding = "ISO8859-16";
1644 #endif
1645 } else if (strIgnoreCaseCmp(encodingMB, "CP1250") == 0) {
1646 #if defined(WIN32)
1647 *encoding = 1250;
1648 #else
1649 *encoding = "CP1250";
1650 #endif
1651 } else if (strIgnoreCaseCmp(encodingMB, "CP1251") == 0) {
1652 #if defined(WIN32)
1653 *encoding = 1251;
1654 #else
1655 *encoding = "CP1251";
1656 #endif
1657 } else if (strIgnoreCaseCmp(encodingMB, "KOI8-R") == 0) {
1658 #if defined(WIN32)
1659 *encoding = 20866;
1660 #else
1661 *encoding = "KOI8-R";
1662 #endif
1663 } else if (strIgnoreCaseCmp(encodingMB, "KOI8-U") == 0) {
1664 #if defined(WIN32)
1665 *encoding = 21866;
1666 #else
1667 *encoding = "KOI8-U";
1668 #endif
1669 } else if (strIgnoreCaseCmp(encodingMB, "DEFAULT") == 0) {
1670 #ifdef WIN32
1671 *encoding = GetACP();
1672 #else
1673 *encoding = nl_langinfo(CODESET);
1674 #ifdef MACOSX
1675 if (strlen(*encoding) == 0) {
1676 *encoding = "UTF-8";
1677 }
1678 #endif
1679 #endif
1680 } else {
1681 return TRUE;
1682 }
1683 return FALSE;
1684 }
1685
1686 #ifdef WIN32
1687 /**
1688 * Converts a Wide string into a specific multibyte encoded string.
1689 *
1690 * @prarm wideChars The Wide string to be converted.
1691 * @param outputBufferMB Returns a newly malloced buffer containing the target MB chars.
1692 * Will contain an error message if the function returns TRUE.
1693 * If this is NULL then there was an out of memory problem.
1694 * Caller must free this up.
1695 * @param outputEncoding Output encoding to use.
1696 *
1697 * @return -1 if there were any problems. size of the buffer in byte otherwise.
1698 */
1699 int converterWideToMB(const TCHAR *wideChars, char **outputBufferMB, int outputEncoding) {
1700 char *errorTemplate;
1701 size_t errorTemplateLen;
1702 int req;
1703
1704 /* Initialize the outputBuffer. */
1705 *outputBufferMB = NULL;
1706
1707 req = WideCharToMultiByte(outputEncoding, 0, wideChars, -1, NULL, 0, NULL, 0);
1708 if (req <= 0) {
1709 errorTemplate = "Unexpected conversion error: %d";
1710 errorTemplateLen = strlen(errorTemplate) + 10 + 1;
1711 *outputBufferMB = malloc(errorTemplateLen);
1712 if (*outputBufferMB) {
1713 _snprintf(*outputBufferMB, errorTemplateLen, errorTemplate, wrapperGetLastError());
1714 } else {
1715 /* Out of memory. *outputBufferW already NULL. */
1716 }
1717 return -1;
1718 }
1719 *outputBufferMB = malloc((req + 1));
1720 if (!(*outputBufferMB)) {
1721 outOfMemory(TEXT("CTW"), 1);
1722 /* Out of memory. *outputBufferW already NULL. */
1723 return -1;
1724 }
1725
1726 WideCharToMultiByte(outputEncoding, 0, wideChars, -1, *outputBufferMB, req + 1, NULL, 0);
1727 return req;
1728 }
1729
1730 /**
1731 * Converts a native multibyte string into a specific multibyte encoded string.
1732 *
1733 * @param multiByteChars The original multi-byte chars.
1734 * @param inputEncoding The multi-byte encoding.
1735 * @param outputBufferMB Returns a newly malloced buffer containing the target MB chars.
1736 * Will contain an error message if the function returns TRUE.
1737 * If this is NULL then there was an out of memory problem.
1738 * Caller must free this up.
1739 * @param outputEncoding Output encoding to use.
1740 *
1741 * @return -1 if there were any problems. buffer size (>=0) if everything was Ok.
1742 */
1743 int converterMBToMB(const char *multiByteChars, int inputEncoding, char **outputBufferMB, int outputEncoding) {
1744 TCHAR* tempBuffer = NULL;
1745 int result1 = 0;
1746 int result2;
1747
1748 if (multiByteToWideChar(multiByteChars, inputEncoding, &tempBuffer, FALSE)) {
1749 if (!tempBuffer) {
1750 return -1;
1751 }
1752 /* The result will be -1 but we still need to convert the error message. */
1753 result1 = -1;
1754 }
1755 result2 = converterWideToMB((const TCHAR*)tempBuffer, outputBufferMB, outputEncoding);
1756 if (result1 == -1) {
1757 return -1;
1758 }
1759 return result2;
1760 }
1761 #else
1762
1763 #ifdef HPUX
1764 static int isIconvHpuxFixEnabled = FALSE;
1765
1766 /**
1767 * Turns on or off a fix used in converterMBToMB()
1768 */
1769 void toggleIconvHpuxFix(int value) {
1770 isIconvHpuxFixEnabled = value;
1771 }
1772 #endif
1773
1774 /**
1775 * Converts a native multibyte string into a specific multibyte encoded string.
1776 *
1777 * @param multiByteChars The original multi-byte chars.
1778 * @param multiByteEncoding The multi-byte encoding.
1779 * @param outputBufferMB Returns a newly malloced buffer containing the target MB chars.
1780 * Will contain an error message if the function returns TRUE.
1781 * If this is NULL then there was an out of memory problem.
1782 * Caller must free this up.
1783 * @param outputEncoding Output encoding to use.
1784 *
1785 * @return -1 if there were any problems. buffer size (>=0) if everything was Ok.
1786 */
1787 int converterMBToMB(const char *multiByteChars, const char *multiByteEncoding, char **outputBufferMB, const char *outputEncoding) {
1788 char *errorTemplate;
1789 size_t errorTemplateLen;
1790 size_t iconv_value;
1791 char *nativeChar;
1792 char *nativeCharStart;
1793 size_t multiByteCharsLen;
1794 int nativeCharLen = -1;
1795 size_t outBytesLeft;
1796 size_t inBytesLeft;
1797 #if defined(FREEBSD) || defined(SOLARIS) || (defined(AIX) && defined(USE_LIBICONV_GNU))
1798 const char* multiByteCharsStart;
1799 #else
1800 char* multiByteCharsStart;
1801 #endif
1802 iconv_t conv_desc;
1803 int err;
1804 #ifdef HPUX
1805 int isIconvHpuxFixEnabledLocal = isIconvHpuxFixEnabled;
1806 #endif
1807
1808 /* Clear the output buffer as a sanity check. Shouldn't be needed. */
1809 *outputBufferMB = NULL;
1810
1811 multiByteCharsLen = strlen(multiByteChars);
1812
1813 /* If the multiByteEncoding and outputEncoding encodings are equal then there is nothing to do. */
1814 if ((strcmp(multiByteEncoding, outputEncoding) != 0) && (strcmp(outputEncoding, "646") != 0) && (multiByteCharsLen > 0)) {
1815 conv_desc = wrapper_iconv_open(outputEncoding, multiByteEncoding); /* convert multiByte encoding to interum-encoding*/
1816 if (conv_desc == (iconv_t)(-1)) {
1817 /* Initialization failure. */
1818 err = errno;
1819 if (err == EINVAL) {
1820 errorTemplate = "Conversion from '%s' to '%s' is not supported.";
1821 errorTemplateLen = strlen(errorTemplate) + strlen(multiByteEncoding) + strlen(outputEncoding) + 1;
1822 *outputBufferMB = malloc(errorTemplateLen);
1823 if (*outputBufferMB) {
1824 snprintf(*outputBufferMB, errorTemplateLen, errorTemplate, multiByteEncoding, outputEncoding);
1825 } else {
1826 /* Out of memory. *outputBufferMB already NULL. */
1827 }
1828 return -1;
1829 } else {
1830 errorTemplate = "Initialization failure in iconv: %d";
1831 errorTemplateLen = strlen(errorTemplate) + 10 + 1;
1832 *outputBufferMB = malloc( errorTemplateLen);
1833 if (*outputBufferMB) {
1834 snprintf(*outputBufferMB, errorTemplateLen, errorTemplate, err);
1835 } else {
1836 /* Out of memory. *outputBufferMB already NULL. */
1837 }
1838 return -1;
1839 }
1840 }
1841
1842 /* We need to figure out how many bytes we need to store the native encoded string. */
1843 nativeCharLen = multiByteCharsLen;
1844 #ifdef HPUX
1845 if (isIconvHpuxFixEnabledLocal) {
1846 multiByteCharsLen = multiByteCharsLen + (((multiByteCharsLen - 1) % 8) == 0 ? 0 : 8 - ((multiByteCharsLen - 1) % 8));
1847 }
1848 #endif
1849 do {
1850 #if defined(FREEBSD) || defined(SOLARIS) || (defined(AIX) && defined(USE_LIBICONV_GNU))
1851 multiByteCharsStart = multiByteChars;
1852 #else
1853 multiByteCharsStart = (char *)multiByteChars;
1854 #endif
1855 nativeChar = calloc(nativeCharLen + 1, 1);
1856 if (!nativeChar) {
1857 wrapper_iconv_close(conv_desc);
1858 /* Out of memory. */
1859 *outputBufferMB = NULL;
1860 return -1;
1861 }
1862
1863 nativeCharStart = nativeChar;
1864
1865 /* Make a copy of nativeCharLen & multiByteCharsLen (Iconv will decrement inBytesLeft and increment outBytesLeft). */
1866 inBytesLeft = multiByteCharsLen + 1;
1867 outBytesLeft = nativeCharLen + 1;
1868 iconv_value = wrapper_iconv(conv_desc, &multiByteCharsStart, &inBytesLeft, &nativeCharStart, &outBytesLeft);
1869 /* Handle failures. */
1870 if (iconv_value == (size_t)-1) {
1871 /* See "man 3 iconv" for an explanation. */
1872 err = errno;
1873 free(nativeChar);
1874 switch (err) {
1875 case EILSEQ:
1876 errorTemplate = "Invalid multibyte sequence.";
1877 errorTemplateLen = strlen(errorTemplate) + 1;
1878 #ifdef HPUX
1879 if (*outputBufferMB) {
1880 free(*outputBufferMB);
1881 }
1882 #endif
1883 *outputBufferMB = malloc(errorTemplateLen);
1884 if (*outputBufferMB) {
1885 snprintf(*outputBufferMB, errorTemplateLen, "%s", errorTemplate);
1886 } else {
1887 /* Out of memory. *outputBufferMB already NULL. */
1888 }
1889 #ifdef HPUX
1890 /* This can happen when multiByteCharsLen was increased to workaround an Iconv bug.
1891 * Keep the error in the output buffer and try again using the original input string size. */
1892 if (isIconvHpuxFixEnabledLocal) {
1893 multiByteCharsLen = strlen(multiByteChars);
1894 isIconvHpuxFixEnabledLocal = FALSE;
1895 continue;
1896 }
1897 #endif
1898 wrapper_iconv_close(conv_desc);
1899 return -1;
1900
1901 case EINVAL:
1902 errorTemplate = "Incomplete multibyte sequence.";
1903 errorTemplateLen = strlen(errorTemplate) + 1;
1904 #ifdef HPUX
1905 if (*outputBufferMB) {
1906 free(*outputBufferMB);
1907 }
1908 #endif
1909 *outputBufferMB = malloc(errorTemplateLen);
1910 if (*outputBufferMB) {
1911 snprintf(*outputBufferMB, errorTemplateLen, "%s", errorTemplate);
1912 } else {
1913 /* Out of memory. *outputBufferMB already NULL. */
1914 }
1915 #ifdef HPUX
1916 /* This can happen when multiByteCharsLen was increased to workaround an Iconv bug.
1917 * Keep the error in the output buffer and try again using the original input string size. */
1918 if (isIconvHpuxFixEnabledLocal) {
1919 multiByteCharsLen = strlen(multiByteChars);
1920 isIconvHpuxFixEnabledLocal = FALSE;
1921 continue;
1922 }
1923 #endif
1924 wrapper_iconv_close(conv_desc);
1925 return -1;
1926
1927 case E2BIG:
1928 /* The output buffer was too small, extend it and redo.
1929 * iconv decrements inBytesLeft by the number of converted input bytes.
1930 * The remaining bytes to convert may not correspond exactly to the additional size
1931 * required in the output buffer, but it is a good value to minimize the number of
1932 * conversions while ensuring not to extend too much the output buffer. */
1933 if (inBytesLeft > 0) {
1934 /* Testing that inBytesLeft is >0 should not be needed, but it's a
1935 * sanity check to make sure we never fall into an infinite loop. */
1936 #ifdef HPUX
1937 /* This can happen when multiByteCharsLen was increased to workaround an Iconv bug.
1938 * Try again using the original input string size. */
1939 if (isIconvHpuxFixEnabledLocal && ((inBytesLeft == 1) || nativeCharLen > (strlen(multiByteChars) * 4))) {
1940 multiByteCharsLen = strlen(multiByteChars);
1941 isIconvHpuxFixEnabledLocal = FALSE;
1942 }
1943 #endif
1944 nativeCharLen += inBytesLeft;
1945 continue;
1946 }
1947 wrapper_iconv_close(conv_desc);
1948 return -1;
1949
1950 default:
1951 #ifdef HPUX
1952 if (isIconvHpuxFixEnabled && !isIconvHpuxFixEnabledLocal && (err == 0)) {
1953 /* We got an error on the first loop, stored it in the output buffer and tried again without the HPUX fix.
1954 * If we get the Iconv bug (with errno=0) this time, then report the original error and return. */
1955 wrapper_iconv_close(conv_desc);
1956 return -1;
1957 }
1958 if (*outputBufferMB) {
1959 free(*outputBufferMB);
1960 }
1961 #endif
1962 errorTemplate = "Unexpected iconv error: %d";
1963 errorTemplateLen = strlen(errorTemplate) + 10 + 1;
1964 *outputBufferMB = malloc(errorTemplateLen);
1965 if (*outputBufferMB) {
1966 snprintf(*outputBufferMB, errorTemplateLen, errorTemplate, err);
1967 } else {
1968 /* Out of memory. *outputBufferMB already NULL. */
1969 }
1970 #ifdef HPUX
1971 /* This can happen when multiByteCharsLen was increased to workaround an Iconv bug.
1972 * Keep the error in the output buffer and try again using the original input string size. */
1973 if (isIconvHpuxFixEnabledLocal && (err != 0)) {
1974 multiByteCharsLen = strlen(multiByteChars);
1975 isIconvHpuxFixEnabledLocal = FALSE;
1976 continue;
1977 }
1978 #endif
1979 wrapper_iconv_close(conv_desc);
1980 return -1;
1981 }
1982 }
1983 break;
1984 } while (TRUE);
1985 #ifdef HPUX
1986 if (*outputBufferMB) {
1987 free(*outputBufferMB);
1988 *outputBufferMB = NULL;
1989 }
1990 #endif
1991
1992 /* finish iconv */
1993 if (wrapper_iconv_close(conv_desc)) {
1994 err = errno;
1995 free(nativeChar);
1996 errorTemplate = "Cleanup failure in iconv: %d";
1997 errorTemplateLen = strlen(errorTemplate) + 10 + 1;
1998 *outputBufferMB = malloc(errorTemplateLen);
1999 if (*outputBufferMB) {
2000 snprintf(*outputBufferMB, errorTemplateLen, errorTemplate, err);
2001 } else {
2002 /* Out of memory. *outputBufferMB already NULL. */
2003 }
2004 return -1;
2005 }
2006 } else {
2007 /* The source chars do not need to be converted. Copy them to make a consistant API. */
2008 nativeCharLen = strlen(multiByteChars);
2009 nativeChar = malloc(sizeof(char) * (nativeCharLen + 1));
2010 if (nativeChar) {
2011 snprintf(nativeChar, nativeCharLen + 1, "%s", multiByteChars);
2012 } else {
2013 /* Out of memory. *outputBufferMB already NULL. */
2014 return -1;
2015 }
2016 }
2017 *outputBufferMB = nativeChar;
2018
2019 return nativeCharLen;
2020 }
2021
2022 /**
2023 * Converts a Wide string into a specific multibyte encoded string.
2024 *
2025 * @prarm wideChars The Wide string to be converted.
2026 * @param outputBufferMB Returns a newly malloced buffer containing the target MB chars.
2027 * Will contain an error message if the function returns TRUE.
2028 * If this is NULL then there was an out of memory problem.
2029 * Caller must free this up.
2030 * @param outputEncoding Output encoding to use (if NULL use the encoding of the locale).
2031 *
2032 * @return -1 if there were any problems. buffer size (>=0) if everything was Ok.
2033 */
2034 int converterWideToMB(const TCHAR *wideChars, char **outputBufferMB, const char *outputEncoding) {
2035 char *errorTemplate;
2036 size_t errorTemplateLen;
2037 size_t len;
2038 char *interumBufferMB;
2039 char* encodingFrom;
2040 int result;
2041
2042 /* Initialize the outputBuffer. */
2043 *outputBufferMB = NULL;
2044
2045 len = wcstombs(NULL, wideChars, 0);
2046
2047 if (len == (size_t)-1) {
2048 errorTemplate = "Invalid multibyte sequence (0x%x)";
2049 errorTemplateLen = strlen(errorTemplate) + 10 + 1;
2050 *outputBufferMB = malloc(errorTemplateLen);
2051 if (*outputBufferMB) {
2052 snprintf(*outputBufferMB, errorTemplateLen, errorTemplate, wrapperGetLastError());
2053 } else {
2054 /* Out of memory. *outputBufferW already NULL. */
2055 }
2056 return -1;
2057 }
2058 interumBufferMB = malloc(len + 1);
2059 if (!interumBufferMB) {
2060 return -1;
2061 }
2062 wcstombs(interumBufferMB, wideChars, len + 1);
2063 encodingFrom = nl_langinfo(CODESET);
2064 #ifdef MACOSX
2065 if (strlen(encodingFrom) == 0) {
2066 encodingFrom = "UTF-8";
2067 }
2068 #endif
2069 if (outputEncoding && (strcmp(encodingFrom, outputEncoding) != 0)) {
2070 result = converterMBToMB(interumBufferMB, encodingFrom, outputBufferMB, outputEncoding);
2071 free(interumBufferMB);
2072 } else {
2073 /* The output encoding is the same as the one of the current locale.
2074 * No need to call converterMBToMB() which would cause an additional malloc/free */
2075 *outputBufferMB = interumBufferMB;
2076 result = (int)strlen(*outputBufferMB);
2077 }
2078
2079 return result;
2080 }
2081 #endif
2082
2083 /**
2084 * Gets the error code for the last operation that failed.
2085 */
2086 int wrapperGetLastError() {
2087 #ifdef WIN32
2088 return WSAGetLastError();
2089 #else
2090 return errno;
2091 #endif
2092 }
2093
2094 /**
2095 * Corrects a path in place by replacing all '/' characters with '\'
2096 * on Windows platforms. Does nothing on NIX platforms.
2097 *
2098 * filename - Filename to be modified. Could be null.
2099 *
2100 * @return TRUE if the filename was changed, FALSE otherwise.
2101 */
2102 int wrapperCorrectWindowsPath(TCHAR *filename) {
2103 int result = FALSE;
2104 #ifdef WIN32
2105 TCHAR *c;
2106
2107 if (filename) {
2108 c = (TCHAR *)filename;
2109 while((c = _tcschr(c, TEXT('/'))) != NULL) {
2110 c[0] = TEXT('\\');
2111 result = TRUE;
2112 }
2113 }
2114 #endif
2115 return result;
2116 }
2117
2118 /**
2119 * Corrects a path in place by replacing all '\' characters with '/'
2120 * on NIX platforms. Does nothing on Windows platforms.
2121 *
2122 * filename - Filename to be modified. Could be null.
2123 *
2124 * @return TRUE if the filename was changed, FALSE otherwise.
2125 */
2126 int wrapperCorrectNixPath(TCHAR *filename) {
2127 int result = FALSE;
2128 #ifndef WIN32
2129 TCHAR *c;
2130
2131 if (filename) {
2132 c = (TCHAR *)filename;
2133 while((c = _tcschr(c, TEXT('\\'))) != NULL) {
2134 c[0] = TEXT('/');
2135 result = TRUE;
2136 }
2137 }
2138 #endif
2139 return result;
2140 }
2141
2142 #ifndef WIN32
2143 /**
2144 * Check if the given encoding is supported by the iconv library.
2145 * We can't use the 'iconv -l' because it is not supported on all platforms.
2146 *
2147 * @return ICONV_ENCODING_SUPPORTED if the encoding is supported,
2148 * ICONV_ENCODING_KNOWN_ISSUE if the encoding exist on iconv but fails to convert some characters.
2149 * ICONV_ENCODING_NOT_SUPPORTED if the encoding is not supported.
2150 */
2151 int getIconvEncodingMBSupport(const char* encodingMB) {
2152 iconv_t conv_desc;
2153 int ret;
2154 const char* fromcode = MB_UTF8;
2155 TCHAR *outputBufferW;
2156
2157 if (encodingMB) {
2158 if (strcmp(encodingMB, fromcode) == 0) {
2159 /* On some platforms, it is not correct to open iconv with the same input and output encodings
2160 * (this is the case on HP-UX). We know that 'fromcode' should be supported, so return TRUE.
2161 * On AIX (and maybe other OS?), the case, dashes and punctuations are important! */
2162 return ICONV_ENCODING_SUPPORTED;
2163 }
2164 conv_desc = wrapper_iconv_open(encodingMB, fromcode);
2165 if (conv_desc != (iconv_t)(-1)) {
2166 wrapper_iconv_close(conv_desc);
2167 /* On some platforms iconv may fail to convert some characters to certain encodings.
2168 * For example backslashs fail to be converted to 'SJIS' on FreeBSD 7.
2169 * The following condition can be improved as new issues are found. */
2170 ret = multiByteToWideChar("\\", fromcode, (char *)encodingMB, &outputBufferW, FALSE);
2171 if (outputBufferW) {
2172 free(outputBufferW);
2173 }
2174 if (ret) {
2175 return ICONV_ENCODING_KNOWN_ISSUE;
2176 } else {
2177 return ICONV_ENCODING_SUPPORTED;
2178 }
2179 }
2180 }
2181 return ICONV_ENCODING_NOT_SUPPORTED;
2182 }
2183
2184 /**
2185 * Check if the given encoding is supported by the iconv library.
2186 *
2187 * @return ICONV_ENCODING_SUPPORTED if the encoding is supported,
2188 * ICONV_ENCODING_KNOWN_ISSUE if the encoding exist on iconv but fails to convert some characters.
2189 * ICONV_ENCODING_NOT_SUPPORTED if the encoding is not supported.
2190 */
2191 int getIconvEncodingSupport(const TCHAR* encoding) {
2192 size_t size;
2193 char *encodingMB = NULL;
2194 int result = FALSE;
2195
2196 if (encoding) {
2197 size = wcstombs(NULL, encoding, 0);
2198 if (size > (size_t)0) {
2199 encodingMB = malloc(size + 1);
2200 if(encodingMB) {
2201 wcstombs(encodingMB, encoding, size + 1);
2202 result = getIconvEncodingMBSupport(encodingMB);
2203 free(encodingMB);
2204 }
2205 }
2206 }
2207 return result;
2208 }
2209 #endif
2210
2211 #ifdef FREEBSD
2212 /**
2213 * Get the name of the iconv library that was loaded.
2214 *
2215 * @return the name of the iconv library (wide chars).
2216 */
2217 TCHAR* getIconvLibName() {
2218 mbstowcs(iconvLibNameW, iconvLibNameMB, 128);
2219 return iconvLibNameW;
2220 }
2221
2222 /**
2223 * Locate an iconv function in the dynamically loaded library.
2224 *
2225 * @param libHandle handle returned from a call to dlopen()
2226 * @param fptr pointer to the function
2227 * @param fname1 first name to search
2228 * @param fname2 second name to search
2229 * @param fname3 third name to search
2230 *
2231 * @return TRUE if there were any problems, FALSE otherwise.
2232 */
2233 int locateIconvFunction(void *libHandle, void **fptr, const char *fname1, const char *fname2, const char *fname3) {
2234 const char *error1;
2235 const char *error2;
2236 const char *error3;
2237 void *func = *fptr;
2238
2239 *(void**)(&func) = dlsym(libHandle, fname1);
2240 if (!func) {
2241 /* The string that dlerror is in a static buffer and should not be freed. It must be immediately used or copied. */
2242 error1 = dlerror();
2243 *(void**)(&func) = dlsym(libHandle, fname2);
2244 if (!func) {
2245 error2 = dlerror();
2246 *(void**)(&func) = dlsym(libHandle, fname3);
2247 if (!func) {
2248 error3 = dlerror();
2249 printf("Failed to locate the %s function from the iconv library (%s): %s\n", fname1, iconvLibNameMB, (error1 ? error1 : "<null>"));
2250 printf("Failed to locate the %s function from the iconv library (%s): %s\n", fname2, iconvLibNameMB, (error2 ? error2 : "<null>"));
2251 printf("Failed to locate the %s function from the iconv library (%s): %s\n", fname3, iconvLibNameMB, (error3 ? error3 : "<null>"));
2252 printf("Unable to continue.\n");
2253 return TRUE;
2254 }
2255 }
2256 }
2257 *fptr = func;
2258
2259 return FALSE;
2260 }
2261
2262 /**
2263 * Tries to load libiconv and then fallback in FreeBSD.
2264 * Unfortunately we can not do any pretty logging here as iconv is
2265 * required for all of that to work.
2266 * Limitation: currently the function will not try the next library
2267 * if the iconv functions failed to load correctly.
2268 *
2269 * @return TRUE if there were any problems, FALSE otherwise.
2270 */
2271 int loadIconvLibrary() {
2272 void *libHandle;
2273 const char *error;
2274
2275 /* After 2013-10-08 (254273), FreeBSD 10-x have the iconv functions in libc.
2276 * Unfortunately there is a problem on the handle when opening libc dynamically.
2277 * We assume there is always at least one of the following libraries on the system. */
2278
2279 /* iconv library name present from FreeBSD 7 to 9 */
2280 strncpy(iconvLibNameMB, "/usr/local/lib/libiconv.so", 128);
2281 libHandle = dlopen(iconvLibNameMB, RTLD_NOW);
2282
2283 /* Falling back to libbiconv library in FreeBSD 10 */
2284 if (libHandle == NULL) {
2285 strncpy(iconvLibNameMB, "/usr/local/lib/libbiconv.so", 128);
2286 libHandle = dlopen(iconvLibNameMB, RTLD_NOW);
2287 }
2288
2289 /* Falling back to libkiconv.4 in FreeBSD 10 */
2290 if (libHandle == NULL && _tcscmp(wrapperBits, TEXT("32")) == 0) {
2291 /* If the 32-bit version of the Wrapper is running on a 64-bit system,
2292 * the correct library is /usr/lib32/libkiconv.so.4.
2293 * Be careful here as not being able to find the library doesn't
2294 * necessarily mean that the system is 32-bit. */
2295 strncpy(iconvLibNameMB, "/usr/lib32/libkiconv.so.4", 128);
2296 libHandle = dlopen(iconvLibNameMB, RTLD_NOW);
2297 }
2298
2299 if (libHandle == NULL) {
2300 strncpy(iconvLibNameMB, "/lib/libkiconv.so.4", 128);
2301 libHandle = dlopen(iconvLibNameMB, RTLD_NOW);
2302 }
2303
2304 /* No library found, we cannot continue as we need iconv support */
2305 if (!libHandle) {
2306 /* The string that dlerror is in a static buffer and should not be freed. It must be immediately used or copied. */
2307 error = dlerror();
2308 printf("Failed to locate the iconv library: %s\n", (error ? error : "<null>"));
2309 printf("Unable to continue.\n");
2310 return TRUE;
2311 }
2312
2313 /* Look up the required functions. Return true if any of them could not be found. */
2314 return locateIconvFunction(libHandle, (void**)&wrapper_iconv_open, "iconv_open", "libiconv_open", "__bsd_iconv_open") ||
2315 locateIconvFunction(libHandle, (void**)&wrapper_iconv, "iconv", "libiconv", "__bsd_iconv") ||
2316 locateIconvFunction(libHandle, (void**)&wrapper_iconv_close, "iconv_close", "libiconv_close", "__bsd_iconv_close");
2317 }
2318 #endif
2319
2320 #ifdef DEBUG_MALLOC
2321 /* There can't be any more malloc calls after the malloc2 function in this file. */
2322 #undef malloc
2323 void *malloc2(size_t size, const char *file, int line, const char *func, const char *sizeVar) {
2324 void *ptr;
2325 #ifdef WIN32
2326 wprintf(L"%S:%d:%S malloc(%S) -> malloc(%d)", file, line, func, sizeVar, size);
2327 #else
2328 wprintf(L"%s:%d:%s malloc(%s) -> malloc(%d)", file, line, func, sizeVar, size);
2329 #endif
2330 ptr = malloc(size);
2331 wprintf(L" -> %p\n", ptr);
2332 return ptr;
2333 }
2334 #endif
2335
2336