Coverage Report

Created: 2026-07-16 07:10

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