xref: /reactos/sdk/lib/crt/string/wcstombs_s.c (revision 5100859e)
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/wcstombs_s.c
6  * PROGRAMMER:        Timo Kreuzer
7  */
8 
9 #include <precomp.h>
10 
11 _Success_(return!=EINVAL)
12 _Check_return_wat_
13 _CRTIMP
14 errno_t
15 __cdecl
16 wcstombs_s(
17     _Out_opt_ size_t * pcchConverted,
18     _Out_writes_bytes_to_opt_(cjDstSize, *pcchConverted)
19         char * pmbstrDst,
20     _In_ size_t cjDstSize,
21     _In_z_ const wchar_t * pwszSrc,
22     _In_ size_t cjMaxCount)
23 {
24     size_t cchMax, cchConverted;
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( ((cjDstSize != 0) && (pmbstrDst != 0)) ||
29                            ((cjDstSize == 0) && (pmbstrDst == 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((cjMaxCount == 0) || (pwszSrc != 0)))
43     {
44         _set_errno(EINVAL);
45         return EINVAL;
46     }
47 
48     /* Check if there is anything to do */
49     if ((pmbstrDst == 0) && (pwszSrc == 0))
50     {
51         _set_errno(EINVAL);
52         return EINVAL;
53     }
54 
55     /* Check if we have a wchar string */
56     if (pwszSrc)
57     {
58         /* Check if we also have a multibyte buffer */
59         if (pmbstrDst)
60         {
61             /* Calculate the maximum that we can write */
62             cchMax = (cjMaxCount < cjDstSize) ? cjMaxCount + 1 : cjDstSize;
63 
64             /* Now do the conversion */
65             cchConverted = wcstombs(pmbstrDst, pwszSrc, cchMax);
66 
67             /* Check if the buffer was not zero terminated */
68             if (cchConverted == cchMax)
69             {
70                 /* Check if we reached the max size of the dest buffer */
71                 if (cchConverted == cjDstSize)
72                 {
73                     /* Does the caller allow this? */
74                     if (cjMaxCount != _TRUNCATE)
75                     {
76                         /* Not allowed, truncate to 0 length */
77                         pmbstrDst[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                 pmbstrDst[cchConverted - 1] = L'\0';
90             }
91             else
92             {
93                 /* The buffer is zero terminated, count the terminating char */
94                 cchConverted++;
95             }
96         }
97         else
98         {
99             /* Get the length of the string, plus 0 terminator */
100             cchConverted = wcsnlen(pwszSrc, cjMaxCount) + 1;
101         }
102     }
103     else
104     {
105         cchConverted = cjMaxCount + 1;
106     }
107 
108     /* Check if we have a return value pointer */
109     if (pcchConverted)
110     {
111         /* Default to 0 bytes written */
112         *pcchConverted = cchConverted;
113     }
114 
115     return retval;
116 }
117