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  for (DWORD i = 0; i < cchLength; i++)
536  {
537  WCHAR value = winpr_Data_Get_UINT16(&lpsz[i]);
538  value = WINPR_TOUPPERW(value);
539  winpr_Data_Write_UINT16(&lpsz[i], value);
540  }
541 
542  return cchLength;
543 }
544 
545 LPSTR CharLowerA(LPSTR lpsz)
546 {
547  size_t length = 0;
548 
549  if (!lpsz)
550  return (LPSTR)NULL;
551 
552  length = strlen(lpsz);
553 
554  if (length < 1)
555  return (LPSTR)NULL;
556 
557  if (length == 1)
558  {
559  char c = *lpsz;
560 
561  if ((c >= 'A') && (c <= 'Z'))
562  c = (char)(c - 'A' + 'a');
563 
564  *lpsz = c;
565  return lpsz;
566  }
567 
568  for (size_t i = 0; i < length; i++)
569  {
570  if ((lpsz[i] >= 'A') && (lpsz[i] <= 'Z'))
571  lpsz[i] = (char)(lpsz[i] - 'A' + 'a');
572  }
573 
574  return lpsz;
575 }
576 
577 LPWSTR CharLowerW(LPWSTR lpsz)
578 {
579  const size_t len = _wcsnlen(lpsz, UINT32_MAX + 1);
580  if (len > UINT32_MAX)
581  return NULL;
582  CharLowerBuffW(lpsz, (UINT32)len);
583  return lpsz;
584 }
585 
586 DWORD CharLowerBuffA(LPSTR lpsz, DWORD cchLength)
587 {
588  if (cchLength < 1)
589  return 0;
590 
591  for (DWORD i = 0; i < cchLength; i++)
592  {
593  if ((lpsz[i] >= 'A') && (lpsz[i] <= 'Z'))
594  lpsz[i] = (char)(lpsz[i] - 'A' + 'a');
595  }
596 
597  return cchLength;
598 }
599 
600 DWORD CharLowerBuffW(LPWSTR lpsz, DWORD cchLength)
601 {
602  for (DWORD i = 0; i < cchLength; i++)
603  {
604  WCHAR value = winpr_Data_Get_UINT16(&lpsz[i]);
605  value = WINPR_TOLOWERW(value);
606  winpr_Data_Write_UINT16(&lpsz[i], value);
607  }
608 
609  return cchLength;
610 }
611 
612 BOOL IsCharAlphaA(CHAR ch)
613 {
614  if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')))
615  return 1;
616  else
617  return 0;
618 }
619 
620 BOOL IsCharAlphaW(WCHAR ch)
621 {
622  if (((ch >= L'a') && (ch <= L'z')) || ((ch >= L'A') && (ch <= L'Z')))
623  return 1;
624  else
625  return 0;
626 }
627 
628 BOOL IsCharAlphaNumericA(CHAR ch)
629 {
630  if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) ||
631  ((ch >= '0') && (ch <= '9')))
632  return 1;
633  else
634  return 0;
635 }
636 
637 BOOL IsCharAlphaNumericW(WCHAR ch)
638 {
639  if (((ch >= L'a') && (ch <= L'z')) || ((ch >= L'A') && (ch <= L'Z')) ||
640  ((ch >= L'0') && (ch <= L'9')))
641  return 1;
642  else
643  return 0;
644 }
645 
646 BOOL IsCharUpperA(CHAR ch)
647 {
648  if ((ch >= 'A') && (ch <= 'Z'))
649  return 1;
650  else
651  return 0;
652 }
653 
654 BOOL IsCharUpperW(WCHAR ch)
655 {
656  if ((ch >= L'A') && (ch <= L'Z'))
657  return 1;
658  else
659  return 0;
660 }
661 
662 BOOL IsCharLowerA(CHAR ch)
663 {
664  if ((ch >= 'a') && (ch <= 'z'))
665  return 1;
666  else
667  return 0;
668 }
669 
670 BOOL IsCharLowerW(WCHAR ch)
671 {
672  if ((ch >= L'a') && (ch <= L'z'))
673  return 1;
674  else
675  return 0;
676 }
677 
678 #endif
679 
680 size_t ConvertLineEndingToLF(char* str, size_t size)
681 {
682  size_t skip = 0;
683 
684  WINPR_ASSERT(str || (size == 0));
685  for (size_t x = 0; x < size; x++)
686  {
687  char c = str[x];
688  switch (c)
689  {
690  case '\r':
691  str[x - skip] = '\n';
692  if ((x + 1 < size) && (str[x + 1] == '\n'))
693  skip++;
694  break;
695  default:
696  str[x - skip] = c;
697  break;
698  }
699  }
700  return size - skip;
701 }
702 
703 char* ConvertLineEndingToCRLF(const char* str, size_t* size)
704 {
705  WINPR_ASSERT(size);
706  const size_t s = *size;
707  WINPR_ASSERT(str || (s == 0));
708 
709  *size = 0;
710  if (s == 0)
711  return NULL;
712 
713  size_t linebreaks = 0;
714  for (size_t x = 0; x < s - 1; x++)
715  {
716  char c = str[x];
717  switch (c)
718  {
719  case '\r':
720  case '\n':
721  linebreaks++;
722  break;
723  default:
724  break;
725  }
726  }
727  char* cnv = calloc(s + linebreaks * 2ull + 1ull, sizeof(char));
728  if (!cnv)
729  return NULL;
730 
731  size_t pos = 0;
732  for (size_t x = 0; x < s; x++)
733  {
734  const char c = str[x];
735  switch (c)
736  {
737  case '\r':
738  cnv[pos++] = '\r';
739  cnv[pos++] = '\n';
740  break;
741  case '\n':
742  /* Do not duplicate existing \r\n sequences */
743  if ((x > 0) && (str[x - 1] != '\r'))
744  {
745  cnv[pos++] = '\r';
746  cnv[pos++] = '\n';
747  }
748  break;
749  default:
750  cnv[pos++] = c;
751  break;
752  }
753  }
754  *size = pos;
755  return cnv;
756 }
757 
758 char* StrSep(char** stringp, const char* delim)
759 {
760  char* start = *stringp;
761  char* p = NULL;
762  p = (start != NULL) ? strpbrk(start, delim) : NULL;
763 
764  if (!p)
765  *stringp = NULL;
766  else
767  {
768  *p = '\0';
769  *stringp = p + 1;
770  }
771 
772  return start;
773 }
774 
775 INT64 GetLine(char** lineptr, size_t* size, FILE* stream)
776 {
777 #if defined(_WIN32)
778  char c;
779  char* n;
780  size_t step = 32;
781  size_t used = 0;
782 
783  if (!lineptr || !size)
784  {
785  errno = EINVAL;
786  return -1;
787  }
788 
789  do
790  {
791  if (used + 2 >= *size)
792  {
793  *size += step;
794  n = realloc(*lineptr, *size);
795 
796  if (!n)
797  {
798  return -1;
799  }
800 
801  *lineptr = n;
802  }
803 
804  c = fgetc(stream);
805 
806  if (c != EOF)
807  (*lineptr)[used++] = c;
808  } while ((c != '\n') && (c != '\r') && (c != EOF));
809 
810  (*lineptr)[used] = '\0';
811  return used;
812 #elif !defined(ANDROID) && !defined(IOS)
813  return getline(lineptr, size, stream);
814 #else
815  return -1;
816 #endif
817 }
818 
819 #if !defined(WINPR_HAVE_STRNDUP)
820 char* strndup(const char* src, size_t n)
821 {
822  char* dst = calloc(n + 1, sizeof(char));
823  if (dst)
824  strncpy(dst, src, n);
825  return dst;
826 }
827 #endif
828 
829 const WCHAR* InitializeConstWCharFromUtf8(const char* str, WCHAR* buffer, size_t len)
830 {
831  WINPR_ASSERT(str);
832  WINPR_ASSERT(buffer || (len == 0));
833  (void)ConvertUtf8ToWChar(str, buffer, len);
834  return buffer;
835 }
836 
837 WCHAR* wcsndup(const WCHAR* s, size_t n)
838 {
839  if (!s)
840  return NULL;
841 
842  WCHAR* copy = calloc(n + 1, sizeof(WCHAR));
843  if (!copy)
844  return NULL;
845  memcpy(copy, s, n * sizeof(WCHAR));
846  return copy;
847 }