1 //
2 // corecrt_internal_string_templates.h
3 //
4 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //
6 // This internal header defines template implementations of several secure
7 // string functions that have identical implementations for both narrow and
8 // wide character strings.
9 //
10 #pragma once
11
12 #include <corecrt_internal_securecrt.h>
13
14
15
16 // _strcat_s() and _wcscat_s()
17 template <typename Character>
18 _Success_(return == 0)
common_tcscat_s(_Inout_updates_z_ (size_in_elements)Character * const destination,size_t const size_in_elements,_In_z_ Character const * const source)19 static errno_t __cdecl common_tcscat_s(
20 _Inout_updates_z_(size_in_elements) Character* const destination,
21 size_t const size_in_elements,
22 _In_z_ Character const* const source
23 ) throw()
24 {
25 _VALIDATE_STRING(destination, size_in_elements);
26 _VALIDATE_POINTER_RESET_STRING(source, destination, size_in_elements);
27
28 Character* destination_it = destination;
29 size_t available = size_in_elements;
30 while (available > 0 && *destination_it != 0)
31 {
32 ++destination_it;
33 --available;
34 }
35
36 if (available == 0)
37 {
38 _RESET_STRING(destination, size_in_elements);
39 _RETURN_DEST_NOT_NULL_TERMINATED(destination, size_in_elements);
40 }
41
42 Character const* source_it = source;
43 while ((*destination_it++ = *source_it++) != 0 && --available > 0)
44 {
45 }
46
47 if (available == 0)
48 {
49 _RESET_STRING(destination, size_in_elements);
50 _RETURN_BUFFER_TOO_SMALL(destination, size_in_elements);
51 }
52 _FILL_STRING(destination, size_in_elements, size_in_elements - available + 1);
53 _RETURN_NO_ERROR;
54 }
55
56
57
58 // _strcpy_s() and _wcscpy_s()
59 template <typename Character>
60 _Success_(return == 0)
common_tcscpy_s(_Out_writes_z_ (size_in_elements)Character * const destination,_In_ size_t const size_in_elements,_In_z_ Character const * const source)61 static errno_t __cdecl common_tcscpy_s(
62 _Out_writes_z_(size_in_elements) Character* const destination,
63 _In_ size_t const size_in_elements,
64 _In_z_ Character const* const source
65 ) throw()
66 {
67 _VALIDATE_STRING(destination, size_in_elements);
68 _VALIDATE_POINTER_RESET_STRING(source, destination, size_in_elements);
69
70 Character* destination_it = destination;
71 Character const* source_it = source;
72
73 size_t available = size_in_elements;
74 while ((*destination_it++ = *source_it++) != 0 && --available > 0)
75 {
76 }
77
78 if (available == 0)
79 {
80 _RESET_STRING(destination, size_in_elements);
81 _RETURN_BUFFER_TOO_SMALL(destination, size_in_elements);
82 }
83 _FILL_STRING(destination, size_in_elements, size_in_elements - available + 1);
84 _RETURN_NO_ERROR;
85 }
86
87
88
89 // _strncat_s() and _wcsncat_s()
90 template <typename Character>
91 _Success_(return == 0)
common_tcsncat_s(_Inout_updates_z_ (size_in_elements)Character * const destination,_In_ size_t const size_in_elements,_In_reads_or_z_ (count)Character const * const source,_In_ size_t const count)92 static errno_t __cdecl common_tcsncat_s(
93 _Inout_updates_z_(size_in_elements) Character* const destination,
94 _In_ size_t const size_in_elements,
95 _In_reads_or_z_(count) Character const* const source,
96 _In_ size_t const count
97 ) throw()
98 {
99 if (count == 0 && destination == nullptr && size_in_elements == 0)
100 {
101 // This case is allowed; nothing to do:
102 _RETURN_NO_ERROR;
103 }
104
105 _VALIDATE_STRING(destination, size_in_elements);
106 if (count != 0)
107 {
108 _VALIDATE_POINTER_RESET_STRING(source, destination, size_in_elements);
109 }
110
111 Character* destination_it = destination;
112
113 size_t available = size_in_elements;
114 size_t remaining = count;
115 while (available > 0 && *destination_it != 0)
116 {
117 ++destination_it;
118 --available;
119 }
120
121 if (available == 0)
122 {
123 _RESET_STRING(destination, size_in_elements);
124 _RETURN_DEST_NOT_NULL_TERMINATED(destination, size_in_elements);
125 }
126
127 Character const* source_it = source;
128 if (count == _TRUNCATE)
129 {
130 while ((*destination_it++ = *source_it++) != 0 && --available > 0)
131 {
132 }
133 }
134 else
135 {
136 while (remaining > 0 && (*destination_it++ = *source_it++) != 0 && --available > 0)
137 {
138 remaining--;
139 }
140
141 if (remaining == 0)
142 {
143 *destination_it = 0;
144 }
145 }
146
147 if (available == 0)
148 {
149 if (count == _TRUNCATE)
150 {
151 destination[size_in_elements - 1] = 0;
152 _RETURN_TRUNCATE;
153 }
154 _RESET_STRING(destination, size_in_elements);
155 _RETURN_BUFFER_TOO_SMALL(destination, size_in_elements);
156 }
157 _FILL_STRING(destination, size_in_elements, size_in_elements - available + 1);
158 _RETURN_NO_ERROR;
159 }
160
161
162
163 // _strncpy_s() and _wcsncpy_s()
164 template <typename Character>
165 _Success_(return == 0)
common_tcsncpy_s(_Out_writes_z_ (size_in_elements)Character * const destination,_In_ size_t const size_in_elements,_In_reads_or_z_ (count)Character const * const source,_In_ size_t const count)166 static errno_t __cdecl common_tcsncpy_s(
167 _Out_writes_z_(size_in_elements) Character* const destination,
168 _In_ size_t const size_in_elements,
169 _In_reads_or_z_(count) Character const* const source,
170 _In_ size_t const count
171 ) throw()
172 {
173 if (count == 0 && destination == nullptr && size_in_elements == 0)
174 {
175 // this case is allowed; nothing to do:
176 _RETURN_NO_ERROR;
177 }
178
179 _VALIDATE_STRING(destination, size_in_elements);
180 if (count == 0)
181 {
182 // Notice that the source string pointer can be nullptr in this case:
183 _RESET_STRING(destination, size_in_elements);
184 _RETURN_NO_ERROR;
185 }
186 _VALIDATE_POINTER_RESET_STRING(source, destination, size_in_elements);
187
188 Character* destination_it = destination;
189 Character const* source_it = source;
190
191 size_t available = size_in_elements;
192 size_t remaining = count;
193 if (count == _TRUNCATE)
194 {
195 while ((*destination_it++ = *source_it++) != 0 && --available > 0)
196 {
197 }
198 }
199 else
200 {
201 while ((*destination_it++ = *source_it++) != 0 && --available > 0 && --remaining > 0)
202 {
203 }
204 if (remaining == 0)
205 {
206 *destination_it = 0;
207 }
208 }
209
210 if (available == 0)
211 {
212 if (count == _TRUNCATE)
213 {
214 destination[size_in_elements - 1] = 0;
215 _RETURN_TRUNCATE;
216 }
217 _RESET_STRING(destination, size_in_elements);
218 _RETURN_BUFFER_TOO_SMALL(destination, size_in_elements);
219 }
220 _FILL_STRING(destination, size_in_elements, size_in_elements - available + 1);
221 _RETURN_NO_ERROR;
222 }
223
224
225
226 // _strnset_s() and _wcsnset_s()
227 template <typename Character>
228 _Success_(return == 0)
common_tcsnset_s(_Inout_updates_z_ (size_in_elements)Character * const destination,_In_ size_t const size_in_elements,_In_ Character const value,_In_ size_t const count)229 static errno_t __cdecl common_tcsnset_s(
230 _Inout_updates_z_(size_in_elements) Character* const destination,
231 _In_ size_t const size_in_elements,
232 _In_ Character const value,
233 _In_ size_t const count
234 ) throw()
235 {
236 if (count == 0 && destination == nullptr && size_in_elements == 0)
237 {
238 // This case is allowed; nothing to do:
239 _RETURN_NO_ERROR;
240 }
241 _VALIDATE_STRING(destination, size_in_elements);
242
243 Character* destination_it = destination;
244
245 size_t available = size_in_elements;
246 size_t remaining = count;
247 while (*destination_it != 0 && remaining > 0 && --available > 0)
248 {
249 *destination_it++ = value;
250 --remaining;
251 }
252
253 if (remaining == 0)
254 {
255 // Ensure the string is null-terminated:
256 while (*destination_it != 0 && --available > 0)
257 {
258 ++destination_it;
259 }
260 }
261
262 if (available == 0)
263 {
264 _RESET_STRING(destination, size_in_elements);
265 _RETURN_DEST_NOT_NULL_TERMINATED(destination, size_in_elements);
266 }
267 _FILL_STRING(destination, size_in_elements, size_in_elements - available + 1);
268 _RETURN_NO_ERROR;
269 }
270
271
272
273 // _strset_s() and _wcsset_s()
274 template <typename Character>
275 _Success_(return == 0)
common_tcsset_s(_Inout_updates_z_ (size_in_elements)Character * const destination,_In_ size_t const size_in_elements,_In_ Character const value)276 static errno_t __cdecl common_tcsset_s(
277 _Inout_updates_z_(size_in_elements) Character* const destination,
278 _In_ size_t const size_in_elements,
279 _In_ Character const value
280 ) throw()
281 {
282 _VALIDATE_STRING(destination, size_in_elements);
283
284 Character* destination_it = destination;
285
286 size_t available = size_in_elements;
287 while (*destination_it != 0 && --available > 0)
288 {
289 *destination_it++ = value;
290 }
291
292 if (available == 0)
293 {
294 _RESET_STRING(destination, size_in_elements);
295 _RETURN_DEST_NOT_NULL_TERMINATED(destination, size_in_elements);
296 }
297 _FILL_STRING(destination, size_in_elements, size_in_elements - available + 1);
298 _RETURN_NO_ERROR;
299 }
300