File indexing completed on 2024-04-14 04:49:03
0001 /* 0002 SPDX-FileCopyrightText: 2004 Koos Vriezen <koos.vriezen@gmail.com> 0003 0004 SPDX-License-Identifier: LGPL-2.0-only 0005 */ 0006 0007 #include "config-kmplayer.h" 0008 #include <ctime> 0009 0010 #include <QTextStream> 0011 #ifdef KMPLAYER_WITH_EXPAT 0012 #include <expat.h> 0013 #endif 0014 #include "kmplayercommon_log.h" 0015 #include "kmplayerplaylist.h" 0016 #include "kmplayer_asx.h" 0017 #include "kmplayer_atom.h" 0018 #include "kmplayer_opml.h" 0019 #include "kmplayer_rp.h" 0020 #include "kmplayer_rss.h" 0021 #include "kmplayer_smil.h" 0022 #include "kmplayer_xspf.h" 0023 #include "mediaobject.h" 0024 0025 #ifdef SHAREDPTR_DEBUG 0026 KMPLAYERCOMMON_EXPORT int shared_data_count; 0027 #endif 0028 0029 using namespace KMPlayer; 0030 0031 //----------------------------------------------------------------------------- 0032 0033 Node *KMPlayer::fromXMLDocumentTag (NodePtr & d, const QString & tag) { 0034 const QByteArray ba = tag.toLatin1 (); 0035 const char * const name = ba.constData(); 0036 if (!strcmp (name, "smil")) 0037 return new SMIL::Smil (d); 0038 else if (!strcasecmp (name, "asx")) 0039 return new ASX::Asx (d); 0040 else if (!strcasecmp (name, "imfl")) 0041 return new RP::Imfl (d); 0042 else if (!strcasecmp (name, "rss")) 0043 return new RSS::Rss (d); 0044 else if (!strcasecmp (name, "feed")) 0045 return new ATOM::Feed (d); 0046 else if (!strcasecmp (name, "playlist")) 0047 return new XSPF::Playlist (d); 0048 else if (!strcasecmp (name, "opml")) 0049 return new OPML::Opml (d); 0050 else if (!strcasecmp (name, "url")) 0051 return new GenericURL (d, QString ()); 0052 else if (!strcasecmp (name, "mrl") || 0053 !strcasecmp (name, "document")) 0054 return new GenericMrl (d); 0055 return nullptr; 0056 } 0057 0058 //----------------------------------------------------------------------------- 0059 0060 QTextStream &KMPlayer::operator << (QTextStream &out, const XMLStringlet &txt) { 0061 int len = int (txt.str.size ()); 0062 for (int i = 0; i < len; ++i) { 0063 if (txt.str [i] == QChar ('<')) { 0064 out << "<"; 0065 } else if (txt.str [i] == QChar ('>')) { 0066 out << ">"; 0067 } else if (txt.str [i] == QChar ('"')) { 0068 out << """; 0069 } else if (txt.str [i] == QChar ('&')) { 0070 out << "&"; 0071 } else 0072 out << txt.str [i]; 0073 } 0074 return out; 0075 } 0076 0077 //----------------------------------------------------------------------------- 0078 0079 Connection::Connection (Node *invoker, Node *receiver, VirtualVoid *pl) 0080 : connectee (invoker), connecter (receiver), payload (pl) { 0081 #ifdef KMPLAYER_TEST_CONNECTION 0082 connection_counter++; 0083 #endif 0084 } 0085 0086 ConnectionLink::ConnectionLink () : connection (nullptr) {} 0087 0088 ConnectionLink::~ConnectionLink () { 0089 disconnect (); 0090 } 0091 0092 bool ConnectionLink::connect (Node *send, MessageType msg, Node *rec, 0093 VirtualVoid *payload) { 0094 disconnect (); 0095 ConnectionList *list = nodeMessageReceivers (send, msg); 0096 if (list) { 0097 connection = new Connection (send, rec, payload); 0098 connection->list = list; 0099 connection->link = &connection; 0100 connection->prev = list->link_last; 0101 connection->next = nullptr; 0102 if (list->link_last) 0103 list->link_last->next = connection; 0104 else 0105 list->link_first = connection; 0106 list->link_last = connection; 0107 } 0108 return list; 0109 } 0110 0111 void ConnectionLink::disconnect () const { 0112 if (connection) { 0113 Connection *tmp = connection; 0114 if (tmp->prev) 0115 tmp->prev->next = tmp->next; 0116 else 0117 tmp->list->link_first = tmp->next; 0118 if (tmp->next) 0119 tmp->next->prev = tmp->prev; 0120 else 0121 tmp->list->link_last = tmp->prev; 0122 *tmp->link = nullptr; 0123 if (tmp->list->link_next == tmp) 0124 tmp->list->link_next = tmp->next; 0125 delete tmp; 0126 } 0127 Q_ASSERT (!connection); 0128 } 0129 0130 void ConnectionLink::assign (const ConnectionLink *link) const { 0131 disconnect (); 0132 connection = link->connection; 0133 link->connection = nullptr; 0134 if (connection) 0135 connection->link = &connection; 0136 } 0137 0138 Node *ConnectionLink::signaler () const { 0139 return connection ? connection->connectee.ptr () : nullptr; 0140 } 0141 0142 ConnectionList::ConnectionList () 0143 : link_first (nullptr), link_last (nullptr), link_next (nullptr) {} 0144 0145 ConnectionList::~ConnectionList () { 0146 clear (); 0147 } 0148 0149 void ConnectionList::clear () { 0150 while (link_first) { 0151 Connection *tmp = link_first; 0152 link_first = tmp->next; 0153 *tmp->link = nullptr; 0154 delete tmp; 0155 } 0156 link_last = link_next = nullptr; 0157 } 0158 0159 //----------------------------------------------------------------------------- 0160 0161 TimerPosting::TimerPosting (int ms, unsigned eid) 0162 : Posting (nullptr, MsgEventTimer), 0163 event_id (eid), 0164 milli_sec (ms), 0165 interval (false) {} 0166 0167 //----------------------------------------------------------------------------- 0168 0169 Matrix::Matrix () : a (1.0), b (0.0), c (0.0), d (1.0), tx (0), ty (0) {} 0170 0171 Matrix::Matrix (const Matrix & m) 0172 : a (m.a), b (m.b), c (m.c), d (m.d), tx (m.tx), ty (m.ty) {} 0173 0174 Matrix::Matrix (Single xoff, Single yoff, float xscale, float yscale) 0175 : a (xscale), b (0.0), c (0.0), d (yscale), tx (xoff), ty (yoff) {} 0176 0177 Matrix & Matrix::operator = (const Matrix& m) 0178 { 0179 a = m.a; 0180 b = m.b; 0181 c = m.c; 0182 d = m.d; 0183 tx = m.tx; 0184 ty = m.ty; 0185 0186 return *this; 0187 } 0188 0189 void Matrix::getXY (Single & x, Single & y) const { 0190 x = Single (x * a) + tx; 0191 y = Single (y * d) + ty; 0192 } 0193 0194 void Matrix::getWH (Single &w, Single &h) const { 0195 w *= a; 0196 h *= d; 0197 } 0198 0199 IRect Matrix::toScreen (const SRect &rect) const { 0200 return IRect ( 0201 (int) (Single (rect.x () * a) + tx), 0202 (int) (Single (rect.y () * d) + ty), 0203 (int) (rect.width () * a), 0204 (int) (rect.height () * d)); 0205 } 0206 0207 SRect Matrix::toUser (const IRect &rect) const { 0208 if (a > 0.00001 && d > 0.00001) { 0209 return SRect ( 0210 Single ((Single (rect.x ()) - tx) / a), 0211 Single ((Single (rect.y ()) - ty) / d), 0212 rect.width () / a, 0213 rect.height () / d); 0214 } else { 0215 qCWarning(LOG_KMPLAYER_COMMON) << "Not invering " << a << ", " << d << " scale"; 0216 return SRect (); 0217 } 0218 } 0219 0220 void Matrix::transform (const Matrix & matrix) { 0221 // TODO: rotate 0222 a *= matrix.a; 0223 d *= matrix.d; 0224 tx = Single (tx * matrix.a) + matrix.tx; 0225 ty = Single (ty * matrix.d) + matrix.ty; 0226 } 0227 0228 void Matrix::scale (float sx, float sy) { 0229 a *= sx; 0230 d *= sy; 0231 tx *= sx; 0232 ty *= sy; 0233 } 0234 0235 void Matrix::translate (Single x, Single y) { 0236 tx += x; 0237 ty += y; 0238 } 0239 0240 //----------------------------------------------------------------------------- 0241 0242 Node::Node (NodePtr & d, short _id) 0243 : m_doc (d), state (state_init), id (_id), 0244 auxiliary_node (false), open (false) {} 0245 0246 Node::~Node () { 0247 clear (); 0248 } 0249 0250 Document * Node::document () { 0251 return convertNode <Document> (m_doc); 0252 } 0253 0254 Mrl * Node::mrl () { 0255 return nullptr; 0256 } 0257 0258 const char * Node::nodeName () const { 0259 return "node"; 0260 } 0261 0262 void Node::setState (State nstate) { 0263 if (state != nstate && (state_init == nstate || state != state_resetting)) { 0264 State old = state; 0265 state = nstate; 0266 if (document ()->notify_listener) 0267 document()->notify_listener->stateElementChanged (this, old, state); 0268 } 0269 } 0270 0271 void Node::activate () { 0272 //qCDebug(LOG_KMPLAYER_COMMON) << nodeName () << " Node::activate"; 0273 setState (state_activated); 0274 if (firstChild ()) 0275 firstChild ()->activate (); // activate only the first 0276 else 0277 finish (); // a quicky :-) 0278 } 0279 0280 void Node::begin () { 0281 if (active ()) { 0282 setState (state_began); 0283 } else 0284 qCCritical(LOG_KMPLAYER_COMMON) << nodeName() << " begin call on not active element" << endl; 0285 } 0286 0287 void Node::defer () { 0288 if (active ()) { 0289 setState (state_deferred); 0290 } else 0291 qCCritical(LOG_KMPLAYER_COMMON) << "Node::defer () call on not activated element" << endl; 0292 } 0293 0294 void Node::undefer () { 0295 if (state == state_deferred) { 0296 if (firstChild () && firstChild ()->state > state_init) { 0297 state = state_began; 0298 } else { 0299 setState (state_activated); 0300 activate (); 0301 } 0302 } else 0303 qCWarning(LOG_KMPLAYER_COMMON) << nodeName () << " call on not deferred element"; 0304 } 0305 0306 void Node::finish () { 0307 if (active ()) { 0308 setState (state_finished); 0309 if (m_parent) 0310 document ()->post (m_parent, new Posting (this, MsgChildFinished)); 0311 else 0312 deactivate (); // document deactivates itself on finish 0313 } else 0314 qCWarning(LOG_KMPLAYER_COMMON) <<"Node::finish () call on not active element"; 0315 } 0316 0317 void Node::deactivate () { 0318 //qCDebug(LOG_KMPLAYER_COMMON) << nodeName () << " Node::deactivate"; 0319 bool need_finish (unfinished ()); 0320 if (state_resetting != state) 0321 setState (state_deactivated); 0322 for (NodePtr e = firstChild (); e; e = e->nextSibling ()) { 0323 if (e->state > state_init && e->state < state_deactivated) 0324 e->deactivate (); 0325 else 0326 break; // remaining not yet activated 0327 } 0328 if (need_finish && m_parent && m_parent->active ()) 0329 document ()->post (m_parent, new Posting (this, MsgChildFinished)); 0330 } 0331 0332 void Node::reset () { 0333 //qCDebug(LOG_KMPLAYER_COMMON) << nodeName () << " Node::reset"; 0334 if (active ()) { 0335 setState (state_resetting); 0336 deactivate (); 0337 } 0338 setState (state_init); 0339 for (NodePtr e = firstChild (); e; e = e->nextSibling ()) { 0340 if (e->state != state_init) 0341 e->reset (); 0342 // else 0343 // break; // rest not activated yet 0344 } 0345 } 0346 0347 void Node::clear () { 0348 clearChildren (); 0349 } 0350 0351 void Node::clearChildren () { 0352 if (m_doc) 0353 document()->m_tree_version++; 0354 while (m_first_child != m_last_child) { 0355 // avoid stack abuse with 10k children derefing each other 0356 m_last_child->m_parent = nullptr; 0357 m_last_child = m_last_child->m_prev; 0358 m_last_child->m_next = nullptr; 0359 } 0360 if (m_first_child) 0361 m_first_child->m_parent = nullptr; 0362 m_first_child = m_last_child = nullptr; 0363 } 0364 0365 template <> 0366 void TreeNode<Node>::appendChild (Node *c) { 0367 static_cast <Node *> (this)->document()->m_tree_version++; 0368 Q_ASSERT (!c->parentNode ()); 0369 appendChildImpl (c); 0370 } 0371 0372 template <> 0373 void TreeNode<Node>::insertBefore (Node *c, Node *b) { 0374 Q_ASSERT (!c->parentNode ()); 0375 static_cast <Node *> (this)->document()->m_tree_version++; 0376 insertBeforeImpl (c, b); 0377 } 0378 0379 template <> 0380 void TreeNode<Node>::removeChild (NodePtr c) { 0381 static_cast <Node *> (this)->document()->m_tree_version++; 0382 removeChildImpl (c); 0383 } 0384 0385 void Node::replaceChild (NodePtr _new, NodePtr old) { 0386 document()->m_tree_version++; 0387 if (old->m_prev) { 0388 old->m_prev->m_next = _new; 0389 _new->m_prev = old->m_prev; 0390 old->m_prev = nullptr; 0391 } else { 0392 _new->m_prev = nullptr; 0393 m_first_child = _new; 0394 } 0395 if (old->m_next) { 0396 old->m_next->m_prev = _new; 0397 _new->m_next = old->m_next; 0398 old->m_next = nullptr; 0399 } else { 0400 _new->m_next = nullptr; 0401 m_last_child = _new; 0402 } 0403 _new->m_parent = this; 0404 old->m_parent = nullptr; 0405 } 0406 0407 Node *Node::childFromTag (const QString &) { 0408 return nullptr; 0409 } 0410 0411 void Node::characterData (const QString & s) { 0412 document()->m_tree_version++; 0413 if (!m_last_child || m_last_child->id != id_node_text) 0414 appendChild (new TextNode (m_doc, s)); 0415 else 0416 convertNode <TextNode> (m_last_child)->appendText (s); 0417 } 0418 0419 void Node::normalize () { 0420 Node *e = firstChild (); 0421 while (e) { 0422 Node *tmp = e->nextSibling (); 0423 if (!e->isElementNode () && e->id == id_node_text) { 0424 QString val = e->nodeValue ().simplified (); 0425 if (val.isEmpty ()) 0426 removeChild (e); 0427 else 0428 static_cast <TextNode *> (e)->setText (val); 0429 } else 0430 e->normalize (); 0431 e = tmp; 0432 } 0433 } 0434 0435 static void getInnerText (const Node *p, QTextStream & out) { 0436 for (Node *e = p->firstChild (); e; e = e->nextSibling ()) { 0437 if (e->id == id_node_text || e->id == id_node_cdata) 0438 out << e->nodeValue (); 0439 else 0440 getInnerText (e, out); 0441 } 0442 } 0443 0444 QString Node::innerText () const { 0445 QString buf; 0446 QTextStream out (&buf, QIODevice::WriteOnly); 0447 getInnerText (this, out); 0448 return buf; 0449 } 0450 0451 static void getOuterXML (const Node *p, QTextStream & out, int depth) { 0452 if (!p->isElementNode ()) { // #text or #cdata 0453 if (p->id == id_node_cdata) 0454 out << "<![CDATA[" << p->nodeValue () << "]]>" << QChar ('\n'); 0455 else 0456 out << XMLStringlet (p->nodeValue ()) << QChar ('\n'); 0457 } else { 0458 const Element *e = static_cast <const Element *> (p); 0459 QString indent (QString ().fill (QChar (' '), depth)); 0460 out << indent << QChar ('<') << XMLStringlet (e->nodeName ()); 0461 for (Attribute *a = e->attributes().first(); a; a = a->nextSibling()) 0462 out << " " << XMLStringlet (a->name ().toString ()) << 0463 "=\"" << XMLStringlet (a->value ()) << "\""; 0464 if (e->hasChildNodes ()) { 0465 out << QChar ('>') << QChar ('\n'); 0466 for (Node *c = e->firstChild (); c; c = c->nextSibling ()) 0467 getOuterXML (c, out, depth + 1); 0468 out << indent << QString("</") << XMLStringlet (e->nodeName()) << 0469 QChar ('>') << QChar ('\n'); 0470 } else 0471 out << QString ("/>") << QChar ('\n'); 0472 } 0473 } 0474 0475 QString Node::innerXML () const { 0476 QString buf; 0477 QTextStream out (&buf, QIODevice::WriteOnly); 0478 for (Node *e = firstChild (); e; e = e->nextSibling ()) 0479 getOuterXML (e, out, 0); 0480 return buf; 0481 } 0482 0483 QString Node::outerXML () const { 0484 QString buf; 0485 QTextStream out (&buf, QIODevice::WriteOnly); 0486 getOuterXML (this, out, 0); 0487 return buf; 0488 } 0489 0490 Node::PlayType Node::playType () { 0491 return play_type_none; 0492 } 0493 0494 void Node::opened () { 0495 open = true; 0496 } 0497 0498 void Node::closed () { 0499 open = false; 0500 } 0501 0502 void Node::message (MessageType msg, void *content) { 0503 switch (msg) { 0504 0505 case MsgChildFinished: { 0506 Posting *post = (Posting *) content; 0507 if (unfinished ()) { 0508 if (post->source && post->source->state == state_finished) 0509 post->source->deactivate (); 0510 if (post->source && post->source->nextSibling ()) 0511 post->source->nextSibling ()->activate (); 0512 else 0513 finish (); // we're done 0514 } 0515 break; 0516 } 0517 0518 default: 0519 break; 0520 } 0521 } 0522 0523 void *Node::role (RoleType msg, void *) { 0524 switch (msg) { 0525 case RoleReady: 0526 return MsgBool (true); 0527 default: 0528 break; 0529 } 0530 return nullptr; 0531 } 0532 0533 void Node::deliver (MessageType msg, void *content) { 0534 ConnectionList *nl = nodeMessageReceivers (this, msg); 0535 if (nl) 0536 for (Connection *c = nl->first(); c; c = nl->next ()) 0537 if (c->connecter) 0538 c->connecter->message (msg, content); 0539 } 0540 0541 void Node::accept (Visitor * v) { 0542 v->visit (this); 0543 } 0544 0545 QString Node::nodeValue () const { 0546 return innerText ().trimmed (); 0547 } 0548 0549 //----------------------------------------------------------------------------- 0550 0551 namespace { 0552 struct ParamValue { 0553 QString val; 0554 QStringList * modifications; 0555 ParamValue (const QString & v) : val (v), modifications (nullptr) {} 0556 ~ParamValue () { delete modifications; } 0557 QString value (); 0558 void setValue (const QString & v) { val = v; } 0559 }; 0560 typedef QMap <TrieString, ParamValue *> ParamMap; 0561 } 0562 0563 namespace KMPlayer { 0564 class ElementPrivate 0565 { 0566 public: 0567 ~ElementPrivate (); 0568 ParamMap params; 0569 void clear (); 0570 }; 0571 } 0572 0573 QString ParamValue::value() { 0574 return modifications && modifications->size () 0575 ? modifications->back () : val; 0576 } 0577 0578 ElementPrivate::~ElementPrivate () { 0579 clear (); 0580 } 0581 0582 void ElementPrivate::clear () { 0583 const ParamMap::iterator e = params.end (); 0584 for (ParamMap::iterator i = params.begin (); i != e; ++i) 0585 delete i.value (); 0586 params.clear (); 0587 } 0588 0589 Element::Element (NodePtr & d, short id) 0590 : Node (d, id), d (new ElementPrivate) {} 0591 0592 Element::~Element () { 0593 delete d; 0594 } 0595 0596 void Element::setParam (const TrieString &name, const QString &val, int *mid) { 0597 ParamValue * pv = d->params [name]; 0598 if (!pv) { 0599 pv = new ParamValue (mid ? getAttribute (name) : val); 0600 d->params.insert (name, pv); 0601 } 0602 if (mid) { 0603 if (!pv->modifications) 0604 pv->modifications = new QStringList; 0605 if (*mid >= 0 && *mid < int (pv->modifications->size ())) { 0606 (*pv->modifications) [*mid] = val; 0607 } else { 0608 *mid = pv->modifications->size (); 0609 pv->modifications->push_back (val); 0610 } 0611 } else { 0612 pv->setValue (val); 0613 } 0614 parseParam (name, val); 0615 } 0616 0617 QString Element::param (const TrieString & name) { 0618 ParamValue * pv = d->params [name]; 0619 if (pv) 0620 return pv->value (); 0621 return getAttribute (name); 0622 } 0623 0624 void Element::resetParam (const TrieString &name, int mid) { 0625 ParamValue * pv = d->params [name]; 0626 if (pv && pv->modifications) { 0627 if (int (pv->modifications->size ()) > mid && mid > -1) { 0628 (*pv->modifications) [mid] = QString (); 0629 while (pv->modifications->size () > 0 && 0630 pv->modifications->back ().isNull ()) 0631 pv->modifications->pop_back (); 0632 } 0633 QString val = pv->value (); 0634 if (pv->modifications->size () == 0) { 0635 delete pv->modifications; 0636 pv->modifications = nullptr; 0637 if (val.isNull ()) { 0638 delete pv; 0639 d->params.remove (name); 0640 } 0641 } 0642 parseParam (name, val); 0643 } else 0644 qCCritical(LOG_KMPLAYER_COMMON) << "resetting " << name.toString() << " that doesn't exists" << endl; 0645 } 0646 0647 void Element::setAttribute (const TrieString & name, const QString & value) { 0648 for (Attribute *a = m_attributes.first (); a; a = a->nextSibling ()) 0649 if (name == a->name ()) { 0650 if (value.isNull ()) 0651 m_attributes.remove (a); 0652 else 0653 a->setValue (value); 0654 return; 0655 } 0656 if (!value.isNull ()) 0657 m_attributes.append (new Attribute (TrieString (), name, value)); 0658 } 0659 0660 QString Element::getAttribute (const TrieString & name) { 0661 for (Attribute *a = m_attributes.first (); a; a = a->nextSibling ()) 0662 if (name == a->name ()) 0663 return a->value (); 0664 return QString (); 0665 } 0666 0667 void Element::init () { 0668 d->clear(); 0669 for (Attribute *a = attributes ().first (); a; a = a->nextSibling ()) { 0670 QString v = a->value (); 0671 int p = v.indexOf ('{'); 0672 if (p > -1) { 0673 int q = v.indexOf ('}', p + 1); 0674 if (q > -1) 0675 continue; 0676 } 0677 parseParam (a->name (), v); 0678 } 0679 } 0680 0681 void Element::reset () { 0682 d->clear(); 0683 Node::reset (); 0684 } 0685 0686 void Element::clear () { 0687 m_attributes = AttributeList (); // remove attributes 0688 d->clear(); 0689 Node::clear (); 0690 } 0691 0692 void Element::setAttributes (const AttributeList &attrs) { 0693 m_attributes = attrs; 0694 } 0695 0696 void Element::accept (Visitor * v) { 0697 v->visit (this); 0698 } 0699 0700 //----------------------------------------------------------------------------- 0701 0702 Attribute::Attribute (const TrieString &ns, const TrieString &n, const QString &v) 0703 : m_namespace (ns), m_name (n), m_value (v) {} 0704 0705 void Attribute::setName (const TrieString & n) { 0706 m_name = n; 0707 } 0708 0709 void Attribute::setValue (const QString & v) { 0710 m_value = v; 0711 } 0712 0713 //----------------------------------------------------------------------------- 0714 0715 QString PlaylistRole::caption () const { 0716 return title; 0717 } 0718 0719 void PlaylistRole::setCaption (const QString &s) { 0720 title = s; 0721 } 0722 0723 //----------------------------------------------------------------------------- 0724 0725 static bool hasMrlChildren (const NodePtr & e) { 0726 for (Node *c = e->firstChild (); c; c = c->nextSibling ()) 0727 if (c->isPlayable () || hasMrlChildren (c)) 0728 return true; 0729 return false; 0730 } 0731 0732 Mrl::Mrl (NodePtr & d, short id) 0733 : Element (d, id), cached_ismrl_version (~0), 0734 media_info (nullptr), 0735 aspect (0), repeat (0), 0736 view_mode (SingleMode), 0737 resolved (false), bookmarkable (true), access_granted (false) {} 0738 0739 Mrl::~Mrl () { 0740 delete media_info; 0741 } 0742 0743 Node::PlayType Mrl::playType () { 0744 if (cached_ismrl_version != document()->m_tree_version) { 0745 bool ismrl = !hasMrlChildren (this); 0746 cached_play_type = ismrl ? play_type_unknown : play_type_none; 0747 cached_ismrl_version = document()->m_tree_version; 0748 } 0749 return cached_play_type; 0750 } 0751 0752 QString Mrl::absolutePath () const 0753 { 0754 QString path = src; 0755 if (!path.isEmpty() && !path.startsWith ("tv:/")) { 0756 for (Node *e = parentNode (); e; e = e->parentNode ()) { 0757 Mrl * mrl = e->mrl (); 0758 if (mrl && !mrl->src.isEmpty () && mrl->src != src) { 0759 path = QUrl(mrl->absolutePath ()).resolved(QUrl(src)).url (); 0760 break; 0761 } 0762 } 0763 } 0764 return path; 0765 } 0766 0767 Node *Mrl::childFromTag (const QString & tag) { 0768 Node * elm = fromXMLDocumentTag (m_doc, tag); 0769 if (elm) 0770 return elm; 0771 return nullptr; 0772 } 0773 0774 Mrl * Mrl::mrl () { 0775 return this; 0776 } 0777 0778 void Mrl::message (MessageType msg, void *content) { 0779 switch (msg) { 0780 case MsgMediaReady: 0781 resolved = true; 0782 if (state == state_deferred) { 0783 if (isPlayable ()) { 0784 setState (state_activated); 0785 begin (); 0786 } else { 0787 Element::activate (); 0788 } 0789 } 0790 break; 0791 0792 case MsgMediaFinished: 0793 if (state == state_deferred && 0794 !isPlayable () && firstChild ()) {//if backend added child links 0795 state = state_activated; 0796 firstChild ()->activate (); 0797 } else if (unfinished ()) { 0798 finish (); 0799 } 0800 break; 0801 0802 default: 0803 break; 0804 } 0805 Node::message (msg, content); 0806 } 0807 0808 void *Mrl::role (RoleType msg, void *content) { 0809 switch (msg) { 0810 0811 case RoleChildDisplay: 0812 for (Node *p = parentNode (); p; p = p->parentNode ()) 0813 if (p->mrl ()) 0814 return p->role (msg, content); 0815 return nullptr; 0816 0817 case RolePlaylist: 0818 if (title.isEmpty ()) 0819 title = src; 0820 return !title.isEmpty () ? (PlaylistRole *) this : nullptr; 0821 0822 default: 0823 break; 0824 } 0825 return Node::role (msg, content); 0826 } 0827 0828 void Mrl::activate () { 0829 if (!resolved && isPlayable ()) { 0830 setState (state_deferred); 0831 media_info = new MediaInfo (this, MediaManager::AudioVideo); 0832 resolved = media_info->wget (absolutePath ()); 0833 if (resolved && isPlayable ()) { 0834 // ignore the MsgMediaReady message redirection 0835 setState (state_activated); 0836 begin (); 0837 } 0838 } else if (isPlayable ()) { 0839 setState (state_activated); 0840 begin (); 0841 } else { 0842 Element::activate (); 0843 } 0844 } 0845 0846 void Mrl::begin () { 0847 qCDebug(LOG_KMPLAYER_COMMON) << nodeName () << src << this; 0848 if (!src.isEmpty ()) { 0849 if (!media_info) 0850 media_info = new MediaInfo (this, MediaManager::AudioVideo); 0851 if (!media_info->media) 0852 media_info->create (); 0853 if (media_info->media->play ()) 0854 setState (state_began); 0855 else 0856 deactivate (); 0857 } else { 0858 deactivate (); // nothing to activate 0859 } 0860 } 0861 0862 void Mrl::defer () { 0863 if (media_info && media_info->media) 0864 media_info->media->pause (); 0865 Node::defer (); 0866 } 0867 0868 void Mrl::undefer () { 0869 if (media_info && media_info->media) { 0870 media_info->media->unpause (); 0871 setState (state_began); 0872 } else { 0873 Node::undefer (); 0874 } 0875 } 0876 0877 void Mrl::deactivate () { 0878 delete media_info; 0879 media_info = nullptr; 0880 Node::deactivate (); 0881 } 0882 0883 void Mrl::parseParam (const TrieString & para, const QString & val) { 0884 if (para == Ids::attr_src && !src.startsWith ("#")) { 0885 QString abs = absolutePath (); 0886 if (abs != src) 0887 src = val; 0888 else 0889 src = QUrl(abs).resolved(QUrl(val)).url (); 0890 for (NodePtr c = firstChild (); c; c = c->nextSibling ()) 0891 if (c->mrl () && c->mrl ()->opener.ptr () == this) { 0892 removeChild (c); 0893 c->reset(); 0894 } 0895 resolved = false; 0896 } 0897 } 0898 0899 unsigned int Mrl::parseTimeString (const QString &ts) { 0900 QString s (ts); 0901 int multiply[] = { 1, 60, 60 * 60, 24 * 60 * 60, 0 }; 0902 int mpos = 0; 0903 double d = 0; 0904 while (!s.isEmpty () && multiply[mpos]) { 0905 int p = s.lastIndexOf (QChar (':')); 0906 QString t = p >= 0 ? s.mid (p + 1) : s; 0907 d += multiply[mpos++] * t.toDouble(); 0908 s = p >= 0 ? s.left (p) : QString (); 0909 } 0910 if (d > 0.01) 0911 return (unsigned int) (d * 100); 0912 return 0; 0913 } 0914 0915 //----------------------%<----------------------------------------------------- 0916 0917 EventData::EventData (Node *t, Posting *e, EventData *n) 0918 : target (t), event (e), next (n) {} 0919 0920 EventData::~EventData () { 0921 delete event; 0922 } 0923 //----------------------------------------------------------------------------- 0924 0925 Postpone::Postpone (NodePtr doc) : m_doc (doc) { 0926 if (m_doc) 0927 m_doc->document ()->timeOfDay (postponed_time); 0928 } 0929 0930 Postpone::~Postpone () { 0931 if (m_doc) 0932 m_doc->document ()->proceed (postponed_time); 0933 } 0934 0935 //----------------------------------------------------------------------------- 0936 0937 static NodePtr dummy_element; 0938 0939 Document::Document (const QString & s, PlayListNotify * n) 0940 : Mrl (dummy_element, id_node_document), 0941 notify_listener (n), 0942 m_tree_version (0), 0943 event_queue (nullptr), 0944 paused_queue (nullptr), 0945 cur_event (nullptr), 0946 cur_timeout (-1) { 0947 m_doc = m_self; // just-in-time setting fragile m_self to m_doc 0948 src = s; 0949 } 0950 0951 Document::~Document () { 0952 qCDebug(LOG_KMPLAYER_COMMON) << "~Document " << src; 0953 } 0954 0955 static Node *getElementByIdImpl (Node *n, const QString & id, bool inter) { 0956 NodePtr elm; 0957 if (!n->isElementNode ()) 0958 return nullptr; 0959 Element *e = static_cast <Element *> (n); 0960 if (e->getAttribute (Ids::attr_id) == id) 0961 return n; 0962 for (Node *c = e->firstChild (); c; c = c->nextSibling ()) { 0963 if (!inter && c->mrl () && c->mrl ()->opener.ptr () == n) 0964 continue; 0965 if ((elm = getElementByIdImpl (c, id, inter))) 0966 break; 0967 } 0968 return elm; 0969 } 0970 0971 Node *Document::getElementById (const QString & id) { 0972 return getElementByIdImpl (this, id, true); 0973 } 0974 0975 Node *Document::getElementById (Node *n, const QString & id, bool inter) { 0976 return getElementByIdImpl (n, id, inter); 0977 } 0978 0979 Node *Document::childFromTag (const QString & tag) { 0980 Node * elm = fromXMLDocumentTag (m_doc, tag); 0981 if (elm) 0982 return elm; 0983 return nullptr; 0984 } 0985 0986 void Document::dispose () { 0987 clear (); 0988 m_doc = nullptr; 0989 } 0990 0991 void Document::activate () { 0992 first_event_time.tv_sec = 0; 0993 last_event_time = 0; 0994 Mrl::activate (); 0995 } 0996 0997 void Document::defer () { 0998 if (resolved) 0999 postpone_lock = postpone (); 1000 Mrl::defer (); 1001 } 1002 1003 void Document::undefer () { 1004 postpone_lock = nullptr; 1005 Mrl::undefer (); 1006 } 1007 1008 void Document::reset () { 1009 Mrl::reset (); 1010 if (event_queue) { 1011 if (notify_listener) 1012 notify_listener->setTimeout (-1); 1013 while (event_queue) { 1014 EventData *ed = event_queue; 1015 event_queue = ed->next; 1016 delete ed; 1017 } 1018 cur_timeout = -1; 1019 } 1020 postpone_lock = nullptr; 1021 } 1022 1023 static inline 1024 int diffTime (const struct timeval & tv1, const struct timeval & tv2) { 1025 //qCDebug(LOG_KMPLAYER_COMMON) << "diffTime sec:" << ((tv1.tv_sec - tv2.tv_sec) * 1000) << " usec:" << ((tv1.tv_usec - tv2.tv_usec) /1000); 1026 return (tv1.tv_sec - tv2.tv_sec) * 1000 + (tv1.tv_usec - tv2.tv_usec) /1000; 1027 } 1028 1029 static inline void addTime (struct timeval & tv, int ms) { 1030 if (ms >= 1000) { 1031 tv.tv_sec += ms / 1000; 1032 ms %= 1000; 1033 } 1034 tv.tv_sec += (tv.tv_usec + ms*1000) / 1000000; 1035 tv.tv_usec = (tv.tv_usec + ms*1000) % 1000000; 1036 } 1037 1038 UpdateEvent::UpdateEvent (Document *doc, unsigned int skip) 1039 : skipped_time (skip) { 1040 struct timeval tv; 1041 doc->timeOfDay (tv); 1042 cur_event_time = doc->last_event_time; 1043 } 1044 1045 //----------------------------------------------------------------------------- 1046 /*static inline void subtractTime (struct timeval & tv, int ms) { 1047 int sec = ms / 1000; 1048 int msec = ms % 1000; 1049 tv.tv_sec -= sec; 1050 if (tv.tv_usec / 1000 >= msec) { 1051 tv.tv_usec -= msec * 1000; 1052 } else { 1053 tv.tv_sec--; 1054 tv.tv_usec = 1000000 - (msec - tv.tv_usec / 1000 ); 1055 } 1056 }*/ 1057 1058 void Document::timeOfDay (struct timeval & tv) { 1059 gettimeofday (&tv, nullptr); 1060 if (!first_event_time.tv_sec) { 1061 first_event_time = tv; 1062 last_event_time = 0; 1063 } else { 1064 last_event_time = diffTime (tv, first_event_time); 1065 } 1066 } 1067 1068 static bool postponedSensible (MessageType msg) { 1069 return msg == MsgEventTimer || 1070 msg == MsgEventStarted || 1071 msg == MsgEventStopped; 1072 } 1073 1074 void Document::insertPosting (Node *n, Posting *e, const struct timeval &tv) { 1075 if (!notify_listener) 1076 return; 1077 bool postponed_sensible = postponedSensible (e->message); 1078 EventData *prev = nullptr; 1079 EventData *ed = event_queue; 1080 for (; ed; ed = ed->next) { 1081 int diff = diffTime (ed->timeout, tv); 1082 bool psens = postponedSensible (ed->event->message); 1083 if ((diff > 0 && postponed_sensible == psens) || (!postponed_sensible && psens)) 1084 break; 1085 prev = ed; 1086 } 1087 ed = new EventData (n, e, ed); 1088 ed->timeout = tv; 1089 if (prev) 1090 prev->next = ed; 1091 else 1092 event_queue = ed; 1093 //qCDebug(LOG_KMPLAYER_COMMON) << "setTimeout " << ms << " at:" << pos << " tv:" << tv.tv_sec << "." << tv.tv_usec; 1094 } 1095 1096 void Document::setNextTimeout (const struct timeval &now) { 1097 if (!cur_event) { // if we're not processing events 1098 int timeout = 0x7FFFFFFF; 1099 if (event_queue && active () && 1100 (!postpone_ref || !postponedSensible (event_queue->event->message))) 1101 timeout = diffTime (event_queue->timeout, now); 1102 timeout = 0x7FFFFFFF != timeout ? (timeout > 0 ? timeout : 0) : -1; 1103 if (timeout != cur_timeout) { 1104 cur_timeout = timeout; 1105 notify_listener->setTimeout (cur_timeout); 1106 } 1107 } 1108 } 1109 1110 void Document::updateTimeout () { 1111 if (!postpone_ref && event_queue && notify_listener) { 1112 struct timeval now; 1113 if (cur_event) 1114 now = cur_event->timeout; 1115 else 1116 timeOfDay (now); 1117 setNextTimeout (now); 1118 } 1119 } 1120 1121 Posting *Document::post (Node *n, Posting *e) { 1122 int ms = e->message == MsgEventTimer 1123 ? static_cast<TimerPosting *>(e)->milli_sec 1124 : 0; 1125 struct timeval now, tv; 1126 if (cur_event) 1127 now = cur_event->timeout; 1128 else 1129 timeOfDay (now); 1130 tv = now; 1131 addTime (tv, ms); 1132 insertPosting (n, e, tv); 1133 if (postpone_ref || event_queue->event == e) 1134 setNextTimeout (now); 1135 return e; 1136 } 1137 1138 static EventData *findPosting (EventData *queue, EventData **prev, const Posting *e) { 1139 *prev = nullptr; 1140 for (EventData *ed = queue; ed; ed = ed->next) { 1141 if (e == ed->event) 1142 return ed; 1143 *prev = ed; 1144 } 1145 return nullptr; 1146 } 1147 1148 void Document::cancelPosting (Posting *e) { 1149 if (cur_event && cur_event->event == e) { 1150 delete cur_event->event; 1151 cur_event->event = nullptr; 1152 } else { 1153 EventData *prev; 1154 EventData **queue = &event_queue; 1155 EventData *ed = findPosting (event_queue, &prev, e); 1156 if (!ed) { 1157 ed = findPosting (paused_queue, &prev, e); 1158 queue = &paused_queue; 1159 } 1160 if (ed) { 1161 if (prev) { 1162 prev->next = ed->next; 1163 } else { 1164 *queue = ed->next; 1165 if (!cur_event && queue == &event_queue) { 1166 struct timeval now; 1167 if (event_queue) // save a sys call 1168 timeOfDay (now); 1169 setNextTimeout (now); 1170 } 1171 } 1172 delete ed; 1173 } else { 1174 qCCritical(LOG_KMPLAYER_COMMON) << "Posting not found"; 1175 } 1176 } 1177 } 1178 1179 void Document::pausePosting (Posting *e) { 1180 if (cur_event && cur_event->event == e) { 1181 paused_queue = new EventData (cur_event->target, cur_event->event, paused_queue); 1182 paused_queue->timeout = cur_event->timeout; 1183 cur_event->event = nullptr; 1184 } else { 1185 EventData *prev; 1186 EventData *ed = findPosting (event_queue, &prev, e); 1187 if (ed) { 1188 if (prev) 1189 prev->next = ed->next; 1190 else 1191 event_queue = ed->next; 1192 ed->next = paused_queue; 1193 paused_queue = ed; 1194 } else { 1195 qCCritical(LOG_KMPLAYER_COMMON) << "pauseEvent not found"; 1196 } 1197 } 1198 } 1199 1200 void Document::unpausePosting (Posting *e, int ms) { 1201 EventData *prev; 1202 EventData *ed = findPosting (paused_queue, &prev, e); 1203 if (ed) { 1204 if (prev) 1205 prev->next = ed->next; 1206 else 1207 paused_queue = ed->next; 1208 addTime (ed->timeout, ms); 1209 insertPosting (ed->target, ed->event, ed->timeout); 1210 ed->event = nullptr; 1211 delete ed; 1212 } else { 1213 qCCritical(LOG_KMPLAYER_COMMON) << "pausePosting not found"; 1214 } 1215 } 1216 1217 void Document::timer () { 1218 struct timeval now; 1219 cur_event = event_queue; 1220 if (cur_event) { 1221 NodePtrW guard = this; 1222 struct timeval start = cur_event->timeout; 1223 timeOfDay (now); 1224 1225 // handle max 100 timeouts with timeout set to now 1226 for (int i = 0; i < 100 && active (); ++i) { 1227 if (postpone_ref && postponedSensible (cur_event->event->message)) 1228 break; 1229 // remove from queue 1230 event_queue = cur_event->next; 1231 1232 if (!cur_event->target) { 1233 // some part of document has gone and didn't remove timer 1234 qCCritical(LOG_KMPLAYER_COMMON) << "spurious timer" << endl; 1235 } else { 1236 EventData *ed = cur_event; 1237 cur_event->target->message (cur_event->event->message, cur_event->event); 1238 if (!guard) { 1239 delete ed; 1240 return; 1241 } 1242 if (cur_event->event && cur_event->event->message == MsgEventTimer) { 1243 TimerPosting *te = static_cast <TimerPosting *> (cur_event->event); 1244 if (te->interval) { 1245 te->interval = false; // reset interval 1246 addTime (cur_event->timeout, te->milli_sec); 1247 insertPosting (cur_event->target, 1248 cur_event->event, 1249 cur_event->timeout); 1250 cur_event->event = nullptr; 1251 } 1252 } 1253 } 1254 delete cur_event; 1255 cur_event = event_queue; 1256 if (!cur_event || diffTime (cur_event->timeout, start) > 5) 1257 break; 1258 } 1259 cur_event = nullptr; 1260 } 1261 setNextTimeout (now); 1262 } 1263 1264 PostponePtr Document::postpone () { 1265 if (postpone_ref) 1266 return postpone_ref; 1267 qCDebug(LOG_KMPLAYER_COMMON) << "postpone"; 1268 PostponePtr p = new Postpone (this); 1269 postpone_ref = p; 1270 PostponedEvent event (true); 1271 deliver (MsgEventPostponed, &event); 1272 if (notify_listener) 1273 notify_listener->enableRepaintUpdaters (false, 0); 1274 if (!cur_event) { 1275 struct timeval now; 1276 if (event_queue) // save a sys call 1277 timeOfDay (now); 1278 setNextTimeout (now); 1279 } 1280 return p; 1281 } 1282 1283 void Document::proceed (const struct timeval &postponed_time) { 1284 qCDebug(LOG_KMPLAYER_COMMON) << "proceed"; 1285 postpone_ref = nullptr; 1286 struct timeval now; 1287 timeOfDay (now); 1288 int diff = diffTime (now, postponed_time); 1289 if (event_queue) { 1290 for (EventData *ed = event_queue; ed; ed = ed->next) 1291 if (ed->event && postponedSensible (ed->event->message)) 1292 addTime (ed->timeout, diff); 1293 setNextTimeout (now); 1294 } 1295 if (notify_listener) 1296 notify_listener->enableRepaintUpdaters (true, diff); 1297 PostponedEvent event (false); 1298 deliver (MsgEventPostponed, &event); 1299 } 1300 1301 void *Document::role (RoleType msg, void *content) { 1302 if (RoleReceivers == msg) { 1303 MessageType m = (MessageType) (long) content; 1304 if (MsgEventPostponed == m) 1305 return &m_PostponedListeners; 1306 } 1307 return Mrl::role (msg, content); 1308 } 1309 1310 //----------------------------------------------------------------------------- 1311 1312 TextNode::TextNode (NodePtr & d, const QString & s, short i) 1313 : Node (d, i), text (s) {} 1314 1315 void TextNode::appendText (const QString & s) { 1316 text += s; 1317 } 1318 1319 QString TextNode::nodeValue () const { 1320 return text; 1321 } 1322 1323 //----------------------------------------------------------------------------- 1324 1325 CData::CData (NodePtr & d, const QString & s) 1326 : TextNode (d, s, id_node_cdata) {} 1327 1328 //----------------------------------------------------------------------------- 1329 1330 DarkNode::DarkNode (NodePtr & d, const QByteArray &n, short id) 1331 : Element (d, id), name (n) { 1332 } 1333 1334 Node *DarkNode::childFromTag (const QString & tag) { 1335 return new DarkNode (m_doc, tag.toUtf8 ()); 1336 } 1337 1338 //----------------------------------------------------------------------------- 1339 1340 GenericURL::GenericURL (NodePtr & d, const QString & s, const QString & name) 1341 : Mrl (d, id_node_playlist_item) { 1342 src = s; 1343 if (!src.isEmpty ()) 1344 setAttribute (Ids::attr_src, src); 1345 title = name; 1346 } 1347 1348 void GenericURL::closed () { 1349 if (src.isEmpty ()) 1350 src = getAttribute (Ids::attr_src); 1351 Mrl::closed (); 1352 } 1353 1354 //----------------------------------------------------------------------------- 1355 1356 GenericMrl::GenericMrl (NodePtr & d, const QString &s, const QString &name, const QByteArray &tag) 1357 : Mrl (d, id_node_playlist_item), node_name (tag) { 1358 src = s; 1359 if (!src.isEmpty ()) 1360 setAttribute (Ids::attr_src, src); 1361 title = name; 1362 if (!name.isEmpty ()) 1363 setAttribute (Ids::attr_name, name); 1364 } 1365 1366 void GenericMrl::closed () { 1367 if (src.isEmpty ()) { 1368 src = getAttribute (Ids::attr_src); 1369 if (src.isEmpty ()) 1370 src = getAttribute (Ids::attr_url); 1371 } 1372 if (title.isEmpty ()) 1373 title = getAttribute (Ids::attr_name); 1374 Mrl::closed (); 1375 } 1376 1377 void *GenericMrl::role (RoleType msg, void *content) 1378 { 1379 if (RolePlaylist == msg) 1380 return !title.isEmpty () || //return false if no title and only one 1381 previousSibling () || nextSibling () 1382 ? (PlaylistRole *) this : nullptr; 1383 return Mrl::role (msg, content); 1384 } 1385 1386 //----------------------------------------------------------------------------- 1387 1388 void Visitor::visit (Element *elm) { 1389 visit (static_cast <Node *> (elm)); 1390 } 1391 1392 void Visitor::visit (TextNode *text) { 1393 visit (static_cast <Node *> (text)); 1394 } 1395 1396 //----------------------------------------------------------------------------- 1397 1398 CacheAllocator::CacheAllocator (size_t s) 1399 : pool ((void**) malloc (10 * sizeof (void *))), size (s), count (0) {} 1400 1401 void *CacheAllocator::alloc () { 1402 return count ? pool[--count] : malloc (size); 1403 } 1404 1405 void CacheAllocator::dealloc (void *p) { 1406 if (count < 10) 1407 pool[count++] = p; 1408 else 1409 free (p); 1410 } 1411 1412 KMPLAYERCOMMON_EXPORT CacheAllocator *KMPlayer::shared_data_cache_allocator = nullptr; 1413 1414 //----------------------------------------------------------------------------- 1415 1416 namespace KMPlayer { 1417 1418 class DocumentBuilder 1419 { 1420 int m_ignore_depth; 1421 bool m_set_opener; 1422 bool m_root_is_first; 1423 NodePtr m_node; 1424 NodePtr m_root; 1425 public: 1426 DocumentBuilder (NodePtr d, bool set_opener); 1427 ~DocumentBuilder () {} 1428 bool startTag (const QString & tag, const AttributeList &attr); 1429 bool endTag (const QString & tag); 1430 bool characterData (const QString & data); 1431 bool cdataData (const QString & data); 1432 #ifdef KMPLAYER_WITH_EXPAT 1433 void cdataStart (); 1434 void cdataEnd (); 1435 private: 1436 bool in_cdata; 1437 QString cdata; 1438 #endif 1439 }; 1440 1441 } // namespace KMPlayer 1442 1443 DocumentBuilder::DocumentBuilder (NodePtr d, bool set_opener) 1444 : m_ignore_depth (0), m_set_opener (set_opener), m_root_is_first (false) 1445 , m_node (d), m_root (d) 1446 #ifdef KMPLAYER_WITH_EXPAT 1447 , in_cdata (false) 1448 #endif 1449 {} 1450 1451 bool DocumentBuilder::startTag(const QString &tag, const AttributeList &attr) { 1452 if (m_ignore_depth) { 1453 m_ignore_depth++; 1454 //qCDebug(LOG_KMPLAYER_COMMON) << "Warning: ignored tag " << tag.latin1 () << " ignore depth = " << m_ignore_depth; 1455 } else if (!m_node) { 1456 return false; // had underflow 1457 } else { 1458 NodePtr n = m_node->childFromTag (tag); 1459 if (!n) { 1460 qCDebug(LOG_KMPLAYER_COMMON) << "Warning: unknown tag " << tag.toLocal8Bit ().constData(); 1461 NodePtr doc = m_root->document (); 1462 n = new DarkNode (doc, tag.toUtf8 ()); 1463 } 1464 //qCDebug(LOG_KMPLAYER_COMMON) << "Found tag " << tag; 1465 if (n->isElementNode ()) 1466 convertNode <Element> (n)->setAttributes (attr); 1467 if (m_node == n && m_node == m_root) 1468 m_root_is_first = true; 1469 else 1470 m_node->appendChild (n); 1471 if (m_set_opener && m_node == m_root) { 1472 Mrl * mrl = n->mrl (); 1473 if (mrl) 1474 mrl->opener = m_root; 1475 } 1476 n->opened (); 1477 m_node = n; 1478 } 1479 return true; 1480 } 1481 1482 bool DocumentBuilder::endTag (const QString & tag) { 1483 if (m_ignore_depth) { // endtag to ignore 1484 m_ignore_depth--; 1485 qCDebug(LOG_KMPLAYER_COMMON) << "Warning: ignored end tag " << " ignore depth = " << m_ignore_depth; 1486 } else if (!m_node) { 1487 return false; // had underflow 1488 } else { // endtag 1489 NodePtr n = m_node; 1490 while (n) { 1491 if (!strcasecmp (n->nodeName (), tag.toLocal8Bit ().constData ()) && 1492 (m_root_is_first || n != m_root)) { 1493 while (n != m_node) { 1494 qCWarning(LOG_KMPLAYER_COMMON) << m_node->nodeName () << " not closed"; 1495 if (m_root == m_node->parentNode ()) 1496 break; 1497 m_node->closed (); 1498 m_node = m_node->parentNode (); 1499 } 1500 break; 1501 } 1502 if (n == m_root) { 1503 if (n == m_node) { 1504 qCCritical(LOG_KMPLAYER_COMMON) << "m_node == m_doc, stack underflow " << endl; 1505 return false; 1506 } 1507 qCWarning(LOG_KMPLAYER_COMMON) << "endtag: no match " << tag.toLocal8Bit ().constData(); 1508 break; 1509 } else 1510 qCWarning(LOG_KMPLAYER_COMMON) << "tag " << tag << " not " << n->nodeName (); 1511 n = n ->parentNode (); 1512 } 1513 //qCDebug(LOG_KMPLAYER_COMMON) << "end tag " << tag; 1514 m_node->closed (); 1515 m_node = m_node->parentNode (); 1516 } 1517 return true; 1518 } 1519 1520 bool DocumentBuilder::characterData (const QString & data) { 1521 if (!m_ignore_depth && m_node) { 1522 #ifdef KMPLAYER_WITH_EXPAT 1523 if (in_cdata) 1524 cdata += data; 1525 else 1526 #endif 1527 m_node->characterData (data); 1528 } 1529 //qCDebug(LOG_KMPLAYER_COMMON) << "characterData " << d.latin1(); 1530 return !!m_node; 1531 } 1532 1533 bool DocumentBuilder::cdataData (const QString & data) { 1534 if (!m_ignore_depth && m_node) { 1535 NodePtr d = m_node->document (); 1536 m_node->appendChild (new CData (d, data)); 1537 } 1538 //qCDebug(LOG_KMPLAYER_COMMON) << "cdataData " << d.latin1(); 1539 return !!m_node; 1540 } 1541 1542 #ifdef KMPLAYER_WITH_EXPAT 1543 1544 void DocumentBuilder::cdataStart () { 1545 cdata.truncate (0); 1546 in_cdata = true; 1547 } 1548 1549 void DocumentBuilder::cdataEnd () { 1550 cdataData (cdata); 1551 cdata.truncate (0); 1552 in_cdata = false; 1553 } 1554 1555 static void startTag (void *data, const char * tag, const char **attr) { 1556 DocumentBuilder * builder = static_cast <DocumentBuilder *> (data); 1557 AttributeList attributes; 1558 if (attr && attr [0]) { 1559 for (int i = 0; attr[i]; i += 2) 1560 attributes.append (new Attribute ( 1561 TrieString(), 1562 QString::fromUtf8 (attr [i]), 1563 QString::fromUtf8 (attr [i+1]))); 1564 } 1565 builder->startTag (QString::fromUtf8 (tag), attributes); 1566 } 1567 1568 static void endTag (void *data, const char * tag) { 1569 DocumentBuilder * builder = static_cast <DocumentBuilder *> (data); 1570 builder->endTag (QString::fromUtf8 (tag)); 1571 } 1572 1573 static void characterData (void *data, const char *s, int len) { 1574 DocumentBuilder * builder = static_cast <DocumentBuilder *> (data); 1575 char * buf = new char [len + 1]; 1576 strncpy (buf, s, len); 1577 buf[len] = 0; 1578 builder->characterData (QString::fromUtf8 (buf)); 1579 delete [] buf; 1580 } 1581 1582 static void cdataStart (void *data) { 1583 DocumentBuilder * builder = static_cast <DocumentBuilder *> (data); 1584 builder->cdataStart (); 1585 } 1586 1587 static void cdataEnd (void *data) { 1588 DocumentBuilder * builder = static_cast <DocumentBuilder *> (data); 1589 builder->cdataEnd (); 1590 } 1591 1592 void KMPlayer::readXML (NodePtr root, QTextStream & in, const QString & firstline, bool set_opener) { 1593 bool ok = true; 1594 DocumentBuilder builder (root, set_opener); 1595 XML_Parser parser = XML_ParserCreate (0L); 1596 XML_SetUserData (parser, &builder); 1597 XML_SetElementHandler (parser, startTag, endTag); 1598 XML_SetCharacterDataHandler (parser, characterData); 1599 XML_SetCdataSectionHandler (parser, cdataStart, cdataEnd); 1600 if (!firstline.isEmpty ()) { 1601 QString str (firstline + QChar ('\n')); 1602 QByteArray ba = str.toUtf8(); 1603 char *buf = ba.data(); 1604 ok = XML_Parse(parser, buf, strlen (buf), false) != XML_STATUS_ERROR; 1605 if (!ok) 1606 qCWarning(LOG_KMPLAYER_COMMON) << XML_ErrorString(XML_GetErrorCode(parser)) << " at " << XML_GetCurrentLineNumber(parser) << " col " << XML_GetCurrentColumnNumber(parser); 1607 } 1608 if (ok && !in.atEnd ()) { 1609 QByteArray ba = in.readAll().toUtf8(); 1610 char *buf = ba.data(); 1611 ok = XML_Parse(parser, buf, strlen (buf), true) != XML_STATUS_ERROR; 1612 if (!ok) 1613 qCWarning(LOG_KMPLAYER_COMMON) << XML_ErrorString(XML_GetErrorCode(parser)) << " at " << XML_GetCurrentLineNumber(parser) << " col " << XML_GetCurrentColumnNumber(parser); 1614 } 1615 XML_ParserFree(parser); 1616 root->normalize (); 1617 //return ok; 1618 } 1619 1620 //----------------------------------------------------------------------------- 1621 #else // KMPLAYER_WITH_EXPAT 1622 1623 namespace { 1624 1625 class SimpleSAXParser 1626 { 1627 enum Token { tok_empty, tok_text, tok_white_space, tok_angle_open, 1628 tok_equal, tok_double_quote, tok_single_quote, tok_angle_close, 1629 tok_slash, tok_exclamation, tok_amp, tok_hash, tok_colon, 1630 tok_semi_colon, tok_question_mark, tok_cdata_start }; 1631 public: 1632 struct TokenInfo { 1633 TokenInfo () : token (tok_empty) {} 1634 void *operator new (size_t); 1635 void operator delete (void *); 1636 Token token; 1637 QString string; 1638 SharedPtr <TokenInfo> next; 1639 }; 1640 typedef SharedPtr <TokenInfo> TokenInfoPtr; 1641 SimpleSAXParser (DocumentBuilder & b) : builder (b), position (0), equal_seen (false), in_dbl_quote (false), in_sngl_quote (false), have_error (false), no_entitity_look_ahead (false), have_next_char (false) {} 1642 virtual ~SimpleSAXParser () {}; 1643 bool parse (QTextStream & d); 1644 private: 1645 QTextStream * data; 1646 DocumentBuilder & builder; 1647 int position; 1648 QChar next_char; 1649 enum State { 1650 InTag, InStartTag, InPITag, InDTDTag, InEndTag, InAttributes, InContent, InCDATA, InComment 1651 }; 1652 struct StateInfo { 1653 StateInfo (State s, SharedPtr <StateInfo> n) : state (s), next (n) {} 1654 State state; 1655 QString data; 1656 SharedPtr <StateInfo> next; 1657 }; 1658 SharedPtr <StateInfo> m_state; 1659 TokenInfoPtr next_token, token, prev_token; 1660 // for element reading 1661 QString tagname; 1662 AttributeList m_attributes; 1663 QString attr_namespace, attr_name, attr_value; 1664 QString cdata; 1665 bool equal_seen; 1666 bool in_dbl_quote; 1667 bool in_sngl_quote; 1668 bool have_error; 1669 bool no_entitity_look_ahead; 1670 bool have_next_char; 1671 1672 bool readTag (); 1673 bool readEndTag (); 1674 bool readAttributes (); 1675 bool readPI (); 1676 bool readDTD (); 1677 bool readCDATA (); 1678 bool readComment (); 1679 bool nextToken (); 1680 void push (); 1681 void push_attribute (); 1682 }; 1683 1684 } // namespace 1685 1686 static CacheAllocator token_pool (sizeof (SimpleSAXParser::TokenInfo)); 1687 1688 inline void *SimpleSAXParser::TokenInfo::operator new (size_t) { 1689 return token_pool.alloc (); 1690 } 1691 1692 inline void SimpleSAXParser::TokenInfo::operator delete (void *p) { 1693 token_pool.dealloc (p); 1694 } 1695 1696 void KMPlayer::readXML (NodePtr root, QTextStream & in, const QString & firstline, bool set_opener) { 1697 DocumentBuilder builder (root, set_opener); 1698 root->opened (); 1699 SimpleSAXParser parser (builder); 1700 if (!firstline.isEmpty ()) { 1701 QString str (firstline + QChar ('\n')); 1702 QTextStream fl_in (&str, QIODevice::ReadOnly); 1703 parser.parse (fl_in); 1704 } 1705 if (!in.atEnd ()) 1706 parser.parse (in); 1707 if (root->open) // endTag may have closed it 1708 root->closed (); 1709 for (NodePtr e = root->parentNode (); e; e = e->parentNode ()) { 1710 if (e->open) 1711 break; 1712 e->closed (); 1713 } 1714 //doc->normalize (); 1715 //qCDebug(LOG_KMPLAYER_COMMON) << root->outerXML (); 1716 } 1717 1718 void SimpleSAXParser::push () { 1719 if (next_token->string.size ()) { 1720 prev_token = token; 1721 token = next_token; 1722 if (prev_token) 1723 prev_token->next = token; 1724 next_token = TokenInfoPtr (new TokenInfo); 1725 //qCDebug(LOG_KMPLAYER_COMMON) << "push " << token->string; 1726 } 1727 } 1728 1729 void SimpleSAXParser::push_attribute () { 1730 //qCDebug(LOG_KMPLAYER_COMMON) << "attribute " << attr_name.latin1 () << "=" << attr_value.latin1 (); 1731 m_attributes.append(new Attribute (attr_namespace, attr_name, attr_value)); 1732 attr_namespace.clear (); 1733 attr_name.truncate (0); 1734 attr_value.truncate (0); 1735 equal_seen = in_sngl_quote = in_dbl_quote = false; 1736 } 1737 1738 bool SimpleSAXParser::nextToken () { 1739 TokenInfoPtr cur_token = token; 1740 while (!data->atEnd () && cur_token == token && !(token && token->next)) { 1741 if (have_next_char) 1742 have_next_char = false; 1743 else 1744 *data >> next_char; 1745 bool append_char = true; 1746 if (next_char.isSpace ()) { 1747 if (next_token->token != tok_white_space) 1748 push (); 1749 next_token->token = tok_white_space; 1750 } else if (!next_char.isLetterOrNumber ()) { 1751 if (next_char == QChar ('#')) { 1752 //if (next_token->token == tok_empty) { // check last item on stack & 1753 push (); 1754 next_token->token = tok_hash; 1755 //} 1756 } else if (next_char == QChar ('/')) { 1757 push (); 1758 next_token->token = tok_slash; 1759 } else if (next_char == QChar ('!')) { 1760 push (); 1761 next_token->token = tok_exclamation; 1762 } else if (next_char == QChar ('?')) { 1763 push (); 1764 next_token->token = tok_question_mark; 1765 } else if (next_char == QChar ('<')) { 1766 push (); 1767 next_token->token = tok_angle_open; 1768 } else if (next_char == QChar ('>')) { 1769 push (); 1770 next_token->token = tok_angle_close; 1771 } else if (InAttributes == m_state->state && 1772 next_char == QChar (':')) { 1773 push (); 1774 next_token->token = tok_colon; 1775 } else if (next_char == QChar (';')) { 1776 push (); 1777 next_token->token = tok_semi_colon; 1778 } else if (next_char == QChar ('=')) { 1779 push (); 1780 next_token->token = tok_equal; 1781 } else if (next_char == QChar ('"')) { 1782 push (); 1783 next_token->token = tok_double_quote; 1784 } else if (next_char == QChar ('\'')) { 1785 push (); 1786 next_token->token = tok_single_quote; 1787 } else if (next_char == QChar ('&')) { 1788 push (); 1789 if (no_entitity_look_ahead) { 1790 have_next_char = true; 1791 break; 1792 } 1793 append_char = false; 1794 no_entitity_look_ahead = true; 1795 TokenInfoPtr tmp = token; 1796 TokenInfoPtr prev_tmp = prev_token; 1797 if (nextToken () && token->token == tok_text && 1798 nextToken () && token->token == tok_semi_colon) { 1799 if (prev_token->string == QString ("amp")) 1800 token->string = QChar ('&'); 1801 else if (prev_token->string == QString ("lt")) 1802 token->string = QChar ('<'); 1803 else if (prev_token->string == QString ("gt")) 1804 token->string = QChar ('>'); 1805 else if (prev_token->string == QString ("quot")) 1806 token->string = QChar ('"'); 1807 else if (prev_token->string == QString ("apos")) 1808 token->string = QChar ('\''); 1809 else if (prev_token->string == QString ("copy")) 1810 token->string = QChar (169); 1811 else 1812 token->string = QChar ('?');// TODO lookup more .. 1813 token->token = tok_text; 1814 if (tmp) { // cut out the & xxx ; tokens 1815 tmp->next = token; 1816 token = tmp; 1817 } 1818 //qCDebug(LOG_KMPLAYER_COMMON) << "entity found "<<prev_token->string; 1819 } else if (token->token == tok_hash && 1820 nextToken () && token->token == tok_text && 1821 nextToken () && token->token == tok_semi_colon) { 1822 //qCDebug(LOG_KMPLAYER_COMMON) << "char entity found " << prev_token->string << prev_token->string.toInt (0L, 16); 1823 token->token = tok_text; 1824 if (!prev_token->string.startsWith (QChar ('x'))) 1825 token->string = QChar (prev_token->string.toInt ()); 1826 else 1827 token->string = QChar (prev_token->string.mid (1).toInt (nullptr, 16)); 1828 if (tmp) { // cut out the '& # xxx ;' tokens 1829 tmp->next = token; 1830 token = tmp; 1831 } 1832 } else { 1833 token = tmp; // restore and insert the lost & token 1834 tmp = TokenInfoPtr (new TokenInfo); 1835 tmp->token = tok_amp; 1836 tmp->string += QChar ('&'); 1837 tmp->next = token->next; 1838 if (token) 1839 token->next = tmp; 1840 else 1841 token = tmp; // hmm 1842 } 1843 no_entitity_look_ahead = false; 1844 prev_token = prev_tmp; 1845 } else if (next_token->token != tok_text) { 1846 push (); 1847 next_token->token = tok_text; 1848 } 1849 } else if (next_token->token != tok_text) { 1850 push (); 1851 next_token->token = tok_text; 1852 } 1853 if (append_char) 1854 next_token->string += next_char; 1855 if (next_token->token == tok_text && 1856 next_char == QChar ('[' ) && next_token->string == "[CDATA[") { 1857 next_token->token = tok_cdata_start; 1858 break; 1859 } 1860 } 1861 if (token == cur_token) { 1862 if (token && token->next) { 1863 prev_token = token; 1864 token = token->next; 1865 } else if (next_token->string.size ()) { 1866 push (); // last token 1867 } else 1868 return false; 1869 return true; 1870 } 1871 return true; 1872 } 1873 1874 bool SimpleSAXParser::readAttributes () { 1875 bool closed = false; 1876 while (true) { 1877 if (!nextToken ()) return false; 1878 //qCDebug(LOG_KMPLAYER_COMMON) << "readAttributes " << token->string.latin1(); 1879 if ((in_dbl_quote && token->token != tok_double_quote) || 1880 (in_sngl_quote && token->token != tok_single_quote)) { 1881 attr_value += token->string; 1882 } else if (token->token == tok_equal) { 1883 if (attr_name.isEmpty ()) 1884 return false; 1885 if (equal_seen) 1886 attr_value += token->string; // EQ=a=2c ??? 1887 //qCDebug(LOG_KMPLAYER_COMMON) << "equal_seen"; 1888 equal_seen = true; 1889 } else if (token->token == tok_white_space) { 1890 if (!attr_value.isEmpty ()) 1891 push_attribute (); 1892 } else if (token->token == tok_single_quote) { 1893 if (!equal_seen) 1894 attr_name += token->string; // D'OH=xxx ??? 1895 else if (in_sngl_quote) { // found one 1896 push_attribute (); 1897 } else if (attr_value.isEmpty ()) 1898 in_sngl_quote = true; 1899 else 1900 attr_value += token->string; 1901 } else if (token->token == tok_colon) { 1902 if (equal_seen) { 1903 attr_value += token->string; 1904 } else { 1905 attr_namespace = attr_name; 1906 attr_name.clear(); 1907 } 1908 } else if (token->token == tok_double_quote) { 1909 if (!equal_seen) 1910 attr_name += token->string; // hmm 1911 else if (in_dbl_quote) { // found one 1912 push_attribute (); 1913 } else if (attr_value.isEmpty ()) 1914 in_dbl_quote = true; 1915 else 1916 attr_value += token->string; 1917 //qCDebug(LOG_KMPLAYER_COMMON) << "in_dbl_quote:"<< in_dbl_quote; 1918 } else if (token->token == tok_slash) { 1919 TokenInfoPtr mark_token = token; 1920 if (nextToken () && 1921 (token->token != tok_white_space || nextToken()) &&//<e / > 1922 token->token == tok_angle_close) { 1923 //qCDebug(LOG_KMPLAYER_COMMON) << "close mark:"; 1924 closed = true; 1925 break; 1926 } else { 1927 token = mark_token; 1928 //qCDebug(LOG_KMPLAYER_COMMON) << "not end mark:"<< equal_seen; 1929 if (equal_seen) 1930 attr_value += token->string; // ABBR=w/o ??? 1931 else 1932 attr_name += token->string; 1933 } 1934 } else if (token->token == tok_angle_close) { 1935 if (!attr_name.isEmpty ()) 1936 push_attribute (); 1937 break; 1938 } else if (equal_seen) { 1939 attr_value += token->string; 1940 } else { 1941 attr_name += token->string; 1942 } 1943 } 1944 m_state = m_state->next; 1945 if (m_state->state == InPITag) { 1946 if (tagname == QString ("xml")) { 1947 /*const AttributeMap::const_iterator e = attr.end (); 1948 for (AttributeMap::const_iterator i = attr.begin (); i != e; ++i) 1949 if (!strcasecmp (i.key ().latin1 (), "encoding")) 1950 qCDebug(LOG_KMPLAYER_COMMON) << "encodeing " << i.data().latin1();*/ 1951 } 1952 } else { 1953 have_error = !builder.startTag (tagname, m_attributes); 1954 if (closed) 1955 have_error &= !builder.endTag (tagname); 1956 //qCDebug(LOG_KMPLAYER_COMMON) << "readTag " << tagname << " closed:" << closed << " ok:" << have_error; 1957 } 1958 m_state = m_state->next; // pop Node or PI 1959 return !have_error; 1960 } 1961 1962 bool SimpleSAXParser::readPI () { 1963 // TODO: <?xml .. encoding="ENC" .. ?> 1964 if (!nextToken ()) return false; 1965 if (token->token == tok_text && !token->string.compare ("xml")) { 1966 m_state = new StateInfo (InAttributes, m_state); 1967 return readAttributes (); 1968 } else { 1969 while (nextToken ()) 1970 if (token->token == tok_angle_close) { 1971 m_state = m_state->next; 1972 return true; 1973 } 1974 } 1975 return false; 1976 } 1977 1978 bool SimpleSAXParser::readDTD () { 1979 //TODO: <!ENTITY ..> 1980 if (!nextToken ()) return false; 1981 if (token->token == tok_text && token->string.startsWith (QString ("--"))) { 1982 m_state = new StateInfo (InComment, m_state->next); // note: pop DTD 1983 return readComment (); 1984 } 1985 //qCDebug(LOG_KMPLAYER_COMMON) << "readDTD: " << token->string.latin1 (); 1986 if (token->token == tok_cdata_start) { 1987 m_state = new StateInfo (InCDATA, m_state->next); // note: pop DTD 1988 if (token->next) { 1989 cdata = token->next->string; 1990 token->next = nullptr; 1991 } else { 1992 cdata = next_token->string; 1993 next_token->string.truncate (0); 1994 next_token->token = tok_empty; 1995 } 1996 return readCDATA (); 1997 } 1998 while (nextToken ()) 1999 if (token->token == tok_angle_close) { 2000 m_state = m_state->next; 2001 return true; 2002 } 2003 return false; 2004 } 2005 2006 bool SimpleSAXParser::readCDATA () { 2007 while (!data->atEnd ()) { 2008 *data >> next_char; 2009 if (next_char == QChar ('>') && cdata.endsWith (QString ("]]"))) { 2010 cdata.truncate (cdata.size () - 2); 2011 m_state = m_state->next; 2012 if (m_state->state == InContent) 2013 have_error = !builder.cdataData (cdata); 2014 else if (m_state->state == InAttributes) { 2015 if (equal_seen) 2016 attr_value += cdata; 2017 else 2018 attr_name += cdata; 2019 } 2020 cdata.truncate (0); 2021 return true; 2022 } 2023 cdata += next_char; 2024 } 2025 return false; 2026 } 2027 2028 bool SimpleSAXParser::readComment () { 2029 while (nextToken ()) { 2030 if (token->token == tok_angle_close && prev_token) 2031 if (prev_token->string.endsWith (QString ("--"))) { 2032 m_state = m_state->next; 2033 return true; 2034 } 2035 } 2036 return false; 2037 } 2038 2039 bool SimpleSAXParser::readEndTag () { 2040 if (!nextToken ()) return false; 2041 if (token->token == tok_white_space) 2042 if (!nextToken ()) return false; 2043 tagname = token->string; 2044 if (!nextToken ()) return false; 2045 if (token->token == tok_white_space) 2046 if (!nextToken ()) return false; 2047 if (token->token != tok_angle_close) 2048 return false; 2049 have_error = !builder.endTag (tagname); 2050 m_state = m_state->next; 2051 return true; 2052 } 2053 2054 // TODO: <!ENTITY ..> Ӓ 2055 bool SimpleSAXParser::readTag () { 2056 if (!nextToken ()) return false; 2057 if (token->token == tok_exclamation) { 2058 m_state = new StateInfo (InDTDTag, m_state->next); 2059 //qCDebug(LOG_KMPLAYER_COMMON) << "readTag: " << token->string.latin1 (); 2060 return readDTD (); 2061 } 2062 if (token->token == tok_white_space) 2063 if (!nextToken ()) return false; // allow '< / foo', '< foo', '< ? foo' 2064 if (token->token == tok_question_mark) { 2065 m_state = new StateInfo (InPITag, m_state->next); 2066 return readPI (); 2067 } 2068 if (token->token == tok_slash) { 2069 m_state = new StateInfo (InEndTag, m_state->next); 2070 return readEndTag (); 2071 } 2072 if (token->token != tok_text) 2073 return false; // FIXME entities 2074 tagname = token->string; 2075 //qCDebug(LOG_KMPLAYER_COMMON) << "readTag " << tagname.latin1(); 2076 m_state = new StateInfo (InAttributes, m_state); 2077 return readAttributes (); 2078 } 2079 2080 bool SimpleSAXParser::parse (QTextStream & d) { 2081 data = &d; 2082 if (!next_token) { 2083 next_token = TokenInfoPtr (new TokenInfo); 2084 m_state = new StateInfo (InContent, m_state); 2085 } 2086 bool ok = true; 2087 bool in_character_data = false; 2088 QString white_space; 2089 while (ok) { 2090 switch (m_state->state) { 2091 case InTag: 2092 ok = readTag (); 2093 break; 2094 case InPITag: 2095 ok = readPI (); 2096 break; 2097 case InDTDTag: 2098 ok = readDTD (); 2099 break; 2100 case InEndTag: 2101 ok = readEndTag (); 2102 break; 2103 case InAttributes: 2104 ok = readAttributes (); 2105 break; 2106 case InCDATA: 2107 ok = readCDATA (); 2108 break; 2109 case InComment: 2110 ok = readComment (); 2111 break; 2112 default: 2113 if ((ok = nextToken ())) { 2114 if (token->token == tok_angle_open) { 2115 attr_name.truncate (0); 2116 attr_value.truncate (0); 2117 m_attributes = AttributeList (); 2118 equal_seen = in_sngl_quote = in_dbl_quote = false; 2119 m_state = new StateInfo (InTag, m_state); 2120 ok = readTag (); 2121 in_character_data = false; 2122 white_space.truncate (0); 2123 } else if (token->token == tok_white_space) { 2124 white_space += token->string; 2125 } else { 2126 if (!white_space.isEmpty ()) { 2127 if (!in_character_data) { 2128 int pos = white_space.lastIndexOf (QChar ('\n')); 2129 if (pos > -1) 2130 white_space = white_space.mid (pos + 1); 2131 } 2132 have_error = !builder.characterData (white_space); 2133 white_space.truncate (0); 2134 } 2135 have_error = !builder.characterData (token->string); 2136 in_character_data = true; 2137 } 2138 } 2139 } 2140 if (!m_state) 2141 return true; // end document 2142 } 2143 return false; // need more data 2144 } 2145 2146 #endif // KMPLAYER_WITH_EXPAT