xref: /reactos/sdk/lib/ucrt/convert/xtoa.cpp (revision 04e0dc4a)
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