Argo  1.0
A C++ library for handling JSON.
pointer.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 Andrew Haisley
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 all
12  * 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 THE
20  * SOFTWARE.
21  */
22 
24 
25 #include <sstream>
26 
27 #include "pointer.hpp"
28 #include "utf8.hpp"
30 
31 using namespace NAMESPACE;
32 using namespace std;
33 
34 pointer::pointer(const std::string &pointer)
35 {
36  // is this a URI fragment type pointer?
37  if (pointer[0] == '#')
38  {
39  build_from_uri_fragment(*utf8::json_string_to_utf8(pointer));
40  }
41  else
42  {
43  build_from_json_string(*utf8::json_string_to_utf8(pointer));
44  }
45 }
46 
47 void pointer::build_from_uri_fragment(const std::string &pointer)
48 {
49  size_t start = 1;
50  size_t end = 0;
51 
52  if (pointer.size() == 1)
53  {
54  m_path.push_back(token());
55  }
56  else
57  {
58  while (next_token(pointer, start, end))
59  {
60  m_path.push_back(translate_uri_token(pointer, start, end));
61  }
62  }
63 }
64 
65 void pointer::build_from_json_string(const std::string &pointer)
66 {
67  size_t start = 0;
68  size_t end = 0;
69 
70  if (pointer.size() == 0)
71  {
72  m_path.push_back(token());
73  }
74  else
75  {
76  while (next_token(pointer, start, end))
77  {
78  m_path.push_back(translate_jsonp_token(pointer, start, end));
79  }
80  }
81 }
82 
83 bool pointer::next_token(const string &pointer, size_t &start, size_t &end)
84 {
85  if (start >= pointer.size())
86  {
87  return false;
88  }
89  else
90  {
91  end = start + 1;
92 
93  while (end < pointer.size())
94  {
95  if (pointer[end] == '/')
96  {
97  break;
98  }
99  else
100  {
101  end++;
102  }
103  }
104 
105  return true;
106  }
107 }
108 
109 pointer::token pointer::translate_uri_token(const string &pointer, size_t &start, size_t &end)
110 {
111  string translated;
112 
113  if (pointer[start++] == '/')
114  {
115  while (start < end)
116  {
117  if (pointer[start] == '~')
118  {
119  if (++start < end)
120  {
121  if (pointer[start] == '0')
122  {
123  translated += '~';
124  }
125  else if (pointer[start] == '1')
126  {
127  translated += '/';
128  }
129  else
130  {
131  throw json_pointer_exception(json_exception::syntax_error_in_pointer_string_e, start - 1);
132  }
133  start++;
134  }
135  else
136  {
137  throw json_pointer_exception(json_exception::syntax_error_in_pointer_string_e, start - 1);
138  }
139  }
140  else if (pointer[start] == '%')
141  {
142  if (++start < (end - 1))
143  {
144  int c = from_hex(pointer, start++) * 16;
145  c += from_hex(pointer, start++);
146  translated += static_cast<char>(c);
147  }
148  else
149  {
150  throw json_pointer_exception(json_exception::syntax_error_in_pointer_string_e, start - 1);
151  }
152  }
153  else
154  {
155  translated += pointer[start++];
156  }
157  }
158 
159  return make_token(translated);
160  }
161  else
162  {
163  throw json_pointer_exception(json_exception::syntax_error_in_pointer_string_e, start - 1);
164  }
165 }
166 
167 pointer::token pointer::translate_jsonp_token(const string &pointer, size_t &start, size_t &end)
168 {
169  string translated;
170 
171  if (pointer[start++] == '/')
172  {
173  while (start < end)
174  {
175  if (pointer[start] == '~')
176  {
177  if (++start < end)
178  {
179  if (pointer[start] == '0')
180  {
181  translated += '~';
182  }
183  else if (pointer[start] == '1')
184  {
185  translated += '/';
186  }
187  else
188  {
189  throw json_pointer_exception(json_exception::syntax_error_in_pointer_string_e, start - 1);
190  }
191  start++;
192  }
193  else
194  {
195  throw json_pointer_exception(json_exception::syntax_error_in_pointer_string_e, start - 1);
196  }
197  }
198  else
199  {
200  translated += pointer[start++];
201  }
202  }
203 
204  return make_token(translated);
205  }
206  else
207  {
208  throw json_pointer_exception(json_exception::syntax_error_in_pointer_string_e, start - 1);
209  }
210 }
211 
212 pointer::token pointer::make_token(const string &s)
213 {
214  istringstream is(s);
215 
216  size_t i;
217 
218  if (is >> i)
219  {
220  return token(i);
221  }
222  else
223  {
224  return token(s);
225  }
226 }
227 
228 int pointer::from_hex(const string &s, size_t index)
229 {
230  char c = s[index];
231 
232  if (c >= '0' && c <= '9')
233  {
234  return c - '0';
235  }
236  else if (c >= 'A' && c <= 'F')
237  {
238  return c - 'A' + 10;
239  }
240  else
241  {
242  throw json_pointer_exception(json_exception::syntax_error_in_pointer_string_e, index - 1);
243  }
244 }
245 
246 pointer::token::token() : m_type(all_e), m_index(0)
247 {
248 }
249 
250 pointer::token::token(const string &name) : m_type(object_e), m_name(name), m_index(0)
251 {
252 }
253 
254 pointer::token::token(size_t index) : m_type(array_e), m_index(index)
255 {
256 }
257 
258 const list<pointer::token> &pointer::get_path() const
259 {
260  return m_path;
261 }
262 
264 {
265  return m_type;
266 }
267 
268 const string &pointer::token::get_name() const
269 {
270  return m_name;
271 }
272 
274 {
275  return m_index;
276 }
277 
278 ostream &NAMESPACE::operator<<(ostream &stream, const pointer &p)
279 {
280  for (auto &t : p.get_path())
281  {
282  stream << "/";
283  if (t.get_type() == pointer::token::object_e)
284  {
285  stream << t.get_name();
286  }
287  else if (t.get_type() == pointer::token::array_e)
288  {
289  stream << t.get_index();
290  }
291  }
292 
293  return stream;
294 }
Specific class of exceptions for IO errors of various types.
token()
Construct a token of type all_e.
Definition: pointer.cpp:246
#define NAMESPACE
You can change the namespace of the whole library by changing this value.
Definition: common.hpp:29
STL namespace.
type_t get_type() const
Get the type of the token.
Definition: pointer.cpp:263
Tokens in a JSON pointer.
Definition: pointer.hpp:53
type_t
Different types of pointer tokens.
Definition: pointer.hpp:58
JSON pointers as per the RFT.
Definition: pointer.hpp:41
const std::string & get_name() const
Get the name of the slot referenced.
Definition: pointer.cpp:268
The pointer class.
The utf8 class.
The json_pointer_exception class.
size_t get_index() const
Get the index in the array referenced.
Definition: pointer.cpp:273
const std::list< token > & get_path() const
Definition: pointer.cpp:258