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