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