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

0001 /**
0002  * This file is part of the DOM implementation for KDE.
0003  *
0004  * Copyright 1999 Lars Knoll (knoll@kde.org)
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Library General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2 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  * Library General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Library General Public License
0017  * along with this library; see the file COPYING.LIB.  If not, write to
0018  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020  */
0021 
0022 #include "dom/dom_string.h"
0023 #include "xml/dom_stringimpl.h"
0024 
0025 #include <wtf/Vector.h>
0026 
0027 using namespace DOM;
0028 
0029 DOMString::DOMString(const QChar *str, uint len)
0030 {
0031     if (!str) {
0032         impl = nullptr;
0033         return;
0034     }
0035     impl = new DOMStringImpl(str, len);
0036     impl->ref();
0037 }
0038 
0039 DOMString::DOMString(const QString &str)
0040 {
0041     if (str.isNull()) {
0042         impl = nullptr;
0043         return;
0044     }
0045 
0046     impl = new DOMStringImpl(str.unicode(), str.length());
0047     impl->ref();
0048 }
0049 
0050 DOMString::DOMString(const char *str)
0051 {
0052     if (!str) {
0053         impl = nullptr;
0054         return;
0055     }
0056 
0057     impl = new DOMStringImpl(str);
0058     impl->ref();
0059 }
0060 
0061 DOMString::DOMString(const char *str, uint len)
0062 {
0063     if (!str) {
0064         impl = nullptr;
0065         return;
0066     }
0067     impl = new DOMStringImpl(str, len);
0068     impl->ref();
0069 }
0070 
0071 DOMString::DOMString(DOMStringImpl *i)
0072 {
0073     impl = i;
0074     if (impl) {
0075         impl->ref();
0076     }
0077 }
0078 
0079 DOMString::DOMString(const DOMString &other)
0080 {
0081     impl = other.impl;
0082     if (impl) {
0083         impl->ref();
0084     }
0085 }
0086 
0087 DOMString::~DOMString()
0088 {
0089     if (impl) {
0090         impl->deref();
0091     }
0092 }
0093 
0094 DOMString &DOMString::operator =(const DOMString &other)
0095 {
0096     if (impl != other.impl) {
0097         if (impl) {
0098             impl->deref();
0099         }
0100         impl = other.impl;
0101         if (impl) {
0102             impl->ref();
0103         }
0104     }
0105     return *this;
0106 }
0107 
0108 DOMString &DOMString::operator += (const DOMString &str)
0109 {
0110     if (!impl) {
0111         // ### FIXME!!!
0112         impl = str.impl;
0113         if (impl) {
0114             impl->ref();
0115         }
0116         return *this;
0117     }
0118     if (str.impl) {
0119         DOMStringImpl *i = impl->copy();
0120         impl->deref();
0121         impl = i;
0122         impl->ref();
0123         impl->append(str.impl);
0124     }
0125     return *this;
0126 }
0127 
0128 DOMString DOMString::operator + (const DOMString &str)
0129 {
0130     if (!impl) {
0131         return str.copy();
0132     }
0133     if (str.impl) {
0134         DOMString s = copy();
0135         s += str;
0136         return s;
0137     }
0138 
0139     return copy();
0140 }
0141 
0142 void DOMString::insert(DOMString str, uint pos)
0143 {
0144     if (!impl) {
0145         impl = str.impl->copy();
0146         impl->ref();
0147     } else {
0148         impl->insert(str.impl, pos);
0149     }
0150 }
0151 
0152 const QChar &DOMString::operator [](unsigned int i) const
0153 {
0154     static const QChar nullChar = 0;
0155 
0156     if (!impl || i >= impl->l) {
0157         return nullChar;
0158     }
0159 
0160     return *(impl->s + i);
0161 }
0162 
0163 int DOMString::find(const QChar c, int start) const
0164 {
0165     unsigned int l = start;
0166     if (!impl || l >= impl->l) {
0167         return -1;
0168     }
0169     while (l < impl->l) {
0170         if (*(impl->s + l) == c) {
0171             return l;
0172         }
0173         l++;
0174     }
0175     return -1;
0176 }
0177 
0178 int DOMString::reverseFind(const QChar c, int start) const
0179 {
0180     unsigned int l = start;
0181     if (!impl || l < -impl->l) {
0182         return -1;
0183     }
0184     l += impl->l;
0185     while (1) {
0186         if (*(impl->s + l) == c) {
0187             return l;
0188         }
0189         l--;
0190         if (l == 0) {
0191             return -1;
0192         }
0193     }
0194     return -1;
0195 }
0196 
0197 DOMString DOMString::substring(unsigned pos, unsigned len) const
0198 {
0199     return (impl) ? impl->substring(pos, len) : DOMString();
0200 }
0201 
0202 uint DOMString::length() const
0203 {
0204     if (!impl) {
0205         return 0;
0206     }
0207     return impl->l;
0208 }
0209 
0210 void DOMString::truncate(unsigned int len)
0211 {
0212     if (impl) {
0213         impl->truncate(len);
0214     }
0215 }
0216 
0217 void DOMString::remove(unsigned int pos, int len)
0218 {
0219     if (impl) {
0220         impl->remove(pos, len);
0221     }
0222 }
0223 
0224 DOMString DOMString::split(unsigned int pos)
0225 {
0226     if (!impl) {
0227         return DOMString();
0228     }
0229     return impl->split(pos);
0230 }
0231 
0232 DOMString DOMString::lower() const
0233 {
0234     if (!impl) {
0235         return DOMString();
0236     }
0237     return impl->lower();
0238 }
0239 
0240 DOMString DOMString::upper() const
0241 {
0242     if (!impl) {
0243         return DOMString();
0244     }
0245     return impl->upper();
0246 }
0247 
0248 bool DOMString::percentage(int &_percentage) const
0249 {
0250     if (!impl || !impl->l) {
0251         return false;
0252     }
0253 
0254     if (*(impl->s + impl->l - 1) != QChar('%')) {
0255         return false;
0256     }
0257 
0258     _percentage = QString::fromRawData(impl->s, impl->l - 1).toInt();
0259     return true;
0260 }
0261 
0262 QChar *DOMString::unicode() const
0263 {
0264     if (!impl) {
0265         return nullptr;
0266     }
0267     return impl->unicode();
0268 }
0269 
0270 QString DOMString::string() const
0271 {
0272     if (!impl) {
0273         return QString();
0274     }
0275 
0276     return impl->string();
0277 }
0278 
0279 int DOMString::toInt() const
0280 {
0281     if (!impl) {
0282         return 0;
0283     }
0284 
0285     return impl->toInt();
0286 }
0287 
0288 int DOMString::toInt(bool *ok) const
0289 {
0290     if (!impl) {
0291         *ok = false;
0292         return 0;
0293     }
0294 
0295     return impl->toInt(ok);
0296 }
0297 
0298 float DOMString::toFloat(bool *ok) const
0299 {
0300     if (!impl) {
0301         if (ok) {
0302             *ok = false;
0303         }
0304         return 0;
0305     }
0306     return impl->toFloat(ok);
0307 }
0308 
0309 DOMString DOMString::number(float f)
0310 {
0311     return DOMString(QString::number(f));
0312 }
0313 
0314 DOMString DOMString::copy() const
0315 {
0316     if (!impl) {
0317         return DOMString();
0318     }
0319     return impl->copy();
0320 }
0321 
0322 bool DOMString::endsWith(const DOMString &str) const
0323 {
0324     if (str.length() > length()) {
0325         return false;
0326     }
0327     return impl->endsWith(str.implementation());
0328 }
0329 
0330 bool DOMString::startsWith(const DOMString &str) const
0331 {
0332     if (str.length() > length()) {
0333         return false;
0334     }
0335     return impl->startsWith(str.implementation());
0336 }
0337 
0338 static inline bool isSpaceCharacter(const ushort &c)
0339 {
0340     // https://dev.w3.org/html5/spec-LC/common-microsyntaxes.html#space-character
0341     return ((c < 0x0021) &&
0342             (c == 0x0020 || c == 0x0009 || c == 0x000A || c == 0x000C || c == 0x000D));
0343 }
0344 
0345 DOMString DOMString::trimSpaces() const
0346 {
0347     if (!impl || !impl->l) {
0348         return *this;
0349     }
0350 
0351     const QChar *s = impl->s;
0352     unsigned int start = 0;
0353     unsigned int end = impl->l - 1;
0354 
0355     while ((start <= end) && isSpaceCharacter(s[start].unicode())) {
0356         ++start;
0357     }
0358 
0359     if (start > end) {
0360         return DOMString("");
0361     }
0362 
0363     while (end && isSpaceCharacter(s[end].unicode())) {
0364         --end;
0365     }
0366 
0367     const unsigned int len = end - start + 1;
0368     DOMStringImpl *out = new DOMStringImpl(s + start, len);
0369 
0370     // remove garbage
0371     unsigned int newLen = 0;
0372     for (unsigned int k = 0; k < len; ++k) {
0373         QChar ch = out->s[k];
0374         if (ch.unicode() > '\r') {
0375             out->s[newLen++] = ch;
0376         }
0377     }
0378     out->l = newLen;
0379 
0380     return out;
0381 }
0382 
0383 // ------------------------------------------------------------------------
0384 
0385 bool DOM::strcasecmp(const DOMString &as, const DOMString &bs)
0386 {
0387     return strcasecmp(as.implementation(), bs.implementation());
0388 }
0389 
0390 bool DOM::strcasecmp(const DOMString &as, const char *bs)
0391 {
0392     const QChar *a = as.unicode();
0393     int l = as.length();
0394     if (!bs) {
0395         return (l != 0);
0396     }
0397     while (l--) {
0398         if (a->toLatin1() != *bs) {
0399             char cc = ((*bs >= 'A') && (*bs <= 'Z')) ? ((*bs) + 'a' - 'A') : (*bs);
0400             if (a->toLower().toLatin1() != cc) {
0401                 return true;
0402             }
0403         }
0404         a++, bs++;
0405     }
0406     return (*bs != '\0');
0407 }
0408 
0409 bool DOMString::isEmpty() const
0410 {
0411     return (!impl || impl->l == 0);
0412 }
0413 
0414 DOMString DOMString::format(const char *format, ...)
0415 {
0416     va_list args;
0417     va_start(args, format);
0418 
0419     Vector<char, 256> buffer;
0420 
0421     // Do the format once to get the length.
0422 #if COMPILER(MSVC)
0423     int result = _vscprintf(format, args);
0424 #else
0425     char ch;
0426     int result = qvsnprintf(&ch, 1, format, args);
0427     // We need to call va_end() and then va_start() again here, as the
0428     // contents of args is undefined after the call to vsnprintf
0429     // according to https://man.cx/snprintf(3)
0430     //
0431     // Not calling va_end/va_start here happens to work on lots of
0432     // systems, but fails e.g. on 64bit Linux.
0433     va_end(args);
0434     va_start(args, format);
0435 #endif
0436 
0437     if (result == 0) {
0438         va_end(args);
0439         return DOMString("");
0440     }
0441     if (result < 0) {
0442         va_end(args);
0443         return DOMString();
0444     }
0445     unsigned len = result;
0446     buffer.grow(len + 1);
0447 
0448     // Now do the formatting again, guaranteed to fit.
0449     qvsnprintf(buffer.data(), buffer.size(), format, args);
0450 
0451     va_end(args);
0452 
0453     buffer[len] = 0; // we don't really need this I guess
0454     return new DOMStringImpl(buffer.data()/*, len*/);
0455 }
0456 
0457 //-----------------------------------------------------------------------------
0458 
0459 bool DOM::operator==(const DOMString &a, const DOMString &b)
0460 {
0461     return !strcmp(a.implementation(), b.implementation());
0462 }
0463 
0464 bool DOM::operator==(const DOMString &a, const QString &b)
0465 {
0466     int l = a.length();
0467 
0468     if (l != b.length()) {
0469         return false;
0470     }
0471 
0472     if (!memcmp(a.unicode(), b.unicode(), l * sizeof(QChar))) {
0473         return true;
0474     }
0475     return false;
0476 }
0477 
0478 bool DOM::operator==(const DOMString &a, const char *b)
0479 {
0480     DOMStringImpl *aimpl = a.impl;
0481     if (!b) {
0482         return !aimpl;
0483     }
0484 
0485     if (aimpl) {
0486         int alen = aimpl->l;
0487         const QChar *aptr = aimpl->s;
0488         while (alen--) {
0489             unsigned char c = *b++;
0490             if (!c || (*aptr++).unicode() != c) {
0491                 return false;
0492             }
0493         }
0494     }
0495 
0496     return !*b;
0497 }