FreeRDP
Loading...
Searching...
No Matches
winpr/libwinpr/crt/string.c
1
20#include <winpr/config.h>
21#include <winpr/assert.h>
22
23#include <errno.h>
24#include <stdio.h>
25#include <ctype.h>
26#include <wctype.h>
27#include <wchar.h>
28
29#include <winpr/crt.h>
30#include <winpr/endian.h>
31
32#if defined(WITH_URIPARSER)
33#include <uriparser/Uri.h>
34#endif
35
36/* String Manipulation (CRT): http://msdn.microsoft.com/en-us/library/f0151s4x.aspx */
37
38#include "../log.h"
39#define TAG WINPR_TAG("crt")
40
41#if defined(WITH_URIPARSER)
42char* winpr_str_url_decode(const char* str, size_t len)
43{
44 char* dst = strndup(str, len);
45 if (!dst)
46 return NULL;
47
48 if (!uriUnescapeInPlaceExA(dst, URI_FALSE, URI_FALSE))
49 {
50 free(dst);
51 return NULL;
52 }
53
54 return dst;
55}
56
57char* winpr_str_url_encode(const char* str, size_t len)
58{
59 char* dst = calloc(len + 1, sizeof(char) * 3);
60 if (!dst)
61 return NULL;
62
63 if (!uriEscapeA(str, dst, URI_FALSE, URI_FALSE))
64 {
65 free(dst);
66 return NULL;
67 }
68 return dst;
69}
70
71#else
72static const char rfc3986[] = {
73 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
74 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
75 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x2e, 0x00,
76 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
78 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x5f,
79 0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
80 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x00, 0x00, 0x00, 0x7e, 0x00,
81 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
82 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
83 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
84 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
85 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
86 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
87 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
88 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
89};
90
91static char hex2bin(char what)
92{
93 if (what >= 'a')
94 what -= 'a' - 'A';
95 if (what >= 'A')
96 what -= ('A' - 10);
97 else
98 what -= '0';
99 return what;
100}
101
102static char unescape(const char* what, size_t* px)
103{
104 if ((*what == '%') && (isxdigit(what[1]) && isxdigit(what[2])))
105 {
106 *px += 2;
107 return 16 * hex2bin(what[1]) + hex2bin(what[2]);
108 }
109
110 return *what;
111}
112
113char* winpr_str_url_decode(const char* str, size_t len)
114{
115 char* dst = calloc(len + 1, sizeof(char));
116 if (!dst)
117 return NULL;
118
119 size_t pos = 0;
120 for (size_t x = 0; x < strnlen(str, len); x++)
121 {
122 const char* cur = &str[x];
123 dst[pos++] = unescape(cur, &x);
124 }
125 return dst;
126}
127
128static char* escape(char* dst, char what)
129{
130 if (rfc3986[what & 0xff])
131 {
132 *dst = what;
133 return dst + 1;
134 }
135
136 sprintf(dst, "%%%02" PRIX8, (BYTE)(what & 0xff));
137 return dst + 3;
138}
139
140char* winpr_str_url_encode(const char* str, size_t len)
141{
142 char* dst = calloc(len + 1, sizeof(char) * 3);
143 if (!dst)
144 return NULL;
145
146 char* ptr = dst;
147 for (size_t x = 0; x < strnlen(str, len); x++)
148 {
149 const char cur = str[x];
150 ptr = escape(ptr, cur);
151 }
152 return dst;
153}
154#endif
155
156BOOL winpr_str_append(const char* what, char* buffer, size_t size, const char* separator)
157{
158 const size_t used = strnlen(buffer, size);
159 const size_t add = strnlen(what, size);
160 const size_t sep_len = separator ? strnlen(separator, size) : 0;
161 const size_t sep = (used > 0) ? sep_len : 0;
162
163 if (used + add + sep >= size)
164 return FALSE;
165
166 if ((used > 0) && (sep_len > 0))
167 strncat(buffer, separator, sep_len);
168
169 strncat(buffer, what, add);
170 return TRUE;
171}
172
173WINPR_ATTR_FORMAT_ARG(3, 4)
174int winpr_asprintf(char** s, size_t* slen, WINPR_FORMAT_ARG const char* templ, ...)
175{
176 va_list ap = { 0 };
177
178 va_start(ap, templ);
179 int rc = winpr_vasprintf(s, slen, templ, ap);
180 va_end(ap);
181 return rc;
182}
183
184WINPR_ATTR_FORMAT_ARG(3, 0)
185int winpr_vasprintf(char** s, size_t* slen, WINPR_FORMAT_ARG const char* templ, va_list oap)
186{
187 va_list ap = { 0 };
188
189 *s = NULL;
190 *slen = 0;
191
192 va_copy(ap, oap);
193 const int length = vsnprintf(NULL, 0, templ, ap);
194 va_end(ap);
195 if (length < 0)
196 return length;
197
198 char* str = calloc((size_t)length + 1UL, sizeof(char));
199 if (!str)
200 return -1;
201
202 va_copy(ap, oap);
203 const int plen = vsnprintf(str, (size_t)length + 1UL, templ, ap);
204 va_end(ap);
205
206 if (length != plen)
207 {
208 free(str);
209 return -1;
210 }
211 *s = str;
212 *slen = (size_t)length;
213 return length;
214}
215
216#ifndef _WIN32
217
218char* _strdup(const char* strSource)
219{
220 if (strSource == NULL)
221 return NULL;
222
223 char* strDestination = strdup(strSource);
224
225 if (strDestination == NULL)
226 WLog_ERR(TAG, "strdup");
227
228 return strDestination;
229}
230
231WCHAR* _wcsdup(const WCHAR* strSource)
232{
233 if (!strSource)
234 return NULL;
235
236 size_t len = _wcslen(strSource);
237 WCHAR* strDestination = calloc(len + 1, sizeof(WCHAR));
238
239 if (strDestination != NULL)
240 memcpy(strDestination, strSource, len * sizeof(WCHAR));
241
242 if (strDestination == NULL)
243 WLog_ERR(TAG, "wcsdup");
244
245 return strDestination;
246}
247
248WCHAR* _wcsncat(WCHAR* dst, const WCHAR* src, size_t sz)
249{
250 WINPR_ASSERT(dst);
251 WINPR_ASSERT(src || (sz == 0));
252
253 const size_t dlen = _wcslen(dst);
254 const size_t slen = _wcsnlen(src, sz);
255 for (size_t x = 0; x < slen; x++)
256 dst[dlen + x] = src[x];
257 dst[dlen + slen] = '\0';
258 return dst;
259}
260
261int _stricmp(const char* string1, const char* string2)
262{
263 return strcasecmp(string1, string2);
264}
265
266int _strnicmp(const char* string1, const char* string2, size_t count)
267{
268 return strncasecmp(string1, string2, count);
269}
270
271/* _wcscmp -> wcscmp */
272
273int _wcscmp(const WCHAR* string1, const WCHAR* string2)
274{
275 WINPR_ASSERT(string1);
276 WINPR_ASSERT(string2);
277
278 while (TRUE)
279 {
280 const WCHAR w1 = *string1++;
281 const WCHAR w2 = *string2++;
282
283 if (w1 != w2)
284 return (int)w1 - w2;
285 else if ((w1 == '\0') || (w2 == '\0'))
286 return (int)w1 - w2;
287 }
288}
289
290int _wcsncmp(const WCHAR* string1, const WCHAR* string2, size_t count)
291{
292 WINPR_ASSERT(string1);
293 WINPR_ASSERT(string2);
294
295 for (size_t x = 0; x < count; x++)
296 {
297 const WCHAR a = string1[x];
298 const WCHAR b = string2[x];
299
300 if (a != b)
301 return (int)a - b;
302 else if ((a == '\0') || (b == '\0'))
303 return (int)a - b;
304 }
305 return 0;
306}
307
308/* _wcslen -> wcslen */
309
310size_t _wcslen(const WCHAR* str)
311{
312 const WCHAR* p = str;
313
314 WINPR_ASSERT(p);
315
316 while (*p)
317 p++;
318
319 return (size_t)(p - str);
320}
321
322/* _wcsnlen -> wcsnlen */
323
324size_t _wcsnlen(const WCHAR* str, size_t max)
325{
326 WINPR_ASSERT(str);
327
328 size_t x = 0;
329 for (; x < max; x++)
330 {
331 if (str[x] == 0)
332 return x;
333 }
334
335 return x;
336}
337
338/* _wcsstr -> wcsstr */
339
340WCHAR* _wcsstr(const WCHAR* str, const WCHAR* strSearch)
341{
342 WINPR_ASSERT(str);
343 WINPR_ASSERT(strSearch);
344
345 if (strSearch[0] == '\0')
346 return WINPR_CAST_CONST_PTR_AWAY(str, WCHAR*);
347
348 const size_t searchLen = _wcslen(strSearch);
349 while (*str)
350 {
351 if (_wcsncmp(str, strSearch, searchLen) == 0)
352 return WINPR_CAST_CONST_PTR_AWAY(str, WCHAR*);
353 str++;
354 }
355 return NULL;
356}
357
358/* _wcschr -> wcschr */
359
360WCHAR* _wcschr(const WCHAR* str, WCHAR c)
361{
362 union
363 {
364 const WCHAR* cc;
365 WCHAR* c;
366 } cnv;
367 const WCHAR* p = str;
368
369 while (*p && (*p != c))
370 p++;
371
372 cnv.cc = (*p == c) ? p : NULL;
373 return cnv.c;
374}
375
376/* _wcsrchr -> wcsrchr */
377
378WCHAR* _wcsrchr(const WCHAR* str, WCHAR c)
379{
380 union
381 {
382 const WCHAR* cc;
383 WCHAR* c;
384 } cnv;
385 const WCHAR* p = NULL;
386
387 if (!str)
388 return NULL;
389
390 for (; *str != '\0'; str++)
391 {
392 const WCHAR ch = *str;
393 if (ch == c)
394 p = str;
395 }
396
397 cnv.cc = p;
398 return cnv.c;
399}
400
401char* strtok_s(char* strToken, const char* strDelimit, char** context)
402{
403 return strtok_r(strToken, strDelimit, context);
404}
405
406WCHAR* wcstok_s(WCHAR* strToken, const WCHAR* strDelimit, WCHAR** context)
407{
408 WCHAR* nextToken = NULL;
409 WCHAR value = 0;
410
411 if (!strToken)
412 strToken = *context;
413
414 value = *strToken;
415
416 while (*strToken && _wcschr(strDelimit, value))
417 {
418 strToken++;
419 value = *strToken;
420 }
421
422 if (!*strToken)
423 return NULL;
424
425 nextToken = strToken++;
426 value = *strToken;
427
428 while (*strToken && !(_wcschr(strDelimit, value)))
429 {
430 strToken++;
431 value = *strToken;
432 }
433
434 if (*strToken)
435 *strToken++ = 0;
436
437 *context = strToken;
438 return nextToken;
439}
440
441#endif
442
443#if !defined(_WIN32) || defined(_UWP)
444
445/* Windows API Sets - api-ms-win-core-string-l2-1-0.dll
446 * http://msdn.microsoft.com/en-us/library/hh802935/
447 */
448
449#include "casing.h"
450
451LPSTR CharUpperA(LPSTR lpsz)
452{
453 size_t length = 0;
454
455 if (!lpsz)
456 return NULL;
457
458 length = strlen(lpsz);
459
460 if (length < 1)
461 return (LPSTR)NULL;
462
463 if (length == 1)
464 {
465 char c = *lpsz;
466
467 if ((c >= 'a') && (c <= 'z'))
468 c = (char)(c - 'a' + 'A');
469
470 *lpsz = c;
471 return lpsz;
472 }
473
474 for (size_t i = 0; i < length; i++)
475 {
476 if ((lpsz[i] >= 'a') && (lpsz[i] <= 'z'))
477 lpsz[i] = (char)(lpsz[i] - 'a' + 'A');
478 }
479
480 return lpsz;
481}
482
483LPWSTR CharUpperW(LPWSTR lpsz)
484{
485 size_t length = 0;
486
487 if (!lpsz)
488 return NULL;
489
490 length = _wcslen(lpsz);
491
492 if (length < 1)
493 return (LPWSTR)NULL;
494
495 if (length == 1)
496 {
497 WCHAR c = *lpsz;
498
499 if ((c >= L'a') && (c <= L'z'))
500 c = c - L'a' + L'A';
501
502 *lpsz = c;
503 return lpsz;
504 }
505
506 for (size_t i = 0; i < length; i++)
507 {
508 if ((lpsz[i] >= L'a') && (lpsz[i] <= L'z'))
509 lpsz[i] = lpsz[i] - L'a' + L'A';
510 }
511
512 return lpsz;
513}
514
515DWORD CharUpperBuffA(LPSTR lpsz, DWORD cchLength)
516{
517 if (cchLength < 1)
518 return 0;
519
520 for (DWORD i = 0; i < cchLength; i++)
521 {
522 if ((lpsz[i] >= 'a') && (lpsz[i] <= 'z'))
523 lpsz[i] = (char)(lpsz[i] - 'a' + 'A');
524 }
525
526 return cchLength;
527}
528
529DWORD CharUpperBuffW(LPWSTR lpsz, DWORD cchLength)
530{
531 for (DWORD i = 0; i < cchLength; i++)
532 {
533 WCHAR value = winpr_Data_Get_UINT16(&lpsz[i]);
534 value = WINPR_TOUPPERW(value);
535 winpr_Data_Write_UINT16(&lpsz[i], value);
536 }
537
538 return cchLength;
539}
540
541LPSTR CharLowerA(LPSTR lpsz)
542{
543 size_t length = 0;
544
545 if (!lpsz)
546 return (LPSTR)NULL;
547
548 length = strlen(lpsz);
549
550 if (length < 1)
551 return (LPSTR)NULL;
552
553 if (length == 1)
554 {
555 char c = *lpsz;
556
557 if ((c >= 'A') && (c <= 'Z'))
558 c = (char)(c - 'A' + 'a');
559
560 *lpsz = c;
561 return lpsz;
562 }
563
564 for (size_t i = 0; i < length; i++)
565 {
566 if ((lpsz[i] >= 'A') && (lpsz[i] <= 'Z'))
567 lpsz[i] = (char)(lpsz[i] - 'A' + 'a');
568 }
569
570 return lpsz;
571}
572
573LPWSTR CharLowerW(LPWSTR lpsz)
574{
575 const size_t len = _wcsnlen(lpsz, UINT32_MAX + 1);
576 if (len > UINT32_MAX)
577 return NULL;
578 CharLowerBuffW(lpsz, (UINT32)len);
579 return lpsz;
580}
581
582DWORD CharLowerBuffA(LPSTR lpsz, DWORD cchLength)
583{
584 if (cchLength < 1)
585 return 0;
586
587 for (DWORD i = 0; i < cchLength; i++)
588 {
589 if ((lpsz[i] >= 'A') && (lpsz[i] <= 'Z'))
590 lpsz[i] = (char)(lpsz[i] - 'A' + 'a');
591 }
592
593 return cchLength;
594}
595
596DWORD CharLowerBuffW(LPWSTR lpsz, DWORD cchLength)
597{
598 for (DWORD i = 0; i < cchLength; i++)
599 {
600 WCHAR value = winpr_Data_Get_UINT16(&lpsz[i]);
601 value = WINPR_TOLOWERW(value);
602 winpr_Data_Write_UINT16(&lpsz[i], value);
603 }
604
605 return cchLength;
606}
607
608BOOL IsCharAlphaA(CHAR ch)
609{
610 if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')))
611 return 1;
612 else
613 return 0;
614}
615
616BOOL IsCharAlphaW(WCHAR ch)
617{
618 if (((ch >= L'a') && (ch <= L'z')) || ((ch >= L'A') && (ch <= L'Z')))
619 return 1;
620 else
621 return 0;
622}
623
624BOOL IsCharAlphaNumericA(CHAR ch)
625{
626 if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) ||
627 ((ch >= '0') && (ch <= '9')))
628 return 1;
629 else
630 return 0;
631}
632
633BOOL IsCharAlphaNumericW(WCHAR ch)
634{
635 if (((ch >= L'a') && (ch <= L'z')) || ((ch >= L'A') && (ch <= L'Z')) ||
636 ((ch >= L'0') && (ch <= L'9')))
637 return 1;
638 else
639 return 0;
640}
641
642BOOL IsCharUpperA(CHAR ch)
643{
644 if ((ch >= 'A') && (ch <= 'Z'))
645 return 1;
646 else
647 return 0;
648}
649
650BOOL IsCharUpperW(WCHAR ch)
651{
652 if ((ch >= L'A') && (ch <= L'Z'))
653 return 1;
654 else
655 return 0;
656}
657
658BOOL IsCharLowerA(CHAR ch)
659{
660 if ((ch >= 'a') && (ch <= 'z'))
661 return 1;
662 else
663 return 0;
664}
665
666BOOL IsCharLowerW(WCHAR ch)
667{
668 if ((ch >= L'a') && (ch <= L'z'))
669 return 1;
670 else
671 return 0;
672}
673
674#endif
675
676size_t ConvertLineEndingToLF(char* str, size_t size)
677{
678 size_t skip = 0;
679
680 WINPR_ASSERT(str || (size == 0));
681 for (size_t x = 0; x < size; x++)
682 {
683 char c = str[x];
684 switch (c)
685 {
686 case '\r':
687 str[x - skip] = '\n';
688 if ((x + 1 < size) && (str[x + 1] == '\n'))
689 skip++;
690 break;
691 default:
692 str[x - skip] = c;
693 break;
694 }
695 }
696 return size - skip;
697}
698
699char* ConvertLineEndingToCRLF(const char* str, size_t* size)
700{
701 WINPR_ASSERT(size);
702 const size_t s = *size;
703 WINPR_ASSERT(str || (s == 0));
704
705 *size = 0;
706 if (s == 0)
707 return NULL;
708
709 size_t linebreaks = 0;
710 for (size_t x = 0; x < s - 1; x++)
711 {
712 char c = str[x];
713 switch (c)
714 {
715 case '\r':
716 case '\n':
717 linebreaks++;
718 break;
719 default:
720 break;
721 }
722 }
723 char* cnv = calloc(s + linebreaks * 2ull + 1ull, sizeof(char));
724 if (!cnv)
725 return NULL;
726
727 size_t pos = 0;
728 for (size_t x = 0; x < s; x++)
729 {
730 const char c = str[x];
731 switch (c)
732 {
733 case '\r':
734 cnv[pos++] = '\r';
735 cnv[pos++] = '\n';
736 break;
737 case '\n':
738 /* Do not duplicate existing \r\n sequences */
739 if ((x > 0) && (str[x - 1] != '\r'))
740 {
741 cnv[pos++] = '\r';
742 cnv[pos++] = '\n';
743 }
744 break;
745 default:
746 cnv[pos++] = c;
747 break;
748 }
749 }
750 *size = pos;
751 return cnv;
752}
753
754char* StrSep(char** stringp, const char* delim)
755{
756 char* start = *stringp;
757 char* p = NULL;
758 p = (start != NULL) ? strpbrk(start, delim) : NULL;
759
760 if (!p)
761 *stringp = NULL;
762 else
763 {
764 *p = '\0';
765 *stringp = p + 1;
766 }
767
768 return start;
769}
770
771INT64 GetLine(char** lineptr, size_t* size, FILE* stream)
772{
773#if defined(_WIN32)
774 char c;
775 char* n;
776 size_t step = 32;
777 size_t used = 0;
778
779 if (!lineptr || !size)
780 {
781 errno = EINVAL;
782 return -1;
783 }
784
785 do
786 {
787 if (used + 2 >= *size)
788 {
789 *size += step;
790 n = realloc(*lineptr, *size);
791
792 if (!n)
793 {
794 return -1;
795 }
796
797 *lineptr = n;
798 }
799
800 c = fgetc(stream);
801
802 if (c != EOF)
803 (*lineptr)[used++] = c;
804 } while ((c != '\n') && (c != '\r') && (c != EOF));
805
806 (*lineptr)[used] = '\0';
807 return used;
808#elif !defined(ANDROID) && !defined(IOS)
809 return getline(lineptr, size, stream);
810#else
811 return -1;
812#endif
813}
814
815#if !defined(WINPR_HAVE_STRNDUP)
816char* strndup(const char* src, size_t n)
817{
818 char* dst = calloc(n + 1, sizeof(char));
819 if (dst)
820 strncpy(dst, src, n);
821 return dst;
822}
823#endif
824
825const WCHAR* InitializeConstWCharFromUtf8(const char* str, WCHAR* buffer, size_t len)
826{
827 WINPR_ASSERT(str);
828 WINPR_ASSERT(buffer || (len == 0));
829 (void)ConvertUtf8ToWChar(str, buffer, len);
830 return buffer;
831}
832
833WCHAR* wcsndup(const WCHAR* s, size_t n)
834{
835 if (!s)
836 return NULL;
837
838 WCHAR* copy = calloc(n + 1, sizeof(WCHAR));
839 if (!copy)
840 return NULL;
841 memcpy(copy, s, n * sizeof(WCHAR));
842 return copy;
843}