OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-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_util.h" | 5 #include "base/file_util.h" |
6 | 6 |
7 #include <stdio.h> | 7 #include <stdio.h> |
8 | 8 |
9 #include <fstream> | 9 #include <fstream> |
10 | 10 |
11 #include "base/file_path.h" | 11 #include "base/file_path.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/string_util.h" | 13 #include "base/string_util.h" |
14 #include "unicode/uniset.h" | 14 #include "unicode/uniset.h" |
15 | 15 |
| 16 #include "base/string_piece.h" |
| 17 #include "base/sys_string_conversions.h" |
| 18 |
16 namespace file_util { | 19 namespace file_util { |
17 | 20 |
18 const wchar_t kExtensionSeparator = L'.'; | 21 void PathComponents(const FilePath& path, |
| 22 std::vector<FilePath::StringType>* components) { |
| 23 DCHECK(components); |
| 24 if (!components) |
| 25 return; |
19 | 26 |
20 void PathComponents(const std::wstring& path, | 27 FilePath::StringType path_str = path.value(); |
21 std::vector<std::wstring>* components) { | 28 FilePath::StringType::size_type start = 0; |
22 DCHECK(components != NULL); | 29 FilePath::StringType::size_type end = |
23 if (components == NULL) | 30 path_str.find_first_of(FilePath::kSeparators); |
24 return; | |
25 std::wstring::size_type start = 0; | |
26 std::wstring::size_type end = path.find(kPathSeparator, start); | |
27 | 31 |
28 // Special case the "/" or "\" directory. On Windows with a drive letter, | 32 // If the path starts with a separator, add it to components. |
29 // this code path won't hit, but the right thing should still happen. | |
30 // "E:\foo" will turn into "E:","foo". | |
31 if (end == start) { | 33 if (end == start) { |
32 components->push_back(std::wstring(path, 0, 1)); | 34 components->push_back(FilePath::StringType(path_str, 0, 1)); |
33 start = end + 1; | 35 start = end + 1; |
34 end = path.find(kPathSeparator, start); | 36 end = path_str.find_first_of(FilePath::kSeparators, start); |
35 } | 37 } |
36 while (end != std::wstring::npos) { | 38 while (end != FilePath::StringType::npos) { |
37 std::wstring component = std::wstring(path, start, end - start); | 39 FilePath::StringType component = |
| 40 FilePath::StringType(path_str, start, end - start); |
38 components->push_back(component); | 41 components->push_back(component); |
39 start = end + 1; | 42 start = end + 1; |
40 end = path.find(kPathSeparator, start); | 43 end = path_str.find(FilePath::kSeparators, start); |
41 } | 44 } |
42 std::wstring component = std::wstring(path, start); | 45 |
43 components->push_back(component); | 46 components->push_back(FilePath::StringType(path_str, start)); |
44 } | 47 } |
45 | 48 |
46 bool EndsWithSeparator(const FilePath& file_path) { | 49 bool EndsWithSeparator(const FilePath& path) { |
47 std::wstring path = file_path.ToWStringHack(); | 50 FilePath::StringType value = path.value(); |
48 bool is_sep = (path.length() > 0 && | 51 if (value.empty()) |
49 path[path.length() - 1] == kPathSeparator); | 52 return false; |
50 return is_sep; | 53 |
| 54 return FilePath::IsSeparator(value[value.size() - 1]); |
51 } | 55 } |
52 | 56 |
53 bool EnsureEndsWithSeparator(FilePath* path) { | 57 bool EnsureEndsWithSeparator(FilePath* path) { |
54 if (!DirectoryExists(*path)) | 58 if (!DirectoryExists(*path)) |
55 return false; | 59 return false; |
56 | 60 |
57 if (EndsWithSeparator(*path)) | 61 if (EndsWithSeparator(*path)) |
58 return true; | 62 return true; |
59 | 63 |
60 FilePath::StringType& path_str = | 64 FilePath::StringType& path_str = |
61 const_cast<FilePath::StringType&>(path->value()); | 65 const_cast<FilePath::StringType&>(path->value()); |
62 path_str.append(&FilePath::kSeparators[0], 1); | 66 path_str.append(&FilePath::kSeparators[0], 1); |
63 | 67 |
64 return true; | 68 return true; |
65 } | 69 } |
66 | 70 |
67 void TrimTrailingSeparator(std::wstring* dir) { | 71 void TrimTrailingSeparator(std::wstring* dir) { |
68 while (dir->length() > 1 && EndsWithSeparator(dir)) | 72 while (dir->length() > 1 && EndsWithSeparator(dir)) |
69 dir->resize(dir->length() - 1); | 73 dir->resize(dir->length() - 1); |
70 } | 74 } |
71 | 75 |
72 void UpOneDirectory(std::wstring* dir) { | |
73 TrimTrailingSeparator(dir); | |
74 | |
75 std::wstring::size_type last_sep = dir->find_last_of(kPathSeparator); | |
76 if (last_sep != std::wstring::npos) | |
77 dir->resize(last_sep); | |
78 } | |
79 | |
80 void UpOneDirectoryOrEmpty(std::wstring* dir) { | |
81 TrimTrailingSeparator(dir); | |
82 | |
83 std::wstring::size_type last_sep = dir->find_last_of(kPathSeparator); | |
84 if (last_sep != std::wstring::npos) | |
85 dir->resize(last_sep); | |
86 else | |
87 dir->clear(); | |
88 } | |
89 | |
90 void TrimFilename(std::wstring* path) { | |
91 if (EndsWithSeparator(path)) { | |
92 TrimTrailingSeparator(path); | |
93 } else { | |
94 std::wstring::size_type last_sep = path->find_last_of(kPathSeparator); | |
95 if (last_sep != std::wstring::npos) | |
96 path->resize(last_sep); | |
97 } | |
98 } | |
99 | |
100 std::wstring GetFilenameFromPath(const std::wstring& path) { | 76 std::wstring GetFilenameFromPath(const std::wstring& path) { |
101 // TODO(erikkay): fix this - it's not using kPathSeparator, but win unit test | 77 // TODO(erikkay): fix this - it's not using kPathSeparator, but win unit test |
102 // are exercising '/' as a path separator as well. | 78 // are exercising '/' as a path separator as well. |
103 std::wstring::size_type pos = path.find_last_of(L"\\/"); | 79 std::wstring::size_type pos = path.find_last_of(L"\\/"); |
104 return std::wstring(path, pos == std::wstring::npos ? 0 : pos + 1); | 80 return std::wstring(path, pos == std::wstring::npos ? 0 : pos + 1); |
105 } | 81 } |
106 | 82 |
107 std::wstring GetFileExtensionFromPath(const std::wstring& path) { | 83 std::wstring GetFileExtensionFromPath(const std::wstring& path) { |
108 std::wstring file_name = GetFilenameFromPath(path); | 84 std::wstring file_name = GetFilenameFromPath(path); |
109 std::wstring::size_type last_dot = file_name.rfind(L'.'); | 85 std::wstring::size_type last_dot = file_name.rfind(L'.'); |
110 return std::wstring(last_dot == std::wstring::npos ? | 86 return std::wstring(last_dot == std::wstring::npos ? |
111 L"" : | 87 L"" : |
112 file_name, last_dot+1); | 88 file_name, last_dot+1); |
113 } | 89 } |
114 | 90 |
115 std::wstring GetFilenameWithoutExtensionFromPath(const std::wstring& path) { | 91 std::wstring GetFilenameWithoutExtensionFromPath(const std::wstring& path) { |
116 std::wstring file_name = GetFilenameFromPath(path); | 92 std::wstring file_name = GetFilenameFromPath(path); |
117 std::wstring::size_type last_dot = file_name.rfind(L'.'); | 93 std::wstring::size_type last_dot = file_name.rfind(L'.'); |
118 return file_name.substr(0, last_dot); | 94 return file_name.substr(0, last_dot); |
119 } | 95 } |
120 | 96 |
121 void AppendToPath(std::wstring* path, const std::wstring& new_ending) { | |
122 if (!path) { | |
123 NOTREACHED(); | |
124 return; // Don't crash in this function in release builds. | |
125 } | |
126 | |
127 if (!EndsWithSeparator(path)) | |
128 path->push_back(kPathSeparator); | |
129 path->append(new_ending); | |
130 } | |
131 | |
132 void InsertBeforeExtension(std::wstring* path, const std::wstring& suffix) { | |
133 DCHECK(path); | |
134 | |
135 const std::wstring::size_type last_dot = path->rfind(kExtensionSeparator); | |
136 const std::wstring::size_type last_sep = path->rfind(kPathSeparator); | |
137 | |
138 if (last_dot == std::wstring::npos || | |
139 (last_sep != std::wstring::npos && last_dot < last_sep)) { | |
140 // The path looks something like "C:\pics.old\jojo" or "C:\pics\jojo". | |
141 // We should just append the suffix to the entire path. | |
142 path->append(suffix); | |
143 return; | |
144 } | |
145 | |
146 path->insert(last_dot, suffix); | |
147 } | |
148 | |
149 void ReplaceIllegalCharacters(std::wstring* file_name, int replace_char) { | 97 void ReplaceIllegalCharacters(std::wstring* file_name, int replace_char) { |
150 DCHECK(file_name); | 98 DCHECK(file_name); |
151 | 99 |
152 // Control characters, formatting characters, non-characters, and | 100 // Control characters, formatting characters, non-characters, and |
153 // some printable ASCII characters regarded as dangerous ('"*/:<>?\\'). | 101 // some printable ASCII characters regarded as dangerous ('"*/:<>?\\'). |
154 // See http://blogs.msdn.com/michkap/archive/2006/11/03/941420.aspx | 102 // See http://blogs.msdn.com/michkap/archive/2006/11/03/941420.aspx |
155 // and http://msdn2.microsoft.com/en-us/library/Aa365247.aspx | 103 // and http://msdn2.microsoft.com/en-us/library/Aa365247.aspx |
156 // TODO(jungshik): Revisit the set. ZWJ and ZWNJ are excluded because they | 104 // TODO(jungshik): Revisit the set. ZWJ and ZWNJ are excluded because they |
157 // are legitimate in Arabic and some S/SE Asian scripts. However, when used | 105 // are legitimate in Arabic and some S/SE Asian scripts. However, when used |
158 // elsewhere, they can be confusing/problematic. | 106 // elsewhere, they can be confusing/problematic. |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
209 if (illegal_characters.contains(wstr[i])) { | 157 if (illegal_characters.contains(wstr[i])) { |
210 (*file_name)[i] = replace_char; | 158 (*file_name)[i] = replace_char; |
211 } | 159 } |
212 ++i; | 160 ++i; |
213 } | 161 } |
214 #else | 162 #else |
215 #error wchar_t* should be either UTF-16 or UTF-32 | 163 #error wchar_t* should be either UTF-16 or UTF-32 |
216 #endif | 164 #endif |
217 } | 165 } |
218 | 166 |
219 // Appends the extension to file adding a '.' if extension doesn't contain one. | |
220 // This does nothing if extension is empty or '.'. This is used internally by | |
221 // ReplaceExtension. | |
222 static void AppendExtension(const std::wstring& extension, | |
223 std::wstring* file) { | |
224 if (!extension.empty() && extension != L".") { | |
225 if (extension[0] != L'.') | |
226 file->append(L"."); | |
227 file->append(extension); | |
228 } | |
229 } | |
230 | |
231 void ReplaceExtension(std::wstring* file_name, const std::wstring& extension) { | |
232 const std::wstring::size_type last_dot = file_name->rfind(L'.'); | |
233 if (last_dot == std::wstring::npos) { | |
234 // No extension, just append the supplied extension. | |
235 AppendExtension(extension, file_name); | |
236 return; | |
237 } | |
238 const std::wstring::size_type last_separator = | |
239 file_name->rfind(kPathSeparator); | |
240 if (last_separator != std::wstring::npos && last_dot < last_separator) { | |
241 // File name doesn't have extension, but one of the directories does; don't | |
242 // replace it, just append the supplied extension. For example | |
243 // 'c:\tmp.bar\foo'. | |
244 AppendExtension(extension, file_name); | |
245 return; | |
246 } | |
247 std::wstring result = file_name->substr(0, last_dot); | |
248 AppendExtension(extension, &result); | |
249 file_name->swap(result); | |
250 } | |
251 | |
252 bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) { | 167 bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) { |
253 // We open the file in binary format even if they are text files because | 168 // We open the file in binary format even if they are text files because |
254 // we are just comparing that bytes are exactly same in both files and not | 169 // we are just comparing that bytes are exactly same in both files and not |
255 // doing anything smart with text formatting. | 170 // doing anything smart with text formatting. |
256 std::ifstream file1(filename1.value().c_str(), | 171 std::ifstream file1(filename1.value().c_str(), |
257 std::ios::in | std::ios::binary); | 172 std::ios::in | std::ios::binary); |
258 std::ifstream file2(filename2.value().c_str(), | 173 std::ifstream file2(filename2.value().c_str(), |
259 std::ios::in | std::ios::binary); | 174 std::ios::in | std::ios::binary); |
260 | 175 |
261 // Even if both files aren't openable (and thus, in some sense, "equal"), | 176 // Even if both files aren't openable (and thus, in some sense, "equal"), |
262 // any unusable file yields a result of "false". | 177 // any unusable file yields a result of "false". |
263 if (!file1.is_open() || !file2.is_open()) | 178 if (!file1.is_open() || !file2.is_open()) |
264 return false; | 179 return false; |
265 | 180 |
266 const int BUFFER_SIZE = 2056; | 181 const int BUFFER_SIZE = 2056; |
267 char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE]; | 182 char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE]; |
268 do { | 183 do { |
269 file1.read(buffer1, BUFFER_SIZE); | 184 file1.read(buffer1, BUFFER_SIZE); |
270 file2.read(buffer2, BUFFER_SIZE); | 185 file2.read(buffer2, BUFFER_SIZE); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
316 | 231 |
317 // Deprecated functions ---------------------------------------------------- | 232 // Deprecated functions ---------------------------------------------------- |
318 | 233 |
319 bool AbsolutePath(std::wstring* path_str) { | 234 bool AbsolutePath(std::wstring* path_str) { |
320 FilePath path(FilePath::FromWStringHack(*path_str)); | 235 FilePath path(FilePath::FromWStringHack(*path_str)); |
321 if (!AbsolutePath(&path)) | 236 if (!AbsolutePath(&path)) |
322 return false; | 237 return false; |
323 *path_str = path.ToWStringHack(); | 238 *path_str = path.ToWStringHack(); |
324 return true; | 239 return true; |
325 } | 240 } |
326 bool Delete(const std::wstring& path, bool recursive) { | 241 void AppendToPath(std::wstring* path, const std::wstring& new_ending) { |
327 return Delete(FilePath::FromWStringHack(path), recursive); | 242 if (!path) { |
328 } | 243 NOTREACHED(); |
329 bool EndsWithSeparator(std::wstring* path) { | 244 return; // Don't crash in this function in release builds. |
330 return EndsWithSeparator(FilePath::FromWStringHack(*path)); | 245 } |
331 } | 246 |
332 bool EndsWithSeparator(const std::wstring& path) { | 247 if (!EndsWithSeparator(path)) |
333 return EndsWithSeparator(FilePath::FromWStringHack(path)); | 248 path->push_back(FilePath::kSeparators[0]); |
334 } | 249 path->append(new_ending); |
335 bool Move(const std::wstring& from_path, const std::wstring& to_path) { | |
336 return Move(FilePath::FromWStringHack(from_path), | |
337 FilePath::FromWStringHack(to_path)); | |
338 } | |
339 bool CopyFile(const std::wstring& from_path, const std::wstring& to_path) { | |
340 return CopyFile(FilePath::FromWStringHack(from_path), | |
341 FilePath::FromWStringHack(to_path)); | |
342 } | 250 } |
343 bool CopyDirectory(const std::wstring& from_path, const std::wstring& to_path, | 251 bool CopyDirectory(const std::wstring& from_path, const std::wstring& to_path, |
344 bool recursive) { | 252 bool recursive) { |
345 return CopyDirectory(FilePath::FromWStringHack(from_path), | 253 return CopyDirectory(FilePath::FromWStringHack(from_path), |
346 FilePath::FromWStringHack(to_path), | 254 FilePath::FromWStringHack(to_path), |
347 recursive); | 255 recursive); |
348 } | 256 } |
349 bool PathExists(const std::wstring& path) { | |
350 return PathExists(FilePath::FromWStringHack(path)); | |
351 } | |
352 bool DirectoryExists(const std::wstring& path) { | |
353 return DirectoryExists(FilePath::FromWStringHack(path)); | |
354 } | |
355 bool ContentsEqual(const std::wstring& filename1, | 257 bool ContentsEqual(const std::wstring& filename1, |
356 const std::wstring& filename2) { | 258 const std::wstring& filename2) { |
357 return ContentsEqual(FilePath::FromWStringHack(filename1), | 259 return ContentsEqual(FilePath::FromWStringHack(filename1), |
358 FilePath::FromWStringHack(filename2)); | 260 FilePath::FromWStringHack(filename2)); |
359 } | 261 } |
| 262 bool CopyFile(const std::wstring& from_path, const std::wstring& to_path) { |
| 263 return CopyFile(FilePath::FromWStringHack(from_path), |
| 264 FilePath::FromWStringHack(to_path)); |
| 265 } |
360 bool CreateDirectory(const std::wstring& full_path) { | 266 bool CreateDirectory(const std::wstring& full_path) { |
361 return CreateDirectory(FilePath::FromWStringHack(full_path)); | 267 return CreateDirectory(FilePath::FromWStringHack(full_path)); |
362 } | 268 } |
363 bool CreateTemporaryFileName(std::wstring* temp_file) { | 269 bool CreateTemporaryFileName(std::wstring* temp_file) { |
364 FilePath temp_file_path; | 270 FilePath temp_file_path; |
365 if (!CreateTemporaryFileName(&temp_file_path)) | 271 if (!CreateTemporaryFileName(&temp_file_path)) |
366 return false; | 272 return false; |
367 *temp_file = temp_file_path.ToWStringHack(); | 273 *temp_file = temp_file_path.ToWStringHack(); |
368 return true; | 274 return true; |
369 } | 275 } |
| 276 bool Delete(const std::wstring& path, bool recursive) { |
| 277 return Delete(FilePath::FromWStringHack(path), recursive); |
| 278 } |
| 279 bool DirectoryExists(const std::wstring& path) { |
| 280 return DirectoryExists(FilePath::FromWStringHack(path)); |
| 281 } |
| 282 bool EndsWithSeparator(std::wstring* path) { |
| 283 return EndsWithSeparator(FilePath::FromWStringHack(*path)); |
| 284 } |
| 285 bool EndsWithSeparator(const std::wstring& path) { |
| 286 return EndsWithSeparator(FilePath::FromWStringHack(path)); |
| 287 } |
370 bool GetCurrentDirectory(std::wstring* path_str) { | 288 bool GetCurrentDirectory(std::wstring* path_str) { |
371 FilePath path; | 289 FilePath path; |
372 if (!GetCurrentDirectory(&path)) | 290 if (!GetCurrentDirectory(&path)) |
373 return false; | 291 return false; |
374 *path_str = path.ToWStringHack(); | 292 *path_str = path.ToWStringHack(); |
375 return true; | 293 return true; |
376 } | 294 } |
377 bool GetFileInfo(const std::wstring& file_path, FileInfo* results) { | 295 bool GetFileInfo(const std::wstring& file_path, FileInfo* results) { |
378 return GetFileInfo(FilePath::FromWStringHack(file_path), results); | 296 return GetFileInfo(FilePath::FromWStringHack(file_path), results); |
379 } | 297 } |
380 bool GetFileSize(const std::wstring& file_path, int64* file_size) { | 298 bool GetFileSize(const std::wstring& file_path, int64* file_size) { |
381 return GetFileSize(FilePath::FromWStringHack(file_path), file_size); | 299 return GetFileSize(FilePath::FromWStringHack(file_path), file_size); |
382 } | 300 } |
383 bool GetTempDir(std::wstring* path_str) { | 301 bool GetTempDir(std::wstring* path_str) { |
384 FilePath path; | 302 FilePath path; |
385 if (!GetTempDir(&path)) | 303 if (!GetTempDir(&path)) |
386 return false; | 304 return false; |
387 *path_str = path.ToWStringHack(); | 305 *path_str = path.ToWStringHack(); |
388 return true; | 306 return true; |
389 } | 307 } |
| 308 bool Move(const std::wstring& from_path, const std::wstring& to_path) { |
| 309 return Move(FilePath::FromWStringHack(from_path), |
| 310 FilePath::FromWStringHack(to_path)); |
| 311 } |
390 FILE* OpenFile(const std::wstring& filename, const char* mode) { | 312 FILE* OpenFile(const std::wstring& filename, const char* mode) { |
391 return OpenFile(FilePath::FromWStringHack(filename), mode); | 313 return OpenFile(FilePath::FromWStringHack(filename), mode); |
392 } | 314 } |
| 315 bool PathExists(const std::wstring& path) { |
| 316 return PathExists(FilePath::FromWStringHack(path)); |
| 317 } |
393 bool SetCurrentDirectory(const std::wstring& directory) { | 318 bool SetCurrentDirectory(const std::wstring& directory) { |
394 return SetCurrentDirectory(FilePath::FromWStringHack(directory)); | 319 return SetCurrentDirectory(FilePath::FromWStringHack(directory)); |
395 } | 320 } |
| 321 void TrimFilename(std::wstring* path) { |
| 322 if (EndsWithSeparator(path)) { |
| 323 TrimTrailingSeparator(path); |
| 324 } else { |
| 325 *path = FilePath::FromWStringHack(*path).DirName().ToWStringHack(); |
| 326 } |
| 327 } |
| 328 void UpOneDirectory(std::wstring* dir) { |
| 329 FilePath path = FilePath::FromWStringHack(*dir); |
| 330 *dir = path.DirName().ToWStringHack(); |
| 331 } |
| 332 void UpOneDirectoryOrEmpty(std::wstring* dir) { |
| 333 FilePath path = FilePath::FromWStringHack(*dir); |
| 334 FilePath directory = path.DirName(); |
396 | 335 |
| 336 if (directory == path) |
| 337 dir->clear(); |
| 338 else |
| 339 *dir = directory.ToWStringHack(); |
| 340 } |
397 } // namespace | 341 } // namespace |
398 | 342 |
OLD | NEW |