File indexing completed on 2024-04-28 11:39:38
0001 /** 0002 * This file is part of the DOM implementation for KDE. 0003 * 0004 * Copyright (C) 2000 Peter Kelly (pmk@post.com) 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_xmlimpl.h" 0023 0024 #include <dom/dom_exception.h> 0025 0026 #include "dom_docimpl.h" 0027 #include "dom_stringimpl.h" 0028 #include <css/css_stylesheetimpl.h> 0029 #include <css/css_mediaquery.h> 0030 #include <misc/loader.h> 0031 0032 using namespace DOM; 0033 0034 EntityImpl::EntityImpl(DocumentImpl *doc) : NodeBaseImpl(doc) 0035 { 0036 m_publicId = nullptr; 0037 m_systemId = nullptr; 0038 m_notationName = nullptr; 0039 m_name = nullptr; 0040 } 0041 0042 EntityImpl::EntityImpl(DocumentImpl *doc, DOMString _name) : NodeBaseImpl(doc) 0043 { 0044 m_publicId = nullptr; 0045 m_systemId = nullptr; 0046 m_notationName = nullptr; 0047 m_name = _name.implementation(); 0048 if (m_name) { 0049 m_name->ref(); 0050 } 0051 } 0052 0053 EntityImpl::EntityImpl(DocumentImpl *doc, DOMString _publicId, DOMString _systemId, DOMString _notationName) : NodeBaseImpl(doc) 0054 { 0055 m_publicId = _publicId.implementation(); 0056 if (m_publicId) { 0057 m_publicId->ref(); 0058 } 0059 m_systemId = _systemId.implementation(); 0060 if (m_systemId) { 0061 m_systemId->ref(); 0062 } 0063 m_notationName = _notationName.implementation(); 0064 if (m_notationName) { 0065 m_notationName->ref(); 0066 } 0067 m_name = nullptr; 0068 } 0069 0070 EntityImpl::~EntityImpl() 0071 { 0072 if (m_publicId) { 0073 m_publicId->deref(); 0074 } 0075 if (m_systemId) { 0076 m_systemId->deref(); 0077 } 0078 if (m_notationName) { 0079 m_notationName->deref(); 0080 } 0081 if (m_name) { 0082 m_name->deref(); 0083 } 0084 } 0085 0086 DOMString EntityImpl::publicId() const 0087 { 0088 return m_publicId; 0089 } 0090 0091 DOMString EntityImpl::systemId() const 0092 { 0093 return m_systemId; 0094 } 0095 0096 DOMString EntityImpl::notationName() const 0097 { 0098 return m_notationName; 0099 } 0100 0101 DOMString EntityImpl::nodeName() const 0102 { 0103 return m_name; 0104 } 0105 0106 unsigned short EntityImpl::nodeType() const 0107 { 0108 return Node::ENTITY_NODE; 0109 } 0110 0111 WTF::PassRefPtr<NodeImpl> EntityImpl::cloneNode(bool /*deep*/) 0112 { 0113 // Spec says cloning Document nodes is "implementation dependent" 0114 // so we do not support it... 0115 return nullptr; 0116 } 0117 0118 // DOM Section 1.1.1 0119 bool EntityImpl::childTypeAllowed(unsigned short type) 0120 { 0121 switch (type) { 0122 case Node::ELEMENT_NODE: 0123 case Node::PROCESSING_INSTRUCTION_NODE: 0124 case Node::COMMENT_NODE: 0125 case Node::TEXT_NODE: 0126 case Node::CDATA_SECTION_NODE: 0127 case Node::ENTITY_REFERENCE_NODE: 0128 return true; 0129 break; 0130 default: 0131 return false; 0132 } 0133 } 0134 0135 DOMString EntityImpl::toString() const 0136 { 0137 DOMString result = "<!ENTITY' "; 0138 0139 if (m_name && m_name->l != 0) { 0140 result += " "; 0141 result += m_name; 0142 } 0143 0144 if (m_publicId && m_publicId->l != 0) { 0145 result += " PUBLIC \""; 0146 result += m_publicId; 0147 result += "\" \""; 0148 result += m_systemId; 0149 result += "\""; 0150 } else if (m_systemId && m_systemId->l != 0) { 0151 result += " SYSTEM \""; 0152 result += m_systemId; 0153 result += "\""; 0154 } 0155 0156 if (m_notationName && m_notationName->l != 0) { 0157 result += " NDATA "; 0158 result += m_notationName; 0159 } 0160 0161 result += ">"; 0162 0163 return result; 0164 } 0165 0166 // ------------------------------------------------------------------------- 0167 0168 EntityReferenceImpl::EntityReferenceImpl(DocumentImpl *doc) : NodeBaseImpl(doc) 0169 { 0170 m_entityName = nullptr; 0171 } 0172 0173 EntityReferenceImpl::EntityReferenceImpl(DocumentImpl *doc, DOMStringImpl *_entityName) : NodeBaseImpl(doc) 0174 { 0175 m_entityName = _entityName; 0176 if (m_entityName) { 0177 m_entityName->ref(); 0178 } 0179 } 0180 0181 EntityReferenceImpl::~EntityReferenceImpl() 0182 { 0183 if (m_entityName) { 0184 m_entityName->deref(); 0185 } 0186 } 0187 0188 DOMString EntityReferenceImpl::nodeName() const 0189 { 0190 return m_entityName; 0191 } 0192 0193 unsigned short EntityReferenceImpl::nodeType() const 0194 { 0195 return Node::ENTITY_REFERENCE_NODE; 0196 } 0197 0198 WTF::PassRefPtr<NodeImpl> EntityReferenceImpl::cloneNode(bool deep) 0199 { 0200 EntityReferenceImpl *clone = new EntityReferenceImpl(docPtr(), m_entityName); 0201 // ### make sure children are readonly 0202 // ### since we are a reference, should we clone children anyway (even if not deep?) 0203 if (deep) { 0204 cloneChildNodes(clone); 0205 } 0206 return clone; 0207 } 0208 0209 // DOM Section 1.1.1 0210 bool EntityReferenceImpl::childTypeAllowed(unsigned short type) 0211 { 0212 switch (type) { 0213 case Node::ELEMENT_NODE: 0214 case Node::PROCESSING_INSTRUCTION_NODE: 0215 case Node::COMMENT_NODE: 0216 case Node::TEXT_NODE: 0217 case Node::CDATA_SECTION_NODE: 0218 case Node::ENTITY_REFERENCE_NODE: 0219 return true; 0220 break; 0221 default: 0222 return false; 0223 } 0224 } 0225 0226 DOMString EntityReferenceImpl::toString() const 0227 { 0228 DOMString result = "&"; 0229 result += m_entityName; 0230 result += ";"; 0231 0232 return result; 0233 } 0234 0235 // ------------------------------------------------------------------------- 0236 0237 NotationImpl::NotationImpl(DocumentImpl *doc) : NodeBaseImpl(doc) 0238 { 0239 m_publicId = nullptr; 0240 m_systemId = nullptr; 0241 m_name = nullptr; 0242 } 0243 0244 NotationImpl::NotationImpl(DocumentImpl *doc, DOMString _name, DOMString _publicId, DOMString _systemId) : NodeBaseImpl(doc) 0245 { 0246 m_name = _name.implementation(); 0247 if (m_name) { 0248 m_name->ref(); 0249 } 0250 m_publicId = _publicId.implementation(); 0251 if (m_publicId) { 0252 m_publicId->ref(); 0253 } 0254 m_systemId = _systemId.implementation(); 0255 if (m_systemId) { 0256 m_systemId->ref(); 0257 } 0258 } 0259 0260 NotationImpl::~NotationImpl() 0261 { 0262 if (m_name) { 0263 m_name->deref(); 0264 } 0265 if (m_publicId) { 0266 m_publicId->deref(); 0267 } 0268 if (m_systemId) { 0269 m_systemId->deref(); 0270 } 0271 } 0272 0273 DOMString NotationImpl::publicId() const 0274 { 0275 return m_publicId; 0276 } 0277 0278 DOMString NotationImpl::systemId() const 0279 { 0280 return m_systemId; 0281 } 0282 0283 DOMString NotationImpl::nodeName() const 0284 { 0285 return m_name; 0286 } 0287 0288 unsigned short NotationImpl::nodeType() const 0289 { 0290 return Node::NOTATION_NODE; 0291 } 0292 0293 WTF::PassRefPtr<NodeImpl> NotationImpl::cloneNode(bool /*deep*/) 0294 { 0295 // Spec says cloning Document nodes is "implementation dependent" 0296 // so we do not support it... 0297 return nullptr; 0298 } 0299 0300 // DOM Section 1.1.1 0301 bool NotationImpl::childTypeAllowed(unsigned short /*type*/) 0302 { 0303 return false; 0304 } 0305 0306 // ------------------------------------------------------------------------- 0307 0308 // ### need a way of updating these properly whenever child nodes of the processing instruction 0309 // change or are added/removed 0310 0311 ProcessingInstructionImpl::ProcessingInstructionImpl(DocumentImpl *doc) : NodeBaseImpl(doc) 0312 { 0313 m_target = nullptr; 0314 m_data = nullptr; 0315 m_localHref = nullptr; 0316 m_alternate = false; 0317 m_title = nullptr; 0318 m_media = nullptr; 0319 m_sheet = nullptr; 0320 m_cachedSheet = nullptr; 0321 } 0322 0323 ProcessingInstructionImpl::ProcessingInstructionImpl(DocumentImpl *doc, DOMString _target, DOMString _data) : NodeBaseImpl(doc) 0324 { 0325 m_target = _target.implementation(); 0326 if (m_target) { 0327 m_target->ref(); 0328 } 0329 m_data = _data.implementation(); 0330 if (m_data) { 0331 m_data->ref(); 0332 } 0333 m_sheet = nullptr; 0334 m_cachedSheet = nullptr; 0335 m_localHref = nullptr; 0336 m_title = nullptr; 0337 m_media = nullptr; 0338 m_alternate = false; 0339 } 0340 0341 ProcessingInstructionImpl::~ProcessingInstructionImpl() 0342 { 0343 if (m_target) { 0344 m_target->deref(); 0345 } 0346 if (m_title) { 0347 m_title->deref(); 0348 } 0349 if (m_media) { 0350 m_media->deref(); 0351 } 0352 if (m_data) { 0353 m_data->deref(); 0354 } 0355 if (m_cachedSheet) { 0356 m_cachedSheet->deref(this); 0357 } 0358 if (m_sheet) { 0359 m_sheet->deref(); 0360 } 0361 } 0362 0363 DOMString ProcessingInstructionImpl::target() const 0364 { 0365 return m_target; 0366 } 0367 0368 void ProcessingInstructionImpl::setData(const DOMString &_data, int &exceptioncode) 0369 { 0370 // NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly. 0371 if (isReadOnly()) { 0372 exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR; 0373 return; 0374 } 0375 0376 if (m_data) { 0377 m_data->deref(); 0378 } 0379 m_data = _data.implementation(); 0380 if (m_data) { 0381 m_data->ref(); 0382 } 0383 } 0384 0385 DOMString ProcessingInstructionImpl::nodeName() const 0386 { 0387 return m_target; 0388 } 0389 0390 unsigned short ProcessingInstructionImpl::nodeType() const 0391 { 0392 return Node::PROCESSING_INSTRUCTION_NODE; 0393 } 0394 0395 DOMString ProcessingInstructionImpl::nodeValue() const 0396 { 0397 return m_data; 0398 } 0399 0400 void ProcessingInstructionImpl::setNodeValue(const DOMString &_nodeValue, int &exceptioncode) 0401 { 0402 // NO_MODIFICATION_ALLOWED_ERR: taken care of by setData() 0403 setData(_nodeValue, exceptioncode); 0404 } 0405 0406 WTF::PassRefPtr<NodeImpl> ProcessingInstructionImpl::cloneNode(bool /*deep*/) 0407 { 0408 // ### copy m_localHref 0409 return new ProcessingInstructionImpl(docPtr(), m_target, m_data); 0410 } 0411 0412 DOMString ProcessingInstructionImpl::localHref() const 0413 { 0414 return m_localHref; 0415 } 0416 0417 // DOM Section 1.1.1 0418 bool ProcessingInstructionImpl::childTypeAllowed(unsigned short /*type*/) 0419 { 0420 return false; 0421 } 0422 0423 void ProcessingInstructionImpl::checkStyleSheet() 0424 { 0425 if (m_target && DOMString(m_target) == "xml-stylesheet") { 0426 // see https://www.w3.org/TR/xml-stylesheet/ 0427 // ### check that this occurs only in the prolog 0428 // ### support stylesheet included in a fragment of this (or another) document 0429 // ### make sure this gets called when adding from javascript 0430 XMLAttributeReader attrReader(DOMString(m_data).string()); 0431 bool attrsOk; 0432 QXmlAttributes attrs = attrReader.readAttrs(attrsOk); 0433 if (!attrsOk) { 0434 return; 0435 } 0436 if (attrs.value("type") != "text/css" && !attrs.value("type").isEmpty()) { 0437 return; 0438 } 0439 0440 DOMString href = attrs.value("href"); 0441 DOMString alternate = attrs.value("alternate"); 0442 m_alternate = alternate == "yes"; 0443 DOMString title = attrs.value("title"); 0444 DOMString media = attrs.value("media"); 0445 if (m_title) { 0446 m_title->deref(); 0447 } 0448 m_title = title.implementation(); 0449 if (m_title) { 0450 m_title->ref(); 0451 } 0452 if (m_media) { 0453 m_media->deref(); 0454 } 0455 m_media = media.implementation(); 0456 if (m_media) { 0457 m_media->ref(); 0458 } 0459 0460 if (href.length() > 1) { 0461 if (href[0] == '#') { 0462 if (m_localHref) { 0463 m_localHref->deref(); 0464 } 0465 m_localHref = href.implementation()->split(1); 0466 if (m_localHref) { 0467 m_localHref->ref(); 0468 } 0469 } else { 0470 // ### some validation on the URL? 0471 // ### FIXME charset 0472 if (m_cachedSheet) { 0473 m_cachedSheet->deref(this); 0474 } 0475 m_cachedSheet = document()->docLoader()->requestStyleSheet(document()->completeURL(href.string()), QString()); 0476 if (m_cachedSheet) { 0477 document()->addPendingSheet(); //before ref, because during the ref it might load! 0478 m_cachedSheet->ref(this); 0479 } 0480 } 0481 0482 } 0483 } 0484 } 0485 0486 StyleSheetImpl *ProcessingInstructionImpl::sheet() const 0487 { 0488 return m_sheet; 0489 } 0490 0491 void ProcessingInstructionImpl::setStyleSheet(const DOM::DOMString &url, const DOM::DOMString &sheet, const DOM::DOMString &charset, const DOM::DOMString &mimetype) 0492 { 0493 if (m_sheet) { 0494 m_sheet->deref(); 0495 } 0496 m_sheet = new CSSStyleSheetImpl(document(), url); 0497 m_sheet->ref(); 0498 m_sheet->setCharset(charset); 0499 m_sheet->setTitle(m_title); 0500 m_sheet->setMedia(new MediaListImpl((CSSStyleSheetImpl *)m_sheet, m_media, false)); 0501 m_sheet->parseString(khtml::isAcceptableCSSMimetype(mimetype) ? sheet : ""); 0502 if (m_cachedSheet) { 0503 m_cachedSheet->deref(this); 0504 } 0505 m_cachedSheet = nullptr; 0506 0507 document()->styleSheetLoaded(); 0508 } 0509 0510 void ProcessingInstructionImpl::setStyleSheet(CSSStyleSheetImpl *sheet) 0511 { 0512 if (m_sheet) { 0513 m_sheet->deref(); 0514 } 0515 m_sheet = sheet; 0516 if (m_sheet) { 0517 m_sheet->ref(); 0518 m_sheet->setTitle(m_title); 0519 } 0520 } 0521 0522 DOMString ProcessingInstructionImpl::toString() const 0523 { 0524 DOMString result = "<?"; 0525 result += m_target; 0526 result += " "; 0527 result += m_data; 0528 result += ">"; 0529 return result; 0530 } 0531 0532 int ProcessingInstructionImpl::maxCharacterOffset() const 0533 { 0534 return m_data ? static_cast<int>(m_data->length()) : 0; 0535 } 0536 0537 // ------------------------------------------------------------------------- 0538 0539 XMLAttributeReader::XMLAttributeReader(const QString &_attrString) 0540 { 0541 m_attrString = _attrString; 0542 } 0543 0544 XMLAttributeReader::~XMLAttributeReader() 0545 { 0546 } 0547 0548 QXmlAttributes XMLAttributeReader::readAttrs(bool &ok) 0549 { 0550 // parse xml file 0551 QXmlInputSource source; 0552 source.setData("<?xml version=\"1.0\"?><attrs " + m_attrString + " />"); 0553 QXmlSimpleReader reader; 0554 reader.setContentHandler(this); 0555 ok = reader.parse(source); 0556 return attrs; 0557 } 0558 0559 bool XMLAttributeReader::startElement(const QString & /*namespaceURI*/, const QString &localName, 0560 const QString & /*qName*/, const QXmlAttributes &atts) 0561 { 0562 if (localName == "attrs") { 0563 attrs = atts; 0564 return true; 0565 } else { 0566 return false; // we shouldn't have any other elements 0567 } 0568 }