xref: /reactos/sdk/lib/crt/string/mbstowcs_s.c (revision c2c66aff)
1 /*
2  * COPYRIGHT:         See COPYING in the top level directory
3  * PROJECT:           ReactOS CRT
4  * PURPOSE:           Implementation of mbstowcs_s
5  * FILE:              lib/sdk/crt/string/mbstowcs_s.c
6  * PROGRAMMER:        Timo Kreuzer
7  */
8 
9 #include <precomp.h>
10 #include <mbstring.h>
11 
12 _Success_(return!=EINVAL)
13 _Check_return_opt_
14 _CRTIMP
15 errno_t
16 __cdecl
mbstowcs_s(_Out_opt_ size_t * pcchConverted,_Out_writes_to_opt_ (sizeInWords,* pcchConverted)wchar_t * pwcstr,_In_ size_t sizeInWords,_In_reads_or_z_ (count)const char * pmbstr,_In_ size_t count)17 mbstowcs_s(
18    _Out_opt_ size_t *pcchConverted,
19    _Out_writes_to_opt_(sizeInWords, *pcchConverted) wchar_t *pwcstr,
20    _In_ size_t sizeInWords,
21    _In_reads_or_z_(count) const char *pmbstr,
22    _In_ size_t count)
23 {
24     size_t cchMax, cwcWritten;
25     errno_t retval = 0;
26 
27     /* Make sure, either we have a target buffer > 0 bytes, or no buffer */
28     if (!MSVCRT_CHECK_PMT( ((sizeInWords != 0) && (pwcstr != 0)) ||
29                            ((sizeInWords == 0) && (pwcstr == 0)) ))
30     {
31         _set_errno(EINVAL);
32         return EINVAL;
33     }
34 
35     /* Check if we have a return value pointer */
36     if (pcchConverted)
37     {
38         /* Default to 0 bytes written */
39         *pcchConverted = 0;
40     }
41 
42     if (!MSVCRT_CHECK_PMT((count == 0) || (pmbstr != 0)))
43     {
44         _set_errno(EINVAL);
45         return EINVAL;
46     }
47 
48     /* Check if there is anything to do */
49     if ((pwcstr == 0) && (pmbstr == 0))
50     {
51         _set_errno(EINVAL);
52         return EINVAL;
53     }
54 
55     /* Check if we have a multibyte string */
56     if (pmbstr)
57     {
58         /* Check if we also have a wchar buffer */
59         if (pwcstr)
60         {
61             /* Calculate the maximum the we can write */
62             cchMax = (count < sizeInWords) ? count + 1 : sizeInWords;
63 
64             /* Now do the conversion */
65             cwcWritten = mbstowcs(pwcstr, pmbstr, cchMax);
66 
67             /* Check if the buffer was not zero terminated */
68             if (cwcWritten == cchMax)
69             {
70                 /* Check if we reached the max size of the dest buffer */
71                 if (cwcWritten == sizeInWords)
72                 {
73                     /* Does the caller allow this? */
74                     if (count != _TRUNCATE)
75                     {
76                         /* Not allowed, truncate to 0 length */
77                         pwcstr[0] = L'\0';
78 
79                         /* Return error */
80                         _set_errno(ERANGE);
81                         return ERANGE;
82                     }
83 
84                     /* Inform the caller about truncation */
85                     retval = STRUNCATE;
86                 }
87 
88                 /* zero teminate the buffer */
89                 pwcstr[cwcWritten - 1] = L'\0';
90             }
91             else
92             {
93                 /* The buffer is zero terminated, count the terminating char */
94                 cwcWritten++;
95             }
96         }
97         else
98         {
99             /* Get the length of the string, plus 0 terminator */
100             cwcWritten = _mbsnlen((const unsigned char *)pmbstr, count) + 1;
101         }
102     }
103     else
104     {
105         cwcWritten = count + 1;
106     }
107 
108     /* Check if we have a return value pointer */
109     if (pcchConverted)
110     {
111         /* Default to 0 bytes written */
112         *pcchConverted = cwcWritten;
113     }
114 
115     return retval;
116 }
117