All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
path.cpp
Go to the documentation of this file.
1 /*
2 Copyright (c) 2009 zooml.com
3 
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10 
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 */
22 #include "path.h"
23 #include "urisyn.h"
24 #include <stdexcept>
25 namespace te
26 {
27  namespace common
28  {
29  namespace uri
30  {
31  const char path::SEPARATOR_CHAR = '/';
32  path::path() : absolute_(false), is_directory_(false) {}
33  path::path(const std::string& v) : absolute_(false), is_directory_(false) {
34  if (!v.empty()) {
35  std::string::const_iterator first = v.begin();
36  if (!parse(first, v.end(), *this) || first != v.end())
37  throw std::invalid_argument("invalid URI path: \"" + v + "\"");
38  }
39  }
40  void path::clear() {
41  absolute_ = false;
42  is_directory_ = false;
43  segments_.clear();
44  }
45  bool path::match_prefix(const path& rhs) const {
46  if (absolute_ != rhs.absolute_)
47  return false;
48  const_iterator itrhs = rhs.begin();
49  for (const_iterator it = begin();; ++it, ++itrhs) {
50  if (it == end()) {
51  if (itrhs != rhs.end())
52  return false;
53  break;
54  }
55  if (itrhs == rhs.end())
56  return true;
57  if (*it != *itrhs)
58  return false;
59  }
60  return !rhs.is_directory_ || is_directory_;
61  }
62  const std::string& path::front() const {
63  if (segments_.empty())
64  throw std::out_of_range("attempt to access empty URI path");
65  return segments_.front();
66  }
67  const std::string& path::back() const {
68  if (segments_.empty())
69  throw std::out_of_range("attempt to access empty URI path");
70  return segments_.back();
71  }
72  void path::pop_front() {
73  if (!segments_.empty()) {
74  segments_.pop_front();
75  absolute_ = false;
76  if (segments_.empty())
77  is_directory_ = false;
78  }
79  }
80  bool path::pop_back(const path& back) {
81  if (is_directory_ != back.is_directory_ || back.empty())
82  return false;
83  segments_type::reverse_iterator rit = segments_.rbegin();
84  segments_type::reverse_iterator rend = segments_.rend();
85  segments_type::const_reverse_iterator ritb = back.segments_.rbegin();
86  segments_type::const_reverse_iterator rendb = back.segments_.rend();
87  bool found = false;
88  for (; rit != rend && *rit == *ritb; ++rit)
89  if (++ritb == rendb) { // Matched all.
90  found = true;
91  break;
92  }
93  if (!found)
94  return false;
95  // Go on to the front of the list, and in from the front.
96  segments_type::iterator it = segments_.begin();
97  for (; ++rit != rend;)
98  ++it;
99  if (back.absolute_ && (it != segments_.begin() || !absolute_))
100  return false;
101  // Erase to end.
102  segments_.erase(it, segments_.end());
103  // Adjust directory bit if we are empty.
104  if (segments_.empty())
105  is_directory_ = false;
106  return true;
107  }
108  bool path::operator ==(const path& rhs) const {
109  return absolute_ == rhs.absolute_ && is_directory_ == rhs.is_directory_ && segments_ == rhs.segments_;
110  }
111  bool path::operator <(const path& rhs) const {
112  if (!absolute_ && rhs.absolute_) return true;
113  if (absolute_ && !rhs.absolute_) return false;
114  segments_type::const_iterator it = segments_.begin();
115  segments_type::const_iterator itr = rhs.segments_.begin();
116  for (;; ++it, ++itr) {
117  if (it == segments_.end() && itr != rhs.segments_.end()) return true;
118  if (it != segments_.end() && itr == rhs.segments_.end()) return false;
119  int i = it->compare(*itr);
120  if (i < 0) return true;
121  if (0 < i) return false;
122  }
123  return !is_directory_ && rhs.is_directory_;
124  }
125  path& path::operator +=(const std::string& rhs) {
126  segments_.push_back(rhs);
127  is_directory_ = false;
128  return *this;
129  }
130  path& path::operator +=(const path& rhs) {
131  if(segments_.empty()) // added by Lauro
132  absolute_ = rhs.absolute_;
133  segments_.insert(segments_.end(), rhs.segments_.begin(), rhs.segments_.end());
135  return *this;
136  }
137  std::string path::encoding() const { // Added by Lauro
138  std::string s;
139  // sempre colocar '/' ou somente se for absoluto?????????????????
140 // if (absolute_)
141  s += SEPARATOR_CHAR;
142  for (segments_type::const_iterator it = segments_.begin(); it != segments_.end(); ++it) {
143  if (it != segments_.begin())
144  s += SEPARATOR_CHAR;
145  s += urisyn::encode(urisyn::PATH_TRAITS, *it); // Encode and append.
146  }
147  if (is_directory_)
148  s += SEPARATOR_CHAR;
149  return s;
150  }
151  std::string path::string() const { // Added by Lauro
152  std::string s;
153  const_iterator it = begin();
154  if(it != end())
155  {
156  // sempre colocar '/' ou somente se for absoluto?????????????????
157 // if(absolute_)
158  s += SEPARATOR_CHAR;
159  while(it != end()) {
160  s.append(*it);
161  s += SEPARATOR_CHAR;
162  it++;
163  }
164  if(is_directory_ == false)
165  s.erase(s.begin() + s.length()-1);
166  }
167  return s;
168  }
169  bool parse(std::string::const_iterator& first, std::string::const_iterator last, path& v, std::string* errs) { // Modified by Lauro
170  std::string::const_iterator f = first;
171  path tmp;
172  std::string e;
173  if (f != last && *f == path::SEPARATOR_CHAR) { // Leading separator: absolute.
174  tmp.absolute_ = true;
175  ++f;
176  }
177  char c = 0;
178  for (; f != last; f++) {
179  if (*f == path::SEPARATOR_CHAR) // Empty segment: ignore.
180  continue;
181  else { // Consume segment.
182  std::string s;
183  urisyn::parse(urisyn::PATH_TRAITS, f, last, s);
184  if (!s.empty()) { // Non-empty segment: decode and push.
185  if (!urisyn::decode(s)) { // Invalid encoding in segment.
186  if (!errs)
187  return false;
188  e += ", (" + convert((size_t)(f - first)) + ") invalid segment encoding (using as is)";
189  }
190  tmp.segments_.push_back(s);
191  }
192  if(f != last)
193  {
194  if(!s.empty())
195  c = *f;
196  if(*f != path::SEPARATOR_CHAR)
197  break;
198  }
199  if (f == last)
200  {
201  c = 0;
202  break;
203  }
204  }
205  }
206  if (f == first)
207  return false;
208  if (errs && !e.empty()) {
209  if (!errs->empty())
210  *errs += "; ";
211  *errs += "URI path: \"" + std::string(first, f) + "\"" + e;
212  }
213  if (c == '/' && !tmp.segments_.empty())
214  tmp.is_directory_ = true;
215  v = tmp;
216  first = f;
217  return true;
218  }
219  std::string convert(const path& v) {return v.encoding();}
220  bool convert(const std::string& s, path& v) {
221  if (s.empty() || isspaces(s.c_str()))
222  return false;
223  v = s;
224  return true;
225  }
226  }
227  }
228 }
path()
Construct.
Definition: path.cpp:32
std::string string() const
Return path string. Added by Lauro.
Definition: path.cpp:151
std::string encoding() const
Calculate encoded string.
Definition: path.cpp:137
bool operator==(const path &rhs) const
Get number of segments.
Definition: path.cpp:108
void pop_front()
Pop front segment and reset absolute.
Definition: path.cpp:72
const_iterator end() const
Get iterator at end.
Definition: path.h:112
URI path component.
Definition: path.h:51
bool match_prefix(const path &rhs) const
Test if the given other URI path is a prefix of this.
Definition: path.cpp:45
bool parse(std::string::const_iterator &first, std::string::const_iterator last, authority &v)
Parse URI authority, returning whether found or not and advancing first and setting authority if foun...
Definition: authority.cpp:156
segments_type segments_
Definition: path.h:118
static const char SEPARATOR_CHAR
separator ('/')
Definition: path.h:113
void clear()
Clear segments and reset absolute and is_directory.
Definition: path.cpp:40
bool empty() const
Test if empty and not absolute.
Definition: path.h:62
bool pop_back(const path &back)
Remove the back of the path if it matches the argument (including whether directory or not) and retur...
Definition: path.cpp:80
const std::string & back() const
Get back segment.
Definition: path.cpp:67
segments_type::const_iterator const_iterator
segments const iterator type
Definition: path.h:54
bool parse(const traits &ts, std::string::const_iterator &first, std::string::const_iterator last, std::string &comp, char *endc)
Parse the URI componet, returning whether successful and setting the string and end char and advancin...
Definition: urisyn.cpp:136
friend bool TECOMMONEXPORT parse(std::string::const_iterator &first, std::string::const_iterator last, path &v, std::string *errs)
Parse URI path, returning whether found or not and advancing first and setting path if found...
Definition: path.cpp:169
bool isspaces(const char *s)
Test if string is empty or all isspace.
Definition: utils.cpp:175
std::string encode(const traits &ts, const std::string &comp)
Encode the URI (sub) component.
Definition: urisyn.cpp:157
const_iterator begin() const
Get iterator at beginning.
Definition: path.h:111
const std::string & front() const
Get front segment.
Definition: path.cpp:62
bool operator<(const path &rhs) const
Less operator.
Definition: path.cpp:111
const traits PATH_TRAITS
path traits
Definition: urisyn.cpp:73
bool decode(std::string &s)
Decode the pct-encoded (hex) sequences, if any, return success.
Definition: urisyn.cpp:171
std::string convert(const path &v)
URI path to string.
Definition: path.cpp:219
path & operator+=(const std::string &rhs)
Append unencoded segment and reset is_directory.
Definition: path.cpp:125