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