File indexing completed on 2025-02-09 04:28:40

0001 /*
0002   This file is part of the KTextTemplate library
0003 
0004   SPDX-FileCopyrightText: 2009, 2010 Stephen Kelly <steveire@gmail.com>
0005 
0006   SPDX-License-Identifier: LGPL-2.1-or-later
0007 
0008 */
0009 
0010 #ifndef KTEXTTEMPLATE_SAFESTRING_H
0011 #define KTEXTTEMPLATE_SAFESTRING_H
0012 
0013 #include "ktexttemplate_export.h"
0014 
0015 #include <QString>
0016 #include <QVariant>
0017 
0018 namespace KTextTemplate
0019 {
0020 
0021 /// @headerfile safestring.h <KTextTemplate/SafeString>
0022 
0023 /**
0024   @brief A QString wrapper class for containing whether a string is safe or
0025   needs to be escaped.
0026 
0027   This allows lazy escaping of strings. Otherwise a string may be escaped
0028   multiple times where it should only be escaped once.
0029 
0030   The **%SafeString** class itself provides information about whether a string
0031   is safe from further escaping through the @ref isSafe method. The actual
0032   string content held by the **%SafeString** instance is available through the
0033   @ref get method. The @ref get method returns a QString subclass which should
0034   be used like any other QString. The difference is that all methods on
0035   NestedString return a **%SafeString** instead of a QString.
0036 
0037   @code
0038     SafeString s("this & that", SafeString::IsSafe);
0039     s.get().replace( "this", "these" ).toUpper();
0040 
0041     qDebug() << s.get() << s.isSafe(); // outputs "these & that" false
0042   @endcode
0043 
0044   Note that most operations on strings make the string unsafe. For example,
0045   while <tt>"K &amp; R"</tt> is safe, using replace("m", "n") will result in
0046   <tt>"K &anp; R"</tt>, which is unsafe. Likewise using upper() will return
0047   <tt>"K &AMP; R"</tt>, which is unsafe. Because the **%SafeString** can not
0048   determine whether a method call with particular arguments will change
0049   a **%SafeString** from being safe to being unsafe, any operation which can
0050   possibly make the string unsafe does cause the string to become unsafe. It is
0051   then up to the caller to restore safe-ness if needed.
0052 
0053   NestedString has overloads for SafeStrings whereever appropriate so that
0054   strings remain marked as safe where possible.
0055 
0056   For example:
0057 
0058   @code
0059     SafeString s1("this & that", SafeString::IsSafe);
0060     s2 = s1;
0061     s1.append( QString( " & the other" ) );
0062     // s1 is now "this & that & the other" and is unsafe.
0063 
0064     SafeString s3(" Wobl & Bob", SafeString::IsSafe);
0065     s2.append(s3);
0066     // Both s2 and s3 are safe, and append is a safe operation, so s2
0067     // is still safe
0068   @endcode
0069 
0070   @see @ref autoescaping
0071   @see OutputStream::escape
0072 
0073   The **%SafeString** class has appropriate operator overloads to make it
0074   convenient to use in methods returning a QVariant, such as Filter::doFilter,
0075   or as a QString. Note that a raw QString is essentially the same
0076   as a **%SafeString** which is marked as unsafe.
0077 
0078   @author Stephen Kelly <steveire@gmail.com>
0079 */
0080 class KTEXTTEMPLATE_EXPORT SafeString
0081 {
0082 public:
0083     /**
0084       Possible safety states of a **%SafeString**
0085     */
0086     enum Safety {
0087         IsSafe, ///< The string is safe and requires no further escaping
0088         IsNotSafe ///< The string is not safe. It will be escaped before being
0089                   /// added to the output of rendering.
0090     };
0091 
0092     /**
0093       Constructs an empty **%SafeString**.
0094     */
0095     SafeString();
0096 
0097     /**
0098       Copy constructor
0099     */
0100     SafeString(const SafeString &safeString);
0101 
0102     /**
0103       Constructs a **%SafeString** with the content @p str whose safety is given
0104       by @p safe.
0105     */
0106     SafeString(const QString &str, bool safe);
0107 
0108     /**
0109       Constructs a **%SafeString** with the content @p str whose safety is given
0110       by @p safety.
0111     */
0112     /* implicit */ SafeString(const QString &str,
0113                               Safety safety = IsNotSafe); // krazy:exclude=explicit
0114 
0115     /**
0116       Destructor
0117     */
0118     ~SafeString();
0119 
0120 #ifndef K_DOXYGEN
0121     /**
0122       Set whether the string should be escaped.
0123     */
0124     void setNeedsEscape(bool needsEscape);
0125 #endif
0126 
0127     /**
0128       Whether the string needs to be escaped.
0129     */
0130     bool needsEscape() const;
0131 
0132     /**
0133       Whether the string is safe.
0134     */
0135     bool isSafe() const;
0136 
0137 #ifndef K_DOXYGEN
0138     /**
0139       Set whether the string is safe.
0140     */
0141     void setSafety(Safety safety);
0142 #endif
0143 
0144     /**
0145       @brief The NestedString is a QString whose methods always return a
0146       SafeString
0147 
0148       This class is largely an implementation detail. See the SafeString
0149       documentation for details.
0150     */
0151     class KTEXTTEMPLATE_EXPORT NestedString : public QString
0152     {
0153 #ifndef K_DOXYGEN
0154         friend class SafeString;
0155         SafeString *m_safeString;
0156 
0157     public:
0158         explicit NestedString(SafeString *safeString);
0159         NestedString(const QString &content, SafeString *safeString);
0160 
0161         SafeString &append(const SafeString &str);
0162         SafeString &append(const QString &str);
0163         SafeString &append(const QLatin1String &str);
0164 #ifndef QT_NO_CAST_FROM_ASCII
0165         SafeString &append(const QByteArray &ba)
0166         {
0167             QString::append(ba);
0168             m_safeString->m_safety = IsNotSafe;
0169             return *m_safeString;
0170         }
0171 
0172         SafeString &append(const char *str)
0173         {
0174             QString::append(str);
0175             m_safeString->m_safety = IsNotSafe;
0176             return *m_safeString;
0177         }
0178 #endif
0179         SafeString &append(const QChar ch);
0180 
0181         SafeString &fill(QChar ch, int size = -1);
0182 
0183         SafeString &insert(int position, const SafeString &str);
0184         SafeString &insert(int position, const QString &str);
0185         SafeString &insert(int position, const QLatin1String &str);
0186         SafeString &insert(int position, const QChar *unicode, int size);
0187         SafeString &insert(int position, QChar ch);
0188 
0189         SafeString left(int n) const;
0190         SafeString leftJustified(int width, QChar fill = QLatin1Char(' '), bool truncate = {}) const;
0191         SafeString mid(int position, int n = -1) const;
0192 
0193         SafeString normalized(NormalizationForm mode) const;
0194         SafeString normalized(NormalizationForm mode, QChar::UnicodeVersion version) const;
0195 
0196         SafeString &prepend(const SafeString &str);
0197         SafeString &prepend(const QString &str);
0198         SafeString &prepend(const QLatin1String &str);
0199 #ifndef QT_NO_CAST_FROM_ASCII
0200         SafeString &prepend(const QByteArray &ba)
0201         {
0202             QString::prepend(ba);
0203             m_safeString->m_safety = IsNotSafe;
0204             return *m_safeString;
0205         }
0206 
0207         SafeString &prepend(const char *str)
0208         {
0209             QString::prepend(str);
0210             m_safeString->m_safety = IsNotSafe;
0211             return *m_safeString;
0212         }
0213 #endif
0214         SafeString &prepend(QChar ch);
0215 
0216         void push_back(const SafeString &other);
0217         void push_front(const SafeString &other);
0218 
0219         SafeString &remove(int position, int n);
0220         SafeString &remove(QChar ch, Qt::CaseSensitivity cs = Qt::CaseSensitive);
0221         SafeString &remove(const SafeString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive);
0222         SafeString &remove(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive);
0223         SafeString &remove(const QRegularExpression &rx);
0224         SafeString repeated(int times) const;
0225         SafeString &replace(int position, int n, const SafeString &after);
0226         SafeString &replace(int position, int n, const QString &after);
0227         SafeString &replace(int position, int n, const QChar *unicode, int size);
0228         SafeString &replace(int position, int n, QChar after);
0229         SafeString &replace(const SafeString &before, const SafeString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive);
0230         SafeString &replace(const QString &before, const SafeString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive);
0231         SafeString &replace(const SafeString &before, const QString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive);
0232         SafeString &replace(const QString &before, const QString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive);
0233         SafeString &replace(const QChar *before, int blen, const QChar *after, int alen, Qt::CaseSensitivity cs = Qt::CaseSensitive);
0234         SafeString &replace(QChar ch, const SafeString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive);
0235         SafeString &replace(QChar ch, const QString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive);
0236         SafeString &replace(QChar before, QChar after, Qt::CaseSensitivity cs = Qt::CaseSensitive);
0237         SafeString &replace(const QLatin1String &before, const QLatin1String &after, Qt::CaseSensitivity cs = Qt::CaseSensitive);
0238         SafeString &replace(const QLatin1String &before, const SafeString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive);
0239         SafeString &replace(const QLatin1String &before, const QString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive);
0240         SafeString &replace(const SafeString &before, const QLatin1String &after, Qt::CaseSensitivity cs = Qt::CaseSensitive);
0241         SafeString &replace(const QString &before, const QLatin1String &after, Qt::CaseSensitivity cs = Qt::CaseSensitive);
0242         SafeString &replace(QChar c, const QLatin1String &after, Qt::CaseSensitivity cs = Qt::CaseSensitive);
0243         SafeString &replace(const QRegularExpression &rx, const SafeString &after);
0244         SafeString &replace(const QRegularExpression &rx, const QString &after);
0245 
0246         SafeString right(int n) const;
0247         SafeString rightJustified(int width, QChar fill = QLatin1Char(' '), bool truncate = {}) const;
0248 
0249         SafeString section(QChar sep, int start, int end = -1, SectionFlags flags = SectionDefault) const;
0250         SafeString section(const SafeString &sep, int start, int end = -1, SectionFlags flags = SectionDefault) const;
0251         SafeString section(const QString &sep, int start, int end = -1, SectionFlags flags = SectionDefault) const;
0252         SafeString section(const QRegularExpression &reg, int start, int end = -1, SectionFlags flags = SectionDefault) const;
0253         SafeString &setNum(int n, int base = 10);
0254         SafeString &setNum(uint n, int base = 10);
0255         SafeString &setNum(long n, int base = 10);
0256         SafeString &setNum(ulong n, int base = 10);
0257         SafeString &setNum(qlonglong n, int base = 10);
0258         SafeString &setNum(qulonglong n, int base = 10);
0259         SafeString &setNum(short n, int base = 10);
0260         SafeString &setNum(ushort n, int base = 10);
0261         SafeString &setNum(double n, char format = 'g', int precision = 6);
0262         SafeString &setNum(float n, char format = 'g', int precision = 6);
0263         SafeString &setUnicode(const QChar *unicode, int size);
0264         SafeString &setUtf16(const ushort *unicode, int size);
0265         SafeString simplified() const;
0266 
0267         QStringList split(const SafeString &sep, Qt::SplitBehavior behavior = Qt::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
0268         QStringList split(const QString &sep, Qt::SplitBehavior behavior = Qt::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
0269         QStringList split(const QChar &sep, Qt::SplitBehavior behavior = Qt::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
0270         QStringList split(const QRegularExpression &rx, Qt::SplitBehavior behavior = Qt::KeepEmptyParts) const;
0271 
0272         SafeString toLower() const;
0273         SafeString toUpper() const;
0274         SafeString trimmed() const;
0275 
0276         void chop(int n);
0277 #endif
0278     };
0279 
0280     /**
0281       Returns the String held by this **%SafeString**
0282     */
0283     const NestedString &get() const
0284     {
0285         return m_nestedString;
0286     }
0287 
0288     /**
0289       Returns the String held by this **%SafeString**
0290     */
0291     NestedString &get()
0292     {
0293         return m_nestedString;
0294     }
0295 
0296     /**
0297       Convenience operator for treating a **%SafeString** like a QString.
0298     */
0299     operator QString() const
0300     {
0301         return m_nestedString;
0302     }
0303 
0304     /**
0305       Assignment operator.
0306     */
0307     SafeString &operator=(const SafeString &str);
0308 
0309     /**
0310       Returns a concatenation of this with @p str.
0311 
0312       The result is not safe because str is not safe.
0313     */
0314     SafeString operator+(const QString &str);
0315 
0316     /**
0317       Returns a concatenation of this with @p str.
0318 
0319       The result is safe if both this and str are safe.
0320     */
0321     SafeString operator+(const SafeString &str);
0322 
0323     /**
0324       Appends the content of @p str to this.
0325 
0326       The result is not safe because @p str is not safe.
0327     */
0328     SafeString &operator+=(const QString &str);
0329 
0330     /**
0331       Appends the content of @p str to this.
0332 
0333       The result is safe if both this and @p str are safe.
0334     */
0335     SafeString &operator+=(const SafeString &str);
0336 
0337     /**
0338       Returns true if the content of @p other matches the content of this.
0339 
0340       Safeness and needing escaping are not accounted for in the comparison.
0341     */
0342     bool operator==(const SafeString &other) const;
0343 
0344     /**
0345       Returns true if the content of @p other matches the content of this.
0346 
0347       Safeness and needing escaping are not accounted for in the comparison.
0348     */
0349     bool operator==(const QString &other) const;
0350 
0351     /**
0352       Convenience operator for storing a **%SafeString** in a QVariant.
0353     */
0354     operator QVariant() const
0355     {
0356         return QVariant::fromValue(*this);
0357     }
0358 
0359 private:
0360 #ifndef K_DOXYGEN
0361     NestedString m_nestedString;
0362 #endif
0363     Safety m_safety;
0364     bool m_needsescape;
0365 };
0366 }
0367 
0368 Q_DECLARE_METATYPE(KTextTemplate::SafeString)
0369 
0370 #endif