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
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Path::Path(const Path& path) {
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  paths_ = path.paths_;
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Path::Path(const std::string& path) {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Set(path);
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Path::IsAbsolute() const {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !paths_.empty() && paths_[0] == "/";
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const std::string& Path::Part(size_t index) const {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return paths_[index];
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t Path::Size() const {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return paths_.size();
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool Path::IsRoot() const {
36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return paths_.empty() || (paths_.size() == 1 && paths_[0] == "/");
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Path& Path::Append(const std::string& path) {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StringArray_t paths = Split(path);
41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (paths.empty())
42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return *this;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t index = 0; index < paths.size(); index++) {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Skip ROOT
4646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (paths_.size() && index == 0 && paths[0] == "/")
4746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      continue;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    paths_.push_back(paths[index]);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  paths_ = Normalize(paths_);
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return *this;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Path& Path::Prepend(const std::string& path) {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StringArray_t paths = Split(path);
57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (paths.empty())
58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return *this;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t index = 0; index < paths_.size(); index++) {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Skip ROOT
6246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (index == 0 && paths_[0] == "/")
6346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      continue;
64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    paths.push_back(paths_[index]);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  paths_ = Normalize(paths);
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return *this;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Path& Path::Set(const std::string& path) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StringArray_t paths = Split(path);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  paths_ = Normalize(paths);
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return *this;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Path Path::Parent() const {
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Path out;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out.paths_ = paths_;
8046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (out.paths_.size())
8146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    out.paths_.pop_back();
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return out;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string Path::Basename() const {
8646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (paths_.size())
8746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return paths_.back();
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::string();
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string Path::Join() const {
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Range(paths_, 0, paths_.size());
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string Path::Range(size_t start, size_t end) const {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Range(paths_, start, end);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StringArray_t Path::Split() const {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return paths_;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StringArray_t Path::Normalize(const StringArray_t& paths) {
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StringArray_t path_out;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t index = 0; index < paths.size(); index++) {
10846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const std::string& curr = paths[index];
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check if '/' was used excessively in the path.
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // For example, in cd Desktop/////
11246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (curr == "/" && index != 0)
11346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      continue;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check for '.' in the path and remove it
11646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (curr == ".")
11746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      continue;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check for '..'
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (curr == "..") {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If the path is empty, or "..", then add ".."
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (path_out.empty() || path_out.back() == "..") {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        path_out.push_back(curr);
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If the path is at root, "/.." = "/"
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (path_out.back() == "/") {
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // if we are already at root, then stay there (root/.. -> root)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (path_out.back() == "/") {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // otherwise, pop off the top path component
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      path_out.pop_back();
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // By now, we should have handled end cases so just append.
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    path_out.push_back(curr);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the path was valid, but now it's empty, return self
147f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (path_out.empty())
14846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    path_out.push_back(".");
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return path_out;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string Path::Join(const StringArray_t& paths) {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Range(paths, 0, paths.size());
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string Path::Range(const StringArray_t& paths, size_t start, size_t end) {
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string out_path;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t index = start;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (end > paths.size())
16446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    end = paths.size();
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If this is an absolute path, paths[0] == "/". In this case, we don't want
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // to add an additional / separator.
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (start == 0 && end > 0 && paths[0] == "/") {
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    out_path += "/";
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index++;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (; index < end; index++) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    out_path += paths[index];
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (index < end - 1)
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      out_path += "/";
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return out_path;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StringArray_t Path::Split(const std::string& path) {
18458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  StringArray_t path_split;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StringArray_t components;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  sdk_util::SplitString(path, '/', &path_split);
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (path[0] == '/')
19058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    components.push_back("/");
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Copy path_split to components, removing empty path segments.
19358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  for (StringArray_t::const_iterator it = path_split.begin();
19446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)       it != path_split.end();
19546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)       ++it) {
19646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (!it->empty())
19746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      components.push_back(*it);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return components;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)Path& Path::operator=(const Path& p) {
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  paths_ = p.paths_;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return *this;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)Path& Path::operator=(const std::string& p) {
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Set(p);
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
211ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}  // namespace nacl_io
212