path.cc revision 46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd
1ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// found in the LICENSE file.
4ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "nacl_io/path.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "sdk_util/string_util.h"
1258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
13ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochnamespace nacl_io {
14ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)Path::Path() {
1646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Path::Path(const Path& path) {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  paths_ = path.paths_;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Path::Path(const std::string& path) {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Set(path);
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)Path::~Path() {
2746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Path::IsAbsolute() const {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !paths_.empty() && paths_[0] == "/";
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const std::string& Path::Part(size_t index) const {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return paths_[index];
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t Path::Size() const {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return paths_.size();
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Path::Top() const {
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return (paths_.size() == 0) || (paths_.size() == 1 && paths_[0] == "/");
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Path& Path::Append(const std::string& path) {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StringArray_t paths = Split(path);
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t index = 0; index < paths.size(); index++) {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Skip ROOT
5046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (paths_.size() && index == 0 && paths[0] == "/")
5146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      continue;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    paths_.push_back(paths[index]);
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  paths_ = Normalize(paths_);
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return *this;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Path& Path::Prepend(const std::string& path) {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StringArray_t paths = Split(path);
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t index = 0; index < paths_.size(); index++) {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Skip ROOT
6446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (index == 0 && paths_[0] == "/")
6546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      continue;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    paths.push_back(paths[index]);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  paths_ = Normalize(paths);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return *this;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Path& Path::Set(const std::string& path) {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StringArray_t paths = Split(path);
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  paths_ = Normalize(paths);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return *this;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Path Path::Parent() const {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Path out;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out.paths_ = paths_;
8146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (out.paths_.size())
8246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    out.paths_.pop_back();
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return out;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string Path::Basename() const {
8746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (paths_.size())
8846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return paths_.back();
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::string();
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string Path::Join() const {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Range(paths_, 0, paths_.size());
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string Path::Range(size_t start, size_t end) const {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Range(paths_, start, end);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StringArray_t Path::Split() const {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return paths_;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StringArray_t Path::Normalize(const StringArray_t& paths) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StringArray_t path_out;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t index = 0; index < paths.size(); index++) {
10946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const std::string& curr = paths[index];
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check if '/' was used excessively in the path.
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // For example, in cd Desktop/////
11346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (curr == "/" && index != 0)
11446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      continue;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check for '.' in the path and remove it
11746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (curr == ".")
11846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      continue;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check for '..'
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (curr == "..") {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If the path is empty, or "..", then add ".."
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (path_out.empty() || path_out.back() == "..") {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        path_out.push_back(curr);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If the path is at root, "/.." = "/"
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (path_out.back() == "/") {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // if we are already at root, then stay there (root/.. -> root)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (path_out.back() == "/") {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // otherwise, pop off the top path component
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      path_out.pop_back();
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // By now, we should have handled end cases so just append.
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    path_out.push_back(curr);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the path was valid, but now it's empty, return self
14846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (path_out.size() == 0)
14946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    path_out.push_back(".");
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return path_out;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string Path::Join(const StringArray_t& paths) {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Range(paths, 0, paths.size());
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string Path::Range(const StringArray_t& paths, size_t start, size_t end) {
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string out_path;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t index = start;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (end > paths.size())
16546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    end = paths.size();
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If this is an absolute path, paths[0] == "/". In this case, we don't want
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // to add an additional / separator.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (start == 0 && end > 0 && paths[0] == "/") {
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    out_path += "/";
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index++;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (; index < end; index++) {
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    out_path += paths[index];
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (index < end - 1)
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      out_path += "/";
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return out_path;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StringArray_t Path::Split(const std::string& path) {
18558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  StringArray_t path_split;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StringArray_t components;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  sdk_util::SplitString(path, '/', &path_split);
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (path[0] == '/')
19158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    components.push_back("/");
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Copy path_split to components, removing empty path segments.
19458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  for (StringArray_t::const_iterator it = path_split.begin();
19546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)       it != path_split.end();
19646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)       ++it) {
19746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (!it->empty())
19846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      components.push_back(*it);
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return components;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)Path& Path::operator=(const Path& p) {
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  paths_ = p.paths_;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return *this;
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)Path& Path::operator=(const std::string& p) {
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Set(p);
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
211eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
212ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}  // namespace nacl_io
213