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