OLD | NEW |
1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2008 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/file_path.h" | 5 #include "base/file_path.h" |
6 #include "base/file_util.h" | 6 #include "base/file_util.h" |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 | 8 |
9 // These includes are just for the *Hack functions, and should be removed | 9 // These includes are just for the *Hack functions, and should be removed |
10 // when those functions are removed. | 10 // when those functions are removed. |
11 #include "base/string_piece.h" | 11 #include "base/string_piece.h" |
12 #include "base/string_util.h" | 12 #include "base/string_util.h" |
13 #include "base/sys_string_conversions.h" | 13 #include "base/sys_string_conversions.h" |
14 | 14 |
15 #if defined(FILE_PATH_USES_WIN_SEPARATORS) | 15 #if defined(FILE_PATH_USES_WIN_SEPARATORS) |
16 const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("\\/"); | 16 const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("\\/"); |
17 #else // FILE_PATH_USES_WIN_SEPARATORS | 17 #else // FILE_PATH_USES_WIN_SEPARATORS |
18 const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("/"); | 18 const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("/"); |
19 #endif // FILE_PATH_USES_WIN_SEPARATORS | 19 #endif // FILE_PATH_USES_WIN_SEPARATORS |
20 | 20 |
21 const FilePath::CharType FilePath::kCurrentDirectory[] = FILE_PATH_LITERAL("."); | 21 const FilePath::CharType FilePath::kCurrentDirectory[] = FILE_PATH_LITERAL("."); |
22 const FilePath::CharType FilePath::kParentDirectory[] = FILE_PATH_LITERAL(".."); | 22 const FilePath::CharType FilePath::kParentDirectory[] = FILE_PATH_LITERAL(".."); |
23 | 23 |
| 24 const FilePath::CharType FilePath::kExtensionSeparator = FILE_PATH_LITERAL('.'); |
| 25 |
| 26 |
24 namespace { | 27 namespace { |
25 | 28 |
26 // If this FilePath contains a drive letter specification, returns the | 29 // If this FilePath contains a drive letter specification, returns the |
27 // position of the last character of the drive letter specification, | 30 // position of the last character of the drive letter specification, |
28 // otherwise returns npos. This can only be true on Windows, when a pathname | 31 // otherwise returns npos. This can only be true on Windows, when a pathname |
29 // begins with a letter followed by a colon. On other platforms, this always | 32 // begins with a letter followed by a colon. On other platforms, this always |
30 // returns npos. | 33 // returns npos. |
31 FilePath::StringType::size_type FindDriveLetter( | 34 FilePath::StringType::size_type FindDriveLetter( |
32 const FilePath::StringType& path) { | 35 const FilePath::StringType& path) { |
33 #if defined(FILE_PATH_USES_DRIVE_LETTERS) | 36 #if defined(FILE_PATH_USES_DRIVE_LETTERS) |
34 // This is dependent on an ASCII-based character set, but that's a | 37 // This is dependent on an ASCII-based character set, but that's a |
35 // reasonable assumption. iswalpha can be too inclusive here. | 38 // reasonable assumption. iswalpha can be too inclusive here. |
36 if (path.length() >= 2 && path[1] == L':' && | 39 if (path.length() >= 2 && path[1] == L':' && |
37 ((path[0] >= L'A' && path[0] <= L'Z') || | 40 ((path[0] >= L'A' && path[0] <= L'Z') || |
38 (path[0] >= L'a' && path[0] <= L'z'))) { | 41 (path[0] >= L'a' && path[0] <= L'z'))) { |
39 return 1; | 42 return 1; |
40 } | 43 } |
| 44 #endif // FILE_PATH_USES_DRIVE_LETTERS |
41 return FilePath::StringType::npos; | 45 return FilePath::StringType::npos; |
42 #else // FILE_PATH_USES_DRIVE_LETTERS | |
43 return FilePath::StringType::npos; | |
44 #endif // FILE_PATH_USES_DRIVE_LETTERS | |
45 } | 46 } |
46 | 47 |
47 bool IsPathAbsolute(const FilePath::StringType& path) { | 48 bool IsPathAbsolute(const FilePath::StringType& path) { |
48 #if defined(FILE_PATH_USES_DRIVE_LETTERS) | 49 #if defined(FILE_PATH_USES_DRIVE_LETTERS) |
49 FilePath::StringType::size_type letter = FindDriveLetter(path); | 50 FilePath::StringType::size_type letter = FindDriveLetter(path); |
50 if (letter != FilePath::StringType::npos) { | 51 if (letter != FilePath::StringType::npos) { |
51 // Look for a separator right after the drive specification. | 52 // Look for a separator right after the drive specification. |
52 return path.length() > letter + 1 && | 53 return path.length() > letter + 1 && |
53 FilePath::IsSeparator(path[letter + 1]); | 54 FilePath::IsSeparator(path[letter + 1]); |
54 } | 55 } |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
129 new_path.path_.find_last_of(kSeparators, StringType::npos, | 130 new_path.path_.find_last_of(kSeparators, StringType::npos, |
130 arraysize(kSeparators) - 1); | 131 arraysize(kSeparators) - 1); |
131 if (last_separator != StringType::npos && | 132 if (last_separator != StringType::npos && |
132 last_separator < new_path.path_.length() - 1) { | 133 last_separator < new_path.path_.length() - 1) { |
133 new_path.path_.erase(0, last_separator + 1); | 134 new_path.path_.erase(0, last_separator + 1); |
134 } | 135 } |
135 | 136 |
136 return new_path; | 137 return new_path; |
137 } | 138 } |
138 | 139 |
139 FilePath FilePath::Append(const FilePath::StringType& component) const { | 140 FilePath::StringType FilePath::Extension() const { |
| 141 // BaseName() calls StripTrailingSeparators, so cases like /foo.baz/// work. |
| 142 StringType base = BaseName().value(); |
| 143 |
| 144 // Special case "." and ".." |
| 145 if (base == kCurrentDirectory || base == kParentDirectory) |
| 146 return StringType(); |
| 147 |
| 148 const StringType::size_type last_dot = base.rfind(kExtensionSeparator); |
| 149 if (last_dot == StringType::npos) |
| 150 return StringType(); |
| 151 return StringType(base, last_dot); |
| 152 } |
| 153 |
| 154 FilePath FilePath::RemoveExtension() const { |
| 155 StringType ext = Extension(); |
| 156 // It's important to check Extension() since that verifies that the |
| 157 // kExtensionSeparator actually appeared in the last path component. |
| 158 if (ext.empty()) |
| 159 return FilePath(path_); |
| 160 // Since Extension() verified that the extension is in fact in the last path |
| 161 // component, this substr will effectively strip trailing separators. |
| 162 const StringType::size_type last_dot = path_.rfind(kExtensionSeparator); |
| 163 return FilePath(path_.substr(0, last_dot)); |
| 164 } |
| 165 |
| 166 FilePath FilePath::InsertBeforeExtension(const StringType& suffix) const { |
| 167 if (suffix.empty()) |
| 168 return FilePath(path_); |
| 169 |
| 170 if (path_.empty()) |
| 171 return FilePath(); |
| 172 |
| 173 StringType base = BaseName().value(); |
| 174 if (base.empty()) |
| 175 return FilePath(); |
| 176 if (*(base.end() - 1) == kExtensionSeparator) { |
| 177 // Special case "." and ".." |
| 178 if (base == kCurrentDirectory || base == kParentDirectory) { |
| 179 return FilePath(); |
| 180 } |
| 181 } |
| 182 |
| 183 StringType ext = Extension(); |
| 184 StringType ret = RemoveExtension().value(); |
| 185 ret.append(suffix); |
| 186 ret.append(ext); |
| 187 return FilePath(ret); |
| 188 } |
| 189 |
| 190 FilePath FilePath::ReplaceExtension(const StringType& extension) const { |
| 191 if (path_.empty()) |
| 192 return FilePath(); |
| 193 |
| 194 StringType base = BaseName().value(); |
| 195 if (base.empty()) |
| 196 return FilePath(); |
| 197 if (*(base.end() - 1) == kExtensionSeparator) { |
| 198 // Special case "." and ".." |
| 199 if (base == kCurrentDirectory || base == kParentDirectory) { |
| 200 return FilePath(); |
| 201 } |
| 202 } |
| 203 |
| 204 FilePath no_ext = RemoveExtension(); |
| 205 // If the new extension is "" or ".", then just remove the current extension. |
| 206 if (extension.empty() || extension == StringType(1, kExtensionSeparator)) |
| 207 return no_ext; |
| 208 |
| 209 StringType str = no_ext.value(); |
| 210 if (extension[0] != kExtensionSeparator) |
| 211 str.append(1, kExtensionSeparator); |
| 212 str.append(extension); |
| 213 return FilePath(str); |
| 214 } |
| 215 |
| 216 FilePath FilePath::Append(const StringType& component) const { |
140 DCHECK(!IsPathAbsolute(component)); | 217 DCHECK(!IsPathAbsolute(component)); |
141 if (path_.compare(kCurrentDirectory) == 0) { | 218 if (path_.compare(kCurrentDirectory) == 0) { |
142 // Append normally doesn't do any normalization, but as a special case, | 219 // Append normally doesn't do any normalization, but as a special case, |
143 // when appending to kCurrentDirectory, just return a new path for the | 220 // when appending to kCurrentDirectory, just return a new path for the |
144 // component argument. Appending component to kCurrentDirectory would | 221 // component argument. Appending component to kCurrentDirectory would |
145 // serve no purpose other than needlessly lengthening the path, and | 222 // serve no purpose other than needlessly lengthening the path, and |
146 // it's likely in practice to wind up with FilePath objects containing | 223 // it's likely in practice to wind up with FilePath objects containing |
147 // only kCurrentDirectory when calling DirName on a single relative path | 224 // only kCurrentDirectory when calling DirName on a single relative path |
148 // component. | 225 // component. |
149 return FilePath(component); | 226 return FilePath(component); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
249 --pos) { | 326 --pos) { |
250 // If the string only has two separators and they're at the beginning, | 327 // If the string only has two separators and they're at the beginning, |
251 // don't strip them, unless the string began with more than two separators. | 328 // don't strip them, unless the string began with more than two separators. |
252 if (pos != start + 1 || last_stripped == start + 2 || | 329 if (pos != start + 1 || last_stripped == start + 2 || |
253 !IsSeparator(path_[start - 1])) { | 330 !IsSeparator(path_[start - 1])) { |
254 path_.resize(pos - 1); | 331 path_.resize(pos - 1); |
255 last_stripped = pos; | 332 last_stripped = pos; |
256 } | 333 } |
257 } | 334 } |
258 } | 335 } |
OLD | NEW |