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 }