8deeee3 by Jos van den Oever at 2009-11-08 1
#include "msoxmlnodemodel.h"
2
#include "utils.h"
3
#include <QtXmlPatterns/QXmlNamePool>
4
#include <QtCore/QUrl>
5
#include <QDebug>
6
7
using namespace std;
8
9
/** This XML model spans one OLE stream file.
b7a7041 by Jos van den Oever at 2009-11-16 10
 * The root node corresponds to the file. The child elements of the root
11
 * correspond to streams.
8deeee3 by Jos van den Oever at 2009-11-08 12
 * Below the streams, the elements can correspond to introspectables or values.
13
 * Each Introspectable contains a colleciont of Introspectables and values.
14
 * Each value is represented by a value element and a value text field.
b7a7041 by Jos van den Oever at 2009-11-16 15
 * There is a tree of introspectables available. Values (QVariants) do not know
16
 * about their parents and have to have a the pointer to their introspectable of
17
 * stream as a parent. The additionalData() filed of the QXmlNodeindex should
18
 * contain this information.
8deeee3 by Jos van den Oever at 2009-11-08 19
 * The data() field is a pointer to the introspectable also for the stream.
20
 **/
21
namespace {
22
9b7de38 by Jos van den Oever at 2009-11-13 23
/** The field additionalData() in QXmlNodeModelIndex is used for storing four
24
 *  bits of information while keeping the field increasing in value with
25
 *  document order. The value of the field data() is the same for each node
b7a7041 by Jos van den Oever at 2009-11-16 26
 *  below another node that is not a numbers: field type, member number and
27
 *  index in the member. These fields are
9b7de38 by Jos van den Oever at 2009-11-13 28
 **/
8deeee3 by Jos van den Oever at 2009-11-08 29
6fcbfa2 by Jos van den Oever at 2009-11-10 30
class Node {
31
public:
e923fbe by Jos van den Oever at 2009-11-12 32
    enum Type { Document, RootElement, Stream, Introspectable, ValueElement };
6fcbfa2 by Jos van den Oever at 2009-11-10 33
    const void* data;
34
    int parent;
35
    int prev;
36
    int next;
37
    int firstChild;
38
    Type type;
f22c301 by Jos van den Oever at 2009-11-16 39
    int memberno;
40
    int arrayno;
6fcbfa2 by Jos van den Oever at 2009-11-10 41
82b52c2 by Jos van den Oever at 2009-11-12 42
    Node() :data(0), parent(-1), prev(-1), next(-1), firstChild(-1) {}
6fcbfa2 by Jos van den Oever at 2009-11-10 43
};
8deeee3 by Jos van den Oever at 2009-11-08 44
6fcbfa2 by Jos van den Oever at 2009-11-10 45
int
82b52c2 by Jos van den Oever at 2009-11-12 46
countItems(const Introspectable* i) {
47
    if (i == 0) return 0;
48
    const Introspection* is = i->getIntrospection();
49
    int n = 0;
50
    for (int j=0; j<is->numberOfMembers; ++j) {
51
        for (int k=0; k<is->numberOfInstances[j](i); ++k) {
52
            const Introspectable* ci = is->introspectable[j](i, k);
53
            if (ci) {
54
                n += 1 + countItems(ci);
e923fbe by Jos van den Oever at 2009-11-12 55
            } else {
56
                n += 1; // empty value element
82b52c2 by Jos van den Oever at 2009-11-12 57
            }
58
        }
59
    }
60
    return n;
61
}
62
63
int
b7a7041 by Jos van den Oever at 2009-11-16 64
countItems(const QMap<QString, QSharedPointer<const Introspectable> >& streams){
82b52c2 by Jos van den Oever at 2009-11-12 65
    int n = 2;
b7a7041 by Jos van den Oever at 2009-11-16 66
    QMap<QString, QSharedPointer<const Introspectable> >::const_iterator it
67
        = streams.begin();
82b52c2 by Jos van den Oever at 2009-11-12 68
    while (it != streams.end()) {
69
        n += 1 + countItems(it.value().data());
70
        it++;
71
    }
72
    return n;
73
}
74
75
void
b7a7041 by Jos van den Oever at 2009-11-16 76
addIntrospectable(QVector<Node>& nodes, const Introspectable* i, int pos,
77
        int parent) {
82b52c2 by Jos van den Oever at 2009-11-12 78
    if (i == 0) return;
79
    const Introspection* is = i->getIntrospection();
80
    nodes[pos].parent = parent;
81
    nodes[pos].data = i;
82
    nodes[pos].type = Node::Introspectable;
83
    int prevp = -1;
84
    int p = pos+1;
85
    for (int j=0; j<is->numberOfMembers; ++j) {
86
        for (int k=0; k<is->numberOfInstances[j](i); ++k) {
87
            const Introspectable* ci = is->introspectable[j](i, k);
9b7de38 by Jos van den Oever at 2009-11-13 88
            if (nodes[pos].firstChild == -1) {
89
                nodes[pos].firstChild = p;
90
            }
91
            if (prevp != -1) {
92
                nodes[p].prev = prevp;
93
                nodes[prevp].next = p;
94
            }
95
            prevp = p;
f22c301 by Jos van den Oever at 2009-11-16 96
            nodes[p].memberno = j;
97
            nodes[p].arrayno = k;
98
            if (ci) {
82b52c2 by Jos van den Oever at 2009-11-12 99
                addIntrospectable(nodes, ci, p, pos);
100
                p += 1 + countItems(ci);
e923fbe by Jos van den Oever at 2009-11-12 101
            } else {
f22c301 by Jos van den Oever at 2009-11-16 102
                nodes[p].parent = pos;
9b7de38 by Jos van den Oever at 2009-11-13 103
                nodes[p].data = i;
104
                nodes[p].type = Node::ValueElement;
e923fbe by Jos van den Oever at 2009-11-12 105
                p += 1; // skip empty position
82b52c2 by Jos van den Oever at 2009-11-12 106
            }
107
        }
108
    }
6fcbfa2 by Jos van den Oever at 2009-11-10 109
}
110
111
QVector<Node>
b7a7041 by Jos van den Oever at 2009-11-16 112
createNodes(const QMap<QString, QSharedPointer<const Introspectable> >&
113
        streams) {
6fcbfa2 by Jos van den Oever at 2009-11-10 114
    QVector<Node> nodes(countItems(streams));
b7a7041 by Jos van den Oever at 2009-11-16 115
    nodes[0].parent = -1; nodes[0].prev = -1; nodes[0].next = -1;
116
    nodes[0].firstChild = 1; nodes[0].type = Node::Document;
117
    nodes[1].parent =  0; nodes[1].prev = -1; nodes[1].next = -1;
118
    nodes[1].firstChild = (streams.size()) ?2 :-1;
6fcbfa2 by Jos van den Oever at 2009-11-10 119
    nodes[1].type = Node::RootElement;
82b52c2 by Jos van den Oever at 2009-11-12 120
    int prevp = -1;
121
    int p = 2;
b7a7041 by Jos van den Oever at 2009-11-16 122
    QMap<QString, QSharedPointer<const Introspectable> >::const_iterator it
123
        = streams.begin();
82b52c2 by Jos van den Oever at 2009-11-12 124
    while (it != streams.end()) {
125
        const Introspectable* i = it.value().data();
126
        addIntrospectable(nodes, i, p, 1);
127
        if (prevp != -1) {
128
            nodes[p].prev = prevp;
129
            nodes[prevp].next = p;
130
        }
131
        nodes[p].type = Node::Stream;
132
        prevp = p;
133
        p += 1 + countItems(i);
134
        it++;
8deeee3 by Jos van den Oever at 2009-11-08 135
    }
6fcbfa2 by Jos van den Oever at 2009-11-10 136
    return nodes;
8deeee3 by Jos van den Oever at 2009-11-08 137
}
138
139
}
140
141
class MsoXmlNodeModel::Private {
142
public:
143
    QXmlNamePool namepool;
144
    QString filepath;
145
    const QMap<QString, QSharedPointer<const Introspectable> > streams;
6fcbfa2 by Jos van den Oever at 2009-11-10 146
    const QVector<Node> nodes;
147
    const QXmlName ppt;
8deeee3 by Jos van den Oever at 2009-11-08 148
    const QXmlName directory;
149
    const QXmlName file;
150
    const QXmlName olestream;
151
    const QXmlName olestreamdir;
152
    const QXmlName name;
153
    const QXmlName size;
154
    const QXmlName type;
155
b7a7041 by Jos van den Oever at 2009-11-16 156
    static const QMap<QString, QSharedPointer<const Introspectable> > read(
157
            const char* filepath) {
8deeee3 by Jos van den Oever at 2009-11-08 158
        QString file = QString::fromLocal8Bit(filepath);
159
        const QMap<QString, QByteArray> streams = readStreams(file);
160
        return parseStreams(streams);
161
    }
162
163
    Private(const QXmlNamePool& pool, const char* filepath_) :namepool(pool),
164
            filepath(filepath_),
165
            streams(read(filepath_)),
6fcbfa2 by Jos van den Oever at 2009-11-10 166
            nodes(createNodes(streams)),
167
            ppt(QXmlName(namepool, QLatin1String("ppt"))),
8deeee3 by Jos van den Oever at 2009-11-08 168
            directory(QXmlName(namepool, QLatin1String("directory"))),
169
            file(QXmlName(namepool, QLatin1String("file"))),
170
            olestream(QXmlName(namepool, QLatin1String("olestream"))),
171
            olestreamdir(QXmlName(namepool, QLatin1String("olestreamdir"))),
172
            name(QXmlName(namepool, QLatin1String("name"))),
173
            size(QXmlName(namepool, QLatin1String("size"))),
174
            type(QXmlName(namepool, QLatin1String("type"))) {
175
    }
9b7de38 by Jos van den Oever at 2009-11-13 176
b7a7041 by Jos van den Oever at 2009-11-16 177
    void getIndex(QAbstractXmlNodeModel::SimpleAxis axis, qint64& data,
178
            qint64& additionalData) {
179
        if (additionalData == 1) {
9b7de38 by Jos van den Oever at 2009-11-13 180
            additionalData = 0;
b7a7041 by Jos van den Oever at 2009-11-16 181
            if (axis != Parent) data = -1;
9b7de38 by Jos van den Oever at 2009-11-13 182
            return;
183
        }
b7a7041 by Jos van den Oever at 2009-11-16 184
        const Node& node = nodes[data];
185
        // additionalData = 0;
186
        if (axis == Parent) {
187
            data = node.parent;
9b7de38 by Jos van den Oever at 2009-11-13 188
            return;
189
        }
b7a7041 by Jos van den Oever at 2009-11-16 190
        if (axis == FirstChild) {
191
            if (node.type == Node::ValueElement) {
192
                additionalData = 1;
193
            } else {
194
                data = node.firstChild;
195
            }
196
            return;
9b7de38 by Jos van den Oever at 2009-11-13 197
        }
b7a7041 by Jos van den Oever at 2009-11-16 198
        data = (axis == NextSibling) ?node.next :node.prev;
9b7de38 by Jos van den Oever at 2009-11-13 199
    }
200
 
f22c301 by Jos van den Oever at 2009-11-16 201
    QXmlName getName(qint64 n, qint64 a) {
202
        if (a) return type;
203
        const Node& node = nodes[n];
b7a7041 by Jos van den Oever at 2009-11-16 204
        const Introspectable* i
205
            = static_cast<const Introspectable*>(nodes[node.parent].data);
f22c301 by Jos van den Oever at 2009-11-16 206
        const Introspection* si = i->getIntrospection();
207
        return QXmlName(namepool, si->names[node.memberno]);
9b7de38 by Jos van den Oever at 2009-11-13 208
    }
8deeee3 by Jos van den Oever at 2009-11-08 209
};
210
b7a7041 by Jos van den Oever at 2009-11-16 211
MsoXmlNodeModel::MsoXmlNodeModel(const QXmlNamePool& pool, const char* filepath)
212
        :d(new Private(pool, filepath)) {
8deeee3 by Jos van den Oever at 2009-11-08 213
}
214
MsoXmlNodeModel::~MsoXmlNodeModel() {
215
    delete d;
216
}
217
218
QVector<QXmlNodeModelIndex>
219
MsoXmlNodeModel::attributes(const QXmlNodeModelIndex& element) const {
220
    QVector<QXmlNodeModelIndex> v;
9b7de38 by Jos van den Oever at 2009-11-13 221
    const Node& node = d->nodes[element.data()];
222
    if (node.type == Node::Introspectable && element.additionalData() == 0) {
223
        v.append(createIndex(element.data(), 1));
224
    }
8deeee3 by Jos van den Oever at 2009-11-08 225
    return v;
226
}
227
228
QXmlNodeModelIndex
b7a7041 by Jos van den Oever at 2009-11-16 229
MsoXmlNodeModel::nextFromSimpleAxis(SimpleAxis axis,
230
        const QXmlNodeModelIndex& origin) const {
9b7de38 by Jos van den Oever at 2009-11-13 231
    qint64 data = -1;
232
    qint64 additionalData = 0;
233
    const Node& node = d->nodes[origin.data()];
b7a7041 by Jos van den Oever at 2009-11-16 234
    if (node.type == Node::Introspectable || node.type == Node::ValueElement) {
9b7de38 by Jos van den Oever at 2009-11-13 235
        data = origin.data();
236
        additionalData = origin.additionalData();
237
        d->getIndex(axis, data, additionalData);
238
    } else {
239
        switch (axis) {
240
            case Parent:          data = node.parent;     break;
241
            case FirstChild:      data = node.firstChild; break;
242
            case PreviousSibling: data = node.prev;       break;
243
            case NextSibling:     data = node.next;       break;
244
            default: break;
245
        }
8deeee3 by Jos van den Oever at 2009-11-08 246
    }
b7a7041 by Jos van den Oever at 2009-11-16 247
    return (data == -1)
248
        ?QXmlNodeModelIndex() :createIndex(data, additionalData);
8deeee3 by Jos van den Oever at 2009-11-08 249
}
250
251
QUrl
252
MsoXmlNodeModel::baseUri(const QXmlNodeModelIndex& n) const {
253
    return documentUri(n);
254
}
255
QXmlNodeModelIndex::DocumentOrder
b7a7041 by Jos van den Oever at 2009-11-16 256
MsoXmlNodeModel::compareOrder(const QXmlNodeModelIndex& ni1,
257
        const QXmlNodeModelIndex& ni2) const {
8deeee3 by Jos van den Oever at 2009-11-08 258
    if (ni1.data() < ni2.data()) return QXmlNodeModelIndex::Precedes;
6fcbfa2 by Jos van den Oever at 2009-11-10 259
    if (ni1.data() == ni2.data()) {
b7a7041 by Jos van den Oever at 2009-11-16 260
        if (ni1.additionalData() < ni2.additionalData())
261
            return QXmlNodeModelIndex::Precedes;
262
        if (ni1.additionalData() == ni2.additionalData())
263
            return QXmlNodeModelIndex::Is;
6fcbfa2 by Jos van den Oever at 2009-11-10 264
    }
265
    return QXmlNodeModelIndex::Follows;
8deeee3 by Jos van den Oever at 2009-11-08 266
}
267
QUrl
268
MsoXmlNodeModel::documentUri(const QXmlNodeModelIndex& n) const {
269
    return QUrl::fromLocalFile(d->filepath);
270
}
271
QXmlNodeModelIndex
272
MsoXmlNodeModel::elementById(const QXmlName& id) const {
273
    return QXmlNodeModelIndex();
274
}
275
QXmlNodeModelIndex::NodeKind
276
MsoXmlNodeModel::kind(const QXmlNodeModelIndex& ni) const {
6fcbfa2 by Jos van den Oever at 2009-11-10 277
    if (ni.data() == 0) return QXmlNodeModelIndex::Document;
b7a7041 by Jos van den Oever at 2009-11-16 278
    if (ni.additionalData() == 1) {
279
        const Node& node = d->nodes[ni.data()];
280
        if (node.type == Node::Introspectable) {
281
            return QXmlNodeModelIndex::Attribute;
282
        }
283
        return QXmlNodeModelIndex::Text;
284
    }
6fcbfa2 by Jos van den Oever at 2009-11-10 285
    return QXmlNodeModelIndex::Element; // no attributes yet
8deeee3 by Jos van den Oever at 2009-11-08 286
}
287
QXmlName
288
MsoXmlNodeModel::name(const QXmlNodeModelIndex& ni) const {
f22c301 by Jos van den Oever at 2009-11-16 289
    const Node& node = d->nodes[ni.data()];
290
    const Introspectable* i = static_cast<const Introspectable*>(node.data);
6fcbfa2 by Jos van den Oever at 2009-11-10 291
    const Introspection* si = (i) ?i->getIntrospection() :0;
b7a7041 by Jos van den Oever at 2009-11-16 292
    switch (node.type) {
6fcbfa2 by Jos van den Oever at 2009-11-10 293
        case Node::Document: return d->name; // should not matter
294
        case Node::RootElement: return d->ppt; 
295
        case Node::Stream: return QXmlName(d->namepool, si->name);
b7a7041 by Jos van den Oever at 2009-11-16 296
        case Node::Introspectable:
297
            return d->getName(ni.data(), ni.additionalData());
298
        case Node::ValueElement:
299
            return d->getName(ni.data(), ni.additionalData());
6fcbfa2 by Jos van den Oever at 2009-11-10 300
        default: break;
8deeee3 by Jos van den Oever at 2009-11-08 301
    }
6fcbfa2 by Jos van den Oever at 2009-11-10 302
    return QXmlName();
8deeee3 by Jos van den Oever at 2009-11-08 303
}
304
QVector<QXmlName>
305
MsoXmlNodeModel::namespaceBindings(const QXmlNodeModelIndex& n) const {
306
    return QVector<QXmlName>();
307
}
308
QVector<QXmlNodeModelIndex>
309
MsoXmlNodeModel::nodesByIdref(const QXmlName& idref) const {
310
    return QVector<QXmlNodeModelIndex>();
311
}
312
QXmlNodeModelIndex
313
MsoXmlNodeModel::root(const QXmlNodeModelIndex& n) const {
6fcbfa2 by Jos van den Oever at 2009-11-10 314
    return createIndex((qint64)0);
8deeee3 by Jos van den Oever at 2009-11-08 315
}
316
QString
317
MsoXmlNodeModel::stringValue(const QXmlNodeModelIndex& n) const {
318
    return typedValue(n).toString();
319
}
320
QVariant
321
MsoXmlNodeModel::typedValue(const QXmlNodeModelIndex& n) const {
b7a7041 by Jos van den Oever at 2009-11-16 322
    if (n.additionalData() == 1) { //attribute or value type
323
        const Node& node = d->nodes[n.data()];
324
        const Introspectable* i
325
            = static_cast<const Introspectable*>(d->nodes[n.data()].data);
326
        const Introspection* si = i->getIntrospection();
327
        if (node.type == Node::Introspectable) {
328
            return si->name;
329
        }
330
        return si->value[node.memberno](i, node.arrayno);
9b7de38 by Jos van den Oever at 2009-11-13 331
    }
8deeee3 by Jos van den Oever at 2009-11-08 332
    return QVariant();
333
}