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