summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/curlx
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libcurl/src/curlx')
-rw-r--r--libs/libcurl/src/curlx/base64.c285
-rw-r--r--libs/libcurl/src/curlx/base64.h36
-rw-r--r--libs/libcurl/src/curlx/curlx.h74
-rw-r--r--libs/libcurl/src/curlx/dynbuf.c298
-rw-r--r--libs/libcurl/src/curlx/dynbuf.h85
-rw-r--r--libs/libcurl/src/curlx/inet_pton.c232
-rw-r--r--libs/libcurl/src/curlx/inet_pton.h48
-rw-r--r--libs/libcurl/src/curlx/multibyte.c360
-rw-r--r--libs/libcurl/src/curlx/multibyte.h87
-rw-r--r--libs/libcurl/src/curlx/nonblock.c93
-rw-r--r--libs/libcurl/src/curlx/nonblock.h32
-rw-r--r--libs/libcurl/src/curlx/strparse.c303
-rw-r--r--libs/libcurl/src/curlx/strparse.h112
-rw-r--r--libs/libcurl/src/curlx/timediff.c88
-rw-r--r--libs/libcurl/src/curlx/timediff.h52
-rw-r--r--libs/libcurl/src/curlx/timeval.c259
-rw-r--r--libs/libcurl/src/curlx/timeval.h67
-rw-r--r--libs/libcurl/src/curlx/version_win32.c243
-rw-r--r--libs/libcurl/src/curlx/version_win32.h56
-rw-r--r--libs/libcurl/src/curlx/warnless.c315
-rw-r--r--libs/libcurl/src/curlx/warnless.h80
-rw-r--r--libs/libcurl/src/curlx/winapi.c135
-rw-r--r--libs/libcurl/src/curlx/winapi.h33
23 files changed, 3373 insertions, 0 deletions
diff --git a/libs/libcurl/src/curlx/base64.c b/libs/libcurl/src/curlx/base64.c
new file mode 100644
index 0000000000..d988cc8e08
--- /dev/null
+++ b/libs/libcurl/src/curlx/base64.c
@@ -0,0 +1,285 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/* Base64 encoding/decoding */
+
+#include "../curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP_AUTH) || defined(USE_SSH) || \
+ !defined(CURL_DISABLE_LDAP) || \
+ !defined(CURL_DISABLE_SMTP) || \
+ !defined(CURL_DISABLE_POP3) || \
+ !defined(CURL_DISABLE_IMAP) || \
+ !defined(CURL_DISABLE_DIGEST_AUTH) || \
+ !defined(CURL_DISABLE_DOH) || defined(USE_SSL) || !defined(BUILDING_LIBCURL)
+#include <curl/curl.h>
+#include "warnless.h"
+#include "base64.h"
+
+/* The last 2 #include files should be in this order */
+#ifdef BUILDING_LIBCURL
+#include "../curl_memory.h"
+#endif
+#include "../memdebug.h"
+
+/* ---- Base64 Encoding/Decoding Table --- */
+const char Curl_base64encdec[]=
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/* The Base 64 encoding with a URL and filename safe alphabet, RFC 4648
+ section 5 */
+static const char base64url[]=
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+static const unsigned char decodetable[] =
+{ 62, 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255,
+ 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, 255, 26, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51 };
+/*
+ * curlx_base64_decode()
+ *
+ * Given a base64 null-terminated string at src, decode it and return a
+ * pointer in *outptr to a newly allocated memory area holding decoded data.
+ * Size of decoded data is returned in variable pointed by outlen.
+ *
+ * Returns CURLE_OK on success, otherwise specific error code. Function
+ * output shall not be considered valid unless CURLE_OK is returned.
+ *
+ * When decoded data length is 0, returns NULL in *outptr.
+ *
+ * @unittest: 1302
+ */
+CURLcode curlx_base64_decode(const char *src,
+ unsigned char **outptr, size_t *outlen)
+{
+ size_t srclen = 0;
+ size_t padding = 0;
+ size_t i;
+ size_t numQuantums;
+ size_t fullQuantums;
+ size_t rawlen = 0;
+ unsigned char *pos;
+ unsigned char *newstr;
+ unsigned char lookup[256];
+
+ *outptr = NULL;
+ *outlen = 0;
+ srclen = strlen(src);
+
+ /* Check the length of the input string is valid */
+ if(!srclen || srclen % 4)
+ return CURLE_BAD_CONTENT_ENCODING;
+
+ /* srclen is at least 4 here */
+ while(src[srclen - 1 - padding] == '=') {
+ /* count padding characters */
+ padding++;
+ /* A maximum of two = padding characters is allowed */
+ if(padding > 2)
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
+ /* Calculate the number of quantums */
+ numQuantums = srclen / 4;
+ fullQuantums = numQuantums - (padding ? 1 : 0);
+
+ /* Calculate the size of the decoded string */
+ rawlen = (numQuantums * 3) - padding;
+
+ /* Allocate our buffer including room for a null-terminator */
+ newstr = malloc(rawlen + 1);
+ if(!newstr)
+ return CURLE_OUT_OF_MEMORY;
+
+ pos = newstr;
+
+ memset(lookup, 0xff, sizeof(lookup));
+ memcpy(&lookup['+'], decodetable, sizeof(decodetable));
+
+ /* Decode the complete quantums first */
+ for(i = 0; i < fullQuantums; i++) {
+ unsigned char val;
+ unsigned int x = 0;
+ int j;
+
+ for(j = 0; j < 4; j++) {
+ val = lookup[(unsigned char)*src++];
+ if(val == 0xff) /* bad symbol */
+ goto bad;
+ x = (x << 6) | val;
+ }
+ pos[2] = x & 0xff;
+ pos[1] = (x >> 8) & 0xff;
+ pos[0] = (x >> 16) & 0xff;
+ pos += 3;
+ }
+ if(padding) {
+ /* this means either 8 or 16 bits output */
+ unsigned char val;
+ unsigned int x = 0;
+ int j;
+ size_t padc = 0;
+ for(j = 0; j < 4; j++) {
+ if(*src == '=') {
+ x <<= 6;
+ src++;
+ if(++padc > padding)
+ /* this is a badly placed '=' symbol! */
+ goto bad;
+ }
+ else {
+ val = lookup[(unsigned char)*src++];
+ if(val == 0xff) /* bad symbol */
+ goto bad;
+ x = (x << 6) | val;
+ }
+ }
+ if(padding == 1)
+ pos[1] = (x >> 8) & 0xff;
+ pos[0] = (x >> 16) & 0xff;
+ pos += 3 - padding;
+ }
+
+ /* Zero terminate */
+ *pos = '\0';
+
+ /* Return the decoded data */
+ *outptr = newstr;
+ *outlen = rawlen;
+
+ return CURLE_OK;
+bad:
+ free(newstr);
+ return CURLE_BAD_CONTENT_ENCODING;
+}
+
+static CURLcode base64_encode(const char *table64,
+ unsigned char padbyte,
+ const char *inputbuff, size_t insize,
+ char **outptr, size_t *outlen)
+{
+ char *output;
+ char *base64data;
+ const unsigned char *in = (const unsigned char *)inputbuff;
+
+ *outptr = NULL;
+ *outlen = 0;
+
+ if(!insize)
+ insize = strlen(inputbuff);
+
+#if SIZEOF_SIZE_T == 4
+ if(insize > UINT_MAX/4)
+ return CURLE_OUT_OF_MEMORY;
+#endif
+
+ base64data = output = malloc((insize + 2) / 3 * 4 + 1);
+ if(!output)
+ return CURLE_OUT_OF_MEMORY;
+
+ while(insize >= 3) {
+ *output++ = table64[ in[0] >> 2 ];
+ *output++ = table64[ ((in[0] & 0x03) << 4) | (in[1] >> 4) ];
+ *output++ = table64[ ((in[1] & 0x0F) << 2) | ((in[2] & 0xC0) >> 6) ];
+ *output++ = table64[ in[2] & 0x3F ];
+ insize -= 3;
+ in += 3;
+ }
+ if(insize) {
+ /* this is only one or two bytes now */
+ *output++ = table64[ in[0] >> 2 ];
+ if(insize == 1) {
+ *output++ = table64[ ((in[0] & 0x03) << 4) ];
+ if(padbyte) {
+ *output++ = padbyte;
+ *output++ = padbyte;
+ }
+ }
+ else {
+ /* insize == 2 */
+ *output++ = table64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xF0) >> 4) ];
+ *output++ = table64[ ((in[1] & 0x0F) << 2) ];
+ if(padbyte)
+ *output++ = padbyte;
+ }
+ }
+
+ /* Zero terminate */
+ *output = '\0';
+
+ /* Return the pointer to the new data (allocated memory) */
+ *outptr = base64data;
+
+ /* Return the length of the new data */
+ *outlen = (size_t)(output - base64data);
+
+ return CURLE_OK;
+}
+
+/*
+ * curlx_base64_encode()
+ *
+ * Given a pointer to an input buffer and an input size, encode it and
+ * return a pointer in *outptr to a newly allocated memory area holding
+ * encoded data. Size of encoded data is returned in variable pointed by
+ * outlen.
+ *
+ * Input length of 0 indicates input buffer holds a null-terminated string.
+ *
+ * Returns CURLE_OK on success, otherwise specific error code. Function
+ * output shall not be considered valid unless CURLE_OK is returned.
+ *
+ * @unittest: 1302
+ */
+CURLcode curlx_base64_encode(const char *inputbuff, size_t insize,
+ char **outptr, size_t *outlen)
+{
+ return base64_encode(Curl_base64encdec, '=',
+ inputbuff, insize, outptr, outlen);
+}
+
+/*
+ * curlx_base64url_encode()
+ *
+ * Given a pointer to an input buffer and an input size, encode it and
+ * return a pointer in *outptr to a newly allocated memory area holding
+ * encoded data. Size of encoded data is returned in variable pointed by
+ * outlen.
+ *
+ * Input length of 0 indicates input buffer holds a null-terminated string.
+ *
+ * Returns CURLE_OK on success, otherwise specific error code. Function
+ * output shall not be considered valid unless CURLE_OK is returned.
+ *
+ * @unittest: 1302
+ */
+CURLcode curlx_base64url_encode(const char *inputbuff, size_t insize,
+ char **outptr, size_t *outlen)
+{
+ return base64_encode(base64url, 0, inputbuff, insize, outptr, outlen);
+}
+
+#endif /* no users so disabled */
diff --git a/libs/libcurl/src/curlx/base64.h b/libs/libcurl/src/curlx/base64.h
new file mode 100644
index 0000000000..ab458cfe6f
--- /dev/null
+++ b/libs/libcurl/src/curlx/base64.h
@@ -0,0 +1,36 @@
+#ifndef HEADER_CURL_BASE64_H
+#define HEADER_CURL_BASE64_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+CURLcode curlx_base64_encode(const char *inputbuff, size_t insize,
+ char **outptr, size_t *outlen);
+CURLcode curlx_base64url_encode(const char *inputbuff, size_t insize,
+ char **outptr, size_t *outlen);
+CURLcode curlx_base64_decode(const char *src,
+ unsigned char **outptr, size_t *outlen);
+
+extern const char Curl_base64encdec[];
+
+#endif /* HEADER_CURL_BASE64_H */
diff --git a/libs/libcurl/src/curlx/curlx.h b/libs/libcurl/src/curlx/curlx.h
new file mode 100644
index 0000000000..bb1ad81b28
--- /dev/null
+++ b/libs/libcurl/src/curlx/curlx.h
@@ -0,0 +1,74 @@
+#ifndef HEADER_CURL_CURLX_H
+#define HEADER_CURL_CURLX_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/*
+ * Defines protos and includes all header files that provide the curlx_*
+ * functions. The curlx_* functions are not part of the libcurl API, but are
+ * stand-alone functions whose sources can be built and linked by apps if need
+ * be.
+ */
+
+#include "nonblock.h"
+/* "nonblock.h" provides curlx_nonblock() */
+
+#include "warnless.h"
+/* "warnless.h" provides functions:
+
+ curlx_ultous()
+ curlx_ultouc()
+ curlx_uztosi()
+*/
+
+#include "multibyte.h"
+/* "multibyte.h" provides these functions and macros:
+
+ curlx_convert_UTF8_to_wchar()
+ curlx_convert_wchar_to_UTF8()
+ curlx_convert_UTF8_to_tchar()
+ curlx_convert_tchar_to_UTF8()
+ curlx_unicodefree()
+*/
+
+#include "version_win32.h"
+/* provides curlx_verify_windows_version() */
+
+#include "strparse.h"
+/* The curlx_str_* parsing functions */
+
+#include "dynbuf.h"
+/* The curlx_dyn_* functions */
+
+#include "base64.h"
+#include "timeval.h"
+#include "timediff.h"
+
+#include "winapi.h"
+/* for curlx_winapi_strerror */
+
+#include "inet_pton.h"
+/* for curlx_inet_pton */
+
+#endif /* HEADER_CURL_CURLX_H */
diff --git a/libs/libcurl/src/curlx/dynbuf.c b/libs/libcurl/src/curlx/dynbuf.c
new file mode 100644
index 0000000000..fd25cc9f77
--- /dev/null
+++ b/libs/libcurl/src/curlx/dynbuf.c
@@ -0,0 +1,298 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "../curl_setup.h"
+#include "dynbuf.h"
+#include "../curl_printf.h"
+#ifdef BUILDING_LIBCURL
+#include "../curl_memory.h"
+#endif
+#include "../memdebug.h"
+
+#define MIN_FIRST_ALLOC 32
+
+#ifdef DEBUGBUILD
+#define DYNINIT 0xbee51da /* random pattern */
+#endif
+
+/*
+ * Init a dynbuf struct.
+ */
+void curlx_dyn_init(struct dynbuf *s, size_t toobig)
+{
+ DEBUGASSERT(s);
+ DEBUGASSERT(toobig);
+ DEBUGASSERT(toobig <= MAX_DYNBUF_SIZE); /* catch crazy mistakes */
+ s->bufr = NULL;
+ s->leng = 0;
+ s->allc = 0;
+ s->toobig = toobig;
+#ifdef DEBUGBUILD
+ s->init = DYNINIT;
+#endif
+}
+
+/*
+ * free the buffer and re-init the necessary fields. It does not touch the
+ * 'init' field and thus this buffer can be reused to add data to again.
+ */
+void curlx_dyn_free(struct dynbuf *s)
+{
+ DEBUGASSERT(s);
+ DEBUGASSERT(s->init == DYNINIT);
+ Curl_safefree(s->bufr);
+ s->leng = s->allc = 0;
+}
+
+/*
+ * Store/append an chunk of memory to the dynbuf.
+ */
+static CURLcode dyn_nappend(struct dynbuf *s,
+ const unsigned char *mem, size_t len)
+{
+ size_t indx = s->leng;
+ size_t a = s->allc;
+ size_t fit = len + indx + 1; /* new string + old string + zero byte */
+
+ /* try to detect if there is rubbish in the struct */
+ DEBUGASSERT(s->init == DYNINIT);
+ DEBUGASSERT(s->toobig);
+ DEBUGASSERT(indx < s->toobig);
+ DEBUGASSERT(!s->leng || s->bufr);
+ DEBUGASSERT(a <= s->toobig);
+ DEBUGASSERT(!len || mem);
+
+ if(fit > s->toobig) {
+ curlx_dyn_free(s);
+ return CURLE_TOO_LARGE;
+ }
+ else if(!a) {
+ DEBUGASSERT(!indx);
+ /* first invoke */
+ if(MIN_FIRST_ALLOC > s->toobig)
+ a = s->toobig;
+ else if(fit < MIN_FIRST_ALLOC)
+ a = MIN_FIRST_ALLOC;
+ else
+ a = fit;
+ }
+ else {
+ while(a < fit)
+ a *= 2;
+ if(a > s->toobig)
+ /* no point in allocating a larger buffer than this is allowed to use */
+ a = s->toobig;
+ }
+
+ if(a != s->allc) {
+ /* this logic is not using Curl_saferealloc() to make the tool not have to
+ include that as well when it uses this code */
+ void *p = realloc(s->bufr, a);
+ if(!p) {
+ curlx_dyn_free(s);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ s->bufr = p;
+ s->allc = a;
+ }
+
+ if(len)
+ memcpy(&s->bufr[indx], mem, len);
+ s->leng = indx + len;
+ s->bufr[s->leng] = 0;
+ return CURLE_OK;
+}
+
+/*
+ * Clears the string, keeps the allocation. This can also be called on a
+ * buffer that already was freed.
+ */
+void curlx_dyn_reset(struct dynbuf *s)
+{
+ DEBUGASSERT(s);
+ DEBUGASSERT(s->init == DYNINIT);
+ DEBUGASSERT(!s->leng || s->bufr);
+ if(s->leng)
+ s->bufr[0] = 0;
+ s->leng = 0;
+}
+
+/*
+ * Specify the size of the tail to keep (number of bytes from the end of the
+ * buffer). The rest will be dropped.
+ */
+CURLcode curlx_dyn_tail(struct dynbuf *s, size_t trail)
+{
+ DEBUGASSERT(s);
+ DEBUGASSERT(s->init == DYNINIT);
+ DEBUGASSERT(!s->leng || s->bufr);
+ if(trail > s->leng)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ else if(trail == s->leng)
+ return CURLE_OK;
+ else if(!trail) {
+ curlx_dyn_reset(s);
+ }
+ else {
+ memmove(&s->bufr[0], &s->bufr[s->leng - trail], trail);
+ s->leng = trail;
+ s->bufr[s->leng] = 0;
+ }
+ return CURLE_OK;
+
+}
+
+/*
+ * Appends a buffer with length.
+ */
+CURLcode curlx_dyn_addn(struct dynbuf *s, const void *mem, size_t len)
+{
+ DEBUGASSERT(s);
+ DEBUGASSERT(s->init == DYNINIT);
+ DEBUGASSERT(!s->leng || s->bufr);
+ return dyn_nappend(s, mem, len);
+}
+
+/*
+ * Append a null-terminated string at the end.
+ */
+CURLcode curlx_dyn_add(struct dynbuf *s, const char *str)
+{
+ size_t n;
+ DEBUGASSERT(str);
+ DEBUGASSERT(s);
+ DEBUGASSERT(s->init == DYNINIT);
+ DEBUGASSERT(!s->leng || s->bufr);
+ n = strlen(str);
+ return dyn_nappend(s, (const unsigned char *)str, n);
+}
+
+/*
+ * Append a string vprintf()-style
+ */
+CURLcode curlx_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
+{
+#ifdef BUILDING_LIBCURL
+ int rc;
+ DEBUGASSERT(s);
+ DEBUGASSERT(s->init == DYNINIT);
+ DEBUGASSERT(!s->leng || s->bufr);
+ DEBUGASSERT(fmt);
+ rc = curlx_dyn_vprintf(s, fmt, ap);
+
+ if(!rc)
+ return CURLE_OK;
+ else if(rc == MERR_TOO_LARGE)
+ return CURLE_TOO_LARGE;
+ return CURLE_OUT_OF_MEMORY;
+#else
+ char *str;
+ str = curl_mvaprintf(fmt, ap); /* this allocs a new string to append */
+
+ if(str) {
+ CURLcode result = dyn_nappend(s, (const unsigned char *)str, strlen(str));
+ free(str);
+ return result;
+ }
+ /* If we failed, we cleanup the whole buffer and return error */
+ curlx_dyn_free(s);
+ return CURLE_OUT_OF_MEMORY;
+#endif
+}
+
+/*
+ * Append a string printf()-style
+ */
+CURLcode curlx_dyn_addf(struct dynbuf *s, const char *fmt, ...)
+{
+ CURLcode result;
+ va_list ap;
+ DEBUGASSERT(s);
+ DEBUGASSERT(s->init == DYNINIT);
+ DEBUGASSERT(!s->leng || s->bufr);
+ va_start(ap, fmt);
+ result = curlx_dyn_vaddf(s, fmt, ap);
+ va_end(ap);
+ return result;
+}
+
+/*
+ * Returns a pointer to the buffer.
+ */
+char *curlx_dyn_ptr(const struct dynbuf *s)
+{
+ DEBUGASSERT(s);
+ DEBUGASSERT(s->init == DYNINIT);
+ DEBUGASSERT(!s->leng || s->bufr);
+ return s->bufr;
+}
+
+char *curlx_dyn_take(struct dynbuf *s, size_t *plen)
+{
+ char *ptr = s->bufr;
+ DEBUGASSERT(s);
+ DEBUGASSERT(s->init == DYNINIT);
+ *plen = s->leng;
+ s->bufr = NULL;
+ s->leng = 0;
+ s->allc = 0;
+ return ptr;
+}
+
+/*
+ * Returns an unsigned pointer to the buffer.
+ */
+unsigned char *curlx_dyn_uptr(const struct dynbuf *s)
+{
+ DEBUGASSERT(s);
+ DEBUGASSERT(s->init == DYNINIT);
+ DEBUGASSERT(!s->leng || s->bufr);
+ return (unsigned char *)s->bufr;
+}
+
+/*
+ * Returns the length of the buffer.
+ */
+size_t curlx_dyn_len(const struct dynbuf *s)
+{
+ DEBUGASSERT(s);
+ DEBUGASSERT(s->init == DYNINIT);
+ DEBUGASSERT(!s->leng || s->bufr);
+ return s->leng;
+}
+
+/*
+ * Set a new (smaller) length.
+ */
+CURLcode curlx_dyn_setlen(struct dynbuf *s, size_t set)
+{
+ DEBUGASSERT(s);
+ DEBUGASSERT(s->init == DYNINIT);
+ DEBUGASSERT(!s->leng || s->bufr);
+ if(set > s->leng)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ s->leng = set;
+ s->bufr[s->leng] = 0;
+ return CURLE_OK;
+}
diff --git a/libs/libcurl/src/curlx/dynbuf.h b/libs/libcurl/src/curlx/dynbuf.h
new file mode 100644
index 0000000000..bd19caa343
--- /dev/null
+++ b/libs/libcurl/src/curlx/dynbuf.h
@@ -0,0 +1,85 @@
+#ifndef HEADER_CURL_DYNBUF_H
+#define HEADER_CURL_DYNBUF_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include <curl/curl.h>
+
+struct dynbuf {
+ char *bufr; /* point to a null-terminated allocated buffer */
+ size_t leng; /* number of bytes *EXCLUDING* the null-terminator */
+ size_t allc; /* size of the current allocation */
+ size_t toobig; /* size limit for the buffer */
+#ifdef DEBUGBUILD
+ int init; /* detect API usage mistakes */
+#endif
+};
+
+void curlx_dyn_init(struct dynbuf *s, size_t toobig);
+void curlx_dyn_free(struct dynbuf *s);
+CURLcode curlx_dyn_addn(struct dynbuf *s, const void *mem, size_t len)
+ WARN_UNUSED_RESULT;
+CURLcode curlx_dyn_add(struct dynbuf *s, const char *str)
+ WARN_UNUSED_RESULT;
+CURLcode curlx_dyn_addf(struct dynbuf *s, const char *fmt, ...)
+ WARN_UNUSED_RESULT CURL_PRINTF(2, 3);
+CURLcode curlx_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
+ WARN_UNUSED_RESULT CURL_PRINTF(2, 0);
+void curlx_dyn_reset(struct dynbuf *s);
+CURLcode curlx_dyn_tail(struct dynbuf *s, size_t trail);
+CURLcode curlx_dyn_setlen(struct dynbuf *s, size_t set);
+char *curlx_dyn_ptr(const struct dynbuf *s);
+unsigned char *curlx_dyn_uptr(const struct dynbuf *s);
+size_t curlx_dyn_len(const struct dynbuf *s);
+
+/* returns 0 on success, -1 on error */
+/* The implementation of this function exists in mprintf.c */
+int curlx_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save);
+
+/* Take the buffer out of the dynbuf. Caller has ownership and
+ * dynbuf resets to initial state. */
+char *curlx_dyn_take(struct dynbuf *s, size_t *plen);
+
+/* Dynamic buffer max sizes */
+#define MAX_DYNBUF_SIZE (SIZE_T_MAX/2)
+
+#define DYN_DOH_RESPONSE 3000
+#define DYN_DOH_CNAME 256
+#define DYN_PAUSE_BUFFER (64 * 1024 * 1024)
+#define DYN_HAXPROXY 2048
+#define DYN_HTTP_REQUEST (1024*1024)
+#define DYN_APRINTF 8000000
+#define DYN_RTSP_REQ_HEADER (64*1024)
+#define DYN_TRAILERS (64*1024)
+#define DYN_PROXY_CONNECT_HEADERS 16384
+#define DYN_QLOG_NAME 1024
+#define DYN_H1_TRAILER 4096
+#define DYN_PINGPPONG_CMD (64*1024)
+#define DYN_IMAP_CMD (64*1024)
+#define DYN_MQTT_RECV (64*1024)
+#define DYN_MQTT_SEND 0xFFFFFFF
+#define DYN_CRLFILE_SIZE (400*1024*1024) /* 400mb */
+#define DYN_CERTFILE_SIZE (100*1024) /* 100KiB */
+#define DYN_KEYFILE_SIZE (100*1024) /* 100KiB */
+#endif
diff --git a/libs/libcurl/src/curlx/inet_pton.c b/libs/libcurl/src/curlx/inet_pton.c
new file mode 100644
index 0000000000..0e32e129da
--- /dev/null
+++ b/libs/libcurl/src/curlx/inet_pton.c
@@ -0,0 +1,232 @@
+/* This is from the BIND 4.9.4 release, modified to compile by itself */
+
+/* Copyright (c) Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ *
+ * SPDX-License-Identifier: ISC
+ */
+
+#include "../curl_setup.h"
+#include "../curl_ctype.h"
+#include "strparse.h"
+
+#ifndef HAVE_INET_PTON
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#include "inet_pton.h"
+
+#define IN6ADDRSZ 16
+#define INADDRSZ 4
+#define INT16SZ 2
+
+/*
+ * If USE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
+ * sure we have _some_ value for AF_INET6 without polluting our fake value
+ * everywhere.
+ */
+#if !defined(USE_IPV6) && !defined(AF_INET6)
+#define AF_INET6 (AF_INET + 1)
+#endif
+
+/*
+ * WARNING: Do not even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static int inet_pton4(const char *src, unsigned char *dst);
+static int inet_pton6(const char *src, unsigned char *dst);
+
+/* int
+ * inet_pton(af, src, dst)
+ * convert from presentation format (which usually means ASCII printable)
+ * to network format (which is usually some kind of binary format).
+ * return:
+ * 1 if the address was valid for the specified address family
+ * 0 if the address was not valid (`dst' is untouched in this case)
+ * -1 if some other error occurred (`dst' is untouched in this case, too)
+ * notice:
+ * On Windows we store the error in the thread errno, not
+ * in the Winsock error code. This is to avoid losing the
+ * actual last Winsock error. When this function returns
+ * -1, check errno not SOCKERRNO.
+ * author:
+ * Paul Vixie, 1996.
+ */
+int
+curlx_inet_pton(int af, const char *src, void *dst)
+{
+ switch(af) {
+ case AF_INET:
+ return inet_pton4(src, (unsigned char *)dst);
+ case AF_INET6:
+ return inet_pton6(src, (unsigned char *)dst);
+ default:
+ CURL_SETERRNO(SOCKEAFNOSUPPORT);
+ return -1;
+ }
+ /* NOTREACHED */
+}
+
+/* int
+ * inet_pton4(src, dst)
+ * like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ * 1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ * does not touch `dst' unless it is returning 1.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton4(const char *src, unsigned char *dst)
+{
+ int saw_digit, octets, ch;
+ unsigned char tmp[INADDRSZ], *tp;
+
+ saw_digit = 0;
+ octets = 0;
+ tp = tmp;
+ *tp = 0;
+ while((ch = *src++) != '\0') {
+ if(ISDIGIT(ch)) {
+ unsigned int val = (*tp * 10) + (ch - '0');
+
+ if(saw_digit && *tp == 0)
+ return 0;
+ if(val > 255)
+ return 0;
+ *tp = (unsigned char)val;
+ if(!saw_digit) {
+ if(++octets > 4)
+ return 0;
+ saw_digit = 1;
+ }
+ }
+ else if(ch == '.' && saw_digit) {
+ if(octets == 4)
+ return 0;
+ *++tp = 0;
+ saw_digit = 0;
+ }
+ else
+ return 0;
+ }
+ if(octets < 4)
+ return 0;
+ memcpy(dst, tmp, INADDRSZ);
+ return 1;
+}
+
+/* int
+ * inet_pton6(src, dst)
+ * convert presentation level address to network order binary form.
+ * return:
+ * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ * (1) does not touch `dst' unless it is returning 1.
+ * (2) :: in a full address is silently ignored.
+ * credit:
+ * inspired by Mark Andrews.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton6(const char *src, unsigned char *dst)
+{
+ unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *curtok;
+ int ch, saw_xdigit;
+ size_t val;
+
+ memset((tp = tmp), 0, IN6ADDRSZ);
+ endp = tp + IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if(*src == ':')
+ if(*++src != ':')
+ return 0;
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+ while((ch = *src++) != '\0') {
+ if(ISXDIGIT(ch)) {
+ val <<= 4;
+ val |= Curl_hexval(ch);
+ if(++saw_xdigit > 4)
+ return 0;
+ continue;
+ }
+ if(ch == ':') {
+ curtok = src;
+ if(!saw_xdigit) {
+ if(colonp)
+ return 0;
+ colonp = tp;
+ continue;
+ }
+ if(tp + INT16SZ > endp)
+ return 0;
+ *tp++ = (unsigned char) ((val >> 8) & 0xff);
+ *tp++ = (unsigned char) (val & 0xff);
+ saw_xdigit = 0;
+ val = 0;
+ continue;
+ }
+ if(ch == '.' && ((tp + INADDRSZ) <= endp) &&
+ inet_pton4(curtok, tp) > 0) {
+ tp += INADDRSZ;
+ saw_xdigit = 0;
+ break; /* '\0' was seen by inet_pton4(). */
+ }
+ return 0;
+ }
+ if(saw_xdigit) {
+ if(tp + INT16SZ > endp)
+ return 0;
+ *tp++ = (unsigned char) ((val >> 8) & 0xff);
+ *tp++ = (unsigned char) (val & 0xff);
+ }
+ if(colonp) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we will do the shift by hand.
+ */
+ const ssize_t n = tp - colonp;
+ ssize_t i;
+
+ if(tp == endp)
+ return 0;
+ for(i = 1; i <= n; i++) {
+ *(endp - i) = *(colonp + n - i);
+ *(colonp + n - i) = 0;
+ }
+ tp = endp;
+ }
+ if(tp != endp)
+ return 0;
+ memcpy(dst, tmp, IN6ADDRSZ);
+ return 1;
+}
+
+#endif /* HAVE_INET_PTON */
diff --git a/libs/libcurl/src/curlx/inet_pton.h b/libs/libcurl/src/curlx/inet_pton.h
new file mode 100644
index 0000000000..4e9c87922e
--- /dev/null
+++ b/libs/libcurl/src/curlx/inet_pton.h
@@ -0,0 +1,48 @@
+#ifndef HEADER_CURL_INET_PTON_H
+#define HEADER_CURL_INET_PTON_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "../curl_setup.h"
+
+int curlx_inet_pton(int, const char *, void *);
+
+#ifdef HAVE_INET_PTON
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef __AMIGA__
+#define curlx_inet_pton(x,y,z) inet_pton(x,(unsigned char *)CURL_UNCONST(y),z)
+#else
+#define curlx_inet_pton(x,y,z) inet_pton(x,y,z)
+#endif
+#endif
+
+#endif /* HEADER_CURL_INET_PTON_H */
diff --git a/libs/libcurl/src/curlx/multibyte.c b/libs/libcurl/src/curlx/multibyte.c
new file mode 100644
index 0000000000..3337397a56
--- /dev/null
+++ b/libs/libcurl/src/curlx/multibyte.c
@@ -0,0 +1,360 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+/*
+ * This file is 'mem-include-scan' clean, which means its memory allocations
+ * are not tracked by the curl memory tracker memdebug, so they must not use
+ * `CURLDEBUG` macro replacements in memdebug.h for free, malloc, etc. To avoid
+ * these macro replacements, wrap the names in parentheses to call the original
+ * versions: `ptr = (malloc)(123)`, `(free)(ptr)`, etc.
+ */
+
+#include "../curl_setup.h"
+
+#ifdef _WIN32
+
+#include "multibyte.h"
+
+/*
+ * MultiByte conversions using Windows kernel32 library.
+ */
+
+wchar_t *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 = (malloc)(str_w_len * sizeof(wchar_t));
+ if(str_w) {
+ if(MultiByteToWideChar(CP_UTF8, 0, str_utf8, -1, str_w,
+ str_w_len) == 0) {
+ (free)(str_w);
+ return NULL;
+ }
+ }
+ }
+ }
+
+ return str_w;
+}
+
+char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w)
+{
+ 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 = (malloc)(bytes);
+ if(str_utf8) {
+ if(WideCharToMultiByte(CP_UTF8, 0, str_w, -1, str_utf8, bytes,
+ NULL, NULL) == 0) {
+ (free)(str_utf8);
+ return NULL;
+ }
+ }
+ }
+ }
+
+ return str_utf8;
+}
+
+#ifndef UNDER_CE
+
+/* declare GetFullPathNameW for mingw-w64 UWP builds targeting old windows */
+#if defined(CURL_WINDOWS_UWP) && defined(__MINGW32__) && \
+ (_WIN32_WINNT < _WIN32_WINNT_WIN10)
+WINBASEAPI DWORD WINAPI GetFullPathNameW(LPCWSTR, DWORD, LPWSTR, LPWSTR *);
+#endif
+
+/* Fix excessive paths (paths that exceed MAX_PATH length of 260).
+ *
+ * This is a helper function to fix paths that would exceed the MAX_PATH
+ * limitation check done by Windows APIs. It does so by normalizing the passed
+ * in filename or path 'in' to its full canonical path, and if that path is
+ * longer than MAX_PATH then setting 'out' to "\\?\" prefix + that full path.
+ *
+ * For example 'in' filename255chars in current directory C:\foo\bar is
+ * fixed as \\?\C:\foo\bar\filename255chars for 'out' which will tell Windows
+ * it is ok to access that filename even though the actual full path is longer
+ * than 260 chars.
+ *
+ * For non-Unicode builds this function may fail sometimes because only the
+ * Unicode versions of some Windows API functions can access paths longer than
+ * MAX_PATH, for example GetFullPathNameW which is used in this function. When
+ * the full path is then converted from Unicode to multibyte that fails if any
+ * directories in the path contain characters not in the current codepage.
+ */
+static bool fix_excessive_path(const TCHAR *in, TCHAR **out)
+{
+ size_t needed, count;
+ const wchar_t *in_w;
+ wchar_t *fbuf = NULL;
+
+ /* MS documented "approximate" limit for the maximum path length */
+ const size_t max_path_len = 32767;
+
+#ifndef _UNICODE
+ wchar_t *ibuf = NULL;
+ char *obuf = NULL;
+#endif
+
+ *out = NULL;
+
+ /* skip paths already normalized */
+ if(!_tcsncmp(in, _T("\\\\?\\"), 4))
+ goto cleanup;
+
+#ifndef _UNICODE
+ /* convert multibyte input to unicode */
+ needed = mbstowcs(NULL, in, 0);
+ if(needed == (size_t)-1 || needed >= max_path_len)
+ goto cleanup;
+ ++needed; /* for NUL */
+ ibuf = (malloc)(needed * sizeof(wchar_t));
+ if(!ibuf)
+ goto cleanup;
+ count = mbstowcs(ibuf, in, needed);
+ if(count == (size_t)-1 || count >= needed)
+ goto cleanup;
+ in_w = ibuf;
+#else
+ in_w = in;
+#endif
+
+ /* GetFullPathNameW returns the normalized full path in unicode. It converts
+ forward slashes to backslashes, processes .. to remove directory segments,
+ etc. Unlike GetFullPathNameA it can process paths that exceed MAX_PATH. */
+ needed = (size_t)GetFullPathNameW(in_w, 0, NULL, NULL);
+ if(!needed || needed > max_path_len)
+ goto cleanup;
+ /* skip paths that are not excessive and do not need modification */
+ if(needed <= MAX_PATH)
+ goto cleanup;
+ fbuf = (malloc)(needed * sizeof(wchar_t));
+ if(!fbuf)
+ goto cleanup;
+ count = (size_t)GetFullPathNameW(in_w, (DWORD)needed, fbuf, NULL);
+ if(!count || count >= needed)
+ goto cleanup;
+
+ /* prepend \\?\ or \\?\UNC\ to the excessively long path.
+ *
+ * c:\longpath ---> \\?\c:\longpath
+ * \\.\c:\longpath ---> \\?\c:\longpath
+ * \\?\c:\longpath ---> \\?\c:\longpath (unchanged)
+ * \\server\c$\longpath ---> \\?\UNC\server\c$\longpath
+ *
+ * https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats
+ */
+ if(!wcsncmp(fbuf, L"\\\\?\\", 4))
+ ; /* do nothing */
+ else if(!wcsncmp(fbuf, L"\\\\.\\", 4))
+ fbuf[2] = '?';
+ else if(!wcsncmp(fbuf, L"\\\\.", 3) || !wcsncmp(fbuf, L"\\\\?", 3)) {
+ /* Unexpected, not UNC. The formatting doc doesn't allow this AFAICT. */
+ goto cleanup;
+ }
+ else {
+ wchar_t *temp;
+
+ if(!wcsncmp(fbuf, L"\\\\", 2)) {
+ /* "\\?\UNC\" + full path without "\\" + null */
+ needed = 8 + (count - 2) + 1;
+ if(needed > max_path_len)
+ goto cleanup;
+
+ temp = (malloc)(needed * sizeof(wchar_t));
+ if(!temp)
+ goto cleanup;
+
+ wcsncpy(temp, L"\\\\?\\UNC\\", 8);
+ wcscpy(temp + 8, fbuf + 2);
+ }
+ else {
+ /* "\\?\" + full path + null */
+ needed = 4 + count + 1;
+ if(needed > max_path_len)
+ goto cleanup;
+
+ temp = (malloc)(needed * sizeof(wchar_t));
+ if(!temp)
+ goto cleanup;
+
+ wcsncpy(temp, L"\\\\?\\", 4);
+ wcscpy(temp + 4, fbuf);
+ }
+
+ (free)(fbuf);
+ fbuf = temp;
+ }
+
+#ifndef _UNICODE
+ /* convert unicode full path to multibyte output */
+ needed = wcstombs(NULL, fbuf, 0);
+ if(needed == (size_t)-1 || needed >= max_path_len)
+ goto cleanup;
+ ++needed; /* for NUL */
+ obuf = (malloc)(needed);
+ if(!obuf)
+ goto cleanup;
+ count = wcstombs(obuf, fbuf, needed);
+ if(count == (size_t)-1 || count >= needed)
+ goto cleanup;
+ *out = obuf;
+ obuf = NULL;
+#else
+ *out = fbuf;
+ fbuf = NULL;
+#endif
+
+cleanup:
+ (free)(fbuf);
+#ifndef _UNICODE
+ (free)(ibuf);
+ (free)(obuf);
+#endif
+ return *out ? true : false;
+}
+
+int curlx_win32_open(const char *filename, int oflag, ...)
+{
+ int pmode = 0;
+ int result = -1;
+ TCHAR *fixed = NULL;
+ const TCHAR *target = NULL;
+
+#ifdef _UNICODE
+ wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename);
+#endif
+
+ va_list param;
+ va_start(param, oflag);
+ if(oflag & O_CREAT)
+ pmode = va_arg(param, int);
+ va_end(param);
+
+#ifdef _UNICODE
+ if(filename_w) {
+ if(fix_excessive_path(filename_w, &fixed))
+ target = fixed;
+ else
+ target = filename_w;
+ result = _wopen(target, oflag, pmode);
+ curlx_unicodefree(filename_w);
+ }
+ else
+ /* !checksrc! disable ERRNOVAR 1 */
+ CURL_SETERRNO(EINVAL);
+#else
+ if(fix_excessive_path(filename, &fixed))
+ target = fixed;
+ else
+ target = filename;
+ result = _open(target, oflag, pmode);
+#endif
+
+ (free)(fixed);
+ return result;
+}
+
+FILE *curlx_win32_fopen(const char *filename, const char *mode)
+{
+ FILE *result = NULL;
+ TCHAR *fixed = NULL;
+ const TCHAR *target = NULL;
+
+#ifdef _UNICODE
+ wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename);
+ wchar_t *mode_w = curlx_convert_UTF8_to_wchar(mode);
+ if(filename_w && mode_w) {
+ if(fix_excessive_path(filename_w, &fixed))
+ target = fixed;
+ else
+ target = filename_w;
+ result = _wfopen(target, mode_w);
+ }
+ else
+ /* !checksrc! disable ERRNOVAR 1 */
+ CURL_SETERRNO(EINVAL);
+ curlx_unicodefree(filename_w);
+ curlx_unicodefree(mode_w);
+#else
+ if(fix_excessive_path(filename, &fixed))
+ target = fixed;
+ else
+ target = filename;
+ result = (fopen)(target, mode);
+#endif
+
+ (free)(fixed);
+ return result;
+}
+
+int curlx_win32_stat(const char *path, struct_stat *buffer)
+{
+ int result = -1;
+ TCHAR *fixed = NULL;
+ const TCHAR *target = NULL;
+
+#ifdef _UNICODE
+ wchar_t *path_w = curlx_convert_UTF8_to_wchar(path);
+ if(path_w) {
+ if(fix_excessive_path(path_w, &fixed))
+ target = fixed;
+ else
+ target = path_w;
+#ifndef USE_WIN32_LARGE_FILES
+ result = _wstat(target, buffer);
+#else
+ result = _wstati64(target, buffer);
+#endif
+ curlx_unicodefree(path_w);
+ }
+ else
+ /* !checksrc! disable ERRNOVAR 1 */
+ CURL_SETERRNO(EINVAL);
+#else
+ if(fix_excessive_path(path, &fixed))
+ target = fixed;
+ else
+ target = path;
+#ifndef USE_WIN32_LARGE_FILES
+ result = _stat(target, buffer);
+#else
+ result = _stati64(target, buffer);
+#endif
+#endif
+
+ (free)(fixed);
+ return result;
+}
+
+#endif /* UNDER_CE */
+
+#endif /* _WIN32 */
diff --git a/libs/libcurl/src/curlx/multibyte.h b/libs/libcurl/src/curlx/multibyte.h
new file mode 100644
index 0000000000..3f8c04bb70
--- /dev/null
+++ b/libs/libcurl/src/curlx/multibyte.h
@@ -0,0 +1,87 @@
+#ifndef HEADER_CURL_MULTIBYTE_H
+#define HEADER_CURL_MULTIBYTE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "../curl_setup.h"
+
+#ifdef _WIN32
+
+ /*
+ * MultiByte conversions using Windows kernel32 library.
+ */
+
+wchar_t *curlx_convert_UTF8_to_wchar(const char *str_utf8);
+char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w);
+#endif /* _WIN32 */
+
+/*
+ * Macros curlx_convert_UTF8_to_tchar(), curlx_convert_tchar_to_UTF8()
+ * and curlx_unicodefree() main purpose is to minimize the number of
+ * preprocessor conditional directives needed by code using these
+ * to differentiate Unicode from non-Unicode builds.
+ *
+ * In the case of a non-Unicode build the tchar strings are char strings that
+ * are duplicated via strdup and remain in whatever the passed in encoding is,
+ * which is assumed to be UTF-8 but may be other encoding. Therefore the
+ * significance of the conversion functions is primarily for Unicode builds.
+ *
+ * Allocated memory should be free'd with curlx_unicodefree().
+ *
+ * Note: Because these are curlx functions their memory usage is not tracked
+ * by the curl memory tracker memdebug. you will notice that curlx
+ * function-like macros call free and strdup in parentheses, eg (strdup)(ptr),
+ * and that is to ensure that the curl memdebug override macros do not replace
+ * them.
+ */
+
+#if defined(UNICODE) && defined(_WIN32)
+
+#define curlx_convert_UTF8_to_tchar(ptr) curlx_convert_UTF8_to_wchar((ptr))
+#define curlx_convert_tchar_to_UTF8(ptr) curlx_convert_wchar_to_UTF8((ptr))
+
+typedef union {
+ unsigned short *tchar_ptr;
+ const unsigned short *const_tchar_ptr;
+ unsigned short *tbyte_ptr;
+ const unsigned short *const_tbyte_ptr;
+} xcharp_u;
+
+#else
+
+#define curlx_convert_UTF8_to_tchar(ptr) (strdup)(ptr)
+#define curlx_convert_tchar_to_UTF8(ptr) (strdup)(ptr)
+
+typedef union {
+ char *tchar_ptr;
+ const char *const_tchar_ptr;
+ unsigned char *tbyte_ptr;
+ const unsigned char *const_tbyte_ptr;
+} xcharp_u;
+
+#endif /* UNICODE && _WIN32 */
+
+/* the purpose of this macro is to free() without being traced by memdebug */
+#define curlx_unicodefree(ptr) (free)(CURL_UNCONST(ptr))
+
+#endif /* HEADER_CURL_MULTIBYTE_H */
diff --git a/libs/libcurl/src/curlx/nonblock.c b/libs/libcurl/src/curlx/nonblock.c
new file mode 100644
index 0000000000..4f8153f140
--- /dev/null
+++ b/libs/libcurl/src/curlx/nonblock.c
@@ -0,0 +1,93 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "../curl_setup.h"
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#include "nonblock.h"
+
+/*
+ * curlx_nonblock() set the given socket to either blocking or non-blocking
+ * mode based on the 'nonblock' boolean argument. This function is highly
+ * portable.
+ */
+int curlx_nonblock(curl_socket_t sockfd, /* operate on this */
+ int nonblock /* TRUE or FALSE */)
+{
+#if defined(HAVE_FCNTL_O_NONBLOCK)
+ /* most recent Unix versions */
+ int flags;
+ flags = sfcntl(sockfd, F_GETFL, 0);
+ if(flags < 0)
+ return -1;
+ /* Check if the current file status flags have already satisfied
+ * the request, if so, it is no need to call fcntl() to replicate it.
+ */
+ if(!!(flags & O_NONBLOCK) == !!nonblock)
+ return 0;
+ if(nonblock)
+ flags |= O_NONBLOCK;
+ else
+ flags &= ~O_NONBLOCK;
+ return sfcntl(sockfd, F_SETFL, flags);
+
+#elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO)
+
+ /* Amiga */
+ long flags = nonblock ? 1L : 0L;
+ return IoctlSocket(sockfd, FIONBIO, (char *)&flags);
+
+#elif defined(HAVE_IOCTL_FIONBIO)
+
+ /* older Unix versions */
+ int flags = nonblock ? 1 : 0;
+ return ioctl(sockfd, FIONBIO, &flags);
+
+#elif defined(HAVE_IOCTLSOCKET_FIONBIO)
+
+ /* Windows */
+ unsigned long flags = nonblock ? 1UL : 0UL;
+ return ioctlsocket(sockfd, (long)FIONBIO, &flags);
+
+#elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK)
+
+ /* Orbis OS */
+ long b = nonblock ? 1L : 0L;
+ return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
+
+#else
+# error "no non-blocking method was found/used/set"
+#endif
+}
diff --git a/libs/libcurl/src/curlx/nonblock.h b/libs/libcurl/src/curlx/nonblock.h
new file mode 100644
index 0000000000..9834ccff01
--- /dev/null
+++ b/libs/libcurl/src/curlx/nonblock.h
@@ -0,0 +1,32 @@
+#ifndef HEADER_CURL_NONBLOCK_H
+#define HEADER_CURL_NONBLOCK_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include <curl/curl.h> /* for curl_socket_t */
+
+int curlx_nonblock(curl_socket_t sockfd, /* operate on this */
+ int nonblock /* TRUE or FALSE */);
+
+#endif /* HEADER_CURL_NONBLOCK_H */
diff --git a/libs/libcurl/src/curlx/strparse.c b/libs/libcurl/src/curlx/strparse.c
new file mode 100644
index 0000000000..b92959ec2c
--- /dev/null
+++ b/libs/libcurl/src/curlx/strparse.c
@@ -0,0 +1,303 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "strparse.h"
+#include "../strcase.h"
+
+void curlx_str_init(struct Curl_str *out)
+{
+ out->str = NULL;
+ out->len = 0;
+}
+
+void curlx_str_assign(struct Curl_str *out, const char *str, size_t len)
+{
+ out->str = str;
+ out->len = len;
+}
+
+/* Get a word until the first DELIM or end of string. At least one byte long.
+ return non-zero on error */
+int curlx_str_until(const char **linep, struct Curl_str *out,
+ const size_t max, char delim)
+{
+ const char *s = *linep;
+ size_t len = 0;
+ DEBUGASSERT(linep && *linep && out && max && delim);
+
+ curlx_str_init(out);
+ while(*s && (*s != delim)) {
+ s++;
+ if(++len > max) {
+ return STRE_BIG;
+ }
+ }
+ if(!len)
+ return STRE_SHORT;
+ out->str = *linep;
+ out->len = len;
+ *linep = s; /* point to the first byte after the word */
+ return STRE_OK;
+}
+
+/* Get a word until the first space or end of string. At least one byte long.
+ return non-zero on error */
+int curlx_str_word(const char **linep, struct Curl_str *out,
+ const size_t max)
+{
+ return curlx_str_until(linep, out, max, ' ');
+}
+
+/* Get a word until a newline byte or end of string. At least one byte long.
+ return non-zero on error */
+int curlx_str_untilnl(const char **linep, struct Curl_str *out,
+ const size_t max)
+{
+ const char *s = *linep;
+ size_t len = 0;
+ DEBUGASSERT(linep && *linep && out && max);
+
+ curlx_str_init(out);
+ while(*s && !ISNEWLINE(*s)) {
+ s++;
+ if(++len > max)
+ return STRE_BIG;
+ }
+ if(!len)
+ return STRE_SHORT;
+ out->str = *linep;
+ out->len = len;
+ *linep = s; /* point to the first byte after the word */
+ return STRE_OK;
+}
+
+
+/* Get a "quoted" word. No escaping possible.
+ return non-zero on error */
+int curlx_str_quotedword(const char **linep, struct Curl_str *out,
+ const size_t max)
+{
+ const char *s = *linep;
+ size_t len = 0;
+ DEBUGASSERT(linep && *linep && out && max);
+
+ curlx_str_init(out);
+ if(*s != '\"')
+ return STRE_BEGQUOTE;
+ s++;
+ while(*s && (*s != '\"')) {
+ s++;
+ if(++len > max)
+ return STRE_BIG;
+ }
+ if(*s != '\"')
+ return STRE_ENDQUOTE;
+ out->str = (*linep) + 1;
+ out->len = len;
+ *linep = s + 1;
+ return STRE_OK;
+}
+
+/* Advance over a single character.
+ return non-zero on error */
+int curlx_str_single(const char **linep, char byte)
+{
+ DEBUGASSERT(linep && *linep);
+ if(**linep != byte)
+ return STRE_BYTE;
+ (*linep)++; /* move over it */
+ return STRE_OK;
+}
+
+/* Advance over a single space.
+ return non-zero on error */
+int curlx_str_singlespace(const char **linep)
+{
+ return curlx_str_single(linep, ' ');
+}
+
+/* given an ASCII character and max ascii, return TRUE if valid */
+#define valid_digit(x,m) \
+ (((x) >= '0') && ((x) <= m) && Curl_hexasciitable[(x)-'0'])
+
+/* We use 16 for the zero index (and the necessary bitwise AND in the loop)
+ to be able to have a non-zero value there to make valid_digit() able to
+ use the info */
+const unsigned char Curl_hexasciitable[] = {
+ 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* 0x30: 0 - 9 */
+ 0, 0, 0, 0, 0, 0, 0,
+ 10, 11, 12, 13, 14, 15, /* 0x41: A - F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 10, 11, 12, 13, 14, 15 /* 0x61: a - f */
+};
+
+/* no support for 0x prefix nor leading spaces */
+static int str_num_base(const char **linep, curl_off_t *nump, curl_off_t max,
+ int base) /* 8, 10 or 16, nothing else */
+{
+ curl_off_t num = 0;
+ const char *p;
+ int m = (base == 10) ? '9' : /* the largest digit possible */
+ (base == 16) ? 'f' : '7';
+ DEBUGASSERT(linep && *linep && nump);
+ DEBUGASSERT((base == 8) || (base == 10) || (base == 16));
+ DEBUGASSERT(max >= 0); /* mostly to catch SIZE_T_MAX, which is too large */
+ *nump = 0;
+ p = *linep;
+ if(!valid_digit(*p, m))
+ return STRE_NO_NUM;
+ if(max < base) {
+ /* special-case low max scenario because check needs to be different */
+ do {
+ int n = Curl_hexval(*p++);
+ num = num * base + n;
+ if(num > max)
+ return STRE_OVERFLOW;
+ } while(valid_digit(*p, m));
+ }
+ else {
+ do {
+ int n = Curl_hexval(*p++);
+ if(num > ((max - n) / base))
+ return STRE_OVERFLOW;
+ num = num * base + n;
+ } while(valid_digit(*p, m));
+ }
+ *nump = num;
+ *linep = p;
+ return STRE_OK;
+}
+
+/* Get an unsigned decimal number with no leading space or minus. Leading
+ zeroes are accepted. return non-zero on error */
+int curlx_str_number(const char **linep, curl_off_t *nump, curl_off_t max)
+{
+ return str_num_base(linep, nump, max, 10);
+}
+
+/* Get an unsigned hexadecimal number with no leading space or minus and no
+ "0x" support. Leading zeroes are accepted. return non-zero on error */
+int curlx_str_hex(const char **linep, curl_off_t *nump, curl_off_t max)
+{
+ return str_num_base(linep, nump, max, 16);
+}
+
+/* Get an unsigned octal number with no leading space or minus and no "0"
+ prefix support. Leading zeroes are accepted. return non-zero on error */
+int curlx_str_octal(const char **linep, curl_off_t *nump, curl_off_t max)
+{
+ return str_num_base(linep, nump, max, 8);
+}
+
+/*
+ * Parse a positive number up to 63-bit number written in ASCII. Skip leading
+ * blanks. No support for prefixes.
+ */
+int curlx_str_numblanks(const char **str, curl_off_t *num)
+{
+ curlx_str_passblanks(str);
+ return curlx_str_number(str, num, CURL_OFF_T_MAX);
+}
+
+/* CR or LF
+ return non-zero on error */
+int curlx_str_newline(const char **linep)
+{
+ DEBUGASSERT(linep && *linep);
+ if(ISNEWLINE(**linep)) {
+ (*linep)++;
+ return STRE_OK; /* yessir */
+ }
+ return STRE_NEWLINE;
+}
+
+#ifndef WITHOUT_LIBCURL
+/* case insensitive compare that the parsed string matches the given string.
+ Returns non-zero on match. */
+int curlx_str_casecompare(struct Curl_str *str, const char *check)
+{
+ size_t clen = check ? strlen(check) : 0;
+ return ((str->len == clen) && strncasecompare(str->str, check, clen));
+}
+#endif
+
+/* case sensitive string compare. Returns non-zero on match. */
+int curlx_str_cmp(struct Curl_str *str, const char *check)
+{
+ if(check) {
+ size_t clen = strlen(check);
+ return ((str->len == clen) && !strncmp(str->str, check, clen));
+ }
+ return !!(str->len);
+}
+
+/* Trim off 'num' number of bytes from the beginning (left side) of the
+ string. If 'num' is larger than the string, return error. */
+int curlx_str_nudge(struct Curl_str *str, size_t num)
+{
+ if(num <= str->len) {
+ str->str += num;
+ str->len -= num;
+ return STRE_OK;
+ }
+ return STRE_OVERFLOW;
+}
+
+/* Get the following character sequence that consists only of bytes not
+ present in the 'reject' string. Like strcspn(). */
+int curlx_str_cspn(const char **linep, struct Curl_str *out,
+ const char *reject)
+{
+ const char *s = *linep;
+ size_t len;
+ DEBUGASSERT(linep && *linep);
+
+ len = strcspn(s, reject);
+ if(len) {
+ out->str = s;
+ out->len = len;
+ *linep = &s[len];
+ return STRE_OK;
+ }
+ curlx_str_init(out);
+ return STRE_SHORT;
+}
+
+/* remove ISBLANK()s from both ends of the string */
+void curlx_str_trimblanks(struct Curl_str *out)
+{
+ while(out->len && ISBLANK(*out->str))
+ curlx_str_nudge(out, 1);
+
+ /* trim trailing spaces and tabs */
+ while(out->len && ISBLANK(out->str[out->len - 1]))
+ out->len--;
+}
+
+/* increase the pointer until it has moved over all blanks */
+void curlx_str_passblanks(const char **linep)
+{
+ while(ISBLANK(**linep))
+ (*linep)++; /* move over it */
+}
diff --git a/libs/libcurl/src/curlx/strparse.h b/libs/libcurl/src/curlx/strparse.h
new file mode 100644
index 0000000000..585e058872
--- /dev/null
+++ b/libs/libcurl/src/curlx/strparse.h
@@ -0,0 +1,112 @@
+#ifndef HEADER_CURL_STRPARSE_H
+#define HEADER_CURL_STRPARSE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "../curl_setup.h"
+
+#define STRE_OK 0
+#define STRE_BIG 1
+#define STRE_SHORT 2
+#define STRE_BEGQUOTE 3
+#define STRE_ENDQUOTE 4
+#define STRE_BYTE 5
+#define STRE_NEWLINE 6
+#define STRE_OVERFLOW 7
+#define STRE_NO_NUM 8
+
+/* public struct, but all accesses should be done using the provided
+ functions */
+struct Curl_str {
+ const char *str;
+ size_t len;
+};
+
+void curlx_str_init(struct Curl_str *out);
+void curlx_str_assign(struct Curl_str *out, const char *str, size_t len);
+
+#define curlx_str(x) ((x)->str)
+#define curlx_strlen(x) ((x)->len)
+
+/* Get a word until the first space
+ return non-zero on error */
+int curlx_str_word(const char **linep, struct Curl_str *out, const size_t max);
+
+/* Get a word until the first DELIM or end of string
+ return non-zero on error */
+int curlx_str_until(const char **linep, struct Curl_str *out, const size_t max,
+ char delim);
+
+/* Get a word until a newline byte or end of string. At least one byte long.
+ return non-zero on error */
+int curlx_str_untilnl(const char **linep, struct Curl_str *out,
+ const size_t max);
+
+/* Get a "quoted" word. No escaping possible.
+ return non-zero on error */
+int curlx_str_quotedword(const char **linep, struct Curl_str *out,
+ const size_t max);
+
+/* Advance over a single character.
+ return non-zero on error */
+int curlx_str_single(const char **linep, char byte);
+
+/* Advance over a single space.
+ return non-zero on error */
+int curlx_str_singlespace(const char **linep);
+
+/* Get an unsigned decimal number. Return non-zero on error */
+int curlx_str_number(const char **linep, curl_off_t *nump, curl_off_t max);
+
+/* As above with CURL_OFF_T_MAX but also pass leading blanks */
+int curlx_str_numblanks(const char **str, curl_off_t *num);
+
+/* Get an unsigned hexadecimal number. Return non-zero on error */
+int curlx_str_hex(const char **linep, curl_off_t *nump, curl_off_t max);
+
+/* Get an unsigned octal number. Return non-zero on error */
+int curlx_str_octal(const char **linep, curl_off_t *nump, curl_off_t max);
+
+/* Check for CR or LF
+ return non-zero on error */
+int curlx_str_newline(const char **linep);
+
+/* case insensitive compare that the parsed string matches the
+ given string. */
+int curlx_str_casecompare(struct Curl_str *str, const char *check);
+int curlx_str_cmp(struct Curl_str *str, const char *check);
+
+int curlx_str_nudge(struct Curl_str *str, size_t num);
+
+int curlx_str_cspn(const char **linep, struct Curl_str *out, const char *cspn);
+void curlx_str_trimblanks(struct Curl_str *out);
+void curlx_str_passblanks(const char **linep);
+
+/* given a hexadecimal letter, return the binary value. '0' returns 0, 'a'
+ returns 10. THIS ONLY WORKS ON VALID HEXADECIMAL LETTER INPUT. Verify
+ before calling this!
+*/
+extern const unsigned char Curl_hexasciitable[];
+#define Curl_hexval(x) (unsigned char)(Curl_hexasciitable[(x) - '0'] & 0x0f)
+
+#endif /* HEADER_CURL_STRPARSE_H */
diff --git a/libs/libcurl/src/curlx/timediff.c b/libs/libcurl/src/curlx/timediff.c
new file mode 100644
index 0000000000..641a15c404
--- /dev/null
+++ b/libs/libcurl/src/curlx/timediff.c
@@ -0,0 +1,88 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "timediff.h"
+
+#include <limits.h>
+
+/*
+ * Converts number of milliseconds into a timeval structure.
+ *
+ * Return values:
+ * NULL IF tv is NULL or ms < 0 (eg. no timeout -> blocking select)
+ * tv with 0 in both fields IF ms == 0 (eg. 0ms timeout -> polling select)
+ * tv with converted fields IF ms > 0 (eg. >0ms timeout -> waiting select)
+ */
+struct timeval *curlx_mstotv(struct timeval *tv, timediff_t ms)
+{
+ if(!tv)
+ return NULL;
+
+ if(ms < 0)
+ return NULL;
+
+ if(ms > 0) {
+ timediff_t tv_sec = ms / 1000;
+ timediff_t tv_usec = (ms % 1000) * 1000; /* max=999000 */
+#ifdef HAVE_SUSECONDS_T
+#if TIMEDIFF_T_MAX > TIME_T_MAX
+ /* tv_sec overflow check in case time_t is signed */
+ if(tv_sec > TIME_T_MAX)
+ tv_sec = TIME_T_MAX;
+#endif
+ tv->tv_sec = (time_t)tv_sec;
+ tv->tv_usec = (suseconds_t)tv_usec;
+#elif defined(_WIN32) /* maybe also others in the future */
+#if TIMEDIFF_T_MAX > LONG_MAX
+ /* tv_sec overflow check on Windows there we know it is long */
+ if(tv_sec > LONG_MAX)
+ tv_sec = LONG_MAX;
+#endif
+ tv->tv_sec = (long)tv_sec;
+ tv->tv_usec = (long)tv_usec;
+#else
+#if TIMEDIFF_T_MAX > INT_MAX
+ /* tv_sec overflow check in case time_t is signed */
+ if(tv_sec > INT_MAX)
+ tv_sec = INT_MAX;
+#endif
+ tv->tv_sec = (int)tv_sec;
+ tv->tv_usec = (int)tv_usec;
+#endif
+ }
+ else {
+ tv->tv_sec = 0;
+ tv->tv_usec = 0;
+ }
+
+ return tv;
+}
+
+/*
+ * Converts a timeval structure into number of milliseconds.
+ */
+timediff_t curlx_tvtoms(struct timeval *tv)
+{
+ return (tv->tv_sec*1000) + (timediff_t)(tv->tv_usec/1000);
+}
diff --git a/libs/libcurl/src/curlx/timediff.h b/libs/libcurl/src/curlx/timediff.h
new file mode 100644
index 0000000000..9a8f695982
--- /dev/null
+++ b/libs/libcurl/src/curlx/timediff.h
@@ -0,0 +1,52 @@
+#ifndef HEADER_CURL_TIMEDIFF_H
+#define HEADER_CURL_TIMEDIFF_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "../curl_setup.h"
+
+/* Use a larger type even for 32-bit time_t systems so that we can keep
+ microsecond accuracy in it */
+typedef curl_off_t timediff_t;
+#define FMT_TIMEDIFF_T FMT_OFF_T
+
+#define TIMEDIFF_T_MAX CURL_OFF_T_MAX
+#define TIMEDIFF_T_MIN CURL_OFF_T_MIN
+
+/*
+ * Converts number of milliseconds into a timeval structure.
+ *
+ * Return values:
+ * NULL IF tv is NULL or ms < 0 (eg. no timeout -> blocking select)
+ * tv with 0 in both fields IF ms == 0 (eg. 0ms timeout -> polling select)
+ * tv with converted fields IF ms > 0 (eg. >0ms timeout -> waiting select)
+ */
+struct timeval *curlx_mstotv(struct timeval *tv, timediff_t ms);
+
+/*
+ * Converts a timeval structure into number of milliseconds.
+ */
+timediff_t curlx_tvtoms(struct timeval *tv);
+
+#endif /* HEADER_CURL_TIMEDIFF_H */
diff --git a/libs/libcurl/src/curlx/timeval.c b/libs/libcurl/src/curlx/timeval.c
new file mode 100644
index 0000000000..e6739b50b3
--- /dev/null
+++ b/libs/libcurl/src/curlx/timeval.c
@@ -0,0 +1,259 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "timeval.h"
+
+#ifdef _WIN32
+
+#include <curl/curl.h>
+#include "version_win32.h"
+#include "../system_win32.h"
+
+LARGE_INTEGER Curl_freq;
+bool Curl_isVistaOrGreater;
+
+/* For tool or tests, we must initialize before calling curlx_now().
+ Providing this function here is wrong. */
+void curlx_now_init(void)
+{
+ if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
+ VERSION_GREATER_THAN_EQUAL))
+ Curl_isVistaOrGreater = true;
+ else
+ Curl_isVistaOrGreater = false;
+
+ QueryPerformanceFrequency(&Curl_freq);
+}
+
+/* In case of bug fix this function has a counterpart in tool_util.c */
+struct curltime curlx_now(void)
+{
+ struct curltime now;
+ bool isVistaOrGreater;
+ isVistaOrGreater = Curl_isVistaOrGreater;
+ if(isVistaOrGreater) { /* QPC timer might have issues pre-Vista */
+ LARGE_INTEGER count;
+ LARGE_INTEGER freq;
+ freq = Curl_freq;
+ DEBUGASSERT(freq.QuadPart);
+ QueryPerformanceCounter(&count);
+ now.tv_sec = (time_t)(count.QuadPart / freq.QuadPart);
+ now.tv_usec = (int)((count.QuadPart % freq.QuadPart) * 1000000 /
+ freq.QuadPart);
+ }
+ else {
+ /* Disable /analyze warning that GetTickCount64 is preferred */
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:28159)
+#endif
+ DWORD milliseconds = GetTickCount();
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+ now.tv_sec = (time_t)(milliseconds / 1000);
+ now.tv_usec = (int)((milliseconds % 1000) * 1000);
+ }
+ return now;
+}
+
+#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC) || \
+ defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW)
+
+struct curltime curlx_now(void)
+{
+ /*
+ ** clock_gettime() is granted to be increased monotonically when the
+ ** monotonic clock is queried. Time starting point is unspecified, it
+ ** could be the system start-up time, the Epoch, or something else,
+ ** in any case the time starting point does not change once that the
+ ** system has started up.
+ */
+#ifdef HAVE_GETTIMEOFDAY
+ struct timeval now;
+#endif
+ struct curltime cnow;
+ struct timespec tsnow;
+
+ /*
+ ** clock_gettime() may be defined by Apple's SDK as weak symbol thus
+ ** code compiles but fails during runtime if clock_gettime() is
+ ** called on unsupported OS version.
+ */
+#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) && \
+ (HAVE_BUILTIN_AVAILABLE == 1)
+ bool have_clock_gettime = FALSE;
+ if(__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *))
+ have_clock_gettime = TRUE;
+#endif
+
+#ifdef HAVE_CLOCK_GETTIME_MONOTONIC_RAW
+ if(
+#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) && \
+ (HAVE_BUILTIN_AVAILABLE == 1)
+ have_clock_gettime &&
+#endif
+ (0 == clock_gettime(CLOCK_MONOTONIC_RAW, &tsnow))) {
+ cnow.tv_sec = tsnow.tv_sec;
+ cnow.tv_usec = (int)(tsnow.tv_nsec / 1000);
+ }
+ else
+#endif
+
+ if(
+#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) && \
+ (HAVE_BUILTIN_AVAILABLE == 1)
+ have_clock_gettime &&
+#endif
+ (0 == clock_gettime(CLOCK_MONOTONIC, &tsnow))) {
+ cnow.tv_sec = tsnow.tv_sec;
+ cnow.tv_usec = (int)(tsnow.tv_nsec / 1000);
+ }
+ /*
+ ** Even when the configure process has truly detected monotonic clock
+ ** availability, it might happen that it is not actually available at
+ ** runtime. When this occurs simply fallback to other time source.
+ */
+#ifdef HAVE_GETTIMEOFDAY
+ else {
+ (void)gettimeofday(&now, NULL);
+ cnow.tv_sec = now.tv_sec;
+ cnow.tv_usec = (int)now.tv_usec;
+ }
+#else
+ else {
+ cnow.tv_sec = time(NULL);
+ cnow.tv_usec = 0;
+ }
+#endif
+ return cnow;
+}
+
+#elif defined(HAVE_MACH_ABSOLUTE_TIME)
+
+#include <stdint.h>
+#include <mach/mach_time.h>
+
+struct curltime curlx_now(void)
+{
+ /*
+ ** Monotonic timer on macOS is provided by mach_absolute_time(), which
+ ** returns time in Mach "absolute time units," which are platform-dependent.
+ ** To convert to nanoseconds, one must use conversion factors specified by
+ ** mach_timebase_info().
+ */
+ static mach_timebase_info_data_t timebase;
+ struct curltime cnow;
+ uint64_t usecs;
+
+ if(0 == timebase.denom)
+ (void) mach_timebase_info(&timebase);
+
+ usecs = mach_absolute_time();
+ usecs *= timebase.numer;
+ usecs /= timebase.denom;
+ usecs /= 1000;
+
+ cnow.tv_sec = usecs / 1000000;
+ cnow.tv_usec = (int)(usecs % 1000000);
+
+ return cnow;
+}
+
+#elif defined(HAVE_GETTIMEOFDAY)
+
+struct curltime curlx_now(void)
+{
+ /*
+ ** gettimeofday() is not granted to be increased monotonically, due to
+ ** clock drifting and external source time synchronization it can jump
+ ** forward or backward in time.
+ */
+ struct timeval now;
+ struct curltime ret;
+ (void)gettimeofday(&now, NULL);
+ ret.tv_sec = now.tv_sec;
+ ret.tv_usec = (int)now.tv_usec;
+ return ret;
+}
+
+#else
+
+struct curltime curlx_now(void)
+{
+ /*
+ ** time() returns the value of time in seconds since the Epoch.
+ */
+ struct curltime now;
+ now.tv_sec = time(NULL);
+ now.tv_usec = 0;
+ return now;
+}
+
+#endif
+
+/*
+ * Returns: time difference in number of milliseconds. For too large diffs it
+ * returns max value.
+ *
+ * @unittest: 1323
+ */
+timediff_t curlx_timediff(struct curltime newer, struct curltime older)
+{
+ timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec;
+ if(diff >= (TIMEDIFF_T_MAX/1000))
+ return TIMEDIFF_T_MAX;
+ else if(diff <= (TIMEDIFF_T_MIN/1000))
+ return TIMEDIFF_T_MIN;
+ return diff * 1000 + (newer.tv_usec-older.tv_usec)/1000;
+}
+
+/*
+ * Returns: time difference in number of milliseconds, rounded up.
+ * For too large diffs it returns max value.
+ */
+timediff_t curlx_timediff_ceil(struct curltime newer, struct curltime older)
+{
+ timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec;
+ if(diff >= (TIMEDIFF_T_MAX/1000))
+ return TIMEDIFF_T_MAX;
+ else if(diff <= (TIMEDIFF_T_MIN/1000))
+ return TIMEDIFF_T_MIN;
+ return diff * 1000 + (newer.tv_usec - older.tv_usec + 999)/1000;
+}
+
+/*
+ * Returns: time difference in number of microseconds. For too large diffs it
+ * returns max value.
+ */
+timediff_t curlx_timediff_us(struct curltime newer, struct curltime older)
+{
+ timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec;
+ if(diff >= (TIMEDIFF_T_MAX/1000000))
+ return TIMEDIFF_T_MAX;
+ else if(diff <= (TIMEDIFF_T_MIN/1000000))
+ return TIMEDIFF_T_MIN;
+ return diff * 1000000 + newer.tv_usec-older.tv_usec;
+}
diff --git a/libs/libcurl/src/curlx/timeval.h b/libs/libcurl/src/curlx/timeval.h
new file mode 100644
index 0000000000..8e34a07967
--- /dev/null
+++ b/libs/libcurl/src/curlx/timeval.h
@@ -0,0 +1,67 @@
+#ifndef HEADER_CURL_TIMEVAL_H
+#define HEADER_CURL_TIMEVAL_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "../curl_setup.h"
+
+#include "timediff.h"
+
+struct curltime {
+ time_t tv_sec; /* seconds */
+ int tv_usec; /* microseconds */
+};
+
+#ifdef _WIN32
+/* For tool or tests, we must initialize before calling curlx_now() */
+void curlx_now_init(void);
+#endif
+
+struct curltime curlx_now(void);
+
+/*
+ * Make sure that the first argument (newer) is the more recent time and older
+ * is the older time, as otherwise you get a weird negative time-diff back...
+ *
+ * Returns: the time difference in number of milliseconds.
+ */
+timediff_t curlx_timediff(struct curltime newer, struct curltime older);
+
+/*
+ * Make sure that the first argument (newer) is the more recent time and older
+ * is the older time, as otherwise you get a weird negative time-diff back...
+ *
+ * Returns: the time difference in number of milliseconds, rounded up.
+ */
+timediff_t curlx_timediff_ceil(struct curltime newer, struct curltime older);
+
+/*
+ * Make sure that the first argument (newer) is the more recent time and older
+ * is the older time, as otherwise you get a weird negative time-diff back...
+ *
+ * Returns: the time difference in number of microseconds.
+ */
+timediff_t curlx_timediff_us(struct curltime newer, struct curltime older);
+
+#endif /* HEADER_CURL_TIMEVAL_H */
diff --git a/libs/libcurl/src/curlx/version_win32.c b/libs/libcurl/src/curlx/version_win32.c
new file mode 100644
index 0000000000..54c02bdfe0
--- /dev/null
+++ b/libs/libcurl/src/curlx/version_win32.c
@@ -0,0 +1,243 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Steve Holme, <steve_holme@hotmail.com>.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "../curl_setup.h"
+
+#ifdef _WIN32
+
+#include <curl/curl.h>
+#include "version_win32.h"
+#include "warnless.h"
+
+/* The last 2 #include files should be in this order */
+#include "../curl_memory.h"
+#include "../memdebug.h"
+
+/* This Unicode version struct works for VerifyVersionInfoW (OSVERSIONINFOEXW)
+ and RtlVerifyVersionInfo (RTLOSVERSIONINFOEXW) */
+struct OUR_OSVERSIONINFOEXW {
+ ULONG dwOSVersionInfoSize;
+ ULONG dwMajorVersion;
+ ULONG dwMinorVersion;
+ ULONG dwBuildNumber;
+ ULONG dwPlatformId;
+ WCHAR szCSDVersion[128];
+ USHORT wServicePackMajor;
+ USHORT wServicePackMinor;
+ USHORT wSuiteMask;
+ UCHAR wProductType;
+ UCHAR wReserved;
+};
+
+/*
+ * curlx_verify_windows_version()
+ *
+ * This is used to verify if we are running on a specific Windows version.
+ *
+ * Parameters:
+ *
+ * majorVersion [in] - The major version number.
+ * minorVersion [in] - The minor version number.
+ * buildVersion [in] - The build version number. If 0, this parameter is
+ * ignored.
+ * platform [in] - The optional platform identifier.
+ * condition [in] - The test condition used to specifier whether we are
+ * checking a version less than, equal to or greater than
+ * what is specified in the major and minor version
+ * numbers.
+ *
+ * Returns TRUE if matched; otherwise FALSE.
+ */
+bool curlx_verify_windows_version(const unsigned int majorVersion,
+ const unsigned int minorVersion,
+ const unsigned int buildVersion,
+ const PlatformIdentifier platform,
+ const VersionCondition condition)
+{
+ bool matched = FALSE;
+
+#ifdef CURL_WINDOWS_UWP
+ /* We have no way to determine the Windows version from Windows apps,
+ so let's assume we are running on the target Windows version. */
+ const WORD fullVersion = MAKEWORD(minorVersion, majorVersion);
+ const WORD targetVersion = (WORD)_WIN32_WINNT;
+
+ (void)buildVersion;
+
+ switch(condition) {
+ case VERSION_LESS_THAN:
+ matched = targetVersion < fullVersion;
+ break;
+
+ case VERSION_LESS_THAN_EQUAL:
+ matched = targetVersion <= fullVersion;
+ break;
+
+ case VERSION_EQUAL:
+ matched = targetVersion == fullVersion;
+ break;
+
+ case VERSION_GREATER_THAN_EQUAL:
+ matched = targetVersion >= fullVersion;
+ break;
+
+ case VERSION_GREATER_THAN:
+ matched = targetVersion > fullVersion;
+ break;
+ }
+
+ if(matched && (platform == PLATFORM_WINDOWS)) {
+ /* we are always running on PLATFORM_WINNT */
+ matched = FALSE;
+ }
+#elif defined(UNDER_CE)
+ (void)majorVersion;
+ (void)minorVersion;
+ (void)buildVersion;
+ (void)platform;
+ (void)condition;
+#else
+ ULONGLONG cm = 0;
+ struct OUR_OSVERSIONINFOEXW osver;
+ BYTE majorCondition;
+ BYTE minorCondition;
+ BYTE buildCondition;
+ BYTE spMajorCondition;
+ BYTE spMinorCondition;
+ DWORD dwTypeMask = VER_MAJORVERSION | VER_MINORVERSION |
+ VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR;
+
+ typedef LONG (APIENTRY *RTLVERIFYVERSIONINFO_FN)
+ (struct OUR_OSVERSIONINFOEXW *, ULONG, ULONGLONG);
+ static RTLVERIFYVERSIONINFO_FN pRtlVerifyVersionInfo;
+ static bool onetime = TRUE; /* safe because first call is during init */
+
+ if(onetime) {
+ pRtlVerifyVersionInfo = CURLX_FUNCTION_CAST(RTLVERIFYVERSIONINFO_FN,
+ (GetProcAddress(GetModuleHandleA("ntdll"), "RtlVerifyVersionInfo")));
+ onetime = FALSE;
+ }
+
+ switch(condition) {
+ case VERSION_LESS_THAN:
+ majorCondition = VER_LESS;
+ minorCondition = VER_LESS;
+ buildCondition = VER_LESS;
+ spMajorCondition = VER_LESS_EQUAL;
+ spMinorCondition = VER_LESS_EQUAL;
+ break;
+
+ case VERSION_LESS_THAN_EQUAL:
+ majorCondition = VER_LESS_EQUAL;
+ minorCondition = VER_LESS_EQUAL;
+ buildCondition = VER_LESS_EQUAL;
+ spMajorCondition = VER_LESS_EQUAL;
+ spMinorCondition = VER_LESS_EQUAL;
+ break;
+
+ case VERSION_EQUAL:
+ majorCondition = VER_EQUAL;
+ minorCondition = VER_EQUAL;
+ buildCondition = VER_EQUAL;
+ spMajorCondition = VER_GREATER_EQUAL;
+ spMinorCondition = VER_GREATER_EQUAL;
+ break;
+
+ case VERSION_GREATER_THAN_EQUAL:
+ majorCondition = VER_GREATER_EQUAL;
+ minorCondition = VER_GREATER_EQUAL;
+ buildCondition = VER_GREATER_EQUAL;
+ spMajorCondition = VER_GREATER_EQUAL;
+ spMinorCondition = VER_GREATER_EQUAL;
+ break;
+
+ case VERSION_GREATER_THAN:
+ majorCondition = VER_GREATER;
+ minorCondition = VER_GREATER;
+ buildCondition = VER_GREATER;
+ spMajorCondition = VER_GREATER_EQUAL;
+ spMinorCondition = VER_GREATER_EQUAL;
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ memset(&osver, 0, sizeof(osver));
+ osver.dwOSVersionInfoSize = sizeof(osver);
+ osver.dwMajorVersion = majorVersion;
+ osver.dwMinorVersion = minorVersion;
+ osver.dwBuildNumber = buildVersion;
+ if(platform == PLATFORM_WINDOWS)
+ osver.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS;
+ else if(platform == PLATFORM_WINNT)
+ osver.dwPlatformId = VER_PLATFORM_WIN32_NT;
+
+ cm = VerSetConditionMask(cm, VER_MAJORVERSION, majorCondition);
+ cm = VerSetConditionMask(cm, VER_MINORVERSION, minorCondition);
+ cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, spMajorCondition);
+ cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, spMinorCondition);
+
+ if(platform != PLATFORM_DONT_CARE) {
+ cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL);
+ dwTypeMask |= VER_PLATFORMID;
+ }
+
+ /* Later versions of Windows have version functions that may not return the
+ real version of Windows unless the application is so manifested. We prefer
+ the real version always, so we use the Rtl variant of the function when
+ possible. Note though the function signatures have underlying fundamental
+ types that are the same, the return values are different. */
+ if(pRtlVerifyVersionInfo)
+ matched = !pRtlVerifyVersionInfo(&osver, dwTypeMask, cm);
+ else
+ matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver, dwTypeMask, cm);
+
+ /* Compare the build number separately. VerifyVersionInfo normally compares
+ major.minor in hierarchical order (eg 1.9 is less than 2.0) but does not
+ do the same for build (eg 1.9 build 222 is not less than 2.0 build 111).
+ Build comparison is only needed when build numbers are equal (eg 1.9 is
+ always less than 2.0 so build comparison is not needed). */
+ if(matched && buildVersion &&
+ (condition == VERSION_EQUAL ||
+ ((condition == VERSION_GREATER_THAN_EQUAL ||
+ condition == VERSION_LESS_THAN_EQUAL) &&
+ curlx_verify_windows_version(majorVersion, minorVersion, 0,
+ platform, VERSION_EQUAL)))) {
+
+ cm = VerSetConditionMask(0, VER_BUILDNUMBER, buildCondition);
+ dwTypeMask = VER_BUILDNUMBER;
+ if(pRtlVerifyVersionInfo)
+ matched = !pRtlVerifyVersionInfo(&osver, dwTypeMask, cm);
+ else
+ matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver,
+ dwTypeMask, cm);
+ }
+
+#endif
+
+ return matched;
+}
+
+#endif /* _WIN32 */
diff --git a/libs/libcurl/src/curlx/version_win32.h b/libs/libcurl/src/curlx/version_win32.h
new file mode 100644
index 0000000000..0a9aa9b2e0
--- /dev/null
+++ b/libs/libcurl/src/curlx/version_win32.h
@@ -0,0 +1,56 @@
+#ifndef HEADER_CURL_VERSION_WIN32_H
+#define HEADER_CURL_VERSION_WIN32_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Steve Holme, <steve_holme@hotmail.com>.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "../curl_setup.h"
+
+#ifdef _WIN32
+
+/* Version condition */
+typedef enum {
+ VERSION_LESS_THAN,
+ VERSION_LESS_THAN_EQUAL,
+ VERSION_EQUAL,
+ VERSION_GREATER_THAN_EQUAL,
+ VERSION_GREATER_THAN
+} VersionCondition;
+
+/* Platform identifier */
+typedef enum {
+ PLATFORM_DONT_CARE,
+ PLATFORM_WINDOWS,
+ PLATFORM_WINNT
+} PlatformIdentifier;
+
+/* This is used to verify if we are running on a specific Windows version */
+bool curlx_verify_windows_version(const unsigned int majorVersion,
+ const unsigned int minorVersion,
+ const unsigned int buildVersion,
+ const PlatformIdentifier platform,
+ const VersionCondition condition);
+
+#endif /* _WIN32 */
+
+#endif /* HEADER_CURL_VERSION_WIN32_H */
diff --git a/libs/libcurl/src/curlx/warnless.c b/libs/libcurl/src/curlx/warnless.c
new file mode 100644
index 0000000000..de43a2c17b
--- /dev/null
+++ b/libs/libcurl/src/curlx/warnless.c
@@ -0,0 +1,315 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "warnless.h"
+
+#if defined(__INTEL_COMPILER) && defined(__unix__)
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
+#endif /* __INTEL_COMPILER && __unix__ */
+
+#ifdef _WIN32
+#undef read
+#undef write
+#endif
+
+#include <limits.h>
+
+#define CURL_MASK_UCHAR ((unsigned char)~0)
+
+#define CURL_MASK_USHORT ((unsigned short)~0)
+
+#define CURL_MASK_UINT ((unsigned int)~0)
+#define CURL_MASK_SINT (CURL_MASK_UINT >> 1)
+
+#define CURL_MASK_ULONG ((unsigned long)~0)
+
+#define CURL_MASK_USIZE_T ((size_t)~0)
+#define CURL_MASK_SSIZE_T (CURL_MASK_USIZE_T >> 1)
+
+/*
+** unsigned long to unsigned char
+*/
+
+unsigned char curlx_ultouc(unsigned long ulnum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_UCHAR);
+ return (unsigned char)(ulnum & (unsigned long) CURL_MASK_UCHAR);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned size_t to signed int
+*/
+
+int curlx_uztosi(size_t uznum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(uznum <= (size_t) CURL_MASK_SINT);
+ return (int)(uznum & (size_t) CURL_MASK_SINT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned size_t to unsigned long
+*/
+
+unsigned long curlx_uztoul(size_t uznum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+#if ULONG_MAX < SIZE_T_MAX
+ DEBUGASSERT(uznum <= (size_t) CURL_MASK_ULONG);
+#endif
+ return (unsigned long)(uznum & (size_t) CURL_MASK_ULONG);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned size_t to unsigned int
+*/
+
+unsigned int curlx_uztoui(size_t uznum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+#if UINT_MAX < SIZE_T_MAX
+ DEBUGASSERT(uznum <= (size_t) CURL_MASK_UINT);
+#endif
+ return (unsigned int)(uznum & (size_t) CURL_MASK_UINT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** signed long to signed int
+*/
+
+int curlx_sltosi(long slnum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(slnum >= 0);
+#if INT_MAX < LONG_MAX
+ DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_SINT);
+#endif
+ return (int)(slnum & (long) CURL_MASK_SINT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** signed long to unsigned int
+*/
+
+unsigned int curlx_sltoui(long slnum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(slnum >= 0);
+#if UINT_MAX < LONG_MAX
+ DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_UINT);
+#endif
+ return (unsigned int)(slnum & (long) CURL_MASK_UINT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** signed long to unsigned short
+*/
+
+unsigned short curlx_sltous(long slnum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(slnum >= 0);
+ DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_USHORT);
+ return (unsigned short)(slnum & (long) CURL_MASK_USHORT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned size_t to signed ssize_t
+*/
+
+ssize_t curlx_uztosz(size_t uznum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(uznum <= (size_t) CURL_MASK_SSIZE_T);
+ return (ssize_t)(uznum & (size_t) CURL_MASK_SSIZE_T);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** signed curl_off_t to unsigned size_t
+*/
+
+size_t curlx_sotouz(curl_off_t sonum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(sonum >= 0);
+ return (size_t)(sonum & (curl_off_t) CURL_MASK_USIZE_T);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** signed ssize_t to signed int
+*/
+
+int curlx_sztosi(ssize_t sznum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(sznum >= 0);
+#if INT_MAX < SSIZE_T_MAX
+ DEBUGASSERT((size_t) sznum <= (size_t) CURL_MASK_SINT);
+#endif
+ return (int)(sznum & (ssize_t) CURL_MASK_SINT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned int to unsigned short
+*/
+
+unsigned short curlx_uitous(unsigned int uinum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(uinum <= (unsigned int) CURL_MASK_USHORT);
+ return (unsigned short) (uinum & (unsigned int) CURL_MASK_USHORT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** signed int to unsigned size_t
+*/
+
+size_t curlx_sitouz(int sinum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(sinum >= 0);
+ return (size_t) sinum;
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+#ifdef _WIN32
+
+ssize_t curlx_read(int fd, void *buf, size_t count)
+{
+ return (ssize_t)read(fd, buf, curlx_uztoui(count));
+}
+
+ssize_t curlx_write(int fd, const void *buf, size_t count)
+{
+ return (ssize_t)write(fd, buf, curlx_uztoui(count));
+}
+
+#endif /* _WIN32 */
+
+/* Ensure that warnless.h redefinitions continue to have an effect
+ in "unity" builds. */
+#undef HEADER_CURL_WARNLESS_H_REDEFS
diff --git a/libs/libcurl/src/curlx/warnless.h b/libs/libcurl/src/curlx/warnless.h
new file mode 100644
index 0000000000..e995a3c9d3
--- /dev/null
+++ b/libs/libcurl/src/curlx/warnless.h
@@ -0,0 +1,80 @@
+#ifndef HEADER_CURL_WARNLESS_H
+#define HEADER_CURL_WARNLESS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "../curl_setup.h"
+
+#ifdef USE_WINSOCK
+#include <curl/curl.h> /* for curl_socket_t */
+#endif
+
+#define CURLX_FUNCTION_CAST(target_type, func) \
+ (target_type)(void (*) (void))(func)
+
+unsigned char curlx_ultouc(unsigned long ulnum);
+
+int curlx_uztosi(size_t uznum);
+
+unsigned long curlx_uztoul(size_t uznum);
+
+unsigned int curlx_uztoui(size_t uznum);
+
+int curlx_sltosi(long slnum);
+
+unsigned int curlx_sltoui(long slnum);
+
+unsigned short curlx_sltous(long slnum);
+
+ssize_t curlx_uztosz(size_t uznum);
+
+size_t curlx_sotouz(curl_off_t sonum);
+
+int curlx_sztosi(ssize_t sznum);
+
+unsigned short curlx_uitous(unsigned int uinum);
+
+size_t curlx_sitouz(int sinum);
+
+#ifdef _WIN32
+
+ssize_t curlx_read(int fd, void *buf, size_t count);
+
+ssize_t curlx_write(int fd, const void *buf, size_t count);
+
+#endif /* _WIN32 */
+
+#endif /* HEADER_CURL_WARNLESS_H */
+
+#ifndef HEADER_CURL_WARNLESS_H_REDEFS
+#define HEADER_CURL_WARNLESS_H_REDEFS
+
+#ifdef _WIN32
+#undef read
+#define read(fd, buf, count) curlx_read(fd, buf, count)
+#undef write
+#define write(fd, buf, count) curlx_write(fd, buf, count)
+#endif
+
+#endif /* HEADER_CURL_WARNLESS_H_REDEFS */
diff --git a/libs/libcurl/src/curlx/winapi.c b/libs/libcurl/src/curlx/winapi.c
new file mode 100644
index 0000000000..60eddc23f2
--- /dev/null
+++ b/libs/libcurl/src/curlx/winapi.c
@@ -0,0 +1,135 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "../curl_setup.h"
+
+/*
+ * curlx_winapi_strerror:
+ * Variant of Curl_strerror if the error code is definitely Windows API.
+ */
+#ifdef _WIN32
+#include "winapi.h"
+
+#ifdef BUILDING_LIBCURL
+#include <curl/mprintf.h>
+#define SNPRINTF curl_msnprintf
+#else
+/* when built for the test servers */
+
+/* adjust for old MSVC */
+#if defined(_MSC_VER) && (_MSC_VER < 1900)
+# define SNPRINTF _snprintf
+#else
+#define SNPRINTF snprintf
+#endif
+
+#endif /* !BUILDING_LIBCURL */
+
+#ifdef _WIN32
+/* This is a helper function for Curl_strerror that converts Windows API error
+ * codes (GetLastError) to error messages.
+ * Returns NULL if no error message was found for error code.
+ */
+const char *curlx_get_winapi_error(int err, char *buf, size_t buflen)
+{
+ char *p;
+ wchar_t wbuf[256];
+
+ if(!buflen)
+ return NULL;
+
+ *buf = '\0';
+ *wbuf = L'\0';
+
+ /* We return the local codepage version of the error string because if it is
+ output to the user's terminal it will likely be with functions which
+ expect the local codepage (eg fprintf, failf, infof).
+ FormatMessageW -> wcstombs is used for Windows CE compatibility. */
+ if(FormatMessageW((FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS), NULL, (DWORD)err,
+ LANG_NEUTRAL, wbuf, CURL_ARRAYSIZE(wbuf), NULL)) {
+ size_t written = wcstombs(buf, wbuf, buflen - 1);
+ if(written != (size_t)-1)
+ buf[written] = '\0';
+ else
+ *buf = '\0';
+ }
+
+ /* Truncate multiple lines */
+ p = strchr(buf, '\n');
+ if(p) {
+ if(p > buf && *(p-1) == '\r')
+ *(p-1) = '\0';
+ else
+ *p = '\0';
+ }
+
+ return *buf ? buf : NULL;
+}
+#endif /* _WIN32 */
+
+const char *curlx_winapi_strerror(DWORD err, char *buf, size_t buflen)
+{
+#ifdef _WIN32
+ DWORD old_win_err = GetLastError();
+#endif
+ int old_errno = errno;
+
+ if(!buflen)
+ return NULL;
+
+ *buf = '\0';
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ if(!curlx_get_winapi_error((int)err, buf, buflen)) {
+#if defined(__GNUC__) && __GNUC__ >= 7
+#pragma GCC diagnostic push
+#pragma GCC diagnostic warning "-Wformat-truncation=1"
+#endif
+ /* some GCC compilers cause false positive warnings if we allow this
+ warning */
+ SNPRINTF(buf, buflen, "Unknown error %lu (0x%08lX)", err, err);
+#if defined(__GNUC__) && __GNUC__ >= 7
+#pragma GCC diagnostic pop
+#endif
+
+ }
+#else
+ {
+ const char *txt = (err == ERROR_SUCCESS) ? "No error" : "Error";
+ if(strlen(txt) < buflen)
+ strcpy(buf, txt);
+ }
+#endif
+
+ if(errno != old_errno)
+ CURL_SETERRNO(old_errno);
+
+#ifdef _WIN32
+ if(old_win_err != GetLastError())
+ SetLastError(old_win_err);
+#endif
+
+ return buf;
+}
+#endif /* _WIN32 */
diff --git a/libs/libcurl/src/curlx/winapi.h b/libs/libcurl/src/curlx/winapi.h
new file mode 100644
index 0000000000..65425b9a0f
--- /dev/null
+++ b/libs/libcurl/src/curlx/winapi.h
@@ -0,0 +1,33 @@
+#ifndef HEADER_CURLX_WINAPI_H
+#define HEADER_CURLX_WINAPI_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#ifdef _WIN32
+#define WINAPI_ERROR_LEN 100
+const char *curlx_get_winapi_error(int err, char *buf, size_t buflen);
+const char *curlx_winapi_strerror(DWORD err, char *buf, size_t buflen);
+#endif
+
+#endif /* HEADER_CURLX_WINAPI_H */