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 if (skip > 0)
784 str[size - skip] = '\0';
785 return size - skip;
786}
787
788char* ConvertLineEndingToCRLF(const char* str, size_t* size)
789{
790 WINPR_ASSERT(size);
791 const size_t s = *size;
792 WINPR_ASSERT(str || (s == 0));
793
794 *size = 0;
795 if (s == 0)
796 return nullptr;
797
798 size_t linebreaks = 0;
799 for (size_t x = 0; x < s; x++)
800 {
801 char c = str[x];
802 switch (c)
803 {
804 case '\r':
805 case '\n':
806 linebreaks++;
807 break;
808 default:
809 break;
810 }
811 }
812 char* cnv = calloc(s + linebreaks * 2ull + 1ull, sizeof(char));
813 if (!cnv)
814 return nullptr;
815
816 size_t pos = 0;
817 for (size_t x = 0; x < s; x++)
818 {
819 const char c = str[x];
820 switch (c)
821 {
822 case '\r':
823 cnv[pos++] = '\r';
824 cnv[pos++] = '\n';
825 break;
826 case '\n':
827 /* Do not duplicate existing \r\n sequences */
828 if ((x == 0) || (str[x - 1] != '\r'))
829 {
830 cnv[pos++] = '\r';
831 cnv[pos++] = '\n';
832 }
833 break;
834 default:
835 cnv[pos++] = c;
836 break;
837 }
838 }
839 *size = pos;
840 return cnv;
841}
842
843char* StrSep(char** stringp, const char* delim)
844{
845 char* start = *stringp;
846 char* p = nullptr;
847 p = (start != nullptr) ? strpbrk(start, delim) : nullptr;
848
849 if (!p)
850 *stringp = nullptr;
851 else
852 {
853 *p = '\0';
854 *stringp = p + 1;
855 }
856
857 return start;
858}
859
860INT64 GetLine(char** lineptr, size_t* size, FILE* stream)
861{
862#if defined(_WIN32)
863 char c;
864 char* n;
865 size_t step = 32;
866 size_t used = 0;
867
868 if (!lineptr || !size)
869 {
870 errno = EINVAL;
871 return -1;
872 }
873
874 do
875 {
876 if (used + 2 >= *size)
877 {
878 *size += step;
879 n = realloc(*lineptr, *size);
880
881 if (!n)
882 {
883 return -1;
884 }
885
886 *lineptr = n;
887 }
888
889 c = fgetc(stream);
890
891 if (c != EOF)
892 (*lineptr)[used++] = c;
893 } while ((c != '\n') && (c != '\r') && (c != EOF));
894
895 (*lineptr)[used] = '\0';
896 return used;
897#elif !defined(ANDROID) && !defined(IOS)
898 return getline(lineptr, size, stream);
899#else
900 return -1;
901#endif
902}
903
904#if !defined(WINPR_HAVE_STRNDUP)
905char* strndup(const char* src, size_t n)
906{
907 char* dst = calloc(n + 1, sizeof(char));
908 if (dst)
909 strncpy(dst, src, n);
910 return dst;
911}
912#endif
913
914const WCHAR* InitializeConstWCharFromUtf8(const char* str, WCHAR* buffer, size_t len)
915{
916 WINPR_ASSERT(str);
917 WINPR_ASSERT(buffer || (len == 0));
918 (void)ConvertUtf8ToWChar(str, buffer, len);
919 return buffer;
920}
921
922WCHAR* wcsndup(const WCHAR* s, size_t n)
923{
924 if (!s)
925 return nullptr;
926
927 WCHAR* copy = calloc(n + 1, sizeof(WCHAR));
928 if (!copy)
929 return nullptr;
930 memcpy(copy, s, n * sizeof(WCHAR));
931 return copy;
932}
933
934char* winpr_strnstr(const char* haystack, const char* needle, size_t hlen)
935{
936 WINPR_ASSERT(haystack || (hlen == 0));
937 WINPR_ASSERT(needle);
938
939#if defined(WINPR_HAVE_STRNSTR)
940 return strnstr(haystack, needle, hlen);
941#else
942 /* Match native strnstr semantics: search at most hlen characters and stop at
943 * the haystack NUL terminator, whichever comes first. */
944 const size_t needle_len = strlen(needle);
945
946 if (0 == needle_len)
947 return WINPR_CAST_CONST_PTR_AWAY(haystack, char*);
948
949 for (; (*haystack != '\0') && (hlen >= needle_len); haystack++, hlen--)
950 {
951 if ((haystack[0] == needle[0]) && (0 == strncmp(haystack, needle, needle_len)))
952 return WINPR_CAST_CONST_PTR_AWAY(haystack, char*);
953 }
954 return nullptr;
955#endif
956}
957
958BOOL winpr_str_has_newlines(const char* str)
959{
960 if (!str)
961 return FALSE;
962 do
963 {
964 char c = *str++;
965 switch (c)
966 {
967 case '\r':
968 case '\n':
969 case 0x0b: /* VT vertical tab */
970 case 0x0c: /* FF form feed */
971 case (char)0x85: /* NEL next line */
972 return TRUE;
973 case (char)0xE2:
974 {
975 if ((str[0] == (char)0x80) && ((str[1] == (char)0xA8) || (str[1] == (char)0xA9)))
976 return TRUE;
977 }
978 break;
979
980 case '\0':
981 return FALSE;
982 default:
983 break;
984 }
985 } while (1);
986}
987
988WCHAR* winpr_wcsnchr(const WCHAR* str, size_t charLen, WCHAR c)
989{
990 if (!str || (charLen == 0))
991 return nullptr;
992
993 const WCHAR* p = str;
994 const WCHAR* end = &str[charLen];
995
996 while (p != end)
997 {
998 const WCHAR wc = winpr_Data_Get_UINT16(p);
999 if (wc == c)
1000 {
1001 union
1002 {
1003 WCHAR* w;
1004 const WCHAR* cw;
1005 } cnv;
1006 cnv.cw = p;
1007 return cnv.w;
1008 }
1009 p++;
1010 }
1011 return nullptr;
1012}
1013
1014WCHAR* winpr_wcsnrchr(const WCHAR* str, size_t charLen, WCHAR c)
1015{
1016 if (!str || (charLen == 0))
1017 return nullptr;
1018
1019 const WCHAR* p = str;
1020 const WCHAR* end = &str[charLen];
1021
1022 union
1023 {
1024 WCHAR* w;
1025 const WCHAR* cw;
1026 } cnv;
1027
1028 cnv.cw = nullptr;
1029 while (p != end)
1030 {
1031 const WCHAR wc = winpr_Data_Get_UINT16(p);
1032 if (wc == c)
1033 cnv.cw = p;
1034 p++;
1035 }
1036 return cnv.w;
1037}