|  | // 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 "base/strings/utf_string_conversion_utils.h" | 
|  | #include "base/third_party/icu/icu_utf.h" | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | 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, char> { | 
|  | static inline uint32_t value() { return 0x80808080U; } | 
|  | }; | 
|  | template<> struct NonASCIIMask<8, char> { | 
|  | static inline uint64_t value() { return 0x8080808080808080ULL; } | 
|  | }; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | namespace base { | 
|  |  | 
|  | 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 std::string& input, | 
|  | const base::StringPiece& replace_chars, | 
|  | const std::string& replace_with, | 
|  | std::string* output) { | 
|  | return ReplaceCharsT(input, replace_chars.as_string(), replace_with, 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 std::string& input, | 
|  | base::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); | 
|  | } | 
|  |  | 
|  | StringPiece TrimString(StringPiece input, | 
|  | const base::StringPiece& trim_chars, | 
|  | TrimPositions positions) { | 
|  | return TrimStringPieceT(input, trim_chars, positions); | 
|  | } | 
|  |  | 
|  | TrimPositions TrimWhitespaceASCII(const std::string& input, | 
|  | TrimPositions positions, | 
|  | std::string* output) { | 
|  | return TrimStringT(input, StringPiece(kWhitespaceASCII), positions, output); | 
|  | } | 
|  |  | 
|  | 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 IsStringUTF8(const StringPiece& 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 (!IsValidCharacter(code_point)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | }  // namespace base |