1 //
2 // _ctype.cpp
3 //
4 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //
6 // Functions for converting integers to strings.
7 //
8 #include <corecrt_internal.h>
9 #include <corecrt_internal_securecrt.h>
10 #include <limits.h>
11 #include <stdlib.h>
12
13 #pragma warning(disable:__WARNING_NOT_SATISFIED) // 28020 Prefast thinks that 18446744073709551615 < 1.
14 #pragma warning(disable:__WARNING_RANGE_PRECONDITION_VIOLATION) // 26060 Prefast thinks that 18446744073709551615 < 1.
15
16 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17 //
18 // Common Conversion Implementation
19 //
20 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
21 namespace
22 {
23 template <typename T> struct make_signed;
24 template <> struct make_signed<unsigned long> { typedef long type; };
25 template <> struct make_signed<unsigned __int64> { typedef __int64 type; };
26 }
27
28
29
30 template <typename UnsignedInteger, typename Character>
31 _Success_(return == 0)
32 static errno_t __cdecl common_xtox(
33 UnsignedInteger const original_value,
34 _Out_writes_z_(buffer_count) Character* const buffer,
35 _When_(is_negative == true, _In_range_(>=, 2)) _In_range_(>=, 1)
36 size_t const buffer_count,
37 unsigned const radix,
38 bool const is_negative
39 ) throw()
40 {
41 // OACR isn't able to track that p stays within the bounds of [buffer, buffer + buffer_count) so manually verified and disabled warning
42 #pragma warning(push)
43 #pragma warning(disable:26014)
44 Character* p = buffer; // pointer to traverse the string
45 size_t length = 0; // current length of string
46
47 UnsignedInteger remaining_value = original_value;;
48
49 if (is_negative)
50 {
51 *p++ = '-';
52 ++length;
53
54 remaining_value = static_cast<UnsignedInteger>(
55 -static_cast<typename make_signed<UnsignedInteger>::type>(remaining_value)
56 );
57 }
58
59 Character* first_digit = p;
60
61 do
62 {
63 unsigned const digit = static_cast<unsigned>(remaining_value % radix);
64 remaining_value /= radix;
65
66 // Convert to ASCII and store:
67 if (digit > 9)
68 {
69 *p++ = static_cast<Character>(digit - 10 + 'a');
70 }
71 else
72 {
73 *p++ = static_cast<Character>(digit + '0');
74 }
75
76 ++length;
77 }
78 while (remaining_value > 0 && length < buffer_count);
79
80 if (length >= buffer_count)
81 {
82 buffer[0] = '\0';
83 _VALIDATE_RETURN_ERRCODE(length < buffer_count, ERANGE);
84 }
85
86 // We now have the digits of the number in the buffer, but in reverse order.
87 // Reverse the order, but first terminate the string:
88 *p-- = '\0';
89
90 do
91 {
92 Character const t = *p;
93 *p = *first_digit;
94 *first_digit = t;
95 --p;
96 ++first_digit;
97 }
98 while (first_digit < p);
99
100 return 0;
101 #pragma warning(pop)
102 }
103
104 template <typename UnsignedInteger, typename Character>
105 _Success_(return == 0)
common_xtox_s(UnsignedInteger const value,_Out_writes_z_ (buffer_count)Character * const buffer,size_t const buffer_count,unsigned const radix,bool const is_negative)106 static errno_t __cdecl common_xtox_s(
107 UnsignedInteger const value,
108 _Out_writes_z_(buffer_count) Character* const buffer,
109 size_t const buffer_count,
110 unsigned const radix,
111 bool const is_negative
112 ) throw()
113 {
114 _VALIDATE_RETURN_ERRCODE(buffer != nullptr, EINVAL);
115 _VALIDATE_RETURN_ERRCODE(buffer_count > 0, EINVAL);
116 _RESET_STRING(buffer, buffer_count);
117 _VALIDATE_RETURN_ERRCODE(buffer_count > static_cast<size_t>(is_negative ? 2 : 1), ERANGE);
118 _VALIDATE_RETURN_ERRCODE(2 <= radix && radix <= 36, EINVAL);
119
120 return common_xtox(value, buffer, buffer_count, radix, is_negative);
121 }
122
123
124
125 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
126 //
127 // 32-bit Integers => Narrow Strings
128 //
129 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
_itoa_s(int const value,char * const buffer,size_t const buffer_count,int const radix)130 extern "C" errno_t __cdecl _itoa_s(
131 int const value,
132 char* const buffer,
133 size_t const buffer_count,
134 int const radix
135 )
136 {
137 bool const is_negative = radix == 10 && value < 0;
138 return common_xtox_s(static_cast<unsigned long>(value), buffer, buffer_count, radix, is_negative);
139 }
140
_ltoa_s(long const value,char * const buffer,size_t const buffer_count,int const radix)141 extern "C" errno_t __cdecl _ltoa_s(
142 long const value,
143 char* const buffer,
144 size_t const buffer_count,
145 int const radix
146 )
147 {
148 bool const is_negative = radix == 10 && value < 0;
149 return common_xtox_s(static_cast<unsigned long>(value), buffer, buffer_count, radix, is_negative);
150 }
151
_ultoa_s(unsigned long const value,char * const buffer,size_t const buffer_count,int const radix)152 extern "C" errno_t __cdecl _ultoa_s(
153 unsigned long const value,
154 char* const buffer,
155 size_t const buffer_count,
156 int const radix
157 )
158 {
159 return common_xtox_s(value, buffer, buffer_count, radix, false);
160 }
161
162
163
_itoa(int const value,char * const buffer,int const radix)164 extern "C" char* __cdecl _itoa(
165 int const value,
166 char* const buffer,
167 int const radix
168 )
169 {
170 bool const is_negative = radix == 10 && value < 0;
171 common_xtox(static_cast<unsigned long>(value), buffer, _CRT_UNBOUNDED_BUFFER_SIZE, radix, is_negative);
172 return buffer;
173 }
174
_ltoa(long const value,char * const buffer,int const radix)175 extern "C" char* __cdecl _ltoa(
176 long const value,
177 char* const buffer,
178 int const radix
179 )
180 {
181 bool const is_negative = radix == 10 && value < 0;
182 common_xtox(static_cast<unsigned long>(value), buffer, _CRT_UNBOUNDED_BUFFER_SIZE, radix, is_negative);
183 return buffer;
184 }
185
_ultoa(unsigned long const value,char * const buffer,int const radix)186 extern "C" char* __cdecl _ultoa(
187 unsigned long const value,
188 char* const buffer,
189 int const radix
190 )
191 {
192 common_xtox(value, buffer, _CRT_UNBOUNDED_BUFFER_SIZE, radix, false);
193 return buffer;
194 }
195
196
197
198 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
199 //
200 // 64-bit Integers => Narrow Strings
201 //
202 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
_i64toa_s(__int64 const value,char * const buffer,size_t const buffer_count,int const radix)203 extern "C" errno_t __cdecl _i64toa_s(
204 __int64 const value,
205 char* const buffer,
206 size_t const buffer_count,
207 int const radix
208 )
209 {
210 bool const is_negative = radix == 10 && value < 0;
211 return common_xtox_s(static_cast<unsigned __int64>(value), buffer, buffer_count, radix, is_negative);
212 }
213
_ui64toa_s(unsigned __int64 const value,char * const buffer,size_t const buffer_count,int const radix)214 extern "C" errno_t __cdecl _ui64toa_s(
215 unsigned __int64 const value,
216 char* const buffer,
217 size_t const buffer_count,
218 int const radix
219 )
220 {
221 return common_xtox_s(value, buffer, buffer_count, radix, false);
222 }
223
224
225
_i64toa(__int64 const value,char * const buffer,int const radix)226 extern "C" char* __cdecl _i64toa(
227 __int64 const value,
228 char* const buffer,
229 int const radix
230 )
231 {
232 bool const is_negative = radix == 10 && value < 0;
233 common_xtox(static_cast<unsigned __int64>(value), buffer, _CRT_UNBOUNDED_BUFFER_SIZE, radix, is_negative);
234 return buffer;
235 }
236
_ui64toa(unsigned __int64 const value,char * const buffer,int const radix)237 extern "C" char* __cdecl _ui64toa(
238 unsigned __int64 const value,
239 char* const buffer,
240 int const radix
241 )
242 {
243 common_xtox(value, buffer, _CRT_UNBOUNDED_BUFFER_SIZE, radix, false);
244 return buffer;
245 }
246
247
248
249 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
250 //
251 // 32-bit Integers => Wide Strings
252 //
253 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
_itow_s(int const value,wchar_t * const buffer,size_t const buffer_count,int const radix)254 extern "C" errno_t __cdecl _itow_s(
255 int const value,
256 wchar_t* const buffer,
257 size_t const buffer_count,
258 int const radix
259 )
260 {
261 bool const is_negative = radix == 10 && value < 0;
262 return common_xtox_s(static_cast<unsigned long>(value), buffer, buffer_count, radix, is_negative);
263 }
264
_ltow_s(long const value,wchar_t * const buffer,size_t const buffer_count,int const radix)265 extern "C" errno_t __cdecl _ltow_s(
266 long const value,
267 wchar_t* const buffer,
268 size_t const buffer_count,
269 int const radix
270 )
271 {
272 bool const is_negative = radix == 10 && value < 0;
273 return common_xtox_s(static_cast<unsigned long>(value), buffer, buffer_count, radix, is_negative);
274 }
275
_ultow_s(unsigned long const value,wchar_t * const buffer,size_t const buffer_count,int const radix)276 extern "C" errno_t __cdecl _ultow_s(
277 unsigned long const value,
278 wchar_t* const buffer,
279 size_t const buffer_count,
280 int const radix
281 )
282 {
283 return common_xtox_s(value, buffer, buffer_count, radix, false);
284 }
285
286
287
_itow(int const value,wchar_t * const buffer,int const radix)288 extern "C" wchar_t* __cdecl _itow(
289 int const value,
290 wchar_t* const buffer,
291 int const radix
292 )
293 {
294 bool const is_negative = radix == 10 && value < 0;
295 common_xtox(static_cast<unsigned long>(value), buffer, _CRT_UNBOUNDED_BUFFER_SIZE, radix, is_negative);
296 return buffer;
297 }
298
_ltow(long const value,wchar_t * const buffer,int const radix)299 extern "C" wchar_t* __cdecl _ltow(
300 long const value,
301 wchar_t* const buffer,
302 int const radix
303 )
304 {
305 bool const is_negative = radix == 10 && value < 0;
306 common_xtox(static_cast<unsigned long>(value), buffer, _CRT_UNBOUNDED_BUFFER_SIZE, radix, is_negative);
307 return buffer;
308 }
309
_ultow(unsigned long const value,wchar_t * const buffer,int const radix)310 extern "C" wchar_t* __cdecl _ultow(
311 unsigned long const value,
312 wchar_t* const buffer,
313 int const radix
314 )
315 {
316 common_xtox(value, buffer, _CRT_UNBOUNDED_BUFFER_SIZE, radix, false);
317 return buffer;
318 }
319
320
321
322 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
323 //
324 // 64-bit Integers => Wide Strings
325 //
326 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
_i64tow_s(__int64 const value,wchar_t * const buffer,size_t const buffer_count,int const radix)327 extern "C" errno_t __cdecl _i64tow_s(
328 __int64 const value,
329 wchar_t* const buffer,
330 size_t const buffer_count,
331 int const radix
332 )
333 {
334 bool const is_negative = radix == 10 && value < 0;
335 return common_xtox_s(static_cast<unsigned __int64>(value), buffer, buffer_count, radix, is_negative);
336 }
337
_ui64tow_s(unsigned __int64 const value,wchar_t * const buffer,size_t const buffer_count,int const radix)338 extern "C" errno_t __cdecl _ui64tow_s(
339 unsigned __int64 const value,
340 wchar_t* const buffer,
341 size_t const buffer_count,
342 int const radix
343 )
344 {
345 return common_xtox_s(value, buffer, buffer_count, radix, false);
346 }
347
348
349
_i64tow(__int64 const value,wchar_t * const buffer,int const radix)350 extern "C" wchar_t* __cdecl _i64tow(
351 __int64 const value,
352 wchar_t* const buffer,
353 int const radix
354 )
355 {
356 bool const is_negative = radix == 10 && value < 0;
357 common_xtox(static_cast<unsigned __int64>(value), buffer, _CRT_UNBOUNDED_BUFFER_SIZE, radix, is_negative);
358 return buffer;
359 }
360
_ui64tow(unsigned __int64 const value,wchar_t * const buffer,int const radix)361 extern "C" wchar_t* __cdecl _ui64tow(
362 unsigned __int64 const value,
363 wchar_t* const buffer,
364 int const radix
365 )
366 {
367 common_xtox(value, buffer, _CRT_UNBOUNDED_BUFFER_SIZE, radix, false);
368 return buffer;
369 }
370