| Index: base/string_util_static.cc
|
| ===================================================================
|
| --- base/string_util_static.cc (revision 81611)
|
| +++ base/string_util_static.cc (working copy)
|
| @@ -2,121 +2,8 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -#include "base/string_util.h"
|
| +#include "base/string_util_static.h"
|
|
|
| -#include "build/build_config.h"
|
| -
|
| -#include <ctype.h>
|
| -#include <errno.h>
|
| -#include <math.h>
|
| -#include <stdarg.h>
|
| -#include <stdio.h>
|
| -#include <stdlib.h>
|
| -#include <string.h>
|
| -#include <time.h>
|
| -#include <wchar.h>
|
| -#include <wctype.h>
|
| -
|
| -#include <algorithm>
|
| -#include <vector>
|
| -
|
| -#include "base/basictypes.h"
|
| -#include "base/logging.h"
|
| -#include "base/memory/singleton.h"
|
| -#include "base/third_party/dmg_fp/dmg_fp.h"
|
| -#include "base/utf_string_conversion_utils.h"
|
| -#include "base/utf_string_conversions.h"
|
| -#include "base/third_party/icu/icu_utf.h"
|
| -
|
| -namespace {
|
| -
|
| -// Force the singleton used by Empty[W]String[16] to be a unique type. This
|
| -// prevents other code that might accidentally use Singleton<string> from
|
| -// getting our internal one.
|
| -struct EmptyStrings {
|
| - EmptyStrings() {}
|
| - const std::string s;
|
| - const std::wstring ws;
|
| - const string16 s16;
|
| -
|
| - static EmptyStrings* GetInstance() {
|
| - return Singleton<EmptyStrings>::get();
|
| - }
|
| -};
|
| -
|
| -// Used by ReplaceStringPlaceholders to track the position in the string of
|
| -// replaced parameters.
|
| -struct ReplacementOffset {
|
| - ReplacementOffset(uintptr_t parameter, size_t offset)
|
| - : parameter(parameter),
|
| - offset(offset) {}
|
| -
|
| - // Index of the parameter.
|
| - uintptr_t parameter;
|
| -
|
| - // Starting position in the string.
|
| - size_t offset;
|
| -};
|
| -
|
| -static bool CompareParameter(const ReplacementOffset& elem1,
|
| - const ReplacementOffset& elem2) {
|
| - return elem1.parameter < elem2.parameter;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -namespace base {
|
| -
|
| -bool IsWprintfFormatPortable(const wchar_t* format) {
|
| - for (const wchar_t* position = format; *position != '\0'; ++position) {
|
| - if (*position == '%') {
|
| - bool in_specification = true;
|
| - bool modifier_l = false;
|
| - while (in_specification) {
|
| - // Eat up characters until reaching a known specifier.
|
| - if (*++position == '\0') {
|
| - // The format string ended in the middle of a specification. Call
|
| - // it portable because no unportable specifications were found. The
|
| - // string is equally broken on all platforms.
|
| - return true;
|
| - }
|
| -
|
| - if (*position == 'l') {
|
| - // 'l' is the only thing that can save the 's' and 'c' specifiers.
|
| - modifier_l = true;
|
| - } else if (((*position == 's' || *position == 'c') && !modifier_l) ||
|
| - *position == 'S' || *position == 'C' || *position == 'F' ||
|
| - *position == 'D' || *position == 'O' || *position == 'U') {
|
| - // Not portable.
|
| - return false;
|
| - }
|
| -
|
| - if (wcschr(L"diouxXeEfgGaAcspn%", *position)) {
|
| - // Portable, keep scanning the rest of the format string.
|
| - in_specification = false;
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -} // namespace base
|
| -
|
| -
|
| -const std::string& EmptyString() {
|
| - return EmptyStrings::GetInstance()->s;
|
| -}
|
| -
|
| -const std::wstring& EmptyWString() {
|
| - return EmptyStrings::GetInstance()->ws;
|
| -}
|
| -
|
| -const string16& EmptyString16() {
|
| - return EmptyStrings::GetInstance()->s16;
|
| -}
|
| -
|
| #define WHITESPACE_UNICODE \
|
| 0x0009, /* <control-0009> to <control-000D> */ \
|
| 0x000A, \
|
| @@ -164,934 +51,3 @@
|
| };
|
|
|
| const char kUtf8ByteOrderMark[] = "\xEF\xBB\xBF";
|
| -
|
| -template<typename STR>
|
| -bool RemoveCharsT(const STR& input,
|
| - const typename STR::value_type remove_chars[],
|
| - STR* output) {
|
| - bool removed = false;
|
| - size_t found;
|
| -
|
| - *output = input;
|
| -
|
| - found = output->find_first_of(remove_chars);
|
| - while (found != STR::npos) {
|
| - removed = true;
|
| - output->replace(found, 1, STR());
|
| - found = output->find_first_of(remove_chars, found);
|
| - }
|
| -
|
| - return removed;
|
| -}
|
| -
|
| -bool RemoveChars(const std::wstring& input,
|
| - const wchar_t remove_chars[],
|
| - std::wstring* output) {
|
| - return RemoveCharsT(input, remove_chars, output);
|
| -}
|
| -
|
| -#if !defined(WCHAR_T_IS_UTF16)
|
| -bool RemoveChars(const string16& input,
|
| - const char16 remove_chars[],
|
| - string16* output) {
|
| - return RemoveCharsT(input, remove_chars, output);
|
| -}
|
| -#endif
|
| -
|
| -bool RemoveChars(const std::string& input,
|
| - const char remove_chars[],
|
| - std::string* output) {
|
| - return RemoveCharsT(input, remove_chars, output);
|
| -}
|
| -
|
| -template<typename STR>
|
| -TrimPositions TrimStringT(const STR& input,
|
| - const typename STR::value_type trim_chars[],
|
| - TrimPositions positions,
|
| - STR* output) {
|
| - // Find the edges of leading/trailing whitespace as desired.
|
| - const typename STR::size_type last_char = input.length() - 1;
|
| - const typename STR::size_type first_good_char = (positions & TRIM_LEADING) ?
|
| - input.find_first_not_of(trim_chars) : 0;
|
| - const typename STR::size_type last_good_char = (positions & TRIM_TRAILING) ?
|
| - input.find_last_not_of(trim_chars) : last_char;
|
| -
|
| - // When the string was all whitespace, report that we stripped off whitespace
|
| - // from whichever position the caller was interested in. For empty input, we
|
| - // stripped no whitespace, but we still need to clear |output|.
|
| - if (input.empty() ||
|
| - (first_good_char == STR::npos) || (last_good_char == STR::npos)) {
|
| - bool input_was_empty = input.empty(); // in case output == &input
|
| - output->clear();
|
| - return input_was_empty ? TRIM_NONE : positions;
|
| - }
|
| -
|
| - // Trim the whitespace.
|
| - *output =
|
| - input.substr(first_good_char, last_good_char - first_good_char + 1);
|
| -
|
| - // Return where we trimmed from.
|
| - return static_cast<TrimPositions>(
|
| - ((first_good_char == 0) ? TRIM_NONE : TRIM_LEADING) |
|
| - ((last_good_char == last_char) ? TRIM_NONE : TRIM_TRAILING));
|
| -}
|
| -
|
| -bool TrimString(const std::wstring& input,
|
| - const wchar_t trim_chars[],
|
| - std::wstring* output) {
|
| - return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE;
|
| -}
|
| -
|
| -#if !defined(WCHAR_T_IS_UTF16)
|
| -bool TrimString(const string16& input,
|
| - const char16 trim_chars[],
|
| - string16* output) {
|
| - return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE;
|
| -}
|
| -#endif
|
| -
|
| -bool TrimString(const std::string& input,
|
| - const char trim_chars[],
|
| - std::string* output) {
|
| - return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE;
|
| -}
|
| -
|
| -void TruncateUTF8ToByteSize(const std::string& input,
|
| - const size_t byte_size,
|
| - std::string* output) {
|
| - DCHECK(output);
|
| - if (byte_size > input.length()) {
|
| - *output = input;
|
| - return;
|
| - }
|
| - DCHECK_LE(byte_size, static_cast<uint32>(kint32max));
|
| - // Note: This cast is necessary because CBU8_NEXT uses int32s.
|
| - int32 truncation_length = static_cast<int32>(byte_size);
|
| - int32 char_index = truncation_length - 1;
|
| - const char* data = input.data();
|
| -
|
| - // Using CBU8, we will move backwards from the truncation point
|
| - // to the beginning of the string looking for a valid UTF8
|
| - // character. Once a full UTF8 character is found, we will
|
| - // truncate the string to the end of that character.
|
| - while (char_index >= 0) {
|
| - int32 prev = char_index;
|
| - uint32 code_point = 0;
|
| - CBU8_NEXT(data, char_index, truncation_length, code_point);
|
| - if (!base::IsValidCharacter(code_point) ||
|
| - !base::IsValidCodepoint(code_point)) {
|
| - char_index = prev - 1;
|
| - } else {
|
| - break;
|
| - }
|
| - }
|
| -
|
| - if (char_index >= 0 )
|
| - *output = input.substr(0, char_index);
|
| - else
|
| - output->clear();
|
| -}
|
| -
|
| -TrimPositions TrimWhitespace(const std::wstring& input,
|
| - TrimPositions positions,
|
| - std::wstring* output) {
|
| - return TrimStringT(input, kWhitespaceWide, positions, output);
|
| -}
|
| -
|
| -#if !defined(WCHAR_T_IS_UTF16)
|
| -TrimPositions TrimWhitespace(const string16& input,
|
| - TrimPositions positions,
|
| - string16* output) {
|
| - return TrimStringT(input, kWhitespaceUTF16, positions, output);
|
| -}
|
| -#endif
|
| -
|
| -TrimPositions TrimWhitespaceASCII(const std::string& input,
|
| - TrimPositions positions,
|
| - std::string* output) {
|
| - return TrimStringT(input, kWhitespaceASCII, positions, output);
|
| -}
|
| -
|
| -// This function is only for backward-compatibility.
|
| -// To be removed when all callers are updated.
|
| -TrimPositions TrimWhitespace(const std::string& input,
|
| - TrimPositions positions,
|
| - std::string* output) {
|
| - return TrimWhitespaceASCII(input, positions, output);
|
| -}
|
| -
|
| -template<typename STR>
|
| -STR CollapseWhitespaceT(const STR& text,
|
| - bool trim_sequences_with_line_breaks) {
|
| - STR result;
|
| - result.resize(text.size());
|
| -
|
| - // Set flags to pretend we're already in a trimmed whitespace sequence, so we
|
| - // will trim any leading whitespace.
|
| - bool in_whitespace = true;
|
| - bool already_trimmed = true;
|
| -
|
| - int chars_written = 0;
|
| - for (typename STR::const_iterator i(text.begin()); i != text.end(); ++i) {
|
| - if (IsWhitespace(*i)) {
|
| - if (!in_whitespace) {
|
| - // Reduce all whitespace sequences to a single space.
|
| - in_whitespace = true;
|
| - result[chars_written++] = L' ';
|
| - }
|
| - if (trim_sequences_with_line_breaks && !already_trimmed &&
|
| - ((*i == '\n') || (*i == '\r'))) {
|
| - // Whitespace sequences containing CR or LF are eliminated entirely.
|
| - already_trimmed = true;
|
| - --chars_written;
|
| - }
|
| - } else {
|
| - // Non-whitespace chracters are copied straight across.
|
| - in_whitespace = false;
|
| - already_trimmed = false;
|
| - result[chars_written++] = *i;
|
| - }
|
| - }
|
| -
|
| - if (in_whitespace && !already_trimmed) {
|
| - // Any trailing whitespace is eliminated.
|
| - --chars_written;
|
| - }
|
| -
|
| - result.resize(chars_written);
|
| - return result;
|
| -}
|
| -
|
| -std::wstring CollapseWhitespace(const std::wstring& text,
|
| - bool trim_sequences_with_line_breaks) {
|
| - return CollapseWhitespaceT(text, trim_sequences_with_line_breaks);
|
| -}
|
| -
|
| -#if !defined(WCHAR_T_IS_UTF16)
|
| -string16 CollapseWhitespace(const string16& text,
|
| - bool trim_sequences_with_line_breaks) {
|
| - return CollapseWhitespaceT(text, trim_sequences_with_line_breaks);
|
| -}
|
| -#endif
|
| -
|
| -std::string CollapseWhitespaceASCII(const std::string& text,
|
| - bool trim_sequences_with_line_breaks) {
|
| - return CollapseWhitespaceT(text, trim_sequences_with_line_breaks);
|
| -}
|
| -
|
| -bool ContainsOnlyWhitespaceASCII(const std::string& str) {
|
| - for (std::string::const_iterator i(str.begin()); i != str.end(); ++i) {
|
| - if (!IsAsciiWhitespace(*i))
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool ContainsOnlyWhitespace(const string16& str) {
|
| - for (string16::const_iterator i(str.begin()); i != str.end(); ++i) {
|
| - if (!IsWhitespace(*i))
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -template<typename STR>
|
| -static bool ContainsOnlyCharsT(const STR& input, const STR& characters) {
|
| - for (typename STR::const_iterator iter = input.begin();
|
| - iter != input.end(); ++iter) {
|
| - if (characters.find(*iter) == STR::npos)
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool ContainsOnlyChars(const std::wstring& input,
|
| - const std::wstring& characters) {
|
| - return ContainsOnlyCharsT(input, characters);
|
| -}
|
| -
|
| -#if !defined(WCHAR_T_IS_UTF16)
|
| -bool ContainsOnlyChars(const string16& input, const string16& characters) {
|
| - return ContainsOnlyCharsT(input, characters);
|
| -}
|
| -#endif
|
| -
|
| -bool ContainsOnlyChars(const std::string& input,
|
| - const std::string& characters) {
|
| - return ContainsOnlyCharsT(input, characters);
|
| -}
|
| -
|
| -std::string WideToASCII(const std::wstring& wide) {
|
| - DCHECK(IsStringASCII(wide)) << wide;
|
| - return std::string(wide.begin(), wide.end());
|
| -}
|
| -
|
| -std::string UTF16ToASCII(const string16& utf16) {
|
| - DCHECK(IsStringASCII(utf16)) << utf16;
|
| - return std::string(utf16.begin(), utf16.end());
|
| -}
|
| -
|
| -// Latin1 is just the low range of Unicode, so we can copy directly to convert.
|
| -bool WideToLatin1(const std::wstring& wide, std::string* latin1) {
|
| - std::string output;
|
| - output.resize(wide.size());
|
| - latin1->clear();
|
| - for (size_t i = 0; i < wide.size(); i++) {
|
| - if (wide[i] > 255)
|
| - return false;
|
| - output[i] = static_cast<char>(wide[i]);
|
| - }
|
| - latin1->swap(output);
|
| - return true;
|
| -}
|
| -
|
| -template<class STR>
|
| -static bool DoIsStringASCII(const STR& str) {
|
| - for (size_t i = 0; i < str.length(); i++) {
|
| - typename ToUnsigned<typename STR::value_type>::Unsigned c = str[i];
|
| - if (c > 0x7F)
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool IsStringASCII(const std::wstring& str) {
|
| - return DoIsStringASCII(str);
|
| -}
|
| -
|
| -#if !defined(WCHAR_T_IS_UTF16)
|
| -bool IsStringASCII(const string16& str) {
|
| - return DoIsStringASCII(str);
|
| -}
|
| -#endif
|
| -
|
| -bool IsStringASCII(const base::StringPiece& str) {
|
| - return DoIsStringASCII(str);
|
| -}
|
| -
|
| -bool IsStringUTF8(const std::string& str) {
|
| - const char *src = str.data();
|
| - int32 src_len = static_cast<int32>(str.length());
|
| - int32 char_index = 0;
|
| -
|
| - while (char_index < src_len) {
|
| - int32 code_point;
|
| - CBU8_NEXT(src, char_index, src_len, code_point);
|
| - if (!base::IsValidCharacter(code_point))
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -template<typename Iter>
|
| -static inline bool DoLowerCaseEqualsASCII(Iter a_begin,
|
| - Iter a_end,
|
| - const char* b) {
|
| - for (Iter it = a_begin; it != a_end; ++it, ++b) {
|
| - if (!*b || base::ToLowerASCII(*it) != *b)
|
| - return false;
|
| - }
|
| - return *b == 0;
|
| -}
|
| -
|
| -// Front-ends for LowerCaseEqualsASCII.
|
| -bool LowerCaseEqualsASCII(const std::string& a, const char* b) {
|
| - return DoLowerCaseEqualsASCII(a.begin(), a.end(), b);
|
| -}
|
| -
|
| -bool LowerCaseEqualsASCII(const std::wstring& a, const char* b) {
|
| - return DoLowerCaseEqualsASCII(a.begin(), a.end(), b);
|
| -}
|
| -
|
| -#if !defined(WCHAR_T_IS_UTF16)
|
| -bool LowerCaseEqualsASCII(const string16& a, const char* b) {
|
| - return DoLowerCaseEqualsASCII(a.begin(), a.end(), b);
|
| -}
|
| -#endif
|
| -
|
| -bool LowerCaseEqualsASCII(std::string::const_iterator a_begin,
|
| - std::string::const_iterator a_end,
|
| - const char* b) {
|
| - return DoLowerCaseEqualsASCII(a_begin, a_end, b);
|
| -}
|
| -
|
| -bool LowerCaseEqualsASCII(std::wstring::const_iterator a_begin,
|
| - std::wstring::const_iterator a_end,
|
| - const char* b) {
|
| - return DoLowerCaseEqualsASCII(a_begin, a_end, b);
|
| -}
|
| -
|
| -#if !defined(WCHAR_T_IS_UTF16)
|
| -bool LowerCaseEqualsASCII(string16::const_iterator a_begin,
|
| - string16::const_iterator a_end,
|
| - const char* b) {
|
| - return DoLowerCaseEqualsASCII(a_begin, a_end, b);
|
| -}
|
| -#endif
|
| -
|
| -bool LowerCaseEqualsASCII(const char* a_begin,
|
| - const char* a_end,
|
| - const char* b) {
|
| - return DoLowerCaseEqualsASCII(a_begin, a_end, b);
|
| -}
|
| -
|
| -bool LowerCaseEqualsASCII(const wchar_t* a_begin,
|
| - const wchar_t* a_end,
|
| - const char* b) {
|
| - return DoLowerCaseEqualsASCII(a_begin, a_end, b);
|
| -}
|
| -
|
| -#if !defined(WCHAR_T_IS_UTF16)
|
| -bool LowerCaseEqualsASCII(const char16* a_begin,
|
| - const char16* a_end,
|
| - const char* b) {
|
| - return DoLowerCaseEqualsASCII(a_begin, a_end, b);
|
| -}
|
| -#endif
|
| -
|
| -bool EqualsASCII(const string16& a, const base::StringPiece& b) {
|
| - if (a.length() != b.length())
|
| - return false;
|
| - return std::equal(b.begin(), b.end(), a.begin());
|
| -}
|
| -
|
| -bool StartsWithASCII(const std::string& str,
|
| - const std::string& search,
|
| - bool case_sensitive) {
|
| - if (case_sensitive)
|
| - return str.compare(0, search.length(), search) == 0;
|
| - else
|
| - return base::strncasecmp(str.c_str(), search.c_str(), search.length()) == 0;
|
| -}
|
| -
|
| -template <typename STR>
|
| -bool StartsWithT(const STR& str, const STR& search, bool case_sensitive) {
|
| - if (case_sensitive) {
|
| - return str.compare(0, search.length(), search) == 0;
|
| - } else {
|
| - if (search.size() > str.size())
|
| - return false;
|
| - return std::equal(search.begin(), search.end(), str.begin(),
|
| - base::CaseInsensitiveCompare<typename STR::value_type>());
|
| - }
|
| -}
|
| -
|
| -bool StartsWith(const std::wstring& str, const std::wstring& search,
|
| - bool case_sensitive) {
|
| - return StartsWithT(str, search, case_sensitive);
|
| -}
|
| -
|
| -#if !defined(WCHAR_T_IS_UTF16)
|
| -bool StartsWith(const string16& str, const string16& search,
|
| - bool case_sensitive) {
|
| - return StartsWithT(str, search, case_sensitive);
|
| -}
|
| -#endif
|
| -
|
| -template <typename STR>
|
| -bool EndsWithT(const STR& str, const STR& search, bool case_sensitive) {
|
| - typename STR::size_type str_length = str.length();
|
| - typename STR::size_type search_length = search.length();
|
| - if (search_length > str_length)
|
| - return false;
|
| - if (case_sensitive) {
|
| - return str.compare(str_length - search_length, search_length, search) == 0;
|
| - } else {
|
| - return std::equal(search.begin(), search.end(),
|
| - str.begin() + (str_length - search_length),
|
| - base::CaseInsensitiveCompare<typename STR::value_type>());
|
| - }
|
| -}
|
| -
|
| -bool EndsWith(const std::string& str, const std::string& search,
|
| - bool case_sensitive) {
|
| - return EndsWithT(str, search, case_sensitive);
|
| -}
|
| -
|
| -bool EndsWith(const std::wstring& str, const std::wstring& search,
|
| - bool case_sensitive) {
|
| - return EndsWithT(str, search, case_sensitive);
|
| -}
|
| -
|
| -#if !defined(WCHAR_T_IS_UTF16)
|
| -bool EndsWith(const string16& str, const string16& search,
|
| - bool case_sensitive) {
|
| - return EndsWithT(str, search, case_sensitive);
|
| -}
|
| -#endif
|
| -
|
| -DataUnits GetByteDisplayUnits(int64 bytes) {
|
| - // The byte thresholds at which we display amounts. A byte count is displayed
|
| - // in unit U when kUnitThresholds[U] <= bytes < kUnitThresholds[U+1].
|
| - // This must match the DataUnits enum.
|
| - static const int64 kUnitThresholds[] = {
|
| - 0, // DATA_UNITS_BYTE,
|
| - 3*1024, // DATA_UNITS_KIBIBYTE,
|
| - 2*1024*1024, // DATA_UNITS_MEBIBYTE,
|
| - 1024*1024*1024 // DATA_UNITS_GIBIBYTE,
|
| - };
|
| -
|
| - if (bytes < 0) {
|
| - NOTREACHED() << "Negative bytes value";
|
| - return DATA_UNITS_BYTE;
|
| - }
|
| -
|
| - int unit_index = arraysize(kUnitThresholds);
|
| - while (--unit_index > 0) {
|
| - if (bytes >= kUnitThresholds[unit_index])
|
| - break;
|
| - }
|
| -
|
| - DCHECK(unit_index >= DATA_UNITS_BYTE && unit_index <= DATA_UNITS_GIBIBYTE);
|
| - return DataUnits(unit_index);
|
| -}
|
| -
|
| -// TODO(mpcomplete): deal with locale
|
| -// Byte suffixes. This must match the DataUnits enum.
|
| -static const char* const kByteStrings[] = {
|
| - "B",
|
| - "kB",
|
| - "MB",
|
| - "GB"
|
| -};
|
| -
|
| -static const char* const kSpeedStrings[] = {
|
| - "B/s",
|
| - "kB/s",
|
| - "MB/s",
|
| - "GB/s"
|
| -};
|
| -
|
| -string16 FormatBytesInternal(int64 bytes,
|
| - DataUnits units,
|
| - bool show_units,
|
| - const char* const* suffix) {
|
| - if (bytes < 0) {
|
| - NOTREACHED() << "Negative bytes value";
|
| - return string16();
|
| - }
|
| -
|
| - DCHECK(units >= DATA_UNITS_BYTE && units <= DATA_UNITS_GIBIBYTE);
|
| -
|
| - // Put the quantity in the right units.
|
| - double unit_amount = static_cast<double>(bytes);
|
| - for (int i = 0; i < units; ++i)
|
| - unit_amount /= 1024.0;
|
| -
|
| - char buf[64];
|
| - if (bytes != 0 && units != DATA_UNITS_BYTE && unit_amount < 100)
|
| - base::snprintf(buf, arraysize(buf), "%.1lf", unit_amount);
|
| - else
|
| - base::snprintf(buf, arraysize(buf), "%.0lf", unit_amount);
|
| -
|
| - std::string ret(buf);
|
| - if (show_units) {
|
| - ret += " ";
|
| - ret += suffix[units];
|
| - }
|
| -
|
| - return ASCIIToUTF16(ret);
|
| -}
|
| -
|
| -string16 FormatBytes(int64 bytes, DataUnits units, bool show_units) {
|
| - return FormatBytesInternal(bytes, units, show_units, kByteStrings);
|
| -}
|
| -
|
| -string16 FormatSpeed(int64 bytes, DataUnits units, bool show_units) {
|
| - return FormatBytesInternal(bytes, units, show_units, kSpeedStrings);
|
| -}
|
| -
|
| -template<class StringType>
|
| -void DoReplaceSubstringsAfterOffset(StringType* str,
|
| - typename StringType::size_type start_offset,
|
| - const StringType& find_this,
|
| - const StringType& replace_with,
|
| - bool replace_all) {
|
| - if ((start_offset == StringType::npos) || (start_offset >= str->length()))
|
| - return;
|
| -
|
| - DCHECK(!find_this.empty());
|
| - for (typename StringType::size_type offs(str->find(find_this, start_offset));
|
| - offs != StringType::npos; offs = str->find(find_this, offs)) {
|
| - str->replace(offs, find_this.length(), replace_with);
|
| - offs += replace_with.length();
|
| -
|
| - if (!replace_all)
|
| - break;
|
| - }
|
| -}
|
| -
|
| -void ReplaceFirstSubstringAfterOffset(string16* str,
|
| - string16::size_type start_offset,
|
| - const string16& find_this,
|
| - const string16& replace_with) {
|
| - DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
|
| - false); // replace first instance
|
| -}
|
| -
|
| -void ReplaceFirstSubstringAfterOffset(std::string* str,
|
| - std::string::size_type start_offset,
|
| - const std::string& find_this,
|
| - const std::string& replace_with) {
|
| - DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
|
| - false); // replace first instance
|
| -}
|
| -
|
| -void ReplaceSubstringsAfterOffset(string16* str,
|
| - string16::size_type start_offset,
|
| - const string16& find_this,
|
| - const string16& replace_with) {
|
| - DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
|
| - true); // replace all instances
|
| -}
|
| -
|
| -void ReplaceSubstringsAfterOffset(std::string* str,
|
| - std::string::size_type start_offset,
|
| - const std::string& find_this,
|
| - const std::string& replace_with) {
|
| - DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
|
| - true); // replace all instances
|
| -}
|
| -
|
| -
|
| -template<typename STR>
|
| -static size_t TokenizeT(const STR& str,
|
| - const STR& delimiters,
|
| - std::vector<STR>* tokens) {
|
| - tokens->clear();
|
| -
|
| - typename STR::size_type start = str.find_first_not_of(delimiters);
|
| - while (start != STR::npos) {
|
| - typename STR::size_type end = str.find_first_of(delimiters, start + 1);
|
| - if (end == STR::npos) {
|
| - tokens->push_back(str.substr(start));
|
| - break;
|
| - } else {
|
| - tokens->push_back(str.substr(start, end - start));
|
| - start = str.find_first_not_of(delimiters, end + 1);
|
| - }
|
| - }
|
| -
|
| - return tokens->size();
|
| -}
|
| -
|
| -size_t Tokenize(const std::wstring& str,
|
| - const std::wstring& delimiters,
|
| - std::vector<std::wstring>* tokens) {
|
| - return TokenizeT(str, delimiters, tokens);
|
| -}
|
| -
|
| -#if !defined(WCHAR_T_IS_UTF16)
|
| -size_t Tokenize(const string16& str,
|
| - const string16& delimiters,
|
| - std::vector<string16>* tokens) {
|
| - return TokenizeT(str, delimiters, tokens);
|
| -}
|
| -#endif
|
| -
|
| -size_t Tokenize(const std::string& str,
|
| - const std::string& delimiters,
|
| - std::vector<std::string>* tokens) {
|
| - return TokenizeT(str, delimiters, tokens);
|
| -}
|
| -
|
| -size_t Tokenize(const base::StringPiece& str,
|
| - const base::StringPiece& delimiters,
|
| - std::vector<base::StringPiece>* tokens) {
|
| - return TokenizeT(str, delimiters, tokens);
|
| -}
|
| -
|
| -template<typename STR>
|
| -static STR JoinStringT(const std::vector<STR>& parts,
|
| - typename STR::value_type sep) {
|
| - if (parts.empty())
|
| - return STR();
|
| -
|
| - STR result(parts[0]);
|
| - typename std::vector<STR>::const_iterator iter = parts.begin();
|
| - ++iter;
|
| -
|
| - for (; iter != parts.end(); ++iter) {
|
| - result += sep;
|
| - result += *iter;
|
| - }
|
| -
|
| - return result;
|
| -}
|
| -
|
| -std::string JoinString(const std::vector<std::string>& parts, char sep) {
|
| - return JoinStringT(parts, sep);
|
| -}
|
| -
|
| -string16 JoinString(const std::vector<string16>& parts, char16 sep) {
|
| - return JoinStringT(parts, sep);
|
| -}
|
| -
|
| -template<class FormatStringType, class OutStringType>
|
| -OutStringType DoReplaceStringPlaceholders(const FormatStringType& format_string,
|
| - const std::vector<OutStringType>& subst, std::vector<size_t>* offsets) {
|
| - size_t substitutions = subst.size();
|
| - DCHECK(substitutions < 10);
|
| -
|
| - size_t sub_length = 0;
|
| - for (typename std::vector<OutStringType>::const_iterator iter = subst.begin();
|
| - iter != subst.end(); ++iter) {
|
| - sub_length += iter->length();
|
| - }
|
| -
|
| - OutStringType formatted;
|
| - formatted.reserve(format_string.length() + sub_length);
|
| -
|
| - std::vector<ReplacementOffset> r_offsets;
|
| - for (typename FormatStringType::const_iterator i = format_string.begin();
|
| - i != format_string.end(); ++i) {
|
| - if ('$' == *i) {
|
| - if (i + 1 != format_string.end()) {
|
| - ++i;
|
| - DCHECK('$' == *i || '1' <= *i) << "Invalid placeholder: " << *i;
|
| - if ('$' == *i) {
|
| - while (i != format_string.end() && '$' == *i) {
|
| - formatted.push_back('$');
|
| - ++i;
|
| - }
|
| - --i;
|
| - } else {
|
| - uintptr_t index = *i - '1';
|
| - if (offsets) {
|
| - ReplacementOffset r_offset(index,
|
| - static_cast<int>(formatted.size()));
|
| - r_offsets.insert(std::lower_bound(r_offsets.begin(),
|
| - r_offsets.end(),
|
| - r_offset,
|
| - &CompareParameter),
|
| - r_offset);
|
| - }
|
| - if (index < substitutions)
|
| - formatted.append(subst.at(index));
|
| - }
|
| - }
|
| - } else {
|
| - formatted.push_back(*i);
|
| - }
|
| - }
|
| - if (offsets) {
|
| - for (std::vector<ReplacementOffset>::const_iterator i = r_offsets.begin();
|
| - i != r_offsets.end(); ++i) {
|
| - offsets->push_back(i->offset);
|
| - }
|
| - }
|
| - return formatted;
|
| -}
|
| -
|
| -string16 ReplaceStringPlaceholders(const string16& format_string,
|
| - const std::vector<string16>& subst,
|
| - std::vector<size_t>* offsets) {
|
| - return DoReplaceStringPlaceholders(format_string, subst, offsets);
|
| -}
|
| -
|
| -std::string ReplaceStringPlaceholders(const base::StringPiece& format_string,
|
| - const std::vector<std::string>& subst,
|
| - std::vector<size_t>* offsets) {
|
| - return DoReplaceStringPlaceholders(format_string, subst, offsets);
|
| -}
|
| -
|
| -string16 ReplaceStringPlaceholders(const string16& format_string,
|
| - const string16& a,
|
| - size_t* offset) {
|
| - std::vector<size_t> offsets;
|
| - std::vector<string16> subst;
|
| - subst.push_back(a);
|
| - string16 result = ReplaceStringPlaceholders(format_string, subst, &offsets);
|
| -
|
| - DCHECK(offsets.size() == 1);
|
| - if (offset) {
|
| - *offset = offsets[0];
|
| - }
|
| - return result;
|
| -}
|
| -
|
| -static bool IsWildcard(base_icu::UChar32 character) {
|
| - return character == '*' || character == '?';
|
| -}
|
| -
|
| -// Move the strings pointers to the point where they start to differ.
|
| -template <typename CHAR, typename NEXT>
|
| -static void EatSameChars(const CHAR** pattern, const CHAR* pattern_end,
|
| - const CHAR** string, const CHAR* string_end,
|
| - NEXT next) {
|
| - const CHAR* escape = NULL;
|
| - while (*pattern != pattern_end && *string != string_end) {
|
| - if (!escape && IsWildcard(**pattern)) {
|
| - // We don't want to match wildcard here, except if it's escaped.
|
| - return;
|
| - }
|
| -
|
| - // Check if the escapement char is found. If so, skip it and move to the
|
| - // next character.
|
| - if (!escape && **pattern == '\\') {
|
| - escape = *pattern;
|
| - next(pattern, pattern_end);
|
| - continue;
|
| - }
|
| -
|
| - // Check if the chars match, if so, increment the ptrs.
|
| - const CHAR* pattern_next = *pattern;
|
| - const CHAR* string_next = *string;
|
| - base_icu::UChar32 pattern_char = next(&pattern_next, pattern_end);
|
| - if (pattern_char == next(&string_next, string_end) &&
|
| - pattern_char != (base_icu::UChar32) CBU_SENTINEL) {
|
| - *pattern = pattern_next;
|
| - *string = string_next;
|
| - } else {
|
| - // Uh ho, it did not match, we are done. If the last char was an
|
| - // escapement, that means that it was an error to advance the ptr here,
|
| - // let's put it back where it was. This also mean that the MatchPattern
|
| - // function will return false because if we can't match an escape char
|
| - // here, then no one will.
|
| - if (escape) {
|
| - *pattern = escape;
|
| - }
|
| - return;
|
| - }
|
| -
|
| - escape = NULL;
|
| - }
|
| -}
|
| -
|
| -template <typename CHAR, typename NEXT>
|
| -static void EatWildcard(const CHAR** pattern, const CHAR* end, NEXT next) {
|
| - while (*pattern != end) {
|
| - if (!IsWildcard(**pattern))
|
| - return;
|
| - next(pattern, end);
|
| - }
|
| -}
|
| -
|
| -template <typename CHAR, typename NEXT>
|
| -static bool MatchPatternT(const CHAR* eval, const CHAR* eval_end,
|
| - const CHAR* pattern, const CHAR* pattern_end,
|
| - int depth,
|
| - NEXT next) {
|
| - const int kMaxDepth = 16;
|
| - if (depth > kMaxDepth)
|
| - return false;
|
| -
|
| - // Eat all the matching chars.
|
| - EatSameChars(&pattern, pattern_end, &eval, eval_end, next);
|
| -
|
| - // If the string is empty, then the pattern must be empty too, or contains
|
| - // only wildcards.
|
| - if (eval == eval_end) {
|
| - EatWildcard(&pattern, pattern_end, next);
|
| - return pattern == pattern_end;
|
| - }
|
| -
|
| - // Pattern is empty but not string, this is not a match.
|
| - if (pattern == pattern_end)
|
| - return false;
|
| -
|
| - // If this is a question mark, then we need to compare the rest with
|
| - // the current string or the string with one character eaten.
|
| - const CHAR* next_pattern = pattern;
|
| - next(&next_pattern, pattern_end);
|
| - if (pattern[0] == '?') {
|
| - if (MatchPatternT(eval, eval_end, next_pattern, pattern_end,
|
| - depth + 1, next))
|
| - return true;
|
| - const CHAR* next_eval = eval;
|
| - next(&next_eval, eval_end);
|
| - if (MatchPatternT(next_eval, eval_end, next_pattern, pattern_end,
|
| - depth + 1, next))
|
| - return true;
|
| - }
|
| -
|
| - // This is a *, try to match all the possible substrings with the remainder
|
| - // of the pattern.
|
| - if (pattern[0] == '*') {
|
| - // Collapse duplicate wild cards (********** into *) so that the
|
| - // method does not recurse unnecessarily. http://crbug.com/52839
|
| - EatWildcard(&next_pattern, pattern_end, next);
|
| -
|
| - while (eval != eval_end) {
|
| - if (MatchPatternT(eval, eval_end, next_pattern, pattern_end,
|
| - depth + 1, next))
|
| - return true;
|
| - eval++;
|
| - }
|
| -
|
| - // We reached the end of the string, let see if the pattern contains only
|
| - // wildcards.
|
| - if (eval == eval_end) {
|
| - EatWildcard(&pattern, pattern_end, next);
|
| - if (pattern != pattern_end)
|
| - return false;
|
| - return true;
|
| - }
|
| - }
|
| -
|
| - return false;
|
| -}
|
| -
|
| -struct NextCharUTF8 {
|
| - base_icu::UChar32 operator()(const char** p, const char* end) {
|
| - base_icu::UChar32 c;
|
| - int offset = 0;
|
| - CBU8_NEXT(*p, offset, end - *p, c);
|
| - *p += offset;
|
| - return c;
|
| - }
|
| -};
|
| -
|
| -struct NextCharUTF16 {
|
| - base_icu::UChar32 operator()(const char16** p, const char16* end) {
|
| - base_icu::UChar32 c;
|
| - int offset = 0;
|
| - CBU16_NEXT(*p, offset, end - *p, c);
|
| - *p += offset;
|
| - return c;
|
| - }
|
| -};
|
| -
|
| -bool MatchPattern(const base::StringPiece& eval,
|
| - const base::StringPiece& pattern) {
|
| - return MatchPatternT(eval.data(), eval.data() + eval.size(),
|
| - pattern.data(), pattern.data() + pattern.size(),
|
| - 0, NextCharUTF8());
|
| -}
|
| -
|
| -bool MatchPattern(const string16& eval, const string16& pattern) {
|
| - return MatchPatternT(eval.c_str(), eval.c_str() + eval.size(),
|
| - pattern.c_str(), pattern.c_str() + pattern.size(),
|
| - 0, NextCharUTF16());
|
| -}
|
| -
|
| -// The following code is compatible with the OpenBSD lcpy interface. See:
|
| -// http://www.gratisoft.us/todd/papers/strlcpy.html
|
| -// ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/{wcs,str}lcpy.c
|
| -
|
| -namespace {
|
| -
|
| -template <typename CHAR>
|
| -size_t lcpyT(CHAR* dst, const CHAR* src, size_t dst_size) {
|
| - for (size_t i = 0; i < dst_size; ++i) {
|
| - if ((dst[i] = src[i]) == 0) // We hit and copied the terminating NULL.
|
| - return i;
|
| - }
|
| -
|
| - // We were left off at dst_size. We over copied 1 byte. Null terminate.
|
| - if (dst_size != 0)
|
| - dst[dst_size - 1] = 0;
|
| -
|
| - // Count the rest of the |src|, and return it's length in characters.
|
| - while (src[dst_size]) ++dst_size;
|
| - return dst_size;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -size_t base::strlcpy(char* dst, const char* src, size_t dst_size) {
|
| - return lcpyT<char>(dst, src, dst_size);
|
| -}
|
| -size_t base::wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) {
|
| - return lcpyT<wchar_t>(dst, src, dst_size);
|
| -}
|
|
|