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 }