LCOV - code coverage report
Current view: directory - ipc/chromium/src/base - file_path.cc (source / functions) Found Hit Coverage
Test: app.info Lines: 122 0 0.0 %
Date: 2012-06-02 Functions: 18 0 0.0 %

       1                 : // Copyright (c) 2008 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 <fstream>
       6                 : 
       7                 : #include "base/file_path.h"
       8                 : #include "base/logging.h"
       9                 : 
      10                 : // These includes are just for the *Hack functions, and should be removed
      11                 : // when those functions are removed.
      12                 : #include "base/string_piece.h"
      13                 : #include "base/string_util.h"
      14                 : #include "base/sys_string_conversions.h"
      15                 : 
      16                 : #if defined(FILE_PATH_USES_WIN_SEPARATORS)
      17                 : const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("\\/");
      18                 : #else  // FILE_PATH_USES_WIN_SEPARATORS
      19                 : const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("/");
      20                 : #endif  // FILE_PATH_USES_WIN_SEPARATORS
      21                 : 
      22                 : const FilePath::CharType FilePath::kCurrentDirectory[] = FILE_PATH_LITERAL(".");
      23                 : const FilePath::CharType FilePath::kParentDirectory[] = FILE_PATH_LITERAL("..");
      24                 : 
      25                 : const FilePath::CharType FilePath::kExtensionSeparator = FILE_PATH_LITERAL('.');
      26                 : 
      27                 : 
      28                 : namespace {
      29                 : 
      30                 : // If this FilePath contains a drive letter specification, returns the
      31                 : // position of the last character of the drive letter specification,
      32                 : // otherwise returns npos.  This can only be true on Windows, when a pathname
      33                 : // begins with a letter followed by a colon.  On other platforms, this always
      34                 : // returns npos.
      35               0 : FilePath::StringType::size_type FindDriveLetter(
      36                 :     const FilePath::StringType& path) {
      37                 : #if defined(FILE_PATH_USES_DRIVE_LETTERS)
      38                 :   // This is dependent on an ASCII-based character set, but that's a
      39                 :   // reasonable assumption.  iswalpha can be too inclusive here.
      40                 :   if (path.length() >= 2 && path[1] == L':' &&
      41                 :       ((path[0] >= L'A' && path[0] <= L'Z') ||
      42                 :        (path[0] >= L'a' && path[0] <= L'z'))) {
      43                 :     return 1;
      44                 :   }
      45                 : #endif  // FILE_PATH_USES_DRIVE_LETTERS
      46               0 :   return FilePath::StringType::npos;
      47                 : }
      48                 : 
      49               0 : bool IsPathAbsolute(const FilePath::StringType& path) {
      50                 : #if defined(FILE_PATH_USES_DRIVE_LETTERS)
      51                 :   FilePath::StringType::size_type letter = FindDriveLetter(path);
      52                 :   if (letter != FilePath::StringType::npos) {
      53                 :     // Look for a separator right after the drive specification.
      54                 :     return path.length() > letter + 1 &&
      55                 :         FilePath::IsSeparator(path[letter + 1]);
      56                 :   }
      57                 :   // Look for a pair of leading separators.
      58                 :   return path.length() > 1 &&
      59                 :       FilePath::IsSeparator(path[0]) && FilePath::IsSeparator(path[1]);
      60                 : #else  // FILE_PATH_USES_DRIVE_LETTERS
      61                 :   // Look for a separator in the first position.
      62               0 :   return path.length() > 0 && FilePath::IsSeparator(path[0]);
      63                 : #endif  // FILE_PATH_USES_DRIVE_LETTERS
      64                 : }
      65                 : 
      66                 : }  // namespace
      67                 : 
      68               0 : bool FilePath::IsSeparator(CharType character) {
      69               0 :   for (size_t i = 0; i < arraysize(kSeparators) - 1; ++i) {
      70               0 :     if (character == kSeparators[i]) {
      71               0 :       return true;
      72                 :     }
      73                 :   }
      74                 : 
      75               0 :   return false;
      76                 : }
      77                 : 
      78                 : // libgen's dirname and basename aren't guaranteed to be thread-safe and aren't
      79                 : // guaranteed to not modify their input strings, and in fact are implemented
      80                 : // differently in this regard on different platforms.  Don't use them, but
      81                 : // adhere to their behavior.
      82               0 : FilePath FilePath::DirName() const {
      83               0 :   FilePath new_path(path_);
      84               0 :   new_path.StripTrailingSeparatorsInternal();
      85                 : 
      86                 :   // The drive letter, if any, always needs to remain in the output.  If there
      87                 :   // is no drive letter, as will always be the case on platforms which do not
      88                 :   // support drive letters, letter will be npos, or -1, so the comparisons and
      89                 :   // resizes below using letter will still be valid.
      90               0 :   StringType::size_type letter = FindDriveLetter(new_path.path_);
      91                 : 
      92                 :   StringType::size_type last_separator =
      93                 :       new_path.path_.find_last_of(kSeparators, StringType::npos,
      94               0 :                                   arraysize(kSeparators) - 1);
      95               0 :   if (last_separator == StringType::npos) {
      96                 :     // path_ is in the current directory.
      97               0 :     new_path.path_.resize(letter + 1);
      98               0 :   } else if (last_separator == letter + 1) {
      99                 :     // path_ is in the root directory.
     100               0 :     new_path.path_.resize(letter + 2);
     101               0 :   } else if (last_separator == letter + 2 &&
     102               0 :              IsSeparator(new_path.path_[letter + 1])) {
     103                 :     // path_ is in "//" (possibly with a drive letter); leave the double
     104                 :     // separator intact indicating alternate root.
     105               0 :     new_path.path_.resize(letter + 3);
     106               0 :   } else if (last_separator != 0) {
     107                 :     // path_ is somewhere else, trim the basename.
     108               0 :     new_path.path_.resize(last_separator);
     109                 :   }
     110                 : 
     111               0 :   new_path.StripTrailingSeparatorsInternal();
     112               0 :   if (!new_path.path_.length())
     113               0 :     new_path.path_ = kCurrentDirectory;
     114                 : 
     115                 :   return new_path;
     116                 : }
     117                 : 
     118               0 : FilePath FilePath::BaseName() const {
     119               0 :   FilePath new_path(path_);
     120               0 :   new_path.StripTrailingSeparatorsInternal();
     121                 : 
     122                 :   // The drive letter, if any, is always stripped.
     123               0 :   StringType::size_type letter = FindDriveLetter(new_path.path_);
     124               0 :   if (letter != StringType::npos) {
     125               0 :     new_path.path_.erase(0, letter + 1);
     126                 :   }
     127                 : 
     128                 :   // Keep everything after the final separator, but if the pathname is only
     129                 :   // one character and it's a separator, leave it alone.
     130                 :   StringType::size_type last_separator =
     131                 :       new_path.path_.find_last_of(kSeparators, StringType::npos,
     132               0 :                                   arraysize(kSeparators) - 1);
     133               0 :   if (last_separator != StringType::npos &&
     134               0 :       last_separator < new_path.path_.length() - 1) {
     135               0 :     new_path.path_.erase(0, last_separator + 1);
     136                 :   }
     137                 : 
     138                 :   return new_path;
     139                 : }
     140                 : 
     141               0 : FilePath::StringType FilePath::Extension() const {
     142                 :   // BaseName() calls StripTrailingSeparators, so cases like /foo.baz/// work.
     143               0 :   StringType base = BaseName().value();
     144                 : 
     145                 :   // Special case "." and ".."
     146               0 :   if (base == kCurrentDirectory || base == kParentDirectory)
     147               0 :     return StringType();
     148                 : 
     149               0 :   const StringType::size_type last_dot = base.rfind(kExtensionSeparator);
     150               0 :   if (last_dot == StringType::npos)
     151               0 :     return StringType();
     152               0 :   return StringType(base, last_dot);
     153                 : }
     154                 : 
     155               0 : FilePath FilePath::RemoveExtension() const {
     156               0 :   StringType ext = Extension();
     157                 :   // It's important to check Extension() since that verifies that the
     158                 :   // kExtensionSeparator actually appeared in the last path component.
     159               0 :   if (ext.empty())
     160               0 :     return FilePath(path_);
     161                 :   // Since Extension() verified that the extension is in fact in the last path
     162                 :   // component, this substr will effectively strip trailing separators.
     163               0 :   const StringType::size_type last_dot = path_.rfind(kExtensionSeparator);
     164               0 :   return FilePath(path_.substr(0, last_dot));
     165                 : }
     166                 : 
     167               0 : FilePath FilePath::InsertBeforeExtension(const StringType& suffix) const {
     168               0 :   if (suffix.empty())
     169               0 :     return FilePath(path_);
     170                 : 
     171               0 :   if (path_.empty())
     172               0 :     return FilePath();
     173                 : 
     174               0 :   StringType base = BaseName().value();
     175               0 :   if (base.empty())
     176               0 :     return FilePath();
     177               0 :   if (*(base.end() - 1) == kExtensionSeparator) {
     178                 :     // Special case "." and ".."
     179               0 :     if (base == kCurrentDirectory || base == kParentDirectory) {
     180               0 :       return FilePath();
     181                 :     }
     182                 :   }
     183                 : 
     184               0 :   StringType ext = Extension();
     185               0 :   StringType ret = RemoveExtension().value();
     186               0 :   ret.append(suffix);
     187               0 :   ret.append(ext);
     188               0 :   return FilePath(ret);
     189                 : }
     190                 : 
     191               0 : FilePath FilePath::ReplaceExtension(const StringType& extension) const {
     192               0 :   if (path_.empty())
     193               0 :     return FilePath();
     194                 : 
     195               0 :   StringType base = BaseName().value();
     196               0 :   if (base.empty())
     197               0 :     return FilePath();
     198               0 :   if (*(base.end() - 1) == kExtensionSeparator) {
     199                 :     // Special case "." and ".."
     200               0 :     if (base == kCurrentDirectory || base == kParentDirectory) {
     201               0 :       return FilePath();
     202                 :     }
     203                 :   }
     204                 : 
     205               0 :   FilePath no_ext = RemoveExtension();
     206                 :   // If the new extension is "" or ".", then just remove the current extension.
     207               0 :   if (extension.empty() || extension == StringType(1, kExtensionSeparator))
     208               0 :     return no_ext;
     209                 : 
     210               0 :   StringType str = no_ext.value();
     211               0 :   if (extension[0] != kExtensionSeparator)
     212               0 :     str.append(1, kExtensionSeparator);
     213               0 :   str.append(extension);
     214               0 :   return FilePath(str);
     215                 : }
     216                 : 
     217               0 : FilePath FilePath::Append(const StringType& component) const {
     218               0 :   DCHECK(!IsPathAbsolute(component));
     219               0 :   if (path_.compare(kCurrentDirectory) == 0) {
     220                 :     // Append normally doesn't do any normalization, but as a special case,
     221                 :     // when appending to kCurrentDirectory, just return a new path for the
     222                 :     // component argument.  Appending component to kCurrentDirectory would
     223                 :     // serve no purpose other than needlessly lengthening the path, and
     224                 :     // it's likely in practice to wind up with FilePath objects containing
     225                 :     // only kCurrentDirectory when calling DirName on a single relative path
     226                 :     // component.
     227               0 :     return FilePath(component);
     228                 :   }
     229                 : 
     230               0 :   FilePath new_path(path_);
     231               0 :   new_path.StripTrailingSeparatorsInternal();
     232                 : 
     233                 :   // Don't append a separator if the path is empty (indicating the current
     234                 :   // directory) or if the path component is empty (indicating nothing to
     235                 :   // append).
     236               0 :   if (component.length() > 0 && new_path.path_.length() > 0) {
     237                 : 
     238                 :     // Don't append a separator if the path still ends with a trailing
     239                 :     // separator after stripping (indicating the root directory).
     240               0 :     if (!IsSeparator(new_path.path_[new_path.path_.length() - 1])) {
     241                 : 
     242                 :       // Don't append a separator if the path is just a drive letter.
     243               0 :       if (FindDriveLetter(new_path.path_) + 1 != new_path.path_.length()) {
     244               0 :         new_path.path_.append(1, kSeparators[0]);
     245                 :       }
     246                 :     }
     247                 :   }
     248                 : 
     249               0 :   new_path.path_.append(component);
     250               0 :   return new_path;
     251                 : }
     252                 : 
     253               0 : FilePath FilePath::Append(const FilePath& component) const {
     254               0 :   return Append(component.value());
     255                 : }
     256                 : 
     257               0 : FilePath FilePath::AppendASCII(const std::string& component) const {
     258               0 :   DCHECK(IsStringASCII(component));
     259                 : #if defined(OS_WIN)
     260                 :   return Append(ASCIIToWide(component));
     261                 : #elif defined(OS_POSIX)
     262               0 :   return Append(component);
     263                 : #endif
     264                 : }
     265                 : 
     266               0 : bool FilePath::IsAbsolute() const {
     267               0 :   return IsPathAbsolute(path_);
     268                 : }
     269                 : 
     270                 : #if defined(OS_POSIX)
     271                 : // See file_path.h for a discussion of the encoding of paths on POSIX
     272                 : // platforms.  These *Hack() functions are not quite correct, but they're
     273                 : // only temporary while we fix the remainder of the code.
     274                 : // Remember to remove the #includes at the top when you remove these.
     275                 : 
     276                 : // static
     277               0 : FilePath FilePath::FromWStringHack(const std::wstring& wstring) {
     278               0 :   return FilePath(base::SysWideToNativeMB(wstring));
     279                 : }
     280               0 : std::wstring FilePath::ToWStringHack() const {
     281               0 :   return base::SysNativeMBToWide(path_);
     282                 : }
     283                 : #elif defined(OS_WIN)
     284                 : // static
     285                 : FilePath FilePath::FromWStringHack(const std::wstring& wstring) {
     286                 :   return FilePath(wstring);
     287                 : }
     288                 : std::wstring FilePath::ToWStringHack() const {
     289                 :   return path_;
     290                 : }
     291                 : #endif
     292                 : 
     293               0 : void FilePath::OpenInputStream(std::ifstream& stream) const {
     294                 :   stream.open(
     295                 : #ifndef __MINGW32__
     296                 :               path_.c_str(),
     297                 : #else
     298                 :               base::SysWideToNativeMB(path_).c_str(),
     299                 : #endif
     300               0 :               std::ios::in | std::ios::binary);
     301               0 : }
     302                 : 
     303               0 : FilePath FilePath::StripTrailingSeparators() const {
     304               0 :   FilePath new_path(path_);
     305               0 :   new_path.StripTrailingSeparatorsInternal();
     306                 : 
     307                 :   return new_path;
     308                 : }
     309                 : 
     310               0 : void FilePath::StripTrailingSeparatorsInternal() {
     311                 :   // If there is no drive letter, start will be 1, which will prevent stripping
     312                 :   // the leading separator if there is only one separator.  If there is a drive
     313                 :   // letter, start will be set appropriately to prevent stripping the first
     314                 :   // separator following the drive letter, if a separator immediately follows
     315                 :   // the drive letter.
     316               0 :   StringType::size_type start = FindDriveLetter(path_) + 2;
     317                 : 
     318               0 :   StringType::size_type last_stripped = StringType::npos;
     319               0 :   for (StringType::size_type pos = path_.length();
     320               0 :        pos > start && IsSeparator(path_[pos - 1]);
     321                 :        --pos) {
     322                 :     // If the string only has two separators and they're at the beginning,
     323                 :     // don't strip them, unless the string began with more than two separators.
     324               0 :     if (pos != start + 1 || last_stripped == start + 2 ||
     325               0 :         !IsSeparator(path_[start - 1])) {
     326               0 :       path_.resize(pos - 1);
     327               0 :       last_stripped = pos;
     328                 :     }
     329                 :   }
     330               0 : }

Generated by: LCOV version 1.7