stlab.adobe.com Adobe Systems Incorporated
xstring.hpp
Go to the documentation of this file.
1 /*
2  Copyright 2005-2007 Adobe Systems Incorporated
3  Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt
4  or a copy at http://stlab.adobe.com/licenses.html)
5 */
6 
7 /*************************************************************************************************/
8 
9 #ifndef ADOBE_XSTRING_HPP
10 #define ADOBE_XSTRING_HPP
11 
12 /*************************************************************************************************/
13 
14 #include <adobe/config.hpp>
15 
16 #include <adobe/functional.hpp>
17 #include <adobe/implementation/string_pool.hpp>
18 #include <adobe/istream.hpp>
19 #include <adobe/name.hpp>
20 #include <adobe/string.hpp>
21 #include <adobe/unicode.hpp>
22 #include <adobe/xml_parser.hpp>
23 
24 #include <boost/function.hpp>
25 #include <boost/noncopyable.hpp>
26 
27 #include <sstream>
28 #include <vector>
29 #include <map>
30 #include <cassert>
31 #include <cctype>
32 
33 /*************************************************************************************************/
34 
35 namespace adobe {
36 
37 /*************************************************************************************************/
38 
39 namespace implementation {
40 
41 /****************************************************************************************************/
42 
43 inline bool xstring_preorder_predicate(const token_range_t& range)
44 {
45  // we want to check for both xstr and marker tags because both are
46  // handled by the xstring system
47 
48  return token_range_equal(range, static_token_range("xstr")) ||
49  token_range_equal(range, static_token_range("marker"));
50 }
51 
52 /****************************************************************************************************/
53 
54 struct null_output_t
55 {
56  typedef std::output_iterator_tag iterator_category;
57  typedef null_output_t value_type;
58  typedef std::ptrdiff_t difference_type;
59  typedef value_type* pointer;
60  typedef value_type& reference;
61 
62  null_output_t& operator ++ (int) { return *this; }
63  null_output_t& operator ++ () { return *this; }
64  reference operator * () { return *this; }
65 
66  template <typename T>
67  null_output_t& operator = (const T&) { return *this; }
68 };
69 
70 /****************************************************************************************************/
71 
72 token_range_t xml_xstr_store(const token_range_t& entire_element_range,
73  const token_range_t& name,
74  const attribute_set_t& attribute_set,
75  const token_range_t& value);
76 
77 token_range_t xml_xstr_lookup( const token_range_t& entire_element_range,
78  const token_range_t& name,
79  const attribute_set_t& attribute_set,
80  const token_range_t& value);
81 
82 token_range_t xml_element_finalize( const token_range_t& entire_element_range,
83  const token_range_t& name,
84  const attribute_set_t& attribute_set,
85  const token_range_t& value);
86 
87 /*************************************************************************************************/
88 
89 struct context_frame_t
90 {
91  struct comp_t
92  {
93  bool operator () (const token_range_t& x, const token_range_t& y) const
94  {
95  return token_range_less(x, y);
96  }
97  };
98 
99  typedef std::pair<attribute_set_t, token_range_t> element_t;
100  typedef std::multimap<token_range_t, element_t, comp_t> store_t;
101  typedef store_t::iterator store_iterator;
102  typedef store_t::value_type store_value_type;
103  typedef std::pair<store_iterator, store_iterator> store_range_pair_t;
104 
105  typedef xml_parser_t<char*>::callback_proc_t callback_proc_t;
106  typedef xml_parser_t<char*>::preorder_predicate_t preorder_predicate_t;
107 
108  context_frame_t() :
109  parse_info_m("xstring context_frame_t"),
110  parsed_m(false)
111  { }
112 
113  context_frame_t(const context_frame_t& rhs) :
114  parse_info_m(rhs.parse_info_m),
115  parsed_m(rhs.parsed_m),
116  attribute_set_m(rhs.attribute_set_m),
117  glossary_m(rhs.glossary_m),
118  callback_m(rhs.callback_m),
119  predicate_m(rhs.predicate_m)
120  //slurp_m(rhs.slurp_m), // not to be transferred from context to context
121  //pool_m(rhs.pool_m), // not to be transferred from context to context
122  { }
123 
124  context_frame_t& operator = (const context_frame_t& rhs)
125  {
126  parse_info_m = rhs.parse_info_m;
127  parsed_m = rhs.parsed_m;
128  attribute_set_m = rhs.attribute_set_m;
129  glossary_m = rhs.glossary_m;
130  callback_m = rhs.callback_m;
131  predicate_m = rhs.predicate_m;
132  //slurp_m = rhs.slurp_m; // not to be transferred from context to context
133  //pool_m = rhs.pool_m; // not to be transferred from context to context
134 
135  return *this;
136  }
137 
138  ~context_frame_t()
139  { if (slurp_m.first) delete [] slurp_m.first; }
140 
141  inline store_range_pair_t range_for_key(const store_t::key_type& key)
142  { return glossary_m.equal_range(key); }
143 
144  std::pair<bool, store_iterator> exact_match_exists( const attribute_set_t& attribute_set,
145  const token_range_t& value);
146 
147  store_t::mapped_type* store( const store_t::key_type& key,
148  const attribute_set_t& attribute_set,
149  const token_range_t& value,
150  bool copy = false);
151 
152  store_iterator closest_match( store_range_pair_t range,
153  const attribute_set_t& searching);
154 
155  token_range_t element_handler( const token_range_t& entire_element_range,
156  const token_range_t& name,
157  const attribute_set_t& attribute_set,
158  const token_range_t& value) const
159  {
160  if (xstring_preorder_predicate(name))
161  // Note that this implicitly handles "marker" elements (by echoing them)
162  return xml_xstr_lookup(entire_element_range, name, attribute_set, value);
163  else if (predicate_m && predicate_m(name))
164  return callback_m(entire_element_range, name, attribute_set, value);
165  else
166  return xml_element_strip(entire_element_range, name, attribute_set, value);
167  }
168 
169  token_range_t clone(const token_range_t& token);
170 
171  line_position_t parse_info_m;
172  bool parsed_m;
173  attribute_set_t attribute_set_m;
174  store_t glossary_m;
175  callback_proc_t callback_m;
176  preorder_predicate_t predicate_m;
177  token_range_t slurp_m;
178  unique_string_pool_t pool_m;
179 };
180 
181 /*************************************************************************************************/
182 
183 inline bool operator == (const context_frame_t::element_t& x, const context_frame_t::element_t& y)
184  { return x.first == y.first && token_range_equal(x.second, y.second); }
185 
186 /*************************************************************************************************/
187 
188 implementation::context_frame_t& top_frame();
189 
190 /*************************************************************************************************/
191 
192 } // namespace implementation
193 
194 /*************************************************************************************************/
195 #ifndef NDEBUG
196 
198 
199 #endif
200 /*************************************************************************************************/
201 
202 // XML fragment parsing
203 
204 template <typename O> // O models OutputIterator
205 inline void parse_xml_fragment(uchar_ptr_t fragment, std::size_t n, O output)
206 {
207  const implementation::context_frame_t& context(implementation::top_frame());
208 
209  make_xml_parser( fragment,
210  fragment + n,
211  line_position_t("parse_xml_fragment"),
213  boost::bind(&implementation::context_frame_t::element_handler, boost::cref(context), _1, _2, _3, _4),
214  output)
215 
216  .parse_content(); // REVISIT (fbrereto) : More or less legible than having it after the above declaration?
217 }
218 
219 template <typename O> // O models OutputIterator
220 inline void parse_xml_fragment(const std::string& fragment, O output)
221  { return parse_xml_fragment(reinterpret_cast<uchar_ptr_t>(fragment.c_str()), fragment.size(), output); }
222 
223 template <typename O> // O models OutputIterator
224 inline void parse_xml_fragment(const char* fragment, O output)
225  { return parse_xml_fragment(reinterpret_cast<uchar_ptr_t>(fragment), std::strlen(fragment), output); }
226 
227 /*************************************************************************************************/
228 
229 // xstring lookup with OutputIterator; all of these functions return a valid XML fragment
230 
231 template <typename O> // O models OutputIterator; required: sizeof(value_type(O)) >= 21 bits
232 inline void xstring(const char* xstr, std::size_t n, O output)
233  { parse_xml_fragment(reinterpret_cast<uchar_ptr_t>(xstr), n, output); }
234 
235 template <typename O> // O models OutputIterator; required: sizeof(value_type(O)) >= 21 bits
236 inline void xstring(const char* xstr, O output)
237  { xstring(xstr, std::strlen(xstr), output); }
238 
239 /*************************************************************************************************/
240 
241 // xstring lookup; all of these functions return a valid XML fragment
242 
243 inline std::string xstring(const char* xstr, std::size_t n)
244 {
245  std::string result;
246 
247  xstring(xstr, n, std::back_inserter(result));
248 
249  return result;
250 }
251 
252 inline std::string xstring(const std::string& xstr)
253  { return xstring(xstr.c_str(), xstr.size()); }
254 
255 /*************************************************************************************************/
256 
257 // Context-sensitive marker replacement
258 
259 std::string xstring_replace( const std::string& xstr,
260  const std::string& marker);
261 
262 std::string xstring_replace( const std::string& xstr,
263  const std::string* first,
264  const std::string* last);
265 
266 std::string xstring_replace( const name_t& xstr_id,
267  const std::string& marker);
268 
269 std::string xstring_replace( const name_t& xstr_id,
270  const std::string* first,
271  const std::string* last);
272 
273 /*************************************************************************************************/
274 
275 struct xstring_context_t : boost::noncopyable
276 {
279 
280  xstring_context_t( const char* parse_first,
281  const char* parse_last,
282  const line_position_t& parse_info =
283  line_position_t("xstring_context_t")) :
284  back_frame_m(implementation::top_frame()) // save snapshot of stack
285  {
286  implementation::context_frame_t& context(implementation::top_frame());
287 
288  context.slurp_m.first = reinterpret_cast<uchar_ptr_t>(parse_first);
289  context.slurp_m.second = reinterpret_cast<uchar_ptr_t>(parse_last);
290  context.parse_info_m = parse_info;
291  context.parsed_m = false;
292 
293  glossary_parse();
294  }
295 
296  template <typename I> // I models InputIterator
297  xstring_context_t( I first_attribute,
298  I last_attribute) :
299  back_frame_m(implementation::top_frame()) // save snapshot of stack
300  {
301  implementation::top_frame().attribute_set_m.insert(first_attribute, last_attribute);
302  }
303 
304  template <typename I> // I models InputIterator
305  xstring_context_t( I first_attribute,
306  I last_attribute,
307  const unsigned char* parse_first,
308  const unsigned char* parse_last,
309  const line_position_t& parse_info =
310  line_position_t("xstring_context_t")) :
311  back_frame_m(implementation::top_frame()) // save snapshot of stack
312  {
313  implementation::context_frame_t& context(implementation::top_frame());
314 
315  context.attribute_set_m.insert(first_attribute, last_attribute);
316  context.slurp_m.first = parse_first;
317  context.slurp_m.second = parse_last;
318  context.parse_info_m = parse_info;
319  context.parsed_m = false;
320 
321  glossary_parse();
322  }
323 
324  void set_preorder_predicate(preorder_predicate_t proc)
325  { implementation::top_frame().predicate_m = proc; }
326 
327  void set_element_handler(callback_proc_t proc)
328  { implementation::top_frame().callback_m = proc; }
329 
331  { implementation::top_frame() = back_frame_m; } // restore stack as it was
332 
333 private:
334  void glossary_parse()
335  {
336  implementation::context_frame_t& context(implementation::top_frame());
337 
338  if (context.parsed_m || !boost::size(context.slurp_m))
339  return;
340 
341  make_xml_parser(
342  context.slurp_m.first,
343  context.slurp_m.second,
344  context.parse_info_m,
345  implementation::xstring_preorder_predicate,
346  &implementation::xml_xstr_store,
347  implementation::null_output_t())
348 
349  .parse_element_sequence(); // REVISIT (fbrereto) : More or less legible than having it after the above declaration?
350 
351  context.parsed_m = true;
352  }
353 
354  implementation::context_frame_t back_frame_m;
355 };
356 
357 /*************************************************************************************************/
358 
359 } // namespace adobe
360 
361 /*************************************************************************************************/
362 #ifdef __ADOBE_COMPILER_CONCEPTS__
363 namespace std {
364  // It would be nice to be able to instantiate this for all T. Not sure why it doesn't work.
365  concept_map OutputIterator<adobe::implementation::null_output_t, char> {};
366  concept_map OutputIterator<adobe::implementation::null_output_t, unsigned char> {};
367 }
368 #endif
369 
370 /*************************************************************************************************/
371 
372 #endif
373 
374 /*************************************************************************************************/
bool token_range_less(const token_range_t &x, const token_range_t &y)
A type detailing parser position information.
Definition: istream.hpp:153
void parse_xml_fragment(uchar_ptr_t fragment, std::size_t n, O output)
Definition: xstring.hpp:205
void set_element_handler(callback_proc_t proc)
Definition: xstring.hpp:327
implementation::context_frame_t::preorder_predicate_t preorder_predicate_t
Definition: xstring.hpp:278
STL namespace.
token_range_t static_token_range(T *begin)
std::pair< uchar_ptr_t, uchar_ptr_t > token_range_t
A range of pointers denoting a token within a character stream.
implementation::context_frame_t::callback_proc_t callback_proc_t
Definition: xstring.hpp:277
std::string xstring_replace(const std::string &xstr, const std::string &marker)
bool operator==(const circular_queue< T > &x, const circular_queue< T > &y)
xstring_context_t(I first_attribute, I last_attribute)
Definition: xstring.hpp:297
bool token_range_equal(const token_range_t &x, const token_range_t &y)
OutputIterator copy(const InputRange &range, OutputIterator result)
copy implementation
Definition: copy.hpp:43
xstring_context_t(I first_attribute, I last_attribute, const unsigned char *parse_first, const unsigned char *parse_last, const line_position_t &parse_info=line_position_t("xstring_context_t"))
Definition: xstring.hpp:305
token_range_t xml_element_strip(const token_range_t &, const token_range_t &, const attribute_set_t &, const token_range_t &value)
Definition: xml_parser.hpp:630
xstring_context_t(const char *parse_first, const char *parse_last, const line_position_t &parse_info=line_position_t("xstring_context_t"))
Definition: xstring.hpp:280
void xstring(const char *xstr, std::size_t n, O output)
Definition: xstring.hpp:232
void xstring_clear_glossary()
void set_preorder_predicate(preorder_predicate_t proc)
Definition: xstring.hpp:324
boost::function< bool(const token_range_t &)> preorder_predicate_t
Definition: xml_parser.hpp:446
boost::range_size< Selection >::type size(const Selection &x)
const unsigned char * uchar_ptr_t
Scope-based runtime context stack for glossary lookups.
Definition: xstring.hpp:275
xml_element_proc_t callback_proc_t
Definition: xml_parser.hpp:445

Copyright © 2006-2007 Adobe Systems Incorporated.

Use of this website signifies your agreement to the Terms of Use and Online Privacy Policy.

Search powered by Google