Coverage Report

Created: 2023-09-25 06:56

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