1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "securecutil.h"
17
SecDoWcsncat(wchar_t * strDest,size_t destMax,const wchar_t * strSrc,size_t count)18 static errno_t SecDoWcsncat(wchar_t *strDest, size_t destMax, const wchar_t *strSrc, size_t count)
19 {
20 wchar_t *tmpDest = strDest;
21 const wchar_t *tmpSrc = strSrc;
22 size_t availableSize = destMax;
23 size_t maxCount = count;
24 SECUREC_IN_REGISTER const wchar_t *overlapGuard = NULL;
25
26 if (tmpDest < tmpSrc) {
27 overlapGuard = tmpSrc;
28 while (availableSize > 0 && *tmpDest != '\0') {
29 if (tmpDest == overlapGuard) {
30 strDest[0] = '\0';
31 SECUREC_ERROR_BUFFER_OVERLAP("wcsncat_s");
32 return EOVERLAP_AND_RESET;
33 }
34 ++tmpDest;
35 --availableSize;
36 }
37 /* strDestination unterminated, return error. */
38 if (availableSize == 0) {
39 strDest[0] = '\0';
40 SECUREC_ERROR_INVALID_PARAMTER("wcsncat_s");
41 return EINVAL_AND_RESET;
42 }
43 while (maxCount > 0 && (*tmpDest++ = *tmpSrc++) != '\0' && --availableSize > 0) {
44 if (tmpDest == overlapGuard) {
45 strDest[0] = '\0';
46 SECUREC_ERROR_BUFFER_OVERLAP("wcsncat_s");
47 return EOVERLAP_AND_RESET;
48 }
49 --maxCount;
50 }
51 } else {
52 overlapGuard = tmpDest;
53 while (availableSize > 0 && *tmpDest != '\0') {
54 /* seek to string end, and no need to check overlap */
55 ++tmpDest;
56 --availableSize;
57 }
58
59 /* strDest unterminated, return error. */
60 if (availableSize == 0) {
61 strDest[0] = '\0';
62 SECUREC_ERROR_INVALID_PARAMTER("wcsncat_s");
63 return EINVAL_AND_RESET;
64 }
65 while (maxCount > 0 && (*tmpDest++ = *tmpSrc++) != '\0' && --availableSize > 0) {
66 if (tmpSrc == overlapGuard) {
67 strDest[0] = '\0';
68 SECUREC_ERROR_BUFFER_OVERLAP("wcsncat_s");
69 return EOVERLAP_AND_RESET;
70 }
71 --maxCount;
72 }
73 }
74 if (maxCount == 0) {
75 *tmpDest = '\0'; /* add terminator to strDest */
76 }
77
78 /* strDest have no space to store the terminator, return error */
79 if (availableSize == 0) {
80 strDest[0] = '\0';
81 SECUREC_ERROR_INVALID_RANGE("wcsncat_s");
82 return ERANGE_AND_RESET;
83 }
84 return EOK;
85 }
86
87 /*******************************************************************************
88 * <FUNCTION DESCRIPTION>
89 * The wcsncat_s function appends not more than n successive wide characters
90 * (not including the terminating null wide character)
91 * from the array pointed to by strSrc to the end of the wide string pointed to by strDest.
92 *
93 * The wcsncat_s function try to append the first D characters of strSrc to
94 * the end of strDest, where D is the lesser of count and the length of strSrc.
95 * If appending those D characters will fit within strDest (whose size is
96 * given as destMax) and still leave room for a null terminator, then those
97 * characters are appended, starting at the original terminating null of
98 * strDest, and a new terminating null is appended; otherwise, strDest[0] is
99 * set to the null character.
100 *
101 * <INPUT PARAMETERS>
102 * strDest Null-terminated destination string.
103 * destMax Size of the destination buffer.
104 * strSrc Null-terminated source string.
105 * count Number of character to append, or truncate.
106 *
107 * <OUTPUT PARAMETERS>
108 * strDest is updated
109 *
110 * <RETURN VALUE>
111 * EOK Success
112 * EINVAL strDest is NULL and destMax != 0 and destMax <= SECUREC_WCHAR_STRING_MAX_LEN
113 * EINVAL_AND_RESET (strDest unterminated and all other parameters are valid) or
114 * (strDest != NULL and strSrc is NULL and destMax != 0 and destMax <= SECUREC_WCHAR_STRING_MAX_LEN)
115 * ERANGE destMax > SECUREC_WCHAR_STRING_MAX_LEN or destMax is 0
116 * ERANGE_AND_RESET strDest have not enough space and all other parameters are valid and not overlap
117 * EOVERLAP_AND_RESET dest buffer and source buffer are overlapped and all parameters are valid
118 *
119 * If there is a runtime-constraint violation, strDest[0] will be set to the '\0' when strDest and destMax valid
120 *******************************************************************************
121 */
wcsncat_s(wchar_t * strDest,size_t destMax,const wchar_t * strSrc,size_t count)122 errno_t wcsncat_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc, size_t count)
123 {
124 if (destMax == 0 || destMax > SECUREC_WCHAR_STRING_MAX_LEN) {
125 SECUREC_ERROR_INVALID_RANGE("wcsncat_s");
126 return ERANGE;
127 }
128
129 if (strDest == NULL || strSrc == NULL) {
130 SECUREC_ERROR_INVALID_PARAMTER("wcsncat_s");
131 if (strDest != NULL) {
132 strDest[0] = '\0';
133 return EINVAL_AND_RESET;
134 }
135 return EINVAL;
136 }
137 #ifdef SECUREC_COMPATIBLE_WIN_FORMAT
138 if (count > SECUREC_WCHAR_STRING_MAX_LEN && count != ((size_t)-1)) {
139 strDest[0] = '\0';
140 SECUREC_ERROR_INVALID_RANGE("wcsncat_s");
141 return ERANGE_AND_RESET;
142 }
143 #else
144 if (count > SECUREC_WCHAR_STRING_MAX_LEN) {
145 strDest[0] = '\0';
146 SECUREC_ERROR_INVALID_RANGE("wcsncat_s");
147 return ERANGE_AND_RESET;
148 }
149 #endif
150
151 return SecDoWcsncat(strDest, destMax, strSrc, count);
152 }
153
154
155