xref: /aosp_15_r20/external/lzma/CPP/Common/StringToInt.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // Common/StringToInt.cpp
2 
3 #include "StdAfx.h"
4 
5 #include <limits.h>
6 #if defined(_MSC_VER) && (_MSC_VER >= 1600)
7 #include <stdint.h> // for WCHAR_MAX in vs2022
8 #endif
9 
10 #include "StringToInt.h"
11 
12 static const UInt32 k_UInt32_max = 0xFFFFFFFF;
13 static const UInt64 k_UInt64_max = UINT64_CONST(0xFFFFFFFFFFFFFFFF);
14 // static const UInt64 k_UInt64_max = (UInt64)(Int64)-1;
15 
16 #define DIGIT_TO_VALUE(charTypeUnsigned, digit)   ((unsigned)(charTypeUnsigned)digit - '0')
17 // #define DIGIT_TO_VALUE(charTypeUnsigned, digit)   ((unsigned)digit - '0')
18 // #define DIGIT_TO_VALUE(charTypeUnsigned, digit)   ((unsigned)(digit - '0'))
19 
20 #define CONVERT_STRING_TO_UINT_FUNC(uintType, charType, charTypeUnsigned) \
21 uintType ConvertStringTo ## uintType(const charType *s, const charType **end) throw() { \
22     if (end) *end = s; \
23     uintType res = 0; \
24     for (;; s++) { \
25       const unsigned v = DIGIT_TO_VALUE(charTypeUnsigned, *s); \
26       if (v > 9) { if (end) *end = s; return res; } \
27       if (res > (k_ ## uintType ## _max) / 10) return 0; \
28       res *= 10; \
29       if (res > (k_ ## uintType ## _max) - v) return 0; \
30       res += v; }}
31 
32 // arm-linux-gnueabi GCC compilers give (WCHAR_MAX > UINT_MAX) by some unknown reason
33 // so we don't use this branch
34 #if 0 && WCHAR_MAX > UINT_MAX
35 /*
36    if (sizeof(wchar_t) > sizeof(unsigned)
37       we must use CONVERT_STRING_TO_UINT_FUNC_SLOW
38    But we just stop compiling instead.
39    We need some real cases to test this code.
40 */
41 #error Stop_Compiling_WCHAR_MAX_IS_LARGER_THAN_UINT_MAX
42 #define CONVERT_STRING_TO_UINT_FUNC_SLOW(uintType, charType, charTypeUnsigned) \
43 uintType ConvertStringTo ## uintType(const charType *s, const charType **end) throw() { \
44     if (end) *end = s; \
45     uintType res = 0; \
46     for (;; s++) { \
47       const charTypeUnsigned c = (charTypeUnsigned)*s; \
48       if (c < '0' || c > '9') { if (end) *end = s; return res; } \
49       if (res > (k_ ## uintType ## _max) / 10) return 0; \
50       res *= 10; \
51       const unsigned v = (unsigned)(c - '0'); \
52       if (res > (k_ ## uintType ## _max) - v) return 0; \
53       res += v; }}
54 #endif
55 
56 
CONVERT_STRING_TO_UINT_FUNC(UInt32,char,Byte)57 CONVERT_STRING_TO_UINT_FUNC(UInt32, char, Byte)
58 CONVERT_STRING_TO_UINT_FUNC(UInt32, wchar_t, wchar_t)
59 CONVERT_STRING_TO_UINT_FUNC(UInt64, char, Byte)
60 CONVERT_STRING_TO_UINT_FUNC(UInt64, wchar_t, wchar_t)
61 
62 Int32 ConvertStringToInt32(const wchar_t *s, const wchar_t **end) throw()
63 {
64   if (end)
65     *end = s;
66   const wchar_t *s2 = s;
67   if (*s == '-')
68     s2++;
69   const wchar_t *end2;
70   UInt32 res = ConvertStringToUInt32(s2, &end2);
71   if (s2 == end2)
72     return 0;
73   if (s != s2)
74   {
75     if (res > (UInt32)1 << (32 - 1))
76       return 0;
77     res = 0 - res;
78   }
79   else
80   {
81     if (res & (UInt32)1 << (32 - 1))
82       return 0;
83   }
84   if (end)
85     *end = end2;
86   return (Int32)res;
87 }
88 
89 
90 #define CONVERT_OCT_STRING_TO_UINT_FUNC(uintType) \
91 uintType ConvertOctStringTo ## uintType(const char *s, const char **end) throw() \
92 { \
93   if (end) *end = s; \
94   uintType res = 0; \
95   for (;; s++) { \
96     const unsigned c = (unsigned)(Byte)*s - '0'; \
97     if (c > 7) { \
98       if (end) \
99         *end = s; \
100       return res; \
101     } \
102     if (res & (uintType)7 << (sizeof(uintType) * 8 - 3)) \
103       return 0; \
104     res <<= 3; \
105     res |= c; \
106   } \
107 }
108 
109 CONVERT_OCT_STRING_TO_UINT_FUNC(UInt32)
CONVERT_OCT_STRING_TO_UINT_FUNC(UInt64)110 CONVERT_OCT_STRING_TO_UINT_FUNC(UInt64)
111 
112 
113 #define CONVERT_HEX_STRING_TO_UINT_FUNC(uintType) \
114 uintType ConvertHexStringTo ## uintType(const char *s, const char **end) throw() \
115 { \
116   if (end) *end = s; \
117   uintType res = 0; \
118   for (;; s++) { \
119     unsigned c = (unsigned)(Byte)*s; \
120     Z7_PARSE_HEX_DIGIT(c, { if (end) *end = s;  return res; }) \
121     if (res & (uintType)0xF << (sizeof(uintType) * 8 - 4)) \
122       return 0; \
123     res <<= 4; \
124     res |= c; \
125   } \
126 }
127 
128 CONVERT_HEX_STRING_TO_UINT_FUNC(UInt32)
129 CONVERT_HEX_STRING_TO_UINT_FUNC(UInt64)
130 
131 const char *FindNonHexChar(const char *s) throw()
132 {
133   for (;;)
134   {
135     unsigned c = (Byte)*s++; // pointer can go 1 byte after end
136     c -= '0';
137     if (c <= 9)
138       continue;
139     c -= 'A' - '0';
140     c &= ~0x20u;
141     if (c > 5)
142       return s - 1;
143   }
144 }
145 
ParseHexString(const char * s,Byte * dest)146 Byte *ParseHexString(const char *s, Byte *dest) throw()
147 {
148   for (;;)
149   {
150     unsigned v0 = (Byte)s[0];         Z7_PARSE_HEX_DIGIT(v0, return dest;)
151     unsigned v1 = (Byte)s[1]; s += 2; Z7_PARSE_HEX_DIGIT(v1, return dest;)
152     *dest++ = (Byte)(v1 | (v0 << 4));
153   }
154 }
155