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