DotNetDupe 4.0.6
C++17/20 Implementation of the .NET Base Class Library (BCL)
Loading...
Searching...
No Matches
Convert.cpp
Go to the documentation of this file.
1#include "pch.h"
2#include "System/Convert.h"
3#include "System/Array.h"
7#include <string>
8#include <limits>
9#include <algorithm>
10#include <cwctype>
11#include <cstring>
12#include <vector>
13
14namespace DotNetDupe {
15 namespace System {
16
17 template<typename Target, typename Source>
18 static Target CheckRange(Source value) {
19 if (value < (Source)(std::numeric_limits<Target>::min)() || value > (Source)(std::numeric_limits<Target>::max)()) {
20 throw OverflowException("Value was either too large or too small for the target type.");
21 }
22 return (Target)value;
23 }
24
25 // Boolean
26 bool Convert::ToBoolean(bool bValue) { return bValue; }
27 bool Convert::ToBoolean(int iValue) { return iValue != 0; }
28 bool Convert::ToBoolean(long long llValue) { return llValue != 0; }
29 bool Convert::ToBoolean(double value) { return value != 0.0; }
30 bool Convert::ToBoolean(const char* value) { return ToBoolean(String(value)); }
31 bool Convert::ToBoolean(const String& sValue) {
32 std::string s = (const char*)sValue;
33 std::transform(s.begin(), s.end(), s.begin(), [](char c) { return (char)std::towlower(c); });
34 if (s == "true") return true;
35 if (s == "false") return false;
36 throw FormatException("String was not recognized as a valid Boolean.");
37 }
38
39 // Byte
40 unsigned char Convert::ToByte(bool bValue) { return bValue ? 1 : 0; }
41 unsigned char Convert::ToByte(unsigned char chValue) { return chValue; }
42 unsigned char Convert::ToByte(const char* value) { return ToByte(String(value)); }
43 unsigned char Convert::ToByte(const char* value, int fromBase) { return ToByte(String(value), fromBase); }
44 unsigned char Convert::ToByte(signed char chValue) { return CheckRange<unsigned char>(chValue); }
45 unsigned char Convert::ToByte(short iValue) { return CheckRange<unsigned char>(iValue); }
46 unsigned char Convert::ToByte(int iValue) { return CheckRange<unsigned char>(iValue); }
47 unsigned char Convert::ToByte(long long llValue) { return CheckRange<unsigned char>(llValue); }
48 unsigned char Convert::ToByte(double value) { return CheckRange<unsigned char>(value); }
49 unsigned char Convert::ToByte(const String& sValue) { return ToByte(sValue, 10); }
50 unsigned char Convert::ToByte(const String& sValue, int iFromBase) {
51 try {
52 size_t nPos;
53 long long llVal = std::stoll((const char*)sValue, &nPos, iFromBase);
54 if (nPos != sValue.GetLength()) throw FormatException("Input string was not in a correct format.");
55 return CheckRange<unsigned char>(llVal);
56 } catch (const std::invalid_argument&) {
57 throw FormatException("Input string was not in a correct format.");
58 } catch (const std::out_of_range&) {
59 throw OverflowException("Value was either too large or too small for an unsigned byte.");
60 }
61 }
62
63 // SByte
64 signed char Convert::ToSByte(bool bValue) { return bValue ? 1 : 0; }
65 signed char Convert::ToSByte(unsigned char chValue) { return CheckRange<signed char>(chValue); }
66 signed char Convert::ToSByte(const char* value) { return ToSByte(String(value)); }
67 signed char Convert::ToSByte(signed char chValue) { return chValue; }
68 signed char Convert::ToSByte(short iValue) { return CheckRange<signed char>(iValue); }
69 signed char Convert::ToSByte(int iValue) { return CheckRange<signed char>(iValue); }
70 signed char Convert::ToSByte(long long llValue) { return CheckRange<signed char>(llValue); }
71 signed char Convert::ToSByte(double value) { return CheckRange<signed char>(value); }
72 signed char Convert::ToSByte(const String& sValue) {
73 try {
74 size_t nPos;
75 long long llVal = std::stoll((const char*)sValue, &nPos, 10);
76 if (nPos != sValue.GetLength()) throw FormatException("Input string was not in a correct format.");
77 return CheckRange<signed char>(llVal);
78 } catch (const std::invalid_argument&) {
79 throw FormatException("Input string was not in a correct format.");
80 } catch (const std::out_of_range&) {
81 throw OverflowException("Value was either too large or too small for a signed byte.");
82 }
83 }
84
85 // Char
86 char Convert::ToChar(unsigned short iValue) { return (char)iValue; }
87 char Convert::ToChar(int iValue) { return CheckRange<char>(iValue); }
88 char Convert::ToChar(long long llValue) { return CheckRange<char>(llValue); }
89 char Convert::ToChar(const char* value) { return ToChar(String(value)); }
90 char Convert::ToChar(const String& sValue) {
91 if (sValue.GetLength() != 1) throw FormatException("String must be exactly one character long.");
92 return sValue[0];
93 }
94
95 // Double
96 double Convert::ToDouble(int iValue) { return (double)iValue; }
97 double Convert::ToDouble(long long llValue) { return (double)llValue; }
98 double Convert::ToDouble(float value) { return (double)value; }
99 double Convert::ToDouble(const char* value) { return ToDouble(String(value)); }
100 double Convert::ToDouble(const String& sValue) {
101 try {
102 size_t nPos;
103 double val = std::stod((const char*)sValue, &nPos);
104 if (nPos != sValue.GetLength()) throw FormatException("Input string was not in a correct format.");
105 return val;
106 } catch (const std::invalid_argument&) {
107 throw FormatException("Input string was not in a correct format.");
108 } catch (const std::out_of_range&) {
109 throw OverflowException("Value was either too large or too small for a Double.");
110 }
111 }
112
113 // Single
114 float Convert::ToSingle(int iValue) { return (float)iValue; }
115 float Convert::ToSingle(long long llValue) { return (float)llValue; }
116 float Convert::ToSingle(double value) { return (float)value; }
117 float Convert::ToSingle(const char* value) { return ToSingle(String(value)); }
118 float Convert::ToSingle(const String& sValue) {
119 try {
120 size_t nPos;
121 float val = std::stof((const char*)sValue, &nPos);
122 if (nPos != sValue.GetLength()) throw FormatException("Input string was not in a correct format.");
123 return val;
124 } catch (const std::invalid_argument&) {
125 throw FormatException("Input string was not in a correct format.");
126 } catch (const std::out_of_range&) {
127 throw OverflowException("Value was either too large or too small for a Single.");
128 }
129 }
130
131 // Int16
132 short Convert::ToInt16(bool bValue) { return bValue ? 1 : 0; }
133 short Convert::ToInt16(short iValue) { return iValue; }
134 short Convert::ToInt16(int iValue) { return CheckRange<short>(iValue); }
135 short Convert::ToInt16(long long llValue) { return CheckRange<short>(llValue); }
136 short Convert::ToInt16(double value) { return CheckRange<short>(value); }
137 short Convert::ToInt16(const char* value) { return ToInt16(String(value)); }
138 short Convert::ToInt16(const char* value, int fromBase) { return ToInt16(String(value), fromBase); }
139 short Convert::ToInt16(const String& sValue) { return ToInt16(sValue, 10); }
140 short Convert::ToInt16(const String& sValue, int iFromBase) {
141 try {
142 size_t nPos;
143 long long llVal = std::stoll((const char*)sValue, &nPos, iFromBase);
144 if (nPos != sValue.GetLength()) throw FormatException("Input string was not in a correct format.");
145 return CheckRange<short>(llVal);
146 } catch (const std::invalid_argument&) {
147 throw FormatException("Input string was not in a correct format.");
148 } catch (const std::out_of_range&) {
149 throw OverflowException("Value was either too large or too small for an Int16.");
150 }
151 }
152
153 // Int32
154 int Convert::ToInt32(bool bValue) { return bValue ? 1 : 0; }
155 int Convert::ToInt32(int iValue) { return iValue; }
156 int Convert::ToInt32(long long llValue) { return CheckRange<int>(llValue); }
157 int Convert::ToInt32(double value) { return CheckRange<int>(value); }
158 int Convert::ToInt32(const char* value) { return ToInt32(String(value)); }
159 int Convert::ToInt32(const char* value, int fromBase) { return ToInt32(String(value), fromBase); }
160 int Convert::ToInt32(const String& sValue) { return ToInt32(sValue, 10); }
161 int Convert::ToInt32(const String& sValue, int iFromBase) {
162 try {
163 size_t nPos;
164 long long llVal = std::stoll((const char*)sValue, &nPos, iFromBase);
165 if (nPos != sValue.GetLength()) throw FormatException("Input string was not in a correct format.");
166 return CheckRange<int>(llVal);
167 } catch (const std::invalid_argument&) {
168 throw FormatException("Input string was not in a correct format.");
169 } catch (const std::out_of_range&) {
170 throw OverflowException("Value was either too large or too small for an Int32.");
171 }
172 }
173
174 // Int64
175 long long Convert::ToInt64(bool bValue) { return bValue ? 1 : 0; }
176 long long Convert::ToInt64(int iValue) { return (long long)iValue; }
177 long long Convert::ToInt64(long long llValue) { return llValue; }
178 long long Convert::ToInt64(double value) { return (long long)value; }
179 long long Convert::ToInt64(const char* value) { return ToInt64(String(value)); }
180 long long Convert::ToInt64(const char* value, int fromBase) { return ToInt64(String(value), fromBase); }
181 long long Convert::ToInt64(const String& sValue) { return ToInt64(sValue, 10); }
182 long long Convert::ToInt64(const String& sValue, int iFromBase) {
183 try {
184 size_t nPos;
185 long long llVal = std::stoll((const char*)sValue, &nPos, iFromBase);
186 if (nPos != sValue.GetLength()) throw FormatException("Input string was not in a correct format.");
187 return llVal;
188 } catch (const std::invalid_argument&) {
189 throw FormatException("Input string was not in a correct format.");
190 } catch (const std::out_of_range&) {
191 throw OverflowException("Value was either too large or too small for an Int64.");
192 }
193 }
194
195 // UInt16
196 unsigned short Convert::ToUInt16(bool bValue) { return bValue ? 1 : 0; }
197 unsigned short Convert::ToUInt16(int iValue) { return CheckRange<unsigned short>(iValue); }
198 unsigned short Convert::ToUInt16(long long llValue) { return CheckRange<unsigned short>(llValue); }
199 unsigned short Convert::ToUInt16(double value) { return CheckRange<unsigned short>(value); }
200 unsigned short Convert::ToUInt16(const char* value) { return ToUInt16(String(value)); }
201 unsigned short Convert::ToUInt16(const String& sValue) {
202 try {
203 size_t nPos;
204 unsigned long long llVal = std::stoull((const char*)sValue, &nPos, 10);
205 if (nPos != sValue.GetLength()) throw FormatException("Input string was not in a correct format.");
206 return CheckRange<unsigned short>(llVal);
207 } catch (const std::invalid_argument&) {
208 throw FormatException("Input string was not in a correct format.");
209 } catch (const std::out_of_range&) {
210 throw OverflowException("Value was either too large or too small for a UInt16.");
211 }
212 }
213
214 // UInt32
215 unsigned int Convert::ToUInt32(bool bValue) { return bValue ? 1 : 0; }
216 unsigned int Convert::ToUInt32(int iValue) { return CheckRange<unsigned int>(iValue); }
217 unsigned int Convert::ToUInt32(long long llValue) { return CheckRange<unsigned int>(llValue); }
218 unsigned int Convert::ToUInt32(double value) { return CheckRange<unsigned int>(value); }
219 unsigned int Convert::ToUInt32(const char* value) { return ToUInt32(String(value)); }
220 unsigned int Convert::ToUInt32(const String& sValue) {
221 try {
222 size_t nPos;
223 unsigned long long llVal = std::stoull((const char*)sValue, &nPos, 10);
224 if (nPos != sValue.GetLength()) throw FormatException("Input string was not in a correct format.");
225 return CheckRange<unsigned int>(llVal);
226 } catch (const std::invalid_argument&) {
227 throw FormatException("Input string was not in a correct format.");
228 } catch (const std::out_of_range&) {
229 throw OverflowException("Value was either too large or too small for a UInt32.");
230 }
231 }
232
233 // UInt64
234 unsigned long long Convert::ToUInt64(bool bValue) { return bValue ? 1 : 0; }
235 unsigned long long Convert::ToUInt64(int iValue) { return CheckRange<unsigned long long>(iValue); }
236 unsigned long long Convert::ToUInt64(long long llValue) { return CheckRange<unsigned long long>(llValue); }
237 unsigned long long Convert::ToUInt64(double value) { return (unsigned long long)value; }
238 unsigned long long Convert::ToUInt64(const char* value) { return ToUInt64(String(value)); }
239 unsigned long long Convert::ToUInt64(const String& sValue) {
240 try {
241 size_t nPos;
242 unsigned long long llVal = std::stoull((const char*)sValue, &nPos, 10);
243 if (nPos != sValue.GetLength()) throw FormatException("Input string was not in a correct format.");
244 return llVal;
245 } catch (const std::invalid_argument&) {
246 throw FormatException("Input string was not in a correct format.");
247 } catch (const std::out_of_range&) {
248 throw OverflowException("Value was either too large or too small for a UInt64.");
249 }
250 }
251
252 // String
253 String Convert::ToString(bool bValue) { return bValue ? "True" : "False"; }
254 String Convert::ToString(unsigned char chValue) { return String(std::to_string(chValue).c_str()); }
255 String Convert::ToString(signed char chValue) { return String(std::to_string(chValue).c_str()); }
256 String Convert::ToString(char chValue) { char buf[2] = { chValue, 0 }; return String(buf); }
257 String Convert::ToString(double value) {
258 char buf[64];
259 snprintf(buf, sizeof(buf), "%g", value);
260 return String(buf);
261 }
263 char buf[64];
264 snprintf(buf, sizeof(buf), "%g", static_cast<double>(value));
265 return String(buf);
266 }
267 String Convert::ToString(short iValue) { return String(std::to_string(iValue).c_str()); }
268 String Convert::ToString(int iValue) { return String(std::to_string(iValue).c_str()); }
269 String Convert::ToString(long long llValue) { return String(std::to_string(llValue).c_str()); }
270 String Convert::ToString(unsigned short iValue) { return String(std::to_string(iValue).c_str()); }
271 String Convert::ToString(unsigned int iValue) { return String(std::to_string(iValue).c_str()); }
272 String Convert::ToString(unsigned long long llValue) { return String(std::to_string(llValue).c_str()); }
273
274 static String ToBaseString(unsigned long long llValue, int iToBase) {
275 if (iToBase != 2 && iToBase != 8 && iToBase != 10 && iToBase != 16)
276 throw ArgumentException("The base must be 2, 8, 10, or 16.");
277
278 if (llValue == 0) return "0";
279
280 std::string res;
281 const char* digits = "0123456789ABCDEF";
282 while (llValue > 0) {
283 res += digits[llValue % iToBase];
284 llValue /= iToBase;
285 }
286 std::reverse(res.begin(), res.end());
287 return String(res.c_str());
288 }
289
290 String Convert::ToString(int iValue, int iToBase) {
291 return ToBaseString((unsigned int)iValue, iToBase);
292 }
293 String Convert::ToString(long long llValue, int iToBase) {
294 return ToBaseString((unsigned long long)llValue, iToBase);
295 }
296
297 static const char base64_chars[] =
298 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
299 "abcdefghijklmnopqrstuvwxyz"
300 "0123456789+/";
301
302 static bool IsBase64(unsigned char c) {
303 return (isalnum(c) || (c == '+') || (c == '/'));
304 }
305
306 static void EncodeBase64Chunk4(const unsigned char* char_array_3, std::string& ret) {
307 unsigned char char_array_4[4];
308 char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
309 char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
310 char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
311 char_array_4[3] = char_array_3[2] & 0x3f;
312 for (int i = 0; i < 4; i++) ret += base64_chars[char_array_4[i]];
313 }
314
315 static void EncodeBase64Remainder(unsigned char* char_array_3, int remainderLen, std::string& ret) {
316 unsigned char char_array_4[4];
317 for (int j = remainderLen; j < 3; ++j) char_array_3[j] = '\0';
318 char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
319 char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
320 char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
321 for (int j = 0; j < remainderLen + 1; ++j) ret += base64_chars[char_array_4[j]];
322 for (int pad = remainderLen; pad < 3; ++pad) ret += '=';
323 }
324
326 int in_len = inArray.GetLength();
327 if (in_len == 0) return String("");
328 const unsigned char* bytes = reinterpret_cast<const unsigned char*>(inArray.GetData());
329 std::string ret;
330 int i = 0;
331 unsigned char char_array_3[3];
332 while (in_len--) {
333 char_array_3[i++] = *(bytes++);
334 if (i == 3) { EncodeBase64Chunk4(char_array_3, ret); i = 0; }
335 }
336 if (i) EncodeBase64Remainder(char_array_3, i, ret);
337 return String(ret.c_str());
338 }
339
340 static void DecodeBase64Chunk4(unsigned char* char_array_4, std::vector<char>& decoded) {
341 for (int k = 0; k < 4; k++) {
342 const char* ptr = std::strchr(base64_chars, char_array_4[k]);
343 if (ptr == nullptr) throw ArgumentException("Invalid base64 character");
344 char_array_4[k] = static_cast<unsigned char>(ptr - base64_chars);
345 }
346 decoded.push_back((char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4));
347 decoded.push_back(((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2));
348 decoded.push_back(((char_array_4[2] & 0x3) << 6) + char_array_4[3]);
349 }
350
351 static void DecodeBase64Remainder(unsigned char* char_array_4, int i, std::vector<char>& decoded) {
353 for (int j = 0; j < i; j++) {
354 const char* ptr = std::strchr(base64_chars, char_array_4[j]);
355 if (ptr == nullptr) throw ArgumentException("Invalid base64 character");
356 char_array_4[j] = static_cast<unsigned char>(ptr - base64_chars);
357 }
358
360 unsigned char char_array_3[2];
361 char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
362 if (i > 2) {
363 char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
364 decoded.push_back(char_array_3[0]);
365 decoded.push_back(char_array_3[1]);
366 } else if (i > 1) {
367 decoded.push_back(char_array_3[0]);
368 }
369 }
370
371 static void DecodeBase64Loop(const std::string& sInput, std::vector<char>& decoded) {
373 size_t in_len = sInput.size();
374 int i = 0, in_ = 0;
375 unsigned char char_array_4[4];
376 while (in_len-- && (sInput[in_] != '=') && IsBase64(sInput[in_])) {
377 char_array_4[i++] = sInput[in_++];
378 if (i == 4) {
379 DecodeBase64Chunk4(char_array_4, decoded);
380 i = 0;
381 }
382 }
383
385 if (i) DecodeBase64Remainder(char_array_4, i, decoded);
386 }
387
389 return FromBase64String(String(s));
390 }
391
393 std::string sInput(s.GetRawString() ? s.GetRawString() : "");
394 std::vector<char> decoded;
395 DecodeBase64Loop(sInput, decoded);
396 Array<char> result(static_cast<int>(decoded.size()));
397 for (size_t idx = 0; idx < decoded.size(); idx++) {
398 result[static_cast<int>(idx)] = decoded[idx];
399 }
400 return result;
401 }
402 }
403}
Defines the exception thrown when an invalid argument is provided to a method.
Provides methods for creating, manipulating, searching, and sorting arrays.
Converts a base data type to another base data type, and encodes/decodes Base64 data.
Defines the exception thrown when the format of an argument is invalid or not compliant with specific...
Defines the exception thrown when an arithmetic, casting, or conversion operation results in an overf...
ArgumentException(const String &sMessage)
Initializes a new instance of the ArgumentException class with a specified error message.
Provides methods for creating, manipulating, searching, and sorting arrays, thereby serving as the ba...
Definition Array.h:29
int GetLength() const
Gets the total number of elements in all dimensions of the Array.
Definition Array.h:142
T * GetData()
Gets a pointer to the contiguous internal element buffer.
Definition Array.h:146
static long long ToInt64(bool value)
Definition Convert.cpp:175
static bool ToBoolean(bool value)
Definition Convert.cpp:26
static unsigned char ToByte(bool value)
Definition Convert.cpp:40
static String ToString(bool value)
Definition Convert.cpp:253
static Array< char > FromBase64String(const String &s)
Definition Convert.cpp:392
static unsigned long long ToUInt64(bool value)
Definition Convert.cpp:234
static unsigned short ToUInt16(bool value)
Definition Convert.cpp:196
static double ToDouble(int value)
Definition Convert.cpp:96
static String ToBase64String(const Array< char > &inArray)
Definition Convert.cpp:325
static signed char ToSByte(bool value)
Definition Convert.cpp:64
static char ToChar(unsigned short value)
Definition Convert.cpp:86
static unsigned int ToUInt32(bool value)
Definition Convert.cpp:215
static short ToInt16(bool value)
Definition Convert.cpp:132
static int ToInt32(bool value)
Definition Convert.cpp:154
static float ToSingle(int value)
Definition Convert.cpp:114
FormatException(const String &sMessage)
Initializes a new instance of the FormatException class with a specified error message.
OverflowException(const String &sMessage)
Initializes a new instance of the OverflowException class with a specified error message.
Represents text as a sequence of UTF-8 code units with culture-invariant operations.
Definition String.h:74
String()
Initializes a new instance of the String class to an empty string.
Definition String.cpp:64
const char * GetRawString() const
Definition String.cpp:230
static void DecodeBase64Loop(const std::string &sInput, std::vector< char > &decoded)
Definition Convert.cpp:371
static void EncodeBase64Remainder(unsigned char *char_array_3, int remainderLen, std::string &ret)
Definition Convert.cpp:315
static void DecodeBase64Chunk4(unsigned char *char_array_4, std::vector< char > &decoded)
Definition Convert.cpp:340
static Target CheckRange(Source value)
Definition Convert.cpp:18
static const char base64_chars[]
Definition Convert.cpp:297
static void DecodeBase64Remainder(unsigned char *char_array_4, int i, std::vector< char > &decoded)
Definition Convert.cpp:351
static String ToBaseString(unsigned long long llValue, int iToBase)
Definition Convert.cpp:274
static void EncodeBase64Chunk4(const unsigned char *char_array_3, std::string &ret)
Definition Convert.cpp:306
static bool IsBase64(unsigned char c)
Definition Convert.cpp:302