Reactos
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//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
21namespace
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
30template <typename UnsignedInteger, typename Character>
31_Success_(return == 0)
32static 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
104template <typename UnsignedInteger, typename Character>
105_Success_(return == 0)
106static 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//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
130extern "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
141extern "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
152extern "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
164extern "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
175extern "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
186extern "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//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
203extern "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
214extern "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
226extern "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
237extern "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//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
254extern "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
265extern "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
276extern "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
288extern "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
299extern "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
310extern "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//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
327extern "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
338extern "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
350extern "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
361extern "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}