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

Side by Side Diff: base/files/file_path.cc

Issue 1182453004: Write new Starts/EndsWith and convert FilePath functions to StringPiece. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@string_util
Patch Set: default back Created 5 years, 6 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/files/file_path.h" 5 #include "base/files/file_path.h"
6 6
7 #include <string.h> 7 #include <string.h>
8 #include <algorithm> 8 #include <algorithm>
9 9
10 #include "base/basictypes.h" 10 #include "base/basictypes.h"
(...skipping 13 matching lines...) Expand all
24 #endif 24 #endif
25 25
26 #if defined(OS_WIN) 26 #if defined(OS_WIN)
27 #include <windows.h> 27 #include <windows.h>
28 #elif defined(OS_MACOSX) 28 #elif defined(OS_MACOSX)
29 #include <CoreFoundation/CoreFoundation.h> 29 #include <CoreFoundation/CoreFoundation.h>
30 #endif 30 #endif
31 31
32 namespace base { 32 namespace base {
33 33
34 typedef FilePath::StringType StringType; 34 using StringType = FilePath::StringType;
35 using StringPieceType = FilePath::StringPieceType;
35 36
36 namespace { 37 namespace {
37 38
38 const char* const kCommonDoubleExtensionSuffixes[] = { "gz", "z", "bz2", "bz" }; 39 const char* const kCommonDoubleExtensionSuffixes[] = { "gz", "z", "bz2", "bz" };
39 const char* const kCommonDoubleExtensions[] = { "user.js" }; 40 const char* const kCommonDoubleExtensions[] = { "user.js" };
40 41
41 const FilePath::CharType kStringTerminator = FILE_PATH_LITERAL('\0'); 42 const FilePath::CharType kStringTerminator = FILE_PATH_LITERAL('\0');
42 43
43 // If this FilePath contains a drive letter specification, returns the 44 // If this FilePath contains a drive letter specification, returns the
44 // position of the last character of the drive letter specification, 45 // position of the last character of the drive letter specification,
45 // otherwise returns npos. This can only be true on Windows, when a pathname 46 // otherwise returns npos. This can only be true on Windows, when a pathname
46 // begins with a letter followed by a colon. On other platforms, this always 47 // begins with a letter followed by a colon. On other platforms, this always
47 // returns npos. 48 // returns npos.
48 StringType::size_type FindDriveLetter(const StringType& path) { 49 StringPieceType::size_type FindDriveLetter(StringPieceType path) {
49 #if defined(FILE_PATH_USES_DRIVE_LETTERS) 50 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
50 // This is dependent on an ASCII-based character set, but that's a 51 // This is dependent on an ASCII-based character set, but that's a
51 // reasonable assumption. iswalpha can be too inclusive here. 52 // reasonable assumption. iswalpha can be too inclusive here.
52 if (path.length() >= 2 && path[1] == L':' && 53 if (path.length() >= 2 && path[1] == L':' &&
53 ((path[0] >= L'A' && path[0] <= L'Z') || 54 ((path[0] >= L'A' && path[0] <= L'Z') ||
54 (path[0] >= L'a' && path[0] <= L'z'))) { 55 (path[0] >= L'a' && path[0] <= L'z'))) {
55 return 1; 56 return 1;
56 } 57 }
57 #endif // FILE_PATH_USES_DRIVE_LETTERS 58 #endif // FILE_PATH_USES_DRIVE_LETTERS
58 return StringType::npos; 59 return StringType::npos;
59 } 60 }
60 61
61 #if defined(FILE_PATH_USES_DRIVE_LETTERS) 62 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
62 bool EqualDriveLetterCaseInsensitive(const StringType& a, 63 bool EqualDriveLetterCaseInsensitive(StringPieceType a, StringPieceType b) {
63 const StringType& b) {
64 size_t a_letter_pos = FindDriveLetter(a); 64 size_t a_letter_pos = FindDriveLetter(a);
65 size_t b_letter_pos = FindDriveLetter(b); 65 size_t b_letter_pos = FindDriveLetter(b);
66 66
67 if (a_letter_pos == StringType::npos || b_letter_pos == StringType::npos) 67 if (a_letter_pos == StringType::npos || b_letter_pos == StringType::npos)
68 return a == b; 68 return a == b;
69 69
70 StringType a_letter(a.substr(0, a_letter_pos + 1)); 70 StringPieceType a_letter(a.substr(0, a_letter_pos + 1));
71 StringType b_letter(b.substr(0, b_letter_pos + 1)); 71 StringPieceType b_letter(b.substr(0, b_letter_pos + 1));
72 if (!StartsWith(a_letter, b_letter, false)) 72 if (!StartsWith(a_letter, b_letter, CompareCase::INSENSITIVE_ASCII))
73 return false; 73 return false;
74 74
75 StringType a_rest(a.substr(a_letter_pos + 1)); 75 StringPieceType a_rest(a.substr(a_letter_pos + 1));
76 StringType b_rest(b.substr(b_letter_pos + 1)); 76 StringPieceType b_rest(b.substr(b_letter_pos + 1));
77 return a_rest == b_rest; 77 return a_rest == b_rest;
78 } 78 }
79 #endif // defined(FILE_PATH_USES_DRIVE_LETTERS) 79 #endif // defined(FILE_PATH_USES_DRIVE_LETTERS)
80 80
81 bool IsPathAbsolute(const StringType& path) { 81 bool IsPathAbsolute(StringPieceType path) {
82 #if defined(FILE_PATH_USES_DRIVE_LETTERS) 82 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
83 StringType::size_type letter = FindDriveLetter(path); 83 StringType::size_type letter = FindDriveLetter(path);
84 if (letter != StringType::npos) { 84 if (letter != StringType::npos) {
85 // Look for a separator right after the drive specification. 85 // Look for a separator right after the drive specification.
86 return path.length() > letter + 1 && 86 return path.length() > letter + 1 &&
87 FilePath::IsSeparator(path[letter + 1]); 87 FilePath::IsSeparator(path[letter + 1]);
88 } 88 }
89 // Look for a pair of leading separators. 89 // Look for a pair of leading separators.
90 return path.length() > 1 && 90 return path.length() > 1 &&
91 FilePath::IsSeparator(path[0]) && FilePath::IsSeparator(path[1]); 91 FilePath::IsSeparator(path[0]) && FilePath::IsSeparator(path[1]);
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
170 } 170 }
171 171
172 } // namespace 172 } // namespace
173 173
174 FilePath::FilePath() { 174 FilePath::FilePath() {
175 } 175 }
176 176
177 FilePath::FilePath(const FilePath& that) : path_(that.path_) { 177 FilePath::FilePath(const FilePath& that) : path_(that.path_) {
178 } 178 }
179 179
180 FilePath::FilePath(const StringType& path) : path_(path) { 180 FilePath::FilePath(StringPieceType path) {
181 path.CopyToString(&path_);
181 StringType::size_type nul_pos = path_.find(kStringTerminator); 182 StringType::size_type nul_pos = path_.find(kStringTerminator);
182 if (nul_pos != StringType::npos) 183 if (nul_pos != StringType::npos)
183 path_.erase(nul_pos, StringType::npos); 184 path_.erase(nul_pos, StringType::npos);
184 } 185 }
185 186
186 FilePath::~FilePath() { 187 FilePath::~FilePath() {
187 } 188 }
188 189
189 FilePath& FilePath::operator=(const FilePath& that) { 190 FilePath& FilePath::operator=(const FilePath& that) {
190 path_ = that.path_; 191 path_ = that.path_;
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
272 parent_components.begin(); 273 parent_components.begin();
273 std::vector<StringType>::const_iterator child_comp = 274 std::vector<StringType>::const_iterator child_comp =
274 child_components.begin(); 275 child_components.begin();
275 276
276 #if defined(FILE_PATH_USES_DRIVE_LETTERS) 277 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
277 // Windows can access case sensitive filesystems, so component 278 // Windows can access case sensitive filesystems, so component
278 // comparisions must be case sensitive, but drive letters are 279 // comparisions must be case sensitive, but drive letters are
279 // never case sensitive. 280 // never case sensitive.
280 if ((FindDriveLetter(*parent_comp) != StringType::npos) && 281 if ((FindDriveLetter(*parent_comp) != StringType::npos) &&
281 (FindDriveLetter(*child_comp) != StringType::npos)) { 282 (FindDriveLetter(*child_comp) != StringType::npos)) {
282 if (!StartsWith(*parent_comp, *child_comp, false)) 283 if (!StartsWith(*parent_comp, *child_comp, CompareCase::INSENSITIVE_ASCII))
283 return false; 284 return false;
284 ++parent_comp; 285 ++parent_comp;
285 ++child_comp; 286 ++child_comp;
286 } 287 }
287 #endif // defined(FILE_PATH_USES_DRIVE_LETTERS) 288 #endif // defined(FILE_PATH_USES_DRIVE_LETTERS)
288 289
289 while (parent_comp != parent_components.end()) { 290 while (parent_comp != parent_components.end()) {
290 if (*parent_comp != *child_comp) 291 if (*parent_comp != *child_comp)
291 return false; 292 return false;
292 ++parent_comp; 293 ++parent_comp;
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
397 if (FinalExtension().empty()) 398 if (FinalExtension().empty())
398 return *this; 399 return *this;
399 400
400 const StringType::size_type dot = FinalExtensionSeparatorPosition(path_); 401 const StringType::size_type dot = FinalExtensionSeparatorPosition(path_);
401 if (dot == StringType::npos) 402 if (dot == StringType::npos)
402 return *this; 403 return *this;
403 404
404 return FilePath(path_.substr(0, dot)); 405 return FilePath(path_.substr(0, dot));
405 } 406 }
406 407
407 FilePath FilePath::InsertBeforeExtension(const StringType& suffix) const { 408 FilePath FilePath::InsertBeforeExtension(StringPieceType suffix) const {
408 if (suffix.empty()) 409 if (suffix.empty())
409 return FilePath(path_); 410 return FilePath(path_);
410 411
411 if (IsEmptyOrSpecialCase(BaseName().value())) 412 if (IsEmptyOrSpecialCase(BaseName().value()))
412 return FilePath(); 413 return FilePath();
413 414
414 StringType ext = Extension(); 415 StringType ext = Extension();
415 StringType ret = RemoveExtension().value(); 416 StringType ret = RemoveExtension().value();
416 ret.append(suffix); 417 suffix.AppendToString(&ret);
417 ret.append(ext); 418 ret.append(ext);
418 return FilePath(ret); 419 return FilePath(ret);
419 } 420 }
420 421
421 FilePath FilePath::InsertBeforeExtensionASCII(const StringPiece& suffix) 422 FilePath FilePath::InsertBeforeExtensionASCII(StringPiece suffix)
422 const { 423 const {
423 DCHECK(IsStringASCII(suffix)); 424 DCHECK(IsStringASCII(suffix));
424 #if defined(OS_WIN) 425 #if defined(OS_WIN)
425 return InsertBeforeExtension(ASCIIToUTF16(suffix.as_string())); 426 return InsertBeforeExtension(ASCIIToUTF16(suffix));
426 #elif defined(OS_POSIX) 427 #elif defined(OS_POSIX)
427 return InsertBeforeExtension(suffix.as_string()); 428 return InsertBeforeExtension(suffix);
428 #endif 429 #endif
429 } 430 }
430 431
431 FilePath FilePath::AddExtension(const StringType& extension) const { 432 FilePath FilePath::AddExtension(StringPieceType extension) const {
432 if (IsEmptyOrSpecialCase(BaseName().value())) 433 if (IsEmptyOrSpecialCase(BaseName().value()))
433 return FilePath(); 434 return FilePath();
434 435
435 // If the new extension is "" or ".", then just return the current FilePath. 436 // If the new extension is "" or ".", then just return the current FilePath.
436 if (extension.empty() || extension == StringType(1, kExtensionSeparator)) 437 if (extension.empty() ||
438 (extension.size() == 1 && extension[0] == kExtensionSeparator))
437 return *this; 439 return *this;
438 440
439 StringType str = path_; 441 StringType str = path_;
440 if (extension[0] != kExtensionSeparator && 442 if (extension[0] != kExtensionSeparator &&
441 *(str.end() - 1) != kExtensionSeparator) { 443 *(str.end() - 1) != kExtensionSeparator) {
442 str.append(1, kExtensionSeparator); 444 str.append(1, kExtensionSeparator);
443 } 445 }
444 str.append(extension); 446 extension.AppendToString(&str);
445 return FilePath(str); 447 return FilePath(str);
446 } 448 }
447 449
448 FilePath FilePath::ReplaceExtension(const StringType& extension) const { 450 FilePath FilePath::ReplaceExtension(StringPieceType extension) const {
449 if (IsEmptyOrSpecialCase(BaseName().value())) 451 if (IsEmptyOrSpecialCase(BaseName().value()))
450 return FilePath(); 452 return FilePath();
451 453
452 FilePath no_ext = RemoveExtension(); 454 FilePath no_ext = RemoveExtension();
453 // If the new extension is "" or ".", then just remove the current extension. 455 // If the new extension is "" or ".", then just remove the current extension.
454 if (extension.empty() || extension == StringType(1, kExtensionSeparator)) 456 if (extension.empty() ||
457 (extension.size() == 1 && extension[0] == kExtensionSeparator))
455 return no_ext; 458 return no_ext;
456 459
457 StringType str = no_ext.value(); 460 StringType str = no_ext.value();
458 if (extension[0] != kExtensionSeparator) 461 if (extension[0] != kExtensionSeparator)
459 str.append(1, kExtensionSeparator); 462 str.append(1, kExtensionSeparator);
460 str.append(extension); 463 extension.AppendToString(&str);
461 return FilePath(str); 464 return FilePath(str);
462 } 465 }
463 466
464 bool FilePath::MatchesExtension(const StringType& extension) const { 467 bool FilePath::MatchesExtension(StringPieceType extension) const {
465 DCHECK(extension.empty() || extension[0] == kExtensionSeparator); 468 DCHECK(extension.empty() || extension[0] == kExtensionSeparator);
466 469
467 StringType current_extension = Extension(); 470 StringType current_extension = Extension();
468 471
469 if (current_extension.length() != extension.length()) 472 if (current_extension.length() != extension.length())
470 return false; 473 return false;
471 474
472 return FilePath::CompareEqualIgnoreCase(extension, current_extension); 475 return FilePath::CompareEqualIgnoreCase(extension, current_extension);
473 } 476 }
474 477
475 FilePath FilePath::Append(const StringType& component) const { 478 FilePath FilePath::Append(StringPieceType component) const {
476 const StringType* appended = &component; 479 StringPieceType appended = component;
477 StringType without_nuls; 480 StringType without_nuls;
478 481
479 StringType::size_type nul_pos = component.find(kStringTerminator); 482 StringType::size_type nul_pos = component.find(kStringTerminator);
480 if (nul_pos != StringType::npos) { 483 if (nul_pos != StringPieceType::npos) {
481 without_nuls = component.substr(0, nul_pos); 484 component.substr(0, nul_pos).CopyToString(&without_nuls);
482 appended = &without_nuls; 485 appended = StringPieceType(without_nuls);
483 } 486 }
484 487
485 DCHECK(!IsPathAbsolute(*appended)); 488 DCHECK(!IsPathAbsolute(appended));
486 489
487 if (path_.compare(kCurrentDirectory) == 0) { 490 if (path_.compare(kCurrentDirectory) == 0) {
488 // Append normally doesn't do any normalization, but as a special case, 491 // Append normally doesn't do any normalization, but as a special case,
489 // when appending to kCurrentDirectory, just return a new path for the 492 // when appending to kCurrentDirectory, just return a new path for the
490 // component argument. Appending component to kCurrentDirectory would 493 // component argument. Appending component to kCurrentDirectory would
491 // serve no purpose other than needlessly lengthening the path, and 494 // serve no purpose other than needlessly lengthening the path, and
492 // it's likely in practice to wind up with FilePath objects containing 495 // it's likely in practice to wind up with FilePath objects containing
493 // only kCurrentDirectory when calling DirName on a single relative path 496 // only kCurrentDirectory when calling DirName on a single relative path
494 // component. 497 // component.
495 return FilePath(*appended); 498 return FilePath(appended);
496 } 499 }
497 500
498 FilePath new_path(path_); 501 FilePath new_path(path_);
499 new_path.StripTrailingSeparatorsInternal(); 502 new_path.StripTrailingSeparatorsInternal();
500 503
501 // Don't append a separator if the path is empty (indicating the current 504 // Don't append a separator if the path is empty (indicating the current
502 // directory) or if the path component is empty (indicating nothing to 505 // directory) or if the path component is empty (indicating nothing to
503 // append). 506 // append).
504 if (appended->length() > 0 && new_path.path_.length() > 0) { 507 if (appended.length() > 0 && new_path.path_.length() > 0) {
505 // Don't append a separator if the path still ends with a trailing 508 // Don't append a separator if the path still ends with a trailing
506 // separator after stripping (indicating the root directory). 509 // separator after stripping (indicating the root directory).
507 if (!IsSeparator(new_path.path_[new_path.path_.length() - 1])) { 510 if (!IsSeparator(new_path.path_[new_path.path_.length() - 1])) {
508 // Don't append a separator if the path is just a drive letter. 511 // Don't append a separator if the path is just a drive letter.
509 if (FindDriveLetter(new_path.path_) + 1 != new_path.path_.length()) { 512 if (FindDriveLetter(new_path.path_) + 1 != new_path.path_.length()) {
510 new_path.path_.append(1, kSeparators[0]); 513 new_path.path_.append(1, kSeparators[0]);
511 } 514 }
512 } 515 }
513 } 516 }
514 517
515 new_path.path_.append(*appended); 518 appended.AppendToString(&new_path.path_);
516 return new_path; 519 return new_path;
517 } 520 }
518 521
519 FilePath FilePath::Append(const FilePath& component) const { 522 FilePath FilePath::Append(const FilePath& component) const {
520 return Append(component.value()); 523 return Append(component.value());
521 } 524 }
522 525
523 FilePath FilePath::AppendASCII(const StringPiece& component) const { 526 FilePath FilePath::AppendASCII(StringPiece component) const {
524 DCHECK(base::IsStringASCII(component)); 527 DCHECK(base::IsStringASCII(component));
525 #if defined(OS_WIN) 528 #if defined(OS_WIN)
526 return Append(ASCIIToUTF16(component.as_string())); 529 return Append(ASCIIToUTF16(component));
527 #elif defined(OS_POSIX) 530 #elif defined(OS_POSIX)
528 return Append(component.as_string()); 531 return Append(component);
529 #endif 532 #endif
530 } 533 }
531 534
532 bool FilePath::IsAbsolute() const { 535 bool FilePath::IsAbsolute() const {
533 return IsPathAbsolute(path_); 536 return IsPathAbsolute(path_);
534 } 537 }
535 538
536 bool FilePath::EndsWithSeparator() const { 539 bool FilePath::EndsWithSeparator() const {
537 if (empty()) 540 if (empty())
538 return false; 541 return false;
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
673 return false; 676 return false;
674 #endif 677 #endif
675 678
676 if (path_.find(kStringTerminator) != StringType::npos) 679 if (path_.find(kStringTerminator) != StringType::npos)
677 return false; 680 return false;
678 681
679 return true; 682 return true;
680 } 683 }
681 684
682 #if defined(OS_WIN) 685 #if defined(OS_WIN)
683 // Windows specific implementation of file string comparisons 686 // Windows specific implementation of file string comparisons.
684 687
685 int FilePath::CompareIgnoreCase(const StringType& string1, 688 int FilePath::CompareIgnoreCase(StringPieceType string1,
686 const StringType& string2) { 689 StringPieceType string2) {
687 // Perform character-wise upper case comparison rather than using the 690 // Perform character-wise upper case comparison rather than using the
688 // fully Unicode-aware CompareString(). For details see: 691 // fully Unicode-aware CompareString(). For details see:
689 // http://blogs.msdn.com/michkap/archive/2005/10/17/481600.aspx 692 // http://blogs.msdn.com/michkap/archive/2005/10/17/481600.aspx
690 StringType::const_iterator i1 = string1.begin(); 693 StringPieceType::const_iterator i1 = string1.begin();
691 StringType::const_iterator i2 = string2.begin(); 694 StringPieceType::const_iterator i2 = string2.begin();
692 StringType::const_iterator string1end = string1.end(); 695 StringPieceType::const_iterator string1end = string1.end();
693 StringType::const_iterator string2end = string2.end(); 696 StringPieceType::const_iterator string2end = string2.end();
694 for ( ; i1 != string1end && i2 != string2end; ++i1, ++i2) { 697 for ( ; i1 != string1end && i2 != string2end; ++i1, ++i2) {
695 wchar_t c1 = 698 wchar_t c1 =
696 (wchar_t)LOWORD(::CharUpperW((LPWSTR)(DWORD_PTR)MAKELONG(*i1, 0))); 699 (wchar_t)LOWORD(::CharUpperW((LPWSTR)(DWORD_PTR)MAKELONG(*i1, 0)));
697 wchar_t c2 = 700 wchar_t c2 =
698 (wchar_t)LOWORD(::CharUpperW((LPWSTR)(DWORD_PTR)MAKELONG(*i2, 0))); 701 (wchar_t)LOWORD(::CharUpperW((LPWSTR)(DWORD_PTR)MAKELONG(*i2, 0)));
699 if (c1 < c2) 702 if (c1 < c2)
700 return -1; 703 return -1;
701 if (c1 > c2) 704 if (c1 > c2)
702 return 1; 705 return 1;
703 } 706 }
704 if (i1 != string1end) 707 if (i1 != string1end)
705 return 1; 708 return 1;
706 if (i2 != string2end) 709 if (i2 != string2end)
707 return -1; 710 return -1;
708 return 0; 711 return 0;
709 } 712 }
710 713
711 #elif defined(OS_MACOSX) 714 #elif defined(OS_MACOSX)
712 // Mac OS X specific implementation of file string comparisons 715 // Mac OS X specific implementation of file string comparisons.
713 716
714 // cf. http://developer.apple.com/mac/library/technotes/tn/tn1150.html#UnicodeSu btleties 717 // cf. http://developer.apple.com/mac/library/technotes/tn/tn1150.html#UnicodeSu btleties
715 // 718 //
716 // "When using CreateTextEncoding to create a text encoding, you should set 719 // "When using CreateTextEncoding to create a text encoding, you should set
717 // the TextEncodingBase to kTextEncodingUnicodeV2_0, set the 720 // the TextEncodingBase to kTextEncodingUnicodeV2_0, set the
718 // TextEncodingVariant to kUnicodeCanonicalDecompVariant, and set the 721 // TextEncodingVariant to kUnicodeCanonicalDecompVariant, and set the
719 // TextEncodingFormat to kUnicode16BitFormat. Using these values ensures that 722 // TextEncodingFormat to kUnicode16BitFormat. Using these values ensures that
720 // the Unicode will be in the same form as on an HFS Plus volume, even as the 723 // the Unicode will be in the same form as on an HFS Plus volume, even as the
721 // Unicode standard evolves." 724 // Unicode standard evolves."
722 // 725 //
(...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after
1146 int lookup_offset = lower_case_table[codepoint >> 8]; 1149 int lookup_offset = lower_case_table[codepoint >> 8];
1147 if (lookup_offset != 0) 1150 if (lookup_offset != 0)
1148 codepoint = lower_case_table[lookup_offset + (codepoint & 0x00FF)]; 1151 codepoint = lower_case_table[lookup_offset + (codepoint & 0x00FF)];
1149 // Note: codepoint1 may be again 0 at this point if the character was 1152 // Note: codepoint1 may be again 0 at this point if the character was
1150 // an ignorable. 1153 // an ignorable.
1151 } 1154 }
1152 } 1155 }
1153 return codepoint; 1156 return codepoint;
1154 } 1157 }
1155 1158
1156 } // anonymous namespace 1159 } // namespace
1157 1160
1158 // Special UTF-8 version of FastUnicodeCompare. Cf: 1161 // Special UTF-8 version of FastUnicodeCompare. Cf:
1159 // http://developer.apple.com/mac/library/technotes/tn/tn1150.html#StringCompari sonAlgorithm 1162 // http://developer.apple.com/mac/library/technotes/tn/tn1150.html#StringCompari sonAlgorithm
1160 // The input strings must be in the special HFS decomposed form. 1163 // The input strings must be in the special HFS decomposed form.
1161 int FilePath::HFSFastUnicodeCompare(const StringType& string1, 1164 int FilePath::HFSFastUnicodeCompare(StringPieceType string1,
1162 const StringType& string2) { 1165 StringPieceType string2) {
1163 int length1 = string1.length(); 1166 int length1 = string1.length();
1164 int length2 = string2.length(); 1167 int length2 = string2.length();
1165 int index1 = 0; 1168 int index1 = 0;
1166 int index2 = 0; 1169 int index2 = 0;
1167 1170
1168 for (;;) { 1171 for (;;) {
1169 int codepoint1 = HFSReadNextNonIgnorableCodepoint(string1.c_str(), 1172 int codepoint1 = HFSReadNextNonIgnorableCodepoint(string1.data(),
1170 length1, 1173 length1,
1171 &index1); 1174 &index1);
1172 int codepoint2 = HFSReadNextNonIgnorableCodepoint(string2.c_str(), 1175 int codepoint2 = HFSReadNextNonIgnorableCodepoint(string2.data(),
1173 length2, 1176 length2,
1174 &index2); 1177 &index2);
1175 if (codepoint1 != codepoint2) 1178 if (codepoint1 != codepoint2)
1176 return (codepoint1 < codepoint2) ? -1 : 1; 1179 return (codepoint1 < codepoint2) ? -1 : 1;
1177 if (codepoint1 == 0) { 1180 if (codepoint1 == 0) {
1178 DCHECK_EQ(index1, length1); 1181 DCHECK_EQ(index1, length1);
1179 DCHECK_EQ(index2, length2); 1182 DCHECK_EQ(index2, length2);
1180 return 0; 1183 return 0;
1181 } 1184 }
1182 } 1185 }
1183 } 1186 }
1184 1187
1185 StringType FilePath::GetHFSDecomposedForm(const StringType& string) { 1188 StringType FilePath::GetHFSDecomposedForm(StringPieceType string) {
1186 ScopedCFTypeRef<CFStringRef> cfstring( 1189 ScopedCFTypeRef<CFStringRef> cfstring(
1187 CFStringCreateWithBytesNoCopy( 1190 CFStringCreateWithBytesNoCopy(
1188 NULL, 1191 NULL,
1189 reinterpret_cast<const UInt8*>(string.c_str()), 1192 reinterpret_cast<const UInt8*>(string.data()),
1190 string.length(), 1193 string.length(),
1191 kCFStringEncodingUTF8, 1194 kCFStringEncodingUTF8,
1192 false, 1195 false,
1193 kCFAllocatorNull)); 1196 kCFAllocatorNull));
1194 // Query the maximum length needed to store the result. In most cases this 1197 // Query the maximum length needed to store the result. In most cases this
1195 // will overestimate the required space. The return value also already 1198 // will overestimate the required space. The return value also already
1196 // includes the space needed for a terminating 0. 1199 // includes the space needed for a terminating 0.
1197 CFIndex length = CFStringGetMaximumSizeOfFileSystemRepresentation(cfstring); 1200 CFIndex length = CFStringGetMaximumSizeOfFileSystemRepresentation(cfstring);
1198 DCHECK_GT(length, 0); // should be at least 1 for the 0-terminator. 1201 DCHECK_GT(length, 0); // should be at least 1 for the 0-terminator.
1199 // Reserve enough space for CFStringGetFileSystemRepresentation to write into. 1202 // Reserve enough space for CFStringGetFileSystemRepresentation to write into.
1200 // Also set the length to the maximum so that we can shrink it later. 1203 // Also set the length to the maximum so that we can shrink it later.
1201 // (Increasing rather than decreasing it would clobber the string contents!) 1204 // (Increasing rather than decreasing it would clobber the string contents!)
1202 StringType result; 1205 StringType result;
1203 result.reserve(length); 1206 result.reserve(length);
1204 result.resize(length - 1); 1207 result.resize(length - 1);
1205 Boolean success = CFStringGetFileSystemRepresentation(cfstring, 1208 Boolean success = CFStringGetFileSystemRepresentation(cfstring,
1206 &result[0], 1209 &result[0],
1207 length); 1210 length);
1208 if (success) { 1211 if (success) {
1209 // Reduce result.length() to actual string length. 1212 // Reduce result.length() to actual string length.
1210 result.resize(strlen(result.c_str())); 1213 result.resize(strlen(result.c_str()));
1211 } else { 1214 } else {
1212 // An error occurred -> clear result. 1215 // An error occurred -> clear result.
1213 result.clear(); 1216 result.clear();
1214 } 1217 }
1215 return result; 1218 return result;
1216 } 1219 }
1217 1220
1218 int FilePath::CompareIgnoreCase(const StringType& string1, 1221 int FilePath::CompareIgnoreCase(StringPieceType string1,
1219 const StringType& string2) { 1222 StringPieceType string2) {
1220 // Quick checks for empty strings - these speed things up a bit and make the 1223 // Quick checks for empty strings - these speed things up a bit and make the
1221 // following code cleaner. 1224 // following code cleaner.
1222 if (string1.empty()) 1225 if (string1.empty())
1223 return string2.empty() ? 0 : -1; 1226 return string2.empty() ? 0 : -1;
1224 if (string2.empty()) 1227 if (string2.empty())
1225 return 1; 1228 return 1;
1226 1229
1227 StringType hfs1 = GetHFSDecomposedForm(string1); 1230 StringType hfs1 = GetHFSDecomposedForm(string1);
1228 StringType hfs2 = GetHFSDecomposedForm(string2); 1231 StringType hfs2 = GetHFSDecomposedForm(string2);
1229 1232
1230 // GetHFSDecomposedForm() returns an empty string in an error case. 1233 // GetHFSDecomposedForm() returns an empty string in an error case.
1231 if (hfs1.empty() || hfs2.empty()) { 1234 if (hfs1.empty() || hfs2.empty()) {
1232 NOTREACHED(); 1235 NOTREACHED();
1233 ScopedCFTypeRef<CFStringRef> cfstring1( 1236 ScopedCFTypeRef<CFStringRef> cfstring1(
1234 CFStringCreateWithBytesNoCopy( 1237 CFStringCreateWithBytesNoCopy(
1235 NULL, 1238 NULL,
1236 reinterpret_cast<const UInt8*>(string1.c_str()), 1239 reinterpret_cast<const UInt8*>(string1.data()),
1237 string1.length(), 1240 string1.length(),
1238 kCFStringEncodingUTF8, 1241 kCFStringEncodingUTF8,
1239 false, 1242 false,
1240 kCFAllocatorNull)); 1243 kCFAllocatorNull));
1241 ScopedCFTypeRef<CFStringRef> cfstring2( 1244 ScopedCFTypeRef<CFStringRef> cfstring2(
1242 CFStringCreateWithBytesNoCopy( 1245 CFStringCreateWithBytesNoCopy(
1243 NULL, 1246 NULL,
1244 reinterpret_cast<const UInt8*>(string2.c_str()), 1247 reinterpret_cast<const UInt8*>(string2.data()),
1245 string2.length(), 1248 string2.length(),
1246 kCFStringEncodingUTF8, 1249 kCFStringEncodingUTF8,
1247 false, 1250 false,
1248 kCFAllocatorNull)); 1251 kCFAllocatorNull));
1249 return CFStringCompare(cfstring1, 1252 return CFStringCompare(cfstring1,
1250 cfstring2, 1253 cfstring2,
1251 kCFCompareCaseInsensitive); 1254 kCFCompareCaseInsensitive);
1252 } 1255 }
1253 1256
1254 return HFSFastUnicodeCompare(hfs1, hfs2); 1257 return HFSFastUnicodeCompare(hfs1, hfs2);
1255 } 1258 }
1256 1259
1257 #else // << WIN. MACOSX | other (POSIX) >> 1260 #else // << WIN. MACOSX | other (POSIX) >>
1258 1261
1259 // Generic (POSIX) implementation of file string comparison. 1262 // Generic (POSIX) implementation of file string comparison.
1260 // TODO(rolandsteiner) check if this is sufficient/correct. 1263 // TODO(rolandsteiner) check if this is sufficient/correct.
1261 int FilePath::CompareIgnoreCase(const StringType& string1, 1264 int FilePath::CompareIgnoreCase(StringPieceType string1,
1262 const StringType& string2) { 1265 StringPieceType string2) {
1263 int comparison = strcasecmp(string1.c_str(), string2.c_str()); 1266 int comparison = strcasecmp(string1.data(), string2.data());
1264 if (comparison < 0) 1267 if (comparison < 0)
1265 return -1; 1268 return -1;
1266 if (comparison > 0) 1269 if (comparison > 0)
1267 return 1; 1270 return 1;
1268 return 0; 1271 return 0;
1269 } 1272 }
1270 1273
1271 #endif // OS versions of CompareIgnoreCase() 1274 #endif // OS versions of CompareIgnoreCase()
1272 1275
1273 1276
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1311 #endif 1314 #endif
1312 } 1315 }
1313 1316
1314 #if defined(OS_ANDROID) 1317 #if defined(OS_ANDROID)
1315 bool FilePath::IsContentUri() const { 1318 bool FilePath::IsContentUri() const {
1316 return StartsWithASCII(path_, "content://", false /*case_sensitive*/); 1319 return StartsWithASCII(path_, "content://", false /*case_sensitive*/);
1317 } 1320 }
1318 #endif 1321 #endif
1319 1322
1320 } // namespace base 1323 } // namespace base
OLDNEW
« no previous file with comments | « base/files/file_path.h ('k') | base/strings/string_util.h » ('j') | base/strings/string_util.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698