Home | History | Annotate | Download | only in base
      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