/*****************************************************************************\ * * * Filename iconv.c * * * * Description: WIN32 port of standard C library's iconv() * * * * Notes: Define here a number of routines, that will eventually * * be used by iconv(). * * * * History: * * 2014-02-27 JFL Created this module. * * 2015-12-09 JFL Added routines fputsU and vfprintfU. * * 2016-09-13 JFL Fixed warnings in fputsU. Do not change the input buffer. * * * * Copyright 2016 Hewlett Packard Enterprise Development LP * * Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 * \*****************************************************************************/ #define _CRT_SECURE_NO_WARNINGS 1 /* Avoid Visual C++ security warnings */ /* Microsoft C libraries include files */ #include #include #include /* MsvcLibX library extensions */ #include "iconv.h" #include "debugm.h" #if defined(_MSDOS) /* TO DO: Add support for DOS code pages! */ #endif /* defined(_MSDOS) */ #ifdef _WIN32 #include /*---------------------------------------------------------------------------*\ * * | Function: ConvertString | | | | Description: Convert a string from one MBCS encoding to another | | | | Parameters: char *buf Buffer containg a NUL-terminated string | | size_t nBytes Buffer size | | UINT cpFrom Initial Windows code page identifier | | UINT cpTo Final Windows code page identifier | | LPCSTR lpDfltC Pointer to the Default Character to use | | (NULL = Use the default default!) | | | | Returns: The converted string size. -1=error, and errno set. | | | | Notes: See the list of Windows code page identifiers there: | | http://msdn.microsoft.com/en-us/library/windows/desktop/dd317756(v=vs.85).aspx | | | History: | | 2014-02-27 JFL Created this routine | * * \*---------------------------------------------------------------------------*/ int ConvertString(char *buf, size_t nBytes, UINT cpFrom, UINT cpTo, LPCSTR lpDefaultChar) { int n = (int)lstrlen(buf); if (cpFrom != cpTo) { WCHAR *pWBuf = (WCHAR *)malloc(sizeof(WCHAR)*nBytes); if (!pWBuf) { errno = ENOMEM; return -1; } n = MultiByteToWideChar(cpFrom, /* CodePage, (CP_ACP, CP_OEMCP, CP_UTF8, ...) */ 0, /* dwFlags, */ buf, /* lpMultiByteStr, */ n+1, /* cbMultiByte, +1 to copy the final NUL */ pWBuf, /* lpWideCharStr, */ (int)nBytes /* cchWideChar, */ ); n = WideCharToMultiByte(cpTo, /* CodePage, (CP_ACP, CP_OEMCP, CP_UTF8, ...) */ 0, /* dwFlags, */ pWBuf, /* lpWideCharStr, */ n, /* cchWideChar, */ buf, /* lpMultiByteStr, */ (int)nBytes, /* cbMultiByte, */ lpDefaultChar, /* lpDefaultChar, */ NULL /* lpUsedDefaultChar */ ); free(pWBuf); if (!n) { errno = Win32ErrorToErrno(); return -1; } n -= 1; /* Output string size, not counting the final NUL */ } return n; } char *DupAndConvert(const char *string, UINT cpFrom, UINT cpTo, LPCSTR lpDefaultChar) { int nBytes; char *pBuf; nBytes = 4 * ((int)lstrlen(string) + 1); /* Worst case for the size needed */ pBuf = (char *)malloc(nBytes); if (!pBuf) { errno = ENOMEM; return NULL; } lstrcpy(pBuf, string); nBytes = ConvertString(pBuf, nBytes, cpFrom, cpTo, lpDefaultChar); if (nBytes == -1) { free(pBuf); return NULL; } pBuf = realloc(pBuf, nBytes+1); return pBuf; } int CountCharacters(const char *string, UINT cp) { int n; WCHAR *pWBuf; n = (int)lstrlen(string); if (!n) return 0; pWBuf = (WCHAR *)malloc(sizeof(WCHAR)*n); if (!pWBuf) { errno = ENOMEM; return -1; } n = MultiByteToWideChar(cp, /* CodePage, (CP_ACP, CP_OEMCP, CP_UTF8, ...) */ 0, /* dwFlags, */ string, /* lpMultiByteStr, */ n, /* cbMultiByte, */ pWBuf, /* lpWideCharStr, */ n /* cchWideChar, */ ); free(pWBuf); if (!n) { errno = Win32ErrorToErrno(); return -1; } return n; } UINT codePage = 0; /*---------------------------------------------------------------------------*\ * * | Functions: fputsU, vfprintfU, fprintfU, printfU | | | | Description: Output UTF-8 strings | | | | Parameters: Same as fputs, vfprintf, fprintf, printf | | | | Returns: Same as fputs, vfprintf, fprintf, printf | | | | Notes: Converts the string to the output code page if needed. | | | | History: | | 2014-02-27 JFL Created fprintfU and printfU. | | 2015-12-09 JFL Restructured them over vfprintfU, itself over fputsU. | | 2016-09-13 JFL Fixed warnings. | | Do not change the input buffer. | * * \*---------------------------------------------------------------------------*/ /* Make sure we're calling Microsoft routines, not our aliases */ #undef printf #undef fprintf #undef vfprintf #undef fputs int fputsU(const char *buf, FILE *f) { /* fputs a UTF-8 string */ int iRet; char *pBuf = NULL; if (!codePage) codePage = GetConsoleOutputCP(); if (codePage != CP_UTF8) { pBuf = DupAndConvert(buf, CP_UTF8, codePage, NULL); } else { pBuf = (char *)buf; } if (pBuf) { /* If no error, and something to output */ iRet = fputs(pBuf, f); if ((iRet >= 0) && DEBUG_IS_ON()) fflush(f); /* Slower, but ensures we get everything before crashes! */ if (pBuf != buf) free(pBuf); } else { iRet = -1; /* Could not convert the string to output */ } return iRet; /* Return the error (n<0) or success (n>=0) */ } int vfprintfU(FILE *f, const char *pszFormat, va_list vl) { /* vfprintf UTF-8 strings */ int n; char buf[UNICODE_PATH_MAX + 4096]; n = _vsnprintf(buf, sizeof(buf), pszFormat, vl); if (n > 0) { /* If no error (n>=0), and something to output (n>0), do output */ int iErr = fputsU(buf, f); if (iErr < 0) n = iErr; } return n; } int fprintfU(FILE *f, const char *pszFormat, ...) { /* fprintf UTF-8 strings */ va_list vl; int n; va_start(vl, pszFormat); n = vfprintfU(f, pszFormat, vl); va_end(vl); return n; } int printfU(const char *pszFormat, ...) { /* printf UTF-8 strings */ va_list vl; int n; va_start(vl, pszFormat); n = vfprintfU(stdout, pszFormat, vl); va_end(vl); return n; } #endif /* _WIN32 */