File indexing completed on 2024-04-28 04:40:01

0001 #include "msoxmlnodemodel.h"
0002 #include "utils.h"
0003 #include <QtXmlPatterns/QXmlNamePool>
0004 #include <QtCore/QUrl>
0005 #include <QDebug>
0006 
0007 using namespace std;
0008 
0009 /** This XML model spans one OLE stream file.
0010  * The root node corresponds to the file. The child elements of the root
0011  * correspond to streams.
0012  * Below the streams, the elements can correspond to introspectables or values.
0013  * Each Introspectable contains a colleciont of Introspectables and values.
0014  * Each value is represented by a value element and a value text field.
0015  * There is a tree of introspectables available. Values (QVariants) do not know
0016  * about their parents and have to have a the pointer to their introspectable of
0017  * stream as a parent. The additionalData() filed of the QXmlNodeindex should
0018  * contain this information.
0019  * The data() field is a pointer to the introspectable also for the stream.
0020  **/
0021 namespace {
0022 
0023 /** The field additionalData() in QXmlNodeModelIndex is used for storing four
0024  *  bits of information while keeping the field increasing in value with
0025  *  document order. The value of the field data() is the same for each node
0026  *  below another node that is not a numbers: field type, member number and
0027  *  index in the member. These fields are
0028  **/
0029 
0030 class Node {
0031 public:
0032     enum Type { Document, RootElement, Stream, Introspectable, ValueElement };
0033     const void* data;
0034     int parent;
0035     int prev;
0036     int next;
0037     int firstChild;
0038     Type type;
0039     int memberno;
0040     int arrayno;
0041 
0042     Node() :data(0), parent(-1), prev(-1), next(-1), firstChild(-1) {}
0043 };
0044 
0045 int
0046 countItems(const Introspectable* i) {
0047     if (i == 0) return 0;
0048     const Introspection* is = i->getIntrospection();
0049     int n = 0;
0050     for (int j=0; j<is->numberOfMembers; ++j) {
0051         for (int k=0; k<is->numberOfInstances[j](i); ++k) {
0052             const Introspectable* ci = is->introspectable[j](i, k);
0053             if (ci) {
0054                 n += 1 + countItems(ci);
0055             } else {
0056                 n += 1; // empty value element
0057             }
0058         }
0059     }
0060     return n;
0061 }
0062 
0063 int
0064 countItems(const QMap<QString, QSharedPointer<const Introspectable> >& streams){
0065     int n = 2;
0066     QMap<QString, QSharedPointer<const Introspectable> >::const_iterator it
0067         = streams.begin();
0068     while (it != streams.end()) {
0069         n += 1 + countItems(it.value().data());
0070         it++;
0071     }
0072     return n;
0073 }
0074 
0075 void
0076 addIntrospectable(QVector<Node>& nodes, const Introspectable* i, int pos,
0077         int parent) {
0078     if (i == 0) return;
0079     const Introspection* is = i->getIntrospection();
0080     nodes[pos].parent = parent;
0081     nodes[pos].data = i;
0082     nodes[pos].type = Node::Introspectable;
0083     int prevp = -1;
0084     int p = pos+1;
0085     for (int j=0; j<is->numberOfMembers; ++j) {
0086         for (int k=0; k<is->numberOfInstances[j](i); ++k) {
0087             const Introspectable* ci = is->introspectable[j](i, k);
0088             if (nodes[pos].firstChild == -1) {
0089                 nodes[pos].firstChild = p;
0090             }
0091             if (prevp != -1) {
0092                 nodes[p].prev = prevp;
0093                 nodes[prevp].next = p;
0094             }
0095             prevp = p;
0096             nodes[p].memberno = j;
0097             nodes[p].arrayno = k;
0098             if (ci) {
0099                 addIntrospectable(nodes, ci, p, pos);
0100                 p += 1 + countItems(ci);
0101             } else {
0102                 nodes[p].parent = pos;
0103                 nodes[p].data = i;
0104                 nodes[p].type = Node::ValueElement;
0105                 p += 1; // skip empty position
0106             }
0107         }
0108     }
0109 }
0110 
0111 QVector<Node>
0112 createNodes(const QMap<QString, QSharedPointer<const Introspectable> >&
0113         streams) {
0114     QVector<Node> nodes(countItems(streams));
0115     nodes[0].parent = -1; nodes[0].prev = -1; nodes[0].next = -1;
0116     nodes[0].firstChild = 1; nodes[0].type = Node::Document;
0117     nodes[1].parent =  0; nodes[1].prev = -1; nodes[1].next = -1;
0118     nodes[1].firstChild = (streams.size()) ?2 :-1;
0119     nodes[1].type = Node::RootElement;
0120     int prevp = -1;
0121     int p = 2;
0122     QMap<QString, QSharedPointer<const Introspectable> >::const_iterator it
0123         = streams.begin();
0124     while (it != streams.end()) {
0125         const Introspectable* i = it.value().data();
0126         addIntrospectable(nodes, i, p, 1);
0127         if (prevp != -1) {
0128             nodes[p].prev = prevp;
0129             nodes[prevp].next = p;
0130         }
0131         nodes[p].type = Node::Stream;
0132         prevp = p;
0133         p += 1 + countItems(i);
0134         it++;
0135     }
0136     return nodes;
0137 }
0138 
0139 }
0140 
0141 class MsoXmlNodeModel::Private {
0142 public:
0143     QXmlNamePool namepool;
0144     QString filepath;
0145     const QMap<QString, QSharedPointer<const Introspectable> > streams;
0146     const QVector<Node> nodes;
0147     const QXmlName ppt;
0148     const QXmlName directory;
0149     const QXmlName file;
0150     const QXmlName olestream;
0151     const QXmlName olestreamdir;
0152     const QXmlName name;
0153     const QXmlName size;
0154     const QXmlName type;
0155 
0156     static const QMap<QString, QSharedPointer<const Introspectable> > read(
0157             const char* filepath) {
0158         QString file = QString::fromLocal8Bit(filepath);
0159         const QMap<QString, QByteArray> streams = readStreams(file);
0160         return parseStreams(streams);
0161     }
0162 
0163     Private(const QXmlNamePool& pool, const char* filepath_) :namepool(pool),
0164             filepath(filepath_),
0165             streams(read(filepath_)),
0166             nodes(createNodes(streams)),
0167             ppt(QXmlName(namepool, QLatin1String("ppt"))),
0168             directory(QXmlName(namepool, QLatin1String("directory"))),
0169             file(QXmlName(namepool, QLatin1String("file"))),
0170             olestream(QXmlName(namepool, QLatin1String("olestream"))),
0171             olestreamdir(QXmlName(namepool, QLatin1String("olestreamdir"))),
0172             name(QXmlName(namepool, QLatin1String("name"))),
0173             size(QXmlName(namepool, QLatin1String("size"))),
0174             type(QXmlName(namepool, QLatin1String("type"))) {
0175     }
0176 
0177     void getIndex(QAbstractXmlNodeModel::SimpleAxis axis, qint64& data,
0178             qint64& additionalData) {
0179         if (additionalData == 1) {
0180             additionalData = 0;
0181             if (axis != Parent) data = -1;
0182             return;
0183         }
0184         const Node& node = nodes[data];
0185         // additionalData = 0;
0186         if (axis == Parent) {
0187             data = node.parent;
0188             return;
0189         }
0190         if (axis == FirstChild) {
0191             if (node.type == Node::ValueElement) {
0192                 additionalData = 1;
0193             } else {
0194                 data = node.firstChild;
0195             }
0196             return;
0197         }
0198         data = (axis == NextSibling) ?node.next :node.prev;
0199     }
0200  
0201     QXmlName getName(qint64 n, qint64 a) {
0202         if (a) return type;
0203         const Node& node = nodes[n];
0204         const Introspectable* i
0205             = static_cast<const Introspectable*>(nodes[node.parent].data);
0206         const Introspection* si = i->getIntrospection();
0207         return QXmlName(namepool, si->names[node.memberno]);
0208     }
0209 };
0210 
0211 MsoXmlNodeModel::MsoXmlNodeModel(const QXmlNamePool& pool, const char* filepath)
0212         :d(new Private(pool, filepath)) {
0213 }
0214 MsoXmlNodeModel::~MsoXmlNodeModel() {
0215     delete d;
0216 }
0217 
0218 QVector<QXmlNodeModelIndex>
0219 MsoXmlNodeModel::attributes(const QXmlNodeModelIndex& element) const {
0220     QVector<QXmlNodeModelIndex> v;
0221     const Node& node = d->nodes[element.data()];
0222     if (node.type == Node::Introspectable && element.additionalData() == 0) {
0223         v.append(createIndex(element.data(), 1));
0224     }
0225     return v;
0226 }
0227 
0228 QXmlNodeModelIndex
0229 MsoXmlNodeModel::nextFromSimpleAxis(SimpleAxis axis,
0230         const QXmlNodeModelIndex& origin) const {
0231     qint64 data = -1;
0232     qint64 additionalData = 0;
0233     const Node& node = d->nodes[origin.data()];
0234     if (node.type == Node::Introspectable || node.type == Node::ValueElement) {
0235         data = origin.data();
0236         additionalData = origin.additionalData();
0237         d->getIndex(axis, data, additionalData);
0238     } else {
0239         switch (axis) {
0240             case Parent:          data = node.parent;     break;
0241             case FirstChild:      data = node.firstChild; break;
0242             case PreviousSibling: data = node.prev;       break;
0243             case NextSibling:     data = node.next;       break;
0244             default: break;
0245         }
0246     }
0247     return (data == -1)
0248         ?QXmlNodeModelIndex() :createIndex(data, additionalData);
0249 }
0250 
0251 QUrl
0252 MsoXmlNodeModel::baseUri(const QXmlNodeModelIndex& n) const {
0253     return documentUri(n);
0254 }
0255 QXmlNodeModelIndex::DocumentOrder
0256 MsoXmlNodeModel::compareOrder(const QXmlNodeModelIndex& ni1,
0257         const QXmlNodeModelIndex& ni2) const {
0258     if (ni1.data() < ni2.data()) return QXmlNodeModelIndex::Precedes;
0259     if (ni1.data() == ni2.data()) {
0260         if (ni1.additionalData() < ni2.additionalData())
0261             return QXmlNodeModelIndex::Precedes;
0262         if (ni1.additionalData() == ni2.additionalData())
0263             return QXmlNodeModelIndex::Is;
0264     }
0265     return QXmlNodeModelIndex::Follows;
0266 }
0267 QUrl
0268 MsoXmlNodeModel::documentUri(const QXmlNodeModelIndex& n) const {
0269     return QUrl::fromLocalFile(d->filepath);
0270 }
0271 QXmlNodeModelIndex
0272 MsoXmlNodeModel::elementById(const QXmlName& id) const {
0273     return QXmlNodeModelIndex();
0274 }
0275 QXmlNodeModelIndex::NodeKind
0276 MsoXmlNodeModel::kind(const QXmlNodeModelIndex& ni) const {
0277     if (ni.data() == 0) return QXmlNodeModelIndex::Document;
0278     if (ni.additionalData() == 1) {
0279         const Node& node = d->nodes[ni.data()];
0280         if (node.type == Node::Introspectable) {
0281             return QXmlNodeModelIndex::Attribute;
0282         }
0283         return QXmlNodeModelIndex::Text;
0284     }
0285     return QXmlNodeModelIndex::Element; // no attributes yet
0286 }
0287 QXmlName
0288 MsoXmlNodeModel::name(const QXmlNodeModelIndex& ni) const {
0289     const Node& node = d->nodes[ni.data()];
0290     const Introspectable* i = static_cast<const Introspectable*>(node.data);
0291     const Introspection* si = (i) ?i->getIntrospection() :0;
0292     switch (node.type) {
0293         case Node::Document: return d->name; // should not matter
0294         case Node::RootElement: return d->ppt; 
0295         case Node::Stream: return QXmlName(d->namepool, si->name);
0296         case Node::Introspectable:
0297             return d->getName(ni.data(), ni.additionalData());
0298         case Node::ValueElement:
0299             return d->getName(ni.data(), ni.additionalData());
0300         default: break;
0301     }
0302     return QXmlName();
0303 }
0304 QVector<QXmlName>
0305 MsoXmlNodeModel::namespaceBindings(const QXmlNodeModelIndex& n) const {
0306     return QVector<QXmlName>();
0307 }
0308 QVector<QXmlNodeModelIndex>
0309 MsoXmlNodeModel::nodesByIdref(const QXmlName& idref) const {
0310     return QVector<QXmlNodeModelIndex>();
0311 }
0312 QXmlNodeModelIndex
0313 MsoXmlNodeModel::root(const QXmlNodeModelIndex& n) const {
0314     return createIndex((qint64)0);
0315 }
0316 QString
0317 MsoXmlNodeModel::stringValue(const QXmlNodeModelIndex& n) const {
0318     return typedValue(n).toString();
0319 }
0320 QVariant
0321 MsoXmlNodeModel::typedValue(const QXmlNodeModelIndex& n) const {
0322     if (n.additionalData() == 1) { //attribute or value type
0323         const Node& node = d->nodes[n.data()];
0324         const Introspectable* i
0325             = static_cast<const Introspectable*>(d->nodes[n.data()].data);
0326         const Introspection* si = i->getIntrospection();
0327         if (node.type == Node::Introspectable) {
0328             return si->name;
0329         }
0330         return si->value[node.memberno](i, node.arrayno);
0331     }
0332     return QVariant();
0333 }