security/sandbox/chromium/base/strings/string_number_conversions.cc

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

michael@0 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
michael@0 2 // Use of this source code is governed by a BSD-style license that can be
michael@0 3 // found in the LICENSE file.
michael@0 4
michael@0 5 #include "base/strings/string_number_conversions.h"
michael@0 6
michael@0 7 #include <ctype.h>
michael@0 8 #include <errno.h>
michael@0 9 #include <stdlib.h>
michael@0 10 #include <wctype.h>
michael@0 11
michael@0 12 #include <limits>
michael@0 13
michael@0 14 #include "base/logging.h"
michael@0 15 #include "base/scoped_clear_errno.h"
michael@0 16 #include "base/strings/utf_string_conversions.h"
michael@0 17 #include "base/third_party/dmg_fp/dmg_fp.h"
michael@0 18
michael@0 19 namespace base {
michael@0 20
michael@0 21 namespace {
michael@0 22
michael@0 23 template <typename STR, typename INT, typename UINT, bool NEG>
michael@0 24 struct IntToStringT {
michael@0 25 // This is to avoid a compiler warning about unary minus on unsigned type.
michael@0 26 // For example, say you had the following code:
michael@0 27 // template <typename INT>
michael@0 28 // INT abs(INT value) { return value < 0 ? -value : value; }
michael@0 29 // Even though if INT is unsigned, it's impossible for value < 0, so the
michael@0 30 // unary minus will never be taken, the compiler will still generate a
michael@0 31 // warning. We do a little specialization dance...
michael@0 32 template <typename INT2, typename UINT2, bool NEG2>
michael@0 33 struct ToUnsignedT {};
michael@0 34
michael@0 35 template <typename INT2, typename UINT2>
michael@0 36 struct ToUnsignedT<INT2, UINT2, false> {
michael@0 37 static UINT2 ToUnsigned(INT2 value) {
michael@0 38 return static_cast<UINT2>(value);
michael@0 39 }
michael@0 40 };
michael@0 41
michael@0 42 template <typename INT2, typename UINT2>
michael@0 43 struct ToUnsignedT<INT2, UINT2, true> {
michael@0 44 static UINT2 ToUnsigned(INT2 value) {
michael@0 45 return static_cast<UINT2>(value < 0 ? -value : value);
michael@0 46 }
michael@0 47 };
michael@0 48
michael@0 49 // This set of templates is very similar to the above templates, but
michael@0 50 // for testing whether an integer is negative.
michael@0 51 template <typename INT2, bool NEG2>
michael@0 52 struct TestNegT {};
michael@0 53 template <typename INT2>
michael@0 54 struct TestNegT<INT2, false> {
michael@0 55 static bool TestNeg(INT2 value) {
michael@0 56 // value is unsigned, and can never be negative.
michael@0 57 return false;
michael@0 58 }
michael@0 59 };
michael@0 60 template <typename INT2>
michael@0 61 struct TestNegT<INT2, true> {
michael@0 62 static bool TestNeg(INT2 value) {
michael@0 63 return value < 0;
michael@0 64 }
michael@0 65 };
michael@0 66
michael@0 67 static STR IntToString(INT value) {
michael@0 68 // log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4.
michael@0 69 // So round up to allocate 3 output characters per byte, plus 1 for '-'.
michael@0 70 const int kOutputBufSize = 3 * sizeof(INT) + 1;
michael@0 71
michael@0 72 // Allocate the whole string right away, we will right back to front, and
michael@0 73 // then return the substr of what we ended up using.
michael@0 74 STR outbuf(kOutputBufSize, 0);
michael@0 75
michael@0 76 bool is_neg = TestNegT<INT, NEG>::TestNeg(value);
michael@0 77 // Even though is_neg will never be true when INT is parameterized as
michael@0 78 // unsigned, even the presence of the unary operation causes a warning.
michael@0 79 UINT res = ToUnsignedT<INT, UINT, NEG>::ToUnsigned(value);
michael@0 80
michael@0 81 for (typename STR::iterator it = outbuf.end();;) {
michael@0 82 --it;
michael@0 83 DCHECK(it != outbuf.begin());
michael@0 84 *it = static_cast<typename STR::value_type>((res % 10) + '0');
michael@0 85 res /= 10;
michael@0 86
michael@0 87 // We're done..
michael@0 88 if (res == 0) {
michael@0 89 if (is_neg) {
michael@0 90 --it;
michael@0 91 DCHECK(it != outbuf.begin());
michael@0 92 *it = static_cast<typename STR::value_type>('-');
michael@0 93 }
michael@0 94 return STR(it, outbuf.end());
michael@0 95 }
michael@0 96 }
michael@0 97 NOTREACHED();
michael@0 98 return STR();
michael@0 99 }
michael@0 100 };
michael@0 101
michael@0 102 // Utility to convert a character to a digit in a given base
michael@0 103 template<typename CHAR, int BASE, bool BASE_LTE_10> class BaseCharToDigit {
michael@0 104 };
michael@0 105
michael@0 106 // Faster specialization for bases <= 10
michael@0 107 template<typename CHAR, int BASE> class BaseCharToDigit<CHAR, BASE, true> {
michael@0 108 public:
michael@0 109 static bool Convert(CHAR c, uint8* digit) {
michael@0 110 if (c >= '0' && c < '0' + BASE) {
michael@0 111 *digit = c - '0';
michael@0 112 return true;
michael@0 113 }
michael@0 114 return false;
michael@0 115 }
michael@0 116 };
michael@0 117
michael@0 118 // Specialization for bases where 10 < base <= 36
michael@0 119 template<typename CHAR, int BASE> class BaseCharToDigit<CHAR, BASE, false> {
michael@0 120 public:
michael@0 121 static bool Convert(CHAR c, uint8* digit) {
michael@0 122 if (c >= '0' && c <= '9') {
michael@0 123 *digit = c - '0';
michael@0 124 } else if (c >= 'a' && c < 'a' + BASE - 10) {
michael@0 125 *digit = c - 'a' + 10;
michael@0 126 } else if (c >= 'A' && c < 'A' + BASE - 10) {
michael@0 127 *digit = c - 'A' + 10;
michael@0 128 } else {
michael@0 129 return false;
michael@0 130 }
michael@0 131 return true;
michael@0 132 }
michael@0 133 };
michael@0 134
michael@0 135 template<int BASE, typename CHAR> bool CharToDigit(CHAR c, uint8* digit) {
michael@0 136 return BaseCharToDigit<CHAR, BASE, BASE <= 10>::Convert(c, digit);
michael@0 137 }
michael@0 138
michael@0 139 // There is an IsWhitespace for wchars defined in string_util.h, but it is
michael@0 140 // locale independent, whereas the functions we are replacing were
michael@0 141 // locale-dependent. TBD what is desired, but for the moment let's not introduce
michael@0 142 // a change in behaviour.
michael@0 143 template<typename CHAR> class WhitespaceHelper {
michael@0 144 };
michael@0 145
michael@0 146 template<> class WhitespaceHelper<char> {
michael@0 147 public:
michael@0 148 static bool Invoke(char c) {
michael@0 149 return 0 != isspace(static_cast<unsigned char>(c));
michael@0 150 }
michael@0 151 };
michael@0 152
michael@0 153 template<> class WhitespaceHelper<char16> {
michael@0 154 public:
michael@0 155 static bool Invoke(char16 c) {
michael@0 156 return 0 != iswspace(c);
michael@0 157 }
michael@0 158 };
michael@0 159
michael@0 160 template<typename CHAR> bool LocalIsWhitespace(CHAR c) {
michael@0 161 return WhitespaceHelper<CHAR>::Invoke(c);
michael@0 162 }
michael@0 163
michael@0 164 // IteratorRangeToNumberTraits should provide:
michael@0 165 // - a typedef for iterator_type, the iterator type used as input.
michael@0 166 // - a typedef for value_type, the target numeric type.
michael@0 167 // - static functions min, max (returning the minimum and maximum permitted
michael@0 168 // values)
michael@0 169 // - constant kBase, the base in which to interpret the input
michael@0 170 template<typename IteratorRangeToNumberTraits>
michael@0 171 class IteratorRangeToNumber {
michael@0 172 public:
michael@0 173 typedef IteratorRangeToNumberTraits traits;
michael@0 174 typedef typename traits::iterator_type const_iterator;
michael@0 175 typedef typename traits::value_type value_type;
michael@0 176
michael@0 177 // Generalized iterator-range-to-number conversion.
michael@0 178 //
michael@0 179 static bool Invoke(const_iterator begin,
michael@0 180 const_iterator end,
michael@0 181 value_type* output) {
michael@0 182 bool valid = true;
michael@0 183
michael@0 184 while (begin != end && LocalIsWhitespace(*begin)) {
michael@0 185 valid = false;
michael@0 186 ++begin;
michael@0 187 }
michael@0 188
michael@0 189 if (begin != end && *begin == '-') {
michael@0 190 if (!std::numeric_limits<value_type>::is_signed) {
michael@0 191 valid = false;
michael@0 192 } else if (!Negative::Invoke(begin + 1, end, output)) {
michael@0 193 valid = false;
michael@0 194 }
michael@0 195 } else {
michael@0 196 if (begin != end && *begin == '+') {
michael@0 197 ++begin;
michael@0 198 }
michael@0 199 if (!Positive::Invoke(begin, end, output)) {
michael@0 200 valid = false;
michael@0 201 }
michael@0 202 }
michael@0 203
michael@0 204 return valid;
michael@0 205 }
michael@0 206
michael@0 207 private:
michael@0 208 // Sign provides:
michael@0 209 // - a static function, CheckBounds, that determines whether the next digit
michael@0 210 // causes an overflow/underflow
michael@0 211 // - a static function, Increment, that appends the next digit appropriately
michael@0 212 // according to the sign of the number being parsed.
michael@0 213 template<typename Sign>
michael@0 214 class Base {
michael@0 215 public:
michael@0 216 static bool Invoke(const_iterator begin, const_iterator end,
michael@0 217 typename traits::value_type* output) {
michael@0 218 *output = 0;
michael@0 219
michael@0 220 if (begin == end) {
michael@0 221 return false;
michael@0 222 }
michael@0 223
michael@0 224 // Note: no performance difference was found when using template
michael@0 225 // specialization to remove this check in bases other than 16
michael@0 226 if (traits::kBase == 16 && end - begin > 2 && *begin == '0' &&
michael@0 227 (*(begin + 1) == 'x' || *(begin + 1) == 'X')) {
michael@0 228 begin += 2;
michael@0 229 }
michael@0 230
michael@0 231 for (const_iterator current = begin; current != end; ++current) {
michael@0 232 uint8 new_digit = 0;
michael@0 233
michael@0 234 if (!CharToDigit<traits::kBase>(*current, &new_digit)) {
michael@0 235 return false;
michael@0 236 }
michael@0 237
michael@0 238 if (current != begin) {
michael@0 239 if (!Sign::CheckBounds(output, new_digit)) {
michael@0 240 return false;
michael@0 241 }
michael@0 242 *output *= traits::kBase;
michael@0 243 }
michael@0 244
michael@0 245 Sign::Increment(new_digit, output);
michael@0 246 }
michael@0 247 return true;
michael@0 248 }
michael@0 249 };
michael@0 250
michael@0 251 class Positive : public Base<Positive> {
michael@0 252 public:
michael@0 253 static bool CheckBounds(value_type* output, uint8 new_digit) {
michael@0 254 if (*output > static_cast<value_type>(traits::max() / traits::kBase) ||
michael@0 255 (*output == static_cast<value_type>(traits::max() / traits::kBase) &&
michael@0 256 new_digit > traits::max() % traits::kBase)) {
michael@0 257 *output = traits::max();
michael@0 258 return false;
michael@0 259 }
michael@0 260 return true;
michael@0 261 }
michael@0 262 static void Increment(uint8 increment, value_type* output) {
michael@0 263 *output += increment;
michael@0 264 }
michael@0 265 };
michael@0 266
michael@0 267 class Negative : public Base<Negative> {
michael@0 268 public:
michael@0 269 static bool CheckBounds(value_type* output, uint8 new_digit) {
michael@0 270 if (*output < traits::min() / traits::kBase ||
michael@0 271 (*output == traits::min() / traits::kBase &&
michael@0 272 new_digit > 0 - traits::min() % traits::kBase)) {
michael@0 273 *output = traits::min();
michael@0 274 return false;
michael@0 275 }
michael@0 276 return true;
michael@0 277 }
michael@0 278 static void Increment(uint8 increment, value_type* output) {
michael@0 279 *output -= increment;
michael@0 280 }
michael@0 281 };
michael@0 282 };
michael@0 283
michael@0 284 template<typename ITERATOR, typename VALUE, int BASE>
michael@0 285 class BaseIteratorRangeToNumberTraits {
michael@0 286 public:
michael@0 287 typedef ITERATOR iterator_type;
michael@0 288 typedef VALUE value_type;
michael@0 289 static value_type min() {
michael@0 290 return std::numeric_limits<value_type>::min();
michael@0 291 }
michael@0 292 static value_type max() {
michael@0 293 return std::numeric_limits<value_type>::max();
michael@0 294 }
michael@0 295 static const int kBase = BASE;
michael@0 296 };
michael@0 297
michael@0 298 template<typename ITERATOR>
michael@0 299 class BaseHexIteratorRangeToIntTraits
michael@0 300 : public BaseIteratorRangeToNumberTraits<ITERATOR, int, 16> {
michael@0 301 };
michael@0 302
michael@0 303 template<typename ITERATOR>
michael@0 304 class BaseHexIteratorRangeToInt64Traits
michael@0 305 : public BaseIteratorRangeToNumberTraits<ITERATOR, int64, 16> {
michael@0 306 };
michael@0 307
michael@0 308 template<typename ITERATOR>
michael@0 309 class BaseHexIteratorRangeToUInt64Traits
michael@0 310 : public BaseIteratorRangeToNumberTraits<ITERATOR, uint64, 16> {
michael@0 311 };
michael@0 312
michael@0 313 typedef BaseHexIteratorRangeToIntTraits<StringPiece::const_iterator>
michael@0 314 HexIteratorRangeToIntTraits;
michael@0 315
michael@0 316 typedef BaseHexIteratorRangeToInt64Traits<StringPiece::const_iterator>
michael@0 317 HexIteratorRangeToInt64Traits;
michael@0 318
michael@0 319 typedef BaseHexIteratorRangeToUInt64Traits<StringPiece::const_iterator>
michael@0 320 HexIteratorRangeToUInt64Traits;
michael@0 321
michael@0 322 template<typename STR>
michael@0 323 bool HexStringToBytesT(const STR& input, std::vector<uint8>* output) {
michael@0 324 DCHECK_EQ(output->size(), 0u);
michael@0 325 size_t count = input.size();
michael@0 326 if (count == 0 || (count % 2) != 0)
michael@0 327 return false;
michael@0 328 for (uintptr_t i = 0; i < count / 2; ++i) {
michael@0 329 uint8 msb = 0; // most significant 4 bits
michael@0 330 uint8 lsb = 0; // least significant 4 bits
michael@0 331 if (!CharToDigit<16>(input[i * 2], &msb) ||
michael@0 332 !CharToDigit<16>(input[i * 2 + 1], &lsb))
michael@0 333 return false;
michael@0 334 output->push_back((msb << 4) | lsb);
michael@0 335 }
michael@0 336 return true;
michael@0 337 }
michael@0 338
michael@0 339 template <typename VALUE, int BASE>
michael@0 340 class StringPieceToNumberTraits
michael@0 341 : public BaseIteratorRangeToNumberTraits<StringPiece::const_iterator,
michael@0 342 VALUE,
michael@0 343 BASE> {
michael@0 344 };
michael@0 345
michael@0 346 template <typename VALUE>
michael@0 347 bool StringToIntImpl(const StringPiece& input, VALUE* output) {
michael@0 348 return IteratorRangeToNumber<StringPieceToNumberTraits<VALUE, 10> >::Invoke(
michael@0 349 input.begin(), input.end(), output);
michael@0 350 }
michael@0 351
michael@0 352 template <typename VALUE, int BASE>
michael@0 353 class StringPiece16ToNumberTraits
michael@0 354 : public BaseIteratorRangeToNumberTraits<StringPiece16::const_iterator,
michael@0 355 VALUE,
michael@0 356 BASE> {
michael@0 357 };
michael@0 358
michael@0 359 template <typename VALUE>
michael@0 360 bool String16ToIntImpl(const StringPiece16& input, VALUE* output) {
michael@0 361 return IteratorRangeToNumber<StringPiece16ToNumberTraits<VALUE, 10> >::Invoke(
michael@0 362 input.begin(), input.end(), output);
michael@0 363 }
michael@0 364
michael@0 365 } // namespace
michael@0 366
michael@0 367 std::string IntToString(int value) {
michael@0 368 return IntToStringT<std::string, int, unsigned int, true>::
michael@0 369 IntToString(value);
michael@0 370 }
michael@0 371
michael@0 372 string16 IntToString16(int value) {
michael@0 373 return IntToStringT<string16, int, unsigned int, true>::
michael@0 374 IntToString(value);
michael@0 375 }
michael@0 376
michael@0 377 std::string UintToString(unsigned int value) {
michael@0 378 return IntToStringT<std::string, unsigned int, unsigned int, false>::
michael@0 379 IntToString(value);
michael@0 380 }
michael@0 381
michael@0 382 string16 UintToString16(unsigned int value) {
michael@0 383 return IntToStringT<string16, unsigned int, unsigned int, false>::
michael@0 384 IntToString(value);
michael@0 385 }
michael@0 386
michael@0 387 std::string Int64ToString(int64 value) {
michael@0 388 return IntToStringT<std::string, int64, uint64, true>::
michael@0 389 IntToString(value);
michael@0 390 }
michael@0 391
michael@0 392 string16 Int64ToString16(int64 value) {
michael@0 393 return IntToStringT<string16, int64, uint64, true>::IntToString(value);
michael@0 394 }
michael@0 395
michael@0 396 std::string Uint64ToString(uint64 value) {
michael@0 397 return IntToStringT<std::string, uint64, uint64, false>::
michael@0 398 IntToString(value);
michael@0 399 }
michael@0 400
michael@0 401 string16 Uint64ToString16(uint64 value) {
michael@0 402 return IntToStringT<string16, uint64, uint64, false>::
michael@0 403 IntToString(value);
michael@0 404 }
michael@0 405
michael@0 406 std::string DoubleToString(double value) {
michael@0 407 // According to g_fmt.cc, it is sufficient to declare a buffer of size 32.
michael@0 408 char buffer[32];
michael@0 409 dmg_fp::g_fmt(buffer, value);
michael@0 410 return std::string(buffer);
michael@0 411 }
michael@0 412
michael@0 413 bool StringToInt(const StringPiece& input, int* output) {
michael@0 414 return StringToIntImpl(input, output);
michael@0 415 }
michael@0 416
michael@0 417 bool StringToInt(const StringPiece16& input, int* output) {
michael@0 418 return String16ToIntImpl(input, output);
michael@0 419 }
michael@0 420
michael@0 421 bool StringToUint(const StringPiece& input, unsigned* output) {
michael@0 422 return StringToIntImpl(input, output);
michael@0 423 }
michael@0 424
michael@0 425 bool StringToUint(const StringPiece16& input, unsigned* output) {
michael@0 426 return String16ToIntImpl(input, output);
michael@0 427 }
michael@0 428
michael@0 429 bool StringToInt64(const StringPiece& input, int64* output) {
michael@0 430 return StringToIntImpl(input, output);
michael@0 431 }
michael@0 432
michael@0 433 bool StringToInt64(const StringPiece16& input, int64* output) {
michael@0 434 return String16ToIntImpl(input, output);
michael@0 435 }
michael@0 436
michael@0 437 bool StringToUint64(const StringPiece& input, uint64* output) {
michael@0 438 return StringToIntImpl(input, output);
michael@0 439 }
michael@0 440
michael@0 441 bool StringToUint64(const StringPiece16& input, uint64* output) {
michael@0 442 return String16ToIntImpl(input, output);
michael@0 443 }
michael@0 444
michael@0 445 bool StringToSizeT(const StringPiece& input, size_t* output) {
michael@0 446 return StringToIntImpl(input, output);
michael@0 447 }
michael@0 448
michael@0 449 bool StringToSizeT(const StringPiece16& input, size_t* output) {
michael@0 450 return String16ToIntImpl(input, output);
michael@0 451 }
michael@0 452
michael@0 453 bool StringToDouble(const std::string& input, double* output) {
michael@0 454 // Thread-safe? It is on at least Mac, Linux, and Windows.
michael@0 455 ScopedClearErrno clear_errno;
michael@0 456
michael@0 457 char* endptr = NULL;
michael@0 458 *output = dmg_fp::strtod(input.c_str(), &endptr);
michael@0 459
michael@0 460 // Cases to return false:
michael@0 461 // - If errno is ERANGE, there was an overflow or underflow.
michael@0 462 // - If the input string is empty, there was nothing to parse.
michael@0 463 // - If endptr does not point to the end of the string, there are either
michael@0 464 // characters remaining in the string after a parsed number, or the string
michael@0 465 // does not begin with a parseable number. endptr is compared to the
michael@0 466 // expected end given the string's stated length to correctly catch cases
michael@0 467 // where the string contains embedded NUL characters.
michael@0 468 // - If the first character is a space, there was leading whitespace
michael@0 469 return errno == 0 &&
michael@0 470 !input.empty() &&
michael@0 471 input.c_str() + input.length() == endptr &&
michael@0 472 !isspace(input[0]);
michael@0 473 }
michael@0 474
michael@0 475 // Note: if you need to add String16ToDouble, first ask yourself if it's
michael@0 476 // really necessary. If it is, probably the best implementation here is to
michael@0 477 // convert to 8-bit and then use the 8-bit version.
michael@0 478
michael@0 479 // Note: if you need to add an iterator range version of StringToDouble, first
michael@0 480 // ask yourself if it's really necessary. If it is, probably the best
michael@0 481 // implementation here is to instantiate a string and use the string version.
michael@0 482
michael@0 483 std::string HexEncode(const void* bytes, size_t size) {
michael@0 484 static const char kHexChars[] = "0123456789ABCDEF";
michael@0 485
michael@0 486 // Each input byte creates two output hex characters.
michael@0 487 std::string ret(size * 2, '\0');
michael@0 488
michael@0 489 for (size_t i = 0; i < size; ++i) {
michael@0 490 char b = reinterpret_cast<const char*>(bytes)[i];
michael@0 491 ret[(i * 2)] = kHexChars[(b >> 4) & 0xf];
michael@0 492 ret[(i * 2) + 1] = kHexChars[b & 0xf];
michael@0 493 }
michael@0 494 return ret;
michael@0 495 }
michael@0 496
michael@0 497 bool HexStringToInt(const StringPiece& input, int* output) {
michael@0 498 return IteratorRangeToNumber<HexIteratorRangeToIntTraits>::Invoke(
michael@0 499 input.begin(), input.end(), output);
michael@0 500 }
michael@0 501
michael@0 502 bool HexStringToInt64(const StringPiece& input, int64* output) {
michael@0 503 return IteratorRangeToNumber<HexIteratorRangeToInt64Traits>::Invoke(
michael@0 504 input.begin(), input.end(), output);
michael@0 505 }
michael@0 506
michael@0 507 bool HexStringToUInt64(const StringPiece& input, uint64* output) {
michael@0 508 return IteratorRangeToNumber<HexIteratorRangeToUInt64Traits>::Invoke(
michael@0 509 input.begin(), input.end(), output);
michael@0 510 }
michael@0 511
michael@0 512 bool HexStringToBytes(const std::string& input, std::vector<uint8>* output) {
michael@0 513 return HexStringToBytesT(input, output);
michael@0 514 }
michael@0 515
michael@0 516 } // namespace base

mercurial