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