1 /* 2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #if defined(WEBRTC_WIN) 12 #include "webrtc/base/win32.h" 13 #include <shellapi.h> 14 #include <shlobj.h> 15 #include <tchar.h> 16 #endif // WEBRTC_WIN 17 18 #include "webrtc/base/common.h" 19 #include "webrtc/base/fileutils.h" 20 #include "webrtc/base/logging.h" 21 #include "webrtc/base/pathutils.h" 22 #include "webrtc/base/stringutils.h" 23 #include "webrtc/base/urlencode.h" 24 25 namespace rtc { 26 27 static const char EMPTY_STR[] = ""; 28 29 // EXT_DELIM separates a file basename from extension 30 const char EXT_DELIM = '.'; 31 32 // FOLDER_DELIMS separate folder segments and the filename 33 const char* const FOLDER_DELIMS = "/\\"; 34 35 // DEFAULT_FOLDER_DELIM is the preferred delimiter for this platform 36 #if WEBRTC_WIN 37 const char DEFAULT_FOLDER_DELIM = '\\'; 38 #else // !WEBRTC_WIN 39 const char DEFAULT_FOLDER_DELIM = '/'; 40 #endif // !WEBRTC_WIN 41 42 /////////////////////////////////////////////////////////////////////////////// 43 // Pathname - parsing of pathnames into components, and vice versa 44 /////////////////////////////////////////////////////////////////////////////// 45 46 bool Pathname::IsFolderDelimiter(char ch) { 47 return (NULL != ::strchr(FOLDER_DELIMS, ch)); 48 } 49 50 char Pathname::DefaultFolderDelimiter() { 51 return DEFAULT_FOLDER_DELIM; 52 } 53 54 Pathname::Pathname() 55 : folder_delimiter_(DEFAULT_FOLDER_DELIM) { 56 } 57 58 Pathname::Pathname(const std::string& pathname) 59 : folder_delimiter_(DEFAULT_FOLDER_DELIM) { 60 SetPathname(pathname); 61 } 62 63 Pathname::Pathname(const std::string& folder, const std::string& filename) 64 : folder_delimiter_(DEFAULT_FOLDER_DELIM) { 65 SetPathname(folder, filename); 66 } 67 68 void Pathname::SetFolderDelimiter(char delimiter) { 69 ASSERT(IsFolderDelimiter(delimiter)); 70 folder_delimiter_ = delimiter; 71 } 72 73 void Pathname::Normalize() { 74 for (size_t i=0; i<folder_.length(); ++i) { 75 if (IsFolderDelimiter(folder_[i])) { 76 folder_[i] = folder_delimiter_; 77 } 78 } 79 } 80 81 void Pathname::clear() { 82 folder_.clear(); 83 basename_.clear(); 84 extension_.clear(); 85 } 86 87 bool Pathname::empty() const { 88 return folder_.empty() && basename_.empty() && extension_.empty(); 89 } 90 91 std::string Pathname::pathname() const { 92 std::string pathname(folder_); 93 pathname.append(basename_); 94 pathname.append(extension_); 95 if (pathname.empty()) { 96 // Instead of the empty pathname, return the current working directory. 97 pathname.push_back('.'); 98 pathname.push_back(folder_delimiter_); 99 } 100 return pathname; 101 } 102 103 std::string Pathname::url() const { 104 std::string s = "file:///"; 105 for (size_t i=0; i<folder_.length(); ++i) { 106 if (IsFolderDelimiter(folder_[i])) 107 s += '/'; 108 else 109 s += folder_[i]; 110 } 111 s += basename_; 112 s += extension_; 113 return UrlEncodeStringForOnlyUnsafeChars(s); 114 } 115 116 void Pathname::SetPathname(const std::string& pathname) { 117 std::string::size_type pos = pathname.find_last_of(FOLDER_DELIMS); 118 if (pos != std::string::npos) { 119 SetFolder(pathname.substr(0, pos + 1)); 120 SetFilename(pathname.substr(pos + 1)); 121 } else { 122 SetFolder(EMPTY_STR); 123 SetFilename(pathname); 124 } 125 } 126 127 void Pathname::SetPathname(const std::string& folder, 128 const std::string& filename) { 129 SetFolder(folder); 130 SetFilename(filename); 131 } 132 133 void Pathname::AppendPathname(const std::string& pathname) { 134 std::string full_pathname(folder_); 135 full_pathname.append(pathname); 136 SetPathname(full_pathname); 137 } 138 139 std::string Pathname::folder() const { 140 return folder_; 141 } 142 143 std::string Pathname::folder_name() const { 144 std::string::size_type pos = std::string::npos; 145 if (folder_.size() >= 2) { 146 pos = folder_.find_last_of(FOLDER_DELIMS, folder_.length() - 2); 147 } 148 if (pos != std::string::npos) { 149 return folder_.substr(pos + 1); 150 } else { 151 return folder_; 152 } 153 } 154 155 std::string Pathname::parent_folder() const { 156 std::string::size_type pos = std::string::npos; 157 if (folder_.size() >= 2) { 158 pos = folder_.find_last_of(FOLDER_DELIMS, folder_.length() - 2); 159 } 160 if (pos != std::string::npos) { 161 return folder_.substr(0, pos + 1); 162 } else { 163 return EMPTY_STR; 164 } 165 } 166 167 void Pathname::SetFolder(const std::string& folder) { 168 folder_.assign(folder); 169 // Ensure folder ends in a path delimiter 170 if (!folder_.empty() && !IsFolderDelimiter(folder_[folder_.length()-1])) { 171 folder_.push_back(folder_delimiter_); 172 } 173 } 174 175 void Pathname::AppendFolder(const std::string& folder) { 176 folder_.append(folder); 177 // Ensure folder ends in a path delimiter 178 if (!folder_.empty() && !IsFolderDelimiter(folder_[folder_.length()-1])) { 179 folder_.push_back(folder_delimiter_); 180 } 181 } 182 183 std::string Pathname::basename() const { 184 return basename_; 185 } 186 187 bool Pathname::SetBasename(const std::string& basename) { 188 if(basename.find_first_of(FOLDER_DELIMS) != std::string::npos) { 189 return false; 190 } 191 basename_.assign(basename); 192 return true; 193 } 194 195 std::string Pathname::extension() const { 196 return extension_; 197 } 198 199 bool Pathname::SetExtension(const std::string& extension) { 200 if (extension.find_first_of(FOLDER_DELIMS) != std::string::npos || 201 extension.find_first_of(EXT_DELIM, 1) != std::string::npos) { 202 return false; 203 } 204 extension_.assign(extension); 205 // Ensure extension begins with the extension delimiter 206 if (!extension_.empty() && (extension_[0] != EXT_DELIM)) { 207 extension_.insert(extension_.begin(), EXT_DELIM); 208 } 209 return true; 210 } 211 212 std::string Pathname::filename() const { 213 std::string filename(basename_); 214 filename.append(extension_); 215 return filename; 216 } 217 218 bool Pathname::SetFilename(const std::string& filename) { 219 std::string::size_type pos = filename.rfind(EXT_DELIM); 220 if ((pos == std::string::npos) || (pos == 0)) { 221 return SetExtension(EMPTY_STR) && SetBasename(filename); 222 } else { 223 return SetExtension(filename.substr(pos)) && SetBasename(filename.substr(0, pos)); 224 } 225 } 226 227 #if defined(WEBRTC_WIN) 228 bool Pathname::GetDrive(char* drive, uint32_t bytes) const { 229 return GetDrive(drive, bytes, folder_); 230 } 231 232 // static 233 bool Pathname::GetDrive(char* drive, 234 uint32_t bytes, 235 const std::string& pathname) { 236 // need at lease 4 bytes to save c: 237 if (bytes < 4 || pathname.size() < 3) { 238 return false; 239 } 240 241 memcpy(drive, pathname.c_str(), 3); 242 drive[3] = 0; 243 // sanity checking 244 return (isalpha(drive[0]) && 245 drive[1] == ':' && 246 drive[2] == '\\'); 247 } 248 #endif 249 250 /////////////////////////////////////////////////////////////////////////////// 251 252 } // namespace rtc 253