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);
157static char* escape(
char* dst,
char what)
159 if (rfc3986[what & 0xff])
165 sprintf(dst,
"%%%02" PRIX8, (BYTE)(what & 0xff));
169char* winpr_str_url_encode(
const char* str,
size_t len)
171 char* dst = calloc(len + 1,
sizeof(
char) * 3);
176 for (
size_t x = 0; x < strnlen(str, len); x++)
178 const char cur = str[x];
179 ptr = escape(ptr, cur);
184BOOL winpr_str_is_valid_urlN(
const char* str,
size_t len)
186 if (!str || (len == 0))
189 char* url = strndup(str, len);
193 const BOOL rc = winpr_str_is_valid_url(url);
201BOOL winpr_str_is_valid_url(
const char* str)
205 return PathIsURLA(str);
208#elif defined(WINPR_HAVE_REGCOMP)
209BOOL winpr_str_is_valid_url(
const char* str)
213 regex_t regex = WINPR_C_ARRAY_INIT;
214 const char pattern[] =
"^([a-z]+://)?([a-zA-Z0-9.-]+)(:[0-9]+)?(/[a-zA-Z0-9./?=&%-]*)?$";
216 int ret = regcomp(®ex, pattern, REG_EXTENDED);
219 printf(
"Could not compile regex\n");
223 ret = regexec(®ex, str, 0,
nullptr, 0);
229BOOL winpr_str_is_valid_url(WINPR_ATTR_UNUSED
const char* str)
231 WLog_WARN(TAG,
"URL validation not supported by your build, not performing check. Build with "
232 "-DWITH_URIPARSER=ON to fix.");
238BOOL winpr_str_append(
const char* what,
char* buffer,
size_t size,
const char* separator)
240 const size_t used = strnlen(buffer, size);
241 const size_t add = strnlen(what, size);
242 const size_t sep_len = separator ? strnlen(separator, size) : 0;
243 const size_t sep = (used > 0) ? sep_len : 0;
245 if (used + add + sep >= size)
248 if ((used > 0) && (sep_len > 0))
249 strncat(buffer, separator, sep_len);
251 strncat(buffer, what, add);
255WINPR_ATTR_FORMAT_ARG(3, 4)
256int winpr_asprintf(
char** s,
size_t* slen, WINPR_FORMAT_ARG const
char* templ, ...)
258 va_list ap = WINPR_C_ARRAY_INIT;
261 int rc = winpr_vasprintf(s, slen, templ, ap);
266WINPR_ATTR_FORMAT_ARG(3, 0)
267int winpr_vasprintf(
char** s,
size_t* slen, WINPR_FORMAT_ARG const
char* templ, va_list oap)
269 va_list ap = WINPR_C_ARRAY_INIT;
275 const int length = vsnprintf(
nullptr, 0, templ, ap);
280 char* str = calloc((
size_t)length + 1UL,
sizeof(
char));
285 const int plen = vsnprintf(str, (
size_t)length + 1UL, templ, ap);
294 *slen = (size_t)length;
300char* _strdup(
const char* strSource)
302 if (strSource ==
nullptr)
305 char* strDestination = strdup(strSource);
307 if (strDestination ==
nullptr)
308 WLog_ERR(TAG,
"strdup");
310 return strDestination;
313WCHAR* _wcsdup(
const WCHAR* strSource)
318 size_t len = _wcslen(strSource);
319 WCHAR* strDestination = calloc(len + 1,
sizeof(WCHAR));
321 if (strDestination !=
nullptr)
322 memcpy(strDestination, strSource, len *
sizeof(WCHAR));
324 if (strDestination ==
nullptr)
325 WLog_ERR(TAG,
"wcsdup");
327 return strDestination;
330WCHAR* _wcsncat(WCHAR* dst,
const WCHAR* src,
size_t sz)
333 WINPR_ASSERT(src || (sz == 0));
335 const size_t dlen = _wcslen(dst);
336 const size_t slen = _wcsnlen(src, sz);
337 for (
size_t x = 0; x < slen; x++)
338 dst[dlen + x] = src[x];
339 dst[dlen + slen] =
'\0';
343int _stricmp(
const char* string1,
const char* string2)
345 return strcasecmp(string1, string2);
348int _strnicmp(
const char* string1,
const char* string2,
size_t count)
350 return strncasecmp(string1, string2, count);
355int _wcscmp(
const WCHAR* string1,
const WCHAR* string2)
357 WINPR_ASSERT(string1);
358 WINPR_ASSERT(string2);
362 const WCHAR w1 = *string1++;
363 const WCHAR w2 = *string2++;
367 else if ((w1 ==
'\0') || (w2 ==
'\0'))
372int _wcsncmp(
const WCHAR* string1,
const WCHAR* string2,
size_t count)
374 WINPR_ASSERT(string1);
375 WINPR_ASSERT(string2);
377 for (
size_t x = 0; x < count; x++)
379 const WCHAR a = string1[x];
380 const WCHAR b = string2[x];
384 else if ((a ==
'\0') || (b ==
'\0'))
392size_t _wcslen(
const WCHAR* str)
394 const WCHAR* p = str;
401 return (
size_t)(p - str);
406size_t _wcsnlen(
const WCHAR* str,
size_t max)
422WCHAR* _wcsstr(
const WCHAR* str,
const WCHAR* strSearch)
425 WINPR_ASSERT(strSearch);
427 if (strSearch[0] ==
'\0')
428 return WINPR_CAST_CONST_PTR_AWAY(str, WCHAR*);
430 const size_t searchLen = _wcslen(strSearch);
433 if (_wcsncmp(str, strSearch, searchLen) == 0)
434 return WINPR_CAST_CONST_PTR_AWAY(str, WCHAR*);
442WCHAR* _wcschr(
const WCHAR* str, WCHAR c)
449 const WCHAR* p = str;
451 while (*p && (*p != c))
454 cnv.cc = (*p == c) ? p : nullptr;
460WCHAR* _wcsrchr(
const WCHAR* str, WCHAR c)
467 const WCHAR* p =
nullptr;
472 for (; *str !=
'\0'; str++)
474 const WCHAR ch = *str;
483char* strtok_s(
char* strToken,
const char* strDelimit,
char** context)
485 return strtok_r(strToken, strDelimit, context);
488WCHAR* wcstok_s(WCHAR* strToken,
const WCHAR* strDelimit, WCHAR** context)
490 WCHAR* nextToken =
nullptr;
498 while (*strToken && _wcschr(strDelimit, value))
507 nextToken = strToken++;
510 while (*strToken && !(_wcschr(strDelimit, value)))
525#if !defined(_WIN32) || defined(_UWP)
533LPSTR CharUpperA(LPSTR lpsz)
540 length = strlen(lpsz);
543 return (LPSTR)
nullptr;
549 if ((c >=
'a') && (c <=
'z'))
550 c = (char)(c -
'a' +
'A');
556 for (
size_t i = 0; i < length; i++)
558 if ((lpsz[i] >=
'a') && (lpsz[i] <=
'z'))
559 lpsz[i] = (char)(lpsz[i] -
'a' +
'A');
565LPWSTR CharUpperW(LPWSTR lpsz)
572 length = _wcslen(lpsz);
575 return (LPWSTR)
nullptr;
581 if ((c >= L
'a') && (c <= L
'z'))
588 for (
size_t i = 0; i < length; i++)
590 if ((lpsz[i] >= L
'a') && (lpsz[i] <= L
'z'))
591 lpsz[i] = lpsz[i] - L
'a' + L
'A';
597DWORD CharUpperBuffA(LPSTR lpsz, DWORD cchLength)
602 for (DWORD i = 0; i < cchLength; i++)
604 if ((lpsz[i] >=
'a') && (lpsz[i] <=
'z'))
605 lpsz[i] = (char)(lpsz[i] -
'a' +
'A');
611DWORD CharUpperBuffW(LPWSTR lpsz, DWORD cchLength)
613 for (DWORD i = 0; i < cchLength; i++)
615 WCHAR value = winpr_Data_Get_UINT16(&lpsz[i]);
616 value = WINPR_TOUPPERW(value);
617 winpr_Data_Write_UINT16(&lpsz[i], value);
623LPSTR CharLowerA(LPSTR lpsz)
628 return (LPSTR)
nullptr;
630 length = strlen(lpsz);
633 return (LPSTR)
nullptr;
639 if ((c >=
'A') && (c <=
'Z'))
640 c = (char)(c -
'A' +
'a');
646 for (
size_t i = 0; i < length; i++)
648 if ((lpsz[i] >=
'A') && (lpsz[i] <=
'Z'))
649 lpsz[i] = (char)(lpsz[i] -
'A' +
'a');
655LPWSTR CharLowerW(LPWSTR lpsz)
657 const size_t len = _wcsnlen(lpsz, UINT32_MAX + 1);
658 if (len > UINT32_MAX)
660 CharLowerBuffW(lpsz, (UINT32)len);
664DWORD CharLowerBuffA(LPSTR lpsz, DWORD cchLength)
669 for (DWORD i = 0; i < cchLength; i++)
671 if ((lpsz[i] >=
'A') && (lpsz[i] <=
'Z'))
672 lpsz[i] = (char)(lpsz[i] -
'A' +
'a');
678DWORD CharLowerBuffW(LPWSTR lpsz, DWORD cchLength)
680 for (DWORD i = 0; i < cchLength; i++)
682 WCHAR value = winpr_Data_Get_UINT16(&lpsz[i]);
683 value = WINPR_TOLOWERW(value);
684 winpr_Data_Write_UINT16(&lpsz[i], value);
690BOOL IsCharAlphaA(CHAR ch)
692 if (((ch >=
'a') && (ch <=
'z')) || ((ch >=
'A') && (ch <=
'Z')))
698BOOL IsCharAlphaW(WCHAR ch)
700 if (((ch >= L
'a') && (ch <= L
'z')) || ((ch >= L
'A') && (ch <= L
'Z')))
706BOOL IsCharAlphaNumericA(CHAR ch)
708 if (((ch >=
'a') && (ch <=
'z')) || ((ch >=
'A') && (ch <=
'Z')) ||
709 ((ch >=
'0') && (ch <=
'9')))
715BOOL IsCharAlphaNumericW(WCHAR ch)
717 if (((ch >= L
'a') && (ch <= L
'z')) || ((ch >= L
'A') && (ch <= L
'Z')) ||
718 ((ch >= L
'0') && (ch <= L
'9')))
724BOOL IsCharUpperA(CHAR ch)
726 if ((ch >=
'A') && (ch <=
'Z'))
732BOOL IsCharUpperW(WCHAR ch)
734 if ((ch >= L
'A') && (ch <= L
'Z'))
740BOOL IsCharLowerA(CHAR ch)
742 if ((ch >=
'a') && (ch <=
'z'))
748BOOL IsCharLowerW(WCHAR ch)
750 if ((ch >= L
'a') && (ch <= L
'z'))
758size_t ConvertLineEndingToLF(
char* str,
size_t size)
762 WINPR_ASSERT(str || (size == 0));
763 for (
size_t x = 0; x < size; x++)
769 str[x - skip] =
'\n';
770 if ((x + 1 < size) && (str[x + 1] ==
'\n'))
781char* ConvertLineEndingToCRLF(
const char* str,
size_t* size)
784 const size_t s = *size;
785 WINPR_ASSERT(str || (s == 0));
791 size_t linebreaks = 0;
792 for (
size_t x = 0; x < s - 1; x++)
805 char* cnv = calloc(s + linebreaks * 2ull + 1ull,
sizeof(
char));
810 for (
size_t x = 0; x < s; x++)
812 const char c = str[x];
821 if ((x > 0) && (str[x - 1] !=
'\r'))
836char* StrSep(
char** stringp,
const char* delim)
838 char* start = *stringp;
840 p = (start !=
nullptr) ? strpbrk(start, delim) :
nullptr;
853INT64 GetLine(
char** lineptr,
size_t* size, FILE* stream)
861 if (!lineptr || !size)
869 if (used + 2 >= *size)
872 n = realloc(*lineptr, *size);
885 (*lineptr)[used++] = c;
886 }
while ((c !=
'\n') && (c !=
'\r') && (c != EOF));
888 (*lineptr)[used] =
'\0';
890#elif !defined(ANDROID) && !defined(IOS)
891 return getline(lineptr, size, stream);
897#if !defined(WINPR_HAVE_STRNDUP)
898char* strndup(
const char* src,
size_t n)
900 char* dst = calloc(n + 1,
sizeof(
char));
902 strncpy(dst, src, n);
907const WCHAR* InitializeConstWCharFromUtf8(
const char* str, WCHAR* buffer,
size_t len)
910 WINPR_ASSERT(buffer || (len == 0));
911 (void)ConvertUtf8ToWChar(str, buffer, len);
915WCHAR* wcsndup(
const WCHAR* s,
size_t n)
920 WCHAR* copy = calloc(n + 1,
sizeof(WCHAR));
923 memcpy(copy, s, n *
sizeof(WCHAR));
927char* winpr_strnstr(
char* haystack,
const char* needle,
size_t hlen)
929 WINPR_ASSERT(haystack || (hlen == 0));
930 WINPR_ASSERT(needle);
932#if defined(WINPR_HAVE_STRNSTR)
933 return strnstr(haystack, needle, hlen);
937 const size_t needle_len = strlen(needle);
942 for (; (*haystack !=
'\0') && (hlen >= needle_len); haystack++, hlen--)
944 if ((haystack[0] == needle[0]) && (0 == strncmp(haystack, needle, needle_len)))
951BOOL winpr_str_has_newlines(
const char* str)