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