OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |