FreeRDP
Loading...
Searching...
No Matches
winpr/libwinpr/crt/string.c
1
20#include <winpr/config.h>
21#include <winpr/assert.h>
22
23#include <string.h>
24#include <errno.h>
25#include <stdio.h>
26#include <ctype.h>
27#include <wctype.h>
28#include <wchar.h>
29
30#include <winpr/crt.h>
31#include <winpr/endian.h>
32
33#if defined(WITH_URIPARSER)
34#include <uriparser/Uri.h>
35#endif
36
37#if defined(WINPR_HAVE_REGCOMP)
38#include <regex.h>
39#endif
40
41/* String Manipulation (CRT): http://msdn.microsoft.com/en-us/library/f0151s4x.aspx */
42
43#include "../log.h"
44#define TAG WINPR_TAG("crt")
45
46#if defined(WITH_URIPARSER)
47BOOL winpr_str_is_valid_urlN(const char* str, size_t len)
48{
49 if (!str || (len == 0))
50 return FALSE;
51
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;
57}
58
59BOOL winpr_str_is_valid_url(const char* str)
60{
61 if (!str)
62 return FALSE;
63
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;
69}
70
71char* winpr_str_url_decode(const char* str, size_t len)
72{
73 char* dst = strndup(str, len);
74 if (!dst)
75 return nullptr;
76
77 if (!uriUnescapeInPlaceExA(dst, URI_FALSE, URI_BR_DONT_TOUCH))
78 {
79 free(dst);
80 return nullptr;
81 }
82
83 return dst;
84}
85
86char* winpr_str_url_encode(const char* str, size_t len)
87{
88 char* dst = calloc(len + 1, sizeof(char) * 3);
89 if (!dst)
90 return nullptr;
91
92 if (!uriEscapeA(str, dst, URI_FALSE, URI_FALSE))
93 {
94 free(dst);
95 return nullptr;
96 }
97 return dst;
98}
99
100#else
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,
118};
119
120static char hex2bin(char what)
121{
122 if (what >= 'a')
123 what -= 'a' - 'A';
124 if (what >= 'A')
125 what -= ('A' - 10);
126 else
127 what -= '0';
128 return what;
129}
130
131static char unescape(const char* what, size_t* px)
132{
133 if ((*what == '%') && (isxdigit(what[1]) && isxdigit(what[2])))
134 {
135 *px += 2;
136 return 16 * hex2bin(what[1]) + hex2bin(what[2]);
137 }
138
139 return *what;
140}
141
142char* winpr_str_url_decode(const char* str, size_t len)
143{
144 char* dst = calloc(len + 1, sizeof(char));
145 if (!dst)
146 return nullptr;
147
148 size_t pos = 0;
149 for (size_t x = 0; x < strnlen(str, len); x++)
150 {
151 const char* cur = &str[x];
152 dst[pos++] = unescape(cur, &x);
153 }
154 return dst;
155}
156
157WINPR_ATTR_NODISCARD
158static char* escape(char* dst, char what)
159{
160 if (rfc3986[what & 0xff])
161 {
162 *dst = what;
163 return dst + 1;
164 }
165
166 if (sprintf(dst, "%%%02" PRIX8, (BYTE)(what & 0xff)) < 0)
167 return nullptr;
168 return dst + 3;
169}
170
171char* winpr_str_url_encode(const char* str, size_t len)
172{
173 char* dst = calloc(len + 1, sizeof(char) * 3);
174 if (!dst)
175 return nullptr;
176
177 char* ptr = dst;
178 for (size_t x = 0; x < strnlen(str, len); x++)
179 {
180 const char cur = str[x];
181 ptr = escape(ptr, cur);
182 }
183 return dst;
184}
185
186BOOL winpr_str_is_valid_urlN(const char* str, size_t len)
187{
188 if (!str || (len == 0))
189 return FALSE;
190
191 char* url = strndup(str, len);
192 if (!url)
193 return FALSE;
194
195 const BOOL rc = winpr_str_is_valid_url(url);
196 free(url);
197 return rc;
198}
199
200#if defined(_WIN32)
201#include <shlwapi.h>
202
203BOOL winpr_str_is_valid_url(const char* str)
204{
205 if (!str)
206 return FALSE;
207 return PathIsURLA(str);
208}
209
210#elif defined(WINPR_HAVE_REGCOMP)
211BOOL winpr_str_is_valid_url(const char* str)
212{
213 if (!str)
214 return FALSE;
215 regex_t regex = WINPR_C_ARRAY_INIT;
216 const char pattern[] = "^([a-z]+://)?([a-zA-Z0-9.-]+)(:[0-9]+)?(/[a-zA-Z0-9./?=&%-]*)?$";
217
218 int ret = regcomp(&regex, pattern, REG_EXTENDED);
219 if (ret)
220 {
221 printf("Could not compile regex\n");
222 return FALSE;
223 }
224
225 ret = regexec(&regex, str, 0, nullptr, 0);
226 regfree(&regex);
227 return ret == 0;
228}
229
230#else
231BOOL winpr_str_is_valid_url(WINPR_ATTR_UNUSED const char* str)
232{
233 WLog_WARN(TAG, "URL validation not supported by your build, not performing check. Build with "
234 "-DWITH_URIPARSER=ON to fix.");
235 return TRUE;
236}
237#endif
238#endif
239
240BOOL winpr_str_append(const char* what, char* buffer, size_t size, const char* separator)
241{
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;
246
247 if (used + add + sep >= size)
248 return FALSE;
249
250 if ((used > 0) && (sep_len > 0))
251 strncat(buffer, separator, sep_len);
252
253 strncat(buffer, what, add);
254 return TRUE;
255}
256
257WINPR_ATTR_FORMAT_ARG(3, 4)
258int winpr_asprintf(char** s, size_t* slen, WINPR_FORMAT_ARG const char* templ, ...)
259{
260 va_list ap = WINPR_C_ARRAY_INIT;
261
262 va_start(ap, templ);
263 int rc = winpr_vasprintf(s, slen, templ, ap);
264 va_end(ap);
265 return rc;
266}
267
268WINPR_ATTR_FORMAT_ARG(3, 0)
269int winpr_vasprintf(char** s, size_t* slen, WINPR_FORMAT_ARG const char* templ, va_list oap)
270{
271 va_list ap = WINPR_C_ARRAY_INIT;
272
273 *s = nullptr;
274 *slen = 0;
275
276 va_copy(ap, oap);
277 const int length = vsnprintf(nullptr, 0, templ, ap);
278 va_end(ap);
279 if (length < 0)
280 return length;
281
282 char* str = calloc((size_t)length + 1UL, sizeof(char));
283 if (!str)
284 return -1;
285
286 va_copy(ap, oap);
287 const int plen = vsnprintf(str, (size_t)length + 1UL, templ, ap);
288 va_end(ap);
289
290 if (length != plen)
291 {
292 free(str);
293 return -1;
294 }
295 *s = str;
296 *slen = (size_t)length;
297 return length;
298}
299
300#ifndef _WIN32
301
302char* _strdup(const char* strSource)
303{
304 if (strSource == nullptr)
305 return nullptr;
306
307 char* strDestination = strdup(strSource);
308
309 if (strDestination == nullptr)
310 WLog_ERR(TAG, "strdup");
311
312 return strDestination;
313}
314
315WCHAR* _wcsdup(const WCHAR* strSource)
316{
317 if (!strSource)
318 return nullptr;
319
320 size_t len = _wcslen(strSource);
321 WCHAR* strDestination = calloc(len + 1, sizeof(WCHAR));
322
323 if (strDestination != nullptr)
324 memcpy(strDestination, strSource, len * sizeof(WCHAR));
325
326 if (strDestination == nullptr)
327 WLog_ERR(TAG, "wcsdup");
328
329 return strDestination;
330}
331
332WCHAR* _wcsncat(WCHAR* dst, const WCHAR* src, size_t sz)
333{
334 WINPR_ASSERT(dst);
335 WINPR_ASSERT(src || (sz == 0));
336
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';
342 return dst;
343}
344
345int _stricmp(const char* string1, const char* string2)
346{
347 return strcasecmp(string1, string2);
348}
349
350int _strnicmp(const char* string1, const char* string2, size_t count)
351{
352 return strncasecmp(string1, string2, count);
353}
354
355/* _wcscmp -> wcscmp */
356
357int _wcscmp(const WCHAR* string1, const WCHAR* string2)
358{
359 WINPR_ASSERT(string1);
360 WINPR_ASSERT(string2);
361
362 while (TRUE)
363 {
364 const WCHAR w1 = *string1++;
365 const WCHAR w2 = *string2++;
366
367 if (w1 != w2)
368 return (int)w1 - w2;
369 else if ((w1 == '\0') || (w2 == '\0'))
370 return (int)w1 - w2;
371 }
372}
373
374int _wcsncmp(const WCHAR* string1, const WCHAR* string2, size_t count)
375{
376 WINPR_ASSERT(string1);
377 WINPR_ASSERT(string2);
378
379 for (size_t x = 0; x < count; x++)
380 {
381 const WCHAR a = string1[x];
382 const WCHAR b = string2[x];
383
384 if (a != b)
385 return (int)a - b;
386 else if ((a == '\0') || (b == '\0'))
387 return (int)a - b;
388 }
389 return 0;
390}
391
392/* _wcslen -> wcslen */
393
394size_t _wcslen(const WCHAR* str)
395{
396 const WCHAR* p = str;
397
398 WINPR_ASSERT(p);
399
400 while (*p)
401 p++;
402
403 return (size_t)(p - str);
404}
405
406/* _wcsnlen -> wcsnlen */
407
408size_t _wcsnlen(const WCHAR* str, size_t max)
409{
410 WINPR_ASSERT(str);
411
412 size_t x = 0;
413 for (; x < max; x++)
414 {
415 if (str[x] == 0)
416 return x;
417 }
418
419 return x;
420}
421
422/* _wcsstr -> wcsstr */
423
424WCHAR* _wcsstr(const WCHAR* str, const WCHAR* strSearch)
425{
426 WINPR_ASSERT(str);
427 WINPR_ASSERT(strSearch);
428
429 if (strSearch[0] == '\0')
430 return WINPR_CAST_CONST_PTR_AWAY(str, WCHAR*);
431
432 const size_t searchLen = _wcslen(strSearch);
433 while (*str)
434 {
435 if (_wcsncmp(str, strSearch, searchLen) == 0)
436 return WINPR_CAST_CONST_PTR_AWAY(str, WCHAR*);
437 str++;
438 }
439 return nullptr;
440}
441
442/* _wcschr -> wcschr */
443#if defined(WITHOUT_WINPR_3x_DEPRECATED)
444static
445#endif
446 WCHAR* _wcschr(const WCHAR* str, WCHAR c)
447{
448 union
449 {
450 const WCHAR* cc;
451 WCHAR* c;
452 } cnv;
453 const WCHAR* p = str;
454
455 while (*p && (*p != c))
456 p++;
457
458 cnv.cc = (*p == c) ? p : nullptr;
459 return cnv.c;
460}
461
462/* _wcsrchr -> wcsrchr */
463#if !defined(WITHOUT_WINPR_3x_DEPRECATED)
464WCHAR* _wcsrchr(const WCHAR* str, WCHAR c)
465{
466 union
467 {
468 const WCHAR* cc;
469 WCHAR* c;
470 } cnv;
471 const WCHAR* p = nullptr;
472
473 if (!str)
474 return nullptr;
475
476 for (; *str != '\0'; str++)
477 {
478 const WCHAR ch = *str;
479 if (ch == c)
480 p = str;
481 }
482
483 cnv.cc = p;
484 return cnv.c;
485}
486#endif
487
488char* strtok_s(char* strToken, const char* strDelimit, char** context)
489{
490 return strtok_r(strToken, strDelimit, context);
491}
492
493WCHAR* wcstok_s(WCHAR* strToken, const WCHAR* strDelimit, WCHAR** context)
494{
495 WCHAR* nextToken = nullptr;
496 WCHAR value = 0;
497
498 if (!strToken)
499 strToken = *context;
500
501 value = *strToken;
502
503 while (*strToken && _wcschr(strDelimit, value))
504 {
505 strToken++;
506 value = *strToken;
507 }
508
509 if (!*strToken)
510 return nullptr;
511
512 nextToken = strToken++;
513 value = *strToken;
514
515 while (*strToken && !(_wcschr(strDelimit, value)))
516 {
517 strToken++;
518 value = *strToken;
519 }
520
521 if (*strToken)
522 *strToken++ = 0;
523
524 *context = strToken;
525 return nextToken;
526}
527
528#endif
529
530#if !defined(_WIN32) || defined(_UWP)
531
532/* Windows API Sets - api-ms-win-core-string-l2-1-0.dll
533 * http://msdn.microsoft.com/en-us/library/hh802935/
534 */
535
536#include "casing.h"
537
538LPSTR CharUpperA(LPSTR lpsz)
539{
540 size_t length = 0;
541
542 if (!lpsz)
543 return nullptr;
544
545 length = strlen(lpsz);
546
547 if (length < 1)
548 return (LPSTR) nullptr;
549
550 if (length == 1)
551 {
552 char c = *lpsz;
553
554 if ((c >= 'a') && (c <= 'z'))
555 c = (char)(c - 'a' + 'A');
556
557 *lpsz = c;
558 return lpsz;
559 }
560
561 for (size_t i = 0; i < length; i++)
562 {
563 if ((lpsz[i] >= 'a') && (lpsz[i] <= 'z'))
564 lpsz[i] = (char)(lpsz[i] - 'a' + 'A');
565 }
566
567 return lpsz;
568}
569
570LPWSTR CharUpperW(LPWSTR lpsz)
571{
572 size_t length = 0;
573
574 if (!lpsz)
575 return nullptr;
576
577 length = _wcslen(lpsz);
578
579 if (length < 1)
580 return (LPWSTR) nullptr;
581
582 if (length == 1)
583 {
584 WCHAR c = *lpsz;
585
586 if ((c >= L'a') && (c <= L'z'))
587 c = c - L'a' + L'A';
588
589 *lpsz = c;
590 return lpsz;
591 }
592
593 for (size_t i = 0; i < length; i++)
594 {
595 if ((lpsz[i] >= L'a') && (lpsz[i] <= L'z'))
596 lpsz[i] = lpsz[i] - L'a' + L'A';
597 }
598
599 return lpsz;
600}
601
602DWORD CharUpperBuffA(LPSTR lpsz, DWORD cchLength)
603{
604 if (cchLength < 1)
605 return 0;
606
607 for (DWORD i = 0; i < cchLength; i++)
608 {
609 if ((lpsz[i] >= 'a') && (lpsz[i] <= 'z'))
610 lpsz[i] = (char)(lpsz[i] - 'a' + 'A');
611 }
612
613 return cchLength;
614}
615
616DWORD CharUpperBuffW(LPWSTR lpsz, DWORD cchLength)
617{
618 for (DWORD i = 0; i < cchLength; i++)
619 {
620 WCHAR value = winpr_Data_Get_UINT16(&lpsz[i]);
621 value = WINPR_TOUPPERW(value);
622 winpr_Data_Write_UINT16(&lpsz[i], value);
623 }
624
625 return cchLength;
626}
627
628LPSTR CharLowerA(LPSTR lpsz)
629{
630 size_t length = 0;
631
632 if (!lpsz)
633 return (LPSTR) nullptr;
634
635 length = strlen(lpsz);
636
637 if (length < 1)
638 return (LPSTR) nullptr;
639
640 if (length == 1)
641 {
642 char c = *lpsz;
643
644 if ((c >= 'A') && (c <= 'Z'))
645 c = (char)(c - 'A' + 'a');
646
647 *lpsz = c;
648 return lpsz;
649 }
650
651 for (size_t i = 0; i < length; i++)
652 {
653 if ((lpsz[i] >= 'A') && (lpsz[i] <= 'Z'))
654 lpsz[i] = (char)(lpsz[i] - 'A' + 'a');
655 }
656
657 return lpsz;
658}
659
660LPWSTR CharLowerW(LPWSTR lpsz)
661{
662 const size_t len = _wcsnlen(lpsz, UINT32_MAX + 1);
663 if (len > UINT32_MAX)
664 return nullptr;
665 CharLowerBuffW(lpsz, (UINT32)len);
666 return lpsz;
667}
668
669DWORD CharLowerBuffA(LPSTR lpsz, DWORD cchLength)
670{
671 if (cchLength < 1)
672 return 0;
673
674 for (DWORD i = 0; i < cchLength; i++)
675 {
676 if ((lpsz[i] >= 'A') && (lpsz[i] <= 'Z'))
677 lpsz[i] = (char)(lpsz[i] - 'A' + 'a');
678 }
679
680 return cchLength;
681}
682
683DWORD CharLowerBuffW(LPWSTR lpsz, DWORD cchLength)
684{
685 for (DWORD i = 0; i < cchLength; i++)
686 {
687 WCHAR value = winpr_Data_Get_UINT16(&lpsz[i]);
688 value = WINPR_TOLOWERW(value);
689 winpr_Data_Write_UINT16(&lpsz[i], value);
690 }
691
692 return cchLength;
693}
694
695BOOL IsCharAlphaA(CHAR ch)
696{
697 if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')))
698 return 1;
699 else
700 return 0;
701}
702
703BOOL IsCharAlphaW(WCHAR ch)
704{
705 if (((ch >= L'a') && (ch <= L'z')) || ((ch >= L'A') && (ch <= L'Z')))
706 return 1;
707 else
708 return 0;
709}
710
711BOOL IsCharAlphaNumericA(CHAR ch)
712{
713 if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) ||
714 ((ch >= '0') && (ch <= '9')))
715 return 1;
716 else
717 return 0;
718}
719
720BOOL IsCharAlphaNumericW(WCHAR ch)
721{
722 if (((ch >= L'a') && (ch <= L'z')) || ((ch >= L'A') && (ch <= L'Z')) ||
723 ((ch >= L'0') && (ch <= L'9')))
724 return 1;
725 else
726 return 0;
727}
728
729BOOL IsCharUpperA(CHAR ch)
730{
731 if ((ch >= 'A') && (ch <= 'Z'))
732 return 1;
733 else
734 return 0;
735}
736
737BOOL IsCharUpperW(WCHAR ch)
738{
739 if ((ch >= L'A') && (ch <= L'Z'))
740 return 1;
741 else
742 return 0;
743}
744
745BOOL IsCharLowerA(CHAR ch)
746{
747 if ((ch >= 'a') && (ch <= 'z'))
748 return 1;
749 else
750 return 0;
751}
752
753BOOL IsCharLowerW(WCHAR ch)
754{
755 if ((ch >= L'a') && (ch <= L'z'))
756 return 1;
757 else
758 return 0;
759}
760
761#endif
762
763size_t ConvertLineEndingToLF(char* str, size_t size)
764{
765 size_t skip = 0;
766
767 WINPR_ASSERT(str || (size == 0));
768 for (size_t x = 0; x < size; x++)
769 {
770 char c = str[x];
771 switch (c)
772 {
773 case '\r':
774 str[x - skip] = '\n';
775 if ((x + 1 < size) && (str[x + 1] == '\n'))
776 skip++;
777 break;
778 default:
779 str[x - skip] = c;
780 break;
781 }
782 }
783 return size - skip;
784}
785
786char* ConvertLineEndingToCRLF(const char* str, size_t* size)
787{
788 WINPR_ASSERT(size);
789 const size_t s = *size;
790 WINPR_ASSERT(str || (s == 0));
791
792 *size = 0;
793 if (s == 0)
794 return nullptr;
795
796 size_t linebreaks = 0;
797 for (size_t x = 0; x < s - 1; x++)
798 {
799 char c = str[x];
800 switch (c)
801 {
802 case '\r':
803 case '\n':
804 linebreaks++;
805 break;
806 default:
807 break;
808 }
809 }
810 char* cnv = calloc(s + linebreaks * 2ull + 1ull, sizeof(char));
811 if (!cnv)
812 return nullptr;
813
814 size_t pos = 0;
815 for (size_t x = 0; x < s; x++)
816 {
817 const char c = str[x];
818 switch (c)
819 {
820 case '\r':
821 cnv[pos++] = '\r';
822 cnv[pos++] = '\n';
823 break;
824 case '\n':
825 /* Do not duplicate existing \r\n sequences */
826 if ((x > 0) && (str[x - 1] != '\r'))
827 {
828 cnv[pos++] = '\r';
829 cnv[pos++] = '\n';
830 }
831 break;
832 default:
833 cnv[pos++] = c;
834 break;
835 }
836 }
837 *size = pos;
838 return cnv;
839}
840
841char* StrSep(char** stringp, const char* delim)
842{
843 char* start = *stringp;
844 char* p = nullptr;
845 p = (start != nullptr) ? strpbrk(start, delim) : nullptr;
846
847 if (!p)
848 *stringp = nullptr;
849 else
850 {
851 *p = '\0';
852 *stringp = p + 1;
853 }
854
855 return start;
856}
857
858INT64 GetLine(char** lineptr, size_t* size, FILE* stream)
859{
860#if defined(_WIN32)
861 char c;
862 char* n;
863 size_t step = 32;
864 size_t used = 0;
865
866 if (!lineptr || !size)
867 {
868 errno = EINVAL;
869 return -1;
870 }
871
872 do
873 {
874 if (used + 2 >= *size)
875 {
876 *size += step;
877 n = realloc(*lineptr, *size);
878
879 if (!n)
880 {
881 return -1;
882 }
883
884 *lineptr = n;
885 }
886
887 c = fgetc(stream);
888
889 if (c != EOF)
890 (*lineptr)[used++] = c;
891 } while ((c != '\n') && (c != '\r') && (c != EOF));
892
893 (*lineptr)[used] = '\0';
894 return used;
895#elif !defined(ANDROID) && !defined(IOS)
896 return getline(lineptr, size, stream);
897#else
898 return -1;
899#endif
900}
901
902#if !defined(WINPR_HAVE_STRNDUP)
903char* strndup(const char* src, size_t n)
904{
905 char* dst = calloc(n + 1, sizeof(char));
906 if (dst)
907 strncpy(dst, src, n);
908 return dst;
909}
910#endif
911
912const WCHAR* InitializeConstWCharFromUtf8(const char* str, WCHAR* buffer, size_t len)
913{
914 WINPR_ASSERT(str);
915 WINPR_ASSERT(buffer || (len == 0));
916 (void)ConvertUtf8ToWChar(str, buffer, len);
917 return buffer;
918}
919
920WCHAR* wcsndup(const WCHAR* s, size_t n)
921{
922 if (!s)
923 return nullptr;
924
925 WCHAR* copy = calloc(n + 1, sizeof(WCHAR));
926 if (!copy)
927 return nullptr;
928 memcpy(copy, s, n * sizeof(WCHAR));
929 return copy;
930}
931
932char* winpr_strnstr(const char* haystack, const char* needle, size_t hlen)
933{
934 WINPR_ASSERT(haystack || (hlen == 0));
935 WINPR_ASSERT(needle);
936
937#if defined(WINPR_HAVE_STRNSTR)
938 return strnstr(haystack, needle, hlen);
939#else
940 /* Match native strnstr semantics: search at most hlen characters and stop at
941 * the haystack NUL terminator, whichever comes first. */
942 const size_t needle_len = strlen(needle);
943
944 if (0 == needle_len)
945 return WINPR_CAST_CONST_PTR_AWAY(haystack, char*);
946
947 for (; (*haystack != '\0') && (hlen >= needle_len); haystack++, hlen--)
948 {
949 if ((haystack[0] == needle[0]) && (0 == strncmp(haystack, needle, needle_len)))
950 return WINPR_CAST_CONST_PTR_AWAY(haystack, char*);
951 }
952 return nullptr;
953#endif
954}
955
956BOOL winpr_str_has_newlines(const char* str)
957{
958 if (!str)
959 return FALSE;
960 do
961 {
962 char c = *str++;
963 switch (c)
964 {
965 case '\r':
966 case '\n':
967 case 0x0b: /* VT vertical tab */
968 case 0x0c: /* FF form feed */
969 case (char)0x85: /* NEL next line */
970 return TRUE;
971 case (char)0xE2:
972 {
973 if ((str[0] == (char)0x80) && ((str[1] == (char)0xA8) || (str[1] == (char)0xA9)))
974 return TRUE;
975 }
976 break;
977
978 case '\0':
979 return FALSE;
980 default:
981 break;
982 }
983 } while (1);
984}
985
986WCHAR* winpr_wcsnchr(const WCHAR* str, size_t charLen, WCHAR c)
987{
988 if (!str || (charLen == 0))
989 return nullptr;
990
991 const WCHAR* p = str;
992 const WCHAR* end = &str[charLen];
993
994 while (p != end)
995 {
996 const WCHAR wc = winpr_Data_Get_UINT16(p);
997 if (wc == c)
998 {
999 union
1000 {
1001 WCHAR* w;
1002 const WCHAR* cw;
1003 } cnv;
1004 cnv.cw = p;
1005 return cnv.w;
1006 }
1007 p++;
1008 }
1009 return nullptr;
1010}
1011
1012WCHAR* winpr_wcsnrchr(const WCHAR* str, size_t charLen, WCHAR c)
1013{
1014 if (!str || (charLen == 0))
1015 return nullptr;
1016
1017 const WCHAR* p = str;
1018 const WCHAR* end = &str[charLen];
1019
1020 union
1021 {
1022 WCHAR* w;
1023 const WCHAR* cw;
1024 } cnv;
1025
1026 cnv.cw = nullptr;
1027 while (p != end)
1028 {
1029 const WCHAR wc = winpr_Data_Get_UINT16(p);
1030 if (wc == c)
1031 cnv.cw = p;
1032 p++;
1033 }
1034 return cnv.w;
1035}