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