20#include <winpr/config.h>
21#include <winpr/assert.h>
31#include <winpr/endian.h>
33#if defined(WITH_URIPARSER)
34#include <uriparser/Uri.h>
37#if defined(WINPR_HAVE_REGCOMP)
44#define TAG WINPR_TAG("crt")
46#if defined(WITH_URIPARSER)
47BOOL winpr_str_is_valid_urlN(
const char* str,
size_t len)
49 if (!str || (len == 0))
52 const char* errorPos =
nullptr;
53 UriUriA uri = WINPR_C_ARRAY_INIT;
54 const int rc = uriParseSingleUriExA(&uri, str, &str[len - 1], &errorPos);
55 uriFreeUriMembersA(&uri);
56 return rc == URI_SUCCESS;
59BOOL winpr_str_is_valid_url(
const char* str)
64 const char* errorPos =
nullptr;
65 UriUriA uri = WINPR_C_ARRAY_INIT;
66 const int rc = uriParseSingleUriA(&uri, str, &errorPos);
67 uriFreeUriMembersA(&uri);
68 return rc == URI_SUCCESS;
71char* winpr_str_url_decode(
const char* str,
size_t len)
73 char* dst = strndup(str, len);
77 if (!uriUnescapeInPlaceExA(dst, URI_FALSE, URI_BR_DONT_TOUCH))
86char* winpr_str_url_encode(
const char* str,
size_t len)
88 char* dst = calloc(len + 1,
sizeof(
char) * 3);
92 if (!uriEscapeA(str, dst, URI_FALSE, URI_FALSE))
101static const char rfc3986[] = {
102 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
103 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
104 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x2e, 0x00,
105 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
106 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
107 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x5f,
108 0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
109 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x00, 0x00, 0x00, 0x7e, 0x00,
110 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
111 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
113 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
114 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
116 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
120static char hex2bin(
char what)
131static char unescape(
const char* what,
size_t* px)
133 if ((*what ==
'%') && (isxdigit(what[1]) && isxdigit(what[2])))
136 return 16 * hex2bin(what[1]) + hex2bin(what[2]);
142char* winpr_str_url_decode(
const char* str,
size_t len)
144 char* dst = calloc(len + 1,
sizeof(
char));
149 for (
size_t x = 0; x < strnlen(str, len); x++)
151 const char* cur = &str[x];
152 dst[pos++] = unescape(cur, &x);
158static char* escape(
char* dst,
char what)
160 if (rfc3986[what & 0xff])
166 if (sprintf(dst,
"%%%02" PRIX8, (BYTE)(what & 0xff)) < 0)
171char* winpr_str_url_encode(
const char* str,
size_t len)
173 char* dst = calloc(len + 1,
sizeof(
char) * 3);
178 for (
size_t x = 0; x < strnlen(str, len); x++)
180 const char cur = str[x];
181 ptr = escape(ptr, cur);
186BOOL winpr_str_is_valid_urlN(
const char* str,
size_t len)
188 if (!str || (len == 0))
191 char* url = strndup(str, len);
195 const BOOL rc = winpr_str_is_valid_url(url);
203BOOL winpr_str_is_valid_url(
const char* str)
207 return PathIsURLA(str);
210#elif defined(WINPR_HAVE_REGCOMP)
211BOOL winpr_str_is_valid_url(
const char* str)
215 regex_t regex = WINPR_C_ARRAY_INIT;
216 const char pattern[] =
"^([a-z]+://)?([a-zA-Z0-9.-]+)(:[0-9]+)?(/[a-zA-Z0-9./?=&%-]*)?$";
218 int ret = regcomp(®ex, pattern, REG_EXTENDED);
221 printf(
"Could not compile regex\n");
225 ret = regexec(®ex, str, 0,
nullptr, 0);
231BOOL winpr_str_is_valid_url(WINPR_ATTR_UNUSED
const char* str)
233 WLog_WARN(TAG,
"URL validation not supported by your build, not performing check. Build with "
234 "-DWITH_URIPARSER=ON to fix.");
240BOOL winpr_str_append(
const char* what,
char* buffer,
size_t size,
const char* separator)
242 const size_t used = strnlen(buffer, size);
243 const size_t add = strnlen(what, size);
244 const size_t sep_len = separator ? strnlen(separator, size) : 0;
245 const size_t sep = (used > 0) ? sep_len : 0;
247 if (used + add + sep >= size)
250 if ((used > 0) && (sep_len > 0))
251 strncat(buffer, separator, sep_len);
253 strncat(buffer, what, add);
257WINPR_ATTR_FORMAT_ARG(3, 4)
258int winpr_asprintf(
char** s,
size_t* slen, WINPR_FORMAT_ARG const
char* templ, ...)
260 va_list ap = WINPR_C_ARRAY_INIT;
263 int rc = winpr_vasprintf(s, slen, templ, ap);
268WINPR_ATTR_FORMAT_ARG(3, 0)
269int winpr_vasprintf(
char** s,
size_t* slen, WINPR_FORMAT_ARG const
char* templ, va_list oap)
271 va_list ap = WINPR_C_ARRAY_INIT;
277 const int length = vsnprintf(
nullptr, 0, templ, ap);
282 char* str = calloc((
size_t)length + 1UL,
sizeof(
char));
287 const int plen = vsnprintf(str, (
size_t)length + 1UL, templ, ap);
296 *slen = (size_t)length;
302char* _strdup(
const char* strSource)
304 if (strSource ==
nullptr)
307 char* strDestination = strdup(strSource);
309 if (strDestination ==
nullptr)
310 WLog_ERR(TAG,
"strdup");
312 return strDestination;
315WCHAR* _wcsdup(
const WCHAR* strSource)
320 size_t len = _wcslen(strSource);
321 WCHAR* strDestination = calloc(len + 1,
sizeof(WCHAR));
323 if (strDestination !=
nullptr)
324 memcpy(strDestination, strSource, len *
sizeof(WCHAR));
326 if (strDestination ==
nullptr)
327 WLog_ERR(TAG,
"wcsdup");
329 return strDestination;
332WCHAR* _wcsncat(WCHAR* dst,
const WCHAR* src,
size_t sz)
335 WINPR_ASSERT(src || (sz == 0));
337 const size_t dlen = _wcslen(dst);
338 const size_t slen = _wcsnlen(src, sz);
339 for (
size_t x = 0; x < slen; x++)
340 dst[dlen + x] = src[x];
341 dst[dlen + slen] =
'\0';
345int _stricmp(
const char* string1,
const char* string2)
347 return strcasecmp(string1, string2);
350int _strnicmp(
const char* string1,
const char* string2,
size_t count)
352 return strncasecmp(string1, string2, count);
357int _wcscmp(
const WCHAR* string1,
const WCHAR* string2)
359 WINPR_ASSERT(string1);
360 WINPR_ASSERT(string2);
364 const WCHAR w1 = *string1++;
365 const WCHAR w2 = *string2++;
369 else if ((w1 ==
'\0') || (w2 ==
'\0'))
374int _wcsncmp(
const WCHAR* string1,
const WCHAR* string2,
size_t count)
376 WINPR_ASSERT(string1);
377 WINPR_ASSERT(string2);
379 for (
size_t x = 0; x < count; x++)
381 const WCHAR a = string1[x];
382 const WCHAR b = string2[x];
386 else if ((a ==
'\0') || (b ==
'\0'))
394size_t _wcslen(
const WCHAR* str)
396 const WCHAR* p = str;
403 return (
size_t)(p - str);
408size_t _wcsnlen(
const WCHAR* str,
size_t max)
424WCHAR* _wcsstr(
const WCHAR* str,
const WCHAR* strSearch)
427 WINPR_ASSERT(strSearch);
429 if (strSearch[0] ==
'\0')
430 return WINPR_CAST_CONST_PTR_AWAY(str, WCHAR*);
432 const size_t searchLen = _wcslen(strSearch);
435 if (_wcsncmp(str, strSearch, searchLen) == 0)
436 return WINPR_CAST_CONST_PTR_AWAY(str, WCHAR*);
444WCHAR* _wcschr(
const WCHAR* str, WCHAR c)
451 const WCHAR* p = str;
453 while (*p && (*p != c))
456 cnv.cc = (*p == c) ? p : nullptr;
462WCHAR* _wcsrchr(
const WCHAR* str, WCHAR c)
469 const WCHAR* p =
nullptr;
474 for (; *str !=
'\0'; str++)
476 const WCHAR ch = *str;
485char* strtok_s(
char* strToken,
const char* strDelimit,
char** context)
487 return strtok_r(strToken, strDelimit, context);
490WCHAR* wcstok_s(WCHAR* strToken,
const WCHAR* strDelimit, WCHAR** context)
492 WCHAR* nextToken =
nullptr;
500 while (*strToken && _wcschr(strDelimit, value))
509 nextToken = strToken++;
512 while (*strToken && !(_wcschr(strDelimit, value)))
527#if !defined(_WIN32) || defined(_UWP)
535LPSTR CharUpperA(LPSTR lpsz)
542 length = strlen(lpsz);
545 return (LPSTR)
nullptr;
551 if ((c >=
'a') && (c <=
'z'))
552 c = (char)(c -
'a' +
'A');
558 for (
size_t i = 0; i < length; i++)
560 if ((lpsz[i] >=
'a') && (lpsz[i] <=
'z'))
561 lpsz[i] = (char)(lpsz[i] -
'a' +
'A');
567LPWSTR CharUpperW(LPWSTR lpsz)
574 length = _wcslen(lpsz);
577 return (LPWSTR)
nullptr;
583 if ((c >= L
'a') && (c <= L
'z'))
590 for (
size_t i = 0; i < length; i++)
592 if ((lpsz[i] >= L
'a') && (lpsz[i] <= L
'z'))
593 lpsz[i] = lpsz[i] - L
'a' + L
'A';
599DWORD CharUpperBuffA(LPSTR lpsz, DWORD cchLength)
604 for (DWORD i = 0; i < cchLength; i++)
606 if ((lpsz[i] >=
'a') && (lpsz[i] <=
'z'))
607 lpsz[i] = (char)(lpsz[i] -
'a' +
'A');
613DWORD CharUpperBuffW(LPWSTR lpsz, DWORD cchLength)
615 for (DWORD i = 0; i < cchLength; i++)
617 WCHAR value = winpr_Data_Get_UINT16(&lpsz[i]);
618 value = WINPR_TOUPPERW(value);
619 winpr_Data_Write_UINT16(&lpsz[i], value);
625LPSTR CharLowerA(LPSTR lpsz)
630 return (LPSTR)
nullptr;
632 length = strlen(lpsz);
635 return (LPSTR)
nullptr;
641 if ((c >=
'A') && (c <=
'Z'))
642 c = (char)(c -
'A' +
'a');
648 for (
size_t i = 0; i < length; i++)
650 if ((lpsz[i] >=
'A') && (lpsz[i] <=
'Z'))
651 lpsz[i] = (char)(lpsz[i] -
'A' +
'a');
657LPWSTR CharLowerW(LPWSTR lpsz)
659 const size_t len = _wcsnlen(lpsz, UINT32_MAX + 1);
660 if (len > UINT32_MAX)
662 CharLowerBuffW(lpsz, (UINT32)len);
666DWORD CharLowerBuffA(LPSTR lpsz, DWORD cchLength)
671 for (DWORD i = 0; i < cchLength; i++)
673 if ((lpsz[i] >=
'A') && (lpsz[i] <=
'Z'))
674 lpsz[i] = (char)(lpsz[i] -
'A' +
'a');
680DWORD CharLowerBuffW(LPWSTR lpsz, DWORD cchLength)
682 for (DWORD i = 0; i < cchLength; i++)
684 WCHAR value = winpr_Data_Get_UINT16(&lpsz[i]);
685 value = WINPR_TOLOWERW(value);
686 winpr_Data_Write_UINT16(&lpsz[i], value);
692BOOL IsCharAlphaA(CHAR ch)
694 if (((ch >=
'a') && (ch <=
'z')) || ((ch >=
'A') && (ch <=
'Z')))
700BOOL IsCharAlphaW(WCHAR ch)
702 if (((ch >= L
'a') && (ch <= L
'z')) || ((ch >= L
'A') && (ch <= L
'Z')))
708BOOL IsCharAlphaNumericA(CHAR ch)
710 if (((ch >=
'a') && (ch <=
'z')) || ((ch >=
'A') && (ch <=
'Z')) ||
711 ((ch >=
'0') && (ch <=
'9')))
717BOOL IsCharAlphaNumericW(WCHAR ch)
719 if (((ch >= L
'a') && (ch <= L
'z')) || ((ch >= L
'A') && (ch <= L
'Z')) ||
720 ((ch >= L
'0') && (ch <= L
'9')))
726BOOL IsCharUpperA(CHAR ch)
728 if ((ch >=
'A') && (ch <=
'Z'))
734BOOL IsCharUpperW(WCHAR ch)
736 if ((ch >= L
'A') && (ch <= L
'Z'))
742BOOL IsCharLowerA(CHAR ch)
744 if ((ch >=
'a') && (ch <=
'z'))
750BOOL IsCharLowerW(WCHAR ch)
752 if ((ch >= L
'a') && (ch <= L
'z'))
760size_t ConvertLineEndingToLF(
char* str,
size_t size)
764 WINPR_ASSERT(str || (size == 0));
765 for (
size_t x = 0; x < size; x++)
771 str[x - skip] =
'\n';
772 if ((x + 1 < size) && (str[x + 1] ==
'\n'))
783char* ConvertLineEndingToCRLF(
const char* str,
size_t* size)
786 const size_t s = *size;
787 WINPR_ASSERT(str || (s == 0));
793 size_t linebreaks = 0;
794 for (
size_t x = 0; x < s - 1; x++)
807 char* cnv = calloc(s + linebreaks * 2ull + 1ull,
sizeof(
char));
812 for (
size_t x = 0; x < s; x++)
814 const char c = str[x];
823 if ((x > 0) && (str[x - 1] !=
'\r'))
838char* StrSep(
char** stringp,
const char* delim)
840 char* start = *stringp;
842 p = (start !=
nullptr) ? strpbrk(start, delim) :
nullptr;
855INT64 GetLine(
char** lineptr,
size_t* size, FILE* stream)
863 if (!lineptr || !size)
871 if (used + 2 >= *size)
874 n = realloc(*lineptr, *size);
887 (*lineptr)[used++] = c;
888 }
while ((c !=
'\n') && (c !=
'\r') && (c != EOF));
890 (*lineptr)[used] =
'\0';
892#elif !defined(ANDROID) && !defined(IOS)
893 return getline(lineptr, size, stream);
899#if !defined(WINPR_HAVE_STRNDUP)
900char* strndup(
const char* src,
size_t n)
902 char* dst = calloc(n + 1,
sizeof(
char));
904 strncpy(dst, src, n);
909const WCHAR* InitializeConstWCharFromUtf8(
const char* str, WCHAR* buffer,
size_t len)
912 WINPR_ASSERT(buffer || (len == 0));
913 (void)ConvertUtf8ToWChar(str, buffer, len);
917WCHAR* wcsndup(
const WCHAR* s,
size_t n)
922 WCHAR* copy = calloc(n + 1,
sizeof(WCHAR));
925 memcpy(copy, s, n *
sizeof(WCHAR));
929char* winpr_strnstr(
char* haystack,
const char* needle,
size_t hlen)
931 WINPR_ASSERT(haystack || (hlen == 0));
932 WINPR_ASSERT(needle);
934#if defined(WINPR_HAVE_STRNSTR)
935 return strnstr(haystack, needle, hlen);
939 const size_t needle_len = strlen(needle);
944 for (; (*haystack !=
'\0') && (hlen >= needle_len); haystack++, hlen--)
946 if ((haystack[0] == needle[0]) && (0 == strncmp(haystack, needle, needle_len)))
953BOOL winpr_str_has_newlines(
const char* str)
970 if ((str[0] == (
char)0x80) && ((str[1] == (
char)0xA8) || (str[1] == (
char)0xA9)))