File indexing completed on 2024-06-23 04:03:44
0001 /* 0002 * xmlcommon.cpp - helper functions for dealing with XML 0003 * Copyright (C) 2001, 2002 Justin Karneges 0004 * 0005 * This library is free software; you can redistribute it and/or 0006 * modify it under the terms of the GNU Lesser General Public 0007 * License as published by the Free Software Foundation; either 0008 * either version 2 0009 of the License, or (at your option) any later version.1 of the License, or (at your option) any later version. 0010 * 0011 * This library is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0014 * Lesser General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU Lesser General Public 0017 * License along with this library; if not, write to the Free Software 0018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 0019 * 0020 */ 0021 0022 #include "xmpp_xmlcommon.h" 0023 #include "xmpp_stanza.h" 0024 0025 #include <QString> 0026 #include <QDateTime> 0027 #include <QSize> 0028 #include <QRect> 0029 #include <QColor> 0030 0031 //---------------------------------------------------------------------------- 0032 // XDomNodeList 0033 //---------------------------------------------------------------------------- 0034 XDomNodeList::XDomNodeList() 0035 { 0036 } 0037 0038 XDomNodeList::XDomNodeList(const XDomNodeList &from) : 0039 list(from.list) 0040 { 0041 } 0042 0043 XDomNodeList::XDomNodeList(const QDomNodeList &from) 0044 { 0045 for(int n = 0; n < from.count(); ++n) 0046 list += from.item(n); 0047 } 0048 0049 XDomNodeList::~XDomNodeList() 0050 { 0051 } 0052 0053 XDomNodeList & XDomNodeList::operator=(const XDomNodeList &from) 0054 { 0055 list = from.list; 0056 return *this; 0057 } 0058 0059 bool XDomNodeList::isEmpty() const 0060 { 0061 return list.isEmpty(); 0062 } 0063 0064 QDomNode XDomNodeList::item(int index) const 0065 { 0066 return list.value(index); 0067 } 0068 0069 uint XDomNodeList::length() const 0070 { 0071 return (uint)list.count(); 0072 } 0073 0074 bool XDomNodeList::operator==(const XDomNodeList &a) const 0075 { 0076 return (list == a.list); 0077 } 0078 0079 void XDomNodeList::append(const QDomNode &i) 0080 { 0081 list += i; 0082 } 0083 0084 0085 QDateTime stamp2TS(const QString &ts) 0086 { 0087 if(ts.length() != 17) 0088 return QDateTime(); 0089 int year = QStringView(ts).mid(0,4).toInt(); 0090 int month = QStringView(ts).mid(4,2).toInt(); 0091 int day = QStringView(ts).mid(6,2).toInt(); 0092 0093 int hour = QStringView(ts).mid(9,2).toInt(); 0094 int min = QStringView(ts).mid(12,2).toInt(); 0095 int sec = QStringView(ts).mid(15,2).toInt(); 0096 0097 QDate xd; 0098 xd.setDate(year, month, day); 0099 if(!xd.isValid()) 0100 return QDateTime(); 0101 0102 QTime xt; 0103 xt.setHMS(hour, min, sec); 0104 if(!xt.isValid()) 0105 return QDateTime(); 0106 0107 return QDateTime(xd, xt); 0108 } 0109 0110 bool stamp2TS(const QString &ts, QDateTime *d) 0111 { 0112 QDateTime dateTime = stamp2TS(ts); 0113 if (dateTime.isNull()) 0114 return false; 0115 0116 *d = dateTime; 0117 0118 return true; 0119 } 0120 0121 QString TS2stamp(const QDateTime &d) 0122 { 0123 const QString str = QString::asprintf("%04d%02d%02dT%02d:%02d:%02d", 0124 d.date().year(), 0125 d.date().month(), 0126 d.date().day(), 0127 d.time().hour(), 0128 d.time().minute(), 0129 d.time().second()); 0130 0131 return str; 0132 } 0133 0134 QDomElement textTag(QDomDocument *doc, const QString &name, const QString &content) 0135 { 0136 QDomElement tag = doc->createElement(name); 0137 QDomText text = doc->createTextNode(content); 0138 tag.appendChild(text); 0139 0140 return tag; 0141 } 0142 0143 QString tagContent(const QDomElement &e) 0144 { 0145 // look for some tag content 0146 for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { 0147 QDomText i = n.toText(); 0148 if(i.isNull()) 0149 continue; 0150 return i.data(); 0151 } 0152 0153 return ""; 0154 } 0155 0156 0157 /** 0158 * \brief find an direct child element by name 0159 * \param e parent element 0160 * \param name name of element to find 0161 * \param found (optional/out) found? 0162 * \return the element (or a null QDomElemnt if not found) 0163 */ 0164 QDomElement findSubTag(const QDomElement &e, const QString &name, bool *found) 0165 { 0166 if(found) 0167 *found = false; 0168 0169 for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { 0170 QDomElement i = n.toElement(); 0171 if(i.isNull()) 0172 continue; 0173 if(i.tagName() == name) { 0174 if(found) 0175 *found = true; 0176 return i; 0177 } 0178 } 0179 0180 QDomElement tmp; 0181 return tmp; 0182 } 0183 0184 0185 /** 0186 * \brief obtain direct child elements of a certain kind. unlike 0187 * elementsByTagNameNS, this function does not descend beyond the first 0188 * level of children. 0189 * \param e parent element 0190 * \param nsURI namespace of the elements to find 0191 * \param localName local name of the elements to find 0192 * \return the node list of found elements (empty list if none are found) 0193 */ 0194 XDomNodeList childElementsByTagNameNS(const QDomElement &e, const QString &nsURI, const QString &localName) 0195 { 0196 XDomNodeList out; 0197 for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { 0198 if(!n.isElement()) 0199 continue; 0200 QDomElement i = n.toElement(); 0201 if(i.namespaceURI() == nsURI && i.localName() == localName) 0202 out.append(i); 0203 } 0204 return out; 0205 } 0206 0207 0208 /** 0209 * \brief create a new IQ stanza 0210 * \param doc 0211 * \param type 0212 * \param to destination jid 0213 * \param id stanza id 0214 * \return the created stanza 0215 */ 0216 QDomElement createIQ(QDomDocument *doc, const QString &type, const QString &to, const QString &id) 0217 { 0218 QDomElement iq = doc->createElement("iq"); 0219 if(!type.isEmpty()) 0220 iq.setAttribute("type", type); 0221 if(!to.isEmpty()) 0222 iq.setAttribute("to", to); 0223 if(!id.isEmpty()) 0224 iq.setAttribute("id", id); 0225 0226 return iq; 0227 } 0228 0229 /** \brief returns direct child element named "query" 0230 * \return the element (or a null QDomElemnt if not found) 0231 */ 0232 QDomElement queryTag(const QDomElement &e) 0233 { 0234 bool found; 0235 QDomElement q = findSubTag(e, "query", &found); 0236 return q; 0237 } 0238 0239 QString queryNS(const QDomElement &e) 0240 { 0241 bool found; 0242 QDomElement q = findSubTag(e, "query", &found); 0243 if(found) 0244 return q.attribute("xmlns"); 0245 0246 return ""; 0247 } 0248 0249 /** 0250 \brief Extracts the error code and description from the stanza element. 0251 0252 This function finds the error element in the given stanza element \a e. 0253 0254 You need to provide the base namespace of the stream to which this stanza belongs to 0255 (probably by using stream.baseNS() function). 0256 0257 The error description is either error text extracted from XML 0258 or - if no text is found - the error name and description (separated by '\n') taken from RFC-3920 0259 or - if the error is not defined in the RFC - the empty string. 0260 0261 Note: This function uses the Stanza::Error class, 0262 so it may guess missing values as defined in JEP-0086. 0263 0264 \param e the element representing stanza 0265 \param baseNS the base namespace of the stream 0266 \param code if not NULL, will be filled with numeric error code 0267 \param str if not NULL, will be filled with human readable error description 0268 */ 0269 0270 void getErrorFromElement(const QDomElement &e, const QString &baseNS, int *code, QString *str) 0271 { 0272 bool found; 0273 QDomElement tag = findSubTag(e, "error", &found); 0274 if(!found) 0275 return; 0276 0277 XMPP::Stanza::Error err; 0278 err.fromXml(tag, baseNS); 0279 0280 if(code) 0281 *code = err.code(); 0282 if(str) { 0283 QPair<QString, QString> desc = err.description(); 0284 if (err.text.isEmpty()) 0285 *str = desc.first + ".\n" + desc.second; 0286 else 0287 *str = desc.first + ".\n" + desc.second + "\n" + err.text; 0288 } 0289 0290 } 0291 0292 QDomElement addCorrectNS(const QDomElement &e) 0293 { 0294 int x; 0295 0296 // grab child nodes 0297 /*QDomDocumentFragment frag = e.ownerDocument().createDocumentFragment(); 0298 QDomNodeList nl = e.childNodes(); 0299 for(x = 0; x < nl.count(); ++x) 0300 frag.appendChild(nl.item(x).cloneNode());*/ 0301 0302 // find closest xmlns 0303 QDomNode n = e; 0304 while(!n.isNull() && !n.toElement().hasAttribute("xmlns")) 0305 n = n.parentNode(); 0306 QString ns; 0307 if(n.isNull() || !n.toElement().hasAttribute("xmlns")) 0308 ns = "jabber:client"; 0309 else 0310 ns = n.toElement().attribute("xmlns"); 0311 0312 // make a new node 0313 QDomElement i = e.ownerDocument().createElementNS(ns, e.tagName()); 0314 0315 // copy attributes 0316 QDomNamedNodeMap al = e.attributes(); 0317 for(x = 0; x < al.count(); ++x) { 0318 QDomAttr a = al.item(x).toAttr(); 0319 if(a.name() != "xmlns") 0320 i.setAttributeNodeNS(a.cloneNode().toAttr()); 0321 } 0322 0323 // copy children 0324 QDomNodeList nl = e.childNodes(); 0325 for(x = 0; x < nl.count(); ++x) { 0326 QDomNode n = nl.item(x); 0327 if(n.isElement()) 0328 i.appendChild(addCorrectNS(n.toElement())); 0329 else 0330 i.appendChild(n.cloneNode()); 0331 } 0332 0333 //i.appendChild(frag); 0334 return i; 0335 } 0336 0337 //---------------------------------------------------------------------------- 0338 // XMLHelper 0339 //---------------------------------------------------------------------------- 0340 0341 namespace XMLHelper { 0342 0343 QDomElement emptyTag(QDomDocument *doc, const QString &name) 0344 { 0345 QDomElement tag = doc->createElement(name); 0346 0347 return tag; 0348 } 0349 0350 bool hasSubTag(const QDomElement &e, const QString &name) 0351 { 0352 bool found; 0353 findSubTag(e, name, &found); 0354 return found; 0355 } 0356 0357 QString subTagText(const QDomElement &e, const QString &name) 0358 { 0359 bool found; 0360 QDomElement i = findSubTag(e, name, &found); 0361 if ( found ) 0362 return i.text(); 0363 return QString(); 0364 } 0365 0366 QDomElement textTag(QDomDocument &doc, const QString &name, const QString &content) 0367 { 0368 QDomElement tag = doc.createElement(name); 0369 QDomText text = doc.createTextNode(content); 0370 tag.appendChild(text); 0371 0372 return tag; 0373 } 0374 0375 QDomElement textTag(QDomDocument &doc, const QString &name, int content) 0376 { 0377 QDomElement tag = doc.createElement(name); 0378 QDomText text = doc.createTextNode(QString::number(content)); 0379 tag.appendChild(text); 0380 0381 return tag; 0382 } 0383 0384 QDomElement textTag(QDomDocument &doc, const QString &name, bool content) 0385 { 0386 QDomElement tag = doc.createElement(name); 0387 QDomText text = doc.createTextNode(content ? "true" : "false"); 0388 tag.appendChild(text); 0389 0390 return tag; 0391 } 0392 0393 QDomElement textTag(QDomDocument &doc, const QString &name, QSize &s) 0394 { 0395 const QString str = QString::asprintf("%d,%d", s.width(), s.height()); 0396 0397 QDomElement tag = doc.createElement(name); 0398 QDomText text = doc.createTextNode(str); 0399 tag.appendChild(text); 0400 0401 return tag; 0402 } 0403 0404 QDomElement textTag(QDomDocument &doc, const QString &name, QRect &r) 0405 { 0406 const QString str = QString::asprintf("%d,%d,%d,%d", r.x(), r.y(), r.width(), r.height()); 0407 0408 QDomElement tag = doc.createElement(name); 0409 QDomText text = doc.createTextNode(str); 0410 tag.appendChild(text); 0411 0412 return tag; 0413 } 0414 0415 QDomElement stringListToXml(QDomDocument &doc, const QString &name, const QStringList &l) 0416 { 0417 QDomElement tag = doc.createElement(name); 0418 for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) 0419 tag.appendChild(textTag(doc, "item", *it)); 0420 0421 return tag; 0422 } 0423 0424 /*QString tagContent(const QDomElement &e) 0425 { 0426 // look for some tag content 0427 for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { 0428 QDomText i = n.toText(); 0429 if(i.isNull()) 0430 continue; 0431 return i.data(); 0432 } 0433 0434 return ""; 0435 }*/ 0436 0437 /*QDomElement findSubTag(const QDomElement &e, const QString &name, bool *found) 0438 { 0439 if(found) 0440 *found = false; 0441 0442 for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) { 0443 QDomElement i = n.toElement(); 0444 if(i.isNull()) 0445 continue; 0446 if(i.tagName() == name) { 0447 if(found) 0448 *found = true; 0449 return i; 0450 } 0451 } 0452 0453 QDomElement tmp; 0454 return tmp; 0455 }*/ 0456 0457 void readEntry(const QDomElement &e, const QString &name, QString *v) 0458 { 0459 bool found = false; 0460 QDomElement tag = findSubTag(e, name, &found); 0461 if(!found) 0462 return; 0463 *v = tagContent(tag); 0464 } 0465 0466 void readNumEntry(const QDomElement &e, const QString &name, int *v) 0467 { 0468 bool found = false; 0469 QDomElement tag = findSubTag(e, name, &found); 0470 if(!found) 0471 return; 0472 *v = tagContent(tag).toInt(); 0473 } 0474 0475 void readBoolEntry(const QDomElement &e, const QString &name, bool *v) 0476 { 0477 bool found = false; 0478 QDomElement tag = findSubTag(e, name, &found); 0479 if(!found) 0480 return; 0481 *v = (tagContent(tag) == "true") ? true: false; 0482 } 0483 0484 void readSizeEntry(const QDomElement &e, const QString &name, QSize *v) 0485 { 0486 bool found = false; 0487 QDomElement tag = findSubTag(e, name, &found); 0488 if(!found) 0489 return; 0490 QStringList list = tagContent(tag).split(','); 0491 if(list.count() != 2) 0492 return; 0493 QSize s; 0494 s.setWidth(list[0].toInt()); 0495 s.setHeight(list[1].toInt()); 0496 *v = s; 0497 } 0498 0499 void readRectEntry(const QDomElement &e, const QString &name, QRect *v) 0500 { 0501 bool found = false; 0502 QDomElement tag = findSubTag(e, name, &found); 0503 if(!found) 0504 return; 0505 QStringList list = tagContent(tag).split(','); 0506 if(list.count() != 4) 0507 return; 0508 QRect r; 0509 r.setX(list[0].toInt()); 0510 r.setY(list[1].toInt()); 0511 r.setWidth(list[2].toInt()); 0512 r.setHeight(list[3].toInt()); 0513 *v = r; 0514 } 0515 0516 void readColorEntry(const QDomElement &e, const QString &name, QColor *v) 0517 { 0518 bool found = false; 0519 QDomElement tag = findSubTag(e, name, &found); 0520 if(!found) 0521 return; 0522 QColor c; 0523 c.setNamedColor(tagContent(tag)); 0524 if(c.isValid()) 0525 *v = c; 0526 } 0527 0528 void xmlToStringList(const QDomElement &e, const QString &name, QStringList *v) 0529 { 0530 bool found = false; 0531 QDomElement tag = findSubTag(e, name, &found); 0532 if(!found) 0533 return; 0534 QStringList list; 0535 for(QDomNode n = tag.firstChild(); !n.isNull(); n = n.nextSibling()) { 0536 QDomElement i = n.toElement(); 0537 if(i.isNull()) 0538 continue; 0539 if(i.tagName() == "item") 0540 list += tagContent(i); 0541 } 0542 *v = list; 0543 } 0544 0545 void setBoolAttribute(QDomElement e, const QString &name, bool b) 0546 { 0547 e.setAttribute(name, b ? "true" : "false"); 0548 } 0549 0550 void readBoolAttribute(QDomElement e, const QString &name, bool *v) 0551 { 0552 if(e.hasAttribute(name)) { 0553 QString s = e.attribute(name); 0554 *v = (s == "true") ? true: false; 0555 } 0556 } 0557 0558 } 0559