1/*** 2*mbsncat_s.inl - general implementation of _mbsncat_s and _mbsnbcat_s 3* 4* Copyright (c) Microsoft Corporation. All rights reserved. 5* 6*Purpose: 7* This file contains the general algorithm for _mbsncat_s and _mbsnbcat_s. 8* 9****/ 10 11errno_t __cdecl _FUNC_NAME(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _COUNT, _LOCALE_ARG_DECL) 12{ 13 unsigned char *p; 14 size_t available; 15 BOOL fIsLeadPrefix; 16 BOOL fFoundInvalidMBC; 17 18 fFoundInvalidMBC = FALSE; 19 20 if (_COUNT == 0 && _Dst == nullptr && _SizeInBytes == 0) 21 { 22 /* this case is allowed; nothing to do */ 23 _RETURN_NO_ERROR; 24 } 25 26 /* validation section */ 27 _VALIDATE_STRING(_Dst, _SizeInBytes); 28 if (_COUNT != 0) 29 { 30 _VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes); 31 } 32 33 _LOCALE_UPDATE; 34 if (_LOCALE_SHORTCUT_TEST) 35 { 36 return strncat_s((char *)_Dst, _SizeInBytes, (const char *)_Src, _COUNT); 37 } 38 39 p = _Dst; 40 available = _SizeInBytes; 41 while (available > 0 && *p != 0) 42 { 43 p++; 44 available--; 45 } 46 47 /* 48 * Ran out of room while looking for end of dst string. 49 * p points 1 past end of buffer. We can't look past 50 * end of buffer so can't tell if dst ended with an 51 * invalid mbc. 52 */ 53 54 if (available == 0) 55 { 56 _RESET_STRING(_Dst, _SizeInBytes); 57 _RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes); 58 } 59 60 61 if (available < _SizeInBytes) 62 { 63 /* 64 * Dst may have terminated with an invalid MBCS, in that case we clear 65 * the bogus lead byte. 66 */ 67 fIsLeadPrefix = FALSE; 68 _ISMBBLEADPREFIX(fIsLeadPrefix, _Dst, &p[-1]); 69 if (fIsLeadPrefix) { 70 /* the original string ended with a lead byte: we remove it */ 71 p--; 72 *p = 0; 73 available++; 74 fFoundInvalidMBC = TRUE; 75 } 76 } 77 78 if (_COUNT == _TRUNCATE) 79 { 80 while ((*p++ = *_Src++) != 0 && --available > 0) 81 { 82 } 83 } 84 else 85 { 86#if _COUNT_IN_BYTES 87 while (_COUNT > 0 && (*p++ = *_Src++) != 0 && --available > 0) 88 { 89 _COUNT--; 90 } 91#else /* _COUNT_IN_BYTES */ 92 while (_COUNT > 0) 93 { 94 if (_ISMBBLEAD(*_Src)) 95 { 96 if (_Src[1] == 0) 97 { 98 /* the source string ended with a lead byte: we remove it */ 99 *p = 0; 100 fFoundInvalidMBC = TRUE; 101 break; 102 } 103 if (available <= 2) 104 { 105 /* not enough space */ 106 available = 0; 107 break; 108 } 109 *p++ = *_Src++; 110 *p++ = *_Src++; 111 available -= 2; 112 } 113 else 114 { 115 if ((*p++ = *_Src++) == 0 || --available == 0) 116 { 117 break; 118 } 119 } 120 _COUNT--; 121 } 122#endif /* _COUNT_IN_BYTES */ 123 if (_COUNT == 0) 124 { 125 *p++ = 0; 126 } 127 } 128 129 if (available == 0) 130 { 131#if _COUNT_IN_BYTES 132 /* 133 * defined(_COUNT_IN_BYTES) loop does not track mbc context, 134 * so we must iterate backwards to discover character context. 135 */ 136 if (*_Src == 0 || _COUNT == 1) 137 { 138 _ISMBBLEADPREFIX(fIsLeadPrefix, _Dst, &p[-1]); 139 if (fIsLeadPrefix) 140 { 141 /* the source string ended with a lead byte: we remove it */ 142 p[-1] = 0; 143 _RETURN_MBCS_ERROR; 144 } 145 } 146#endif /* _COUNT_IN_BYTES */ 147 148 /* 149 * _COUNT == _TRUNCATE loop terminated because available became 0. 150 * This means that we copied at least one character, and it wasn't 151 * a null. If this last character acted as a lead then overwrite 152 * it with null. Do not set the mbcs error in this case, due that the 153 * user cannot predict this case and he/she's only asking for truncation. 154 */ 155 if (_COUNT == _TRUNCATE) 156 { 157 if (fFoundInvalidMBC) 158 { 159 _SET_MBCS_ERROR; 160 } 161 162 if (_SizeInBytes > 1) 163 { 164 fIsLeadPrefix = FALSE; 165 _ISMBBLEADPREFIX(fIsLeadPrefix, _Dst, &_Dst[_SizeInBytes - 2]); 166 if (fIsLeadPrefix) 167 { 168 _Dst[_SizeInBytes - 2] = 0; 169 _FILL_BYTE(_Dst[_SizeInBytes - 1]); 170 _RETURN_TRUNCATE; 171 } 172 } 173 174 _Dst[_SizeInBytes - 1] = 0; 175 176 _RETURN_TRUNCATE; 177 } 178 _RESET_STRING(_Dst, _SizeInBytes); 179 _RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes); 180 } 181#if _COUNT_IN_BYTES 182 if (available < _SizeInBytes) 183 { 184 _ISMBBLEADPREFIX(fIsLeadPrefix, _Dst, &p[-2]); 185 if (fIsLeadPrefix) 186 { 187 /* the source string ended with a lead byte: we remove it */ 188 p[-2] = 0; 189 available++; 190 fFoundInvalidMBC = TRUE; 191 } 192 } 193#endif /* _COUNT_IN_BYTES */ 194 _FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1); 195 196 if (fFoundInvalidMBC) 197 { 198 _RETURN_MBCS_ERROR; 199 } 200 201 _RETURN_NO_ERROR; 202} 203 204