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