1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <errno.h>
20 #include <stdlib.h>
21 #include <string.h>
22 
23 #include <limits>
24 #include <string>
25 #include <type_traits>
26 
27 namespace android {
28 namespace base {
29 
30 // Parses the unsigned decimal or hexadecimal integer in the string 's' and sets
31 // 'out' to that value if it is specified. Optionally allows the caller to
32 // define a 'max' beyond which otherwise valid values will be rejected. Returns
33 // boolean success; 'out' is untouched if parsing fails.
34 template <typename T>
35 bool ParseUint(const char* s, T* out, T max = std::numeric_limits<T>::max(),
36                bool allow_suffixes = false) {
37   static_assert(std::is_unsigned<T>::value, "ParseUint can only be used with unsigned types");
38   while (isspace(*s)) {
39     s++;
40   }
41 
42   if (s[0] == '-') {
43     errno = EINVAL;
44     return false;
45   }
46 
47   // This is never out of bounds. If string is zero-sized, s[0] == '\0'
48   // so the second condition is not checked. If string is "0",
49   // s[1] will compare against the '\0'.
50   int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
51   errno = 0;
52   char* end;
53   unsigned long long int result = strtoull(s, &end, base);
54   if (errno != 0) {
55     return false;
56   }
57   if (end == s) {
58     errno = EINVAL;
59     return false;
60   }
61   if (*end != '\0') {
62     const char* suffixes = "bkmgtpe";
63     const char* suffix;
64     if ((!allow_suffixes || (suffix = strchr(suffixes, tolower(*end))) == nullptr) ||
65         __builtin_mul_overflow(result, 1ULL << (10 * (suffix - suffixes)), &result)) {
66       errno = EINVAL;
67       return false;
68     }
69   }
70   if (max < result) {
71     errno = ERANGE;
72     return false;
73   }
74   if (out != nullptr) {
75     *out = static_cast<T>(result);
76   }
77   return true;
78 }
79 
80 // TODO: string_view
81 template <typename T>
82 bool ParseUint(const std::string& s, T* out, T max = std::numeric_limits<T>::max(),
83                bool allow_suffixes = false) {
84   return ParseUint(s.c_str(), out, max, allow_suffixes);
85 }
86 
87 template <typename T>
88 bool ParseByteCount(const char* s, T* out, T max = std::numeric_limits<T>::max()) {
89   return ParseUint(s, out, max, true);
90 }
91 
92 // TODO: string_view
93 template <typename T>
94 bool ParseByteCount(const std::string& s, T* out, T max = std::numeric_limits<T>::max()) {
95   return ParseByteCount(s.c_str(), out, max);
96 }
97 
98 // Parses the signed decimal or hexadecimal integer in the string 's' and sets
99 // 'out' to that value if it is specified. Optionally allows the caller to
100 // define a 'min' and 'max' beyond which otherwise valid values will be
101 // rejected. Returns boolean success; 'out' is untouched if parsing fails.
102 template <typename T>
103 bool ParseInt(const char* s, T* out, T min = std::numeric_limits<T>::min(),
104               T max = std::numeric_limits<T>::max()) {
105   static_assert(std::is_signed<T>::value, "ParseInt can only be used with signed types");
106   while (isspace(*s)) {
107     s++;
108   }
109 
110   int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
111   errno = 0;
112   char* end;
113   long long int result = strtoll(s, &end, base);
114   if (errno != 0) {
115     return false;
116   }
117   if (s == end || *end != '\0') {
118     errno = EINVAL;
119     return false;
120   }
121   if (result < min || max < result) {
122     errno = ERANGE;
123     return false;
124   }
125   if (out != nullptr) {
126     *out = static_cast<T>(result);
127   }
128   return true;
129 }
130 
131 // TODO: string_view
132 template <typename T>
133 bool ParseInt(const std::string& s, T* out, T min = std::numeric_limits<T>::min(),
134               T max = std::numeric_limits<T>::max()) {
135   return ParseInt(s.c_str(), out, min, max);
136 }
137 
138 }  // namespace base
139 }  // namespace android
140