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