Subversion Repositories Scribus

Rev

Rev 8289 | Rev 8390 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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