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