diff options
Diffstat (limited to 'grpc/third_party/xxhash/cli/xsum_os_specific.c')
-rw-r--r-- | grpc/third_party/xxhash/cli/xsum_os_specific.c | 487 |
1 files changed, 487 insertions, 0 deletions
diff --git a/grpc/third_party/xxhash/cli/xsum_os_specific.c b/grpc/third_party/xxhash/cli/xsum_os_specific.c new file mode 100644 index 00000000..8f48ce07 --- /dev/null +++ b/grpc/third_party/xxhash/cli/xsum_os_specific.c @@ -0,0 +1,487 @@ +/* + * xxhsum - Command line interface for xxhash algorithms + * Copyright (C) 2013-2020 Yann Collet + * + * GPL v2 License + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * You can contact the author at: + * - xxHash homepage: https://www.xxhash.com + * - xxHash source repository: https://github.com/Cyan4973/xxHash + */ + +#include "xsum_config.h" +#include "xsum_os_specific.h" +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <sys/types.h> /* struct stat / __wstat64 */ +#include <sys/stat.h> /* stat() / _stat64() */ + +/* + * This file contains all of the ugly boilerplate to make xxhsum work across + * platforms. + */ +#if defined(_MSC_VER) || XSUM_WIN32_USE_WCHAR + typedef struct __stat64 XSUM_stat_t; +# if defined(_MSC_VER) + typedef int mode_t; +# endif +#else + typedef struct stat XSUM_stat_t; +#endif + +#if (defined(__linux__) && (XSUM_PLATFORM_POSIX_VERSION >= 1)) \ + || (XSUM_PLATFORM_POSIX_VERSION >= 200112L) \ + || defined(__DJGPP__) \ + || defined(__MSYS__) +# include <unistd.h> /* isatty */ +# define XSUM_IS_CONSOLE(stdStream) isatty(fileno(stdStream)) +#elif defined(MSDOS) || defined(OS2) +# include <io.h> /* _isatty */ +# define XSUM_IS_CONSOLE(stdStream) _isatty(_fileno(stdStream)) +#elif defined(WIN32) || defined(_WIN32) +# include <io.h> /* _isatty */ +# include <windows.h> /* DeviceIoControl, HANDLE, FSCTL_SET_SPARSE */ +# include <stdio.h> /* FILE */ +static __inline int XSUM_IS_CONSOLE(FILE* stdStream) +{ + DWORD dummy; + return _isatty(_fileno(stdStream)) && GetConsoleMode((HANDLE)_get_osfhandle(_fileno(stdStream)), &dummy); +} +#else +# define XSUM_IS_CONSOLE(stdStream) 0 +#endif + +#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(_WIN32) +# include <fcntl.h> /* _O_BINARY */ +# include <io.h> /* _setmode, _fileno, _get_osfhandle */ +# if !defined(__DJGPP__) +# include <windows.h> /* DeviceIoControl, HANDLE, FSCTL_SET_SPARSE */ +# include <winioctl.h> /* FSCTL_SET_SPARSE */ +# define XSUM_SET_BINARY_MODE(file) { int const unused=_setmode(_fileno(file), _O_BINARY); (void)unused; } +# else +# define XSUM_SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +# endif +#else +# define XSUM_SET_BINARY_MODE(file) ((void)file) +#endif + +XSUM_API int XSUM_isConsole(FILE* stream) +{ + return XSUM_IS_CONSOLE(stream); +} + +XSUM_API void XSUM_setBinaryMode(FILE* stream) +{ + XSUM_SET_BINARY_MODE(stream); +} + +#if !XSUM_WIN32_USE_WCHAR + +XSUM_API FILE* XSUM_fopen(const char* filename, const char* mode) +{ + return fopen(filename, mode); +} +XSUM_ATTRIBUTE((__format__(__printf__, 2, 0))) +XSUM_API int XSUM_vfprintf(FILE* stream, const char* format, va_list ap) +{ + return vfprintf(stream, format, ap); +} + +static int XSUM_stat(const char* infilename, XSUM_stat_t* statbuf) +{ +#if defined(_MSC_VER) + return _stat64(infilename, statbuf); +#else + return stat(infilename, statbuf); +#endif +} + +#ifndef XSUM_NO_MAIN +int main(int argc, char* argv[]) +{ + return XSUM_main(argc, argv); +} +#endif + +/* Unicode helpers for Windows to make UTF-8 act as it should. */ +#else +# include <windows.h> +# include <wchar.h> + +/***************************************************************************** + * Unicode conversion tools + *****************************************************************************/ + +/* + * Converts a UTF-8 string to UTF-16. Acts like strdup. The string must be freed afterwards. + * This version allows keeping the output length. + */ +static wchar_t* XSUM_widenString(const char* str, int* lenOut) +{ + int const len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); + if (lenOut != NULL) *lenOut = len; + if (len == 0) return NULL; + { wchar_t* buf = (wchar_t*)malloc((size_t)len * sizeof(wchar_t)); + if (buf != NULL) { + if (MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, len) == 0) { + free(buf); + return NULL; + } } + return buf; + } +} + +/* + * Converts a UTF-16 string to UTF-8. Acts like strdup. The string must be freed afterwards. + * This version allows keeping the output length. + */ +static char* XSUM_narrowString(const wchar_t *str, int *lenOut) +{ + int len = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL); + if (lenOut != NULL) *lenOut = len; + if (len == 0) return NULL; + { char* const buf = (char*)malloc((size_t)len * sizeof(char)); + if (buf != NULL) { + if (WideCharToMultiByte(CP_UTF8, 0, str, -1, buf, len, NULL, NULL) == 0) { + free(buf); + return NULL; + } } + return buf; + } +} + + + +/***************************************************************************** + * File helpers + *****************************************************************************/ +/* + * fopen wrapper that supports UTF-8 + * + * fopen will only accept ANSI filenames, which means that we can't open Unicode filenames. + * + * In order to open a Unicode filename, we need to convert filenames to UTF-16 and use _wfopen. + */ +XSUM_API FILE* XSUM_fopen(const char* filename, const char* mode) +{ + FILE* f = NULL; + wchar_t* const wide_filename = XSUM_widenString(filename, NULL); + if (wide_filename != NULL) { + wchar_t* const wide_mode = XSUM_widenString(mode, NULL); + if (wide_mode != NULL) { + f = _wfopen(wide_filename, wide_mode); + free(wide_mode); + } + free(wide_filename); + } + return f; +} + +/* + * stat() wrapper which supports UTF-8 filenames. + */ +static int XSUM_stat(const char* infilename, XSUM_stat_t* statbuf) +{ + int r = -1; + wchar_t* const wide_filename = XSUM_widenString(infilename, NULL); + if (wide_filename != NULL) { + r = _wstat64(wide_filename, statbuf); + free(wide_filename); + } + return r; +} + +/* + * In case it isn't available, this is what MSVC 2019 defines in stdarg.h. + */ +#if defined(_MSC_VER) && !defined(__clang__) && !defined(va_copy) +# define XSUM_va_copy(destination, source) ((destination) = (source)) +#else +# define XSUM_va_copy(destination, source) va_copy(destination, source) +#endif + +/* + * vasprintf for Windows. + */ +XSUM_ATTRIBUTE((__format__(__printf__, 2, 0))) +static int XSUM_vasprintf(char** strp, const char* format, va_list ap) +{ + int ret; + int size; + va_list copy; + /* + * To be safe, make a va_copy. + * + * Note that Microsoft doesn't use va_copy in its sample code: + * https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/vsprintf-vsprintf-l-vswprintf-vswprintf-l-vswprintf-l?view=vs-2019 + */ + XSUM_va_copy(copy, ap); + /* Calculate how many characters we need */ + size = _vscprintf(format, ap); + va_end(copy); + + if (size < 0) { + *strp = NULL; + return size; + } else { + *strp = (char*) malloc((size_t)size + 1); + if (*strp == NULL) { + return -1; + } + /* vsprintf into the new buffer */ + ret = vsprintf(*strp, format, ap); + if (ret < 0) { + free(*strp); + *strp = NULL; + } + return ret; + } +} + +/* + * fprintf wrapper that supports UTF-8. + * + * fprintf doesn't properly handle Unicode on Windows. + * + * Additionally, it is codepage sensitive on console and may crash the program. + * + * Instead, we use vsnprintf, and either print with fwrite or convert to UTF-16 + * for console output and use the codepage-independent WriteConsoleW. + * + * Credit to t-mat: https://github.com/t-mat/xxHash/commit/5691423 + */ +XSUM_ATTRIBUTE((__format__(__printf__, 2, 0))) +XSUM_API int XSUM_vfprintf(FILE *stream, const char *format, va_list ap) +{ + int result; + char* u8_str = NULL; + + /* + * Generate the UTF-8 output string with vasprintf. + */ + result = XSUM_vasprintf(&u8_str, format, ap); + + if (result >= 0) { + const size_t nchar = (size_t)result + 1; + + /* + * Check if we are outputting to a console. Don't use XSUM_isConsole + * directly -- we don't need to call _get_osfhandle twice. + */ + int fileNb = _fileno(stream); + intptr_t handle_raw = _get_osfhandle(fileNb); + HANDLE handle = (HANDLE)handle_raw; + DWORD dwTemp; + + if (handle_raw < 0) { + result = -1; + } else if (_isatty(fileNb) && GetConsoleMode(handle, &dwTemp)) { + /* + * Convert to UTF-16 and output with WriteConsoleW. + * + * This is codepage independent and works on Windows XP's default + * msvcrt.dll. + */ + int len; + wchar_t* const u16_buf = XSUM_widenString(u8_str, &len); + if (u16_buf == NULL) { + result = -1; + } else { + if (WriteConsoleW(handle, u16_buf, (DWORD)len - 1, &dwTemp, NULL)) { + result = (int)dwTemp; + } else { + result = -1; + } + free(u16_buf); + } + } else { + /* fwrite the UTF-8 string if we are printing to a file */ + result = (int)fwrite(u8_str, 1, nchar - 1, stream); + if (result == 0) { + result = -1; + } + } + free(u8_str); + } + return result; +} + +#ifndef XSUM_NO_MAIN +/***************************************************************************** + * Command Line argument parsing + *****************************************************************************/ + +/* Converts a UTF-16 argv to UTF-8. */ +static char** XSUM_convertArgv(int argc, wchar_t* utf16_argv[]) +{ + char** const utf8_argv = (char**)malloc((size_t)(argc + 1) * sizeof(char*)); + if (utf8_argv != NULL) { + int i; + for (i = 0; i < argc; i++) { + utf8_argv[i] = XSUM_narrowString(utf16_argv[i], NULL); + if (utf8_argv[i] == NULL) { + /* Out of memory, whoops. */ + while (i-- > 0) { + free(utf8_argv[i]); + } + free(utf8_argv); + return NULL; + } + } + utf8_argv[argc] = NULL; + } + return utf8_argv; +} +/* Frees arguments returned by XSUM_convertArgv */ +static void XSUM_freeArgv(int argc, char** argv) +{ + int i; + if (argv == NULL) { + return; + } + for (i = 0; i < argc; i++) { + free(argv[i]); + } + free(argv); +} + +static int XSUM_wmain(int argc, wchar_t* utf16_argv[]) +{ + /* Convert the UTF-16 arguments to UTF-8. */ + char** utf8_argv = XSUM_convertArgv(argc, utf16_argv); + + if (utf8_argv == NULL) { + /* An unfortunate but incredibly unlikely error. */ + fprintf(stderr, "xxhsum: error converting command line arguments!\n"); + abort(); + } else { + int ret; + + /* + * MinGW's terminal uses full block buffering for stderr. + * + * This is nonstandard behavior and causes text to not display until + * the buffer fills. + * + * `setvbuf()` can easily correct this to make text display instantly. + */ + setvbuf(stderr, NULL, _IONBF, 0); + + /* Call our real main function */ + ret = XSUM_main(argc, utf8_argv); + + /* Cleanup */ + XSUM_freeArgv(argc, utf8_argv); + return ret; + } +} + +#if XSUM_WIN32_USE_WMAIN + +/* + * The preferred method of obtaining the real UTF-16 arguments. Always works + * on MSVC, sometimes works on MinGW-w64 depending on the compiler flags. + */ +#ifdef __cplusplus +extern "C" +#endif +int __cdecl wmain(int argc, wchar_t* utf16_argv[]) +{ + return XSUM_wmain(argc, utf16_argv); +} +#else /* !XSUM_WIN32_USE_WMAIN */ + +/* + * Wrap `XSUM_wmain()` using `main()` and `__wgetmainargs()` on MinGW without + * Unicode support. + * + * `__wgetmainargs()` is used in the CRT startup to retrieve the arguments for + * `wmain()`, so we use it on MinGW to emulate `wmain()`. + * + * It is an internal function and not declared in any public headers, so we + * have to declare it manually. + * + * An alternative that doesn't mess with internal APIs is `GetCommandLineW()` + * with `CommandLineToArgvW()`, but the former doesn't expand wildcards and the + * latter requires linking to Shell32.dll and its numerous dependencies. + * + * This method keeps our dependencies to kernel32.dll and the CRT. + * + * https://docs.microsoft.com/en-us/cpp/c-runtime-library/getmainargs-wgetmainargs?view=vs-2019 + */ +typedef struct { + int newmode; +} _startupinfo; + +#ifdef __cplusplus +extern "C" +#endif +int __cdecl __wgetmainargs( + int* Argc, + wchar_t*** Argv, + wchar_t*** Env, + int DoWildCard, + _startupinfo* StartInfo +); + +int main(int ansi_argc, char* ansi_argv[]) +{ + int utf16_argc; + wchar_t** utf16_argv; + wchar_t** utf16_envp; /* Unused but required */ + _startupinfo startinfo = {0}; /* 0 == don't change new mode */ + + /* Get wmain's UTF-16 arguments. Make sure we expand wildcards. */ + if (__wgetmainargs(&utf16_argc, &utf16_argv, &utf16_envp, 1, &startinfo) < 0) + /* In the very unlikely case of an error, use the ANSI arguments. */ + return XSUM_main(ansi_argc, ansi_argv); + + /* Call XSUM_wmain with our UTF-16 arguments */ + return XSUM_wmain(utf16_argc, utf16_argv); +} + +#endif /* !XSUM_WIN32_USE_WMAIN */ +#endif /* !XSUM_NO_MAIN */ +#endif /* XSUM_WIN32_USE_WCHAR */ + + +/* + * Determines whether the file at filename is a directory. + */ +XSUM_API int XSUM_isDirectory(const char* filename) +{ + XSUM_stat_t statbuf; + int r = XSUM_stat(filename, &statbuf); +#ifdef _MSC_VER + if (!r && (statbuf.st_mode & _S_IFDIR)) return 1; +#else + if (!r && S_ISDIR(statbuf.st_mode)) return 1; +#endif + return 0; +} + +/* + * Returns the filesize of the file at filename. + */ +XSUM_API XSUM_U64 XSUM_getFileSize(const char* filename) +{ + XSUM_stat_t statbuf; + int r = XSUM_stat(filename, &statbuf); + if (r || !S_ISREG(statbuf.st_mode)) return 0; /* No good... */ + return (XSUM_U64)statbuf.st_size; +} |