1/* 2 * libjingle 3 * Copyright 2004--2005, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#ifdef WIN32 29#include "talk/base/win32.h" 30#include <shellapi.h> 31#include <shlobj.h> 32#include <tchar.h> 33#endif // WIN32 34 35#include "talk/base/common.h" 36#include "talk/base/fileutils.h" 37#include "talk/base/logging.h" 38#include "talk/base/pathutils.h" 39#include "talk/base/stringutils.h" 40#include "talk/base/urlencode.h" 41 42namespace talk_base { 43 44std::string const EMPTY_STR = ""; 45 46// EXT_DELIM separates a file basename from extension 47const char EXT_DELIM = '.'; 48 49// FOLDER_DELIMS separate folder segments and the filename 50const char* const FOLDER_DELIMS = "/\\"; 51 52// DEFAULT_FOLDER_DELIM is the preferred delimiter for this platform 53#if WIN32 54const char DEFAULT_FOLDER_DELIM = '\\'; 55#else // !WIN32 56const char DEFAULT_FOLDER_DELIM = '/'; 57#endif // !WIN32 58 59/////////////////////////////////////////////////////////////////////////////// 60// Pathname - parsing of pathnames into components, and vice versa 61/////////////////////////////////////////////////////////////////////////////// 62 63bool Pathname::IsFolderDelimiter(char ch) { 64 return (NULL != ::strchr(FOLDER_DELIMS, ch)); 65} 66 67char Pathname::DefaultFolderDelimiter() { 68 return DEFAULT_FOLDER_DELIM; 69} 70 71Pathname::Pathname() 72 : folder_delimiter_(DEFAULT_FOLDER_DELIM) { 73} 74 75Pathname::Pathname(const std::string& pathname) 76 : folder_delimiter_(DEFAULT_FOLDER_DELIM) { 77 SetPathname(pathname); 78} 79 80Pathname::Pathname(const std::string& folder, const std::string& filename) 81 : folder_delimiter_(DEFAULT_FOLDER_DELIM) { 82 SetPathname(folder, filename); 83} 84 85void Pathname::SetFolderDelimiter(char delimiter) { 86 ASSERT(IsFolderDelimiter(delimiter)); 87 folder_delimiter_ = delimiter; 88} 89 90void Pathname::Normalize() { 91 for (size_t i=0; i<folder_.length(); ++i) { 92 if (IsFolderDelimiter(folder_[i])) { 93 folder_[i] = folder_delimiter_; 94 } 95 } 96} 97 98void Pathname::clear() { 99 folder_.clear(); 100 basename_.clear(); 101 extension_.clear(); 102} 103 104bool Pathname::empty() const { 105 return folder_.empty() && basename_.empty() && extension_.empty(); 106} 107 108std::string Pathname::pathname() const { 109 std::string pathname(folder_); 110 pathname.append(basename_); 111 pathname.append(extension_); 112 if (pathname.empty()) { 113 // Instead of the empty pathname, return the current working directory. 114 pathname.push_back('.'); 115 pathname.push_back(folder_delimiter_); 116 } 117 return pathname; 118} 119 120std::string Pathname::url() const { 121 std::string s = "file:///"; 122 for (size_t i=0; i<folder_.length(); ++i) { 123 if (IsFolderDelimiter(folder_[i])) 124 s += '/'; 125 else 126 s += folder_[i]; 127 } 128 s += basename_; 129 s += extension_; 130 return UrlEncodeStringForOnlyUnsafeChars(s); 131} 132 133void Pathname::SetPathname(const std::string& pathname) { 134 std::string::size_type pos = pathname.find_last_of(FOLDER_DELIMS); 135 if (pos != std::string::npos) { 136 SetFolder(pathname.substr(0, pos + 1)); 137 SetFilename(pathname.substr(pos + 1)); 138 } else { 139 SetFolder(EMPTY_STR); 140 SetFilename(pathname); 141 } 142} 143 144void Pathname::SetPathname(const std::string& folder, 145 const std::string& filename) { 146 SetFolder(folder); 147 SetFilename(filename); 148} 149 150void Pathname::AppendPathname(const std::string& pathname) { 151 std::string full_pathname(folder_); 152 full_pathname.append(pathname); 153 SetPathname(full_pathname); 154} 155 156std::string Pathname::folder() const { 157 return folder_; 158} 159 160std::string Pathname::folder_name() const { 161 std::string::size_type pos = std::string::npos; 162 if (folder_.size() >= 2) { 163 pos = folder_.find_last_of(FOLDER_DELIMS, folder_.length() - 2); 164 } 165 if (pos != std::string::npos) { 166 return folder_.substr(pos + 1); 167 } else { 168 return folder_; 169 } 170} 171 172std::string Pathname::parent_folder() const { 173 std::string::size_type pos = std::string::npos; 174 if (folder_.size() >= 2) { 175 pos = folder_.find_last_of(FOLDER_DELIMS, folder_.length() - 2); 176 } 177 if (pos != std::string::npos) { 178 return folder_.substr(0, pos + 1); 179 } else { 180 return EMPTY_STR; 181 } 182} 183 184void Pathname::SetFolder(const std::string& folder) { 185 folder_.assign(folder); 186 // Ensure folder ends in a path delimiter 187 if (!folder_.empty() && !IsFolderDelimiter(folder_[folder_.length()-1])) { 188 folder_.push_back(folder_delimiter_); 189 } 190} 191 192void Pathname::AppendFolder(const std::string& folder) { 193 folder_.append(folder); 194 // Ensure folder ends in a path delimiter 195 if (!folder_.empty() && !IsFolderDelimiter(folder_[folder_.length()-1])) { 196 folder_.push_back(folder_delimiter_); 197 } 198} 199 200std::string Pathname::basename() const { 201 return basename_; 202} 203 204bool Pathname::SetBasename(const std::string& basename) { 205 if(basename.find_first_of(FOLDER_DELIMS) != std::string::npos) { 206 return false; 207 } 208 basename_.assign(basename); 209 return true; 210} 211 212std::string Pathname::extension() const { 213 return extension_; 214} 215 216bool Pathname::SetExtension(const std::string& extension) { 217 if (extension.find_first_of(FOLDER_DELIMS) != std::string::npos || 218 extension.find_first_of(EXT_DELIM, 1) != std::string::npos) { 219 return false; 220 } 221 extension_.assign(extension); 222 // Ensure extension begins with the extension delimiter 223 if (!extension_.empty() && (extension_[0] != EXT_DELIM)) { 224 extension_.insert(extension_.begin(), EXT_DELIM); 225 } 226 return true; 227} 228 229std::string Pathname::filename() const { 230 std::string filename(basename_); 231 filename.append(extension_); 232 return filename; 233} 234 235bool Pathname::SetFilename(const std::string& filename) { 236 std::string::size_type pos = filename.rfind(EXT_DELIM); 237 if ((pos == std::string::npos) || (pos == 0)) { 238 return SetExtension(EMPTY_STR) && SetBasename(filename); 239 } else { 240 return SetExtension(filename.substr(pos)) && SetBasename(filename.substr(0, pos)); 241 } 242} 243 244#ifdef WIN32 245bool Pathname::GetDrive(char *drive, uint32 bytes) const { 246 return GetDrive(drive, bytes, folder_); 247} 248 249// static 250bool Pathname::GetDrive(char *drive, uint32 bytes, 251 const std::string& pathname) { 252 // need at lease 4 bytes to save c: 253 if (bytes < 4 || pathname.size() < 3) { 254 return false; 255 } 256 257 memcpy(drive, pathname.c_str(), 3); 258 drive[3] = 0; 259 // sanity checking 260 return (isalpha(drive[0]) && 261 drive[1] == ':' && 262 drive[2] == '\\'); 263} 264#endif 265 266/////////////////////////////////////////////////////////////////////////////// 267 268} // namespace talk_base 269