xref: /reactos/sdk/lib/ucrt/mbstring/mbscat_s_l.cpp (revision 04e0dc4a)
1 /***
2 *mbscat_s_l.c - Concatenate one string to another (MBCS)
3 *
4 *       Copyright (c) Microsoft Corporation.  All rights reserved.
5 *
6 *Purpose:
7 *       Concatenate one string to another (MBCS)
8 *
9 *******************************************************************************/
10 #ifndef _MBCS
11     #error This file should only be compiled with _MBCS defined
12 #endif
13 
14 #include <corecrt_internal_mbstring.h>
15 #include <corecrt_internal_securecrt.h>
16 
17 
18 
_mbscat_s_l(unsigned char * _Dst,size_t _SizeInBytes,const unsigned char * _Src,_LOCALE_ARG_DECL)19 errno_t __cdecl _mbscat_s_l(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, _LOCALE_ARG_DECL)
20 {
21     unsigned char *p;
22     size_t available;
23     BOOL fFoundInvalidMBC, fIsLeadPrefix;
24 
25     /* validation section */
26     _VALIDATE_STRING(_Dst, _SizeInBytes);
27     _VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes);
28 
29     _LOCALE_UPDATE;
30     if (_LOCALE_SHORTCUT_TEST)
31     {
32         return strcat_s((char *)_Dst, _SizeInBytes, (const char *)_Src);
33     }
34 
35     fFoundInvalidMBC = FALSE;
36     p = _Dst;
37     available = _SizeInBytes;
38     while (available > 0 && *p != 0)
39     {
40         p++;
41         available--;
42     }
43 
44     /*
45      * Ran out of room while looking for end of dst string.
46      * p points 1 past end of buffer. We can't look past
47      * end of buffer so can't tell if dst ended with an
48      * invalid mbc.
49      */
50 
51     if (available == 0)
52     {
53         _RESET_STRING(_Dst, _SizeInBytes);
54         _RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes);
55     }
56 
57     /*
58      * Otherwise we have space available, p points at null that lies
59      * within _SizeInBytes, so available > 0. Check if dst ended with
60      * an invalid MBC (lead+null), if so then clear that lead byte,
61      * move the pointer back one and increase available by one.
62      */
63 
64     _ISMBBLEADPREFIX(fIsLeadPrefix, _Dst, p-1);
65     if (fIsLeadPrefix)
66     {
67         fFoundInvalidMBC = TRUE;
68         p--;
69         *p = 0;
70         available++;
71     }
72 
73     /* Append dst to src. */
74 
75     while ((*p++ = *_Src++) != 0 && --available > 0)
76     {
77     }
78 
79     /*
80      * We've run out of room in the destination before finding null in the src.
81      * It could be that the src was terminated with an invalid mbc (lead+null).
82      * In that case its ok to clear the copied lead byte and return mbcs_error.
83      */
84 
85     if (available == 0)
86     {
87         if (*_Src == 0)
88         {
89             _ISMBBLEADPREFIX(fIsLeadPrefix, _Dst, p-1);
90             if (fIsLeadPrefix)
91             {
92                 /* the source string ended with a lead byte: we remove it */
93                 p[-1] = 0;
94                 _RETURN_MBCS_ERROR;
95             }
96         }
97         _RESET_STRING(_Dst, _SizeInBytes);
98         _RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
99     }
100 
101     /*
102      * If the src string ended with an invalid mbc (lead+null) then clear the
103      * lead byte.
104      */
105 
106     _ISMBBLEADPREFIX(fIsLeadPrefix, _Dst, p-2);
107     if (fIsLeadPrefix)
108     {
109         p[-2] = 0;
110         available++;
111         fFoundInvalidMBC = TRUE;
112     }
113 
114     _FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
115 
116     if (fFoundInvalidMBC)
117     {
118         _RETURN_MBCS_ERROR;
119     }
120 
121     _RETURN_NO_ERROR;
122 }
123