summaryrefslogtreecommitdiffstats
path: root/security/sandbox/chromium/base/strings/string_util.cc
diff options
context:
space:
mode:
Diffstat (limited to 'security/sandbox/chromium/base/strings/string_util.cc')
-rw-r--r--security/sandbox/chromium/base/strings/string_util.cc1001
1 files changed, 0 insertions, 1001 deletions
diff --git a/security/sandbox/chromium/base/strings/string_util.cc b/security/sandbox/chromium/base/strings/string_util.cc
deleted file mode 100644
index e8000abd4..000000000
--- a/security/sandbox/chromium/base/strings/string_util.cc
+++ /dev/null
@@ -1,1001 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/strings/string_util.h"
-
-#include <ctype.h>
-#include <errno.h>
-#include <math.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <wchar.h>
-#include <wctype.h>
-
-#include <algorithm>
-#include <limits>
-#include <vector>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/singleton.h"
-#include "base/strings/string_split.h"
-#include "base/strings/utf_string_conversion_utils.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/third_party/icu/icu_utf.h"
-#include "build/build_config.h"
-
-namespace base {
-
-namespace {
-
-// Force the singleton used by EmptyString[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 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;
-}
-
-// Assuming that a pointer is the size of a "machine word", then
-// uintptr_t is an integer type that is also a machine word.
-typedef uintptr_t MachineWord;
-const uintptr_t kMachineWordAlignmentMask = sizeof(MachineWord) - 1;
-
-inline bool IsAlignedToMachineWord(const void* pointer) {
- return !(reinterpret_cast<MachineWord>(pointer) & kMachineWordAlignmentMask);
-}
-
-template<typename T> inline T* AlignToMachineWord(T* pointer) {
- return reinterpret_cast<T*>(reinterpret_cast<MachineWord>(pointer) &
- ~kMachineWordAlignmentMask);
-}
-
-template<size_t size, typename CharacterType> struct NonASCIIMask;
-template<> struct NonASCIIMask<4, char16> {
- static inline uint32_t value() { return 0xFF80FF80U; }
-};
-template<> struct NonASCIIMask<4, char> {
- static inline uint32_t value() { return 0x80808080U; }
-};
-template<> struct NonASCIIMask<8, char16> {
- static inline uint64_t value() { return 0xFF80FF80FF80FF80ULL; }
-};
-template<> struct NonASCIIMask<8, char> {
- static inline uint64_t value() { return 0x8080808080808080ULL; }
-};
-#if defined(WCHAR_T_IS_UTF32)
-template<> struct NonASCIIMask<4, wchar_t> {
- static inline uint32_t value() { return 0xFFFFFF80U; }
-};
-template<> struct NonASCIIMask<8, wchar_t> {
- static inline uint64_t value() { return 0xFFFFFF80FFFFFF80ULL; }
-};
-#endif // WCHAR_T_IS_UTF32
-
-} // namespace
-
-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 {
-
-template<typename StringType>
-StringType ToLowerASCIIImpl(BasicStringPiece<StringType> str) {
- StringType ret;
- ret.reserve(str.size());
- for (size_t i = 0; i < str.size(); i++)
- ret.push_back(ToLowerASCII(str[i]));
- return ret;
-}
-
-template<typename StringType>
-StringType ToUpperASCIIImpl(BasicStringPiece<StringType> str) {
- StringType ret;
- ret.reserve(str.size());
- for (size_t i = 0; i < str.size(); i++)
- ret.push_back(ToUpperASCII(str[i]));
- return ret;
-}
-
-} // namespace
-
-std::string ToLowerASCII(StringPiece str) {
- return ToLowerASCIIImpl<std::string>(str);
-}
-
-string16 ToLowerASCII(StringPiece16 str) {
- return ToLowerASCIIImpl<string16>(str);
-}
-
-std::string ToUpperASCII(StringPiece str) {
- return ToUpperASCIIImpl<std::string>(str);
-}
-
-string16 ToUpperASCII(StringPiece16 str) {
- return ToUpperASCIIImpl<string16>(str);
-}
-
-template<class StringType>
-int CompareCaseInsensitiveASCIIT(BasicStringPiece<StringType> a,
- BasicStringPiece<StringType> b) {
- // Find the first characters that aren't equal and compare them. If the end
- // of one of the strings is found before a nonequal character, the lengths
- // of the strings are compared.
- size_t i = 0;
- while (i < a.length() && i < b.length()) {
- typename StringType::value_type lower_a = ToLowerASCII(a[i]);
- typename StringType::value_type lower_b = ToLowerASCII(b[i]);
- if (lower_a < lower_b)
- return -1;
- if (lower_a > lower_b)
- return 1;
- i++;
- }
-
- // End of one string hit before finding a different character. Expect the
- // common case to be "strings equal" at this point so check that first.
- if (a.length() == b.length())
- return 0;
-
- if (a.length() < b.length())
- return -1;
- return 1;
-}
-
-int CompareCaseInsensitiveASCII(StringPiece a, StringPiece b) {
- return CompareCaseInsensitiveASCIIT<std::string>(a, b);
-}
-
-int CompareCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b) {
- return CompareCaseInsensitiveASCIIT<string16>(a, b);
-}
-
-bool EqualsCaseInsensitiveASCII(StringPiece a, StringPiece b) {
- if (a.length() != b.length())
- return false;
- return CompareCaseInsensitiveASCIIT<std::string>(a, b) == 0;
-}
-
-bool EqualsCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b) {
- if (a.length() != b.length())
- return false;
- return CompareCaseInsensitiveASCIIT<string16>(a, b) == 0;
-}
-
-const std::string& EmptyString() {
- return EmptyStrings::GetInstance()->s;
-}
-
-const string16& EmptyString16() {
- return EmptyStrings::GetInstance()->s16;
-}
-
-template<typename STR>
-bool ReplaceCharsT(const STR& input,
- const STR& replace_chars,
- const STR& replace_with,
- STR* output) {
- bool removed = false;
- size_t replace_length = replace_with.length();
-
- *output = input;
-
- size_t found = output->find_first_of(replace_chars);
- while (found != STR::npos) {
- removed = true;
- output->replace(found, 1, replace_with);
- found = output->find_first_of(replace_chars, found + replace_length);
- }
-
- return removed;
-}
-
-bool ReplaceChars(const string16& input,
- const StringPiece16& replace_chars,
- const string16& replace_with,
- string16* output) {
- return ReplaceCharsT(input, replace_chars.as_string(), replace_with, output);
-}
-
-bool ReplaceChars(const std::string& input,
- const StringPiece& replace_chars,
- const std::string& replace_with,
- std::string* output) {
- return ReplaceCharsT(input, replace_chars.as_string(), replace_with, output);
-}
-
-bool RemoveChars(const string16& input,
- const StringPiece16& remove_chars,
- string16* output) {
- return ReplaceChars(input, remove_chars.as_string(), string16(), output);
-}
-
-bool RemoveChars(const std::string& input,
- const StringPiece& remove_chars,
- std::string* output) {
- return ReplaceChars(input, remove_chars.as_string(), std::string(), output);
-}
-
-template<typename Str>
-TrimPositions TrimStringT(const Str& input,
- BasicStringPiece<Str> trim_chars,
- TrimPositions positions,
- Str* output) {
- // Find the edges of leading/trailing whitespace as desired. Need to use
- // a StringPiece version of input to be able to call find* on it with the
- // StringPiece version of trim_chars (normally the trim_chars will be a
- // constant so avoid making a copy).
- BasicStringPiece<Str> input_piece(input);
- const size_t last_char = input.length() - 1;
- const size_t first_good_char = (positions & TRIM_LEADING) ?
- input_piece.find_first_not_of(trim_chars) : 0;
- const size_t last_good_char = (positions & TRIM_TRAILING) ?
- input_piece.find_last_not_of(trim_chars) : last_char;
-
- // When the string was all trimmed, report that we stripped off characters
- // from whichever position the caller was interested in. For empty input, we
- // stripped no characters, 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.
- *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 string16& input,
- StringPiece16 trim_chars,
- string16* output) {
- return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE;
-}
-
-bool TrimString(const std::string& input,
- StringPiece trim_chars,
- std::string* output) {
- return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE;
-}
-
-template<typename Str>
-BasicStringPiece<Str> TrimStringPieceT(BasicStringPiece<Str> input,
- BasicStringPiece<Str> trim_chars,
- TrimPositions positions) {
- size_t begin = (positions & TRIM_LEADING) ?
- input.find_first_not_of(trim_chars) : 0;
- size_t end = (positions & TRIM_TRAILING) ?
- input.find_last_not_of(trim_chars) + 1 : input.size();
- return input.substr(begin, end - begin);
-}
-
-StringPiece16 TrimString(StringPiece16 input,
- const StringPiece16& trim_chars,
- TrimPositions positions) {
- return TrimStringPieceT(input, trim_chars, positions);
-}
-
-StringPiece TrimString(StringPiece input,
- const StringPiece& trim_chars,
- TrimPositions positions) {
- return TrimStringPieceT(input, trim_chars, positions);
-}
-
-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_t>(std::numeric_limits<int32_t>::max()));
- // Note: This cast is necessary because CBU8_NEXT uses int32_ts.
- int32_t truncation_length = static_cast<int32_t>(byte_size);
- int32_t 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_t prev = char_index;
- base_icu::UChar32 code_point = 0;
- CBU8_NEXT(data, char_index, truncation_length, code_point);
- if (!IsValidCharacter(code_point) ||
- !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 string16& input,
- TrimPositions positions,
- string16* output) {
- return TrimStringT(input, StringPiece16(kWhitespaceUTF16), positions, output);
-}
-
-StringPiece16 TrimWhitespace(StringPiece16 input,
- TrimPositions positions) {
- return TrimStringPieceT(input, StringPiece16(kWhitespaceUTF16), positions);
-}
-
-TrimPositions TrimWhitespaceASCII(const std::string& input,
- TrimPositions positions,
- std::string* output) {
- return TrimStringT(input, StringPiece(kWhitespaceASCII), positions, output);
-}
-
-StringPiece TrimWhitespaceASCII(StringPiece input, TrimPositions positions) {
- return TrimStringPieceT(input, StringPiece(kWhitespaceASCII), positions);
-}
-
-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 (IsUnicodeWhitespace(*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;
-}
-
-string16 CollapseWhitespace(const string16& text,
- bool trim_sequences_with_line_breaks) {
- return CollapseWhitespaceT(text, trim_sequences_with_line_breaks);
-}
-
-std::string CollapseWhitespaceASCII(const std::string& text,
- bool trim_sequences_with_line_breaks) {
- return CollapseWhitespaceT(text, trim_sequences_with_line_breaks);
-}
-
-bool ContainsOnlyChars(const StringPiece& input,
- const StringPiece& characters) {
- return input.find_first_not_of(characters) == StringPiece::npos;
-}
-
-bool ContainsOnlyChars(const StringPiece16& input,
- const StringPiece16& characters) {
- return input.find_first_not_of(characters) == StringPiece16::npos;
-}
-
-template <class Char>
-inline bool DoIsStringASCII(const Char* characters, size_t length) {
- MachineWord all_char_bits = 0;
- const Char* end = characters + length;
-
- // Prologue: align the input.
- while (!IsAlignedToMachineWord(characters) && characters != end) {
- all_char_bits |= *characters;
- ++characters;
- }
-
- // Compare the values of CPU word size.
- const Char* word_end = AlignToMachineWord(end);
- const size_t loop_increment = sizeof(MachineWord) / sizeof(Char);
- while (characters < word_end) {
- all_char_bits |= *(reinterpret_cast<const MachineWord*>(characters));
- characters += loop_increment;
- }
-
- // Process the remaining bytes.
- while (characters != end) {
- all_char_bits |= *characters;
- ++characters;
- }
-
- MachineWord non_ascii_bit_mask =
- NonASCIIMask<sizeof(MachineWord), Char>::value();
- return !(all_char_bits & non_ascii_bit_mask);
-}
-
-bool IsStringASCII(const StringPiece& str) {
- return DoIsStringASCII(str.data(), str.length());
-}
-
-bool IsStringASCII(const StringPiece16& str) {
- return DoIsStringASCII(str.data(), str.length());
-}
-
-bool IsStringASCII(const string16& str) {
- return DoIsStringASCII(str.data(), str.length());
-}
-
-#if defined(WCHAR_T_IS_UTF32)
-bool IsStringASCII(const std::wstring& str) {
- return DoIsStringASCII(str.data(), str.length());
-}
-#endif
-
-bool IsStringUTF8(const StringPiece& str) {
- const char *src = str.data();
- int32_t src_len = static_cast<int32_t>(str.length());
- int32_t char_index = 0;
-
- while (char_index < src_len) {
- int32_t code_point;
- CBU8_NEXT(src, char_index, src_len, code_point);
- if (!IsValidCharacter(code_point))
- return false;
- }
- return true;
-}
-
-// Implementation note: Normally this function will be called with a hardcoded
-// constant for the lowercase_ascii parameter. Constructing a StringPiece from
-// a C constant requires running strlen, so the result will be two passes
-// through the buffers, one to file the length of lowercase_ascii, and one to
-// compare each letter.
-//
-// This function could have taken a const char* to avoid this and only do one
-// pass through the string. But the strlen is faster than the case-insensitive
-// compares and lets us early-exit in the case that the strings are different
-// lengths (will often be the case for non-matches). So whether one approach or
-// the other will be faster depends on the case.
-//
-// The hardcoded strings are typically very short so it doesn't matter, and the
-// string piece gives additional flexibility for the caller (doesn't have to be
-// null terminated) so we choose the StringPiece route.
-template<typename Str>
-static inline bool DoLowerCaseEqualsASCII(BasicStringPiece<Str> str,
- StringPiece lowercase_ascii) {
- if (str.size() != lowercase_ascii.size())
- return false;
- for (size_t i = 0; i < str.size(); i++) {
- if (ToLowerASCII(str[i]) != lowercase_ascii[i])
- return false;
- }
- return true;
-}
-
-bool LowerCaseEqualsASCII(StringPiece str, StringPiece lowercase_ascii) {
- return DoLowerCaseEqualsASCII<std::string>(str, lowercase_ascii);
-}
-
-bool LowerCaseEqualsASCII(StringPiece16 str, StringPiece lowercase_ascii) {
- return DoLowerCaseEqualsASCII<string16>(str, lowercase_ascii);
-}
-
-bool EqualsASCII(StringPiece16 str, StringPiece ascii) {
- if (str.length() != ascii.length())
- return false;
- return std::equal(ascii.begin(), ascii.end(), str.begin());
-}
-
-template<typename Str>
-bool StartsWithT(BasicStringPiece<Str> str,
- BasicStringPiece<Str> search_for,
- CompareCase case_sensitivity) {
- if (search_for.size() > str.size())
- return false;
-
- BasicStringPiece<Str> source = str.substr(0, search_for.size());
-
- switch (case_sensitivity) {
- case CompareCase::SENSITIVE:
- return source == search_for;
-
- case CompareCase::INSENSITIVE_ASCII:
- return std::equal(
- search_for.begin(), search_for.end(),
- source.begin(),
- CaseInsensitiveCompareASCII<typename Str::value_type>());
-
- default:
- NOTREACHED();
- return false;
- }
-}
-
-bool StartsWith(StringPiece str,
- StringPiece search_for,
- CompareCase case_sensitivity) {
- return StartsWithT<std::string>(str, search_for, case_sensitivity);
-}
-
-bool StartsWith(StringPiece16 str,
- StringPiece16 search_for,
- CompareCase case_sensitivity) {
- return StartsWithT<string16>(str, search_for, case_sensitivity);
-}
-
-template <typename Str>
-bool EndsWithT(BasicStringPiece<Str> str,
- BasicStringPiece<Str> search_for,
- CompareCase case_sensitivity) {
- if (search_for.size() > str.size())
- return false;
-
- BasicStringPiece<Str> source = str.substr(str.size() - search_for.size(),
- search_for.size());
-
- switch (case_sensitivity) {
- case CompareCase::SENSITIVE:
- return source == search_for;
-
- case CompareCase::INSENSITIVE_ASCII:
- return std::equal(
- source.begin(), source.end(),
- search_for.begin(),
- CaseInsensitiveCompareASCII<typename Str::value_type>());
-
- default:
- NOTREACHED();
- return false;
- }
-}
-
-bool EndsWith(StringPiece str,
- StringPiece search_for,
- CompareCase case_sensitivity) {
- return EndsWithT<std::string>(str, search_for, case_sensitivity);
-}
-
-bool EndsWith(StringPiece16 str,
- StringPiece16 search_for,
- CompareCase case_sensitivity) {
- return EndsWithT<string16>(str, search_for, case_sensitivity);
-}
-
-char HexDigitToInt(wchar_t c) {
- DCHECK(IsHexDigit(c));
- if (c >= '0' && c <= '9')
- return static_cast<char>(c - '0');
- if (c >= 'A' && c <= 'F')
- return static_cast<char>(c - 'A' + 10);
- if (c >= 'a' && c <= 'f')
- return static_cast<char>(c - 'a' + 10);
- return 0;
-}
-
-bool IsUnicodeWhitespace(wchar_t c) {
- // kWhitespaceWide is a NULL-terminated string
- for (const wchar_t* cur = kWhitespaceWide; *cur; ++cur) {
- if (*cur == c)
- return true;
- }
- return false;
-}
-
-static const char* const kByteStringsUnlocalized[] = {
- " B",
- " kB",
- " MB",
- " GB",
- " TB",
- " PB"
-};
-
-string16 FormatBytesUnlocalized(int64_t bytes) {
- double unit_amount = static_cast<double>(bytes);
- size_t dimension = 0;
- const int kKilo = 1024;
- while (unit_amount >= kKilo &&
- dimension < arraysize(kByteStringsUnlocalized) - 1) {
- unit_amount /= kKilo;
- dimension++;
- }
-
- char buf[64];
- if (bytes != 0 && dimension > 0 && unit_amount < 100) {
- base::snprintf(buf, arraysize(buf), "%.1lf%s", unit_amount,
- kByteStringsUnlocalized[dimension]);
- } else {
- base::snprintf(buf, arraysize(buf), "%.0lf%s", unit_amount,
- kByteStringsUnlocalized[dimension]);
- }
-
- return ASCIIToUTF16(buf);
-}
-
-// Runs in O(n) time in the length of |str|.
-template<class StringType>
-void DoReplaceSubstringsAfterOffset(StringType* str,
- size_t offset,
- BasicStringPiece<StringType> find_this,
- BasicStringPiece<StringType> replace_with,
- bool replace_all) {
- DCHECK(!find_this.empty());
-
- // If the find string doesn't appear, there's nothing to do.
- offset = str->find(find_this.data(), offset, find_this.size());
- if (offset == StringType::npos)
- return;
-
- // If we're only replacing one instance, there's no need to do anything
- // complicated.
- size_t find_length = find_this.length();
- if (!replace_all) {
- str->replace(offset, find_length, replace_with.data(), replace_with.size());
- return;
- }
-
- // If the find and replace strings are the same length, we can simply use
- // replace() on each instance, and finish the entire operation in O(n) time.
- size_t replace_length = replace_with.length();
- if (find_length == replace_length) {
- do {
- str->replace(offset, find_length,
- replace_with.data(), replace_with.size());
- offset = str->find(find_this.data(), offset + replace_length,
- find_this.size());
- } while (offset != StringType::npos);
- return;
- }
-
- // Since the find and replace strings aren't the same length, a loop like the
- // one above would be O(n^2) in the worst case, as replace() will shift the
- // entire remaining string each time. We need to be more clever to keep
- // things O(n).
- //
- // If we're shortening the string, we can alternate replacements with shifting
- // forward the intervening characters using memmove().
- size_t str_length = str->length();
- if (find_length > replace_length) {
- size_t write_offset = offset;
- do {
- if (replace_length) {
- str->replace(write_offset, replace_length,
- replace_with.data(), replace_with.size());
- write_offset += replace_length;
- }
- size_t read_offset = offset + find_length;
- offset = std::min(
- str->find(find_this.data(), read_offset, find_this.size()),
- str_length);
- size_t length = offset - read_offset;
- if (length) {
- memmove(&(*str)[write_offset], &(*str)[read_offset],
- length * sizeof(typename StringType::value_type));
- write_offset += length;
- }
- } while (offset < str_length);
- str->resize(write_offset);
- return;
- }
-
- // We're lengthening the string. We can use alternating replacements and
- // memmove() calls like above, but we need to precalculate the final string
- // length and then expand from back-to-front to avoid overwriting the string
- // as we're reading it, needing to shift, or having to copy to a second string
- // temporarily.
- size_t first_match = offset;
-
- // First, calculate the final length and resize the string.
- size_t final_length = str_length;
- size_t expansion = replace_length - find_length;
- size_t current_match;
- do {
- final_length += expansion;
- // Minor optimization: save this offset into |current_match|, so that on
- // exit from the loop, |current_match| will point at the last instance of
- // the find string, and we won't need to find() it again immediately.
- current_match = offset;
- offset = str->find(find_this.data(), offset + find_length,
- find_this.size());
- } while (offset != StringType::npos);
- str->resize(final_length);
-
- // Now do the replacement loop, working backwards through the string.
- for (size_t prev_match = str_length, write_offset = final_length; ;
- current_match = str->rfind(find_this.data(), current_match - 1,
- find_this.size())) {
- size_t read_offset = current_match + find_length;
- size_t length = prev_match - read_offset;
- if (length) {
- write_offset -= length;
- memmove(&(*str)[write_offset], &(*str)[read_offset],
- length * sizeof(typename StringType::value_type));
- }
- write_offset -= replace_length;
- str->replace(write_offset, replace_length,
- replace_with.data(), replace_with.size());
- if (current_match == first_match)
- return;
- prev_match = current_match;
- }
-}
-
-void ReplaceFirstSubstringAfterOffset(string16* str,
- size_t start_offset,
- StringPiece16 find_this,
- StringPiece16 replace_with) {
- DoReplaceSubstringsAfterOffset<string16>(
- str, start_offset, find_this, replace_with, false); // Replace first.
-}
-
-void ReplaceFirstSubstringAfterOffset(std::string* str,
- size_t start_offset,
- StringPiece find_this,
- StringPiece replace_with) {
- DoReplaceSubstringsAfterOffset<std::string>(
- str, start_offset, find_this, replace_with, false); // Replace first.
-}
-
-void ReplaceSubstringsAfterOffset(string16* str,
- size_t start_offset,
- StringPiece16 find_this,
- StringPiece16 replace_with) {
- DoReplaceSubstringsAfterOffset<string16>(
- str, start_offset, find_this, replace_with, true); // Replace all.
-}
-
-void ReplaceSubstringsAfterOffset(std::string* str,
- size_t start_offset,
- StringPiece find_this,
- StringPiece replace_with) {
- DoReplaceSubstringsAfterOffset<std::string>(
- str, start_offset, find_this, replace_with, true); // Replace all.
-}
-
-template <class string_type>
-inline typename string_type::value_type* WriteIntoT(string_type* str,
- size_t length_with_null) {
- DCHECK_GT(length_with_null, 1u);
- str->reserve(length_with_null);
- str->resize(length_with_null - 1);
- return &((*str)[0]);
-}
-
-char* WriteInto(std::string* str, size_t length_with_null) {
- return WriteIntoT(str, length_with_null);
-}
-
-char16* WriteInto(string16* str, size_t length_with_null) {
- return WriteIntoT(str, length_with_null);
-}
-
-template<typename STR>
-static STR JoinStringT(const std::vector<STR>& parts,
- BasicStringPiece<STR> sep) {
- if (parts.empty())
- return STR();
-
- STR result(parts[0]);
- auto iter = parts.begin();
- ++iter;
-
- for (; iter != parts.end(); ++iter) {
- sep.AppendToString(&result);
- result += *iter;
- }
-
- return result;
-}
-
-std::string JoinString(const std::vector<std::string>& parts,
- StringPiece separator) {
- return JoinStringT(parts, separator);
-}
-
-string16 JoinString(const std::vector<string16>& parts,
- StringPiece16 separator) {
- return JoinStringT(parts, separator);
-}
-
-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();
-
- size_t sub_length = 0;
- for (const auto& cur : subst)
- sub_length += cur.length();
-
- OutStringType formatted;
- formatted.reserve(format_string.length() + sub_length);
-
- std::vector<ReplacementOffset> r_offsets;
- for (auto 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 = 0;
- while (i != format_string.end() && '0' <= *i && *i <= '9') {
- index *= 10;
- index += *i - '0';
- ++i;
- }
- --i;
- index -= 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 (const auto& cur : r_offsets)
- offsets->push_back(cur.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 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_EQ(1U, offsets.size());
- if (offset)
- *offset = offsets[0];
- return result;
-}
-
-// 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 strlcpy(char* dst, const char* src, size_t dst_size) {
- return lcpyT<char>(dst, src, dst_size);
-}
-size_t wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) {
- return lcpyT<wchar_t>(dst, src, dst_size);
-}
-
-} // namespace base