OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/sync/util/path_helpers.h" |
| 6 |
| 7 #include <Shlwapi.h> |
| 8 #include <stdlib.h> |
| 9 |
| 10 #include "base/logging.h" |
| 11 #include "base/port.h" |
| 12 #include "chrome/browser/sync/syncable/syncable.h" |
| 13 |
| 14 #ifndef OS_WINDOWS |
| 15 #error Compile this file on Windows only. |
| 16 #endif |
| 17 |
| 18 using std::string; |
| 19 |
| 20 #if OS_WINDOWS |
| 21 const char PATH_SEPARATOR = '\\'; |
| 22 #else |
| 23 const char PATH_SEPARATOR = '/'; |
| 24 #endif // OS_WINDOWS |
| 25 |
| 26 |
| 27 static PathString RemoveTrailingSlashes16(PathString str) { |
| 28 while ((str.length() > 0) && (str.at(str.length() - 1) == kPathSeparator[0])) |
| 29 str.resize(str.length() - 1); |
| 30 return str; |
| 31 } |
| 32 |
| 33 static string RemoveTrailingSlashes(string str) { |
| 34 while ((str.length() > 0) && (str.at(str.length() - 1) == PATH_SEPARATOR)) |
| 35 str.resize(str.length() - 1); |
| 36 return str; |
| 37 } |
| 38 |
| 39 PathString LastPathSegment(const PathString& path) { |
| 40 return RemoveTrailingSlashes16(PathFindFileNameW(path.c_str())); |
| 41 } |
| 42 |
| 43 string LastPathSegment(const string& path) { |
| 44 return RemoveTrailingSlashes(PathFindFileNameA(path.c_str())); |
| 45 } |
| 46 |
| 47 PathString GetFullPath(const PathString& path) { |
| 48 PathChar buffer[MAX_PATH]; |
| 49 PathChar* file_part; |
| 50 DWORD const size = GetFullPathName(path.c_str(), ARRAYSIZE(buffer), buffer, |
| 51 &file_part); |
| 52 return PathString(buffer, size); |
| 53 } |
| 54 |
| 55 PathString AppendSlash(const PathString& path) { |
| 56 PathString result(path); |
| 57 if (!result.empty()) { |
| 58 if (*result.rbegin() == '/') |
| 59 *result.rbegin() = '\\'; |
| 60 else if (*result.rbegin() != '\\') |
| 61 result.push_back('\\'); |
| 62 } |
| 63 return result; |
| 64 } |
| 65 |
| 66 PathString ExpandTilde(const PathString& path) { |
| 67 // Do nothing on windows. |
| 68 return path; |
| 69 } |
| 70 |
| 71 // Returns a string with length or fewer elements, careful to |
| 72 // not truncate a string mid-surrogate pair. |
| 73 PathString TruncatePathString(const PathString& original, int length) { |
| 74 if (original.size() <= length) |
| 75 return original; |
| 76 if (length <= 0) |
| 77 return original; |
| 78 PathString ret(original.begin(), original.begin() + length); |
| 79 COMPILE_ASSERT(sizeof(PathChar) == sizeof(uint16), PathStringNotUTF16); |
| 80 PathChar last_char = *ret.rbegin(); |
| 81 |
| 82 // Values taken from |
| 83 // http://en.wikipedia.org/w/index.php?title=UTF-16/UCS-2&oldid=248072840 |
| 84 if (last_char >= 0xD800 && last_char <= 0xDBFF) |
| 85 ret.resize(ret.size() - 1); |
| 86 return ret; |
| 87 } |
| 88 |
| 89 namespace { |
| 90 const PathString kWindowsIllegalBaseFilenames[] = { |
| 91 L"CON", L"PRN", L"AUX", L"NUL", L"COM1", L"COM2", |
| 92 L"COM3", L"COM4", L"COM5", L"COM6", L"COM7", |
| 93 L"COM8", L"COM9", L"LPT1", L"LPT2", L"LPT3", |
| 94 L"LPT4", L"LPT5", L"LPT6", L"LPT7", L"LPT8", |
| 95 L"LPT9" }; |
| 96 } |
| 97 |
| 98 // See: http://msdn.microsoft.com/library/default.asp?url=/library/ |
| 99 // en-us/fileio/fs/naming_a_file.asp |
| 100 // note that * and ? are not listed on the page as illegal characters, |
| 101 // but they are. |
| 102 PathString MakePathComponentOSLegal(const PathString& component) { |
| 103 CHECK(!component.empty()); |
| 104 PathString mutable_component = component; |
| 105 |
| 106 // Remove illegal characters. |
| 107 for (PathString::iterator i = mutable_component.begin(); |
| 108 i != mutable_component.end();) { |
| 109 if ((PathString::npos != PathString(L"<>:\"/\\|*?").find(*i)) || |
| 110 ((static_cast<unsigned short>(*i) >= 0) && |
| 111 (static_cast<unsigned short>(*i) <= 31))) { |
| 112 mutable_component.erase(i); |
| 113 } else { |
| 114 ++i; |
| 115 } |
| 116 } |
| 117 |
| 118 // Remove trailing spaces or periods. |
| 119 while (mutable_component.size() && |
| 120 ((mutable_component.at(mutable_component.size() - 1) == L' ') || |
| 121 (mutable_component.at(mutable_component.size() - 1) == L'.'))) |
| 122 mutable_component.resize(mutable_component.size() - 1, L' '); |
| 123 |
| 124 // Remove a bunch of forbidden names. windows only seems to mind if |
| 125 // a forbidden name matches our name exactly (e.g. "prn") or if the |
| 126 // name is the forbidden name, followed by a dot, followed by anything |
| 127 // (e.g., "prn.anything.foo.bar") |
| 128 |
| 129 // From this point out, we break mutable_component into two strings, and |
| 130 // use them this way: we save anything after and including the first dot |
| 131 // (usually the extension) and only mess with stuff before the first dot. |
| 132 PathString::size_type first_dot = mutable_component.find_first_of(L'.'); |
| 133 if (PathString::npos == first_dot) |
| 134 first_dot = mutable_component.size(); |
| 135 PathString sub = mutable_component.substr(0, first_dot); |
| 136 PathString postsub = mutable_component.substr(first_dot); |
| 137 CHECK(sub + postsub == mutable_component); |
| 138 for (int i = 0; i < ARRAYSIZE(kWindowsIllegalBaseFilenames); i++) { |
| 139 // ComparePathNames(a, b) == 0 -> same |
| 140 if (syncable::ComparePathNames(kWindowsIllegalBaseFilenames[i], sub) == 0) { |
| 141 sub.append(L"~1"); |
| 142 break; |
| 143 } |
| 144 } |
| 145 if ((L"" == sub) && (L"" == postsub)) { |
| 146 sub = L"~1"; |
| 147 } |
| 148 |
| 149 // Return the new name, only if it differs from the original. |
| 150 if ((sub + postsub) == component) |
| 151 return L""; |
| 152 return (sub + postsub); |
| 153 } |
OLD | NEW |