| Index: base/file_path.cc
|
| diff --git a/base/file_path.cc b/base/file_path.cc
|
| index 1787a697eba86709b7e78603def15368effa38ff..dd80eab916aa159b3400b928966ddbf94339a783 100644
|
| --- a/base/file_path.cc
|
| +++ b/base/file_path.cc
|
| @@ -36,16 +36,18 @@ const FilePath::CharType FilePath::kParentDirectory[] = FILE_PATH_LITERAL("..");
|
|
|
| const FilePath::CharType FilePath::kExtensionSeparator = FILE_PATH_LITERAL('.');
|
|
|
| +typedef FilePath::StringType StringType;
|
|
|
| namespace {
|
|
|
| +const char* kCommonDoubleExtensions[] = { "gz", "z", "bz2" };
|
| +
|
| // If this FilePath contains a drive letter specification, returns the
|
| // position of the last character of the drive letter specification,
|
| // otherwise returns npos. This can only be true on Windows, when a pathname
|
| // begins with a letter followed by a colon. On other platforms, this always
|
| // returns npos.
|
| -FilePath::StringType::size_type FindDriveLetter(
|
| - const FilePath::StringType& path) {
|
| +StringType::size_type FindDriveLetter(const StringType& path) {
|
| #if defined(FILE_PATH_USES_DRIVE_LETTERS)
|
| // This is dependent on an ASCII-based character set, but that's a
|
| // reasonable assumption. iswalpha can be too inclusive here.
|
| @@ -55,35 +57,33 @@ FilePath::StringType::size_type FindDriveLetter(
|
| return 1;
|
| }
|
| #endif // FILE_PATH_USES_DRIVE_LETTERS
|
| - return FilePath::StringType::npos;
|
| + return StringType::npos;
|
| }
|
|
|
| -
|
| #if defined(FILE_PATH_USES_DRIVE_LETTERS)
|
| -bool EqualDriveLetterCaseInsensitive(const FilePath::StringType a,
|
| - const FilePath::StringType b) {
|
| +bool EqualDriveLetterCaseInsensitive(const StringType a,
|
| + const StringType b) {
|
| size_t a_letter_pos = FindDriveLetter(a);
|
| size_t b_letter_pos = FindDriveLetter(b);
|
|
|
| - if ((a_letter_pos == FilePath::StringType::npos) ||
|
| - (b_letter_pos == FilePath::StringType::npos))
|
| + if (a_letter_pos == StringType::npos || b_letter_pos == StringType::npos)
|
| return a == b;
|
|
|
| - FilePath::StringType a_letter(a.substr(0, a_letter_pos + 1));
|
| - FilePath::StringType b_letter(b.substr(0, b_letter_pos + 1));
|
| + StringType a_letter(a.substr(0, a_letter_pos + 1));
|
| + StringType b_letter(b.substr(0, b_letter_pos + 1));
|
| if (!StartsWith(a_letter, b_letter, false))
|
| return false;
|
|
|
| - FilePath::StringType a_rest(a.substr(a_letter_pos + 1));
|
| - FilePath::StringType b_rest(b.substr(b_letter_pos + 1));
|
| + StringType a_rest(a.substr(a_letter_pos + 1));
|
| + StringType b_rest(b.substr(b_letter_pos + 1));
|
| return a_rest == b_rest;
|
| }
|
| #endif // defined(FILE_PATH_USES_DRIVE_LETTERS)
|
|
|
| -bool IsPathAbsolute(const FilePath::StringType& path) {
|
| +bool IsPathAbsolute(const StringType& path) {
|
| #if defined(FILE_PATH_USES_DRIVE_LETTERS)
|
| - FilePath::StringType::size_type letter = FindDriveLetter(path);
|
| - if (letter != FilePath::StringType::npos) {
|
| + StringType::size_type letter = FindDriveLetter(path);
|
| + if (letter != StringType::npos) {
|
| // Look for a separator right after the drive specification.
|
| return path.length() > letter + 1 &&
|
| FilePath::IsSeparator(path[letter + 1]);
|
| @@ -97,8 +97,8 @@ bool IsPathAbsolute(const FilePath::StringType& path) {
|
| #endif // FILE_PATH_USES_DRIVE_LETTERS
|
| }
|
|
|
| -bool AreAllSeparators(const FilePath::StringType& input) {
|
| - for (FilePath::StringType::const_iterator it = input.begin();
|
| +bool AreAllSeparators(const StringType& input) {
|
| + for (StringType::const_iterator it = input.begin();
|
| it != input.end(); ++it) {
|
| if (!FilePath::IsSeparator(*it))
|
| return false;
|
| @@ -107,6 +107,54 @@ bool AreAllSeparators(const FilePath::StringType& input) {
|
| return true;
|
| }
|
|
|
| +// Find the position of the '.' that separates the extension from the rest
|
| +// of the file name. The position is relative to BaseName(), not value().
|
| +// This allows a second extension component of up to 4 characters when the
|
| +// rightmost extension component is a common double extension (gz, bz2, Z).
|
| +// For example, foo.tar.gz or foo.tar.Z would have extension components of
|
| +// '.tar.gz' and '.tar.Z' respectively. Returns npos if it can't find an
|
| +// extension.
|
| +StringType::size_type ExtensionSeparatorPosition(const StringType& path) {
|
| + // Special case "." and ".."
|
| + if (path == FilePath::kCurrentDirectory || path == FilePath::kParentDirectory)
|
| + return StringType::npos;
|
| +
|
| + const StringType::size_type last_dot =
|
| + path.rfind(FilePath::kExtensionSeparator);
|
| +
|
| + // No extension, or the extension is the whole filename.
|
| + if (last_dot == StringType::npos || last_dot == 0U)
|
| + return last_dot;
|
| +
|
| + // Special case .<extension1>.<extension2>, but only if the final extension
|
| + // is one of a few common double extensions.
|
| + StringType extension(path, last_dot + 1);
|
| + bool is_common_double_extension = false;
|
| + for (size_t i = 0; i < arraysize(kCommonDoubleExtensions); ++i) {
|
| + if (LowerCaseEqualsASCII(extension, kCommonDoubleExtensions[i]))
|
| + is_common_double_extension = true;
|
| + }
|
| + if (!is_common_double_extension)
|
| + return last_dot;
|
| +
|
| + // Check that <extension1> is 1-4 characters, otherwise fall back to
|
| + // <extension2>.
|
| + const StringType::size_type penultimate_dot =
|
| + path.rfind(FilePath::kExtensionSeparator, last_dot - 1);
|
| + const StringType::size_type last_separator =
|
| + path.find_last_of(FilePath::kSeparators, last_dot - 1,
|
| + arraysize(FilePath::kSeparators) - 1);
|
| + if (penultimate_dot != StringType::npos &&
|
| + (last_separator == StringType::npos ||
|
| + penultimate_dot > last_separator) &&
|
| + last_dot - penultimate_dot <= 5U &&
|
| + last_dot - penultimate_dot > 1U) {
|
| + return penultimate_dot;
|
| + }
|
| +
|
| + return last_dot;
|
| +}
|
| +
|
| } // namespace
|
|
|
| FilePath::FilePath() {
|
| @@ -136,8 +184,7 @@ bool FilePath::IsSeparator(CharType character) {
|
| return false;
|
| }
|
|
|
| -void FilePath::GetComponents(std::vector<FilePath::StringType>* components)
|
| - const {
|
| +void FilePath::GetComponents(std::vector<StringType>* components) const {
|
| DCHECK(components);
|
| if (!components)
|
| return;
|
| @@ -145,7 +192,7 @@ void FilePath::GetComponents(std::vector<FilePath::StringType>* components)
|
| if (value().empty())
|
| return;
|
|
|
| - std::vector<FilePath::StringType> ret_val;
|
| + std::vector<StringType> ret_val;
|
| FilePath current = *this;
|
| FilePath base;
|
|
|
| @@ -165,12 +212,11 @@ void FilePath::GetComponents(std::vector<FilePath::StringType>* components)
|
| // Capture drive letter, if any.
|
| FilePath dir = current.DirName();
|
| StringType::size_type letter = FindDriveLetter(dir.value());
|
| - if (letter != FilePath::StringType::npos) {
|
| - ret_val.push_back(FilePath::StringType(dir.value(), 0, letter + 1));
|
| + if (letter != StringType::npos) {
|
| + ret_val.push_back(StringType(dir.value(), 0, letter + 1));
|
| }
|
|
|
| - *components = std::vector<FilePath::StringType>(ret_val.rbegin(),
|
| - ret_val.rend());
|
| + *components = std::vector<StringType>(ret_val.rbegin(), ret_val.rend());
|
| }
|
|
|
| bool FilePath::operator==(const FilePath& that) const {
|
| @@ -195,8 +241,8 @@ bool FilePath::IsParent(const FilePath& child) const {
|
|
|
| bool FilePath::AppendRelativePath(const FilePath& child,
|
| FilePath* path) const {
|
| - std::vector<FilePath::StringType> parent_components;
|
| - std::vector<FilePath::StringType> child_components;
|
| + std::vector<StringType> parent_components;
|
| + std::vector<StringType> child_components;
|
| GetComponents(&parent_components);
|
| child.GetComponents(&child_components);
|
|
|
| @@ -205,17 +251,17 @@ bool FilePath::AppendRelativePath(const FilePath& child,
|
| if (parent_components.size() == 0)
|
| return false;
|
|
|
| - std::vector<FilePath::StringType>::const_iterator parent_comp =
|
| + std::vector<StringType>::const_iterator parent_comp =
|
| parent_components.begin();
|
| - std::vector<FilePath::StringType>::const_iterator child_comp =
|
| + std::vector<StringType>::const_iterator child_comp =
|
| child_components.begin();
|
|
|
| #if defined(FILE_PATH_USES_DRIVE_LETTERS)
|
| // Windows can access case sensitive filesystems, so component
|
| // comparisions must be case sensitive, but drive letters are
|
| // never case sensitive.
|
| - if ((FindDriveLetter(*parent_comp) != FilePath::StringType::npos) &&
|
| - (FindDriveLetter(*child_comp) != FilePath::StringType::npos)) {
|
| + if ((FindDriveLetter(*parent_comp) != StringType::npos) &&
|
| + (FindDriveLetter(*child_comp) != StringType::npos)) {
|
| if (!StartsWith(*parent_comp, *child_comp, false))
|
| return false;
|
| ++parent_comp;
|
| @@ -301,30 +347,24 @@ FilePath FilePath::BaseName() const {
|
| return new_path;
|
| }
|
|
|
| -FilePath::StringType FilePath::Extension() const {
|
| - // BaseName() calls StripTrailingSeparators, so cases like /foo.baz/// work.
|
| - StringType base = BaseName().value();
|
| -
|
| - // Special case "." and ".."
|
| - if (base == kCurrentDirectory || base == kParentDirectory)
|
| +StringType FilePath::Extension() const {
|
| + FilePath base(BaseName());
|
| + const StringType::size_type dot = ExtensionSeparatorPosition(base.path_);
|
| + if (dot == StringType::npos)
|
| return StringType();
|
|
|
| - const StringType::size_type last_dot = base.rfind(kExtensionSeparator);
|
| - if (last_dot == StringType::npos)
|
| - return StringType();
|
| - return StringType(base, last_dot);
|
| + return base.path_.substr(dot, StringType::npos);
|
| }
|
|
|
| FilePath FilePath::RemoveExtension() const {
|
| - StringType ext = Extension();
|
| - // It's important to check Extension() since that verifies that the
|
| - // kExtensionSeparator actually appeared in the last path component.
|
| - if (ext.empty())
|
| - return FilePath(path_);
|
| - // Since Extension() verified that the extension is in fact in the last path
|
| - // component, this substr will effectively strip trailing separators.
|
| - const StringType::size_type last_dot = path_.rfind(kExtensionSeparator);
|
| - return FilePath(path_.substr(0, last_dot));
|
| + if (Extension().empty())
|
| + return *this;
|
| +
|
| + const StringType::size_type dot = ExtensionSeparatorPosition(path_);
|
| + if (dot == StringType::npos)
|
| + return *this;
|
| +
|
| + return FilePath(path_.substr(0, dot));
|
| }
|
|
|
| FilePath FilePath::InsertBeforeExtension(const StringType& suffix) const {
|
| @@ -390,7 +430,7 @@ FilePath FilePath::ReplaceExtension(const StringType& extension) const {
|
| bool FilePath::MatchesExtension(const StringType& extension) const {
|
| DCHECK(extension.empty() || extension[0] == kExtensionSeparator);
|
|
|
| - FilePath::StringType current_extension = Extension();
|
| + StringType current_extension = Extension();
|
|
|
| if (current_extension.length() != extension.length())
|
| return false;
|
| @@ -950,7 +990,7 @@ int FilePath::HFSFastUnicodeCompare(const StringType& string1,
|
| }
|
| }
|
|
|
| -FilePath::StringType FilePath::GetHFSDecomposedForm(const StringType& string) {
|
| +StringType FilePath::GetHFSDecomposedForm(const StringType& string) {
|
| scoped_cftyperef<CFStringRef> cfstring(
|
| CFStringCreateWithBytesNoCopy(
|
| NULL,
|
| @@ -1071,7 +1111,7 @@ FilePath FilePath::StripTrailingSeparators() const {
|
|
|
| // static.
|
| void FilePath::WriteStringTypeToPickle(Pickle* pickle,
|
| - const FilePath::StringType& path) {
|
| + const StringType& path) {
|
| #if defined(WCHAR_T_IS_UTF16)
|
| pickle->WriteWString(path);
|
| #elif defined(WCHAR_T_IS_UTF32)
|
| @@ -1083,7 +1123,7 @@ void FilePath::WriteStringTypeToPickle(Pickle* pickle,
|
|
|
| // static.
|
| bool FilePath::ReadStringTypeFromPickle(Pickle* pickle, void** iter,
|
| - FilePath::StringType* path) {
|
| + StringType* path) {
|
| #if defined(WCHAR_T_IS_UTF16)
|
| if (!pickle->ReadWString(iter, path))
|
| return false;
|
| @@ -1129,12 +1169,12 @@ void FilePath::StripTrailingSeparatorsInternal() {
|
| }
|
|
|
| bool FilePath::ReferencesParent() const {
|
| - std::vector<FilePath::StringType> components;
|
| + std::vector<StringType> components;
|
| GetComponents(&components);
|
|
|
| - std::vector<FilePath::StringType>::const_iterator it = components.begin();
|
| + std::vector<StringType>::const_iterator it = components.begin();
|
| for (; it != components.end(); ++it) {
|
| - const FilePath::StringType& component = *it;
|
| + const StringType& component = *it;
|
| if (component == kParentDirectory)
|
| return true;
|
| }
|
|
|