Qt 4.8
qacceltreeresourceloader.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include <QtCore/QFile>
43 #include <QtCore/QTextCodec>
44 #include <QtCore/QTimer>
45 #include <QtCore/QXmlStreamReader>
46 
47 #include <QtNetwork/QNetworkRequest>
48 
49 #include "qatomicstring_p.h"
50 #include "qautoptr_p.h"
51 #include "qcommonsequencetypes_p.h"
52 
54 
56 
57 using namespace QPatternist;
58 
60  const NetworkAccessDelegator::Ptr &manager,
62  : m_namePool(np)
63  , m_networkAccessDelegator(manager)
64  , m_features(features)
65 {
68 }
69 
71  const ReportContext::Ptr &context)
72 {
73  Q_ASSERT(uri.isValid());
74  AccelTreeBuilder<true> builder(uri, uri, m_namePool, context.data(), m_features);
75 
76  const AutoPtr<QNetworkReply> reply(load(uri, m_networkAccessDelegator, context));
77 
78  if(!reply)
79  return false;
80 
81  bool success = false;
82  success = streamToReceiver(reply.data(), &builder, m_namePool, context, uri);
83 
84  m_loadedDocuments.insert(uri, builder.builtDocument());
85  return success;
86 }
87 
88 bool AccelTreeResourceLoader::retrieveDocument(QIODevice *source, const QUrl &documentUri, const ReportContext::Ptr &context)
89 {
90  Q_ASSERT(source);
91  Q_ASSERT(source->isReadable());
92  Q_ASSERT(documentUri.isValid());
93 
94  AccelTreeBuilder<true> builder(documentUri, documentUri, m_namePool, context.data(), m_features);
95 
96  bool success = false;
97  success = streamToReceiver(source, &builder, m_namePool, context, documentUri);
98 
99  m_loadedDocuments.insert(documentUri, builder.builtDocument());
100 
101  return success;
102 }
103 
105  const NetworkAccessDelegator::Ptr &networkDelegator,
106  const ReportContext::Ptr &context, ErrorHandling errorHandling)
107 {
108  return load(uri,
109  networkDelegator->managerFor(uri),
110  context, errorHandling);
111 }
112 
114  QNetworkAccessManager *const networkManager,
115  const ReportContext::Ptr &context, ErrorHandling errorHandling)
116 
117 {
118  Q_ASSERT(networkManager);
119  Q_ASSERT(uri.isValid());
120 
121  NetworkLoop networkLoop;
122 
123  QNetworkRequest request(uri);
124  QNetworkReply *const reply = networkManager->get(request);
126  networkLoop.connect(reply, SIGNAL(finished()), SLOT(finished()));
127 
128  if(networkLoop.exec(QEventLoop::ExcludeUserInputEvents))
129  {
130  const QString errorMessage(escape(reply->errorString()));
131 
132  /* Note, we delete reply before we exit this function with error(). */
133  delete reply;
134 
135  const QSourceLocation location(uri);
136 
137  if(context && (errorHandling == FailOnError))
138  context->error(errorMessage, ReportContext::FODC0002, location);
139 
140  return 0;
141  }
142  else
143  return reply;
144 }
145 
147  AccelTreeBuilder<true> *const receiver,
148  const NamePool::Ptr &np,
149  const ReportContext::Ptr &context,
150  const QUrl &uri)
151 {
152  Q_ASSERT(dev);
153  Q_ASSERT(receiver);
154  Q_ASSERT(np);
155 
156  QXmlStreamReader reader(dev);
157 
158  /* Optimize: change NamePool to take QStringRef such that we don't have to call toString() below. That
159  * will save us a gazillion of temporary QStrings. */
160 
161  while(!reader.atEnd())
162  {
163  reader.readNext();
164 
165  switch(reader.tokenType())
166  {
168  {
169  /* Send the name. */
170  receiver->startElement(np->allocateQName(reader.namespaceUri().toString(), reader.name().toString(),
171  reader.prefix().toString()), reader.lineNumber(), reader.columnNumber());
172 
173  /* Send namespace declarations. */
175 
176  /* The far most common case, is for it to be empty. */
177  if(!nss.isEmpty())
178  {
179  const int len = nss.size();
180 
181  for(int i = 0; i < len; ++i)
182  {
183  const QXmlStreamNamespaceDeclaration &ns = nss.at(i);
184  receiver->namespaceBinding(np->allocateBinding(ns.prefix().toString(), ns.namespaceUri().toString()));
185  }
186  }
187 
188  /* Send attributes. */
189  const QXmlStreamAttributes &attrs = reader.attributes();
190  const int len = attrs.size();
191 
192  for(int i = 0; i < len; ++i)
193  {
194  const QXmlStreamAttribute &attr = attrs.at(i);
195 
196  receiver->attribute(np->allocateQName(attr.namespaceUri().toString(), attr.name().toString(),
197  attr.prefix().toString()),
198  attr.value());
199  }
200 
201  continue;
202  }
204  {
205  receiver->endElement();
206  continue;
207  }
209  {
210  if(reader.isWhitespace())
211  receiver->whitespaceOnly(reader.text());
212  else
213  receiver->characters(reader.text());
214 
215  continue;
216  }
218  {
219  receiver->comment(reader.text().toString());
220  continue;
221  }
223  {
226  continue;
227  }
229  {
230  receiver->startDocument();
231  continue;
232  }
234  {
235  receiver->endDocument();
236  continue;
237  }
239  /* Fallthrough. */
241  {
242  /* We just ignore any DTD and entity references. */
243  continue;
244  }
246  {
247  if(context)
248  context->error(escape(reader.errorString()), ReportContext::FODC0002, QSourceLocation(uri, reader.lineNumber(), reader.columnNumber()));
249 
250  return false;
251  }
253  {
254  Q_ASSERT_X(false, Q_FUNC_INFO,
255  "This token is never expected to be received.");
256  return false;
257  }
258  }
259  }
260 
261  return true;
262 }
263 
265  const ReportContext::Ptr &context)
266 {
267  const AccelTree::Ptr doc(m_loadedDocuments.value(uri));
268 
269  if(doc)
270  return doc->root(QXmlNodeModelIndex()); /* Pass in dummy object. We know AccelTree doesn't use it. */
271  else
272  {
273  if(retrieveDocument(uri, context))
274  return m_loadedDocuments.value(uri)->root(QXmlNodeModelIndex()); /* Pass in dummy object. We know AccelTree doesn't use it. */
275  else
276  return Item();
277  }
278 }
279 
281  const ReportContext::Ptr &context)
282 {
283  const AccelTree::Ptr doc(m_loadedDocuments.value(documentUri));
284 
285  if(doc)
286  return doc->root(QXmlNodeModelIndex()); /* Pass in dummy object. We know AccelTree doesn't use it. */
287  else
288  {
289  if(retrieveDocument(source, documentUri, context))
290  return m_loadedDocuments.value(documentUri)->root(QXmlNodeModelIndex()); /* Pass in dummy object. We know AccelTree doesn't use it. */
291  else
292  return Item();
293  }
294 }
295 
297 {
298  // TODO deal with the usage thingy
299  Q_ASSERT(uri.isValid());
300  Q_ASSERT(!uri.isRelative());
301  Q_UNUSED(uri); /* Needed when compiling in release mode. */
302 
304 }
305 
307 {
308  return retrieveDocument(uri, ReportContext::Ptr());
309 }
310 
311 static inline uint qHash(const QPair<QUrl, QString> &desc)
312 {
313  /* Probably a lousy hash. */
314  return qHash(desc.first) + qHash(desc.second);
315 }
316 
318  const QString &encoding,
319  const ReportContext::Ptr &context,
320  const SourceLocationReflection *const where)
321 {
322  const AutoPtr<QNetworkReply> reply(load(uri, m_networkAccessDelegator, context));
323 
324  if(!reply)
325  return false;
326 
327  const QTextCodec * codec;
328  if(encoding.isEmpty())
329  {
330  /* XSL Transformations (XSLT) Version 2.0 16.2 Reading Text Files:
331  *
332  * "if the media type of the resource is text/xml or application/xml
333  * (see [RFC2376]), or if it matches the conventions text/\*+xml or
334  * application/\*+xml (see [RFC3023] and/or its successors), then the
335  * encoding is recognized as specified in [XML 1.0]"
336  */
337  codec = QTextCodec::codecForMib(106);
338  }
339  else
340  {
341  codec = QTextCodec::codecForName(encoding.toLatin1());
342  if(codec && context)
343  {
344  context->error(QtXmlPatterns::tr("%1 is an unsupported encoding.").arg(formatURI(encoding)),
346  where);
347  }
348  else
349  return false;
350  }
351 
352  QTextCodec::ConverterState converterState;
353  const QByteArray inData(reply->readAll());
354  const QString result(codec->toUnicode(inData.constData(), inData.length(), &converterState));
355 
356  if(converterState.invalidChars)
357  {
358  if(context)
359  {
360  context->error(QtXmlPatterns::tr("%1 contains octets which are disallowed in "
361  "the requested encoding %2.").arg(formatURI(uri),
362  formatURI(encoding)),
364  where);
365  }
366  else
367  return false;
368  }
369 
370  const int len = result.length();
371  /* This code is a candidate for threading. Divide and conqueror. */
372  for(int i = 0; i < len; ++i)
373  {
374  if(!QXmlUtils::isChar(result.at(i)))
375  {
376  if(context)
377  {
378  context->error(QtXmlPatterns::tr("The codepoint %1, occurring in %2 using encoding %3, "
379  "is an invalid XML character.").arg(formatData(result.at(i)),
380  formatURI(uri),
381  formatURI(encoding)),
383  where);
384  }
385  else
386  return false;
387  }
388  }
389 
390  m_unparsedTexts.insert(qMakePair(uri, encoding), result);
391  return true;
392 }
393 
395  const QString &encoding)
396 {
397  return retrieveUnparsedText(uri, encoding, ReportContext::Ptr(), 0);
398 }
399 
401  const QString &encoding,
402  const ReportContext::Ptr &context,
403  const SourceLocationReflection *const where)
404 {
405  const QString &text = m_unparsedTexts.value(qMakePair(uri, encoding));
406 
407  if(text.isNull())
408  {
409  if(retrieveUnparsedText(uri, encoding, context, where))
410  return openUnparsedText(uri, encoding, context, where);
411  else
412  return Item();
413  }
414  else
415  return AtomicString::fromValue(text);
416 }
417 
419 {
422  QSet<QUrl> retval;
423 
424  while (it != end)
425  {
426  if(it.key().toString().startsWith(QLatin1String("tag:trolltech.com,2007:QtXmlPatterns:QIODeviceVariable:")))
427  retval.insert(it.key());
428 
429  ++it;
430  }
431 
432  return retval;
433 }
434 
436 {
437  m_loadedDocuments.remove(uri);
438 }
439 
441 
QString toString() const
Returns a copy of the string reference as a QString object.
Definition: qstring.cpp:8653
The QHash::const_iterator class provides an STL-style const iterator for QHash and QMultiHash...
Definition: qhash.h:395
The QXmlNodeModelIndex class identifies a node in an XML node model subclassed from QAbstractXmlNodeM...
bool isValid() const
Returns true if the URL is valid; otherwise returns false.
Definition: qurl.cpp:4303
QString Q_AUTOTEST_EXPORT escape(const QString &input)
Similar to Qt::escape(), but also escapes apostrophes and quotes, such that the result is suitable as...
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
virtual SequenceType::Ptr announceDocument(const QUrl &uri, const Usage usageHint)
May be called by the compilation framework at compile time to report that an XML document referenced ...
bool isReadable() const
Returns true if data can be read from the device; otherwise returns false.
Definition: qiodevice.cpp:544
qint64 lineNumber() const
Returns the current line number, starting with 1.
#define it(className, varName)
virtual void clear(const QUrl &uri)
Asks to unload uri from its document pool, such that a subsequent request will require a new read...
QHash< QUrl, AccelTree::Ptr > m_loadedDocuments
virtual void whitespaceOnly(const QStringRef &ch)
QXmlName allocateBinding(const QString &prefix, const QString &uri)
Allocates a namespace binding for prefix and uri.
Definition: qnamepool.cpp:275
A smart pointer very similar to std::auto_ptr.
Definition: qautoptr_p.h:73
#define error(msg)
The QNetworkReply class contains the data and headers for a request sent with QNetworkAccessManager.
Definition: qnetworkreply.h:65
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
#define SLOT(a)
Definition: qobjectdefs.h:226
QString errorString() const
Returns a human-readable description of the last device error that occurred.
Definition: qiodevice.cpp:1671
T1 first
Definition: qpair.h:65
Builds an AccelTree from a stream of XML/Item events received through the NodeBuilder interface...
Definition: qacceltree_p.h:69
QStringRef value() const
Returns the attribute&#39;s value.
Definition: qxmlstream.h:156
T2 second
Definition: qpair.h:66
virtual Item openDocument(const QUrl &uri, const ReportContext::Ptr &context)
Calls to this function are generated by calls to the fn:document() or fn:doc() function.
NetworkError
Indicates all possible error conditions found during the processing of the request.
Definition: qnetworkreply.h:70
const NetworkAccessDelegator::Ptr m_networkAccessDelegator
static bool isChar(const QChar c)
Determines whether c is a valid instance of production [2]Char in the XML 1.0 specification.
Definition: qxmlutils.cpp:271
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
QStringRef name() const
Returns the local name of a StartElement, EndElement, or an EntityReference.
bool atEnd() const
Returns true if the reader has read until the end of the XML document, or if an error() has occurred ...
Definition: qxmlstream.cpp:590
The QUrl class provides a convenient interface for working with URLs.
Definition: qurl.h:61
The QString class provides a Unicode character string.
Definition: qstring.h:83
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
QStringRef prefix() const
Returns the prefix of a StartElement or EndElement.
QNetworkAccessManager * managerFor(const QUrl &uri)
bool isRelative() const
Returns true if the URL is relative; otherwise returns false.
Definition: qurl.cpp:5880
static AtomicString::Ptr fromValue(const QString &value)
const T value(const Key &key) const
Returns the value associated with the key.
Definition: qhash.h:606
virtual QXmlNodeModelIndex root(const QXmlNodeModelIndex &n) const
Returns the root node.
Definition: qacceltree.cpp:236
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition: qhash.h:753
The QXmlStreamAttribute class represents a single XML attribute.
Definition: qxmlstream.h:135
virtual void startElement(const QXmlName &name)
virtual Item openUnparsedText(const QUrl &uri, const QString &encoding, const ReportContext::Ptr &context, const SourceLocationReflection *const where)
Calls to this function are generated by calls to the fn:unparsed-text() function. ...
AccelTreeResourceLoader(const NamePool::Ptr &np, const NetworkAccessDelegator::Ptr &networkDelegator, AccelTreeBuilder< true >::Features=AccelTreeBuilder< true >::NoneFeature)
QStringRef namespaceUri() const
Returns the namespaceUri of a StartElement or EndElement.
#define SIGNAL(a)
Definition: qobjectdefs.h:227
T * data() const
Returns a pointer to the shared data object.
Definition: qshareddata.h:145
TokenType tokenType() const
Returns the type of the current token.
Definition: qxmlstream.cpp:656
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
An helper class which enables QNetworkAccessManager to be used in a blocking manner.
uint qHash(const QPatternist::TargetNode &node)
virtual bool isDocumentAvailable(const QUrl &uri)
Calls to this function are generated by calls to the fn:doc-available() function. ...
static bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Creates a connection of the given type from the signal in the sender object to the method in the rece...
Definition: qobject.cpp:2580
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
virtual void namespaceBinding(const QXmlName &nb)
Signals the presence of the namespace declaration nb.
The namespace for the internal API of QtXmlPatterns.
virtual void processingInstruction(const QXmlName &target, const QString &data)
The QSourceLocation class identifies a location in a resource by URI, line, and column.
bool retrieveUnparsedText(const QUrl &uri, const QString &encoding, const ReportContext::Ptr &context, const SourceLocationReflection *const where)
unsigned int uint
Definition: qglobal.h:996
static QTextCodec * codec(MYSQL *mysql)
Definition: qsql_mysql.cpp:220
QStringRef namespaceUri() const
Returns the namespaceUri.
Definition: qxmlstream.h:216
static QTextCodec * codecForMib(int mib)
Returns the QTextCodec which matches the MIBenum mib.
QStringRef prefix() const
Returns the prefix.
Definition: qxmlstream.h:215
QByteArray toLatin1() const Q_REQUIRED_RESULT
Returns a Latin-1 representation of the string as a QByteArray.
Definition: qstring.cpp:3993
QStringRef name() const
Returns the attribute&#39;s local name.
Definition: qxmlstream.h:149
static QString formatData(const QString &data)
QNetworkReply * get(const QNetworkRequest &request)
Posts a request to obtain the contents of the target request and returns a new QNetworkReply object o...
The QNetworkAccessManager class allows the application to send network requests and receive replies...
const T & at(int i) const
Returns the item at index position i in the vector.
Definition: qvector.h:350
TokenType readNext()
Reads the next token and returns its type.
Definition: qxmlstream.cpp:623
The QXmlStreamNamespaceDeclaration class represents a namespace declaration.
Definition: qxmlstream.h:204
static QNetworkReply * load(const QUrl &uri, QNetworkAccessManager *const networkManager, const ReportContext::Ptr &context, ErrorHandling handling=FailOnError)
Helper function that do NetworkAccessDelegator::get(), but does it blocked.
bool isNull() const
Returns true if this string is null; otherwise returns false.
Definition: qstring.h:505
QString toUnicode(const QByteArray &) const
Converts a from the encoding of this codec to Unicode, and returns the result in a QString...
virtual void comment(const QString &content)
#define Q_ASSERT_X(cond, where, what)
Definition: qglobal.h:1837
QHash< QPair< QUrl, QString >, QString > m_unparsedTexts
static const SequenceType::Ptr ZeroOrOneDocumentNode
Represents an item in the XPath 2.0 Data Model.
Definition: qitem_p.h:182
virtual void endElement()
Signals the end of the current element.
The QXmlStreamAttributes class represents a vector of QXmlStreamAttribute.
Definition: qxmlstream.h:169
virtual void attribute(const QXmlName &name, const QStringRef &value)
virtual bool isUnparsedTextAvailable(const QUrl &uri, const QString &encoding)
Calls to this function are generated by calls to the fn:unparsed-text-available() function...
qint64 columnNumber() const
Returns the current column number, starting with 0.
Q_OUTOFLINE_TEMPLATE QPair< T1, T2 > qMakePair(const T1 &x, const T2 &y)
Definition: qpair.h:102
static QTestResult::TestLocation location
Definition: qtestresult.cpp:63
virtual void characters(const QStringRef &ch)
QStringRef prefix() const
Returns the attribute&#39;s namespace prefix.
Definition: qxmlstream.h:151
QXmlStreamNamespaceDeclarations namespaceDeclarations() const
If the state() is StartElement , this function returns the element&#39;s namespace declarations.
QXmlName allocateQName(const QString &uri, const QString &localName, const QString &prefix=QString())
Definition: qnamepool.cpp:251
static QTextCodec * codecForName(const QByteArray &name)
Searches all installed QTextCodec objects and returns the one which best matches name; the match is c...
QByteArray readAll()
Reads all available data from the device, and returns it as a QByteArray.
Definition: qiodevice.cpp:1025
The QNetworkRequest class holds a request to be sent with QNetworkAccessManager.
QStringRef processingInstructionData() const
Returns the data of a ProcessingInstruction.
bool isWhitespace() const
Returns true if the reader reports characters that only consist of white-space; otherwise returns fal...
bool isEmpty() const
Returns true if the vector has size 0; otherwise returns false.
Definition: qvector.h:139
The QXmlStreamReader class provides a fast parser for reading well-formed XML via a simple streaming ...
Definition: qxmlstream.h:290
QStringRef processingInstructionTarget() const
Returns the target of a ProcessingInstruction.
static QString formatURI(const NamePool::Ptr &np, const QXmlName::NamespaceCode &uri)
Formats uri, that&#39;s considered to be a URI, for display.
Definition: qanyuri_p.h:202
AccelTreeBuilder< true >::Features m_features
The QTextCodec class provides conversions between text encodings.
Definition: qtextcodec.h:62
QStringRef text() const
Returns the text of Characters , Comment , DTD , or EntityReference.
QString errorString() const
Returns the error message that was set with raiseError().
The resource loader will report the error via the report context.
static const KeyPair *const end
The QIODevice class is the base interface class of all I/O devices in Qt.
Definition: qiodevice.h:66
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
bool retrieveDocument(const QUrl &uri, const ReportContext::Ptr &context)
int size() const
Returns the number of items in the vector.
Definition: qvector.h:137
QXmlStreamAttributes attributes() const
Returns the attributes of a StartElement.
virtual QSet< QUrl > deviceURIs() const
Returns the URIs this AccelTreeResourceLoader has loaded which are for devices through variable bindi...
static bool streamToReceiver(QIODevice *const dev, AccelTreeBuilder< true > *const receiver, const NamePool::Ptr &np, const ReportContext::Ptr &context, const QUrl &uri)
#define text
Definition: qobjectdefs.h:80
Base class for all instances that represents something at a certain location.
#define Q_FUNC_INFO
Definition: qglobal.h:1871
QStringRef namespaceUri() const
Returns the attribute&#39;s resolved namespaceUri, or an empty string reference if the attribute does not...
Definition: qxmlstream.h:148