Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(300)

Side by Side Diff: base/strings/string_util.cc

Issue 1641513004: Update //base to chromium 9659b08ea5a34f889dc4166217f438095ddc10d2 (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/strings/string_util.h ('k') | base/strings/string_util_constants.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/strings/string_util.h" 5 #include "base/strings/string_util.h"
6 6
7 #include <ctype.h> 7 #include <ctype.h>
8 #include <errno.h> 8 #include <errno.h>
9 #include <math.h> 9 #include <math.h>
10 #include <stdarg.h> 10 #include <stdarg.h>
11 #include <stdio.h> 11 #include <stdio.h>
12 #include <stdlib.h> 12 #include <stdlib.h>
13 #include <string.h> 13 #include <string.h>
14 #include <time.h> 14 #include <time.h>
15 #include <wchar.h> 15 #include <wchar.h>
16 #include <wctype.h> 16 #include <wctype.h>
17 17
18 #include <algorithm> 18 #include <algorithm>
19 #include <vector> 19 #include <vector>
20 20
21 #include "base/basictypes.h" 21 #include "base/basictypes.h"
22 #include "base/logging.h" 22 #include "base/logging.h"
23 #include "base/memory/singleton.h" 23 #include "base/memory/singleton.h"
24 #include "base/strings/string_split.h"
24 #include "base/strings/utf_string_conversion_utils.h" 25 #include "base/strings/utf_string_conversion_utils.h"
25 #include "base/strings/utf_string_conversions.h" 26 #include "base/strings/utf_string_conversions.h"
26 #include "base/third_party/icu/icu_utf.h" 27 #include "base/third_party/icu/icu_utf.h"
27 #include "build/build_config.h" 28 #include "build/build_config.h"
28 29
29 // Remove when this entire file is in the base namespace. 30 namespace base {
30 using base::char16;
31 using base::string16;
32 31
33 namespace { 32 namespace {
34 33
35 // Force the singleton used by EmptyString[16] to be a unique type. This 34 // Force the singleton used by EmptyString[16] to be a unique type. This
36 // prevents other code that might accidentally use Singleton<string> from 35 // prevents other code that might accidentally use Singleton<string> from
37 // getting our internal one. 36 // getting our internal one.
38 struct EmptyStrings { 37 struct EmptyStrings {
39 EmptyStrings() {} 38 EmptyStrings() {}
40 const std::string s; 39 const std::string s;
41 const string16 s16; 40 const string16 s16;
(...skipping 30 matching lines...) Expand all
72 inline bool IsAlignedToMachineWord(const void* pointer) { 71 inline bool IsAlignedToMachineWord(const void* pointer) {
73 return !(reinterpret_cast<MachineWord>(pointer) & kMachineWordAlignmentMask); 72 return !(reinterpret_cast<MachineWord>(pointer) & kMachineWordAlignmentMask);
74 } 73 }
75 74
76 template<typename T> inline T* AlignToMachineWord(T* pointer) { 75 template<typename T> inline T* AlignToMachineWord(T* pointer) {
77 return reinterpret_cast<T*>(reinterpret_cast<MachineWord>(pointer) & 76 return reinterpret_cast<T*>(reinterpret_cast<MachineWord>(pointer) &
78 ~kMachineWordAlignmentMask); 77 ~kMachineWordAlignmentMask);
79 } 78 }
80 79
81 template<size_t size, typename CharacterType> struct NonASCIIMask; 80 template<size_t size, typename CharacterType> struct NonASCIIMask;
82 template<> struct NonASCIIMask<4, base::char16> { 81 template <>
83 static inline uint32_t value() { return 0xFF80FF80U; } 82 struct NonASCIIMask<4, char16> {
83 static inline uint32_t value() { return 0xFF80FF80U; }
84 }; 84 };
85 template<> struct NonASCIIMask<4, char> { 85 template<> struct NonASCIIMask<4, char> {
86 static inline uint32_t value() { return 0x80808080U; } 86 static inline uint32_t value() { return 0x80808080U; }
87 }; 87 };
88 template<> struct NonASCIIMask<8, base::char16> { 88 template <>
89 static inline uint64_t value() { return 0xFF80FF80FF80FF80ULL; } 89 struct NonASCIIMask<8, char16> {
90 static inline uint64_t value() { return 0xFF80FF80FF80FF80ULL; }
90 }; 91 };
91 template<> struct NonASCIIMask<8, char> { 92 template<> struct NonASCIIMask<8, char> {
92 static inline uint64_t value() { return 0x8080808080808080ULL; } 93 static inline uint64_t value() { return 0x8080808080808080ULL; }
93 }; 94 };
94 #if defined(WCHAR_T_IS_UTF32) 95 #if defined(WCHAR_T_IS_UTF32)
95 template<> struct NonASCIIMask<4, wchar_t> { 96 template<> struct NonASCIIMask<4, wchar_t> {
96 static inline uint32_t value() { return 0xFFFFFF80U; } 97 static inline uint32_t value() { return 0xFFFFFF80U; }
97 }; 98 };
98 template<> struct NonASCIIMask<8, wchar_t> { 99 template<> struct NonASCIIMask<8, wchar_t> {
99 static inline uint64_t value() { return 0xFFFFFF80FFFFFF80ULL; } 100 static inline uint64_t value() { return 0xFFFFFF80FFFFFF80ULL; }
100 }; 101 };
101 #endif // WCHAR_T_IS_UTF32 102 #endif // WCHAR_T_IS_UTF32
102 103
104 // DO NOT USE. http://crbug.com/24917
105 //
106 // tolower() will given incorrect results for non-ASCII characters. Use the
107 // ASCII version, base::i18n::ToLower, or base::i18n::FoldCase. This is here
108 // for backwards-compat for StartsWith until such calls can be updated.
109 struct CaseInsensitiveCompareDeprecated {
110 public:
111 bool operator()(char16 x, char16 y) const { return tolower(x) == tolower(y); }
112 };
113
103 } // namespace 114 } // namespace
104 115
105 namespace base {
106
107 bool IsWprintfFormatPortable(const wchar_t* format) { 116 bool IsWprintfFormatPortable(const wchar_t* format) {
108 for (const wchar_t* position = format; *position != '\0'; ++position) { 117 for (const wchar_t* position = format; *position != '\0'; ++position) {
109 if (*position == '%') { 118 if (*position == '%') {
110 bool in_specification = true; 119 bool in_specification = true;
111 bool modifier_l = false; 120 bool modifier_l = false;
112 while (in_specification) { 121 while (in_specification) {
113 // Eat up characters until reaching a known specifier. 122 // Eat up characters until reaching a known specifier.
114 if (*++position == '\0') { 123 if (*++position == '\0') {
115 // The format string ended in the middle of a specification. Call 124 // The format string ended in the middle of a specification. Call
116 // it portable because no unportable specifications were found. The 125 // it portable because no unportable specifications were found. The
(...skipping 15 matching lines...) Expand all
132 // Portable, keep scanning the rest of the format string. 141 // Portable, keep scanning the rest of the format string.
133 in_specification = false; 142 in_specification = false;
134 } 143 }
135 } 144 }
136 } 145 }
137 } 146 }
138 147
139 return true; 148 return true;
140 } 149 }
141 150
151 template <class StringType>
152 int CompareCaseInsensitiveASCIIT(BasicStringPiece<StringType> a,
153 BasicStringPiece<StringType> b) {
154 // Find the first characters that aren't equal and compare them. If the end
155 // of one of the strings is found before a nonequal character, the lengths
156 // of the strings are compared.
157 size_t i = 0;
158 while (i < a.length() && i < b.length()) {
159 typename StringType::value_type lower_a = ToLowerASCII(a[i]);
160 typename StringType::value_type lower_b = ToLowerASCII(b[i]);
161 if (lower_a < lower_b)
162 return -1;
163 if (lower_a > lower_b)
164 return 1;
165 i++;
166 }
167
168 // End of one string hit before finding a different character. Expect the
169 // common case to be "strings equal" at this point so check that first.
170 if (a.length() == b.length())
171 return 0;
172
173 if (a.length() < b.length())
174 return -1;
175 return 1;
176 }
177
178 int CompareCaseInsensitiveASCII(StringPiece a, StringPiece b) {
179 return CompareCaseInsensitiveASCIIT<std::string>(a, b);
180 }
181
182 int CompareCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b) {
183 return CompareCaseInsensitiveASCIIT<string16>(a, b);
184 }
185
186 bool EqualsCaseInsensitiveASCII(StringPiece a, StringPiece b) {
187 if (a.length() != b.length())
188 return false;
189 return CompareCaseInsensitiveASCIIT<std::string>(a, b) == 0;
190 }
191
192 bool EqualsCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b) {
193 if (a.length() != b.length())
194 return false;
195 return CompareCaseInsensitiveASCIIT<string16>(a, b) == 0;
196 }
197
142 const std::string& EmptyString() { 198 const std::string& EmptyString() {
143 return EmptyStrings::GetInstance()->s; 199 return EmptyStrings::GetInstance()->s;
144 } 200 }
145 201
146 const string16& EmptyString16() { 202 const string16& EmptyString16() {
147 return EmptyStrings::GetInstance()->s16; 203 return EmptyStrings::GetInstance()->s16;
148 } 204 }
149 205
150 template<typename STR> 206 template<typename STR>
151 bool ReplaceCharsT(const STR& input, 207 bool ReplaceCharsT(const STR& input,
152 const STR& replace_chars, 208 const STR& replace_chars,
153 const STR& replace_with, 209 const STR& replace_with,
154 STR* output) { 210 STR* output) {
155 bool removed = false; 211 bool removed = false;
156 size_t replace_length = replace_with.length(); 212 size_t replace_length = replace_with.length();
157 213
158 *output = input; 214 *output = input;
159 215
160 size_t found = output->find_first_of(replace_chars); 216 size_t found = output->find_first_of(replace_chars);
161 while (found != STR::npos) { 217 while (found != STR::npos) {
162 removed = true; 218 removed = true;
163 output->replace(found, 1, replace_with); 219 output->replace(found, 1, replace_with);
164 found = output->find_first_of(replace_chars, found + replace_length); 220 found = output->find_first_of(replace_chars, found + replace_length);
165 } 221 }
166 222
167 return removed; 223 return removed;
168 } 224 }
169 225
170 bool ReplaceChars(const string16& input, 226 bool ReplaceChars(const string16& input,
171 const base::StringPiece16& replace_chars, 227 const StringPiece16& replace_chars,
172 const string16& replace_with, 228 const string16& replace_with,
173 string16* output) { 229 string16* output) {
174 return ReplaceCharsT(input, replace_chars.as_string(), replace_with, output); 230 return ReplaceCharsT(input, replace_chars.as_string(), replace_with, output);
175 } 231 }
176 232
177 bool ReplaceChars(const std::string& input, 233 bool ReplaceChars(const std::string& input,
178 const base::StringPiece& replace_chars, 234 const StringPiece& replace_chars,
179 const std::string& replace_with, 235 const std::string& replace_with,
180 std::string* output) { 236 std::string* output) {
181 return ReplaceCharsT(input, replace_chars.as_string(), replace_with, output); 237 return ReplaceCharsT(input, replace_chars.as_string(), replace_with, output);
182 } 238 }
183 239
184 bool RemoveChars(const string16& input, 240 bool RemoveChars(const string16& input,
185 const base::StringPiece16& remove_chars, 241 const StringPiece16& remove_chars,
186 string16* output) { 242 string16* output) {
187 return ReplaceChars(input, remove_chars.as_string(), string16(), output); 243 return ReplaceChars(input, remove_chars.as_string(), string16(), output);
188 } 244 }
189 245
190 bool RemoveChars(const std::string& input, 246 bool RemoveChars(const std::string& input,
191 const base::StringPiece& remove_chars, 247 const StringPiece& remove_chars,
192 std::string* output) { 248 std::string* output) {
193 return ReplaceChars(input, remove_chars.as_string(), std::string(), output); 249 return ReplaceChars(input, remove_chars.as_string(), std::string(), output);
194 } 250 }
195 251
196 template<typename STR> 252 template <typename Str>
197 TrimPositions TrimStringT(const STR& input, 253 TrimPositions TrimStringT(const Str& input,
198 const STR& trim_chars, 254 BasicStringPiece<Str> trim_chars,
199 TrimPositions positions, 255 TrimPositions positions,
200 STR* output) { 256 Str* output) {
201 // Find the edges of leading/trailing whitespace as desired. 257 // Find the edges of leading/trailing whitespace as desired. Need to use
258 // a StringPiece version of input to be able to call find* on it with the
259 // StringPiece version of trim_chars (normally the trim_chars will be a
260 // constant so avoid making a copy).
261 BasicStringPiece<Str> input_piece(input);
202 const size_t last_char = input.length() - 1; 262 const size_t last_char = input.length() - 1;
203 const size_t first_good_char = (positions & TRIM_LEADING) ? 263 const size_t first_good_char = (positions & TRIM_LEADING)
204 input.find_first_not_of(trim_chars) : 0; 264 ? input_piece.find_first_not_of(trim_chars)
205 const size_t last_good_char = (positions & TRIM_TRAILING) ? 265 : 0;
206 input.find_last_not_of(trim_chars) : last_char; 266 const size_t last_good_char = (positions & TRIM_TRAILING)
267 ? input_piece.find_last_not_of(trim_chars)
268 : last_char;
207 269
208 // When the string was all whitespace, report that we stripped off whitespace 270 // When the string was all trimmed, report that we stripped off characters
209 // from whichever position the caller was interested in. For empty input, we 271 // from whichever position the caller was interested in. For empty input, we
210 // stripped no whitespace, but we still need to clear |output|. 272 // stripped no characters, but we still need to clear |output|.
211 if (input.empty() || 273 if (input.empty() || (first_good_char == Str::npos) ||
212 (first_good_char == STR::npos) || (last_good_char == STR::npos)) { 274 (last_good_char == Str::npos)) {
213 bool input_was_empty = input.empty(); // in case output == &input 275 bool input_was_empty = input.empty(); // in case output == &input
214 output->clear(); 276 output->clear();
215 return input_was_empty ? TRIM_NONE : positions; 277 return input_was_empty ? TRIM_NONE : positions;
216 } 278 }
217 279
218 // Trim the whitespace. 280 // Trim.
219 *output = 281 *output =
220 input.substr(first_good_char, last_good_char - first_good_char + 1); 282 input.substr(first_good_char, last_good_char - first_good_char + 1);
221 283
222 // Return where we trimmed from. 284 // Return where we trimmed from.
223 return static_cast<TrimPositions>( 285 return static_cast<TrimPositions>(
224 ((first_good_char == 0) ? TRIM_NONE : TRIM_LEADING) | 286 ((first_good_char == 0) ? TRIM_NONE : TRIM_LEADING) |
225 ((last_good_char == last_char) ? TRIM_NONE : TRIM_TRAILING)); 287 ((last_good_char == last_char) ? TRIM_NONE : TRIM_TRAILING));
226 } 288 }
227 289
228 bool TrimString(const string16& input, 290 bool TrimString(const string16& input,
229 const base::StringPiece16& trim_chars, 291 StringPiece16 trim_chars,
230 string16* output) { 292 string16* output) {
231 return TrimStringT(input, trim_chars.as_string(), TRIM_ALL, output) != 293 return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE;
232 TRIM_NONE;
233 } 294 }
234 295
235 bool TrimString(const std::string& input, 296 bool TrimString(const std::string& input,
236 const base::StringPiece& trim_chars, 297 StringPiece trim_chars,
237 std::string* output) { 298 std::string* output) {
238 return TrimStringT(input, trim_chars.as_string(), TRIM_ALL, output) != 299 return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE;
239 TRIM_NONE; 300 }
301
302 template <typename Str>
303 BasicStringPiece<Str> TrimStringPieceT(BasicStringPiece<Str> input,
304 BasicStringPiece<Str> trim_chars,
305 TrimPositions positions) {
306 size_t begin =
307 (positions & TRIM_LEADING) ? input.find_first_not_of(trim_chars) : 0;
308 size_t end = (positions & TRIM_TRAILING)
309 ? input.find_last_not_of(trim_chars) + 1
310 : input.size();
311 return input.substr(begin, end - begin);
312 }
313
314 StringPiece16 TrimString(StringPiece16 input,
315 const StringPiece16& trim_chars,
316 TrimPositions positions) {
317 return TrimStringPieceT(input, trim_chars, positions);
318 }
319
320 StringPiece TrimString(StringPiece input,
321 const StringPiece& trim_chars,
322 TrimPositions positions) {
323 return TrimStringPieceT(input, trim_chars, positions);
240 } 324 }
241 325
242 void TruncateUTF8ToByteSize(const std::string& input, 326 void TruncateUTF8ToByteSize(const std::string& input,
243 const size_t byte_size, 327 const size_t byte_size,
244 std::string* output) { 328 std::string* output) {
245 DCHECK(output); 329 DCHECK(output);
246 if (byte_size > input.length()) { 330 if (byte_size > input.length()) {
247 *output = input; 331 *output = input;
248 return; 332 return;
249 } 333 }
(...skipping 21 matching lines...) Expand all
271 355
272 if (char_index >= 0 ) 356 if (char_index >= 0 )
273 *output = input.substr(0, char_index); 357 *output = input.substr(0, char_index);
274 else 358 else
275 output->clear(); 359 output->clear();
276 } 360 }
277 361
278 TrimPositions TrimWhitespace(const string16& input, 362 TrimPositions TrimWhitespace(const string16& input,
279 TrimPositions positions, 363 TrimPositions positions,
280 string16* output) { 364 string16* output) {
281 return TrimStringT(input, base::string16(kWhitespaceUTF16), positions, 365 return TrimStringT(input, StringPiece16(kWhitespaceUTF16), positions, output);
282 output); 366 }
367
368 StringPiece16 TrimWhitespaceASCII(StringPiece16 input,
369 TrimPositions positions) {
370 return TrimStringPieceT(input, StringPiece16(kWhitespaceUTF16), positions);
283 } 371 }
284 372
285 TrimPositions TrimWhitespaceASCII(const std::string& input, 373 TrimPositions TrimWhitespaceASCII(const std::string& input,
286 TrimPositions positions, 374 TrimPositions positions,
287 std::string* output) { 375 std::string* output) {
288 return TrimStringT(input, std::string(kWhitespaceASCII), positions, output); 376 return TrimStringT(input, StringPiece(kWhitespaceASCII), positions, output);
377 }
378
379 StringPiece TrimWhitespaceASCII(StringPiece input, TrimPositions positions) {
380 return TrimStringPieceT(input, StringPiece(kWhitespaceASCII), positions);
289 } 381 }
290 382
291 // This function is only for backward-compatibility. 383 // This function is only for backward-compatibility.
292 // To be removed when all callers are updated. 384 // To be removed when all callers are updated.
293 TrimPositions TrimWhitespace(const std::string& input, 385 TrimPositions TrimWhitespace(const std::string& input,
294 TrimPositions positions, 386 TrimPositions positions,
295 std::string* output) { 387 std::string* output) {
296 return TrimWhitespaceASCII(input, positions, output); 388 return TrimWhitespaceASCII(input, positions, output);
297 } 389 }
298 390
299 template<typename STR> 391 template<typename STR>
300 STR CollapseWhitespaceT(const STR& text, 392 STR CollapseWhitespaceT(const STR& text,
301 bool trim_sequences_with_line_breaks) { 393 bool trim_sequences_with_line_breaks) {
302 STR result; 394 STR result;
303 result.resize(text.size()); 395 result.resize(text.size());
304 396
305 // Set flags to pretend we're already in a trimmed whitespace sequence, so we 397 // Set flags to pretend we're already in a trimmed whitespace sequence, so we
306 // will trim any leading whitespace. 398 // will trim any leading whitespace.
307 bool in_whitespace = true; 399 bool in_whitespace = true;
308 bool already_trimmed = true; 400 bool already_trimmed = true;
309 401
310 int chars_written = 0; 402 int chars_written = 0;
311 for (typename STR::const_iterator i(text.begin()); i != text.end(); ++i) { 403 for (typename STR::const_iterator i(text.begin()); i != text.end(); ++i) {
312 if (IsWhitespace(*i)) { 404 if (IsUnicodeWhitespace(*i)) {
313 if (!in_whitespace) { 405 if (!in_whitespace) {
314 // Reduce all whitespace sequences to a single space. 406 // Reduce all whitespace sequences to a single space.
315 in_whitespace = true; 407 in_whitespace = true;
316 result[chars_written++] = L' '; 408 result[chars_written++] = L' ';
317 } 409 }
318 if (trim_sequences_with_line_breaks && !already_trimmed && 410 if (trim_sequences_with_line_breaks && !already_trimmed &&
319 ((*i == '\n') || (*i == '\r'))) { 411 ((*i == '\n') || (*i == '\r'))) {
320 // Whitespace sequences containing CR or LF are eliminated entirely. 412 // Whitespace sequences containing CR or LF are eliminated entirely.
321 already_trimmed = true; 413 already_trimmed = true;
322 --chars_written; 414 --chars_written;
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
475 const char* b) { 567 const char* b) {
476 return DoLowerCaseEqualsASCII(a_begin, a_end, b); 568 return DoLowerCaseEqualsASCII(a_begin, a_end, b);
477 } 569 }
478 570
479 bool EqualsASCII(const string16& a, const StringPiece& b) { 571 bool EqualsASCII(const string16& a, const StringPiece& b) {
480 if (a.length() != b.length()) 572 if (a.length() != b.length())
481 return false; 573 return false;
482 return std::equal(b.begin(), b.end(), a.begin()); 574 return std::equal(b.begin(), b.end(), a.begin());
483 } 575 }
484 576
485 } // namespace base 577 template <typename Str>
578 bool StartsWithT(BasicStringPiece<Str> str,
579 BasicStringPiece<Str> search_for,
580 CompareCase case_sensitivity) {
581 if (search_for.size() > str.size())
582 return false;
486 583
487 bool StartsWithASCII(const std::string& str, 584 BasicStringPiece<Str> source = str.substr(0, search_for.size());
488 const std::string& search, 585
489 bool case_sensitive) { 586 switch (case_sensitivity) {
490 if (case_sensitive) 587 case CompareCase::SENSITIVE:
491 return str.compare(0, search.length(), search) == 0; 588 return source == search_for;
492 else 589
493 return base::strncasecmp(str.c_str(), search.c_str(), search.length()) == 0; 590 case CompareCase::INSENSITIVE_ASCII:
591 return std::equal(
592 search_for.begin(), search_for.end(), source.begin(),
593 CaseInsensitiveCompareASCII<typename Str::value_type>());
594
595 default:
596 NOTREACHED();
597 return false;
598 }
494 } 599 }
495 600
496 template <typename STR> 601 bool StartsWith(StringPiece str,
497 bool StartsWithT(const STR& str, const STR& search, bool case_sensitive) { 602 StringPiece search_for,
498 if (case_sensitive) { 603 CompareCase case_sensitivity) {
499 return str.compare(0, search.length(), search) == 0; 604 return StartsWithT<std::string>(str, search_for, case_sensitivity);
500 } else { 605 }
606
607 bool StartsWith(StringPiece16 str,
608 StringPiece16 search_for,
609 CompareCase case_sensitivity) {
610 return StartsWithT<string16>(str, search_for, case_sensitivity);
611 }
612
613 bool StartsWith(const string16& str,
614 const string16& search,
615 bool case_sensitive) {
616 if (!case_sensitive) {
617 // This function was originally written using the current locale functions
618 // for case-insensitive comparisons. Emulate this behavior until callers
619 // can be converted either to use the case-insensitive ASCII one (most
620 // callers) or ICU functions in base_i18n.
501 if (search.size() > str.size()) 621 if (search.size() > str.size())
502 return false; 622 return false;
503 return std::equal(search.begin(), search.end(), str.begin(), 623 return std::equal(search.begin(), search.end(), str.begin(),
504 base::CaseInsensitiveCompare<typename STR::value_type>()); 624 CaseInsensitiveCompareDeprecated());
625 }
626 return StartsWith(StringPiece16(str), StringPiece16(search),
627 CompareCase::SENSITIVE);
628 }
629
630 template <typename Str>
631 bool EndsWithT(BasicStringPiece<Str> str,
632 BasicStringPiece<Str> search_for,
633 CompareCase case_sensitivity) {
634 if (search_for.size() > str.size())
635 return false;
636
637 BasicStringPiece<Str> source =
638 str.substr(str.size() - search_for.size(), search_for.size());
639
640 switch (case_sensitivity) {
641 case CompareCase::SENSITIVE:
642 return source == search_for;
643
644 case CompareCase::INSENSITIVE_ASCII:
645 return std::equal(
646 source.begin(), source.end(), search_for.begin(),
647 CaseInsensitiveCompareASCII<typename Str::value_type>());
648
649 default:
650 NOTREACHED();
651 return false;
505 } 652 }
506 } 653 }
507 654
508 bool StartsWith(const string16& str, const string16& search, 655 bool EndsWith(StringPiece str,
509 bool case_sensitive) { 656 StringPiece search_for,
510 return StartsWithT(str, search, case_sensitive); 657 CompareCase case_sensitivity) {
658 return EndsWithT<std::string>(str, search_for, case_sensitivity);
511 } 659 }
512 660
513 template <typename STR> 661 bool EndsWith(StringPiece16 str,
514 bool EndsWithT(const STR& str, const STR& search, bool case_sensitive) { 662 StringPiece16 search_for,
515 size_t str_length = str.length(); 663 CompareCase case_sensitivity) {
516 size_t search_length = search.length(); 664 return EndsWithT<string16>(str, search_for, case_sensitivity);
517 if (search_length > str_length)
518 return false;
519 if (case_sensitive)
520 return str.compare(str_length - search_length, search_length, search) == 0;
521 return std::equal(search.begin(), search.end(),
522 str.begin() + (str_length - search_length),
523 base::CaseInsensitiveCompare<typename STR::value_type>());
524 } 665 }
525 666
526 bool EndsWith(const std::string& str, const std::string& search, 667 bool EndsWith(const string16& str,
668 const string16& search,
527 bool case_sensitive) { 669 bool case_sensitive) {
528 return EndsWithT(str, search, case_sensitive); 670 if (!case_sensitive) {
671 // This function was originally written using the current locale functions
672 // for case-insensitive comparisons. Emulate this behavior until callers
673 // can be converted either to use the case-insensitive ASCII one (most
674 // callers) or ICU functions in base_i18n.
675 if (search.size() > str.size())
676 return false;
677 return std::equal(search.begin(), search.end(),
678 str.begin() + (str.size() - search.size()),
679 CaseInsensitiveCompareDeprecated());
680 }
681 return EndsWith(StringPiece16(str), StringPiece16(search),
682 CompareCase::SENSITIVE);
529 } 683 }
530 684
531 bool EndsWith(const string16& str, const string16& search, 685 char HexDigitToInt(wchar_t c) {
532 bool case_sensitive) { 686 DCHECK(IsHexDigit(c));
533 return EndsWithT(str, search, case_sensitive); 687 if (c >= '0' && c <= '9')
688 return static_cast<char>(c - '0');
689 if (c >= 'A' && c <= 'F')
690 return static_cast<char>(c - 'A' + 10);
691 if (c >= 'a' && c <= 'f')
692 return static_cast<char>(c - 'a' + 10);
693 return 0;
534 } 694 }
535 695
536 static const char* const kByteStringsUnlocalized[] = { 696 static const char* const kByteStringsUnlocalized[] = {
537 " B", 697 " B",
538 " kB", 698 " kB",
539 " MB", 699 " MB",
540 " GB", 700 " GB",
541 " TB", 701 " TB",
542 " PB" 702 " PB"
543 }; 703 };
(...skipping 10 matching lines...) Expand all
554 714
555 char buf[64]; 715 char buf[64];
556 if (bytes != 0 && dimension > 0 && unit_amount < 100) { 716 if (bytes != 0 && dimension > 0 && unit_amount < 100) {
557 base::snprintf(buf, arraysize(buf), "%.1lf%s", unit_amount, 717 base::snprintf(buf, arraysize(buf), "%.1lf%s", unit_amount,
558 kByteStringsUnlocalized[dimension]); 718 kByteStringsUnlocalized[dimension]);
559 } else { 719 } else {
560 base::snprintf(buf, arraysize(buf), "%.0lf%s", unit_amount, 720 base::snprintf(buf, arraysize(buf), "%.0lf%s", unit_amount,
561 kByteStringsUnlocalized[dimension]); 721 kByteStringsUnlocalized[dimension]);
562 } 722 }
563 723
564 return base::ASCIIToUTF16(buf); 724 return ASCIIToUTF16(buf);
565 } 725 }
566 726
567 // Runs in O(n) time in the length of |str|. 727 // Runs in O(n) time in the length of |str|.
568 template<class StringType> 728 template <class StringType>
569 void DoReplaceSubstringsAfterOffset(StringType* str, 729 void DoReplaceSubstringsAfterOffset(StringType* str,
570 size_t offset, 730 size_t offset,
571 const StringType& find_this, 731 BasicStringPiece<StringType> find_this,
572 const StringType& replace_with, 732 BasicStringPiece<StringType> replace_with,
573 bool replace_all) { 733 bool replace_all) {
574 DCHECK(!find_this.empty()); 734 DCHECK(!find_this.empty());
575 735
576 // If the find string doesn't appear, there's nothing to do. 736 // If the find string doesn't appear, there's nothing to do.
577 offset = str->find(find_this, offset); 737 offset = str->find(find_this.data(), offset, find_this.size());
578 if (offset == StringType::npos) 738 if (offset == StringType::npos)
579 return; 739 return;
580 740
581 // If we're only replacing one instance, there's no need to do anything 741 // If we're only replacing one instance, there's no need to do anything
582 // complicated. 742 // complicated.
583 size_t find_length = find_this.length(); 743 size_t find_length = find_this.length();
584 if (!replace_all) { 744 if (!replace_all) {
585 str->replace(offset, find_length, replace_with); 745 str->replace(offset, find_length, replace_with.data(), replace_with.size());
586 return; 746 return;
587 } 747 }
588 748
589 // If the find and replace strings are the same length, we can simply use 749 // If the find and replace strings are the same length, we can simply use
590 // replace() on each instance, and finish the entire operation in O(n) time. 750 // replace() on each instance, and finish the entire operation in O(n) time.
591 size_t replace_length = replace_with.length(); 751 size_t replace_length = replace_with.length();
592 if (find_length == replace_length) { 752 if (find_length == replace_length) {
593 do { 753 do {
594 str->replace(offset, find_length, replace_with); 754 str->replace(offset, find_length, replace_with.data(),
595 offset = str->find(find_this, offset + replace_length); 755 replace_with.size());
756 offset = str->find(find_this.data(), offset + replace_length,
757 find_this.size());
596 } while (offset != StringType::npos); 758 } while (offset != StringType::npos);
597 return; 759 return;
598 } 760 }
599 761
600 // Since the find and replace strings aren't the same length, a loop like the 762 // Since the find and replace strings aren't the same length, a loop like the
601 // one above would be O(n^2) in the worst case, as replace() will shift the 763 // one above would be O(n^2) in the worst case, as replace() will shift the
602 // entire remaining string each time. We need to be more clever to keep 764 // entire remaining string each time. We need to be more clever to keep
603 // things O(n). 765 // things O(n).
604 // 766 //
605 // If we're shortening the string, we can alternate replacements with shifting 767 // If we're shortening the string, we can alternate replacements with shifting
606 // forward the intervening characters using memmove(). 768 // forward the intervening characters using memmove().
607 size_t str_length = str->length(); 769 size_t str_length = str->length();
608 if (find_length > replace_length) { 770 if (find_length > replace_length) {
609 size_t write_offset = offset; 771 size_t write_offset = offset;
610 do { 772 do {
611 if (replace_length) { 773 if (replace_length) {
612 str->replace(write_offset, replace_length, replace_with); 774 str->replace(write_offset, replace_length, replace_with.data(),
775 replace_with.size());
613 write_offset += replace_length; 776 write_offset += replace_length;
614 } 777 }
615 size_t read_offset = offset + find_length; 778 size_t read_offset = offset + find_length;
616 offset = std::min(str->find(find_this, read_offset), str_length); 779 offset =
780 std::min(str->find(find_this.data(), read_offset, find_this.size()),
781 str_length);
617 size_t length = offset - read_offset; 782 size_t length = offset - read_offset;
618 if (length) { 783 if (length) {
619 memmove(&(*str)[write_offset], &(*str)[read_offset], 784 memmove(&(*str)[write_offset], &(*str)[read_offset],
620 length * sizeof(typename StringType::value_type)); 785 length * sizeof(typename StringType::value_type));
621 write_offset += length; 786 write_offset += length;
622 } 787 }
623 } while (offset < str_length); 788 } while (offset < str_length);
624 str->resize(write_offset); 789 str->resize(write_offset);
625 return; 790 return;
626 } 791 }
627 792
628 // We're lengthening the string. We can use alternating replacements and 793 // We're lengthening the string. We can use alternating replacements and
629 // memmove() calls like above, but we need to precalculate the final string 794 // memmove() calls like above, but we need to precalculate the final string
630 // length and then expand from back-to-front to avoid overwriting the string 795 // length and then expand from back-to-front to avoid overwriting the string
631 // as we're reading it, needing to shift, or having to copy to a second string 796 // as we're reading it, needing to shift, or having to copy to a second string
632 // temporarily. 797 // temporarily.
633 size_t first_match = offset; 798 size_t first_match = offset;
634 799
635 // First, calculate the final length and resize the string. 800 // First, calculate the final length and resize the string.
636 size_t final_length = str_length; 801 size_t final_length = str_length;
637 size_t expansion = replace_length - find_length; 802 size_t expansion = replace_length - find_length;
638 size_t current_match; 803 size_t current_match;
639 do { 804 do {
640 final_length += expansion; 805 final_length += expansion;
641 // Minor optimization: save this offset into |current_match|, so that on 806 // Minor optimization: save this offset into |current_match|, so that on
642 // exit from the loop, |current_match| will point at the last instance of 807 // exit from the loop, |current_match| will point at the last instance of
643 // the find string, and we won't need to find() it again immediately. 808 // the find string, and we won't need to find() it again immediately.
644 current_match = offset; 809 current_match = offset;
645 offset = str->find(find_this, offset + find_length); 810 offset =
811 str->find(find_this.data(), offset + find_length, find_this.size());
646 } while (offset != StringType::npos); 812 } while (offset != StringType::npos);
647 str->resize(final_length); 813 str->resize(final_length);
648 814
649 // Now do the replacement loop, working backwards through the string. 815 // Now do the replacement loop, working backwards through the string.
650 for (size_t prev_match = str_length, write_offset = final_length; ; 816 for (size_t prev_match = str_length, write_offset = final_length;;
651 current_match = str->rfind(find_this, current_match - 1)) { 817 current_match =
818 str->rfind(find_this.data(), current_match - 1, find_this.size())) {
652 size_t read_offset = current_match + find_length; 819 size_t read_offset = current_match + find_length;
653 size_t length = prev_match - read_offset; 820 size_t length = prev_match - read_offset;
654 if (length) { 821 if (length) {
655 write_offset -= length; 822 write_offset -= length;
656 memmove(&(*str)[write_offset], &(*str)[read_offset], 823 memmove(&(*str)[write_offset], &(*str)[read_offset],
657 length * sizeof(typename StringType::value_type)); 824 length * sizeof(typename StringType::value_type));
658 } 825 }
659 write_offset -= replace_length; 826 write_offset -= replace_length;
660 str->replace(write_offset, replace_length, replace_with); 827 str->replace(write_offset, replace_length, replace_with.data(),
828 replace_with.size());
661 if (current_match == first_match) 829 if (current_match == first_match)
662 return; 830 return;
663 prev_match = current_match; 831 prev_match = current_match;
664 } 832 }
665 } 833 }
666 834
667 void ReplaceFirstSubstringAfterOffset(string16* str, 835 void ReplaceFirstSubstringAfterOffset(string16* str,
668 size_t start_offset, 836 size_t start_offset,
669 const string16& find_this, 837 StringPiece16 find_this,
670 const string16& replace_with) { 838 StringPiece16 replace_with) {
671 DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with, 839 DoReplaceSubstringsAfterOffset<string16>(
672 false); // replace first instance 840 str, start_offset, find_this, replace_with, false); // Replace first.
673 } 841 }
674 842
675 void ReplaceFirstSubstringAfterOffset(std::string* str, 843 void ReplaceFirstSubstringAfterOffset(std::string* str,
676 size_t start_offset, 844 size_t start_offset,
677 const std::string& find_this, 845 StringPiece find_this,
678 const std::string& replace_with) { 846 StringPiece replace_with) {
679 DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with, 847 DoReplaceSubstringsAfterOffset<std::string>(
680 false); // replace first instance 848 str, start_offset, find_this, replace_with, false); // Replace first.
681 } 849 }
682 850
683 void ReplaceSubstringsAfterOffset(string16* str, 851 void ReplaceSubstringsAfterOffset(string16* str,
684 size_t start_offset, 852 size_t start_offset,
685 const string16& find_this, 853 StringPiece16 find_this,
686 const string16& replace_with) { 854 StringPiece16 replace_with) {
687 DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with, 855 DoReplaceSubstringsAfterOffset<string16>(str, start_offset, find_this,
688 true); // replace all instances 856 replace_with, true); // Replace all.
689 } 857 }
690 858
691 void ReplaceSubstringsAfterOffset(std::string* str, 859 void ReplaceSubstringsAfterOffset(std::string* str,
692 size_t start_offset, 860 size_t start_offset,
693 const std::string& find_this, 861 StringPiece find_this,
694 const std::string& replace_with) { 862 StringPiece replace_with) {
695 DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with, 863 DoReplaceSubstringsAfterOffset<std::string>(
696 true); // replace all instances 864 str, start_offset, find_this, replace_with, true); // Replace all.
697 } 865 }
698 866
699 867 template <class string_type>
700 template<typename STR> 868 inline typename string_type::value_type* WriteIntoT(string_type* str,
701 static size_t TokenizeT(const STR& str, 869 size_t length_with_null) {
702 const STR& delimiters, 870 DCHECK_GT(length_with_null, 1u);
703 std::vector<STR>* tokens) { 871 str->reserve(length_with_null);
704 tokens->clear(); 872 str->resize(length_with_null - 1);
705 873 return &((*str)[0]);
706 size_t start = str.find_first_not_of(delimiters);
707 while (start != STR::npos) {
708 size_t end = str.find_first_of(delimiters, start + 1);
709 if (end == STR::npos) {
710 tokens->push_back(str.substr(start));
711 break;
712 } else {
713 tokens->push_back(str.substr(start, end - start));
714 start = str.find_first_not_of(delimiters, end + 1);
715 }
716 }
717
718 return tokens->size();
719 } 874 }
720 875
721 size_t Tokenize(const string16& str, 876 char* WriteInto(std::string* str, size_t length_with_null) {
722 const string16& delimiters, 877 return WriteIntoT(str, length_with_null);
723 std::vector<string16>* tokens) {
724 return TokenizeT(str, delimiters, tokens);
725 } 878 }
726 879
727 size_t Tokenize(const std::string& str, 880 char16* WriteInto(string16* str, size_t length_with_null) {
728 const std::string& delimiters, 881 return WriteIntoT(str, length_with_null);
729 std::vector<std::string>* tokens) {
730 return TokenizeT(str, delimiters, tokens);
731 } 882 }
732 883
733 size_t Tokenize(const base::StringPiece& str, 884 template <typename STR>
734 const base::StringPiece& delimiters, 885 static STR JoinStringT(const std::vector<STR>& parts,
735 std::vector<base::StringPiece>* tokens) { 886 BasicStringPiece<STR> sep) {
736 return TokenizeT(str, delimiters, tokens);
737 }
738
739 template<typename STR>
740 static STR JoinStringT(const std::vector<STR>& parts, const STR& sep) {
741 if (parts.empty()) 887 if (parts.empty())
742 return STR(); 888 return STR();
743 889
744 STR result(parts[0]); 890 STR result(parts[0]);
745 typename std::vector<STR>::const_iterator iter = parts.begin(); 891 auto iter = parts.begin();
746 ++iter; 892 ++iter;
747 893
748 for (; iter != parts.end(); ++iter) { 894 for (; iter != parts.end(); ++iter) {
749 result += sep; 895 sep.AppendToString(&result);
750 result += *iter; 896 result += *iter;
751 } 897 }
752 898
753 return result; 899 return result;
754 } 900 }
755 901
756 std::string JoinString(const std::vector<std::string>& parts, char sep) {
757 return JoinStringT(parts, std::string(1, sep));
758 }
759
760 string16 JoinString(const std::vector<string16>& parts, char16 sep) {
761 return JoinStringT(parts, string16(1, sep));
762 }
763
764 std::string JoinString(const std::vector<std::string>& parts, 902 std::string JoinString(const std::vector<std::string>& parts,
765 const std::string& separator) { 903 StringPiece separator) {
766 return JoinStringT(parts, separator); 904 return JoinStringT(parts, separator);
767 } 905 }
768 906
769 string16 JoinString(const std::vector<string16>& parts, 907 string16 JoinString(const std::vector<string16>& parts,
770 const string16& separator) { 908 StringPiece16 separator) {
771 return JoinStringT(parts, separator); 909 return JoinStringT(parts, separator);
772 } 910 }
773 911
774 template<class FormatStringType, class OutStringType> 912 template <class FormatStringType, class OutStringType>
775 OutStringType DoReplaceStringPlaceholders(const FormatStringType& format_string, 913 OutStringType DoReplaceStringPlaceholders(
776 const std::vector<OutStringType>& subst, std::vector<size_t>* offsets) { 914 const FormatStringType& format_string,
915 const std::vector<OutStringType>& subst,
916 std::vector<size_t>* offsets) {
777 size_t substitutions = subst.size(); 917 size_t substitutions = subst.size();
778 918
779 size_t sub_length = 0; 919 size_t sub_length = 0;
780 for (typename std::vector<OutStringType>::const_iterator iter = subst.begin(); 920 for (const auto& cur : subst)
781 iter != subst.end(); ++iter) { 921 sub_length += cur.length();
782 sub_length += iter->length();
783 }
784 922
785 OutStringType formatted; 923 OutStringType formatted;
786 formatted.reserve(format_string.length() + sub_length); 924 formatted.reserve(format_string.length() + sub_length);
787 925
788 std::vector<ReplacementOffset> r_offsets; 926 std::vector<ReplacementOffset> r_offsets;
789 for (typename FormatStringType::const_iterator i = format_string.begin(); 927 for (auto i = format_string.begin(); i != format_string.end(); ++i) {
790 i != format_string.end(); ++i) {
791 if ('$' == *i) { 928 if ('$' == *i) {
792 if (i + 1 != format_string.end()) { 929 if (i + 1 != format_string.end()) {
793 ++i; 930 ++i;
794 DCHECK('$' == *i || '1' <= *i) << "Invalid placeholder: " << *i; 931 DCHECK('$' == *i || '1' <= *i) << "Invalid placeholder: " << *i;
795 if ('$' == *i) { 932 if ('$' == *i) {
796 while (i != format_string.end() && '$' == *i) { 933 while (i != format_string.end() && '$' == *i) {
797 formatted.push_back('$'); 934 formatted.push_back('$');
798 ++i; 935 ++i;
799 } 936 }
800 --i; 937 --i;
(...skipping 17 matching lines...) Expand all
818 } 955 }
819 if (index < substitutions) 956 if (index < substitutions)
820 formatted.append(subst.at(index)); 957 formatted.append(subst.at(index));
821 } 958 }
822 } 959 }
823 } else { 960 } else {
824 formatted.push_back(*i); 961 formatted.push_back(*i);
825 } 962 }
826 } 963 }
827 if (offsets) { 964 if (offsets) {
828 for (std::vector<ReplacementOffset>::const_iterator i = r_offsets.begin(); 965 for (const auto& cur : r_offsets)
829 i != r_offsets.end(); ++i) { 966 offsets->push_back(cur.offset);
830 offsets->push_back(i->offset);
831 }
832 } 967 }
833 return formatted; 968 return formatted;
834 } 969 }
835 970
836 string16 ReplaceStringPlaceholders(const string16& format_string, 971 string16 ReplaceStringPlaceholders(const string16& format_string,
837 const std::vector<string16>& subst, 972 const std::vector<string16>& subst,
838 std::vector<size_t>* offsets) { 973 std::vector<size_t>* offsets) {
839 return DoReplaceStringPlaceholders(format_string, subst, offsets); 974 return DoReplaceStringPlaceholders(format_string, subst, offsets);
840 } 975 }
841 976
842 std::string ReplaceStringPlaceholders(const base::StringPiece& format_string, 977 std::string ReplaceStringPlaceholders(const StringPiece& format_string,
843 const std::vector<std::string>& subst, 978 const std::vector<std::string>& subst,
844 std::vector<size_t>* offsets) { 979 std::vector<size_t>* offsets) {
845 return DoReplaceStringPlaceholders(format_string, subst, offsets); 980 return DoReplaceStringPlaceholders(format_string, subst, offsets);
846 } 981 }
847 982
848 string16 ReplaceStringPlaceholders(const string16& format_string, 983 string16 ReplaceStringPlaceholders(const string16& format_string,
849 const string16& a, 984 const string16& a,
850 size_t* offset) { 985 size_t* offset) {
851 std::vector<size_t> offsets; 986 std::vector<size_t> offsets;
852 std::vector<string16> subst; 987 std::vector<string16> subst;
853 subst.push_back(a); 988 subst.push_back(a);
854 string16 result = ReplaceStringPlaceholders(format_string, subst, &offsets); 989 string16 result = ReplaceStringPlaceholders(format_string, subst, &offsets);
855 990
856 DCHECK_EQ(1U, offsets.size()); 991 DCHECK_EQ(1U, offsets.size());
857 if (offset) 992 if (offset)
858 *offset = offsets[0]; 993 *offset = offsets[0];
859 return result; 994 return result;
860 } 995 }
861 996
862 static bool IsWildcard(base_icu::UChar32 character) {
863 return character == '*' || character == '?';
864 }
865
866 // Move the strings pointers to the point where they start to differ.
867 template <typename CHAR, typename NEXT>
868 static void EatSameChars(const CHAR** pattern, const CHAR* pattern_end,
869 const CHAR** string, const CHAR* string_end,
870 NEXT next) {
871 const CHAR* escape = NULL;
872 while (*pattern != pattern_end && *string != string_end) {
873 if (!escape && IsWildcard(**pattern)) {
874 // We don't want to match wildcard here, except if it's escaped.
875 return;
876 }
877
878 // Check if the escapement char is found. If so, skip it and move to the
879 // next character.
880 if (!escape && **pattern == '\\') {
881 escape = *pattern;
882 next(pattern, pattern_end);
883 continue;
884 }
885
886 // Check if the chars match, if so, increment the ptrs.
887 const CHAR* pattern_next = *pattern;
888 const CHAR* string_next = *string;
889 base_icu::UChar32 pattern_char = next(&pattern_next, pattern_end);
890 if (pattern_char == next(&string_next, string_end) &&
891 pattern_char != CBU_SENTINEL) {
892 *pattern = pattern_next;
893 *string = string_next;
894 } else {
895 // Uh oh, it did not match, we are done. If the last char was an
896 // escapement, that means that it was an error to advance the ptr here,
897 // let's put it back where it was. This also mean that the MatchPattern
898 // function will return false because if we can't match an escape char
899 // here, then no one will.
900 if (escape) {
901 *pattern = escape;
902 }
903 return;
904 }
905
906 escape = NULL;
907 }
908 }
909
910 template <typename CHAR, typename NEXT>
911 static void EatWildcard(const CHAR** pattern, const CHAR* end, NEXT next) {
912 while (*pattern != end) {
913 if (!IsWildcard(**pattern))
914 return;
915 next(pattern, end);
916 }
917 }
918
919 template <typename CHAR, typename NEXT>
920 static bool MatchPatternT(const CHAR* eval, const CHAR* eval_end,
921 const CHAR* pattern, const CHAR* pattern_end,
922 int depth,
923 NEXT next) {
924 const int kMaxDepth = 16;
925 if (depth > kMaxDepth)
926 return false;
927
928 // Eat all the matching chars.
929 EatSameChars(&pattern, pattern_end, &eval, eval_end, next);
930
931 // If the string is empty, then the pattern must be empty too, or contains
932 // only wildcards.
933 if (eval == eval_end) {
934 EatWildcard(&pattern, pattern_end, next);
935 return pattern == pattern_end;
936 }
937
938 // Pattern is empty but not string, this is not a match.
939 if (pattern == pattern_end)
940 return false;
941
942 // If this is a question mark, then we need to compare the rest with
943 // the current string or the string with one character eaten.
944 const CHAR* next_pattern = pattern;
945 next(&next_pattern, pattern_end);
946 if (pattern[0] == '?') {
947 if (MatchPatternT(eval, eval_end, next_pattern, pattern_end,
948 depth + 1, next))
949 return true;
950 const CHAR* next_eval = eval;
951 next(&next_eval, eval_end);
952 if (MatchPatternT(next_eval, eval_end, next_pattern, pattern_end,
953 depth + 1, next))
954 return true;
955 }
956
957 // This is a *, try to match all the possible substrings with the remainder
958 // of the pattern.
959 if (pattern[0] == '*') {
960 // Collapse duplicate wild cards (********** into *) so that the
961 // method does not recurse unnecessarily. http://crbug.com/52839
962 EatWildcard(&next_pattern, pattern_end, next);
963
964 while (eval != eval_end) {
965 if (MatchPatternT(eval, eval_end, next_pattern, pattern_end,
966 depth + 1, next))
967 return true;
968 eval++;
969 }
970
971 // We reached the end of the string, let see if the pattern contains only
972 // wildcards.
973 if (eval == eval_end) {
974 EatWildcard(&pattern, pattern_end, next);
975 if (pattern != pattern_end)
976 return false;
977 return true;
978 }
979 }
980
981 return false;
982 }
983
984 struct NextCharUTF8 {
985 base_icu::UChar32 operator()(const char** p, const char* end) {
986 base_icu::UChar32 c;
987 int offset = 0;
988 CBU8_NEXT(*p, offset, end - *p, c);
989 *p += offset;
990 return c;
991 }
992 };
993
994 struct NextCharUTF16 {
995 base_icu::UChar32 operator()(const char16** p, const char16* end) {
996 base_icu::UChar32 c;
997 int offset = 0;
998 CBU16_NEXT(*p, offset, end - *p, c);
999 *p += offset;
1000 return c;
1001 }
1002 };
1003
1004 bool MatchPattern(const base::StringPiece& eval,
1005 const base::StringPiece& pattern) {
1006 return MatchPatternT(eval.data(), eval.data() + eval.size(),
1007 pattern.data(), pattern.data() + pattern.size(),
1008 0, NextCharUTF8());
1009 }
1010
1011 bool MatchPattern(const string16& eval, const string16& pattern) {
1012 return MatchPatternT(eval.c_str(), eval.c_str() + eval.size(),
1013 pattern.c_str(), pattern.c_str() + pattern.size(),
1014 0, NextCharUTF16());
1015 }
1016
1017 // The following code is compatible with the OpenBSD lcpy interface. See: 997 // The following code is compatible with the OpenBSD lcpy interface. See:
1018 // http://www.gratisoft.us/todd/papers/strlcpy.html 998 // http://www.gratisoft.us/todd/papers/strlcpy.html
1019 // ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/{wcs,str}lcpy.c 999 // ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/{wcs,str}lcpy.c
1020 1000
1021 namespace { 1001 namespace {
1022 1002
1023 template <typename CHAR> 1003 template <typename CHAR>
1024 size_t lcpyT(CHAR* dst, const CHAR* src, size_t dst_size) { 1004 size_t lcpyT(CHAR* dst, const CHAR* src, size_t dst_size) {
1025 for (size_t i = 0; i < dst_size; ++i) { 1005 for (size_t i = 0; i < dst_size; ++i) {
1026 if ((dst[i] = src[i]) == 0) // We hit and copied the terminating NULL. 1006 if ((dst[i] = src[i]) == 0) // We hit and copied the terminating NULL.
1027 return i; 1007 return i;
1028 } 1008 }
1029 1009
1030 // We were left off at dst_size. We over copied 1 byte. Null terminate. 1010 // We were left off at dst_size. We over copied 1 byte. Null terminate.
1031 if (dst_size != 0) 1011 if (dst_size != 0)
1032 dst[dst_size - 1] = 0; 1012 dst[dst_size - 1] = 0;
1033 1013
1034 // Count the rest of the |src|, and return it's length in characters. 1014 // Count the rest of the |src|, and return it's length in characters.
1035 while (src[dst_size]) ++dst_size; 1015 while (src[dst_size]) ++dst_size;
1036 return dst_size; 1016 return dst_size;
1037 } 1017 }
1038 1018
1039 } // namespace 1019 } // namespace
1040 1020
1041 size_t base::strlcpy(char* dst, const char* src, size_t dst_size) { 1021 size_t strlcpy(char* dst, const char* src, size_t dst_size) {
1042 return lcpyT<char>(dst, src, dst_size); 1022 return lcpyT<char>(dst, src, dst_size);
1043 } 1023 }
1044 size_t base::wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) { 1024 size_t wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) {
1045 return lcpyT<wchar_t>(dst, src, dst_size); 1025 return lcpyT<wchar_t>(dst, src, dst_size);
1046 } 1026 }
1027
1028 } // namespace base
OLDNEW
« no previous file with comments | « base/strings/string_util.h ('k') | base/strings/string_util_constants.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698