File indexing completed on 2024-04-28 15:34:22

0001 /*
0002     This file is part of the syndication library
0003     SPDX-FileCopyrightText: 2006 Frank Osterfeld <osterfeld@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "content.h"
0009 
0010 #include <tools.h>
0011 
0012 #include <QByteArray>
0013 #include <QDomElement>
0014 #include <QStringList>
0015 
0016 namespace Syndication
0017 {
0018 namespace Atom
0019 {
0020 class SYNDICATION_NO_EXPORT Content::ContentPrivate
0021 {
0022 public:
0023     ContentPrivate()
0024         : formatIdentified(false)
0025     {
0026     }
0027     mutable Format format;
0028     mutable bool formatIdentified;
0029 };
0030 
0031 Content::Content()
0032     : ElementWrapper()
0033     , d(new ContentPrivate)
0034 {
0035 }
0036 
0037 Content::Content(const QDomElement &element)
0038     : ElementWrapper(element)
0039     , d(new ContentPrivate)
0040 {
0041 }
0042 
0043 Content::Content(const Content &other)
0044     : ElementWrapper(other)
0045     , d(other.d)
0046 {
0047 }
0048 
0049 Content::~Content()
0050 {
0051 }
0052 
0053 Content &Content::operator=(const Content &other)
0054 {
0055     ElementWrapper::operator=(other);
0056     d = other.d;
0057     return *this;
0058 }
0059 
0060 QString Content::type() const
0061 {
0062     return attribute(QStringLiteral("type"));
0063 }
0064 
0065 QString Content::src() const
0066 {
0067     return completeURI(attribute(QStringLiteral("src")));
0068 }
0069 
0070 QByteArray Content::asByteArray() const
0071 {
0072     if (!isBinary()) {
0073         return QByteArray();
0074     }
0075     return QByteArray::fromBase64(text().trimmed().toLatin1());
0076 }
0077 
0078 Content::Format Content::mapTypeToFormat(const QString &typep, const QString &src)
0079 {
0080     QString type = typep;
0081     //"If neither the type attribute nor the src attribute is provided,
0082     // Atom Processors MUST behave as though the type attribute were
0083     // present with a value of "text""
0084     if (type.isNull() && src.isEmpty()) {
0085         type = QStringLiteral("text");
0086     }
0087 
0088     if (type == QLatin1String("html") || type == QLatin1String("text/html")) {
0089         return EscapedHTML;
0090     }
0091 
0092     /* clang-format off */
0093     if (type == QLatin1String("text")
0094         || (type.startsWith(QLatin1String("text/"), Qt::CaseInsensitive)
0095             && !type.startsWith(QLatin1String("text/xml"), Qt::CaseInsensitive))) { /* clang-format on */
0096         return PlainText;
0097     }
0098 
0099     static QStringList xmltypes;
0100     if (xmltypes.isEmpty()) {
0101         xmltypes.reserve(8);
0102         xmltypes.append(QStringLiteral("xhtml"));
0103         xmltypes.append(QStringLiteral("application/xhtml+xml"));
0104         // XML media types as defined in RFC3023:
0105         xmltypes.append(QStringLiteral("text/xml"));
0106         xmltypes.append(QStringLiteral("application/xml"));
0107         xmltypes.append(QStringLiteral("text/xml-external-parsed-entity"));
0108         xmltypes.append(QStringLiteral("application/xml-external-parsed-entity"));
0109         xmltypes.append(QStringLiteral("application/xml-dtd"));
0110         xmltypes.append(QStringLiteral("text/x-dtd")); // from shared-mime-info
0111     }
0112 
0113     /* clang-format off */
0114     if (xmltypes.contains(type)
0115         || type.endsWith(QLatin1String("+xml"), Qt::CaseInsensitive)
0116         || type.endsWith(QLatin1String("/xml"), Qt::CaseInsensitive)) { /* clang-format on */
0117         return XML;
0118     }
0119 
0120     return Binary;
0121 }
0122 
0123 Content::Format Content::format() const
0124 {
0125     if (d->formatIdentified == false) {
0126         d->format = mapTypeToFormat(type(), src());
0127         d->formatIdentified = true;
0128     }
0129     return d->format;
0130 }
0131 
0132 bool Content::isBinary() const
0133 {
0134     return format() == Binary;
0135 }
0136 
0137 bool Content::isContained() const
0138 {
0139     return src().isEmpty();
0140 }
0141 
0142 bool Content::isPlainText() const
0143 {
0144     return format() == PlainText;
0145 }
0146 
0147 bool Content::isEscapedHTML() const
0148 {
0149     return format() == EscapedHTML;
0150 }
0151 
0152 bool Content::isXML() const
0153 {
0154     return format() == XML;
0155 }
0156 
0157 QString Content::asString() const
0158 {
0159     Format f = format();
0160 
0161     if (f == PlainText) {
0162         return plainTextToHtml(text()).trimmed();
0163     } else if (f == EscapedHTML) {
0164         return text().trimmed();
0165     } else if (f == XML) {
0166         return childNodesAsXML().trimmed();
0167     }
0168 
0169     return QString();
0170 }
0171 
0172 QString Content::debugInfo() const
0173 {
0174     QString info = QLatin1String("### Content: ###################\n");
0175     info += QLatin1String("type: #") + type() + QLatin1String("#\n");
0176     if (!src().isNull()) {
0177         info += QLatin1String("src: #") + src() + QLatin1String("#\n");
0178     }
0179     if (!isBinary()) {
0180         info += QLatin1String("content: #") + asString() + QLatin1String("#\n");
0181     } else {
0182         info += QLatin1String("binary length: #") + QString::number(asByteArray().size()) + QLatin1String("#\n");
0183     }
0184     info += QLatin1String("### Content end ################\n");
0185 
0186     return info;
0187 }
0188 
0189 } // namespace Atom
0190 } // namespace Syndication