1 /*
2 * digester.h
3 *
4 *
5 * Created by Andreas Vox on 02.06.06.
6 * Copyright 2006 under GPL2. All rights reserved.
7 *
8 */
9
10
11
12 #ifndef DIGESTER_H
13 #define DIGESTER_H
14
15 #include <cassert>
16 #include <iostream>
17 #include <vector>
18 #include <map>
19 #include <string>
20 #include <typeinfo>
21
22 #include "desaxe_conf.h"
23 #include "saxhandler.h"
24
25
26 //#define DESAXE_DEBUG 1
27
28 namespace desaxe {
29
30 class Action;
31 class RuleState;
32
33
34 namespace PRIVATE {
35
36 class VarPtr
37 {
38 public:
39 void* ptr;
40 std::string type;
41 };
42
43
44 template<class ObjType>
45 inline
mkcell(ObjType * obj)46 VarPtr mkcell(ObjType* obj)
47 {
48 VarPtr result;
49 result.ptr = obj;// result.ptr = const_cast<void*>(static_cast<const void*>(obj)); //??
50 result.type = typeid(obj).name();
51 return result;
52 }
53
54
55 template<class ObjType>
56 inline
57 void chkcell(const VarPtr& cell, std::vector<VarPtr>* stack = nullptr)
58 {
59 ObjType* dummy = nullptr;
60 if( cell.type != typeid(dummy).name() )
61 {
62 std::cerr << "requested type '" << typeid(dummy).name() << "' doesn't match cell type '" << cell.type << "'\n";
63 if (stack)
64 {
65 int i=0;
66 std::vector<VarPtr>::iterator it;
67 for (it = stack->begin(); it != stack->end(); ++it)
68 {
69 std::cerr << i++ << "\t" << (*it).type << "\t" << (*it).ptr << "\n";
70 }
71 }
72 assert (false);
73 }
74 }
75
76
77
78 class Patch {
79 public:
80 // internal linked list
81 Patch* next;
Patch(Patch * nxt)82 Patch(Patch* nxt) : next(nxt) {}
83
84 virtual void run(VarPtr lnk) = 0;
~Patch()85 virtual ~Patch() {}
86 };
87
88
89 } // namespace PRIVATE
90
91
92
93 /**
94 Digester helps you to create C++ objects from a SAX stream.
95 All you have to do is register actions for patterns of element tags
96 you expect in your XML stream. These actions can create new objects, set
97 attributes, or call methods. Actions operate on intermediate objects which
98 are hold on a stack maintained by Digester.
99 */
100 class Digester : public SaxHandler {
101 public:
102 Digester();
103 Digester& operator=(const Digester& other);
104 virtual ~Digester();
105 void reset();
106 void addRule(const Xml_string& pattern, Action action);
107
108 void parseFile(const Xml_string& filename);
109 void parseMemory(const char* data, unsigned int length);
110 void parseMemory(const Xml_string& data);
111
112 template<class ObjType>
113 ObjType* result();
114 int nrOfErrors() const;
115 const Xml_string &getError(int i) const;
116
117 // called by SAX parser:
118 void beginDoc();
119 void endDoc();
120 void begin(const Xml_string& tag, Xml_attr attr);
121 void end(const Xml_string& tag);
122 void chars(const Xml_string& text);
123
124 // used by actions:
125 void fail();
126 void error(const Xml_string& msg);
127
128 template<class ObjType>
129 ObjType* top(unsigned int offset = 0);
130
131 template<class ObjType>
132 ObjType* bottom(unsigned int offset = 0);
133
134 template<class ObjType>
135 void setResult( ObjType* res );
136
137 void pop();
138 void popn(unsigned int number);
139
140 template<class ObjType>
141 void push(ObjType* obj);
142
143 // used to resolve idrefs and for general storage
144 template<class ObjType>
145 ObjType* lookup(const Xml_string& idref);
146 template<class ObjType>
147 void store(const Xml_string& idref, ObjType* res );
148
149 // used to resolve idrefs if use is before definition
150 template<class LinkType>
151 void patchCall(const Xml_string& idref, void (*fun)(LinkType*) );
152 template<class ObjType, class LinkType>
153 void patchInvoke(const Xml_string& idref, ObjType* obj, void (ObjType::*fun)(LinkType*) );
154
155 // used to insert "/" where necessary
156 static Xml_string concat(const Xml_string& pattern1, const Xml_string& pattern2);
157
158 private:
159 RuleState*
160 m_state;
161
162 std::vector<PRIVATE::VarPtr>
163 m_objects;
164
165 std::map<Xml_string, PRIVATE::VarPtr>
166 m_storage;
167
168 std::map<Xml_string, PRIVATE::Patch*>
169 m_patches;
170
171 PRIVATE::VarPtr
172 m_result_;
173
174 std::vector<Xml_string>
175 m_errors;
176 };
177
178
179
180 template<class ObjType>
181 inline
top(unsigned int offset)182 ObjType* Digester::top(unsigned int offset)
183 {
184 #ifdef DESAXE_DEBUG
185 std::cerr << "top(" << offset << ") of " << objects.size() << "\n";
186 #endif
187 unsigned int count = m_objects.size();
188 assert (offset < count);
189 PRIVATE::chkcell<ObjType>(m_objects[count - offset - 1], &m_objects);
190 #ifdef DESAXE_DEBUG
191 std::cerr << "stack-> " << static_cast<ObjType*>(objects[count - offset - 1].ptr) << "\n";
192 #endif
193
194 return static_cast<ObjType*>(m_objects[count - offset - 1].ptr);
195 }
196
197
198 template<class ObjType>
199 inline
bottom(unsigned int offset)200 ObjType* Digester::bottom(unsigned int offset)
201 {
202 #ifdef DESAXE_DEBUG
203 std::cerr << "bottom(" << offset << ") of " << objects.size() << "\n";
204 #endif
205 //unsigned int count = objects.size();
206 assert (offset < m_objects.size());
207 PRIVATE::chkcell<ObjType> (m_objects[offset]);
208 return static_cast<ObjType*>(m_objects[offset].ptr);
209 }
210
211
212 template<class ObjType>
213 inline
result()214 ObjType* Digester::result()
215 {
216 ObjType* dummy = nullptr;
217 if (m_result_.type != typeid(dummy).name())
218 return nullptr;
219 #ifdef DESAXE_DEBUG
220 std::cerr << "result-> " << static_cast<ObjType*>(result_.ptr) << "\n";
221 #endif
222 return static_cast<ObjType*>(m_result_.ptr);
223 }
224
225
226 template<class ObjType>
227 inline
setResult(ObjType * res)228 void Digester::setResult(ObjType* res)
229 {
230 #ifdef DESAXE_DEBUG
231 std::cerr << res << " ->result\n";
232 #endif
233 m_result_ = PRIVATE::mkcell(res);
234 }
235
236
237 inline
pop()238 void Digester::pop()
239 {
240 assert (1 <= (unsigned int) m_objects.size());
241 m_objects.pop_back();
242 }
243
244 inline
popn(unsigned int number)245 void Digester::popn(unsigned int number)
246 {
247 unsigned int count = (unsigned int) m_objects.size();
248 assert (number <= count);
249 m_objects.resize(count - number);
250 }
251
252
253 template<class ObjType>
254 inline
push(ObjType * obj)255 void Digester::push(ObjType* obj)
256 {
257 #ifdef DESAXE_DEBUG
258 std::cerr << "stack<- " << obj << "\n";
259 #endif
260 m_objects.push_back(PRIVATE::mkcell(obj));
261 }
262
263
264 // now lookup / store / patch business
265
266 namespace PRIVATE {
267
268 template <class LinkType>
269 struct Patch1 : public Patch
270 {
271 typedef void (*FunType1)(LinkType*);
272 FunType1 fun;
273
PatchPatch1274 Patch1(FunType1 fn, Patch* nxt = nullptr) : Patch(nxt), fun(fn) {}
275
runPatch1276 void run(VarPtr link)
277 {
278 fun( static_cast<LinkType*>(link.ptr) );
279 }
280 };
281
282
283 template <class ObjType, class LinkType>
284 struct Patch2 : public Patch
285 {
286 typedef void (ObjType::*FunType2)(LinkType*);
287 ObjType* obj;
288 FunType2 fun;
289
PatchPatch2290 Patch2(ObjType* ob, FunType2 fn, Patch* nxt = nullptr) : Patch(nxt), obj(ob), fun(fn) {}
291
runPatch2292 void run(VarPtr link)
293 {
294 (obj->*fun)( static_cast<LinkType*>(link.ptr) );
295 }
296 };
297
298
299 inline
runPatches(Patch * & list,VarPtr link)300 void runPatches(Patch*& list, VarPtr link)
301 {
302 while (list)
303 {
304 Patch* nxt = list->next;
305 list->run(link);
306 delete list;
307 list = nxt;
308 }
309 }
310
311 inline
deletePatches(std::map<Xml_string,Patch * > & patches)312 void deletePatches(std::map<Xml_string, Patch*>& patches)
313 {
314 std::map<Xml_string, Patch*>::iterator it;
315 for (it = patches.begin(); it != patches.end(); ++it)
316 {
317 Patch* list = it->second;
318 while (list)
319 {
320 Patch* nxt = list->next;
321 delete list;
322 list = nxt;
323 }
324 }
325 patches.clear();
326 }
327
328
329 // template<> class Patch1<void>;
330 // template<> class Patch2<VarPtr,void>;
331
332 } //namespace PRIVATE
333
334
335
336 template<class ObjType>
337 inline
lookup(const Xml_string & idref)338 ObjType* Digester::lookup(const Xml_string& idref)
339 {
340 using namespace PRIVATE;
341
342 std::map<Xml_string, VarPtr>::iterator cell = m_storage.find(idref);
343 if (cell == m_storage.end())
344 {
345 #ifdef DESAXE_DEBUG
346 std::cerr << "lookup[" << idref << "]-> nullptr\n";
347 #endif
348 return nullptr;
349 }
350 else
351 {
352 chkcell<ObjType> (cell->second);
353 #ifdef DESAXE_DEBUG
354 std::cerr << "lookup[" << idref << "]-> " << static_cast<ObjType*>(cell->second.ptr) << "\n";
355 #endif
356 return static_cast<ObjType*>(cell->second.ptr);
357 }
358 }
359
360
361
362 template<class ObjType>
363 inline
store(const Xml_string & idref,ObjType * obj)364 void Digester::store(const Xml_string& idref, ObjType* obj)
365 {
366 using namespace PRIVATE;
367 #ifdef DESAXE_DEBUG
368 std::cerr << "store[" << idref << "] <- " << obj << "\n";
369 #endif
370 m_storage[idref] = mkcell(obj);
371 runPatches(m_patches[idref], m_storage[idref]);
372 }
373
374
375
376 template<class LinkType>
patchCall(const Xml_string & idref,void (* fun)(LinkType *))377 void Digester::patchCall(const Xml_string& idref, void (*fun)(LinkType*) )
378 {
379 using namespace PRIVATE;
380
381 std::map<Xml_string, VarPtr>::iterator cell = m_storage.find(idref);
382 if (cell == m_storage.end())
383 {
384 m_patches[idref] = new Patch1<LinkType>(fun, m_patches[idref] );
385 }
386 else
387 {
388 Patch1<LinkType>(fun).run(cell->second);
389 }
390 }
391
392
393 template<class ObjType, class LinkType>
patchInvoke(const Xml_string & idref,ObjType * obj,void (ObjType::* fun)(LinkType *))394 void Digester::patchInvoke(const Xml_string& idref, ObjType* obj, void (ObjType::*fun)(LinkType*) )
395 {
396 using namespace PRIVATE;
397
398 std::map<Xml_string, VarPtr>::iterator cell = m_storage.find(idref);
399 if (cell == m_storage.end())
400 {
401 m_patches[idref] = new Patch2<ObjType,LinkType>(obj, fun, m_patches[idref] );
402 }
403 else
404 {
405 Patch2<ObjType,LinkType>(obj, fun).run(cell->second);
406 }
407 }
408
409 } // namespace desaxe
410
411 #endif
412