// Copyright 2005-2020 The Mumble Developers. All rights reserved. // Use of this source code is governed by a BSD-style license // that can be found in the LICENSE file at the root of the // Mumble source tree or at . #include "XMLTools.h" #include #include #include void XMLTools::recurseParse(QXmlStreamReader &reader, QXmlStreamWriter &writer, int ¶graphs, const QMap &opstyle, const int close, bool ignore) { while (! reader.atEnd()) { QXmlStreamReader::TokenType tt = reader.readNext(); QXmlStreamAttributes a = reader.attributes(); QMap style; QMap pstyle = opstyle; QStringRef styleref = a.value(QLatin1String("style")); if (!styleref.isNull()) { QString stylestring = styleref.toString(); QStringList styles = stylestring.split(QLatin1String(";"), QString::SkipEmptyParts); foreach(QString s, styles) { s = s.simplified(); int idx = s.indexOf(QLatin1Char(':')); QString key = (idx > 0) ? s.left(idx).simplified() : s; QString val = (idx > 0) ? s.mid(idx+1).simplified() : QString(); if (! pstyle.contains(key) || (pstyle.value(key) != val)) { style.insert(key,val); pstyle.insert(key,val); } } } switch (tt) { case QXmlStreamReader::StartElement: { QString name = reader.name().toString(); int rclose = 1; if (name == QLatin1String("body")) { rclose = 0; ignore = false; } else if (name == QLatin1String("span")) { // Substitute style with , and rclose = 0; if (style.value(QLatin1String("font-weight")) == QLatin1String("600")) { writer.writeStartElement(QLatin1String("b")); rclose++; style.remove(QLatin1String("font-weight")); } if (style.value(QLatin1String("font-style")) == QLatin1String("italic")) { writer.writeStartElement(QLatin1String("i")); rclose++; style.remove(QLatin1String("font-style")); } if (style.value(QLatin1String("text-decoration")) == QLatin1String("underline")) { writer.writeStartElement(QLatin1String("u")); rclose++; style.remove(QLatin1String("text-decoration")); } if (! style.isEmpty()) { rclose++; writer.writeStartElement(name); QStringList qsl; QMap::const_iterator i; for (i=style.constBegin(); i != style.constEnd(); ++i) { if (! i.value().isEmpty()) qsl << QString::fromLatin1("%1:%2").arg(i.key(), i.value()); else qsl << i.key(); } writer.writeAttribute(QLatin1String("style"), qsl.join(QLatin1String("; "))); } } else if (name == QLatin1String("p")) { paragraphs++; if (paragraphs == 1) { // Ignore first paragraph. If it is styled empty drop its contents (e.g.
) too. if (style.value(QLatin1String("-qt-paragraph-type")) == QLatin1String("empty")) { reader.skipCurrentElement(); continue; } rclose = 0; } else { rclose = 1; writer.writeStartElement(name); if (! style.isEmpty()) { QStringList qsl; QMap::const_iterator i; for (i=style.constBegin(); i != style.constEnd(); ++i) { if (! i.value().isEmpty()) qsl << QString::fromLatin1("%1:%2").arg(i.key(), i.value()); else qsl << i.key(); } writer.writeAttribute(QLatin1String("style"), qsl.join(QLatin1String("; "))); } } } else if (name == QLatin1String("a")) { // Set pstyle to include implicit blue underline. rclose = 1; writer.writeCurrentToken(reader); pstyle.insert(QLatin1String("text-decoration"), QLatin1String("underline")); pstyle.insert(QLatin1String("color"), QLatin1String("#0000ff")); } else if (! ignore) { rclose = 1; writer.writeCurrentToken(reader); } recurseParse(reader, writer, paragraphs, pstyle, rclose, ignore); break; } case QXmlStreamReader::EndElement: if (!ignore) for (int i=0;i qlNames; QList qlAttributes; while (! reader.atEnd()) { QXmlStreamReader::TokenType tt = reader.readNext(); QString name = reader.name().toString(); switch (tt) { case QXmlStreamReader::StartDocument: case QXmlStreamReader::EndDocument: break; case QXmlStreamReader::StartElement: { QXmlStreamAttributes a = reader.attributes(); if (name == QLatin1String("unduplicate")) break; if (needclose) { needclose = false; if ((a == qlAttributes.last()) && (name == qlNames.last()) && (qslConcat.contains(name))) { changed = true; break; } qlNames.takeLast(); qlAttributes.takeLast(); writer.writeEndElement(); } writer.writeCurrentToken(reader); qlNames.append(name); qlAttributes.append(a); } break; case QXmlStreamReader::EndElement: { if (name == QLatin1String("unduplicate")) break; if (needclose) { qlNames.takeLast(); qlAttributes.takeLast(); writer.writeCurrentToken(reader); } needclose = true; } break; default: if (needclose) { writer.writeEndElement(); needclose = false; } writer.writeCurrentToken(reader); } } if (needclose) writer.writeEndElement(); return changed; }