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*);
443#if defined(WITHOUT_WINPR_3x_DEPRECATED)
446 WCHAR* _wcschr(
const WCHAR* str, WCHAR c)
453 const WCHAR* p = str;
455 while (*p && (*p != c))
458 cnv.cc = (*p == c) ? p : nullptr;
463#if !defined(WITHOUT_WINPR_3x_DEPRECATED)
464WCHAR* _wcsrchr(
const WCHAR* str, WCHAR c)
471 const WCHAR* p =
nullptr;
476 for (; *str !=
'\0'; str++)
478 const WCHAR ch = *str;
488char* strtok_s(
char* strToken,
const char* strDelimit,
char** context)
490 return strtok_r(strToken, strDelimit, context);
493WCHAR* wcstok_s(WCHAR* strToken,
const WCHAR* strDelimit, WCHAR** context)
495 WCHAR* nextToken =
nullptr;
503 while (*strToken && _wcschr(strDelimit, value))
512 nextToken = strToken++;
515 while (*strToken && !(_wcschr(strDelimit, value)))
530#if !defined(_WIN32) || defined(_UWP)
538LPSTR CharUpperA(LPSTR lpsz)
545 length = strlen(lpsz);
548 return (LPSTR)
nullptr;
554 if ((c >=
'a') && (c <=
'z'))
555 c = (char)(c -
'a' +
'A');
561 for (
size_t i = 0; i < length; i++)
563 if ((lpsz[i] >=
'a') && (lpsz[i] <=
'z'))
564 lpsz[i] = (char)(lpsz[i] -
'a' +
'A');
570LPWSTR CharUpperW(LPWSTR lpsz)
577 length = _wcslen(lpsz);
580 return (LPWSTR)
nullptr;
586 if ((c >= L
'a') && (c <= L
'z'))
593 for (
size_t i = 0; i < length; i++)
595 if ((lpsz[i] >= L
'a') && (lpsz[i] <= L
'z'))
596 lpsz[i] = lpsz[i] - L
'a' + L
'A';
602DWORD CharUpperBuffA(LPSTR lpsz, DWORD cchLength)
607 for (DWORD i = 0; i < cchLength; i++)
609 if ((lpsz[i] >=
'a') && (lpsz[i] <=
'z'))
610 lpsz[i] = (char)(lpsz[i] -
'a' +
'A');
616DWORD CharUpperBuffW(LPWSTR lpsz, DWORD cchLength)
618 for (DWORD i = 0; i < cchLength; i++)
620 WCHAR value = winpr_Data_Get_UINT16(&lpsz[i]);
621 value = WINPR_TOUPPERW(value);
622 winpr_Data_Write_UINT16(&lpsz[i], value);
628LPSTR CharLowerA(LPSTR lpsz)
633 return (LPSTR)
nullptr;
635 length = strlen(lpsz);
638 return (LPSTR)
nullptr;
644 if ((c >=
'A') && (c <=
'Z'))
645 c = (char)(c -
'A' +
'a');
651 for (
size_t i = 0; i < length; i++)
653 if ((lpsz[i] >=
'A') && (lpsz[i] <=
'Z'))
654 lpsz[i] = (char)(lpsz[i] -
'A' +
'a');
660LPWSTR CharLowerW(LPWSTR lpsz)
662 const size_t len = _wcsnlen(lpsz, UINT32_MAX + 1);
663 if (len > UINT32_MAX)
665 CharLowerBuffW(lpsz, (UINT32)len);
669DWORD CharLowerBuffA(LPSTR lpsz, DWORD cchLength)
674 for (DWORD i = 0; i < cchLength; i++)
676 if ((lpsz[i] >=
'A') && (lpsz[i] <=
'Z'))
677 lpsz[i] = (char)(lpsz[i] -
'A' +
'a');
683DWORD CharLowerBuffW(LPWSTR lpsz, DWORD cchLength)
685 for (DWORD i = 0; i < cchLength; i++)
687 WCHAR value = winpr_Data_Get_UINT16(&lpsz[i]);
688 value = WINPR_TOLOWERW(value);
689 winpr_Data_Write_UINT16(&lpsz[i], value);
695BOOL IsCharAlphaA(CHAR ch)
697 if (((ch >=
'a') && (ch <=
'z')) || ((ch >=
'A') && (ch <=
'Z')))
703BOOL IsCharAlphaW(WCHAR ch)
705 if (((ch >= L
'a') && (ch <= L
'z')) || ((ch >= L
'A') && (ch <= L
'Z')))
711BOOL IsCharAlphaNumericA(CHAR ch)
713 if (((ch >=
'a') && (ch <=
'z')) || ((ch >=
'A') && (ch <=
'Z')) ||
714 ((ch >=
'0') && (ch <=
'9')))
720BOOL IsCharAlphaNumericW(WCHAR ch)
722 if (((ch >= L
'a') && (ch <= L
'z')) || ((ch >= L
'A') && (ch <= L
'Z')) ||
723 ((ch >= L
'0') && (ch <= L
'9')))
729BOOL IsCharUpperA(CHAR ch)
731 if ((ch >=
'A') && (ch <=
'Z'))
737BOOL IsCharUpperW(WCHAR ch)
739 if ((ch >= L
'A') && (ch <= L
'Z'))
745BOOL IsCharLowerA(CHAR ch)
747 if ((ch >=
'a') && (ch <=
'z'))
753BOOL IsCharLowerW(WCHAR ch)
755 if ((ch >= L
'a') && (ch <= L
'z'))
763size_t ConvertLineEndingToLF(
char* str,
size_t size)
767 WINPR_ASSERT(str || (size == 0));
768 for (
size_t x = 0; x < size; x++)
774 str[x - skip] =
'\n';
775 if ((x + 1 < size) && (str[x + 1] ==
'\n'))
786char* ConvertLineEndingToCRLF(
const char* str,
size_t* size)
789 const size_t s = *size;
790 WINPR_ASSERT(str || (s == 0));
796 size_t linebreaks = 0;
797 for (
size_t x = 0; x < s - 1; x++)
810 char* cnv = calloc(s + linebreaks * 2ull + 1ull,
sizeof(
char));
815 for (
size_t x = 0; x < s; x++)
817 const char c = str[x];
826 if ((x > 0) && (str[x - 1] !=
'\r'))
841char* StrSep(
char** stringp,
const char* delim)
843 char* start = *stringp;
845 p = (start !=
nullptr) ? strpbrk(start, delim) :
nullptr;
858INT64 GetLine(
char** lineptr,
size_t* size, FILE* stream)
866 if (!lineptr || !size)
874 if (used + 2 >= *size)
877 n = realloc(*lineptr, *size);
890 (*lineptr)[used++] = c;
891 }
while ((c !=
'\n') && (c !=
'\r') && (c != EOF));
893 (*lineptr)[used] =
'\0';
895#elif !defined(ANDROID) && !defined(IOS)
896 return getline(lineptr, size, stream);
902#if !defined(WINPR_HAVE_STRNDUP)
903char* strndup(
const char* src,
size_t n)
905 char* dst = calloc(n + 1,
sizeof(
char));
907 strncpy(dst, src, n);
912const WCHAR* InitializeConstWCharFromUtf8(
const char* str, WCHAR* buffer,
size_t len)
915 WINPR_ASSERT(buffer || (len == 0));
916 (void)ConvertUtf8ToWChar(str, buffer, len);
920WCHAR* wcsndup(
const WCHAR* s,
size_t n)
925 WCHAR* copy = calloc(n + 1,
sizeof(WCHAR));
928 memcpy(copy, s, n *
sizeof(WCHAR));
932char* winpr_strnstr(
const char* haystack,
const char* needle,
size_t hlen)
934 WINPR_ASSERT(haystack || (hlen == 0));
935 WINPR_ASSERT(needle);
937#if defined(WINPR_HAVE_STRNSTR)
938 return strnstr(haystack, needle, hlen);
942 const size_t needle_len = strlen(needle);
945 return WINPR_CAST_CONST_PTR_AWAY(haystack,
char*);
947 for (; (*haystack !=
'\0') && (hlen >= needle_len); haystack++, hlen--)
949 if ((haystack[0] == needle[0]) && (0 == strncmp(haystack, needle, needle_len)))
950 return WINPR_CAST_CONST_PTR_AWAY(haystack,
char*);
956BOOL winpr_str_has_newlines(
const char* str)
973 if ((str[0] == (
char)0x80) && ((str[1] == (
char)0xA8) || (str[1] == (
char)0xA9)))
986WCHAR* winpr_wcsnchr(
const WCHAR* str,
size_t charLen, WCHAR c)
988 if (!str || (charLen == 0))
991 const WCHAR* p = str;
992 const WCHAR* end = &str[charLen];
996 const WCHAR wc = winpr_Data_Get_UINT16(p);
1012WCHAR* winpr_wcsnrchr(
const WCHAR* str,
size_t charLen, WCHAR c)
1014 if (!str || (charLen == 0))
1017 const WCHAR* p = str;
1018 const WCHAR* end = &str[charLen];
1029 const WCHAR wc = winpr_Data_Get_UINT16(p);