230 lines
7.4 KiB
C
230 lines
7.4 KiB
C
/*****************************************************************************\
|
|
* *
|
|
* 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 <errno.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
/* MsvcLibX library extensions */
|
|
#include "msvcIconv.h"
|
|
#include "msvcDebugm.h"
|
|
#include "msvcLimits.h"
|
|
|
|
#if defined(_MSDOS)
|
|
|
|
/* TO DO: Add support for DOS code pages! */
|
|
|
|
#endif /* defined(_MSDOS) */
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
#include <windows.h>
|
|
|
|
/*---------------------------------------------------------------------------*\
|
|
* *
|
|
| 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 */
|
|
|