LCOV - app.info - ipc/chromium/src/base/file_path.cc

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-07-07 | 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