Home | History | Annotate | Download | only in nacl_io
      1 // Copyright (c) 2012 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 "nacl_io/path.h"
      6 
      7 #include <stdio.h>
      8 #include <string.h>
      9 #include <string>
     10 
     11 #include "sdk_util/string_util.h"
     12 
     13 namespace nacl_io {
     14 
     15 Path::Path(const Path& path) {
     16   paths_ = path.paths_;
     17 }
     18 
     19 Path::Path(const std::string& path) {
     20   Set(path);
     21 }
     22 
     23 bool Path::IsAbsolute() const {
     24   return !paths_.empty() && paths_[0] == "/";
     25 }
     26 
     27 const std::string& Path::Part(size_t index) const {
     28   return paths_[index];
     29 }
     30 
     31 size_t Path::Size() const {
     32   return paths_.size();
     33 }
     34 
     35 bool Path::IsRoot() const {
     36   return paths_.empty() || (paths_.size() == 1 && paths_[0] == "/");
     37 }
     38 
     39 Path& Path::Append(const std::string& path) {
     40   StringArray_t paths = Split(path);
     41   if (paths.empty())
     42     return *this;
     43 
     44   for (size_t index = 0; index < paths.size(); index++) {
     45     // Skip ROOT
     46     if (paths_.size() && index == 0 && paths[0] == "/")
     47       continue;
     48     paths_.push_back(paths[index]);
     49   }
     50 
     51   paths_ = Normalize(paths_);
     52   return *this;
     53 }
     54 
     55 Path& Path::Prepend(const std::string& path) {
     56   StringArray_t paths = Split(path);
     57   if (paths.empty())
     58     return *this;
     59 
     60   for (size_t index = 0; index < paths_.size(); index++) {
     61     // Skip ROOT
     62     if (index == 0 && paths_[0] == "/")
     63       continue;
     64     paths.push_back(paths_[index]);
     65   }
     66 
     67   paths_ = Normalize(paths);
     68   return *this;
     69 }
     70 
     71 Path& Path::Set(const std::string& path) {
     72   StringArray_t paths = Split(path);
     73   paths_ = Normalize(paths);
     74   return *this;
     75 }
     76 
     77 Path Path::Parent() const {
     78   Path out;
     79   out.paths_ = paths_;
     80   if (out.paths_.size())
     81     out.paths_.pop_back();
     82   return out;
     83 }
     84 
     85 std::string Path::Basename() const {
     86   if (paths_.size())
     87     return paths_.back();
     88   return std::string();
     89 }
     90 
     91 std::string Path::Join() const {
     92   return Range(paths_, 0, paths_.size());
     93 }
     94 
     95 std::string Path::Range(size_t start, size_t end) const {
     96   return Range(paths_, start, end);
     97 }
     98 
     99 StringArray_t Path::Split() const {
    100   return paths_;
    101 }
    102 
    103 // static
    104 StringArray_t Path::Normalize(const StringArray_t& paths) {
    105   StringArray_t path_out;
    106 
    107   for (size_t index = 0; index < paths.size(); index++) {
    108     const std::string& curr = paths[index];
    109 
    110     // Check if '/' was used excessively in the path.
    111     // For example, in cd Desktop/////
    112     if (curr == "/" && index != 0)
    113       continue;
    114 
    115     // Check for '.' in the path and remove it
    116     if (curr == ".")
    117       continue;
    118 
    119     // Check for '..'
    120     if (curr == "..") {
    121       // If the path is empty, or "..", then add ".."
    122       if (path_out.empty() || path_out.back() == "..") {
    123         path_out.push_back(curr);
    124         continue;
    125       }
    126 
    127       // If the path is at root, "/.." = "/"
    128       if (path_out.back() == "/") {
    129         continue;
    130       }
    131 
    132       // if we are already at root, then stay there (root/.. -> root)
    133       if (path_out.back() == "/") {
    134         continue;
    135       }
    136 
    137       // otherwise, pop off the top path component
    138       path_out.pop_back();
    139       continue;
    140     }
    141 
    142     // By now, we should have handled end cases so just append.
    143     path_out.push_back(curr);
    144   }
    145 
    146   // If the path was valid, but now it's empty, return self
    147   if (path_out.empty())
    148     path_out.push_back(".");
    149 
    150   return path_out;
    151 }
    152 
    153 // static
    154 std::string Path::Join(const StringArray_t& paths) {
    155   return Range(paths, 0, paths.size());
    156 }
    157 
    158 // static
    159 std::string Path::Range(const StringArray_t& paths, size_t start, size_t end) {
    160   std::string out_path;
    161   size_t index = start;
    162 
    163   if (end > paths.size())
    164     end = paths.size();
    165 
    166   // If this is an absolute path, paths[0] == "/". In this case, we don't want
    167   // to add an additional / separator.
    168   if (start == 0 && end > 0 && paths[0] == "/") {
    169     out_path += "/";
    170     index++;
    171   }
    172 
    173   for (; index < end; index++) {
    174     out_path += paths[index];
    175     if (index < end - 1)
    176       out_path += "/";
    177   }
    178 
    179   return out_path;
    180 }
    181 
    182 // static
    183 StringArray_t Path::Split(const std::string& path) {
    184   StringArray_t path_split;
    185   StringArray_t components;
    186 
    187   sdk_util::SplitString(path, '/', &path_split);
    188 
    189   if (path[0] == '/')
    190     components.push_back("/");
    191 
    192   // Copy path_split to components, removing empty path segments.
    193   for (StringArray_t::const_iterator it = path_split.begin();
    194        it != path_split.end();
    195        ++it) {
    196     if (!it->empty())
    197       components.push_back(*it);
    198   }
    199   return components;
    200 }
    201 
    202 Path& Path::operator=(const Path& p) {
    203   paths_ = p.paths_;
    204   return *this;
    205 }
    206 
    207 Path& Path::operator=(const std::string& p) {
    208   return Set(p);
    209 }
    210 
    211 }  // namespace nacl_io
    212