mirror of
https://github.com/curl/curl.git
synced 2026-07-23 00:47:18 +03:00
idn: avoid allocations and wcslen on Windows
Eliminate a heap buffer in both `win32_idn_to_ascii()` and `win32_ascii_to_idn()`, by replacing it with stack buffer. The maximum size is fixed in these cases, and small enough to fit there. Also reuse length returned by the UTF-8 to wchar conversion, allowing to drop `wcslen()` call in both functions, and allowing to call the wchar to UTF-8 conversion API `WideCharToMultiByte()` with the known length, saving length calculations within that API too. Ref: https://github.com/curl/curl/pull/19748#issuecomment-3592015200 Closes #19798
This commit is contained in:
parent
c3b030b860
commit
6694a42aa0
1 changed files with 24 additions and 48 deletions
72
lib/idn.c
72
lib/idn.c
|
|
@ -162,42 +162,18 @@ WINBASEAPI int WINAPI IdnToUnicode(DWORD dwFlags,
|
|||
|
||||
#define IDN_MAX_LENGTH 255
|
||||
|
||||
static wchar_t *idn_curlx_convert_UTF8_to_wchar(const char *str_utf8)
|
||||
{
|
||||
wchar_t *str_w = NULL;
|
||||
|
||||
if(str_utf8) {
|
||||
int str_w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
|
||||
str_utf8, -1, NULL, 0);
|
||||
if(str_w_len > 0) {
|
||||
str_w = curlx_malloc(str_w_len * sizeof(wchar_t));
|
||||
if(str_w) {
|
||||
if(MultiByteToWideChar(CP_UTF8, 0, str_utf8, -1, str_w,
|
||||
str_w_len) == 0) {
|
||||
curlx_free(str_w);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return str_w;
|
||||
}
|
||||
|
||||
static char *idn_curlx_convert_wchar_to_UTF8(const wchar_t *str_w)
|
||||
static char *idn_curlx_convert_wchar_to_UTF8(const wchar_t *str_w, int chars)
|
||||
{
|
||||
char *str_utf8 = NULL;
|
||||
|
||||
if(str_w) {
|
||||
int bytes = WideCharToMultiByte(CP_UTF8, 0, str_w, -1,
|
||||
NULL, 0, NULL, NULL);
|
||||
if(bytes > 0) {
|
||||
str_utf8 = curlx_malloc(bytes);
|
||||
if(str_utf8) {
|
||||
if(WideCharToMultiByte(CP_UTF8, 0, str_w, -1, str_utf8, bytes,
|
||||
NULL, NULL) == 0) {
|
||||
curlx_free(str_utf8);
|
||||
return NULL;
|
||||
}
|
||||
int bytes = WideCharToMultiByte(CP_UTF8, 0, str_w, chars, NULL, 0,
|
||||
NULL, NULL);
|
||||
if(bytes > 0) {
|
||||
str_utf8 = curlx_malloc(bytes);
|
||||
if(str_utf8) {
|
||||
if(WideCharToMultiByte(CP_UTF8, 0, str_w, chars, str_utf8, bytes,
|
||||
NULL, NULL) == 0) {
|
||||
curlx_free(str_utf8);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -206,15 +182,15 @@ static char *idn_curlx_convert_wchar_to_UTF8(const wchar_t *str_w)
|
|||
|
||||
static CURLcode win32_idn_to_ascii(const char *in, char **out)
|
||||
{
|
||||
wchar_t *in_w = idn_curlx_convert_UTF8_to_wchar(in);
|
||||
wchar_t in_w[IDN_MAX_LENGTH];
|
||||
int in_w_len;
|
||||
*out = NULL;
|
||||
if(in_w) {
|
||||
in_w_len = MultiByteToWideChar(CP_UTF8, 0, in, -1, in_w, IDN_MAX_LENGTH);
|
||||
if(in_w_len) {
|
||||
wchar_t punycode[IDN_MAX_LENGTH];
|
||||
int chars = IdnToAscii(0, in_w, (int)(wcslen(in_w) + 1), punycode,
|
||||
IDN_MAX_LENGTH);
|
||||
curlx_free(in_w);
|
||||
if(chars) {
|
||||
*out = idn_curlx_convert_wchar_to_UTF8(punycode);
|
||||
int chars = IdnToAscii(0, in_w, in_w_len, punycode, IDN_MAX_LENGTH);
|
||||
if(chars > 0) {
|
||||
*out = idn_curlx_convert_wchar_to_UTF8(punycode, chars);
|
||||
if(!*out)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
|
@ -229,15 +205,15 @@ static CURLcode win32_idn_to_ascii(const char *in, char **out)
|
|||
|
||||
static CURLcode win32_ascii_to_idn(const char *in, char **out)
|
||||
{
|
||||
wchar_t *in_w = idn_curlx_convert_UTF8_to_wchar(in);
|
||||
wchar_t in_w[IDN_MAX_LENGTH];
|
||||
int in_w_len;
|
||||
*out = NULL;
|
||||
if(in_w) {
|
||||
in_w_len = MultiByteToWideChar(CP_UTF8, 0, in, -1, in_w, IDN_MAX_LENGTH);
|
||||
if(in_w_len) {
|
||||
WCHAR idn[IDN_MAX_LENGTH]; /* stores a UTF-16 string */
|
||||
int chars = IdnToUnicode(0, in_w, (int)(wcslen(in_w) + 1), idn,
|
||||
IDN_MAX_LENGTH);
|
||||
curlx_free(in_w);
|
||||
if(chars) { /* 'chars' is "the number of characters retrieved" */
|
||||
*out = idn_curlx_convert_wchar_to_UTF8(idn);
|
||||
int chars = IdnToUnicode(0, in_w, in_w_len, idn, IDN_MAX_LENGTH);
|
||||
if(chars > 0) { /* 'chars' is "the number of characters retrieved" */
|
||||
*out = idn_curlx_convert_wchar_to_UTF8(idn, chars);
|
||||
if(!*out)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue