Path: blob/main/crypto/openssl/apps/lib/win32_init.c
34878 views
/*1* Copyright 2016-2020 The OpenSSL Project Authors. All Rights Reserved.2*3* Licensed under the Apache License 2.0 (the "License"). You may not use4* this file except in compliance with the License. You can obtain a copy5* in the file LICENSE in the source distribution or at6* https://www.openssl.org/source/license.html7*/89#include <windows.h>10#include <stdlib.h>11#include <string.h>12#include <malloc.h>1314#if defined(CP_UTF8)1516static UINT saved_cp;17static int newargc;18static char **newargv;1920static void cleanup(void)21{22int i;2324SetConsoleOutputCP(saved_cp);2526for (i = 0; i < newargc; i++)27free(newargv[i]);2829free(newargv);30}3132/*33* Incrementally [re]allocate newargv and keep it NULL-terminated.34*/35static int validate_argv(int argc)36{37static int size = 0;3839if (argc >= size) {40char **ptr;4142while (argc >= size)43size += 64;4445ptr = realloc(newargv, size * sizeof(newargv[0]));46if (ptr == NULL)47return 0;4849(newargv = ptr)[argc] = NULL;50} else {51newargv[argc] = NULL;52}5354return 1;55}5657static int process_glob(WCHAR *wstr, int wlen)58{59int i, slash, udlen;60WCHAR saved_char;61WIN32_FIND_DATAW data;62HANDLE h;6364/*65* Note that we support wildcard characters only in filename part66* of the path, and not in directories. Windows users are used to67* this, that's why recursive glob processing is not implemented.68*/69/*70* Start by looking for last slash or backslash, ...71*/72for (slash = 0, i = 0; i < wlen; i++)73if (wstr[i] == L'/' || wstr[i] == L'\\')74slash = i + 1;75/*76* ... then look for asterisk or question mark in the file name.77*/78for (i = slash; i < wlen; i++)79if (wstr[i] == L'*' || wstr[i] == L'?')80break;8182if (i == wlen)83return 0; /* definitely not a glob */8485saved_char = wstr[wlen];86wstr[wlen] = L'\0';87h = FindFirstFileW(wstr, &data);88wstr[wlen] = saved_char;89if (h == INVALID_HANDLE_VALUE)90return 0; /* not a valid glob, just pass... */9192if (slash)93udlen = WideCharToMultiByte(CP_UTF8, 0, wstr, slash,94NULL, 0, NULL, NULL);95else96udlen = 0;9798do {99int uflen;100char *arg;101102/*103* skip over . and ..104*/105if (data.cFileName[0] == L'.') {106if ((data.cFileName[1] == L'\0') ||107(data.cFileName[1] == L'.' && data.cFileName[2] == L'\0'))108continue;109}110111if (!validate_argv(newargc + 1))112break;113114/*115* -1 below means "scan for trailing '\0' *and* count it",116* so that |uflen| covers even trailing '\0'.117*/118uflen = WideCharToMultiByte(CP_UTF8, 0, data.cFileName, -1,119NULL, 0, NULL, NULL);120121arg = malloc(udlen + uflen);122if (arg == NULL)123break;124125if (udlen)126WideCharToMultiByte(CP_UTF8, 0, wstr, slash,127arg, udlen, NULL, NULL);128129WideCharToMultiByte(CP_UTF8, 0, data.cFileName, -1,130arg + udlen, uflen, NULL, NULL);131132newargv[newargc++] = arg;133} while (FindNextFileW(h, &data));134135CloseHandle(h);136137return 1;138}139140void win32_utf8argv(int *argc, char **argv[])141{142const WCHAR *wcmdline;143WCHAR *warg, *wend, *p;144int wlen, ulen, valid = 1;145char *arg;146147if (GetEnvironmentVariableW(L"OPENSSL_WIN32_UTF8", NULL, 0) == 0)148return;149150newargc = 0;151newargv = NULL;152if (!validate_argv(newargc))153return;154155wcmdline = GetCommandLineW();156if (wcmdline == NULL) return;157158/*159* make a copy of the command line, since we might have to modify it...160*/161wlen = wcslen(wcmdline);162p = _alloca((wlen + 1) * sizeof(WCHAR));163wcscpy(p, wcmdline);164165while (*p != L'\0') {166int in_quote = 0;167168if (*p == L' ' || *p == L'\t') {169p++; /* skip over whitespace */170continue;171}172173/*174* Note: because we may need to fiddle with the number of backslashes,175* the argument string is copied into itself. This is safe because176* the number of characters will never expand.177*/178warg = wend = p;179while (*p != L'\0'180&& (in_quote || (*p != L' ' && *p != L'\t'))) {181switch (*p) {182case L'\\':183/*184* Microsoft documentation on how backslashes are treated185* is:186*187* + Backslashes are interpreted literally, unless they188* immediately precede a double quotation mark.189* + If an even number of backslashes is followed by a double190* quotation mark, one backslash is placed in the argv array191* for every pair of backslashes, and the double quotation192* mark is interpreted as a string delimiter.193* + If an odd number of backslashes is followed by a double194* quotation mark, one backslash is placed in the argv array195* for every pair of backslashes, and the double quotation196* mark is "escaped" by the remaining backslash, causing a197* literal double quotation mark (") to be placed in argv.198*199* Ref: https://msdn.microsoft.com/en-us/library/17w5ykft.aspx200*201* Though referred page doesn't mention it, multiple qouble202* quotes are also special. Pair of double quotes in quoted203* string is counted as single double quote.204*/205{206const WCHAR *q = p;207int i;208209while (*p == L'\\')210p++;211212if (*p == L'"') {213int i;214215for (i = (p - q) / 2; i > 0; i--)216*wend++ = L'\\';217218/*219* if odd amount of backslashes before the quote,220* said quote is part of the argument, not a delimiter221*/222if ((p - q) % 2 == 1)223*wend++ = *p++;224} else {225for (i = p - q; i > 0; i--)226*wend++ = L'\\';227}228}229break;230case L'"':231/*232* Without the preceding backslash (or when preceded with an233* even number of backslashes), the double quote is a simple234* string delimiter and just slightly change the parsing state235*/236if (in_quote && p[1] == L'"')237*wend++ = *p++;238else239in_quote = !in_quote;240p++;241break;242default:243/*244* Any other non-delimiter character is just taken verbatim245*/246*wend++ = *p++;247}248}249250wlen = wend - warg;251252if (wlen == 0 || !process_glob(warg, wlen)) {253if (!validate_argv(newargc + 1)) {254valid = 0;255break;256}257258ulen = 0;259if (wlen > 0) {260ulen = WideCharToMultiByte(CP_UTF8, 0, warg, wlen,261NULL, 0, NULL, NULL);262if (ulen <= 0)263continue;264}265266arg = malloc(ulen + 1);267if (arg == NULL) {268valid = 0;269break;270}271272if (wlen > 0)273WideCharToMultiByte(CP_UTF8, 0, warg, wlen,274arg, ulen, NULL, NULL);275arg[ulen] = '\0';276277newargv[newargc++] = arg;278}279}280281if (valid) {282saved_cp = GetConsoleOutputCP();283SetConsoleOutputCP(CP_UTF8);284285*argc = newargc;286*argv = newargv;287288atexit(cleanup);289} else if (newargv != NULL) {290int i;291292for (i = 0; i < newargc; i++)293free(newargv[i]);294295free(newargv);296297newargc = 0;298newargv = NULL;299}300301return;302}303#else304void win32_utf8argv(int *argc, char **argv[])305{ return; }306#endif307308309