Coverage Report

Created: 2026-09-14 06:31

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