homework-jianmu/deps/MsvcLibX/src/iconv.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 */